From 9fe4b635174060697a9ea8a9e33f47394a34d9e9 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 24 May 2022 12:56:24 +0200 Subject: [PATCH 001/282] refactor avalon imports from lib_template_builder --- .../hosts/maya/api/lib_template_builder.py | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 openpype/hosts/maya/api/lib_template_builder.py diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py new file mode 100644 index 0000000000..172a6f9b2b --- /dev/null +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -0,0 +1,184 @@ +from collections import OrderedDict +import maya.cmds as cmds + +import qargparse +from openpype.tools.utils.widgets import OptionDialog +from lib import get_main_window, imprint + +# To change as enum +build_types = ["context_asset", "linked_asset", "all_assets"] + + +def get_placeholder_attributes(node): + return { + attr: cmds.getAttr("{}.{}".format(node, attr)) + for attr in cmds.listAttr(node, userDefined=True)} + + +def delete_placeholder_attributes(node): + ''' + function to delete all extra placeholder attributes + ''' + extra_attributes = get_placeholder_attributes(node) + for attribute in extra_attributes: + cmds.deleteAttr(node + '.' + attribute) + + +def create_placeholder(): + args = placeholder_window() + + if not args: + return # operation canceled, no locator created + + selection = cmds.ls(selection=True) + placeholder = cmds.spaceLocator(name="_TEMPLATE_PLACEHOLDER_")[0] + if selection: + cmds.parent(placeholder, selection[0]) + # custom arg parse to force empty data query + # and still imprint them on placeholder + # and getting items when arg is of type Enumerator + options = OrderedDict() + for arg in args: + if not type(arg) == qargparse.Separator: + options[str(arg)] = arg._data.get("items") or arg.read() + imprint(placeholder, options) + # Some tweaks because imprint force enums to to default value so we get + # back arg read and force them to attributes + imprint_enum(placeholder, args) + + # Add helper attributes to keep placeholder info + cmds.addAttr( + placeholder, longName="parent", + hidden=True, dataType="string") + cmds.addAttr( + placeholder, longName="index", + hidden=True, attributeType="short", + defaultValue=-1) + + +def update_placeholder(): + placeholder = cmds.ls(selection=True) + if len(placeholder) == 0: + raise ValueError("No node selected") + if len(placeholder) > 1: + raise ValueError("Too many selected nodes") + placeholder = placeholder[0] + + args = placeholder_window(get_placeholder_attributes(placeholder)) + # delete placeholder attributes + delete_placeholder_attributes(placeholder) + if not args: + return # operation canceled + + options = OrderedDict() + for arg in args: + if not type(arg) == qargparse.Separator: + options[str(arg)] = arg._data.get("items") or arg.read() + imprint(placeholder, options) + imprint_enum(placeholder, args) + + +def imprint_enum(placeholder, args): + """ + Imprint method doesn't act properly with enums. + Replacing the functionnality with this for now + """ + enum_values = {str(arg): arg.read() + for arg in args if arg._data.get("items")} + string_to_value_enum_table = { + build: i for i, build + in enumerate(build_types)} + for key, value in enum_values.items(): + cmds.setAttr( + placeholder + "." + key, + string_to_value_enum_table[value]) + + +def placeholder_window(options=None): + options = options or dict() + dialog = OptionDialog(parent=get_main_window()) + dialog.setWindowTitle("Create Placeholder") + + args = [ + qargparse.Separator("Main attributes"), + qargparse.Enum( + "builder_type", + label="Asset Builder Type", + default=options.get("builder_type", 0), + items=build_types, + help="""Asset Builder Type +Builder type describe what template loader will look for. +context_asset : Template loader will look for subsets of +current context asset (Asset bob will find asset) +linked_asset : Template loader will look for assets linked +to current context asset. +Linked asset are looked in avalon database under field "inputLinks" +""" + ), + qargparse.String( + "family", + default=options.get("family", ""), + label="OpenPype Family", + placeholder="ex: model, look ..."), + qargparse.String( + "representation", + default=options.get("representation", ""), + label="OpenPype Representation", + placeholder="ex: ma, abc ..."), + qargparse.String( + "loader", + default=options.get("loader", ""), + label="Loader", + placeholder="ex: ReferenceLoader, LightLoader ...", + help="""Loader +Defines what openpype loader will be used to load assets. +Useable loader depends on current host's loader list. +Field is case sensitive. +"""), + qargparse.String( + "loader_args", + default=options.get("loader_args", ""), + label="Loader Arguments", + placeholder='ex: {"camera":"persp", "lights":True}', + help="""Loader +Defines a dictionnary of arguments used to load assets. +Useable arguments depend on current placeholder Loader. +Field should be a valid python dict. Anything else will be ignored. +"""), + qargparse.Integer( + "order", + default=options.get("order", 0), + min=0, + max=999, + label="Order", + placeholder="ex: 0, 100 ... (smallest order loaded first)", + help="""Order +Order defines asset loading priority (0 to 999) +Priority rule is : "lowest is first to load"."""), + qargparse.Separator( + "Optional attributes"), + qargparse.String( + "asset", + default=options.get("asset", ""), + label="Asset filter", + placeholder="regex filtering by asset name", + help="Filtering assets by matching field regex to asset's name"), + qargparse.String( + "subset", + default=options.get("subset", ""), + label="Subset filter", + placeholder="regex filtering by subset name", + help="Filtering assets by matching field regex to subset's name"), + qargparse.String( + "hierarchy", + default=options.get("hierarchy", ""), + label="Hierarchy filter", + placeholder="regex filtering by asset's hierarchy", + help="Filtering assets by matching field asset's hierarchy") + ] + dialog.create(args) + + if not dialog.exec_(): + return None + + return args From 69a388de1319eb49de84a0f6d846631623fc5a7d Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 24 May 2022 14:58:27 +0200 Subject: [PATCH 002/282] add the templated wrokfile build schema for maya --- .../defaults/project_settings/maya.json | 8 +++++ .../projects_schema/schema_project_maya.json | 4 +++ .../schema_templated_workfile_build.json | 29 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index a42f889e85..303cd052bb 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -718,6 +718,14 @@ } ] }, + "templated_workfile_build": { + "profiles": [ + { + "task_types": [], + "path": "/path/to/your/template" + } + ] + }, "filters": { "preset 1": { "ValidateNoAnimation": false, diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index 40e98b0333..d137049e9e 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -73,6 +73,10 @@ "type": "schema", "name": "schema_workfile_build" }, + { + "type": "schema", + "name": "schema_templated_workfile_build" + }, { "type": "schema", "name": "schema_publish_gui_filter" 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 new file mode 100644 index 0000000000..01e74f64b0 --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json @@ -0,0 +1,29 @@ +{ + "type": "dict", + "collapsible": true, + "key": "templated_workfile_build", + "label": "Templated Workfile Build Settings", + "children": [ + { + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": { + "type": "dict", + "children": [ + { + "key": "task_types", + "label": "Task types", + "type": "task-types-enum" + }, + { + "key": "path", + "label": "Path to template", + "type": "text", + "object_type": "text" + } + ] + } + } + ] +} From 108597f9b1e139f31e6b0f20568866cb2971020a Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 24 May 2022 17:28:42 +0200 Subject: [PATCH 003/282] add placeholder menu to maya --- .../hosts/maya/api/lib_template_builder.py | 2 +- openpype/hosts/maya/api/menu.py | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index 172a6f9b2b..d8772f3f9a 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -3,7 +3,7 @@ import maya.cmds as cmds import qargparse from openpype.tools.utils.widgets import OptionDialog -from lib import get_main_window, imprint +from .lib import get_main_window, imprint # To change as enum build_types = ["context_asset", "linked_asset", "all_assets"] diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index 97f06c43af..8beaf491bb 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -11,8 +11,10 @@ from openpype.settings import get_project_settings from openpype.pipeline import legacy_io from openpype.tools.utils import host_tools from openpype.hosts.maya.api import lib + from .lib import get_main_window, IS_HEADLESS from .commands import reset_frame_range +from .lib_template_builder import create_placeholder, update_placeholder log = logging.getLogger(__name__) @@ -139,6 +141,24 @@ def install(): parent_widget ) ) + + builder_menu = cmds.menuItem( + "Template Builder", + subMenu=True, + tearOff=True, + parent=MENU_NAME + ) + cmds.menuItem( + "Create Placeholder", + parent=builder_menu, + command=lambda *args: create_placeholder() + ) + cmds.menuItem( + "Update Placeholder", + parent=builder_menu, + command=lambda *args: update_placeholder() + ) + cmds.setParent(MENU_NAME, menu=True) def add_scripts_menu(): From 199aba87727d7a2417d7f8122dd34f6e4160b467 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 12:25:39 +0200 Subject: [PATCH 004/282] setup build template in openpype lib --- openpype/lib/__init__.py | 2 + openpype/lib/abstract_template_loader.py | 447 ++++++++++++++++++++++ openpype/lib/avalon_context.py | 222 +++++------ openpype/lib/build_template.py | 61 +++ openpype/lib/build_template_exceptions.py | 35 ++ 5 files changed, 660 insertions(+), 107 deletions(-) create mode 100644 openpype/lib/abstract_template_loader.py create mode 100644 openpype/lib/build_template.py create mode 100644 openpype/lib/build_template_exceptions.py diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 8d4e733b7d..8f3919d378 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -136,6 +136,7 @@ from .avalon_context import ( create_workfile_doc, save_workfile_data_to_doc, get_workfile_doc, + get_loaders_by_name, BuildWorkfile, @@ -308,6 +309,7 @@ __all__ = [ "create_workfile_doc", "save_workfile_data_to_doc", "get_workfile_doc", + "get_loaders_by_name", "BuildWorkfile", diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py new file mode 100644 index 0000000000..6888cbf757 --- /dev/null +++ b/openpype/lib/abstract_template_loader.py @@ -0,0 +1,447 @@ +import os +from abc import ABCMeta, abstractmethod + +import traceback + +import six + +import openpype +from openpype.settings import get_project_settings +from openpype.lib import Anatomy, get_linked_assets, get_loaders_by_name +from openpype.api import PypeLogger as Logger +from openpype.pipeline import legacy_io + +from functools import reduce + +from openpype.lib.build_template_exceptions import ( + TemplateAlreadyImported, + TemplateLoadingFailed, + TemplateProfileNotFound, + TemplateNotFound +) + + +def update_representations(entities, entity): + if entity['context']['subset'] not in entities: + entities[entity['context']['subset']] = entity + else: + current = entities[entity['context']['subset']] + incomming = entity + entities[entity['context']['subset']] = max( + current, incomming, + key=lambda entity: entity["context"].get("version", -1)) + + return entities + + +def parse_loader_args(loader_args): + if not loader_args: + return dict() + try: + parsed_args = eval(loader_args) + if not isinstance(parsed_args, dict): + return dict() + else: + return parsed_args + except Exception as err: + print( + "Error while parsing loader arguments '{}'.\n{}: {}\n\n" + "Continuing with default arguments. . .".format( + loader_args, + err.__class__.__name__, + err)) + return dict() + + +@six.add_metaclass(ABCMeta) +class AbstractTemplateLoader: + """ + Abstraction of Template Loader. + Properties: + template_path : property to get current template path + Methods: + import_template : Abstract Method. Used to load template, + depending on current host + get_template_nodes : Abstract Method. Used to query nodes acting + as placeholders. Depending on current host + """ + + def __init__(self, placeholder_class): + + self.loaders_by_name = get_loaders_by_name() + self.current_asset = legacy_io.Session["AVALON_ASSET"] + self.project_name = legacy_io.Session["AVALON_PROJECT"] + self.host_name = legacy_io.Session["AVALON_APP"] + self.task_name = legacy_io.Session["AVALON_TASK"] + self.placeholder_class = placeholder_class + self.current_asset_docs = legacy_io.find_one({ + "type": "asset", + "name": self.current_asset + }) + self.task_type = ( + self.current_asset_docs + .get("data", {}) + .get("tasks", {}) + .get(self.task_name, {}) + .get("type") + ) + + self.log = Logger().get_logger("BUILD TEMPLATE") + + self.log.info( + "BUILDING ASSET FROM TEMPLATE :\n" + "Starting templated build for {asset} in {project}\n\n" + "Asset : {asset}\n" + "Task : {task_name} ({task_type})\n" + "Host : {host}\n" + "Project : {project}\n".format( + asset=self.current_asset, + host=self.host_name, + project=self.project_name, + task_name=self.task_name, + task_type=self.task_type + )) + # Skip if there is no loader + if not self.loaders_by_name: + self.log.warning( + "There is no registered loaders. No assets will be loaded") + return + + def template_already_imported(self, err_msg): + """In case template was already loaded. + Raise the error as a default action. + Override this method in your template loader implementation + to manage this case.""" + self.log.error("{}: {}".format( + err_msg.__class__.__name__, + err_msg)) + raise TemplateAlreadyImported(err_msg) + + def template_loading_failed(self, err_msg): + """In case template loading failed + Raise the error as a default action. + Override this method in your template loader implementation + to manage this case. + """ + self.log.error("{}: {}".format( + err_msg.__class__.__name__, + err_msg)) + raise TemplateLoadingFailed(err_msg) + + @property + def template_path(self): + """ + Property returning template path. Avoiding setter. + Getting template path from open pype settings based on current avalon + session and solving the path variables if needed. + Returns: + str: Solved template path + Raises: + TemplateProfileNotFound: No profile found from settings for + current avalon session + KeyError: Could not solve path because a key does not exists + in avalon context + TemplateNotFound: Solved path does not exists on current filesystem + """ + project_name = self.project_name + host_name = self.host_name + task_name = self.task_name + task_type = self.task_type + + anatomy = Anatomy(project_name) + project_settings = get_project_settings(project_name) + + build_info = project_settings[host_name]['templated_workfile_build'] + profiles = build_info['profiles'] + + for prf in profiles: + if prf['task_types'] and task_type not in prf['task_types']: + continue + if prf['task_names'] and task_name not in prf['task_names']: + continue + path = prf['path'] + break + else: # IF no template were found (no break happened) + raise TemplateProfileNotFound( + "No matching profile found for task '{}' of type '{}' " + "with host '{}'".format(task_name, task_type, host_name) + ) + if path is None: + raise TemplateLoadingFailed( + "Template path is not set.\n" + "Path need to be set in {}\\Template Workfile Build " + "Settings\\Profiles".format(host_name.title())) + try: + solved_path = None + while True: + solved_path = anatomy.path_remapper(path) + if solved_path is None: + solved_path = path + if solved_path == path: + break + path = solved_path + except KeyError as missing_key: + raise KeyError( + "Could not solve key '{}' in template path '{}'".format( + missing_key, path)) + finally: + solved_path = os.path.normpath(solved_path) + + if not os.path.exists(solved_path): + raise TemplateNotFound( + "Template found in openPype settings for task '{}' with host " + "'{}' does not exists. (Not found : {})".format( + task_name, host_name, solved_path)) + + self.log.info("Found template at : '{}'".format(solved_path)) + + return solved_path + + def populate_template(self, ignored_ids=None): + """ + Use template placeholders to load assets and parent them in hierarchy + Arguments : + ignored_ids : + Returns: + None + """ + loaders_by_name = self.loaders_by_name + current_asset = self.current_asset + linked_assets = [asset['name'] for asset + in get_linked_assets(self.current_asset_docs)] + + ignored_ids = ignored_ids or [] + placeholders = self.get_placeholders() + for placeholder in placeholders: + placeholder_representations = self.get_placeholder_representations( + placeholder, + current_asset, + linked_assets + ) + for representation in placeholder_representations: + + self.preload(placeholder, loaders_by_name, representation) + + if self.load_data_is_incorrect( + placeholder, + representation, + ignored_ids): + continue + + self.log.info( + "Loading {}_{} with loader {}\n" + "Loader arguments used : {}".format( + representation['context']['asset'], + representation['context']['subset'], + placeholder.loader, + placeholder.data['loader_args'])) + + try: + container = self.load( + placeholder, loaders_by_name, representation) + except Exception: + self.load_failed(placeholder, representation) + else: + self.load_succeed(placeholder, container) + finally: + self.postload(placeholder) + + def get_placeholder_representations( + self, placeholder, current_asset, linked_assets): + placeholder_db_filters = placeholder.convert_to_db_filters( + current_asset, + linked_assets) + # get representation by assets + for db_filter in placeholder_db_filters: + placeholder_representations = list(avalon.io.find(db_filter)) + for representation in reduce(update_representations, + placeholder_representations, + dict()).values(): + yield representation + + def load_data_is_incorrect( + self, placeholder, last_representation, ignored_ids): + if not last_representation: + self.log.warning(placeholder.err_message()) + return True + if (str(last_representation['_id']) in ignored_ids): + print("Ignoring : ", last_representation['_id']) + return True + return False + + def preload(self, placeholder, loaders_by_name, last_representation): + pass + + def load(self, placeholder, loaders_by_name, last_representation): + return openpype.pipeline.load( + loaders_by_name[placeholder.loader], + last_representation['_id'], + options=parse_loader_args(placeholder.data['loader_args'])) + + def load_succeed(self, placeholder, container): + placeholder.parent_in_hierarchy(container) + + def load_failed(self, placeholder, last_representation): + self.log.warning("Got error trying to load {}:{} with {}\n\n" + "{}".format(last_representation['context']['asset'], + last_representation['context']['subset'], + placeholder.loader, + traceback.format_exc())) + + def postload(self, placeholder): + placeholder.clean() + + def update_missing_containers(self): + loaded_containers_ids = self.get_loaded_containers_by_id() + self.populate_template(ignored_ids=loaded_containers_ids) + + def get_placeholders(self): + placeholder_class = self.placeholder_class + placeholders = map(placeholder_class, self.get_template_nodes()) + valid_placeholders = filter(placeholder_class.is_valid, placeholders) + sorted_placeholders = sorted(valid_placeholders, + key=placeholder_class.order) + return sorted_placeholders + + @abstractmethod + def get_loaded_containers_by_id(self): + """ + Collect already loaded containers for updating scene + Return: + dict (string, node): A dictionnary id as key + and containers as value + """ + pass + + @abstractmethod + def import_template(self, template_path): + """ + Import template in current host + Args: + template_path (str): fullpath to current task and + host's template file + Return: + None + """ + pass + + @abstractmethod + def get_template_nodes(self): + """ + Returning a list of nodes acting as host placeholders for + templating. The data representation is by user. + AbstractLoadTemplate (and LoadTemplate) won't directly manipulate nodes + Args : + None + Returns: + list(AnyNode): Solved template path + """ + pass + + +@six.add_metaclass(ABCMeta) +class AbstractPlaceholder: + """Abstraction of placeholders logic + Properties: + attributes: A list of mandatory attribute to decribe placeholder + and assets to load. + optional_attributes: A list of optional attribute to decribe + placeholder and assets to load + loader: Name of linked loader to use while loading assets + is_context: Is placeholder linked + to context asset (or to linked assets) + Methods: + is_repres_valid: + loader: + order: + is_valid: + get_data: + parent_in_hierachy: + """ + + attributes = {'builder_type', 'op_family', 'op_representation', + 'order', 'loader', 'loader_args'} + optional_attributes = {} + + def __init__(self, node): + self.get_data(node) + + def order(self): + """Get placeholder order. + Order is used to sort them by priority + Priority is lowset first, highest last + (ex: + 1: First to load + 100: Last to load) + Returns: + Int: Order priority + """ + return self.data.get('order') + + @property + def loader(self): + """Return placeholder loader type + Returns: + string: Loader name + """ + return self.data.get('loader') + + @property + def is_context(self): + """Return placeholder type + context_asset: For loading current asset + linked_asset: For loading linked assets + Returns: + bool: true if placeholder is a context placeholder + """ + return self.data.get('builder_type') == 'context_asset' + + def is_valid(self): + """Test validity of placeholder + i.e.: every attributes exists in placeholder data + Returns: + Bool: True if every attributes are a key of data + """ + if set(self.attributes).issubset(self.data.keys()): + print("Valid placeholder : {}".format(self.data["node"])) + return True + print("Placeholder is not valid : {}".format(self.data["node"])) + return False + + @abstractmethod + def parent_in_hierarchy(self, containers): + """Place container in correct hierarchy + given by placeholder + Args: + containers (String): Container name returned back by + placeholder's loader. + """ + pass + + @abstractmethod + def clean(self): + """Clean placeholder from hierarchy after loading assets. + """ + pass + + @abstractmethod + def convert_to_db_filters(self, current_asset, linked_asset): + """map current placeholder data as a db filter + args: + current_asset (String): Name of current asset in context + linked asset (list[String]) : Names of assets linked to + current asset in context + Returns: + dict: a dictionnary describing a filter to look for asset in + a database + """ + pass + + @abstractmethod + def get_data(self, node): + """ + Collect placeholders information. + Args: + node (AnyNode): A unique node decided by Placeholder implementation + """ + pass diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 9d8a92cfe9..8c80b4a4ae 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -15,6 +15,7 @@ from openpype.settings import ( get_project_settings, get_system_settings ) + from .anatomy import Anatomy from .profiles_filtering import filter_profiles from .events import emit_event @@ -922,6 +923,118 @@ def save_workfile_data_to_doc(workfile_doc, data, dbcon=None): ) +@with_pipeline_io +def collect_last_version_repres(asset_entities): + """Collect subsets, versions and representations for asset_entities. + + Args: + asset_entities (list): Asset entities for which want to find data + + Returns: + (dict): collected entities + + Example output: + ``` + { + {Asset ID}: { + "asset_entity": , + "subsets": { + {Subset ID}: { + "subset_entity": , + "version": { + "version_entity": , + "repres": [ + , , ... + ] + } + }, + ... + } + }, + ... + } + output[asset_id]["subsets"][subset_id]["version"]["repres"] + ``` + """ + + if not asset_entities: + return {} + + asset_entity_by_ids = {asset["_id"]: asset for asset in asset_entities} + + subsets = list(legacy_io.find({ + "type": "subset", + "parent": {"$in": list(asset_entity_by_ids.keys())} + })) + subset_entity_by_ids = {subset["_id"]: subset for subset in subsets} + + sorted_versions = list(legacy_io.find({ + "type": "version", + "parent": {"$in": list(subset_entity_by_ids.keys())} + }).sort("name", -1)) + + subset_id_with_latest_version = [] + last_versions_by_id = {} + for version in sorted_versions: + subset_id = version["parent"] + if subset_id in subset_id_with_latest_version: + continue + subset_id_with_latest_version.append(subset_id) + last_versions_by_id[version["_id"]] = version + + repres = legacy_io.find({ + "type": "representation", + "parent": {"$in": list(last_versions_by_id.keys())} + }) + + output = {} + for repre in repres: + version_id = repre["parent"] + version = last_versions_by_id[version_id] + + subset_id = version["parent"] + subset = subset_entity_by_ids[subset_id] + + asset_id = subset["parent"] + asset = asset_entity_by_ids[asset_id] + + if asset_id not in output: + output[asset_id] = { + "asset_entity": asset, + "subsets": {} + } + + if subset_id not in output[asset_id]["subsets"]: + output[asset_id]["subsets"][subset_id] = { + "subset_entity": subset, + "version": { + "version_entity": version, + "repres": [] + } + } + + output[asset_id]["subsets"][subset_id]["version"]["repres"].append( + repre + ) + + return output + + +@with_pipeline_io +def get_loaders_by_name(): + from openpype.pipeline import discover_loader_plugins + + loaders_by_name = {} + for loader in discover_loader_plugins(): + loader_name = loader.__name__ + if loader_name in loaders_by_name: + raise KeyError( + "Duplicated loader name {} !".format(loader_name) + ) + loaders_by_name[loader_name] = loader + return loaders_by_name + + class BuildWorkfile: """Wrapper for build workfile process. @@ -979,8 +1092,6 @@ class BuildWorkfile: ... }] """ - from openpype.pipeline import discover_loader_plugins - # Get current asset name and entity current_asset_name = legacy_io.Session["AVALON_ASSET"] current_asset_entity = legacy_io.find_one({ @@ -996,14 +1107,7 @@ class BuildWorkfile: return # Prepare available loaders - loaders_by_name = {} - for loader in discover_loader_plugins(): - loader_name = loader.__name__ - if loader_name in loaders_by_name: - raise KeyError( - "Duplicated loader name {0}!".format(loader_name) - ) - loaders_by_name[loader_name] = loader + loaders_by_name = get_loaders_by_name() # Skip if there are any loaders if not loaders_by_name: @@ -1075,7 +1179,7 @@ class BuildWorkfile: return # Prepare entities from database for assets - prepared_entities = self._collect_last_version_repres(assets) + prepared_entities = collect_last_version_repres(assets) # Load containers by prepared entities and presets loaded_containers = [] @@ -1491,102 +1595,6 @@ class BuildWorkfile: return loaded_containers - @with_pipeline_io - def _collect_last_version_repres(self, asset_entities): - """Collect subsets, versions and representations for asset_entities. - - Args: - asset_entities (list): Asset entities for which want to find data - - Returns: - (dict): collected entities - - Example output: - ``` - { - {Asset ID}: { - "asset_entity": , - "subsets": { - {Subset ID}: { - "subset_entity": , - "version": { - "version_entity": , - "repres": [ - , , ... - ] - } - }, - ... - } - }, - ... - } - output[asset_id]["subsets"][subset_id]["version"]["repres"] - ``` - """ - - if not asset_entities: - return {} - - asset_entity_by_ids = {asset["_id"]: asset for asset in asset_entities} - - subsets = list(legacy_io.find({ - "type": "subset", - "parent": {"$in": list(asset_entity_by_ids.keys())} - })) - subset_entity_by_ids = {subset["_id"]: subset for subset in subsets} - - sorted_versions = list(legacy_io.find({ - "type": "version", - "parent": {"$in": list(subset_entity_by_ids.keys())} - }).sort("name", -1)) - - subset_id_with_latest_version = [] - last_versions_by_id = {} - for version in sorted_versions: - subset_id = version["parent"] - if subset_id in subset_id_with_latest_version: - continue - subset_id_with_latest_version.append(subset_id) - last_versions_by_id[version["_id"]] = version - - repres = legacy_io.find({ - "type": "representation", - "parent": {"$in": list(last_versions_by_id.keys())} - }) - - output = {} - for repre in repres: - version_id = repre["parent"] - version = last_versions_by_id[version_id] - - subset_id = version["parent"] - subset = subset_entity_by_ids[subset_id] - - asset_id = subset["parent"] - asset = asset_entity_by_ids[asset_id] - - if asset_id not in output: - output[asset_id] = { - "asset_entity": asset, - "subsets": {} - } - - if subset_id not in output[asset_id]["subsets"]: - output[asset_id]["subsets"][subset_id] = { - "subset_entity": subset, - "version": { - "version_entity": version, - "repres": [] - } - } - - output[asset_id]["subsets"][subset_id]["version"]["repres"].append( - repre - ) - - return output - @with_pipeline_io def get_creator_by_name(creator_name, case_sensitive=False): diff --git a/openpype/lib/build_template.py b/openpype/lib/build_template.py new file mode 100644 index 0000000000..7f749cbec2 --- /dev/null +++ b/openpype/lib/build_template.py @@ -0,0 +1,61 @@ +from openpype.pipeline import registered_host +from openpype.lib import classes_from_module +from importlib import import_module + +from .abstract_template_loader import ( + AbstractPlaceholder, + AbstractTemplateLoader) + +from .build_template_exceptions import ( + TemplateLoadingFailed, + TemplateAlreadyImported, + MissingHostTemplateModule, + MissingTemplatePlaceholderClass, + MissingTemplateLoaderClass +) + +_module_path_format = 'openpype.{host}.template_loader' + + +def build_workfile_template(*args): + template_loader = build_template_loader() + try: + template_loader.import_template(template_loader.template_path) + except TemplateAlreadyImported as err: + template_loader.template_already_imported(err) + except TemplateLoadingFailed as err: + template_loader.template_loading_failed(err) + else: + template_loader.populate_template() + + +def update_workfile_template(args): + template_loader = build_template_loader() + template_loader.update_missing_containers() + + +def build_template_loader(): + host_name = registered_host().__name__.partition('.')[2] + module_path = _module_path_format.format(host=host_name) + module = import_module(module_path) + if not module: + raise MissingHostTemplateModule( + "No template loader found for host {}".format(host_name)) + + template_loader_class = classes_from_module( + AbstractTemplateLoader, + module + ) + template_placeholder_class = classes_from_module( + AbstractPlaceholder, + module + ) + + if not template_loader_class: + raise MissingTemplateLoaderClass() + template_loader_class = template_loader_class[0] + + if not template_placeholder_class: + raise MissingTemplatePlaceholderClass() + template_placeholder_class = template_placeholder_class[0] + return template_loader_class(template_placeholder_class) diff --git a/openpype/lib/build_template_exceptions.py b/openpype/lib/build_template_exceptions.py new file mode 100644 index 0000000000..d781eff204 --- /dev/null +++ b/openpype/lib/build_template_exceptions.py @@ -0,0 +1,35 @@ +class MissingHostTemplateModule(Exception): + """Error raised when expected module does not exists""" + pass + + +class MissingTemplatePlaceholderClass(Exception): + """Error raised when module doesn't implement a placeholder class""" + pass + + +class MissingTemplateLoaderClass(Exception): + """Error raised when module doesn't implement a template loader class""" + pass + + +class TemplateNotFound(Exception): + """Exception raised when template does not exist.""" + pass + + +class TemplateProfileNotFound(Exception): + """Exception raised when current profile + doesn't match any template profile""" + pass + + +class TemplateAlreadyImported(Exception): + """Error raised when Template was already imported by host for + this session""" + pass + + +class TemplateLoadingFailed(Exception): + """Error raised whend Template loader was unable to load the template""" + pass \ No newline at end of file From bd884262b0c001715432f28ec1cae6feeeabfed1 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 12:52:44 +0200 Subject: [PATCH 005/282] add template loader module --- openpype/hosts/maya/api/template_loader.py | 242 +++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 openpype/hosts/maya/api/template_loader.py diff --git a/openpype/hosts/maya/api/template_loader.py b/openpype/hosts/maya/api/template_loader.py new file mode 100644 index 0000000000..0e346ca411 --- /dev/null +++ b/openpype/hosts/maya/api/template_loader.py @@ -0,0 +1,242 @@ +from maya import cmds + +from openpype.pipeline import legacy_io +from openpype.lib.abstract_template_loader import ( + AbstractPlaceholder, + AbstractTemplateLoader +) +from openpype.lib.build_template_exceptions import TemplateAlreadyImported + +PLACEHOLDER_SET = 'PLACEHOLDERS_SET' + + +class MayaTemplateLoader(AbstractTemplateLoader): + """Concrete implementation of AbstractTemplateLoader for maya + """ + + def import_template(self, path): + """Import template into current scene. + Block if a template is already loaded. + Args: + path (str): A path to current template (usually given by + get_template_path implementation) + Returns: + bool: Wether the template was succesfully imported or not + """ + if cmds.objExists(PLACEHOLDER_SET): + raise TemplateAlreadyImported( + "Build template already loaded\n" + "Clean scene if needed (File > New Scene)") + + cmds.sets(name=PLACEHOLDER_SET, empty=True) + self.new_nodes = cmds.file(path, i=True, returnNewNodes=True) + cmds.setAttr(PLACEHOLDER_SET + '.hiddenInOutliner', True) + + for set in cmds.listSets(allSets=True): + if (cmds.objExists(set) and + cmds.attributeQuery('id', node=set, exists=True) and + cmds.getAttr(set + '.id') == 'pyblish.avalon.instance'): + if cmds.attributeQuery('asset', node=set, exists=True): + cmds.setAttr( + set + '.asset', + legacy_io.Session['AVALON_ASSET'], type='string' + ) + + return True + + def template_already_imported(self, err_msg): + clearButton = "Clear scene and build" + updateButton = "Update template" + abortButton = "Abort" + + title = "Scene already builded" + message = ( + "It's seems a template was already build for this scene.\n" + "Error message reveived :\n\n\"{}\"".format(err_msg)) + buttons = [clearButton, updateButton, abortButton] + defaultButton = clearButton + cancelButton = abortButton + dismissString = abortButton + answer = cmds.confirmDialog( + t=title, + m=message, + b=buttons, + db=defaultButton, + cb=cancelButton, + ds=dismissString) + + if answer == clearButton: + cmds.file(newFile=True, force=True) + self.import_template(self.template_path) + self.populate_template() + elif answer == updateButton: + self.update_missing_containers() + elif answer == abortButton: + return + + @staticmethod + def get_template_nodes(): + attributes = cmds.ls('*.builder_type', long=True) + return [attribute.rpartition('.')[0] for attribute in attributes] + + def get_loaded_containers_by_id(self): + containers = cmds.sets('AVALON_CONTAINERS', q=True) + return [ + cmds.getAttr(container + '.representation') + for container in containers] + + +class MayaPlaceholder(AbstractPlaceholder): + """Concrete implementation of AbstractPlaceholder for maya + """ + + optional_attributes = {'asset', 'subset', 'hierarchy'} + + def get_data(self, node): + user_data = dict() + for attr in self.attributes.union(self.optional_attributes): + attribute_name = '{}.{}'.format(node, attr) + if not cmds.attributeQuery(attr, node=node, exists=True): + print("{} not found".format(attribute_name)) + continue + user_data[attr] = cmds.getAttr( + attribute_name, + asString=True) + user_data['parent'] = ( + cmds.getAttr(node + '.parent', asString=True) + or node.rpartition('|')[0] or "") + user_data['node'] = node + if user_data['parent']: + siblings = cmds.listRelatives(user_data['parent'], children=True) + else: + siblings = cmds.ls(assemblies=True) + node_shortname = user_data['node'].rpartition('|')[2] + current_index = cmds.getAttr(node + '.index', asString=True) + user_data['index'] = ( + current_index if current_index >= 0 + else siblings.index(node_shortname)) + + self.data = user_data + + def parent_in_hierarchy(self, containers): + """Parent loaded container to placeholder's parent + ie : Set loaded content as placeholder's sibling + Args: + containers (String): Placeholder loaded containers + """ + if not containers: + return + + roots = cmds.sets(containers, q=True) + nodes_to_parent = [] + for root in roots: + if root.endswith("_RN"): + refRoot = cmds.referenceQuery(root, n=True)[0] + refRoot = cmds.listRelatives(refRoot, parent=True) or [refRoot] + nodes_to_parent.extend(refRoot) + elif root in cmds.listSets(allSets=True): + if not cmds.sets(root, q=True): + return + else: + continue + else: + nodes_to_parent.append(root) + + if self.data['parent']: + cmds.parent(nodes_to_parent, self.data['parent']) + # Move loaded nodes to correct index in outliner hierarchy + placeholder_node = self.data['node'] + placeholder_form = cmds.xform( + placeholder_node, + q=True, + matrix=True, + worldSpace=True + ) + for node in set(nodes_to_parent): + cmds.reorder(node, front=True) + cmds.reorder(node, relative=self.data['index']) + cmds.xform(node, matrix=placeholder_form, ws=True) + + holding_sets = cmds.listSets(object=placeholder_node) + if not holding_sets: + return + for holding_set in holding_sets: + cmds.sets(roots, forceElement=holding_set) + + def clean(self): + """Hide placeholder, parent them to root + add them to placeholder set and register placeholder's parent + to keep placeholder info available for future use + """ + node = self.data['node'] + if self.data['parent']: + cmds.setAttr(node + '.parent', self.data['parent'], type='string') + if cmds.getAttr(node + '.index') < 0: + cmds.setAttr(node + '.index', self.data['index']) + + holding_sets = cmds.listSets(object=node) + if holding_sets: + for set in holding_sets: + cmds.sets(node, remove=set) + + if cmds.listRelatives(node, p=True): + node = cmds.parent(node, world=True)[0] + cmds.sets(node, addElement=PLACEHOLDER_SET) + cmds.hide(node) + cmds.setAttr(node + '.hiddenInOutliner', True) + + def convert_to_db_filters(self, current_asset, linked_asset): + if self.data['builder_type'] == "context_asset": + return [ + { + "type": "representation", + "context.asset": { + "$eq": current_asset, + "$regex": self.data['asset'] + }, + "context.subset": {"$regex": self.data['subset']}, + "context.hierarchy": {"$regex": self.data['hierarchy']}, + "context.representation": self.data['representation'], + "context.family": self.data['family'], + } + ] + + elif self.data['builder_type'] == "linked_asset": + return [ + { + "type": "representation", + "context.asset": { + "$eq": asset_name, + "$regex": self.data['asset'] + }, + "context.subset": {"$regex": self.data['subset']}, + "context.hierarchy": {"$regex": self.data['hierarchy']}, + "context.representation": self.data['representation'], + "context.family": self.data['family'], + } for asset_name in linked_asset + ] + + else: + return [ + { + "type": "representation", + "context.asset": {"$regex": self.data['asset']}, + "context.subset": {"$regex": self.data['subset']}, + "context.hierarchy": {"$regex": self.data['hierarchy']}, + "context.representation": self.data['representation'], + "context.family": self.data['family'], + } + ] + + def err_message(self): + return ( + "Error while trying to load a representation.\n" + "Either the subset wasn't published or the template is malformed." + "\n\n" + "Builder was looking for :\n{attributes}".format( + attributes="\n".join([ + "{}: {}".format(key.title(), value) + for key, value in self.data.items()] + ) + ) + ) From 60cc108251db884a04cef1d2ea29a558a7750b8c Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 14:28:28 +0200 Subject: [PATCH 006/282] add build workfile in menu --- openpype/hosts/maya/api/menu.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index 8beaf491bb..c66eeb449f 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -6,7 +6,13 @@ from Qt import QtWidgets, QtGui import maya.utils import maya.cmds as cmds -from openpype.api import BuildWorkfile +from openpype.api import ( + BuildWorkfile, + # build_workfile_template + # update_workfile_template +) + +from openpype.lib.build_template import build_workfile_template, update_workfile_template from openpype.settings import get_project_settings from openpype.pipeline import legacy_io from openpype.tools.utils import host_tools @@ -158,6 +164,16 @@ def install(): parent=builder_menu, command=lambda *args: update_placeholder() ) + cmds.menuItem( + "Build Workfile from template", + parent=builder_menu, + command=lambda *args: build_workfile_template() + ) + cmds.menuItem( + "Update Workfile from template", + parent=builder_menu, + command=lambda *args: update_workfile_template() + ) cmds.setParent(MENU_NAME, menu=True) From aaa1f13f9d0ae038f70eb2cdc21cba56f92b97dd Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 16:35:05 +0200 Subject: [PATCH 007/282] delete the task_name verification since it does not exists in the maya menu settings --- openpype/lib/abstract_template_loader.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 6888cbf757..2dfec1a006 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -157,8 +157,6 @@ class AbstractTemplateLoader: for prf in profiles: if prf['task_types'] and task_type not in prf['task_types']: continue - if prf['task_names'] and task_name not in prf['task_names']: - continue path = prf['path'] break else: # IF no template were found (no break happened) @@ -253,7 +251,7 @@ class AbstractTemplateLoader: linked_assets) # get representation by assets for db_filter in placeholder_db_filters: - placeholder_representations = list(avalon.io.find(db_filter)) + placeholder_representations = list(legacy_io.find(db_filter)) for representation in reduce(update_representations, placeholder_representations, dict()).values(): From c2aca3422c8c2e29a169f9550e7e1719733f7ec4 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 16:38:47 +0200 Subject: [PATCH 008/282] rename correctly attributes to correpsond the ones in the placeholders --- openpype/lib/abstract_template_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 2dfec1a006..628d0bd895 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -357,7 +357,7 @@ class AbstractPlaceholder: parent_in_hierachy: """ - attributes = {'builder_type', 'op_family', 'op_representation', + attributes = {'builder_type', 'family', 'representation', 'order', 'loader', 'loader_args'} optional_attributes = {} From 95d3686889470a8ad6d677b949a86cab094e47ea Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Fri, 27 May 2022 12:44:51 +0200 Subject: [PATCH 009/282] create placeholder name dynamically from arguments --- .../hosts/maya/api/lib_template_builder.py | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index d8772f3f9a..ee78f19a3e 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -1,3 +1,4 @@ +import json from collections import OrderedDict import maya.cmds as cmds @@ -30,17 +31,20 @@ def create_placeholder(): if not args: return # operation canceled, no locator created - selection = cmds.ls(selection=True) - placeholder = cmds.spaceLocator(name="_TEMPLATE_PLACEHOLDER_")[0] - if selection: - cmds.parent(placeholder, selection[0]) # custom arg parse to force empty data query # and still imprint them on placeholder # and getting items when arg is of type Enumerator - options = OrderedDict() - for arg in args: - if not type(arg) == qargparse.Separator: - options[str(arg)] = arg._data.get("items") or arg.read() + options = create_options(args) + + # create placeholder name dynamically from args and options + placeholder_name = create_placeholder_name(args, options) + + selection = cmds.ls(selection=True) + placeholder = cmds.spaceLocator(name=placeholder_name.capitalize())[0] + + if selection: + cmds.parent(placeholder, selection[0]) + imprint(placeholder, options) # Some tweaks because imprint force enums to to default value so we get # back arg read and force them to attributes @@ -49,13 +53,42 @@ def create_placeholder(): # Add helper attributes to keep placeholder info cmds.addAttr( placeholder, longName="parent", - hidden=True, dataType="string") + hidden=False, dataType="string") cmds.addAttr( placeholder, longName="index", - hidden=True, attributeType="short", + hidden=False, attributeType="short", defaultValue=-1) +def create_options(args): + options = OrderedDict() + for arg in args: + if not type(arg) == qargparse.Separator: + options[str(arg)] = arg._data.get("items") or arg.read() + return options + + +def create_placeholder_name(args, options): + placeholder_builder_type = [ + arg.read() for arg in args if 'builder_type' in str(arg) + ][0] + placeholder_family = options['family'] + placeholder_name = placeholder_builder_type.split('_') + placeholder_name.insert(1, placeholder_family) + + # add loader arguments if any + if options['loader_args']: + pos = 2 + loader_args = options['loader_args'].replace('\'', '\"') + loader_args = json.loads(loader_args) + values = [v for v in loader_args.values()] + for i in range(len(values)): + placeholder_name.insert(i + pos, values[i]) + placeholder_name = '_'.join(placeholder_name) + + return placeholder_name + + def update_placeholder(): placeholder = cmds.ls(selection=True) if len(placeholder) == 0: From e29d4e5699e6dace616933317c57fcc9bc43c878 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 30 May 2022 14:19:12 +0200 Subject: [PATCH 010/282] minor refactoring --- .../hosts/maya/api/lib_template_builder.py | 19 ++++++++++++++----- openpype/hosts/maya/api/menu.py | 11 +++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index ee78f19a3e..bec0f1fc66 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -52,12 +52,21 @@ def create_placeholder(): # Add helper attributes to keep placeholder info cmds.addAttr( - placeholder, longName="parent", - hidden=False, dataType="string") + placeholder, + longName="parent", + hidden=False, + dataType="string" + ) cmds.addAttr( - placeholder, longName="index", - hidden=False, attributeType="short", - defaultValue=-1) + placeholder, + longName="index", + hidden=False, + attributeType="short", + defaultValue=-1 + ) + + parents = cmds.ls(selection[0], long=True) + cmds.setAttr(placeholder + '.parent', parents[0], type="string") def create_options(args): diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index c66eeb449f..1337713561 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -6,13 +6,12 @@ from Qt import QtWidgets, QtGui import maya.utils import maya.cmds as cmds -from openpype.api import ( - BuildWorkfile, - # build_workfile_template - # update_workfile_template -) +from openpype.api import BuildWorkfile -from openpype.lib.build_template import build_workfile_template, update_workfile_template +from openpype.lib.build_template import ( + build_workfile_template, + update_workfile_template +) from openpype.settings import get_project_settings from openpype.pipeline import legacy_io from openpype.tools.utils import host_tools From 28518eeb21f2a9ef56c32c0009ce09aecf871a86 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 30 May 2022 14:20:31 +0200 Subject: [PATCH 011/282] change load method since avalon doesn't exsist anymore --- openpype/lib/abstract_template_loader.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 628d0bd895..77ba04c4db 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -5,11 +5,10 @@ import traceback import six -import openpype from openpype.settings import get_project_settings from openpype.lib import Anatomy, get_linked_assets, get_loaders_by_name from openpype.api import PypeLogger as Logger -from openpype.pipeline import legacy_io +from openpype.pipeline import legacy_io, load from functools import reduce @@ -271,9 +270,10 @@ class AbstractTemplateLoader: pass def load(self, placeholder, loaders_by_name, last_representation): - return openpype.pipeline.load( + repre = load.get_representation_context(last_representation) + return load.load_with_repre_context( loaders_by_name[placeholder.loader], - last_representation['_id'], + repre, options=parse_loader_args(placeholder.data['loader_args'])) def load_succeed(self, placeholder, container): From b65a1d4e79e3fa2ff4ca11392f9ccbce68a19a78 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 30 May 2022 14:53:49 +0200 Subject: [PATCH 012/282] fix update placeholder --- .../hosts/maya/api/lib_template_builder.py | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index bec0f1fc66..2efc210d10 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -69,14 +69,6 @@ def create_placeholder(): cmds.setAttr(placeholder + '.parent', parents[0], type="string") -def create_options(args): - options = OrderedDict() - for arg in args: - if not type(arg) == qargparse.Separator: - options[str(arg)] = arg._data.get("items") or arg.read() - return options - - def create_placeholder_name(args, options): placeholder_builder_type = [ arg.read() for arg in args if 'builder_type' in str(arg) @@ -112,12 +104,38 @@ def update_placeholder(): if not args: return # operation canceled + options = create_options(args) + + imprint(placeholder, options) + imprint_enum(placeholder, args) + + cmds.addAttr( + placeholder, + longName="parent", + hidden=False, + dataType="string" + ) + cmds.addAttr( + placeholder, + longName="index", + hidden=False, + attributeType="short", + defaultValue=-1 + ) + + selected = cmds.ls(selection=True, long=True) + selected = selected[0].split('|')[-2] + selected = cmds.ls(selected) + parents = cmds.ls(selected, long=True) + cmds.setAttr(placeholder + '.parent', parents[0], type="string") + + +def create_options(args): options = OrderedDict() for arg in args: if not type(arg) == qargparse.Separator: options[str(arg)] = arg._data.get("items") or arg.read() - imprint(placeholder, options) - imprint_enum(placeholder, args) + return options def imprint_enum(placeholder, args): From b095249fb859c9845d00efb8d69bd515867c6e94 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Thu, 2 Jun 2022 10:40:44 +0200 Subject: [PATCH 013/282] change menu command for build and update workfile from template --- openpype/hosts/maya/api/menu.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index 1337713561..c0bad7092f 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -166,12 +166,12 @@ def install(): cmds.menuItem( "Build Workfile from template", parent=builder_menu, - command=lambda *args: build_workfile_template() + command=build_workfile_template ) cmds.menuItem( "Update Workfile from template", parent=builder_menu, - command=lambda *args: update_workfile_template() + command=update_workfile_template ) cmds.setParent(MENU_NAME, menu=True) From 79c9dc94528ff8f3ae216f106b2225ae790fb044 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Thu, 2 Jun 2022 12:22:06 +0200 Subject: [PATCH 014/282] get full name placeholder to avoid any conflict between two placeholders with same short name --- .../hosts/maya/api/lib_template_builder.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index 2efc210d10..108988a676 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -40,33 +40,37 @@ def create_placeholder(): placeholder_name = create_placeholder_name(args, options) selection = cmds.ls(selection=True) - placeholder = cmds.spaceLocator(name=placeholder_name.capitalize())[0] + placeholder = cmds.spaceLocator(name=placeholder_name)[0] + + # get the long name of the placeholder (with the groups) + placeholder_full_name = cmds.ls(selection[0], long=True)[0] + '|' + placeholder.replace('|', '') if selection: cmds.parent(placeholder, selection[0]) - imprint(placeholder, options) + imprint(placeholder_full_name, options) + # Some tweaks because imprint force enums to to default value so we get # back arg read and force them to attributes - imprint_enum(placeholder, args) + imprint_enum(placeholder_full_name, args) # Add helper attributes to keep placeholder info cmds.addAttr( - placeholder, + placeholder_full_name, longName="parent", - hidden=False, + hidden=True, dataType="string" ) cmds.addAttr( - placeholder, + placeholder_full_name, longName="index", - hidden=False, + hidden=True, attributeType="short", defaultValue=-1 ) parents = cmds.ls(selection[0], long=True) - cmds.setAttr(placeholder + '.parent', parents[0], type="string") + cmds.setAttr(placeholder_full_name + '.parent', parents[0], type="string") def create_placeholder_name(args, options): @@ -75,7 +79,10 @@ def create_placeholder_name(args, options): ][0] placeholder_family = options['family'] placeholder_name = placeholder_builder_type.split('_') - placeholder_name.insert(1, placeholder_family) + + # add famlily in any + if placeholder_family: + placeholder_name.insert(1, placeholder_family) # add loader arguments if any if options['loader_args']: @@ -85,9 +92,10 @@ def create_placeholder_name(args, options): values = [v for v in loader_args.values()] for i in range(len(values)): placeholder_name.insert(i + pos, values[i]) + placeholder_name = '_'.join(placeholder_name) - return placeholder_name + return placeholder_name.capitalize() def update_placeholder(): @@ -112,13 +120,13 @@ def update_placeholder(): cmds.addAttr( placeholder, longName="parent", - hidden=False, + hidden=True, dataType="string" ) cmds.addAttr( placeholder, longName="index", - hidden=False, + hidden=True, attributeType="short", defaultValue=-1 ) From aa7e7093df8d72357118bdb34dbe03e4e73d6801 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 8 Jun 2022 12:46:24 +0200 Subject: [PATCH 015/282] add a log if no reprensation found for the current placeholder --- openpype/lib/abstract_template_loader.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 77ba04c4db..cd0416426c 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -19,6 +19,10 @@ from openpype.lib.build_template_exceptions import ( TemplateNotFound ) +import logging + +log = logging.getLogger(__name__) + def update_representations(entities, entity): if entity['context']['subset'] not in entities: @@ -215,8 +219,15 @@ class AbstractTemplateLoader: current_asset, linked_assets ) - for representation in placeholder_representations: + if not placeholder_representations: + self.log.info( + "There's no representation for this placeholder: " + "{}".format(placeholder.data['node']) + ) + continue + + for representation in placeholder_representations: self.preload(placeholder, loaders_by_name, representation) if self.load_data_is_incorrect( From f50999d0927bf533a74417479e4cdb4a06b32b3d Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 8 Jun 2022 12:53:59 +0200 Subject: [PATCH 016/282] add debug logs for placeholders --- openpype/lib/abstract_template_loader.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index cd0416426c..159d5c8f6c 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -213,7 +213,13 @@ class AbstractTemplateLoader: ignored_ids = ignored_ids or [] placeholders = self.get_placeholders() + self.log.debug("Placeholders found in template: {}".format( + [placeholder.data['node'] for placeholder in placeholders] + )) for placeholder in placeholders: + self.log.debug("Start to processing placeholder {}".format( + placeholder.data['node'] + )) placeholder_representations = self.get_placeholder_representations( placeholder, current_asset, From edb55949df619a81c1828571030634a4b0c49584 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 24 May 2022 12:56:24 +0200 Subject: [PATCH 017/282] refactor avalon imports from lib_template_builder --- .../hosts/maya/api/lib_template_builder.py | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 openpype/hosts/maya/api/lib_template_builder.py diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py new file mode 100644 index 0000000000..172a6f9b2b --- /dev/null +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -0,0 +1,184 @@ +from collections import OrderedDict +import maya.cmds as cmds + +import qargparse +from openpype.tools.utils.widgets import OptionDialog +from lib import get_main_window, imprint + +# To change as enum +build_types = ["context_asset", "linked_asset", "all_assets"] + + +def get_placeholder_attributes(node): + return { + attr: cmds.getAttr("{}.{}".format(node, attr)) + for attr in cmds.listAttr(node, userDefined=True)} + + +def delete_placeholder_attributes(node): + ''' + function to delete all extra placeholder attributes + ''' + extra_attributes = get_placeholder_attributes(node) + for attribute in extra_attributes: + cmds.deleteAttr(node + '.' + attribute) + + +def create_placeholder(): + args = placeholder_window() + + if not args: + return # operation canceled, no locator created + + selection = cmds.ls(selection=True) + placeholder = cmds.spaceLocator(name="_TEMPLATE_PLACEHOLDER_")[0] + if selection: + cmds.parent(placeholder, selection[0]) + # custom arg parse to force empty data query + # and still imprint them on placeholder + # and getting items when arg is of type Enumerator + options = OrderedDict() + for arg in args: + if not type(arg) == qargparse.Separator: + options[str(arg)] = arg._data.get("items") or arg.read() + imprint(placeholder, options) + # Some tweaks because imprint force enums to to default value so we get + # back arg read and force them to attributes + imprint_enum(placeholder, args) + + # Add helper attributes to keep placeholder info + cmds.addAttr( + placeholder, longName="parent", + hidden=True, dataType="string") + cmds.addAttr( + placeholder, longName="index", + hidden=True, attributeType="short", + defaultValue=-1) + + +def update_placeholder(): + placeholder = cmds.ls(selection=True) + if len(placeholder) == 0: + raise ValueError("No node selected") + if len(placeholder) > 1: + raise ValueError("Too many selected nodes") + placeholder = placeholder[0] + + args = placeholder_window(get_placeholder_attributes(placeholder)) + # delete placeholder attributes + delete_placeholder_attributes(placeholder) + if not args: + return # operation canceled + + options = OrderedDict() + for arg in args: + if not type(arg) == qargparse.Separator: + options[str(arg)] = arg._data.get("items") or arg.read() + imprint(placeholder, options) + imprint_enum(placeholder, args) + + +def imprint_enum(placeholder, args): + """ + Imprint method doesn't act properly with enums. + Replacing the functionnality with this for now + """ + enum_values = {str(arg): arg.read() + for arg in args if arg._data.get("items")} + string_to_value_enum_table = { + build: i for i, build + in enumerate(build_types)} + for key, value in enum_values.items(): + cmds.setAttr( + placeholder + "." + key, + string_to_value_enum_table[value]) + + +def placeholder_window(options=None): + options = options or dict() + dialog = OptionDialog(parent=get_main_window()) + dialog.setWindowTitle("Create Placeholder") + + args = [ + qargparse.Separator("Main attributes"), + qargparse.Enum( + "builder_type", + label="Asset Builder Type", + default=options.get("builder_type", 0), + items=build_types, + help="""Asset Builder Type +Builder type describe what template loader will look for. +context_asset : Template loader will look for subsets of +current context asset (Asset bob will find asset) +linked_asset : Template loader will look for assets linked +to current context asset. +Linked asset are looked in avalon database under field "inputLinks" +""" + ), + qargparse.String( + "family", + default=options.get("family", ""), + label="OpenPype Family", + placeholder="ex: model, look ..."), + qargparse.String( + "representation", + default=options.get("representation", ""), + label="OpenPype Representation", + placeholder="ex: ma, abc ..."), + qargparse.String( + "loader", + default=options.get("loader", ""), + label="Loader", + placeholder="ex: ReferenceLoader, LightLoader ...", + help="""Loader +Defines what openpype loader will be used to load assets. +Useable loader depends on current host's loader list. +Field is case sensitive. +"""), + qargparse.String( + "loader_args", + default=options.get("loader_args", ""), + label="Loader Arguments", + placeholder='ex: {"camera":"persp", "lights":True}', + help="""Loader +Defines a dictionnary of arguments used to load assets. +Useable arguments depend on current placeholder Loader. +Field should be a valid python dict. Anything else will be ignored. +"""), + qargparse.Integer( + "order", + default=options.get("order", 0), + min=0, + max=999, + label="Order", + placeholder="ex: 0, 100 ... (smallest order loaded first)", + help="""Order +Order defines asset loading priority (0 to 999) +Priority rule is : "lowest is first to load"."""), + qargparse.Separator( + "Optional attributes"), + qargparse.String( + "asset", + default=options.get("asset", ""), + label="Asset filter", + placeholder="regex filtering by asset name", + help="Filtering assets by matching field regex to asset's name"), + qargparse.String( + "subset", + default=options.get("subset", ""), + label="Subset filter", + placeholder="regex filtering by subset name", + help="Filtering assets by matching field regex to subset's name"), + qargparse.String( + "hierarchy", + default=options.get("hierarchy", ""), + label="Hierarchy filter", + placeholder="regex filtering by asset's hierarchy", + help="Filtering assets by matching field asset's hierarchy") + ] + dialog.create(args) + + if not dialog.exec_(): + return None + + return args From 15e51cd6a640aea61eb927b84ce6b48990d206f3 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 24 May 2022 14:58:27 +0200 Subject: [PATCH 018/282] add the templated wrokfile build schema for maya --- .../defaults/project_settings/maya.json | 8 +++++ .../projects_schema/schema_project_maya.json | 4 +++ .../schema_templated_workfile_build.json | 29 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index efd22e13c8..2e0e30b74b 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -718,6 +718,14 @@ } ] }, + "templated_workfile_build": { + "profiles": [ + { + "task_types": [], + "path": "/path/to/your/template" + } + ] + }, "filters": { "preset 1": { "ValidateNoAnimation": false, diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index 40e98b0333..d137049e9e 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -73,6 +73,10 @@ "type": "schema", "name": "schema_workfile_build" }, + { + "type": "schema", + "name": "schema_templated_workfile_build" + }, { "type": "schema", "name": "schema_publish_gui_filter" 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 new file mode 100644 index 0000000000..01e74f64b0 --- /dev/null +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_templated_workfile_build.json @@ -0,0 +1,29 @@ +{ + "type": "dict", + "collapsible": true, + "key": "templated_workfile_build", + "label": "Templated Workfile Build Settings", + "children": [ + { + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": { + "type": "dict", + "children": [ + { + "key": "task_types", + "label": "Task types", + "type": "task-types-enum" + }, + { + "key": "path", + "label": "Path to template", + "type": "text", + "object_type": "text" + } + ] + } + } + ] +} From c8c36144cb26df5d0024fcd02df265736bbd209f Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 24 May 2022 17:28:42 +0200 Subject: [PATCH 019/282] add placeholder menu to maya --- .../hosts/maya/api/lib_template_builder.py | 2 +- openpype/hosts/maya/api/menu.py | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index 172a6f9b2b..d8772f3f9a 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -3,7 +3,7 @@ import maya.cmds as cmds import qargparse from openpype.tools.utils.widgets import OptionDialog -from lib import get_main_window, imprint +from .lib import get_main_window, imprint # To change as enum build_types = ["context_asset", "linked_asset", "all_assets"] diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index 97f06c43af..8beaf491bb 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -11,8 +11,10 @@ from openpype.settings import get_project_settings from openpype.pipeline import legacy_io from openpype.tools.utils import host_tools from openpype.hosts.maya.api import lib + from .lib import get_main_window, IS_HEADLESS from .commands import reset_frame_range +from .lib_template_builder import create_placeholder, update_placeholder log = logging.getLogger(__name__) @@ -139,6 +141,24 @@ def install(): parent_widget ) ) + + builder_menu = cmds.menuItem( + "Template Builder", + subMenu=True, + tearOff=True, + parent=MENU_NAME + ) + cmds.menuItem( + "Create Placeholder", + parent=builder_menu, + command=lambda *args: create_placeholder() + ) + cmds.menuItem( + "Update Placeholder", + parent=builder_menu, + command=lambda *args: update_placeholder() + ) + cmds.setParent(MENU_NAME, menu=True) def add_scripts_menu(): From 770b6d3ab2ee9e3bdf460cee4fdba96d67e44fb2 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 12:25:39 +0200 Subject: [PATCH 020/282] setup build template in openpype lib --- openpype/lib/__init__.py | 2 + openpype/lib/abstract_template_loader.py | 447 ++++++++++++++++++++++ openpype/lib/avalon_context.py | 222 +++++------ openpype/lib/build_template.py | 61 +++ openpype/lib/build_template_exceptions.py | 35 ++ 5 files changed, 660 insertions(+), 107 deletions(-) create mode 100644 openpype/lib/abstract_template_loader.py create mode 100644 openpype/lib/build_template.py create mode 100644 openpype/lib/build_template_exceptions.py diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 8d4e733b7d..8f3919d378 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -136,6 +136,7 @@ from .avalon_context import ( create_workfile_doc, save_workfile_data_to_doc, get_workfile_doc, + get_loaders_by_name, BuildWorkfile, @@ -308,6 +309,7 @@ __all__ = [ "create_workfile_doc", "save_workfile_data_to_doc", "get_workfile_doc", + "get_loaders_by_name", "BuildWorkfile", diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py new file mode 100644 index 0000000000..6888cbf757 --- /dev/null +++ b/openpype/lib/abstract_template_loader.py @@ -0,0 +1,447 @@ +import os +from abc import ABCMeta, abstractmethod + +import traceback + +import six + +import openpype +from openpype.settings import get_project_settings +from openpype.lib import Anatomy, get_linked_assets, get_loaders_by_name +from openpype.api import PypeLogger as Logger +from openpype.pipeline import legacy_io + +from functools import reduce + +from openpype.lib.build_template_exceptions import ( + TemplateAlreadyImported, + TemplateLoadingFailed, + TemplateProfileNotFound, + TemplateNotFound +) + + +def update_representations(entities, entity): + if entity['context']['subset'] not in entities: + entities[entity['context']['subset']] = entity + else: + current = entities[entity['context']['subset']] + incomming = entity + entities[entity['context']['subset']] = max( + current, incomming, + key=lambda entity: entity["context"].get("version", -1)) + + return entities + + +def parse_loader_args(loader_args): + if not loader_args: + return dict() + try: + parsed_args = eval(loader_args) + if not isinstance(parsed_args, dict): + return dict() + else: + return parsed_args + except Exception as err: + print( + "Error while parsing loader arguments '{}'.\n{}: {}\n\n" + "Continuing with default arguments. . .".format( + loader_args, + err.__class__.__name__, + err)) + return dict() + + +@six.add_metaclass(ABCMeta) +class AbstractTemplateLoader: + """ + Abstraction of Template Loader. + Properties: + template_path : property to get current template path + Methods: + import_template : Abstract Method. Used to load template, + depending on current host + get_template_nodes : Abstract Method. Used to query nodes acting + as placeholders. Depending on current host + """ + + def __init__(self, placeholder_class): + + self.loaders_by_name = get_loaders_by_name() + self.current_asset = legacy_io.Session["AVALON_ASSET"] + self.project_name = legacy_io.Session["AVALON_PROJECT"] + self.host_name = legacy_io.Session["AVALON_APP"] + self.task_name = legacy_io.Session["AVALON_TASK"] + self.placeholder_class = placeholder_class + self.current_asset_docs = legacy_io.find_one({ + "type": "asset", + "name": self.current_asset + }) + self.task_type = ( + self.current_asset_docs + .get("data", {}) + .get("tasks", {}) + .get(self.task_name, {}) + .get("type") + ) + + self.log = Logger().get_logger("BUILD TEMPLATE") + + self.log.info( + "BUILDING ASSET FROM TEMPLATE :\n" + "Starting templated build for {asset} in {project}\n\n" + "Asset : {asset}\n" + "Task : {task_name} ({task_type})\n" + "Host : {host}\n" + "Project : {project}\n".format( + asset=self.current_asset, + host=self.host_name, + project=self.project_name, + task_name=self.task_name, + task_type=self.task_type + )) + # Skip if there is no loader + if not self.loaders_by_name: + self.log.warning( + "There is no registered loaders. No assets will be loaded") + return + + def template_already_imported(self, err_msg): + """In case template was already loaded. + Raise the error as a default action. + Override this method in your template loader implementation + to manage this case.""" + self.log.error("{}: {}".format( + err_msg.__class__.__name__, + err_msg)) + raise TemplateAlreadyImported(err_msg) + + def template_loading_failed(self, err_msg): + """In case template loading failed + Raise the error as a default action. + Override this method in your template loader implementation + to manage this case. + """ + self.log.error("{}: {}".format( + err_msg.__class__.__name__, + err_msg)) + raise TemplateLoadingFailed(err_msg) + + @property + def template_path(self): + """ + Property returning template path. Avoiding setter. + Getting template path from open pype settings based on current avalon + session and solving the path variables if needed. + Returns: + str: Solved template path + Raises: + TemplateProfileNotFound: No profile found from settings for + current avalon session + KeyError: Could not solve path because a key does not exists + in avalon context + TemplateNotFound: Solved path does not exists on current filesystem + """ + project_name = self.project_name + host_name = self.host_name + task_name = self.task_name + task_type = self.task_type + + anatomy = Anatomy(project_name) + project_settings = get_project_settings(project_name) + + build_info = project_settings[host_name]['templated_workfile_build'] + profiles = build_info['profiles'] + + for prf in profiles: + if prf['task_types'] and task_type not in prf['task_types']: + continue + if prf['task_names'] and task_name not in prf['task_names']: + continue + path = prf['path'] + break + else: # IF no template were found (no break happened) + raise TemplateProfileNotFound( + "No matching profile found for task '{}' of type '{}' " + "with host '{}'".format(task_name, task_type, host_name) + ) + if path is None: + raise TemplateLoadingFailed( + "Template path is not set.\n" + "Path need to be set in {}\\Template Workfile Build " + "Settings\\Profiles".format(host_name.title())) + try: + solved_path = None + while True: + solved_path = anatomy.path_remapper(path) + if solved_path is None: + solved_path = path + if solved_path == path: + break + path = solved_path + except KeyError as missing_key: + raise KeyError( + "Could not solve key '{}' in template path '{}'".format( + missing_key, path)) + finally: + solved_path = os.path.normpath(solved_path) + + if not os.path.exists(solved_path): + raise TemplateNotFound( + "Template found in openPype settings for task '{}' with host " + "'{}' does not exists. (Not found : {})".format( + task_name, host_name, solved_path)) + + self.log.info("Found template at : '{}'".format(solved_path)) + + return solved_path + + def populate_template(self, ignored_ids=None): + """ + Use template placeholders to load assets and parent them in hierarchy + Arguments : + ignored_ids : + Returns: + None + """ + loaders_by_name = self.loaders_by_name + current_asset = self.current_asset + linked_assets = [asset['name'] for asset + in get_linked_assets(self.current_asset_docs)] + + ignored_ids = ignored_ids or [] + placeholders = self.get_placeholders() + for placeholder in placeholders: + placeholder_representations = self.get_placeholder_representations( + placeholder, + current_asset, + linked_assets + ) + for representation in placeholder_representations: + + self.preload(placeholder, loaders_by_name, representation) + + if self.load_data_is_incorrect( + placeholder, + representation, + ignored_ids): + continue + + self.log.info( + "Loading {}_{} with loader {}\n" + "Loader arguments used : {}".format( + representation['context']['asset'], + representation['context']['subset'], + placeholder.loader, + placeholder.data['loader_args'])) + + try: + container = self.load( + placeholder, loaders_by_name, representation) + except Exception: + self.load_failed(placeholder, representation) + else: + self.load_succeed(placeholder, container) + finally: + self.postload(placeholder) + + def get_placeholder_representations( + self, placeholder, current_asset, linked_assets): + placeholder_db_filters = placeholder.convert_to_db_filters( + current_asset, + linked_assets) + # get representation by assets + for db_filter in placeholder_db_filters: + placeholder_representations = list(avalon.io.find(db_filter)) + for representation in reduce(update_representations, + placeholder_representations, + dict()).values(): + yield representation + + def load_data_is_incorrect( + self, placeholder, last_representation, ignored_ids): + if not last_representation: + self.log.warning(placeholder.err_message()) + return True + if (str(last_representation['_id']) in ignored_ids): + print("Ignoring : ", last_representation['_id']) + return True + return False + + def preload(self, placeholder, loaders_by_name, last_representation): + pass + + def load(self, placeholder, loaders_by_name, last_representation): + return openpype.pipeline.load( + loaders_by_name[placeholder.loader], + last_representation['_id'], + options=parse_loader_args(placeholder.data['loader_args'])) + + def load_succeed(self, placeholder, container): + placeholder.parent_in_hierarchy(container) + + def load_failed(self, placeholder, last_representation): + self.log.warning("Got error trying to load {}:{} with {}\n\n" + "{}".format(last_representation['context']['asset'], + last_representation['context']['subset'], + placeholder.loader, + traceback.format_exc())) + + def postload(self, placeholder): + placeholder.clean() + + def update_missing_containers(self): + loaded_containers_ids = self.get_loaded_containers_by_id() + self.populate_template(ignored_ids=loaded_containers_ids) + + def get_placeholders(self): + placeholder_class = self.placeholder_class + placeholders = map(placeholder_class, self.get_template_nodes()) + valid_placeholders = filter(placeholder_class.is_valid, placeholders) + sorted_placeholders = sorted(valid_placeholders, + key=placeholder_class.order) + return sorted_placeholders + + @abstractmethod + def get_loaded_containers_by_id(self): + """ + Collect already loaded containers for updating scene + Return: + dict (string, node): A dictionnary id as key + and containers as value + """ + pass + + @abstractmethod + def import_template(self, template_path): + """ + Import template in current host + Args: + template_path (str): fullpath to current task and + host's template file + Return: + None + """ + pass + + @abstractmethod + def get_template_nodes(self): + """ + Returning a list of nodes acting as host placeholders for + templating. The data representation is by user. + AbstractLoadTemplate (and LoadTemplate) won't directly manipulate nodes + Args : + None + Returns: + list(AnyNode): Solved template path + """ + pass + + +@six.add_metaclass(ABCMeta) +class AbstractPlaceholder: + """Abstraction of placeholders logic + Properties: + attributes: A list of mandatory attribute to decribe placeholder + and assets to load. + optional_attributes: A list of optional attribute to decribe + placeholder and assets to load + loader: Name of linked loader to use while loading assets + is_context: Is placeholder linked + to context asset (or to linked assets) + Methods: + is_repres_valid: + loader: + order: + is_valid: + get_data: + parent_in_hierachy: + """ + + attributes = {'builder_type', 'op_family', 'op_representation', + 'order', 'loader', 'loader_args'} + optional_attributes = {} + + def __init__(self, node): + self.get_data(node) + + def order(self): + """Get placeholder order. + Order is used to sort them by priority + Priority is lowset first, highest last + (ex: + 1: First to load + 100: Last to load) + Returns: + Int: Order priority + """ + return self.data.get('order') + + @property + def loader(self): + """Return placeholder loader type + Returns: + string: Loader name + """ + return self.data.get('loader') + + @property + def is_context(self): + """Return placeholder type + context_asset: For loading current asset + linked_asset: For loading linked assets + Returns: + bool: true if placeholder is a context placeholder + """ + return self.data.get('builder_type') == 'context_asset' + + def is_valid(self): + """Test validity of placeholder + i.e.: every attributes exists in placeholder data + Returns: + Bool: True if every attributes are a key of data + """ + if set(self.attributes).issubset(self.data.keys()): + print("Valid placeholder : {}".format(self.data["node"])) + return True + print("Placeholder is not valid : {}".format(self.data["node"])) + return False + + @abstractmethod + def parent_in_hierarchy(self, containers): + """Place container in correct hierarchy + given by placeholder + Args: + containers (String): Container name returned back by + placeholder's loader. + """ + pass + + @abstractmethod + def clean(self): + """Clean placeholder from hierarchy after loading assets. + """ + pass + + @abstractmethod + def convert_to_db_filters(self, current_asset, linked_asset): + """map current placeholder data as a db filter + args: + current_asset (String): Name of current asset in context + linked asset (list[String]) : Names of assets linked to + current asset in context + Returns: + dict: a dictionnary describing a filter to look for asset in + a database + """ + pass + + @abstractmethod + def get_data(self, node): + """ + Collect placeholders information. + Args: + node (AnyNode): A unique node decided by Placeholder implementation + """ + pass diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 9d8a92cfe9..8c80b4a4ae 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -15,6 +15,7 @@ from openpype.settings import ( get_project_settings, get_system_settings ) + from .anatomy import Anatomy from .profiles_filtering import filter_profiles from .events import emit_event @@ -922,6 +923,118 @@ def save_workfile_data_to_doc(workfile_doc, data, dbcon=None): ) +@with_pipeline_io +def collect_last_version_repres(asset_entities): + """Collect subsets, versions and representations for asset_entities. + + Args: + asset_entities (list): Asset entities for which want to find data + + Returns: + (dict): collected entities + + Example output: + ``` + { + {Asset ID}: { + "asset_entity": , + "subsets": { + {Subset ID}: { + "subset_entity": , + "version": { + "version_entity": , + "repres": [ + , , ... + ] + } + }, + ... + } + }, + ... + } + output[asset_id]["subsets"][subset_id]["version"]["repres"] + ``` + """ + + if not asset_entities: + return {} + + asset_entity_by_ids = {asset["_id"]: asset for asset in asset_entities} + + subsets = list(legacy_io.find({ + "type": "subset", + "parent": {"$in": list(asset_entity_by_ids.keys())} + })) + subset_entity_by_ids = {subset["_id"]: subset for subset in subsets} + + sorted_versions = list(legacy_io.find({ + "type": "version", + "parent": {"$in": list(subset_entity_by_ids.keys())} + }).sort("name", -1)) + + subset_id_with_latest_version = [] + last_versions_by_id = {} + for version in sorted_versions: + subset_id = version["parent"] + if subset_id in subset_id_with_latest_version: + continue + subset_id_with_latest_version.append(subset_id) + last_versions_by_id[version["_id"]] = version + + repres = legacy_io.find({ + "type": "representation", + "parent": {"$in": list(last_versions_by_id.keys())} + }) + + output = {} + for repre in repres: + version_id = repre["parent"] + version = last_versions_by_id[version_id] + + subset_id = version["parent"] + subset = subset_entity_by_ids[subset_id] + + asset_id = subset["parent"] + asset = asset_entity_by_ids[asset_id] + + if asset_id not in output: + output[asset_id] = { + "asset_entity": asset, + "subsets": {} + } + + if subset_id not in output[asset_id]["subsets"]: + output[asset_id]["subsets"][subset_id] = { + "subset_entity": subset, + "version": { + "version_entity": version, + "repres": [] + } + } + + output[asset_id]["subsets"][subset_id]["version"]["repres"].append( + repre + ) + + return output + + +@with_pipeline_io +def get_loaders_by_name(): + from openpype.pipeline import discover_loader_plugins + + loaders_by_name = {} + for loader in discover_loader_plugins(): + loader_name = loader.__name__ + if loader_name in loaders_by_name: + raise KeyError( + "Duplicated loader name {} !".format(loader_name) + ) + loaders_by_name[loader_name] = loader + return loaders_by_name + + class BuildWorkfile: """Wrapper for build workfile process. @@ -979,8 +1092,6 @@ class BuildWorkfile: ... }] """ - from openpype.pipeline import discover_loader_plugins - # Get current asset name and entity current_asset_name = legacy_io.Session["AVALON_ASSET"] current_asset_entity = legacy_io.find_one({ @@ -996,14 +1107,7 @@ class BuildWorkfile: return # Prepare available loaders - loaders_by_name = {} - for loader in discover_loader_plugins(): - loader_name = loader.__name__ - if loader_name in loaders_by_name: - raise KeyError( - "Duplicated loader name {0}!".format(loader_name) - ) - loaders_by_name[loader_name] = loader + loaders_by_name = get_loaders_by_name() # Skip if there are any loaders if not loaders_by_name: @@ -1075,7 +1179,7 @@ class BuildWorkfile: return # Prepare entities from database for assets - prepared_entities = self._collect_last_version_repres(assets) + prepared_entities = collect_last_version_repres(assets) # Load containers by prepared entities and presets loaded_containers = [] @@ -1491,102 +1595,6 @@ class BuildWorkfile: return loaded_containers - @with_pipeline_io - def _collect_last_version_repres(self, asset_entities): - """Collect subsets, versions and representations for asset_entities. - - Args: - asset_entities (list): Asset entities for which want to find data - - Returns: - (dict): collected entities - - Example output: - ``` - { - {Asset ID}: { - "asset_entity": , - "subsets": { - {Subset ID}: { - "subset_entity": , - "version": { - "version_entity": , - "repres": [ - , , ... - ] - } - }, - ... - } - }, - ... - } - output[asset_id]["subsets"][subset_id]["version"]["repres"] - ``` - """ - - if not asset_entities: - return {} - - asset_entity_by_ids = {asset["_id"]: asset for asset in asset_entities} - - subsets = list(legacy_io.find({ - "type": "subset", - "parent": {"$in": list(asset_entity_by_ids.keys())} - })) - subset_entity_by_ids = {subset["_id"]: subset for subset in subsets} - - sorted_versions = list(legacy_io.find({ - "type": "version", - "parent": {"$in": list(subset_entity_by_ids.keys())} - }).sort("name", -1)) - - subset_id_with_latest_version = [] - last_versions_by_id = {} - for version in sorted_versions: - subset_id = version["parent"] - if subset_id in subset_id_with_latest_version: - continue - subset_id_with_latest_version.append(subset_id) - last_versions_by_id[version["_id"]] = version - - repres = legacy_io.find({ - "type": "representation", - "parent": {"$in": list(last_versions_by_id.keys())} - }) - - output = {} - for repre in repres: - version_id = repre["parent"] - version = last_versions_by_id[version_id] - - subset_id = version["parent"] - subset = subset_entity_by_ids[subset_id] - - asset_id = subset["parent"] - asset = asset_entity_by_ids[asset_id] - - if asset_id not in output: - output[asset_id] = { - "asset_entity": asset, - "subsets": {} - } - - if subset_id not in output[asset_id]["subsets"]: - output[asset_id]["subsets"][subset_id] = { - "subset_entity": subset, - "version": { - "version_entity": version, - "repres": [] - } - } - - output[asset_id]["subsets"][subset_id]["version"]["repres"].append( - repre - ) - - return output - @with_pipeline_io def get_creator_by_name(creator_name, case_sensitive=False): diff --git a/openpype/lib/build_template.py b/openpype/lib/build_template.py new file mode 100644 index 0000000000..7f749cbec2 --- /dev/null +++ b/openpype/lib/build_template.py @@ -0,0 +1,61 @@ +from openpype.pipeline import registered_host +from openpype.lib import classes_from_module +from importlib import import_module + +from .abstract_template_loader import ( + AbstractPlaceholder, + AbstractTemplateLoader) + +from .build_template_exceptions import ( + TemplateLoadingFailed, + TemplateAlreadyImported, + MissingHostTemplateModule, + MissingTemplatePlaceholderClass, + MissingTemplateLoaderClass +) + +_module_path_format = 'openpype.{host}.template_loader' + + +def build_workfile_template(*args): + template_loader = build_template_loader() + try: + template_loader.import_template(template_loader.template_path) + except TemplateAlreadyImported as err: + template_loader.template_already_imported(err) + except TemplateLoadingFailed as err: + template_loader.template_loading_failed(err) + else: + template_loader.populate_template() + + +def update_workfile_template(args): + template_loader = build_template_loader() + template_loader.update_missing_containers() + + +def build_template_loader(): + host_name = registered_host().__name__.partition('.')[2] + module_path = _module_path_format.format(host=host_name) + module = import_module(module_path) + if not module: + raise MissingHostTemplateModule( + "No template loader found for host {}".format(host_name)) + + template_loader_class = classes_from_module( + AbstractTemplateLoader, + module + ) + template_placeholder_class = classes_from_module( + AbstractPlaceholder, + module + ) + + if not template_loader_class: + raise MissingTemplateLoaderClass() + template_loader_class = template_loader_class[0] + + if not template_placeholder_class: + raise MissingTemplatePlaceholderClass() + template_placeholder_class = template_placeholder_class[0] + return template_loader_class(template_placeholder_class) diff --git a/openpype/lib/build_template_exceptions.py b/openpype/lib/build_template_exceptions.py new file mode 100644 index 0000000000..d781eff204 --- /dev/null +++ b/openpype/lib/build_template_exceptions.py @@ -0,0 +1,35 @@ +class MissingHostTemplateModule(Exception): + """Error raised when expected module does not exists""" + pass + + +class MissingTemplatePlaceholderClass(Exception): + """Error raised when module doesn't implement a placeholder class""" + pass + + +class MissingTemplateLoaderClass(Exception): + """Error raised when module doesn't implement a template loader class""" + pass + + +class TemplateNotFound(Exception): + """Exception raised when template does not exist.""" + pass + + +class TemplateProfileNotFound(Exception): + """Exception raised when current profile + doesn't match any template profile""" + pass + + +class TemplateAlreadyImported(Exception): + """Error raised when Template was already imported by host for + this session""" + pass + + +class TemplateLoadingFailed(Exception): + """Error raised whend Template loader was unable to load the template""" + pass \ No newline at end of file From a5a3685f2b5b99bbd1f8de78581eb17af0175ed3 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 12:52:44 +0200 Subject: [PATCH 021/282] add template loader module --- openpype/hosts/maya/api/template_loader.py | 242 +++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 openpype/hosts/maya/api/template_loader.py diff --git a/openpype/hosts/maya/api/template_loader.py b/openpype/hosts/maya/api/template_loader.py new file mode 100644 index 0000000000..0e346ca411 --- /dev/null +++ b/openpype/hosts/maya/api/template_loader.py @@ -0,0 +1,242 @@ +from maya import cmds + +from openpype.pipeline import legacy_io +from openpype.lib.abstract_template_loader import ( + AbstractPlaceholder, + AbstractTemplateLoader +) +from openpype.lib.build_template_exceptions import TemplateAlreadyImported + +PLACEHOLDER_SET = 'PLACEHOLDERS_SET' + + +class MayaTemplateLoader(AbstractTemplateLoader): + """Concrete implementation of AbstractTemplateLoader for maya + """ + + def import_template(self, path): + """Import template into current scene. + Block if a template is already loaded. + Args: + path (str): A path to current template (usually given by + get_template_path implementation) + Returns: + bool: Wether the template was succesfully imported or not + """ + if cmds.objExists(PLACEHOLDER_SET): + raise TemplateAlreadyImported( + "Build template already loaded\n" + "Clean scene if needed (File > New Scene)") + + cmds.sets(name=PLACEHOLDER_SET, empty=True) + self.new_nodes = cmds.file(path, i=True, returnNewNodes=True) + cmds.setAttr(PLACEHOLDER_SET + '.hiddenInOutliner', True) + + for set in cmds.listSets(allSets=True): + if (cmds.objExists(set) and + cmds.attributeQuery('id', node=set, exists=True) and + cmds.getAttr(set + '.id') == 'pyblish.avalon.instance'): + if cmds.attributeQuery('asset', node=set, exists=True): + cmds.setAttr( + set + '.asset', + legacy_io.Session['AVALON_ASSET'], type='string' + ) + + return True + + def template_already_imported(self, err_msg): + clearButton = "Clear scene and build" + updateButton = "Update template" + abortButton = "Abort" + + title = "Scene already builded" + message = ( + "It's seems a template was already build for this scene.\n" + "Error message reveived :\n\n\"{}\"".format(err_msg)) + buttons = [clearButton, updateButton, abortButton] + defaultButton = clearButton + cancelButton = abortButton + dismissString = abortButton + answer = cmds.confirmDialog( + t=title, + m=message, + b=buttons, + db=defaultButton, + cb=cancelButton, + ds=dismissString) + + if answer == clearButton: + cmds.file(newFile=True, force=True) + self.import_template(self.template_path) + self.populate_template() + elif answer == updateButton: + self.update_missing_containers() + elif answer == abortButton: + return + + @staticmethod + def get_template_nodes(): + attributes = cmds.ls('*.builder_type', long=True) + return [attribute.rpartition('.')[0] for attribute in attributes] + + def get_loaded_containers_by_id(self): + containers = cmds.sets('AVALON_CONTAINERS', q=True) + return [ + cmds.getAttr(container + '.representation') + for container in containers] + + +class MayaPlaceholder(AbstractPlaceholder): + """Concrete implementation of AbstractPlaceholder for maya + """ + + optional_attributes = {'asset', 'subset', 'hierarchy'} + + def get_data(self, node): + user_data = dict() + for attr in self.attributes.union(self.optional_attributes): + attribute_name = '{}.{}'.format(node, attr) + if not cmds.attributeQuery(attr, node=node, exists=True): + print("{} not found".format(attribute_name)) + continue + user_data[attr] = cmds.getAttr( + attribute_name, + asString=True) + user_data['parent'] = ( + cmds.getAttr(node + '.parent', asString=True) + or node.rpartition('|')[0] or "") + user_data['node'] = node + if user_data['parent']: + siblings = cmds.listRelatives(user_data['parent'], children=True) + else: + siblings = cmds.ls(assemblies=True) + node_shortname = user_data['node'].rpartition('|')[2] + current_index = cmds.getAttr(node + '.index', asString=True) + user_data['index'] = ( + current_index if current_index >= 0 + else siblings.index(node_shortname)) + + self.data = user_data + + def parent_in_hierarchy(self, containers): + """Parent loaded container to placeholder's parent + ie : Set loaded content as placeholder's sibling + Args: + containers (String): Placeholder loaded containers + """ + if not containers: + return + + roots = cmds.sets(containers, q=True) + nodes_to_parent = [] + for root in roots: + if root.endswith("_RN"): + refRoot = cmds.referenceQuery(root, n=True)[0] + refRoot = cmds.listRelatives(refRoot, parent=True) or [refRoot] + nodes_to_parent.extend(refRoot) + elif root in cmds.listSets(allSets=True): + if not cmds.sets(root, q=True): + return + else: + continue + else: + nodes_to_parent.append(root) + + if self.data['parent']: + cmds.parent(nodes_to_parent, self.data['parent']) + # Move loaded nodes to correct index in outliner hierarchy + placeholder_node = self.data['node'] + placeholder_form = cmds.xform( + placeholder_node, + q=True, + matrix=True, + worldSpace=True + ) + for node in set(nodes_to_parent): + cmds.reorder(node, front=True) + cmds.reorder(node, relative=self.data['index']) + cmds.xform(node, matrix=placeholder_form, ws=True) + + holding_sets = cmds.listSets(object=placeholder_node) + if not holding_sets: + return + for holding_set in holding_sets: + cmds.sets(roots, forceElement=holding_set) + + def clean(self): + """Hide placeholder, parent them to root + add them to placeholder set and register placeholder's parent + to keep placeholder info available for future use + """ + node = self.data['node'] + if self.data['parent']: + cmds.setAttr(node + '.parent', self.data['parent'], type='string') + if cmds.getAttr(node + '.index') < 0: + cmds.setAttr(node + '.index', self.data['index']) + + holding_sets = cmds.listSets(object=node) + if holding_sets: + for set in holding_sets: + cmds.sets(node, remove=set) + + if cmds.listRelatives(node, p=True): + node = cmds.parent(node, world=True)[0] + cmds.sets(node, addElement=PLACEHOLDER_SET) + cmds.hide(node) + cmds.setAttr(node + '.hiddenInOutliner', True) + + def convert_to_db_filters(self, current_asset, linked_asset): + if self.data['builder_type'] == "context_asset": + return [ + { + "type": "representation", + "context.asset": { + "$eq": current_asset, + "$regex": self.data['asset'] + }, + "context.subset": {"$regex": self.data['subset']}, + "context.hierarchy": {"$regex": self.data['hierarchy']}, + "context.representation": self.data['representation'], + "context.family": self.data['family'], + } + ] + + elif self.data['builder_type'] == "linked_asset": + return [ + { + "type": "representation", + "context.asset": { + "$eq": asset_name, + "$regex": self.data['asset'] + }, + "context.subset": {"$regex": self.data['subset']}, + "context.hierarchy": {"$regex": self.data['hierarchy']}, + "context.representation": self.data['representation'], + "context.family": self.data['family'], + } for asset_name in linked_asset + ] + + else: + return [ + { + "type": "representation", + "context.asset": {"$regex": self.data['asset']}, + "context.subset": {"$regex": self.data['subset']}, + "context.hierarchy": {"$regex": self.data['hierarchy']}, + "context.representation": self.data['representation'], + "context.family": self.data['family'], + } + ] + + def err_message(self): + return ( + "Error while trying to load a representation.\n" + "Either the subset wasn't published or the template is malformed." + "\n\n" + "Builder was looking for :\n{attributes}".format( + attributes="\n".join([ + "{}: {}".format(key.title(), value) + for key, value in self.data.items()] + ) + ) + ) From f2ae0ffa5950d922fd3cb90ce8bbf30ec64ca0b7 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 14:28:28 +0200 Subject: [PATCH 022/282] add build workfile in menu --- openpype/hosts/maya/api/menu.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index 8beaf491bb..c66eeb449f 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -6,7 +6,13 @@ from Qt import QtWidgets, QtGui import maya.utils import maya.cmds as cmds -from openpype.api import BuildWorkfile +from openpype.api import ( + BuildWorkfile, + # build_workfile_template + # update_workfile_template +) + +from openpype.lib.build_template import build_workfile_template, update_workfile_template from openpype.settings import get_project_settings from openpype.pipeline import legacy_io from openpype.tools.utils import host_tools @@ -158,6 +164,16 @@ def install(): parent=builder_menu, command=lambda *args: update_placeholder() ) + cmds.menuItem( + "Build Workfile from template", + parent=builder_menu, + command=lambda *args: build_workfile_template() + ) + cmds.menuItem( + "Update Workfile from template", + parent=builder_menu, + command=lambda *args: update_workfile_template() + ) cmds.setParent(MENU_NAME, menu=True) From 41a47bb2bfb9b728f0cad37f5614e5d382b2d9d1 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 16:35:05 +0200 Subject: [PATCH 023/282] delete the task_name verification since it does not exists in the maya menu settings --- openpype/lib/abstract_template_loader.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 6888cbf757..2dfec1a006 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -157,8 +157,6 @@ class AbstractTemplateLoader: for prf in profiles: if prf['task_types'] and task_type not in prf['task_types']: continue - if prf['task_names'] and task_name not in prf['task_names']: - continue path = prf['path'] break else: # IF no template were found (no break happened) @@ -253,7 +251,7 @@ class AbstractTemplateLoader: linked_assets) # get representation by assets for db_filter in placeholder_db_filters: - placeholder_representations = list(avalon.io.find(db_filter)) + placeholder_representations = list(legacy_io.find(db_filter)) for representation in reduce(update_representations, placeholder_representations, dict()).values(): From 58814d21e4688fbb13d183fab7ba9010c68b57f8 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 25 May 2022 16:38:47 +0200 Subject: [PATCH 024/282] rename correctly attributes to correpsond the ones in the placeholders --- openpype/lib/abstract_template_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 2dfec1a006..628d0bd895 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -357,7 +357,7 @@ class AbstractPlaceholder: parent_in_hierachy: """ - attributes = {'builder_type', 'op_family', 'op_representation', + attributes = {'builder_type', 'family', 'representation', 'order', 'loader', 'loader_args'} optional_attributes = {} From 6cb037d3d63290752bacc0aa8c2b81cac8e3b370 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Fri, 27 May 2022 12:44:51 +0200 Subject: [PATCH 025/282] create placeholder name dynamically from arguments --- .../hosts/maya/api/lib_template_builder.py | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index d8772f3f9a..ee78f19a3e 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -1,3 +1,4 @@ +import json from collections import OrderedDict import maya.cmds as cmds @@ -30,17 +31,20 @@ def create_placeholder(): if not args: return # operation canceled, no locator created - selection = cmds.ls(selection=True) - placeholder = cmds.spaceLocator(name="_TEMPLATE_PLACEHOLDER_")[0] - if selection: - cmds.parent(placeholder, selection[0]) # custom arg parse to force empty data query # and still imprint them on placeholder # and getting items when arg is of type Enumerator - options = OrderedDict() - for arg in args: - if not type(arg) == qargparse.Separator: - options[str(arg)] = arg._data.get("items") or arg.read() + options = create_options(args) + + # create placeholder name dynamically from args and options + placeholder_name = create_placeholder_name(args, options) + + selection = cmds.ls(selection=True) + placeholder = cmds.spaceLocator(name=placeholder_name.capitalize())[0] + + if selection: + cmds.parent(placeholder, selection[0]) + imprint(placeholder, options) # Some tweaks because imprint force enums to to default value so we get # back arg read and force them to attributes @@ -49,13 +53,42 @@ def create_placeholder(): # Add helper attributes to keep placeholder info cmds.addAttr( placeholder, longName="parent", - hidden=True, dataType="string") + hidden=False, dataType="string") cmds.addAttr( placeholder, longName="index", - hidden=True, attributeType="short", + hidden=False, attributeType="short", defaultValue=-1) +def create_options(args): + options = OrderedDict() + for arg in args: + if not type(arg) == qargparse.Separator: + options[str(arg)] = arg._data.get("items") or arg.read() + return options + + +def create_placeholder_name(args, options): + placeholder_builder_type = [ + arg.read() for arg in args if 'builder_type' in str(arg) + ][0] + placeholder_family = options['family'] + placeholder_name = placeholder_builder_type.split('_') + placeholder_name.insert(1, placeholder_family) + + # add loader arguments if any + if options['loader_args']: + pos = 2 + loader_args = options['loader_args'].replace('\'', '\"') + loader_args = json.loads(loader_args) + values = [v for v in loader_args.values()] + for i in range(len(values)): + placeholder_name.insert(i + pos, values[i]) + placeholder_name = '_'.join(placeholder_name) + + return placeholder_name + + def update_placeholder(): placeholder = cmds.ls(selection=True) if len(placeholder) == 0: From aa88ee13c0d3b647dc9c11534ed4a742168b0e1d Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 30 May 2022 14:19:12 +0200 Subject: [PATCH 026/282] minor refactoring --- .../hosts/maya/api/lib_template_builder.py | 19 ++++++++++++++----- openpype/hosts/maya/api/menu.py | 11 +++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index ee78f19a3e..bec0f1fc66 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -52,12 +52,21 @@ def create_placeholder(): # Add helper attributes to keep placeholder info cmds.addAttr( - placeholder, longName="parent", - hidden=False, dataType="string") + placeholder, + longName="parent", + hidden=False, + dataType="string" + ) cmds.addAttr( - placeholder, longName="index", - hidden=False, attributeType="short", - defaultValue=-1) + placeholder, + longName="index", + hidden=False, + attributeType="short", + defaultValue=-1 + ) + + parents = cmds.ls(selection[0], long=True) + cmds.setAttr(placeholder + '.parent', parents[0], type="string") def create_options(args): diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index c66eeb449f..1337713561 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -6,13 +6,12 @@ from Qt import QtWidgets, QtGui import maya.utils import maya.cmds as cmds -from openpype.api import ( - BuildWorkfile, - # build_workfile_template - # update_workfile_template -) +from openpype.api import BuildWorkfile -from openpype.lib.build_template import build_workfile_template, update_workfile_template +from openpype.lib.build_template import ( + build_workfile_template, + update_workfile_template +) from openpype.settings import get_project_settings from openpype.pipeline import legacy_io from openpype.tools.utils import host_tools From d8edf2b1aa9e83861bad1b8aef6da69cc6011de4 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 30 May 2022 14:20:31 +0200 Subject: [PATCH 027/282] change load method since avalon doesn't exsist anymore --- openpype/lib/abstract_template_loader.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 628d0bd895..77ba04c4db 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -5,11 +5,10 @@ import traceback import six -import openpype from openpype.settings import get_project_settings from openpype.lib import Anatomy, get_linked_assets, get_loaders_by_name from openpype.api import PypeLogger as Logger -from openpype.pipeline import legacy_io +from openpype.pipeline import legacy_io, load from functools import reduce @@ -271,9 +270,10 @@ class AbstractTemplateLoader: pass def load(self, placeholder, loaders_by_name, last_representation): - return openpype.pipeline.load( + repre = load.get_representation_context(last_representation) + return load.load_with_repre_context( loaders_by_name[placeholder.loader], - last_representation['_id'], + repre, options=parse_loader_args(placeholder.data['loader_args'])) def load_succeed(self, placeholder, container): From bae9eef400e2b1195d8ece023543ca8d89c83b1b Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 30 May 2022 14:53:49 +0200 Subject: [PATCH 028/282] fix update placeholder --- .../hosts/maya/api/lib_template_builder.py | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index bec0f1fc66..2efc210d10 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -69,14 +69,6 @@ def create_placeholder(): cmds.setAttr(placeholder + '.parent', parents[0], type="string") -def create_options(args): - options = OrderedDict() - for arg in args: - if not type(arg) == qargparse.Separator: - options[str(arg)] = arg._data.get("items") or arg.read() - return options - - def create_placeholder_name(args, options): placeholder_builder_type = [ arg.read() for arg in args if 'builder_type' in str(arg) @@ -112,12 +104,38 @@ def update_placeholder(): if not args: return # operation canceled + options = create_options(args) + + imprint(placeholder, options) + imprint_enum(placeholder, args) + + cmds.addAttr( + placeholder, + longName="parent", + hidden=False, + dataType="string" + ) + cmds.addAttr( + placeholder, + longName="index", + hidden=False, + attributeType="short", + defaultValue=-1 + ) + + selected = cmds.ls(selection=True, long=True) + selected = selected[0].split('|')[-2] + selected = cmds.ls(selected) + parents = cmds.ls(selected, long=True) + cmds.setAttr(placeholder + '.parent', parents[0], type="string") + + +def create_options(args): options = OrderedDict() for arg in args: if not type(arg) == qargparse.Separator: options[str(arg)] = arg._data.get("items") or arg.read() - imprint(placeholder, options) - imprint_enum(placeholder, args) + return options def imprint_enum(placeholder, args): From 349d57a4a8ec86364d64b02798c7579f6c3cb5c2 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Thu, 2 Jun 2022 10:40:44 +0200 Subject: [PATCH 029/282] change menu command for build and update workfile from template --- openpype/hosts/maya/api/menu.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index 1337713561..c0bad7092f 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -166,12 +166,12 @@ def install(): cmds.menuItem( "Build Workfile from template", parent=builder_menu, - command=lambda *args: build_workfile_template() + command=build_workfile_template ) cmds.menuItem( "Update Workfile from template", parent=builder_menu, - command=lambda *args: update_workfile_template() + command=update_workfile_template ) cmds.setParent(MENU_NAME, menu=True) From e2506d569adf78c74ba6452643fec5d1afca0ab2 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Thu, 2 Jun 2022 12:22:06 +0200 Subject: [PATCH 030/282] get full name placeholder to avoid any conflict between two placeholders with same short name --- .../hosts/maya/api/lib_template_builder.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index 2efc210d10..108988a676 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -40,33 +40,37 @@ def create_placeholder(): placeholder_name = create_placeholder_name(args, options) selection = cmds.ls(selection=True) - placeholder = cmds.spaceLocator(name=placeholder_name.capitalize())[0] + placeholder = cmds.spaceLocator(name=placeholder_name)[0] + + # get the long name of the placeholder (with the groups) + placeholder_full_name = cmds.ls(selection[0], long=True)[0] + '|' + placeholder.replace('|', '') if selection: cmds.parent(placeholder, selection[0]) - imprint(placeholder, options) + imprint(placeholder_full_name, options) + # Some tweaks because imprint force enums to to default value so we get # back arg read and force them to attributes - imprint_enum(placeholder, args) + imprint_enum(placeholder_full_name, args) # Add helper attributes to keep placeholder info cmds.addAttr( - placeholder, + placeholder_full_name, longName="parent", - hidden=False, + hidden=True, dataType="string" ) cmds.addAttr( - placeholder, + placeholder_full_name, longName="index", - hidden=False, + hidden=True, attributeType="short", defaultValue=-1 ) parents = cmds.ls(selection[0], long=True) - cmds.setAttr(placeholder + '.parent', parents[0], type="string") + cmds.setAttr(placeholder_full_name + '.parent', parents[0], type="string") def create_placeholder_name(args, options): @@ -75,7 +79,10 @@ def create_placeholder_name(args, options): ][0] placeholder_family = options['family'] placeholder_name = placeholder_builder_type.split('_') - placeholder_name.insert(1, placeholder_family) + + # add famlily in any + if placeholder_family: + placeholder_name.insert(1, placeholder_family) # add loader arguments if any if options['loader_args']: @@ -85,9 +92,10 @@ def create_placeholder_name(args, options): values = [v for v in loader_args.values()] for i in range(len(values)): placeholder_name.insert(i + pos, values[i]) + placeholder_name = '_'.join(placeholder_name) - return placeholder_name + return placeholder_name.capitalize() def update_placeholder(): @@ -112,13 +120,13 @@ def update_placeholder(): cmds.addAttr( placeholder, longName="parent", - hidden=False, + hidden=True, dataType="string" ) cmds.addAttr( placeholder, longName="index", - hidden=False, + hidden=True, attributeType="short", defaultValue=-1 ) From a6d948aa93e2c84c001a109c50dede9b9c160321 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 8 Jun 2022 12:46:24 +0200 Subject: [PATCH 031/282] add a log if no reprensation found for the current placeholder --- openpype/lib/abstract_template_loader.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 77ba04c4db..cd0416426c 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -19,6 +19,10 @@ from openpype.lib.build_template_exceptions import ( TemplateNotFound ) +import logging + +log = logging.getLogger(__name__) + def update_representations(entities, entity): if entity['context']['subset'] not in entities: @@ -215,8 +219,15 @@ class AbstractTemplateLoader: current_asset, linked_assets ) - for representation in placeholder_representations: + if not placeholder_representations: + self.log.info( + "There's no representation for this placeholder: " + "{}".format(placeholder.data['node']) + ) + continue + + for representation in placeholder_representations: self.preload(placeholder, loaders_by_name, representation) if self.load_data_is_incorrect( From d6543bf281a418fe768059a58a1a9eb8257ef68f Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Wed, 8 Jun 2022 12:53:59 +0200 Subject: [PATCH 032/282] add debug logs for placeholders --- openpype/lib/abstract_template_loader.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index cd0416426c..159d5c8f6c 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -213,7 +213,13 @@ class AbstractTemplateLoader: ignored_ids = ignored_ids or [] placeholders = self.get_placeholders() + self.log.debug("Placeholders found in template: {}".format( + [placeholder.data['node'] for placeholder in placeholders] + )) for placeholder in placeholders: + self.log.debug("Start to processing placeholder {}".format( + placeholder.data['node'] + )) placeholder_representations = self.get_placeholder_representations( placeholder, current_asset, From 4a02dd039de637398aa6c2a1d2c26ba772f720da Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Thu, 9 Jun 2022 14:51:48 +0200 Subject: [PATCH 033/282] set empty placholder parent at creation --- openpype/hosts/maya/api/lib_template_builder.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index 108988a676..20f6f041fb 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -69,8 +69,7 @@ def create_placeholder(): defaultValue=-1 ) - parents = cmds.ls(selection[0], long=True) - cmds.setAttr(placeholder_full_name + '.parent', parents[0], type="string") + cmds.setAttr(placeholder_full_name + '.parent', "", type="string") def create_placeholder_name(args, options): @@ -131,11 +130,11 @@ def update_placeholder(): defaultValue=-1 ) - selected = cmds.ls(selection=True, long=True) + """selected = cmds.ls(selection=True, long=True) selected = selected[0].split('|')[-2] selected = cmds.ls(selected) - parents = cmds.ls(selected, long=True) - cmds.setAttr(placeholder + '.parent', parents[0], type="string") + parents = cmds.ls(selected, long=True)""" + cmds.setAttr(placeholder + '.parent', '', type="string") def create_options(args): From a97f5379b16f4141035629aa23d7ca26f16fdced Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 10 Jun 2022 14:17:30 +0200 Subject: [PATCH 034/282] Add documentation --- website/docs/admin_hosts_maya.md | 50 ++++++++++++++++++ .../docs/assets/maya-create_placeholder.png | Bin 0 -> 31543 bytes website/docs/assets/maya-placeholder_new.png | Bin 0 -> 28008 bytes 3 files changed, 50 insertions(+) create mode 100644 website/docs/assets/maya-create_placeholder.png create mode 100644 website/docs/assets/maya-placeholder_new.png diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index 93bf32798f..c55dcc1b36 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -120,3 +120,53 @@ raw json. You can configure path mapping using Maya `dirmap` command. This will add bi-directional mapping between list of paths specified in **Settings**. You can find it in **Settings -> Project Settings -> Maya -> Maya Directory Mapping** ![Dirmap settings](assets/maya-admin_dirmap_settings.png) + +## Templated Build Workfile + +Building a workfile using a template designed by users. Helping to assert homogeneous subsets hierarchy and imports. Template stored as file easy to define, change and customize for production needs. + + **1. Make a template** + +Make your template. Add families and everything needed for your tasks. Here is an example template for the modeling task using a placeholder to import a gauge. + +![Dirmap settings](assets/maya-workfile-outliner.png) + +If needed, you can add placeholders when the template needs to load some assets. **OpenPype > Template Builder > Create Placeholder** + +![create placeholder](assets/maya-create_placeholder.png) + +- **Configure placeholders** + +Fill in the necessary fields (the optional fields are regex filters) + +![new place holder](assets/maya-placeholder_new.png) + + + - Builder type: Wether the the placeholder should load current asset representations or linked assets representations + + - Representation: Representation that will be loaded (ex: ma, abc, png, etc...) + + - Family: Family of the representation to load (main, look, image, etc ...) + + - Loader: Placeholder loader name that will be used to load corresponding representations + + - Order: Priority for current placeholder loader (priority is lowest first, highet last) + +- **Save your template** + + + **2. Configure Template** + +- **Go to Studio settings > Project > Your DCC > Templated Build Settings** +- Add a profile for your task and enter path to your template +![Dirmap settings](assets/settings/template_build_workfile.png) + +**3. Build your workfile** + +- Open maya + +- Build your workfile + +![Dirmap settings](assets/maya-build_workfile_from_template.png) + + diff --git a/website/docs/assets/maya-create_placeholder.png b/website/docs/assets/maya-create_placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..3f49fe2e2b801e89e2027ec521dbf700b97f80d2 GIT binary patch literal 31543 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 Pn$XtJKYU;9ROtTzYS3%b literal 0 HcmV?d00001 diff --git a/website/docs/assets/maya-placeholder_new.png b/website/docs/assets/maya-placeholder_new.png new file mode 100644 index 0000000000000000000000000000000000000000..106a5275cdb5bc0588c811d9a059ec3b6e072e20 GIT binary patch literal 28008 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 literal 0 HcmV?d00001 From e4a7dd6548eec1c3d85bdf133c4f273432313c12 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 10 Jun 2022 14:27:00 +0200 Subject: [PATCH 035/282] add sreenshot --- .../maya-build_workfile_from_template.png | Bin 0 -> 20676 bytes .../assets/settings/template_build_workfile.png | Bin 0 -> 29814 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 website/docs/assets/maya-build_workfile_from_template.png create mode 100644 website/docs/assets/settings/template_build_workfile.png diff --git a/website/docs/assets/maya-build_workfile_from_template.png b/website/docs/assets/maya-build_workfile_from_template.png new file mode 100644 index 0000000000000000000000000000000000000000..336b76f8aa1ef8d22aa8b912da1cc5f4827fc5e8 GIT binary patch literal 20676 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 Z{|`+)aTxx~sMG)e002ovPDHLkV1iGtk!t_| literal 0 HcmV?d00001 diff --git a/website/docs/assets/settings/template_build_workfile.png b/website/docs/assets/settings/template_build_workfile.png new file mode 100644 index 0000000000000000000000000000000000000000..7ef87861fe97322a3b23c28ee3644b76ce995e9d GIT binary patch literal 29814 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 literal 0 HcmV?d00001 From 4441a7cc1c07dc62fc04bd7428bd2f7efcdb0fd9 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 10 Jun 2022 14:50:42 +0200 Subject: [PATCH 036/282] add screenshot --- website/docs/admin_hosts_maya.md | 5 +++-- .../maya-build_workfile_from_template.png | Bin 20676 -> 29814 bytes .../docs/assets/maya-workfile-outliner.png | Bin 0 -> 4835 bytes .../settings/template_build_workfile.png | Bin 29814 -> 12596 bytes 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 website/docs/assets/maya-workfile-outliner.png diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index c55dcc1b36..0ba030c26f 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -129,7 +129,7 @@ Building a workfile using a template designed by users. Helping to assert homoge Make your template. Add families and everything needed for your tasks. Here is an example template for the modeling task using a placeholder to import a gauge. -![Dirmap settings](assets/maya-workfile-outliner.png) +![maya outliner](assets/maya-workfile-outliner.png) If needed, you can add placeholders when the template needs to load some assets. **OpenPype > Template Builder > Create Placeholder** @@ -159,7 +159,8 @@ Fill in the necessary fields (the optional fields are regex filters) - **Go to Studio settings > Project > Your DCC > Templated Build Settings** - Add a profile for your task and enter path to your template -![Dirmap settings](assets/settings/template_build_workfile.png) + +![build template](assets/settings/template_build_workfile.png) **3. Build your workfile** diff --git a/website/docs/assets/maya-build_workfile_from_template.png b/website/docs/assets/maya-build_workfile_from_template.png index 336b76f8aa1ef8d22aa8b912da1cc5f4827fc5e8..7ef87861fe97322a3b23c28ee3644b76ce995e9d 100644 GIT binary patch literal 29814 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 literal 20676 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 Z{|`+)aTxx~sMG)e002ovPDHLkV1iGtk!t_| diff --git a/website/docs/assets/maya-workfile-outliner.png b/website/docs/assets/maya-workfile-outliner.png new file mode 100644 index 0000000000000000000000000000000000000000..fbd1bbd03bce52041ad511dac138479494641361 GIT binary patch literal 4835 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 X`o37wi;`y6#S|Ob%*wRV#3TNnn_AI~ literal 0 HcmV?d00001 diff --git a/website/docs/assets/settings/template_build_workfile.png b/website/docs/assets/settings/template_build_workfile.png index 7ef87861fe97322a3b23c28ee3644b76ce995e9d..1bea5b01f5f3145e2d1aa5d46545c3739aaf2584 100644 GIT binary patch literal 12596 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 literal 29814 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 From 90754fb0b8d36eb0b34cba6da48f672505470f0e Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 10 Jun 2022 14:51:02 +0200 Subject: [PATCH 037/282] modify readme doc --- website/docs/admin_hosts_maya.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/admin_hosts_maya.md b/website/docs/admin_hosts_maya.md index 0ba030c26f..0e77f29fc2 100644 --- a/website/docs/admin_hosts_maya.md +++ b/website/docs/admin_hosts_maya.md @@ -160,7 +160,7 @@ Fill in the necessary fields (the optional fields are regex filters) - **Go to Studio settings > Project > Your DCC > Templated Build Settings** - Add a profile for your task and enter path to your template -![build template](assets/settings/template_build_workfile.png) +![setting build template](assets/settings/template_build_workfile.png) **3. Build your workfile** @@ -168,6 +168,6 @@ Fill in the necessary fields (the optional fields are regex filters) - Build your workfile -![Dirmap settings](assets/maya-build_workfile_from_template.png) +![maya build template](assets/maya-build_workfile_from_template.png) From d3c2dc57d8f39865c3f3900db1be1f911b6436c9 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 10 Jun 2022 15:02:43 +0200 Subject: [PATCH 038/282] fix linter --- openpype/hosts/maya/api/lib_template_builder.py | 6 +++++- openpype/lib/build_template_exceptions.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index bed4291e3d..e5254b7f87 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -43,7 +43,11 @@ def create_placeholder(): placeholder = cmds.spaceLocator(name=placeholder_name)[0] # get the long name of the placeholder (with the groups) - placeholder_full_name = cmds.ls(selection[0], long=True)[0] + '|' + placeholder.replace('|', '') + placeholder_full_name = cmds.ls( + selection[0], + long=True)[0] + '|' + placeholder.replace('|', + '' + ) if selection: cmds.parent(placeholder, selection[0]) diff --git a/openpype/lib/build_template_exceptions.py b/openpype/lib/build_template_exceptions.py index d781eff204..7a5075e3dc 100644 --- a/openpype/lib/build_template_exceptions.py +++ b/openpype/lib/build_template_exceptions.py @@ -32,4 +32,4 @@ class TemplateAlreadyImported(Exception): class TemplateLoadingFailed(Exception): """Error raised whend Template loader was unable to load the template""" - pass \ No newline at end of file + pass From bc9c5b183171b9ef03b88062c7536a5effed3ae1 Mon Sep 17 00:00:00 2001 From: "clement.hector" Date: Fri, 10 Jun 2022 15:22:33 +0200 Subject: [PATCH 039/282] fix linter lengh line --- openpype/hosts/maya/api/lib_template_builder.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index e5254b7f87..a30b3868b0 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -43,11 +43,8 @@ def create_placeholder(): placeholder = cmds.spaceLocator(name=placeholder_name)[0] # get the long name of the placeholder (with the groups) - placeholder_full_name = cmds.ls( - selection[0], - long=True)[0] + '|' + placeholder.replace('|', - '' - ) + placeholder_full_name = cmds.ls(selection[0], long=True)[ + 0] + '|' + placeholder.replace('|', '') if selection: cmds.parent(placeholder, selection[0]) From ba1abf8b15e1476b430180bc63b1a3801ff118ef Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 14 Jun 2022 10:35:41 +0200 Subject: [PATCH 040/282] add task name field in build templated workfile settings --- openpype/settings/defaults/project_settings/maya.json | 1 + .../schemas/schema_templated_workfile_build.json | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 2e0e30b74b..453706ff88 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -722,6 +722,7 @@ "profiles": [ { "task_types": [], + "tasks": [], "path": "/path/to/your/template" } ] 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 01e74f64b0..a591facf98 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 @@ -16,6 +16,12 @@ "label": "Task types", "type": "task-types-enum" }, + { + "key": "tasks", + "label": "Task names", + "type": "list", + "object_type": "text" + }, { "key": "path", "label": "Path to template", From ef7627199eb8297196c9d0a778e222132d742be2 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Tue, 14 Jun 2022 11:37:08 +0200 Subject: [PATCH 041/282] add a task name verification for template loader --- openpype/lib/abstract_template_loader.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/lib/abstract_template_loader.py index 159d5c8f6c..e296e3207f 100644 --- a/openpype/lib/abstract_template_loader.py +++ b/openpype/lib/abstract_template_loader.py @@ -160,6 +160,8 @@ class AbstractTemplateLoader: for prf in profiles: if prf['task_types'] and task_type not in prf['task_types']: continue + if prf['tasks'] and task_name not in prf['tasks']: + continue path = prf['path'] break else: # IF no template were found (no break happened) From 712e1c6707a9b0b57bbf1a50f108d692c6f9030b Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Tue, 14 Jun 2022 16:00:51 +0100 Subject: [PATCH 042/282] Implemented extraction of JSON layout from Maya --- .../maya/plugins/publish/extract_layout.py | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 openpype/hosts/maya/plugins/publish/extract_layout.py diff --git a/openpype/hosts/maya/plugins/publish/extract_layout.py b/openpype/hosts/maya/plugins/publish/extract_layout.py new file mode 100644 index 0000000000..4ae99f1052 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/extract_layout.py @@ -0,0 +1,101 @@ +import os +import json + +from maya import cmds + +from bson.objectid import ObjectId + +from openpype.pipeline import legacy_io +import openpype.api + + +class ExtractLayout(openpype.api.Extractor): + """Extract a layout.""" + + label = "Extract Layout" + hosts = ["maya"] + families = ["layout"] + optional = True + + def process(self, instance): + # Define extract output file path + stagingdir = self.staging_dir(instance) + + # Perform extraction + self.log.info("Performing extraction..") + + if "representations" not in instance.data: + instance.data["representations"] = [] + + json_data = [] + + for asset in cmds.sets(str(instance), query=True): + # Find the container + grp_name = asset.split(':')[0] + containers = cmds.ls(f"{grp_name}*_CON") + + assert len(containers) == 1, \ + f"More than one container found for {asset}" + + container = containers[0] + + representation_id = cmds.getAttr(f"{container}.representation") + + representation = legacy_io.find_one( + { + "type": "representation", + "_id": ObjectId(representation_id) + }, projection={"parent": True, "context.family": True}) + + self.log.info(representation) + + version_id = representation.get("parent") + family = representation.get("context").get("family") + + json_element = { + "family": family, + "instance_name": cmds.getAttr(f"{container}.name"), + "representation": str(representation_id), + "version": str(version_id) + } + + loc = cmds.xform(asset, query=True, translation=True) + rot = cmds.xform(asset, query=True, rotation=True) + scl = cmds.xform(asset, query=True, relative=True, scale=True) + + json_element["transform"] = { + "translation": { + "x": loc[0], + "y": loc[1], + "z": loc[2] + }, + "rotation": { + "x": rot[0], + "y": rot[1], + "z": rot[2] + }, + "scale": { + "x": scl[0], + "y": scl[1], + "z": scl[2] + } + } + + json_data.append(json_element) + + json_filename = "{}.json".format(instance.name) + json_path = os.path.join(stagingdir, json_filename) + + with open(json_path, "w+") as file: + json.dump(json_data, fp=file, indent=2) + + json_representation = { + 'name': 'json', + 'ext': 'json', + 'files': json_filename, + "stagingDir": stagingdir, + } + instance.data["representations"].append(json_representation) + + self.log.info("Extracted instance '%s' to: %s", + instance.name, json_representation) From 8e8aa452402c965cf70dbb59dfaa87a419c405a4 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Tue, 21 Jun 2022 17:09:19 +0100 Subject: [PATCH 043/282] Implemented loading of JSON layout from Maya The JSON file is an updated version of the one currently in use for Blender. Compatibility is kept for existing JSON layouts. However, the transform data is different in Blender, Maya and Unreal. This commit works for Maya -> Unreal, but breaks Blender -> Unreal. Will fix in future commits. --- .../plugins/load/load_alembic_staticmesh.py | 13 +- .../hosts/unreal/plugins/load/load_layout.py | 121 ++++++++++++------ 2 files changed, 84 insertions(+), 50 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py b/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py index 5a73c72c64..691971e02f 100644 --- a/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py +++ b/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py @@ -24,7 +24,11 @@ class StaticMeshAlembicLoader(plugin.Loader): task = unreal.AssetImportTask() options = unreal.AbcImportSettings() sm_settings = unreal.AbcStaticMeshSettings() - conversion_settings = unreal.AbcConversionSettings() + conversion_settings = unreal.AbcConversionSettings( + preset=unreal.AbcConversionPreset.CUSTOM, + flip_u=False, flip_v=True, + rotation=[90.0, 0.0, 0.0], + scale=[1.0, -1.0, 1.0]) task.set_editor_property('filename', filename) task.set_editor_property('destination_path', asset_dir) @@ -40,13 +44,6 @@ class StaticMeshAlembicLoader(plugin.Loader): sm_settings.set_editor_property('merge_meshes', True) - conversion_settings.set_editor_property('flip_u', False) - conversion_settings.set_editor_property('flip_v', True) - conversion_settings.set_editor_property( - 'scale', unreal.Vector(x=100.0, y=100.0, z=100.0)) - conversion_settings.set_editor_property( - 'rotation', unreal.Vector(x=-90.0, y=0.0, z=180.0)) - options.static_mesh_settings = sm_settings options.conversion_settings = conversion_settings task.options = options diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index c65cd25ac8..ee31d32811 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -12,6 +12,8 @@ from unreal import AssetToolsHelpers from unreal import FBXImportType from unreal import MathLibrary as umath +from bson.objectid import ObjectId + from openpype.pipeline import ( discover_loader_plugins, loaders_from_representation, @@ -196,12 +198,12 @@ class LayoutLoader(plugin.Loader): except Exception as e: print(e) actor.set_actor_rotation(unreal.Rotator( - umath.radians_to_degrees( + ( transform.get('rotation').get('x')), - -umath.radians_to_degrees( - transform.get('rotation').get('y')), - umath.radians_to_degrees( + ( transform.get('rotation').get('z')), + -( + transform.get('rotation').get('y')), ), False) actor.set_actor_scale3d(transform.get('scale')) @@ -354,7 +356,7 @@ class LayoutLoader(plugin.Loader): sec_params.set_editor_property('animation', animation) @staticmethod - def _generate_sequence(self, h, h_dir): + def _generate_sequence(h, h_dir): tools = unreal.AssetToolsHelpers().get_asset_tools() sequence = tools.create_asset( @@ -406,7 +408,7 @@ class LayoutLoader(plugin.Loader): return sequence, (min_frame, max_frame) - def _process(self, lib_path, asset_dir, sequence, loaded=None): + def _process(self, lib_path, asset_dir, sequence, repr_loaded=None): ar = unreal.AssetRegistryHelpers.get_asset_registry() with open(lib_path, "r") as fp: @@ -414,8 +416,8 @@ class LayoutLoader(plugin.Loader): all_loaders = discover_loader_plugins() - if not loaded: - loaded = [] + if not repr_loaded: + repr_loaded = [] path = Path(lib_path) @@ -426,36 +428,64 @@ class LayoutLoader(plugin.Loader): loaded_assets = [] for element in data: - reference = None - if element.get('reference_fbx'): - reference = element.get('reference_fbx') + representation = None + repr_format = None + if element.get('representation'): + # representation = element.get('representation') + + self.log.info(element.get("version")) + + valid_formats = ['fbx', 'abc'] + + repr_data = legacy_io.find_one({ + "type": "representation", + "parent": ObjectId(element.get("version")), + "name": {"$in": valid_formats} + }) + repr_format = repr_data.get('name') + + if not repr_data: + self.log.error( + f"No valid representation found for version " + f"{element.get('version')}") + continue + + representation = str(repr_data.get('_id')) + print(representation) + # This is to keep compatibility with old versions of the + # json format. + elif element.get('reference_fbx'): + representation = element.get('reference_fbx') + repr_format = 'fbx' elif element.get('reference_abc'): - reference = element.get('reference_abc') + representation = element.get('reference_abc') + repr_format = 'abc' # If reference is None, this element is skipped, as it cannot be # imported in Unreal - if not reference: + if not representation: continue instance_name = element.get('instance_name') skeleton = None - if reference not in loaded: - loaded.append(reference) + if representation not in repr_loaded: + repr_loaded.append(representation) family = element.get('family') loaders = loaders_from_representation( - all_loaders, reference) + all_loaders, representation) loader = None - if reference == element.get('reference_fbx'): + if repr_format == 'fbx': loader = self._get_fbx_loader(loaders, family) - elif reference == element.get('reference_abc'): + elif repr_format == 'abc': loader = self._get_abc_loader(loaders, family) if not loader: + self.log.error(f"No valid loader found for {representation}") continue options = { @@ -464,7 +494,7 @@ class LayoutLoader(plugin.Loader): assets = load_container( loader, - reference, + representation, namespace=instance_name, options=options ) @@ -482,8 +512,10 @@ class LayoutLoader(plugin.Loader): instances = [ item for item in data - if (item.get('reference_fbx') == reference or - item.get('reference_abc') == reference)] + if ((item.get('version') and + item.get('version') == element.get('version')) or + item.get('reference_fbx') == representation or + item.get('reference_abc') == representation)] for instance in instances: transform = instance.get('transform') @@ -501,9 +533,9 @@ class LayoutLoader(plugin.Loader): bindings_dict[inst] = bindings if skeleton: - skeleton_dict[reference] = skeleton + skeleton_dict[representation] = skeleton else: - skeleton = skeleton_dict.get(reference) + skeleton = skeleton_dict.get(representation) animation_file = element.get('animation') @@ -599,23 +631,26 @@ class LayoutLoader(plugin.Loader): # Create map for the shot, and create hierarchy of map. If the maps # already exist, we will use them. - h_dir = hierarchy_dir_list[0] - h_asset = hierarchy[0] - master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map" - if not EditorAssetLibrary.does_asset_exist(master_level): - EditorLevelLibrary.new_level(f"{h_dir}/{h_asset}_map") + master_level = None + if hierarchy: + h_dir = hierarchy_dir_list[0] + h_asset = hierarchy[0] + master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map" + if not EditorAssetLibrary.does_asset_exist(master_level): + EditorLevelLibrary.new_level(f"{h_dir}/{h_asset}_map") level = f"{asset_dir}/{asset}_map.{asset}_map" EditorLevelLibrary.new_level(f"{asset_dir}/{asset}_map") - EditorLevelLibrary.load_level(master_level) - EditorLevelUtils.add_level_to_world( - EditorLevelLibrary.get_editor_world(), - level, - unreal.LevelStreamingDynamic - ) - EditorLevelLibrary.save_all_dirty_levels() - EditorLevelLibrary.load_level(level) + if master_level: + EditorLevelLibrary.load_level(master_level) + EditorLevelUtils.add_level_to_world( + EditorLevelLibrary.get_editor_world(), + level, + unreal.LevelStreamingDynamic + ) + EditorLevelLibrary.save_all_dirty_levels() + EditorLevelLibrary.load_level(level) # Get all the sequences in the hierarchy. It will create them, if # they don't exist. @@ -664,11 +699,12 @@ class LayoutLoader(plugin.Loader): unreal.FrameRate(data.get("fps"), 1.0)) shot.set_playback_start(0) shot.set_playback_end(data.get('clipOut') - data.get('clipIn') + 1) - self._set_sequence_hierarchy( - sequences[-1], shot, - frame_ranges[-1][1], - data.get('clipIn'), data.get('clipOut'), - [level]) + if sequences: + self._set_sequence_hierarchy( + sequences[-1], shot, + frame_ranges[-1][1], + data.get('clipIn'), data.get('clipOut'), + [level]) EditorLevelLibrary.load_level(level) @@ -705,7 +741,8 @@ class LayoutLoader(plugin.Loader): for a in asset_content: EditorAssetLibrary.save_asset(a) - EditorLevelLibrary.load_level(master_level) + if master_level: + EditorLevelLibrary.load_level(master_level) return asset_content From b9f81b64ff81c74ef86698ce7e3ce69ec21485e3 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Tue, 21 Jun 2022 17:11:08 +0100 Subject: [PATCH 044/282] Hound fixes --- openpype/hosts/unreal/plugins/load/load_layout.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index ee31d32811..fb8f46dad1 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -485,7 +485,8 @@ class LayoutLoader(plugin.Loader): loader = self._get_abc_loader(loaders, family) if not loader: - self.log.error(f"No valid loader found for {representation}") + self.log.error( + f"No valid loader found for {representation}") continue options = { @@ -512,7 +513,7 @@ class LayoutLoader(plugin.Loader): instances = [ item for item in data - if ((item.get('version') and + if ((item.get('version') and item.get('version') == element.get('version')) or item.get('reference_fbx') == representation or item.get('reference_abc') == representation)] From 0353ec38f3593c9e81a9b82a735ab7868e406d9f Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Fri, 1 Jul 2022 11:06:44 +0100 Subject: [PATCH 045/282] Generalization of the basis of the origin platform in the JSON layout --- .../blender/plugins/publish/extract_layout.py | 14 ++++- .../maya/plugins/publish/extract_layout.py | 50 +++++++++++++-- .../plugins/load/load_alembic_staticmesh.py | 6 +- .../hosts/unreal/plugins/load/load_layout.py | 63 ++++++++++--------- 4 files changed, 97 insertions(+), 36 deletions(-) diff --git a/openpype/hosts/blender/plugins/publish/extract_layout.py b/openpype/hosts/blender/plugins/publish/extract_layout.py index 8ecc78a2c6..f987dffe05 100644 --- a/openpype/hosts/blender/plugins/publish/extract_layout.py +++ b/openpype/hosts/blender/plugins/publish/extract_layout.py @@ -193,7 +193,7 @@ class ExtractLayout(openpype.api.Extractor): "rotation": { "x": asset.rotation_euler.x, "y": asset.rotation_euler.y, - "z": asset.rotation_euler.z, + "z": asset.rotation_euler.z }, "scale": { "x": asset.scale.x, @@ -202,6 +202,18 @@ class ExtractLayout(openpype.api.Extractor): } } + json_element["transform_matrix"] = [] + + for row in list(asset.matrix_world.transposed()): + json_element["transform_matrix"].append(list(row)) + + json_element["basis"] = [ + [1, 0, 0, 0], + [0, -1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1] + ] + # Extract the animation as well if family == "rig": f, n = self._export_animation( diff --git a/openpype/hosts/maya/plugins/publish/extract_layout.py b/openpype/hosts/maya/plugins/publish/extract_layout.py index 4ae99f1052..7eb6a64e6d 100644 --- a/openpype/hosts/maya/plugins/publish/extract_layout.py +++ b/openpype/hosts/maya/plugins/publish/extract_layout.py @@ -1,7 +1,9 @@ +import math import os import json from maya import cmds +from maya.api import OpenMaya as om from bson.objectid import ObjectId @@ -60,7 +62,7 @@ class ExtractLayout(openpype.api.Extractor): } loc = cmds.xform(asset, query=True, translation=True) - rot = cmds.xform(asset, query=True, rotation=True) + rot = cmds.xform(asset, query=True, rotation=True, euler=True) scl = cmds.xform(asset, query=True, relative=True, scale=True) json_element["transform"] = { @@ -70,9 +72,9 @@ class ExtractLayout(openpype.api.Extractor): "z": loc[2] }, "rotation": { - "x": rot[0], - "y": rot[1], - "z": rot[2] + "x": math.radians(rot[0]), + "y": math.radians(rot[1]), + "z": math.radians(rot[2]) }, "scale": { "x": scl[0], @@ -81,6 +83,46 @@ class ExtractLayout(openpype.api.Extractor): } } + row_length = 4 + t_matrix_list = cmds.xform(asset, query=True, matrix=True) + + transform_mm = om.MMatrix(t_matrix_list) + transform = om.MTransformationMatrix(transform_mm) + + transform.scaleBy([1.0, 1.0, -1.0], om.MSpace.kWorld) + transform.rotateBy( + om.MEulerRotation(math.radians(-90), 0, 0), om.MSpace.kWorld) + + t_matrix_list = list(transform.asMatrix()) + + t_matrix = [] + for i in range(0, len(t_matrix_list), row_length): + t_matrix.append(t_matrix_list[i:i + row_length]) + + json_element["transform_matrix"] = [] + for row in t_matrix: + json_element["transform_matrix"].append(list(row)) + + basis_list = [ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, -1, 0, + 0, 0, 0, 1 + ] + + basis_mm = om.MMatrix(basis_list) + basis = om.MTransformationMatrix(basis_mm) + + b_matrix_list = list(basis.asMatrix()) + b_matrix = [] + + for i in range(0, len(b_matrix_list), row_length): + b_matrix.append(b_matrix_list[i:i + row_length]) + + json_element["basis"] = [] + for row in b_matrix: + json_element["basis"].append(list(row)) + json_data.append(json_element) json_filename = "{}.json".format(instance.name) diff --git a/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py b/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py index 691971e02f..42abbda80f 100644 --- a/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py +++ b/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py @@ -26,9 +26,9 @@ class StaticMeshAlembicLoader(plugin.Loader): sm_settings = unreal.AbcStaticMeshSettings() conversion_settings = unreal.AbcConversionSettings( preset=unreal.AbcConversionPreset.CUSTOM, - flip_u=False, flip_v=True, - rotation=[90.0, 0.0, 0.0], - scale=[1.0, -1.0, 1.0]) + flip_u=False, flip_v=False, + rotation=[0.0, 0.0, 0.0], + scale=[1.0, 1.0, 1.0]) task.set_editor_property('filename', filename) task.set_editor_property('destination_path', asset_dir) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index fb8f46dad1..361c3684fa 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- """Loader for layouts.""" -import os import json from pathlib import Path @@ -170,9 +169,29 @@ class LayoutLoader(plugin.Loader): hid_section.set_row_index(index) hid_section.set_level_names(maps) - @staticmethod + def _transform_from_basis(self, transform, basis): + """Transform a transform from a basis to a new basis.""" + # Get the basis matrix + basis_matrix = unreal.Matrix( + basis[0], + basis[1], + basis[2], + basis[3] + ) + transform_matrix = unreal.Matrix( + transform[0], + transform[1], + transform[2], + transform[3] + ) + + new_transform = ( + basis_matrix.get_inverse() * transform_matrix * basis_matrix) + + return new_transform.transform() + def _process_family( - assets, class_name, transform, sequence, inst_name=None + self, assets, class_name, transform, basis, sequence, inst_name=None ): ar = unreal.AssetRegistryHelpers.get_asset_registry() @@ -182,30 +201,12 @@ class LayoutLoader(plugin.Loader): for asset in assets: obj = ar.get_asset_by_object_path(asset).get_asset() if obj.get_class().get_name() == class_name: + t = self._transform_from_basis(transform, basis) actor = EditorLevelLibrary.spawn_actor_from_object( - obj, - transform.get('translation') + obj, t.translation ) - if inst_name: - try: - # Rename method leads to crash - # actor.rename(name=inst_name) - - # The label works, although it make it slightly more - # complicated to check for the names, as we need to - # loop through all the actors in the level - actor.set_actor_label(inst_name) - except Exception as e: - print(e) - actor.set_actor_rotation(unreal.Rotator( - ( - transform.get('rotation').get('x')), - ( - transform.get('rotation').get('z')), - -( - transform.get('rotation').get('y')), - ), False) - actor.set_actor_scale3d(transform.get('scale')) + actor.set_actor_rotation(t.rotation.rotator(), False) + actor.set_actor_scale3d(t.scale3d) if class_name == 'SkeletalMesh': skm_comp = actor.get_editor_property( @@ -519,17 +520,23 @@ class LayoutLoader(plugin.Loader): item.get('reference_abc') == representation)] for instance in instances: - transform = instance.get('transform') + # transform = instance.get('transform') + transform = instance.get('transform_matrix') + basis = instance.get('basis') inst = instance.get('instance_name') actors = [] if family == 'model': actors, _ = self._process_family( - assets, 'StaticMesh', transform, sequence, inst) + assets, 'StaticMesh', transform, basis, + sequence, inst + ) elif family == 'rig': actors, bindings = self._process_family( - assets, 'SkeletalMesh', transform, sequence, inst) + assets, 'SkeletalMesh', transform, basis, + sequence, inst + ) actors_dict[inst] = actors bindings_dict[inst] = bindings From 1bf95ddce5587c25258c9a7a7b07cf3a555b745b Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Wed, 6 Jul 2022 17:00:35 +0100 Subject: [PATCH 046/282] Fix Maya transform --- openpype/hosts/maya/plugins/publish/extract_layout.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_layout.py b/openpype/hosts/maya/plugins/publish/extract_layout.py index 7eb6a64e6d..991217684a 100644 --- a/openpype/hosts/maya/plugins/publish/extract_layout.py +++ b/openpype/hosts/maya/plugins/publish/extract_layout.py @@ -89,9 +89,12 @@ class ExtractLayout(openpype.api.Extractor): transform_mm = om.MMatrix(t_matrix_list) transform = om.MTransformationMatrix(transform_mm) - transform.scaleBy([1.0, 1.0, -1.0], om.MSpace.kWorld) + t = transform.translation(om.MSpace.kWorld) + t = om.MVector(t.x, t.z, -t.y) + transform.setTranslation(t, om.MSpace.kWorld) transform.rotateBy( om.MEulerRotation(math.radians(-90), 0, 0), om.MSpace.kWorld) + transform.scaleBy([1.0, 1.0, -1.0], om.MSpace.kObject) t_matrix_list = list(transform.asMatrix()) From 3555143f06e61dd68e072f192f76f23bff40e5cc Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 11 Jul 2022 17:15:42 +0100 Subject: [PATCH 047/282] Load layouts without sequences. --- .../hosts/unreal/plugins/load/load_layout.py | 431 +++++++++--------- 1 file changed, 227 insertions(+), 204 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index 361c3684fa..0dbaf0880a 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -215,16 +215,17 @@ class LayoutLoader(plugin.Loader): actors.append(actor) - binding = None - for p in sequence.get_possessables(): - if p.get_name() == actor.get_name(): - binding = p - break + if sequence: + binding = None + for p in sequence.get_possessables(): + if p.get_name() == actor.get_name(): + binding = p + break - if not binding: - binding = sequence.add_possessable(actor) + if not binding: + binding = sequence.add_possessable(actor) - bindings.append(binding) + bindings.append(binding) return actors, bindings @@ -312,49 +313,50 @@ class LayoutLoader(plugin.Loader): actor.skeletal_mesh_component.animation_data.set_editor_property( 'anim_to_play', animation) - # Add animation to the sequencer - bindings = bindings_dict.get(instance_name) + if sequence: + # Add animation to the sequencer + bindings = bindings_dict.get(instance_name) - ar = unreal.AssetRegistryHelpers.get_asset_registry() + ar = unreal.AssetRegistryHelpers.get_asset_registry() - for binding in bindings: - tracks = binding.get_tracks() - track = None - track = tracks[0] if tracks else binding.add_track( - unreal.MovieSceneSkeletalAnimationTrack) + for binding in bindings: + tracks = binding.get_tracks() + track = None + track = tracks[0] if tracks else binding.add_track( + unreal.MovieSceneSkeletalAnimationTrack) - sections = track.get_sections() - section = None - if not sections: - section = track.add_section() - else: - section = sections[0] + sections = track.get_sections() + section = None + if not sections: + section = track.add_section() + else: + section = sections[0] + sec_params = section.get_editor_property('params') + curr_anim = sec_params.get_editor_property('animation') + + if curr_anim: + # Checks if the animation path has a container. + # If it does, it means that the animation is + # already in the sequencer. + anim_path = str(Path( + curr_anim.get_path_name()).parent + ).replace('\\', '/') + + _filter = unreal.ARFilter( + class_names=["AssetContainer"], + package_paths=[anim_path], + recursive_paths=False) + containers = ar.get_assets(_filter) + + if len(containers) > 0: + return + + section.set_range( + sequence.get_playback_start(), + sequence.get_playback_end()) sec_params = section.get_editor_property('params') - curr_anim = sec_params.get_editor_property('animation') - - if curr_anim: - # Checks if the animation path has a container. - # If it does, it means that the animation is already - # in the sequencer. - anim_path = str(Path( - curr_anim.get_path_name()).parent - ).replace('\\', '/') - - _filter = unreal.ARFilter( - class_names=["AssetContainer"], - package_paths=[anim_path], - recursive_paths=False) - containers = ar.get_assets(_filter) - - if len(containers) > 0: - return - - section.set_range( - sequence.get_playback_start(), - sequence.get_playback_end()) - sec_params = section.get_editor_property('params') - sec_params.set_editor_property('animation', animation) + sec_params.set_editor_property('animation', animation) @staticmethod def _generate_sequence(h, h_dir): @@ -617,6 +619,9 @@ class LayoutLoader(plugin.Loader): Returns: list(str): list of container content """ + # TODO: get option from OpenPype settings + create_sequences = False + # Create directory for asset and avalon container hierarchy = context.get('asset').get('data').get('parents') root = self.ASSET_ROOT @@ -637,85 +642,88 @@ class LayoutLoader(plugin.Loader): EditorAssetLibrary.make_directory(asset_dir) - # Create map for the shot, and create hierarchy of map. If the maps - # already exist, we will use them. master_level = None - if hierarchy: - h_dir = hierarchy_dir_list[0] - h_asset = hierarchy[0] - master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map" - if not EditorAssetLibrary.does_asset_exist(master_level): - EditorLevelLibrary.new_level(f"{h_dir}/{h_asset}_map") + shot = None + sequences = [] level = f"{asset_dir}/{asset}_map.{asset}_map" EditorLevelLibrary.new_level(f"{asset_dir}/{asset}_map") - if master_level: - EditorLevelLibrary.load_level(master_level) - EditorLevelUtils.add_level_to_world( - EditorLevelLibrary.get_editor_world(), - level, - unreal.LevelStreamingDynamic + if create_sequences: + # Create map for the shot, and create hierarchy of map. If the maps + # already exist, we will use them. + if hierarchy: + h_dir = hierarchy_dir_list[0] + h_asset = hierarchy[0] + master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map" + if not EditorAssetLibrary.does_asset_exist(master_level): + EditorLevelLibrary.new_level(f"{h_dir}/{h_asset}_map") + + if master_level: + EditorLevelLibrary.load_level(master_level) + EditorLevelUtils.add_level_to_world( + EditorLevelLibrary.get_editor_world(), + level, + unreal.LevelStreamingDynamic + ) + EditorLevelLibrary.save_all_dirty_levels() + EditorLevelLibrary.load_level(level) + + # Get all the sequences in the hierarchy. It will create them, if + # they don't exist. + frame_ranges = [] + for (h_dir, h) in zip(hierarchy_dir_list, hierarchy): + root_content = EditorAssetLibrary.list_assets( + h_dir, recursive=False, include_folder=False) + + existing_sequences = [ + EditorAssetLibrary.find_asset_data(asset) + for asset in root_content + if EditorAssetLibrary.find_asset_data( + asset).get_class().get_name() == 'LevelSequence' + ] + + if not existing_sequences: + sequence, frame_range = self._generate_sequence(h, h_dir) + + sequences.append(sequence) + frame_ranges.append(frame_range) + else: + for e in existing_sequences: + sequences.append(e.get_asset()) + frame_ranges.append(( + e.get_asset().get_playback_start(), + e.get_asset().get_playback_end())) + + shot = tools.create_asset( + asset_name=asset, + package_path=asset_dir, + asset_class=unreal.LevelSequence, + factory=unreal.LevelSequenceFactoryNew() ) - EditorLevelLibrary.save_all_dirty_levels() + + # sequences and frame_ranges have the same length + for i in range(0, len(sequences) - 1): + self._set_sequence_hierarchy( + sequences[i], sequences[i + 1], + frame_ranges[i][1], + frame_ranges[i + 1][0], frame_ranges[i + 1][1], + [level]) + + data = self._get_data(asset) + shot.set_display_rate( + unreal.FrameRate(data.get("fps"), 1.0)) + shot.set_playback_start(0) + shot.set_playback_end(data.get('clipOut') - data.get('clipIn') + 1) + if sequences: + self._set_sequence_hierarchy( + sequences[-1], shot, + frame_ranges[-1][1], + data.get('clipIn'), data.get('clipOut'), + [level]) + EditorLevelLibrary.load_level(level) - # Get all the sequences in the hierarchy. It will create them, if - # they don't exist. - sequences = [] - frame_ranges = [] - for (h_dir, h) in zip(hierarchy_dir_list, hierarchy): - root_content = EditorAssetLibrary.list_assets( - h_dir, recursive=False, include_folder=False) - - existing_sequences = [ - EditorAssetLibrary.find_asset_data(asset) - for asset in root_content - if EditorAssetLibrary.find_asset_data( - asset).get_class().get_name() == 'LevelSequence' - ] - - if not existing_sequences: - sequence, frame_range = self._generate_sequence(h, h_dir) - - sequences.append(sequence) - frame_ranges.append(frame_range) - else: - for e in existing_sequences: - sequences.append(e.get_asset()) - frame_ranges.append(( - e.get_asset().get_playback_start(), - e.get_asset().get_playback_end())) - - shot = tools.create_asset( - asset_name=asset, - package_path=asset_dir, - asset_class=unreal.LevelSequence, - factory=unreal.LevelSequenceFactoryNew() - ) - - # sequences and frame_ranges have the same length - for i in range(0, len(sequences) - 1): - self._set_sequence_hierarchy( - sequences[i], sequences[i + 1], - frame_ranges[i][1], - frame_ranges[i + 1][0], frame_ranges[i + 1][1], - [level]) - - data = self._get_data(asset) - shot.set_display_rate( - unreal.FrameRate(data.get("fps"), 1.0)) - shot.set_playback_start(0) - shot.set_playback_end(data.get('clipOut') - data.get('clipIn') + 1) - if sequences: - self._set_sequence_hierarchy( - sequences[-1], shot, - frame_ranges[-1][1], - data.get('clipIn'), data.get('clipOut'), - [level]) - - EditorLevelLibrary.load_level(level) - loaded_assets = self._process(self.fname, asset_dir, shot) for s in sequences: @@ -755,27 +763,31 @@ class LayoutLoader(plugin.Loader): return asset_content def update(self, container, representation): + # TODO: get option from OpenPype settings + create_sequences = False + ar = unreal.AssetRegistryHelpers.get_asset_registry() root = "/Game/OpenPype" asset_dir = container.get('namespace') - context = representation.get("context") - hierarchy = context.get('hierarchy').split("/") - h_dir = f"{root}/{hierarchy[0]}" - h_asset = hierarchy[0] - master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map" + sequence = None + master_level = None - # # Create a temporary level to delete the layout level. - # EditorLevelLibrary.save_all_dirty_levels() - # EditorAssetLibrary.make_directory(f"{root}/tmp") - # tmp_level = f"{root}/tmp/temp_map" - # if not EditorAssetLibrary.does_asset_exist(f"{tmp_level}.temp_map"): - # EditorLevelLibrary.new_level(tmp_level) - # else: - # EditorLevelLibrary.load_level(tmp_level) + if create_sequences: + hierarchy = context.get('hierarchy').split("/") + h_dir = f"{root}/{hierarchy[0]}" + h_asset = hierarchy[0] + master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map" + + filter = unreal.ARFilter( + class_names=["LevelSequence"], + package_paths=[asset_dir], + recursive_paths=False) + sequences = ar.get_assets(filter) + sequence = sequences[0].get_asset() # Get layout level filter = unreal.ARFilter( @@ -783,11 +795,6 @@ class LayoutLoader(plugin.Loader): package_paths=[asset_dir], recursive_paths=False) levels = ar.get_assets(filter) - filter = unreal.ARFilter( - class_names=["LevelSequence"], - package_paths=[asset_dir], - recursive_paths=False) - sequences = ar.get_assets(filter) layout_level = levels[0].get_editor_property('object_path') @@ -799,14 +806,14 @@ class LayoutLoader(plugin.Loader): for actor in actors: unreal.EditorLevelLibrary.destroy_actor(actor) - EditorLevelLibrary.save_current_level() + if create_sequences: + EditorLevelLibrary.save_current_level() EditorAssetLibrary.delete_directory(f"{asset_dir}/animations/") source_path = get_representation_path(representation) - loaded_assets = self._process( - source_path, asset_dir, sequences[0].get_asset()) + loaded_assets = self._process(source_path, asset_dir, sequence) data = { "representation": str(representation["_id"]), @@ -824,13 +831,18 @@ class LayoutLoader(plugin.Loader): for a in asset_content: EditorAssetLibrary.save_asset(a) - EditorLevelLibrary.load_level(master_level) + if master_level: + EditorLevelLibrary.load_level(master_level) def remove(self, container): """ Delete the layout. First, check if the assets loaded with the layout are used by other layouts. If not, delete the assets. """ + # TODO: get option from OpenPype settings + create_sequences = False + + root = "/Game/OpenPype" path = Path(container.get("namespace")) containers = unreal_pipeline.ls() @@ -841,7 +853,7 @@ class LayoutLoader(plugin.Loader): # Check if the assets have been loaded by other layouts, and deletes # them if they haven't. - for asset in container.get('loaded_assets'): + for asset in eval(container.get('loaded_assets')): layouts = [ lc for lc in layout_containers if asset in lc.get('loaded_assets')] @@ -849,71 +861,83 @@ class LayoutLoader(plugin.Loader): if not layouts: EditorAssetLibrary.delete_directory(str(Path(asset).parent)) - # Remove the Level Sequence from the parent. - # We need to traverse the hierarchy from the master sequence to find - # the level sequence. - root = "/Game/OpenPype" - namespace = container.get('namespace').replace(f"{root}/", "") - ms_asset = namespace.split('/')[0] - ar = unreal.AssetRegistryHelpers.get_asset_registry() - _filter = unreal.ARFilter( - class_names=["LevelSequence"], - package_paths=[f"{root}/{ms_asset}"], - recursive_paths=False) - sequences = ar.get_assets(_filter) - master_sequence = sequences[0].get_asset() - _filter = unreal.ARFilter( - class_names=["World"], - package_paths=[f"{root}/{ms_asset}"], - recursive_paths=False) - levels = ar.get_assets(_filter) - master_level = levels[0].get_editor_property('object_path') + # Delete the parent folder if there aren't any more layouts in it. + asset_content = EditorAssetLibrary.list_assets( + str(Path(asset).parent.parent), recursive=False, include_folder=True + ) - sequences = [master_sequence] + if len(asset_content) == 0: + EditorAssetLibrary.delete_directory(str(Path(asset).parent.parent)) - parent = None - for s in sequences: - tracks = s.get_master_tracks() - subscene_track = None - visibility_track = None - for t in tracks: - if t.get_class() == unreal.MovieSceneSubTrack.static_class(): - subscene_track = t - if (t.get_class() == - unreal.MovieSceneLevelVisibilityTrack.static_class()): - visibility_track = t - if subscene_track: - sections = subscene_track.get_sections() - for ss in sections: - if ss.get_sequence().get_name() == container.get('asset'): - parent = s - subscene_track.remove_section(ss) - break - sequences.append(ss.get_sequence()) - # Update subscenes indexes. - i = 0 - for ss in sections: - ss.set_row_index(i) - i += 1 + master_sequence = None + master_level = None + sequences = [] - if visibility_track: - sections = visibility_track.get_sections() - for ss in sections: - if (unreal.Name(f"{container.get('asset')}_map") - in ss.get_level_names()): - visibility_track.remove_section(ss) - # Update visibility sections indexes. - i = -1 - prev_name = [] - for ss in sections: - if prev_name != ss.get_level_names(): + if create_sequences: + # Remove the Level Sequence from the parent. + # We need to traverse the hierarchy from the master sequence to find + # the level sequence. + namespace = container.get('namespace').replace(f"{root}/", "") + ms_asset = namespace.split('/')[0] + ar = unreal.AssetRegistryHelpers.get_asset_registry() + _filter = unreal.ARFilter( + class_names=["LevelSequence"], + package_paths=[f"{root}/{ms_asset}"], + recursive_paths=False) + sequences = ar.get_assets(_filter) + master_sequence = sequences[0].get_asset() + _filter = unreal.ARFilter( + class_names=["World"], + package_paths=[f"{root}/{ms_asset}"], + recursive_paths=False) + levels = ar.get_assets(_filter) + master_level = levels[0].get_editor_property('object_path') + + sequences = [master_sequence] + + parent = None + for s in sequences: + tracks = s.get_master_tracks() + subscene_track = None + visibility_track = None + for t in tracks: + if t.get_class() == unreal.MovieSceneSubTrack.static_class(): + subscene_track = t + if (t.get_class() == + unreal.MovieSceneLevelVisibilityTrack.static_class()): + visibility_track = t + if subscene_track: + sections = subscene_track.get_sections() + for ss in sections: + if ss.get_sequence().get_name() == container.get('asset'): + parent = s + subscene_track.remove_section(ss) + break + sequences.append(ss.get_sequence()) + # Update subscenes indexes. + i = 0 + for ss in sections: + ss.set_row_index(i) i += 1 - ss.set_row_index(i) - prev_name = ss.get_level_names() - if parent: - break - assert parent, "Could not find the parent sequence" + if visibility_track: + sections = visibility_track.get_sections() + for ss in sections: + if (unreal.Name(f"{container.get('asset')}_map") + in ss.get_level_names()): + visibility_track.remove_section(ss) + # Update visibility sections indexes. + i = -1 + prev_name = [] + for ss in sections: + if prev_name != ss.get_level_names(): + i += 1 + ss.set_row_index(i) + prev_name = ss.get_level_names() + if parent: + break + + assert parent, "Could not find the parent sequence" # Create a temporary level to delete the layout level. EditorLevelLibrary.save_all_dirty_levels() @@ -927,10 +951,9 @@ class LayoutLoader(plugin.Loader): # Delete the layout directory. EditorAssetLibrary.delete_directory(str(path)) - EditorLevelLibrary.load_level(master_level) - EditorAssetLibrary.delete_directory(f"{root}/tmp") - - EditorLevelLibrary.save_current_level() + if create_sequences: + EditorLevelLibrary.load_level(master_level) + EditorAssetLibrary.delete_directory(f"{root}/tmp") # Delete the parent folder if there aren't any more layouts in it. asset_content = EditorAssetLibrary.list_assets( From ef35c17ba484de54ce43998a437e7775e1d5b557 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 11 Jul 2022 17:19:54 +0100 Subject: [PATCH 048/282] Hound fixes --- .../hosts/unreal/plugins/load/load_layout.py | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index 0dbaf0880a..7c8f78bd9a 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -9,7 +9,8 @@ from unreal import EditorLevelLibrary from unreal import EditorLevelUtils from unreal import AssetToolsHelpers from unreal import FBXImportType -from unreal import MathLibrary as umath +from unreal import MovieSceneLevelVisibilityTrack +from unreal import MovieSceneSubTrack from bson.objectid import ObjectId @@ -650,8 +651,8 @@ class LayoutLoader(plugin.Loader): EditorLevelLibrary.new_level(f"{asset_dir}/{asset}_map") if create_sequences: - # Create map for the shot, and create hierarchy of map. If the maps - # already exist, we will use them. + # Create map for the shot, and create hierarchy of map. If the + # maps already exist, we will use them. if hierarchy: h_dir = hierarchy_dir_list[0] h_asset = hierarchy[0] @@ -861,13 +862,16 @@ class LayoutLoader(plugin.Loader): if not layouts: EditorAssetLibrary.delete_directory(str(Path(asset).parent)) - # Delete the parent folder if there aren't any more layouts in it. + # Delete the parent folder if there aren't any more + # layouts in it. asset_content = EditorAssetLibrary.list_assets( - str(Path(asset).parent.parent), recursive=False, include_folder=True + str(Path(asset).parent.parent), recursive=False, + include_folder=True ) if len(asset_content) == 0: - EditorAssetLibrary.delete_directory(str(Path(asset).parent.parent)) + EditorAssetLibrary.delete_directory( + str(Path(asset).parent.parent)) master_sequence = None master_level = None @@ -875,8 +879,8 @@ class LayoutLoader(plugin.Loader): if create_sequences: # Remove the Level Sequence from the parent. - # We need to traverse the hierarchy from the master sequence to find - # the level sequence. + # We need to traverse the hierarchy from the master sequence to + # find the level sequence. namespace = container.get('namespace').replace(f"{root}/", "") ms_asset = namespace.split('/')[0] ar = unreal.AssetRegistryHelpers.get_asset_registry() @@ -901,15 +905,16 @@ class LayoutLoader(plugin.Loader): subscene_track = None visibility_track = None for t in tracks: - if t.get_class() == unreal.MovieSceneSubTrack.static_class(): + if t.get_class() == MovieSceneSubTrack.static_class(): subscene_track = t if (t.get_class() == - unreal.MovieSceneLevelVisibilityTrack.static_class()): + MovieSceneLevelVisibilityTrack.static_class()): visibility_track = t if subscene_track: sections = subscene_track.get_sections() for ss in sections: - if ss.get_sequence().get_name() == container.get('asset'): + if (ss.get_sequence().get_name() == + container.get('asset')): parent = s subscene_track.remove_section(ss) break From 5de5a37475f4fbab6d02d7a83776adb8646dbfda Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 11 Jul 2022 17:21:10 +0100 Subject: [PATCH 049/282] More hound fixes --- openpype/hosts/unreal/plugins/load/load_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index 7c8f78bd9a..f600a131c5 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -879,7 +879,7 @@ class LayoutLoader(plugin.Loader): if create_sequences: # Remove the Level Sequence from the parent. - # We need to traverse the hierarchy from the master sequence to + # We need to traverse the hierarchy from the master sequence to # find the level sequence. namespace = container.get('namespace').replace(f"{root}/", "") ms_asset = namespace.split('/')[0] From a2361d8283f55e91e7e5c2a9c30a4d8cea4cd7fc Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 11 Jul 2022 17:27:37 +0100 Subject: [PATCH 050/282] Set conversion settings for abc Skeletal Meshes --- .../plugins/load/load_alembic_skeletalmesh.py | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py b/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py index b2c3889f68..d51a3ae0af 100644 --- a/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py +++ b/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py @@ -20,6 +20,34 @@ class SkeletalMeshAlembicLoader(plugin.Loader): icon = "cube" color = "orange" + def get_task(self, filename, asset_dir, asset_name, replace): + task = unreal.AssetImportTask() + options = unreal.AbcImportSettings() + sm_settings = unreal.AbcStaticMeshSettings() + conversion_settings = unreal.AbcConversionSettings( + preset=unreal.AbcConversionPreset.CUSTOM, + flip_u=False, flip_v=False, + rotation=[0.0, 0.0, 0.0], + scale=[1.0, 1.0, 1.0]) + + task.set_editor_property('filename', filename) + task.set_editor_property('destination_path', asset_dir) + task.set_editor_property('destination_name', asset_name) + task.set_editor_property('replace_existing', replace) + task.set_editor_property('automated', True) + task.set_editor_property('save', True) + + # set import options here + # Unreal 4.24 ignores the settings. It works with Unreal 4.26 + options.set_editor_property( + 'import_type', unreal.AlembicImportType.SKELETAL) + + options.static_mesh_settings = sm_settings + options.conversion_settings = conversion_settings + task.options = options + + return task + def load(self, context, name, namespace, data): """Load and containerise representation into Content Browser. @@ -59,22 +87,8 @@ class SkeletalMeshAlembicLoader(plugin.Loader): unreal.EditorAssetLibrary.make_directory(asset_dir) - task = unreal.AssetImportTask() + task = self.get_task(self.fname, asset_dir, asset_name, False) - task.set_editor_property('filename', self.fname) - task.set_editor_property('destination_path', asset_dir) - task.set_editor_property('destination_name', asset_name) - task.set_editor_property('replace_existing', False) - task.set_editor_property('automated', True) - task.set_editor_property('save', True) - - # set import options here - # Unreal 4.24 ignores the settings. It works with Unreal 4.26 - options = unreal.AbcImportSettings() - options.set_editor_property( - 'import_type', unreal.AlembicImportType.SKELETAL) - - task.options = options unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # noqa: E501 # Create Asset Container @@ -110,23 +124,8 @@ class SkeletalMeshAlembicLoader(plugin.Loader): source_path = get_representation_path(representation) destination_path = container["namespace"] - task = unreal.AssetImportTask() + task = self.get_task(source_path, destination_path, name, True) - task.set_editor_property('filename', source_path) - task.set_editor_property('destination_path', destination_path) - # strip suffix - task.set_editor_property('destination_name', name) - task.set_editor_property('replace_existing', True) - task.set_editor_property('automated', True) - task.set_editor_property('save', True) - - # set import options here - # Unreal 4.24 ignores the settings. It works with Unreal 4.26 - options = unreal.AbcImportSettings() - options.set_editor_property( - 'import_type', unreal.AlembicImportType.SKELETAL) - - task.options = options # do import fbx and replace existing data unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) container_path = "{}/{}".format(container["namespace"], From 46e2f629299a66b388d449d3ec29b2e296307348 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 11 Jul 2022 17:34:56 +0100 Subject: [PATCH 051/282] Avoid overwriting and reloading of loaded assets --- .../plugins/load/load_alembic_skeletalmesh.py | 16 +++++++++------- .../plugins/load/load_alembic_staticmesh.py | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py b/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py index d51a3ae0af..9fe5f3ab4b 100644 --- a/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py +++ b/openpype/hosts/unreal/plugins/load/load_alembic_skeletalmesh.py @@ -78,22 +78,24 @@ class SkeletalMeshAlembicLoader(plugin.Loader): asset_name = "{}_{}".format(asset, name) else: asset_name = "{}".format(name) + version = context.get('version').get('name') tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( - "{}/{}/{}".format(root, asset, name), suffix="") + f"{root}/{asset}/{name}_v{version:03d}", suffix="") container_name += suffix - unreal.EditorAssetLibrary.make_directory(asset_dir) + if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir): + unreal.EditorAssetLibrary.make_directory(asset_dir) - task = self.get_task(self.fname, asset_dir, asset_name, False) + task = self.get_task(self.fname, asset_dir, asset_name, False) - unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # noqa: E501 + unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # noqa: E501 - # Create Asset Container - unreal_pipeline.create_container( - container=container_name, path=asset_dir) + # Create Asset Container + unreal_pipeline.create_container( + container=container_name, path=asset_dir) data = { "schema": "openpype:container-2.0", diff --git a/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py b/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py index 42abbda80f..50e498dbb0 100644 --- a/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py +++ b/openpype/hosts/unreal/plugins/load/load_alembic_staticmesh.py @@ -80,22 +80,24 @@ class StaticMeshAlembicLoader(plugin.Loader): asset_name = "{}_{}".format(asset, name) else: asset_name = "{}".format(name) + version = context.get('version').get('name') tools = unreal.AssetToolsHelpers().get_asset_tools() asset_dir, container_name = tools.create_unique_asset_name( - "{}/{}/{}".format(root, asset, name), suffix="") + f"{root}/{asset}/{name}_v{version:03d}", suffix="") container_name += suffix - unreal.EditorAssetLibrary.make_directory(asset_dir) + if not unreal.EditorAssetLibrary.does_directory_exist(asset_dir): + unreal.EditorAssetLibrary.make_directory(asset_dir) - task = self.get_task(self.fname, asset_dir, asset_name, False) + task = self.get_task(self.fname, asset_dir, asset_name, False) - unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # noqa: E501 + unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([task]) # noqa: E501 - # Create Asset Container - unreal_pipeline.create_container( - container=container_name, path=asset_dir) + # Create Asset Container + unreal_pipeline.create_container( + container=container_name, path=asset_dir) data = { "schema": "openpype:container-2.0", From 2e8e4a0ee9724f0345038f1b9a2d78954ecf476d Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Tue, 12 Jul 2022 16:31:03 +0100 Subject: [PATCH 052/282] Added setting to generate sequences for layouts --- openpype/hosts/unreal/plugins/load/load_layout.py | 13 +++++++------ .../settings/defaults/project_settings/unreal.json | 1 + .../projects_schema/schema_project_unreal.json | 5 +++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index f600a131c5..727488ee66 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -23,6 +23,7 @@ from openpype.pipeline import ( legacy_io, ) from openpype.api import get_asset +from openpype.api import get_current_project_settings from openpype.hosts.unreal.api import plugin from openpype.hosts.unreal.api import pipeline as unreal_pipeline @@ -620,8 +621,8 @@ class LayoutLoader(plugin.Loader): Returns: list(str): list of container content """ - # TODO: get option from OpenPype settings - create_sequences = False + data = get_current_project_settings() + create_sequences = data["unreal"]["level_sequences_for_layouts"] # Create directory for asset and avalon container hierarchy = context.get('asset').get('data').get('parents') @@ -764,8 +765,8 @@ class LayoutLoader(plugin.Loader): return asset_content def update(self, container, representation): - # TODO: get option from OpenPype settings - create_sequences = False + data = get_current_project_settings() + create_sequences = data["unreal"]["level_sequences_for_layouts"] ar = unreal.AssetRegistryHelpers.get_asset_registry() @@ -840,8 +841,8 @@ class LayoutLoader(plugin.Loader): Delete the layout. First, check if the assets loaded with the layout are used by other layouts. If not, delete the assets. """ - # TODO: get option from OpenPype settings - create_sequences = False + data = get_current_project_settings() + create_sequences = data["unreal"]["level_sequences_for_layouts"] root = "/Game/OpenPype" path = Path(container.get("namespace")) diff --git a/openpype/settings/defaults/project_settings/unreal.json b/openpype/settings/defaults/project_settings/unreal.json index dad61cd1f0..c5f5cdf719 100644 --- a/openpype/settings/defaults/project_settings/unreal.json +++ b/openpype/settings/defaults/project_settings/unreal.json @@ -1,4 +1,5 @@ { + "level_sequences_for_layouts": false, "project_setup": { "dev_mode": true } diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_unreal.json b/openpype/settings/entities/schemas/projects_schema/schema_project_unreal.json index 4e197e9fc8..d26b5c1ccf 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_unreal.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_unreal.json @@ -5,6 +5,11 @@ "label": "Unreal Engine", "is_file": true, "children": [ + { + "type": "boolean", + "key": "level_sequences_for_layouts", + "label": "Generate level sequences when loading layouts" + }, { "type": "dict", "collapsible": true, From 284c152ff0d892d273763f0428c4fce645162886 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 18 Jul 2022 12:47:23 +0100 Subject: [PATCH 053/282] Reopen previous level after the update --- openpype/hosts/unreal/plugins/load/load_layout.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/openpype/hosts/unreal/plugins/load/load_layout.py b/openpype/hosts/unreal/plugins/load/load_layout.py index b2d5b43e1e..4fdfac51c8 100644 --- a/openpype/hosts/unreal/plugins/load/load_layout.py +++ b/openpype/hosts/unreal/plugins/load/load_layout.py @@ -788,6 +788,16 @@ class LayoutLoader(plugin.Loader): sequences = ar.get_assets(filter) sequence = sequences[0].get_asset() + prev_level = None + + if not master_level: + curr_level = unreal.LevelEditorSubsystem().get_current_level() + curr_level_path = curr_level.get_outer().get_path_name() + # If the level path does not start with "/Game/", the current + # level is a temporary, unsaved level. + if curr_level_path.startswith("/Game/"): + prev_level = curr_level_path + # Get layout level filter = unreal.ARFilter( class_names=["World"], @@ -832,6 +842,8 @@ class LayoutLoader(plugin.Loader): if master_level: EditorLevelLibrary.load_level(master_level) + elif prev_level: + EditorLevelLibrary.load_level(prev_level) def remove(self, container): """ From 01f2c59049be47fce42a5bfdcf67ef1227be1d11 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 18 Jul 2022 15:15:40 +0200 Subject: [PATCH 054/282] the update placeholder keep placeholder info when canceled or closed --- openpype/hosts/maya/api/lib_template_builder.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index a30b3868b0..855c72e361 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -107,11 +107,13 @@ def update_placeholder(): placeholder = placeholder[0] args = placeholder_window(get_placeholder_attributes(placeholder)) - # delete placeholder attributes - delete_placeholder_attributes(placeholder) + if not args: return # operation canceled + # delete placeholder attributes + delete_placeholder_attributes(placeholder) + options = create_options(args) imprint(placeholder, options) From e6cad709cd5904087f687a4e2ec5a15641ab48e0 Mon Sep 17 00:00:00 2001 From: Thomas Fricard Date: Mon, 18 Jul 2022 18:43:34 +0200 Subject: [PATCH 055/282] fix error when updating workfile from template with empty scene --- openpype/hosts/maya/api/template_loader.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/template_loader.py b/openpype/hosts/maya/api/template_loader.py index 0e346ca411..c7946b6ad3 100644 --- a/openpype/hosts/maya/api/template_loader.py +++ b/openpype/hosts/maya/api/template_loader.py @@ -80,7 +80,11 @@ class MayaTemplateLoader(AbstractTemplateLoader): return [attribute.rpartition('.')[0] for attribute in attributes] def get_loaded_containers_by_id(self): - containers = cmds.sets('AVALON_CONTAINERS', q=True) + try: + containers = cmds.sets("AVALON_CONTAINERS", q=True) + except ValueError: + return None + return [ cmds.getAttr(container + '.representation') for container in containers] From 7793ea5580595c95d875b056bdf1a61685f63a1d Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Wed, 20 Jul 2022 19:26:10 +0100 Subject: [PATCH 056/282] Added documentation for UE5, layout and rendering --- website/docs/artist_hosts_unreal.md | 132 +++++++++++++++++- website/docs/assets/unreal-avalon_tools.jpg | Bin 25212 -> 0 bytes website/docs/assets/unreal-container.jpg | Bin 10414 -> 0 bytes website/docs/assets/unreal_add_level.png | Bin 0 -> 8393 bytes website/docs/assets/unreal_container.jpg | Bin 0 -> 10414 bytes website/docs/assets/unreal_create_render.png | Bin 0 -> 124745 bytes .../unreal_layout_loading_no_sequence.png | Bin 0 -> 12529 bytes .../assets/unreal_layout_loading_result.png | Bin 0 -> 23833 bytes website/docs/assets/unreal_level_list.png | Bin 0 -> 21009 bytes .../assets/unreal_level_list_no_sequences.png | Bin 0 -> 10784 bytes .../assets/unreal_level_streaming_method.png | Bin 0 -> 153336 bytes ...al_level_streaming_method_no_sequences.png | Bin 0 -> 82416 bytes website/docs/assets/unreal_load_layout.png | Bin 0 -> 138927 bytes .../docs/assets/unreal_load_layout_batch.png | Bin 0 -> 121461 bytes website/docs/assets/unreal_openpype_tools.png | Bin 0 -> 27332 bytes .../assets/unreal_openpype_tools_create.png | Bin 0 -> 27449 bytes .../assets/unreal_openpype_tools_load.png | Bin 0 -> 27465 bytes .../assets/unreal_openpype_tools_manage.png | Bin 0 -> 27475 bytes .../assets/unreal_openpype_tools_publish.png | Bin 0 -> 27453 bytes .../assets/unreal_openpype_tools_render.png | Bin 0 -> 27453 bytes website/docs/assets/unreal_publish_render.png | Bin 0 -> 247922 bytes .../assets/unreal_setting_level_sequence.png | Bin 0 -> 3881 bytes 22 files changed, 127 insertions(+), 5 deletions(-) delete mode 100644 website/docs/assets/unreal-avalon_tools.jpg delete mode 100644 website/docs/assets/unreal-container.jpg create mode 100644 website/docs/assets/unreal_add_level.png create mode 100644 website/docs/assets/unreal_container.jpg create mode 100644 website/docs/assets/unreal_create_render.png create mode 100644 website/docs/assets/unreal_layout_loading_no_sequence.png create mode 100644 website/docs/assets/unreal_layout_loading_result.png create mode 100644 website/docs/assets/unreal_level_list.png create mode 100644 website/docs/assets/unreal_level_list_no_sequences.png create mode 100644 website/docs/assets/unreal_level_streaming_method.png create mode 100644 website/docs/assets/unreal_level_streaming_method_no_sequences.png create mode 100644 website/docs/assets/unreal_load_layout.png create mode 100644 website/docs/assets/unreal_load_layout_batch.png create mode 100644 website/docs/assets/unreal_openpype_tools.png create mode 100644 website/docs/assets/unreal_openpype_tools_create.png create mode 100644 website/docs/assets/unreal_openpype_tools_load.png create mode 100644 website/docs/assets/unreal_openpype_tools_manage.png create mode 100644 website/docs/assets/unreal_openpype_tools_publish.png create mode 100644 website/docs/assets/unreal_openpype_tools_render.png create mode 100644 website/docs/assets/unreal_publish_render.png create mode 100644 website/docs/assets/unreal_setting_level_sequence.png diff --git a/website/docs/artist_hosts_unreal.md b/website/docs/artist_hosts_unreal.md index 1ff09893e3..45a0c8bb6f 100644 --- a/website/docs/artist_hosts_unreal.md +++ b/website/docs/artist_hosts_unreal.md @@ -8,6 +8,20 @@ sidebar_label: Unreal OpenPype supports Unreal in similar ways as in other DCCs Yet there are few specific you need to be aware of. +### Creating the Unreal project + +Selecting a task and opening it with Unreal will generate the Unreal project, if it hasn't been created before. +By default, OpenPype includes the plugin that will be built together with the project. + +Alternatively, the Environment variable `"OPENPYPE_UNREAL_PLUGIN"` can be set to the path of a compiled version of the plugin. +The version of the compiled plugin must match the version of Unreal with which the project is being created. + +:::note +Unreal version 5.0 onwards requires the following Environment variable: + +`"UE_PYTHONPATH": "{PYTHONPATH}"` +::: + ### Project naming Unreal doesn't support project names starting with non-alphabetic character. So names like `123_myProject` are @@ -15,9 +29,9 @@ invalid. If OpenPype detects such name it automatically prepends letter **P** to ## OpenPype global tools -OpenPype global tools can be found in *Window* main menu: +OpenPype global tools can be found in Unreal's toolbar and in the *Tools* main menu: -![Unreal OpenPype Menu](assets/unreal-avalon_tools.jpg) +![Unreal OpenPype Menu](assets/unreal_openpype_tools.png) - [Create](artist_tools.md#creator) - [Load](artist_tools.md#loader) @@ -31,10 +45,118 @@ OpenPype global tools can be found in *Window* main menu: To import Static Mesh model, just choose **OpenPype → Load ...** and select your mesh. Static meshes are transferred as FBX files as specified in [Unreal Engine 4 Static Mesh Pipeline](https://docs.unrealengine.com/en-US/Engine/Content/Importing/FBX/StaticMeshes/index.html). This action will create new folder with subset name (`unrealStaticMeshMain_CON` for example) and put all data into it. Inside, you can find: -![Unreal Container Content](assets/unreal-container.jpg) +![Unreal Container Content](assets/unreal_container.jpg) -In this case there is **lambert1**, material pulled from Maya when this static mesh was published, **unrealStaticMeshCube** is the geometry itself, **unrealStaticMeshCube_CON** is a *AssetContainer* type and is there to mark this directory as Avalon Container (to track changes) and to hold OpenPype metadata. +In this case there is **lambert1**, material pulled from Maya when this static mesh was published, **antennaA_modelMain** is the geometry itself, **modelMain_v002_CON** is a *AssetContainer* type and is there to mark this directory as Avalon Container (to track changes) and to hold OpenPype metadata. ### Publishing -Publishing of Static Mesh works in similar ways. Select your mesh in *Content Browser* and **OpenPype → Create ...**. This will create folder named by subset you've chosen - for example **unrealStaticMeshDefault_INS**. It this folder is that mesh and *Avalon Publish Instance* asset marking this folder as publishable instance and holding important metadata on it. If you want to publish this instance, go **OpenPype → Publish ...** \ No newline at end of file +Publishing of Static Mesh works in similar ways. Select your mesh in *Content Browser* and **OpenPype → Create ...**. This will create folder named by subset you've chosen - for example **unrealStaticMeshDefault_INS**. It this folder is that mesh and *Avalon Publish Instance* asset marking this folder as publishable instance and holding important metadata on it. If you want to publish this instance, go **OpenPype → Publish ...** + +## Layout + +There are two different layout options in Unreal, depending on the type of project you are working on. +One only imports the layout, and saves it in a level. +The other uses [Master Sequences](https://docs.unrealengine.com/4.27/en-US/AnimatingObjects/Sequencer/Overview/TracksShot/) to track the whole level sequence hierarchy. +You can choose in the Project Settings if you want to generate the level sequences. + +![Unreal OP Settings Level Sequence](assets/unreal_setting_level_sequence.png) + +### Loading + +To load a layout, click on the OpenPype icon in Unreal’s main taskbar, and select **Load**. + +![Unreal OP Tools Load](assets/unreal_openpype_tools_load.png) + +Select the task on the left, then right click on the layout asset and select **Load Layout**. + +![Unreal Layout Load](assets/unreal_load_layout.png) + +If you need to load multiple layouts, you can select more than one task on the left, and you can load them together. + +![Unreal Layout Load Batch](assets/unreal_load_layout_batch.png) + +### Navigating the project + +The layout will be imported in the directory `/Content/OpenPype`. The layout will be split into two subfolders: +- *Assets*, which will contain all the rigs and models contained in the layout; +- *Asset name* (in the following example, *episode 2*), a folder named as the **asset** of the current **task**. + +![Unreal Layout Loading Result](assets/unreal_layout_loading_result.png) + +If you chose to generate the level sequences, in the second folder you will find the master level for the task (usually an episode), the level sequence and the folders for all the scenes in the episodes. +Otherwise you will find the level generated for the loaded layout. + +#### Layout without level sequences + +In the layout folder, you will find the level with the imported layout and an object of *AssetContainer* type. The latter is there to mark this directory as Avalon Container (to track changes) and to hold OpenPype metadata. + +![Unreal Layout Loading No Sequence](assets/unreal_layout_loading_no_sequence.png) + +The layout level will and should contain only the data included in the layout. To add lighting, or other elements, like an environment, you have to create a master level, and add the layout level as a [streaming level](https://docs.unrealengine.com/5.0/en-US/level-streaming-in-unreal-engine/). + +Create the master level and open it. Then, open the *Levels* window (from the menu **Windows → Levels**). Click on **Levels → Add Existing** and select the layout level and the other levels you with to include in the scene. The following example shows a master level in which have been added a light level and the layout level. + +![Unreal Add Level](assets/unreal_add_level.png) +![Unreal Level List](assets/unreal_level_list_no_sequences.png) + +#### Layout with level sequences + +In the episode folder, you will find the master level for the episode, the master level sequence and the folders for all the scenes in the episodes. + +After opening the master level, open the *Levels* window (from the menu **Windows → Levels**), and you will see the list of the levels of each shot of the episode for which a layout has been loaded. + +![Unreal Level List](assets/unreal_level_list.png) + +If it has not been added already, you will need to add the environment to the level. Click on **Levels → Add Existing** and select the level with the environment (check with the studio where it is located). + +![Unreal Add Level](assets/unreal_add_level.png) + +After adding the environment level to the master level, you will need to set it as always loaded by right clicking it, and selecting **Change Streaming Method** and selecting **Always Loaded**. + +![Unreal Level Streaming Method](assets/unreal_level_streaming_method.png) + +### Update layouts + +To manage loaded layouts, click on the OpenPype icon in Unreal’s main taskbar, and select **Manage**. + +![Unreal OP Tools Manage](assets/unreal_openpype_tools_manage.png) + +You will get a list of all the assets that have been loaded in the project. +The version number will be in red if it isn’t the latest version. Right click on the element, and select Update if you need to update the layout. + +:::note +**DO NOT** update rigs or models imported with a layout. Update only the layout. +::: + +## Rendering + +:::note +The rendering requires a layout loaded with the option to create the level sequences **on**. +::: + +To render and publish an episode, a scene or a shot, you will need to create a publish instance. The publish instance for the rendering is based on one level sequence. That means that if you want to render the whole episode, you will need to create it for the level sequence of the episode, but if you want to render just one shot, you will need to create it for that shot. + +Navigate to the folder that contains the level sequence that you need to render. Select the level sequence, and then click on the OpenPype icon in Unreal’s main taskbar, and select **Create**. + +![Unreal OP Tools Create](assets/unreal_openpype_tools_create.png) + +In the Instance Creator, select **Unreal - Render**, give it a name, and click **Create**. + +![Unreal OP Instance Creator](assets/unreal_create_render.png) + +The render instance will be created in `/Content/OpenPype/PublishInstances`. + +Select the instance you need to render, and then click on the OpenPype icon in Unreal’s main taskbar, and select **Render**. You can render more than one instance at a time, if needed. Just select all the instances that you need to render before selecting the **Render** button from the OpenPype menu. + +![Unreal OP Tools Render](assets/unreal_openpype_tools_render.png) + +Once the render is finished, click on the OpenPype icon in Unreal’s main taskbar, and select **Publish**. + +![Unreal OP Tools Publish](assets/unreal_openpype_tools_publish.png) + +On the left, you will see the render instances. They will be automatically reorganised to have an instance for each shot. So, for example, if you have created the render instance for the whole episode, here you will have an instance for each shot in the episode. + +![Unreal Publish Render](assets/unreal_publish_render.png) + +Click on the play button in the bottom right, and it will start the publishing process. diff --git a/website/docs/assets/unreal-avalon_tools.jpg b/website/docs/assets/unreal-avalon_tools.jpg deleted file mode 100644 index 531fbe516a2d0e645140c4a102afbbfa4cbdbbd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25212 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 diff --git a/website/docs/assets/unreal-container.jpg b/website/docs/assets/unreal-container.jpg deleted file mode 100644 index f0c0a61e9519359a5dd980295e0d1d2b3d573e2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10414 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 diff --git a/website/docs/assets/unreal_add_level.png b/website/docs/assets/unreal_add_level.png new file mode 100644 index 0000000000000000000000000000000000000000..caeef03d10148da9cccfdbc8b0816b130709710e GIT binary patch literal 8393 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 VC)c$H{QcmOlDxWHwTwl`{{l*bXLbMp literal 0 HcmV?d00001 diff --git a/website/docs/assets/unreal_container.jpg b/website/docs/assets/unreal_container.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0fda640b00a4327255a316d96683dc9ae2331903 GIT binary patch literal 10414 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/unreal_create_render.png b/website/docs/assets/unreal_create_render.png new file mode 100644 index 0000000000000000000000000000000000000000..2e3ef20b35bf1d89bc77946472886d4719bf7b66 GIT binary patch literal 124745 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

sT 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∨e?`UX!=eGccIe-aKm{I|H{ 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


8;lMR(C3OiYA(rG%8Odl)3#q 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 z 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�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 t5%TuMTpYfozivRT!Iw4)68MdOwxt*N z_Q>_Mj5u8BF!46{0l`X4Nem9IA`bo51QGm<>Ljb<3I~VT3Hy4~>-fza4oj`2vd~4aIRwhO{YCv-EOKF0P9F1HU`_cjGBAb-U`*sj-*ZD=gC1`%-$559VYiK^ctG&I_TZHckeU2s9LEwZ$9>E z?qd7Ip3l#6<$V?>=W4f??tU?}>3wXL%w%AS&vHHgi&5`6gV7VC&kzbkC4RT9S5-TO zMd>t3=~UdPs$Os2ycsHMy?>L;5*Jwmp`cdMGJI>mR!JI~Y(59|U-^!^a7z$}E1j0bZ|EiY zetxl?Eakgv@LcrsbiG^-&rnn5qXutWy1hLeiS*o_b{S+UVLdGG#GH8bu9q}mu7%>r z$nPxaY9*Rw=&<#{p%zt@d5v+DXU-{j+OhR+NLgUtyaYcdvcYHj~#2jZ!0+X-n zIg)KjwWg^8iE>W!P&(IO45^541&!o3E@@bNXjBwh)uf@%v=$@b*01l0e1}b^dpC5a z+h4QOKMDEJOh~?To-zr~f4b@Bwl~Fg%*-1neEn_Od$$DFR{UvrCW3eEyaz{#UTw|c z&7W;Eqd0*B-qXp}``@haRHO?&heG3xo`+rOba+lo#m(n41v(sIggwhbvzfD>Kh_<# z+!W*8PnpH(u$2}U|7hJb^++WRxINy;ez>(VW#aMvvt?o+k}D|3FdB1U{D^j-e2}>@ z)qT=nl3PTt`i%u9{}x%}yiXII$b`1p6W1sdi>YFToS6o$^nj zj1&BcLCD^<*Lc`sdDwiRyl1bS&g1By=Ur4%lfFGuZEI@laevt>a*bpCevbahPc%-f zm6h&jrD%MnH}lWmRfkkBGj5v2^7RN86A$unrOMc^U0iSwx!J3N zKE@I>UhL%GEjAN=xOE+`ceQF9etWSP@PM{SUA0@lP?I*9?g%xD!z|nqQla7#&4p028f|0Sfv4sA_*WaDb?$!@o zG8uYITby4+F8Pe~3c2=Er%d_r%)2E{`<_B^eKgG*_iH##H=rD4&FAS?2nJxbQ-zgto}vnco~^5o7~`)=3hfqlNgy=oS$nu9~j zmF3NJY4f>m)tEHV^ghM&FHfx58hhKgyVL9kJE`OapW()vgT|6FzAHf%bxw6gPW!jd z7JN^Yd@>m$=Pp6m4JE1w+xTCt6WqjCjp__>pC>)upRMIN-5gOV{_VVxW|bZ%azFKF ze|EA#0tu7Y+Q9$zoVj6(g2R4>Q{YeB;>#X{tj)Rr=B6X@)3ZsV3|wX2_84NmN)IFY zXC2oQdXCfbL1^!6B?^4Vu0d)y2*p)8tHfsUxfbwUttCR6FBWWN4D1`W3(j@l1^#Xg z2)JoFdhsD(Ih3Gy5a)5YyAbXedA{hW*)sB@vZj-$X|L7y9L%MgnXbH(SP?YU7e!?) zZ=|x3;Tim@pxhir{#W^F>=yF&r?`Rs=hIgEKAtbu-8PSpoDA8uz4vFTt29YXp>euq z)~?|XowV7$rUI)V5Nha_7`J@8LKiV96Yoz_T2ncOc{@FPDc|*zMd)WNK53QEjnS?~ zSxmPrwYgxMi<8eri(Z}TJ)=?1v~Dfh9{;K*VHNy@TUNgsbMCozB`6LxLa`rIi@{w} z1#2i$OHhkPCtEFNc`kgPgx~OWjJBGtw6Hw;tyOEPRCF@HQ1*)hoBTBzXEjG@^tg(M zP+6$!PaTx$C7GeP^&jKP9GjnfN=y2$oa?{0p|H0&6<`$EaslA*Gt$6?5PeL>y9BNY7y2dUu{tEjhx!%UEUH z9@MqK4>=MzY#MLCyg!Z$n39M4AkAwd<%NhvKqP^DWv`*7l@W|3JavB%%fCa%kovu# zW;NG%Mu5cMEk_MWw={nHMZc3u&1pTc>*jFvq%7iOmwS+jge}f)qxuc*KvHI}SU6%H z@6q7c+G$Wm2+cI<{ZaVGszJzx^J-7ptV1L8K3;`?o2oJE6rwkLde2J2xqg3t(W+1v#aZgznYk4%B{C< zozD;1s+Yh!ah*?zbDNcvfM(9>dC9>}8? z-eLKw{S{=Ups;As@Jrz3;tqYT!ah0M%CUS9Ev_9^YPY zY_}*f6*HQ&UUBV$_t^`7+99)^n2NHtx4$lLpN(fBcR|`sdpdH0KMdm*qx*lP5YX;J zVPDL`Wn8E#iO&kr_PHIgHo)sFl(2S=H1M2v*W_)z+92A+Z+DEbeG<6Jqi_Z3*)3~b zXkaM!nE!^ts3k3LTtZWev{lu9wrsh{f627E(dUNsOu(ZU&w3zSA=He}y+g?6cvQa4 z@e|sddL1{b^_KqE>JB<=C}u3?lYJc^%b54FEh}ehogpncauxLjDMZu zti~Dw#rm}nV}VaWaDu(1D4Qe2m+(5r<{CM${Z@P}2thaEPhU5Al)N@PlO$h4W#TIo za>?TlqUhw3lK*)eqr)T*iFoGVmdI!gUeMwE#}N_F`UC~XRR>(<{;9f9KZ$INHMXCu zwbO46t+YXwR(+eekO&k+B1@UlHipu=4og8oZaZz$B5S&H(B8Tle?cM^Ea=JKM_+>Ne4;prLQ;_2iNVJfhVi~KC+L8ASxTnn%yFLxAD30$G zWH?mn5J8#_f_AIU3GfmNF7JS z80)2l-S%gG!@!^A&o6T4c#j;WEA!p+$=J0UwX5HWn&Ca(EU6miXUGJ3yE}bnn9QVS zSz^e~W8`}*<$4O`p*=6|1BvI*O{{P=DuJbB$8|0=JJrk94eu;`G3QD>EdCMl8KbI` z34$~t^5DB-K;niYe7O|tAy}P~eLd=>*w8P4nEx#!)~^dbcTl-r1AX_3wRklu+UGPegnf#q7?2M-bgC_`D3 zDTqq8MnjBD-m>Zm-AE>P-s~z@^0AYxiINOItnc@<;t?Gy`rkia<}_ouLFT$pS+;#g z>(re-uo5CE5TmDAvgZt&1oti>k!5bc)B3_`+_^%SF-yUWgPU&$CFuVq9I+X+U{=%#wM zKB#Z<1zJW-Tcj9RS`MX}2w;HNb~K=7X}zt)yH#8&+d%I@>)m0dQKxZBc&+0lmRXTG ze?buvfvKEBnXQWG`Isbvi_5)RvKU*%w=bq^%Bk~738WbSy^ToPPv5GYw#x<2r_7)_ zR#_GTlq6}xrwzOwQzpo+ZI6((12Y6XOW$5^e}&4B`hBdE|MM9!@Q`>CGwY-F8JROa z#SAZj%$nb52Pp}^TX}n&<#49W{Ifbch>b3mp|kQiA8p=4B)D&chM{BKp%`mt3g|15 zIYIG=Eu2EpXzTW84q?!-{%zybMery;Y2%7Z64H*Qn;C?SrbY5TfG+6qv_D5ImX{|tp}ix&4^_3!3N zMelT55`1@t&+?SU>q>*WM)0FmE#`?Aw)-(A&HYNadK0W*Za^61Juznxq}CdlFot!j zPg}h(z8^K~=6bgbSFfX2OB(NuXcyr!b!SA1u-|p+YOKKU#=+@H50PW4NoUw}-S`PjtHTqGi&tN$FUWUFdxO_L}2R2<0QiabgpsxcafH9 z3F{K7=xpB+mSl+C3@3Aj@_3)4_fI+6H03P*=`+^;=^)FGNL-|mn$29K$sD9hVA**9 zIZ-sVC0V;`yxu9=e;eUZsX&E0YghH2>#X&11-)^&`jQ=1NSaDhB>E^8a zfsCM;Wc&w8?QtTjpKR5lU#prR*2#A&&;%-LO$=uV%-Y}PJsJ!$uLczO)BdaeKZMQjN{)Q~ zY_VS{J`=|jVpBvNHTGgb9R-O%WmQ=*I8gi~I1Pw1RmBGBpQV#QmfA3Ke#sT|PfSbo zRMo_qTzF8x#TgynvP7YeCT1f{_DvhQHfH9_ zl`LQ+7&ORVP1sUgyXZelBi4-=6!G{FyA&0dM%zlbLzy--cp&WEc|=tsJ{SL_sd?0e z?zP=I7M)V!X_w2EH!+yP=(DIlM>f~PyBZ*>h)iN?Xx;dF zb|%@`IXS4Sy>Yc8zwos5O}HYHh0qVDdxSCi%e$r(hT-4SQR$g$+r^g{M{qfujG@z&@xGenK&%Cmr1~;Xww?9bAS!L9 zaf*1o02>C+l=0(PcK?%p+Wo4?_Dj&sGe(4OhIVjfr^2%{@qMO%vV)@UQdVR;AmH4O z(EH`hwN(&{|M}kZgv%XJ5Nr`6(xWSl$0!PX1AT264UHHlgi3>e{y}d~8~oV0r+1Cy zI+!cnA%blEB+8S!G6_#?|4y(E5Of+1*~rNYiqNoXLTVIZ*r(jwCh5H zHn#xaVNcO_iF7BW7>HT#dEKL(!C@8a9#{FKqQ|KLhUWz~mV&XA^{IL5ixkmXZch{# zGy!T+v6Fj}%rZgdKd;|zDycm$g8jgN&ox0AO+*_p_}F%gsSX*!=c``~1NhbV^KMQ| z2vCLw?cZXyUNQxhL9VV#{GYcs>BHhP1EOrBG^ z-HtyqSjHbn`d*Bgt|%(C(YG#`Bk{o!f02XINMDU{nwnZtT~y)rUU-c7urC%=%GpWT zIDIi!OrbxoX4$)K-;r@Fne@aEdd!lC6Pq?aj&Peocy76A+;-j;_}IScdBv(k9ias0 z^wm2cCuNY(LcMIrC0A);Ogx550!6>R*rWfn|=Tw_i5_L_@nU+dcr-P&> zQ|Bdu9$n@8(HKeN8R|ST>s(i2{JFjllu*E|EWY}z^4zyR+=$pdG9^SOe@T>Y!j;vc-$nHV`^qiQBvK7Lrn`yXu6?k~_B*dAjpbSN z9p51#iTqQ=HpGRY|DZMu4<(31RI<`6{DAPTENl$nGM{iGjC!BH>6=cbEXSLm)ey*g ztZQ{AQhw|Kq*4LhwX1iw@%4|zuKtXxl!U#1#@5kdwboXg&L!-Px!~`v&q$;qV-@`=QZk4(RPRp z^ODvV!ZfjOKlN>2kxOm|^Nz#IWR64G=nzxQ0xNX;obp-_pF?aA_Xxz-;7xn_C=8DU zQYv|Qo(3X3zpOl_u3GX`9bh02dF*FQm-X84in3f(AQdG@3d->Cv7E*eg=yEP5!<1JI5&!sH5q$*l3Y<%^ zA`3g_{`>J;;;V>w@=O{Nce9aXg9n(<9B_Y{9fUMVo_1pNaINK|av-y%5c=o+iz^Qt z`J7Oc4?-7n=s$o(pE-XQqFbeQH-4uD4 z)(7NT2bU)0F_y@!lOZ|HxhtOz@f|O&u;BJK`>i zy%on)?n-+qXa0<$l?we3`N?zhi+qJrVg#2J^4rdEEFPHBsl*VjT_vRW4dEV?$4O=a zeJ3$fm1Dl0Z+SR}njwA;B4xfT$Ruv@266nK(K&65U;wo7NVu^0=l3E!rP{r_K8&i< z_zKHrziXOUl(=q@VQ#fU67v?n{jn+C4Wz*^)|S!&JfxN%y?q>)ukr+xEidWNS#DLCQ-Tx*J{^y9k;zVy0O48stF5lgsM)T-l^2 zD#n2{LtA4qr1rL7^c#BAd{c@Z_Nl3eGvnnZ@IK$ONo2Rw<)y*EzdI_y8!7wL zI_T>**zYkrBd||;Guu@>RuVpaoK7%gh^5RSuy~Sga}hqjfA2BxS*v+5VWpmKaL+ev zSH5`caf1}VH+H){9BEk=-oh%Nf0wCamT13!ZcZT6uzFs1VOI5em%HF?(eGmSS=0CD z9zG2&Zd1-8KJ)M6n%ZuUD{1%6$|Evr?d;F%4ig(}yJMXv2a?<__MH1E&%KL^i3pw_ zK)t^jhEJbez8xuZGUWDNxGmf+?`(;z{u!c3-X*GxeBT?kGx(W3hmVx1h>NhqIcan` zwQ#(G?Xosn$vE)-X7Rxxz$?Yj`+FLfZL*To@D0#5=Im;wEj@^Ki90Lm;}t%YfrPZ3 zpg3qNGdyX;`|%?9-d@w8we;#_dsZO!=p<6>w7cPs~nq|rWQQ#SAh(r8^e|rX9kVb5z>|(b(Z^ibuFeE z&AUpe)}BG<<4(fCiUUKLv@5j*ZV{E6GMm=@PnOLhq-MeaTRV8ANenh3H|e{nhqPTB z)MfSS%;(kn$wJVRoqWp!pFBYe0~ULo#A)M2+@Xobjy!lp)f~1Lf^E0UO*fS_vbku} zI~QQk(lryc*K%|4fk-EilrPcf?Q%zGq-T$Qz};E(y*@raxx%B1Y55PLD)7m6vo-cG zFi{5^!^s$|^*Fdz4(Tzac<9%xO7M_tjL~t?|n5JZ0id z{)6Lk3Tavzn${BNx@b*^Ve_>#ENt`d8D>A&J@&SBqNCDNuAK+~zulkvY?^;XvcS&6phS9{ID zd}D@HwjXx|wFpF_EZ&=d7vST4pV+}(ybl9q`h}$!j_V&B0)c*$3g&VPEphxUi0PPZ zFzo>C@ML{(pBo`{&MdZi(s0&oYqY&(GZj$d5n|^qY#jkCo8&Rc(}@MlnhF-#aj3#+ za*-~9=h7q$kETK!MI&$oE_H-+7~UFKW<`keJ9rOc?I*FmM=3@IZmltY+p z_4?3yp`O>$uT0&fA=_sJ4SF*{WcOU)z-+{sX{EQMK6ak8%xi}+wfod+c2a+Enfgk% zKH)zgWcDq+y$uXkYzkDe9SllE7x8pC zz5iI-ib`jRGRLME`A!5Mw5N`iTv4i&_1(9M5yM3F zw63_Dl+C)-ciyo@*EXd#3x(C&=e1%JLdJs?TeX>k%lYTJz51qQNod6jXFeB21{2d~ zWrV^$L_Wiro<`hUgUM-JwF}VO%T^v}rO_&$gMrS-P;+s`$o>3ooQ~&EF;6zP0#1^| z%TqAl)w#&7TJgR(u&)h8?Liw!Hj17LROs4;?_1M~J>j)J^2e+lWhn>fS1(XHehiym zgwSN7NUN+XZHziz^l^|Py?Z*u_sC|vU>a+LfZcuP*9=QA=t@SHk77wh7MR5XVy?o&H)qoDRL;j5mM?=IYRuSyEl zb5bxy{d&LW9Khd+w5j4h+tNEitfq6*Qd(@ZW-#GmdVhO0(Qt-_STe}^d7MOnbu!Jy z|G0rt!JYUIZ1M}!1zl%szUuJo$G}-6M!$MfwgG`e1Y6$M$ZOWMgOb_>`C=}?e@qahPQ}p4Lr@5GM#V#7 z*b6@r{07|(kw87YFw3X+DMz%DUe%ns;xmgG{nhFw2p ze=nm8`1V&BmrjCW1mKgS%R+V8X!DfGC%J==-i= zN0Ul#EXn>6m5ACqqMcKGBKAU7v*Ztt)e00V@{qMtWABCq4pZ;%ZZi54X*06@uU|S# z^Ew%XRVJufzzEOz9LQCNUbaLiHRCsgIs!Zh`Ui&S>E#K?5UE?rcf&;)j6)iwp`TA0 z(li}eKNQ94o4IkUVvAphrN~PsiA$)Rg0X8w`xn?i{icl4r??jCFGUKy4-&mnM8t;OLuf|xKdR>INa0pB`4yjN+j89uc&D;voD6Y{ zaDur-=HCJIT)nIPGtFL@REj)|oVDNWSEpHXLzTGSd%s?Pu zfRCmc`&yDvLvjiMXGnLLGBi4$KP%b#7BZ#P>0Udn<-M6pqc|T4E?FyK%Io0M{yK zj#CL6Ye0qeMQ11R<%}~T*{7tWr1Q`1v`{)^{u5c)|29bni`970SO)lHR4(c*q;c1Xfyr%nkAlnpK0Sy}DV8{9^b|b4x=S$G%H>Di!FLF7>jIn2;Y7HxMGw?dz#|H3u zC{N;bO=DF8LY^BKkH{1Pu?PZJ5C

87P+}^Q)B(I0`r?7$olt@N)=6Q>#>?C!sDb*nmV;NnBTNw%+mRv zgg1QD-DoW}xcN9lv`Vp%`oH;&nBT9u-xs6*hVgG4ewSJFKJ=$2y%-uyj6bN> zZfQk@uk1KGa=r}SKl0y-xT^k?!p2lyEkR(+xB}3I-w51=2%a%F9&5X=q7Q%86KO54 zJ$ph-iaHAZ9HoN9fu5BfL_rnxBaI)qdg05a=?#qM(+Kyxp&>-{yxjR#Bc;sn$k4Cc zzSk>g&WSwgV?L>(-X@>3bbi8wS+gmIxHD`E*5Tr{gyKjlPl{8`@R+LQSZN>8eBLuA z;qI@QAtiGnQ~$u%s)w`d6vdi9Zf@=pMbyH9%_8+dSdm5;{Q@Q4tUl$`71;ZiTdaA@EPC{y4>OjPe=k%X&xQ+&yBXecD1Py#alabspx@7Q^Gf5tKC=}$IiD|f zWne5;TNXpI*-PuX=78tsIPSdqwPP_x$Y`1E_VaO7PL%C_(=U!t9X_qF3ki!pRQlQQf@JqaO_^EC$U~ZdAl;ls(LX(O^+L9w zt!}7RBvXdXWza5ex=9S98%*|U<()gRO?uDABeiX_PGI*Ww8+f z7tQgYedT7NNaij}510j{h4VHTB-lN6KA+6zaQjR4Q7p&hZhg2}V9vl&(I^8B3C9|E z_F<$-WlqO??CQSby~BAft!VKv_hT|W*%f4#JNQ6@0;IG!Z2Nk5Wf!*gE7jCvE5P(Ukj(z$vB#OCBl5C|nIeh7UqI~G z3B!FKKvQU(cBt#r_i3as!(O-fUOCohhYD{{+=HDYFXnR;@K{s^&kZKI@<@`Zr~PXT zSBeMlHOK#LeWVXBTa9OhTmeC3pl#YVs2F$e!3Y3(Lu7Pc6NNDEXFa>~ql|vozyeT@ z;#OOVkx6I0`hMju!>z@OkULm$(KsXXXFGPNHgr&<4#G`Xn3-iZwto5&>*>mWHJFm@ zOImw>;?Ak66%ENcQ~p`rCJVXqjy-HRZvXlH-2=E~3Z(G|hTkZTsczt#e5!3tL$P>P zszVTVUYv`%OuOh$r`wA8-Ci>pa-4F^#{W+r+#~w&3`@27Z+^t40R-~5(uP%}Ouxu9 zn*<)TvF3fwqQFwG?w|wnqwXPG*{54@IB#EQpP%DLx;aBFd(igfA2#2TOs9T=T^Z3Q zRnHkPsrj3Y;dS~|Qk74ilhtYcJS(2Qqxho7c63(Z3SP%U-*aMytoM1F`{R(Z-*<@6 z_2^aGx$k(!x)edVvuMIf2$^4jZ}dx|2@V(&}LXVES9bj*K4O;@!xe(I1e z+2+j_rV)hwtP-2emUdFTY$j3v*%D-8E=NcE=-o(XeT8w6V~4eW8=)`7l_sA^3HCNc z`Op|+Nmia6yycr;A|g3#{;mm3Dfwyq>_Z9PdLeb)Fdb2qX)8ZzU#?Wb`7NUI@`P?b!S5fK}k~7#=e*wgp4``|CN;jgCSfhR}sr zpwPd0hWp2Hf5Wxw$J(R}E6x~<>A`O-E??eW&;1>mWA>u$|D85mt)BZet~d>lAQE8k zlyy^`=ZQfboLBR1vfj_1QHHNaS}C;Z*0Uj(5gYu6%)`n|4qmS|!~H~d3kgJYYhX=UF2i3B+UaRQvs#9K^}P@I z%~Ss%T1Fq(qC91sV%%^uBDr{|)a)nEYC;|}=#T;;KjBdyXmvbkEc#rJ?Rz<@2GUC| zB2b8BOrqXyx;l#QQMN)$Y>EPFb3rDwwYMFv2Vw{mXF7JH{5-d+S_!AiUSJwXpkUyQ z$3Luu{;Z_8Tg;BCr&ep>*N)JW=gmouhL%2j!RFKd8swv7J{4 z>ZX+h`5o-tzEN8sI6AjqMmu;&$G!)PzCVuFjsdcLu7+yI9;%7b1=A)5%9obc-|o_< zC%2@*uzORyxsyWVaIVMBA{A9D9zEQ<0?`jT_v68$F@T&QQk;_#4Lw#c(|Dj^WsI= zoogc&VI&Swg53wgP3DZ&@z}+E06NZ)jS)diakl%&L3P_@YvdV zI1yiACee9Uj7bu(1$0_E|61^zMmzXy zfBcuTV-z4Qyk!bUsMgcm7q|S$bFH&SbJXGz@zciYn)jK`+D-rbnBU9($pDetNi!X1 zCpr+84=Ta+n>Ce?ATUVYA45VH?!{zZSB|uY>*ozsHT6wAlS%;UBcZSo1O9KQyF2Ue zlkra17T|CWZfYu>Z2w8sWA$G*$$GY$4NK0b*IU##`PlfVXOb6s!fnp?@uVzF zqPCCD%h6hLML+j{gRlG00>~bSa33 zs^}80NjfSY|JCQjl3%)N>#gW5ohbS?d;oW^=RiB>u%ye)02O@MG zLUMWCF{^AE?qpiW&OLP`PINY?+GQDkM|jb+Oz3kOV0c`bZ{MR4 zA|_sf`HMD?jo>=TYH{FrRnq9)KC~qh`np`^rn8@h1WO7moR54V^S|G&S>bp!N34~X zPWvKXdW9_3@ES4X zgw-Lgij%f^(%n5h`$>nB?`%~h7Ynb$dxYZ31*mMT#hD&k4#RCNAr6$GZnGL%4E_&2 zWUCOK`AKGT#7(HQ(cpi7L1ipT91sEe^K*}+ocq7Sn=W-Bkrj7sFSW3~)@D8&uO~wL zPAPNaNzLx3Di6=cwwtrMZ45%!w_^Q2@4?Z$YsDvx=ccaF-l>@t8N+P;oiCUGkk>YXND(g z)yA_!H?d1)&}I!ArRDm$n@X8ou1_Vc`faQRzT5RPNgw^gi-PDAzItu zI0^6a>>e_CN5w-+=A?aNb<*W;iu`5HhQWi!aW&wXrALAlgTRTzTt=b5f5x1rM2vXm zXbd#t*pe9Tm&&wxqf3?RYF~4;k%`1Rtb33Ujjs1QGYS2of7W~q;b?m!J-Y3Xp@wlc z38ds!GXYU{e#r|Xcxi`5oInTlokrzJ;6U%jM6Tt)1{J5TK%=;{Z&|+P!9ppadi8*D z-zQD__2&+l^W#W~|LprJ-SD3j z!$R?)1ghe9gtz_bcT}Sn=f_KBKZ{Vy1Vx@JG|Jlz6`yjg@r04@zXulm`loX=E1UP0 zuHs{TOEW1$VFy6(L+7Pg{-W0>&XDGJ`tt-A_P3uG_na6ycNe330OXx?OwH;%O zgzR04%jw%LDcwE_(|h~(BE&`N2>Lxu=MY*g1oeH5{)2GFqwW8CYYCUraK16$@#ePM zi)z~2(?7(Y6zCBO&xsh-zpyd5$HJ507Q3It`y&Jp3Tn3j$q}#RuM~Jd SDDz~X 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 z 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
    J* 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/unreal_openpype_tools_manage.png b/website/docs/assets/unreal_openpype_tools_manage.png new file mode 100644 index 0000000000000000000000000000000000000000..af7b182842f7046776a32dd3e5dc70e6101ed3b0 GIT binary patch literal 27475 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 RPrtlEl9N`Fs+2Ga{2$Lx;9md$ literal 0 HcmV?d00001 diff --git a/website/docs/assets/unreal_openpype_tools_render.png b/website/docs/assets/unreal_openpype_tools_render.png new file mode 100644 index 0000000000000000000000000000000000000000..377dc2951eb1040153b5ada28254b06cb9a89fb9 GIT binary patch literal 27453 zcmZs?WmMZu^eqg9BE_K;cPnni-5m-PcL@}C2wohDyE_yp?(RWT+}+*X;fCjb?_KMa z4-k^|V`efl=gi*w>D24I~{}U7x6pDYIiFCl28W%?eN+`M-3o@LaI2|i_bu6e(;TCF*q9my*xp~;fRN>eKGI$LE)Q(}h2 zBg>43iIY3Tkt6cHf389)LW3CwlKD-!FHRoIEfWiy33-f$mUrzTb1fBoj2R}rNhyB! zu$RqT0C_+ixAq+F$X#z0d!z_M9867dF)hkLD^H*Xzg6?!dt)1WARS{9S$j z%(J~4oLk-XWhgOANx){jgYIT#yMeLnhSs}Xx{!{H>rED5Blo;&)=ksoAbk)rGoiO>s0>odVVMSmTH&q8V?U% zFYHx2y4g4=%C0Dcj9N33+ZML{RIhc|V(m?Arx~VGP2cN&EwOu3)P{%izb{fsGyvcM z;rVV&#ekiBm_peEZ7^ zej%qi@*@)9B3&uD*Y~;=aK3rui7M>@nP=nrtrX1bG&jBPqxan;^h$42oiyM~wx`Bd z<%0?>jYosGEtN0HvZ?!tQIm!Wjn{K-!<*ArJI!lNm2KBMzB-HyB=6G;X=Xl%yQSUn z5$#3uVK<;t8%{2qd~;}0tFwZ^`y^~K+qVTd%l%J+c{XDJ&Ngf3wF+$rj%*Q^)}M-3 zlHut)FC`B0(5}q)#r!;n$oTbJ8e2#%V(Eq06_tI5A?^ zWx0?(Lf@Osn1Jpa=Z>ScukV|LHo`=5Jf6=rDfx9@2-6T1+G`05QORW(%2D0p)UERe z>dT?cPSBd?Pw_$Yn`^v6zIN8Xaxaq$y5RR6_h~By!}*M8FDdBlG24>yc}v7?2-fCI zt7J_`H!15$lIMAv#L{$#*OH=p*Q#iF3`nct4Ow##WVnvAk2Tjf&DzibliB-E{)Pqm zT34BT;3cNkij3x`0skCNfgKDx;^&KOZg`>#kN53)$ZZC@lKq)X=*_zPBV4?h+=uHMRJ7oZGh5+f!vyH&=FPyZAVPV(I&a;dXI2MtCf=I}~7g z#>-SmqD~&3Y*9R@#KNdNOO$Bt_x?dWhb*x7s;ZROr}W~KOyF_m<;h3|8Er{8WRAk$ zZaNbj`(v}t3@uBL6_1i$Ed+{!gm^Tw_|6M2d;FM__edTiFGmboYWaPS24vqB%q^pZ z_paHkXy0Q}kC4y*HM275)Q#}qfhjB}S@9^L5JmPV@%0`J>}2q$`w;)+Q{8r62tN!0 z9TYk(#uf-Z2;d~XzOI$l|Ig_EA$T0fz2!QuT@_g>kbGa+@}EUCpo;=hO~3Qxp|{%+Im)iw2g6-jpoS|%Ke z`F9RHz+%PtAUx+uj=32{xWC`D-KuJewn*;+I`%4gc>SEf^RoqH`pe+16@^}|v;VO0 z@K|)08u6eFkvt~{6uLd2C0t&!1I}+CaeDSFav*dkf8cwA2A=GVPVQqKWUmm?xS1s3 z*M1!Hs%^WsdsRD7ET=cuf54jcHahEceVXVx!=i>vvt_@7JMs0j!5cl`obSy*>;Cdh zm8vpgHMlVmrIm@^s&fy17^(AVX(x4TjVg&m2k{brFoX)SKr>NWw_UGcLU*e*yPlnu z3@;&XnqPd+N(BFr6W3 z=!Clhwq2M1X|lRiJ@q}!Qs_VLdNDFWl3{<_*JQ{ic1%eM<70xJ+fJO2U?q3(s<#(9J7+-#itV)4yI`5e=_?jECVAW zPkCTLd=3^Q>=n8;dPBgQn|T5U|M!75CbYEh0Gi7WM(+{x2`Iq2KYD$AeOVukWj6Lw zp)CsuznL(h$CrUN-R8L?9v9xs#mhsW9OgHI#*K*D;pyoF&L%;n_wJ+EA77{j;<8`j z?GmUGHT>tq#_gJMos|OH9Hy+bT3z+xoFIc&h2HBDASf~)kr*Jbq??aC;DT4(O5PZkQa+a! zfQ5sIainU>vdTlG?*-ltxc7M1>3<@XVHee>JSi&5&1WE+$&Sy{BvsJdis$H90Wh+7 zBhs@e?sy;D^eqgVWLP#?^2$<5&;f^IzmfCrDJ9#5JP#pi9O zkOZ*xPNi3m`qBCwwQ-TZzn`!(DBS7=1KHfH{N`88(+p%6p9qawTc$V0vt(vl0HPoZ z(efKV%{HV~w~NSwX^duLq_~+@UCYHH>LU666f^Eo_!w9CCEarIU?S|VPo{=1R7-M@ zW>sOhOE(pl0p!Tipvb`Rjn&C+9$Uu?nlhC1be7fxBg0bd*)!$@;@`lb>&orrgHT=1 z?Yy1BkF;Ev8p@83X`Wl#=#FtCQbHB}{nC)FTHOMD#vw{L$dl;CAc*{Wv`H8)wz1hA zXVOotP#?|;FDH_aC{Ly_=q3tBO+&56#agQ9f8m)agT*BTd&GH+032~0Vcou!NF=lS z8$tE-x4GgIT^NXdGtX+6M$mN$;~?qIt|D^aOKU}Yu5L%6Is^^;YO=&ZsKi5LqjF%$ zH4RC*Fg}3|mm=G|IEOL)9fEvpobDE2f6=CJ%t01`i<=74AgF0ywGDa3TFw~J{;Q-)AV%+>q5w41MfXn z#|5xuFp}$=a)kc*rD&xgb^vzKpv7GMMpSTD>3cFYoE)Ot=kUo8T)2}&(3m`6+nMk6 zimkzF!<4+{1)$Ad(J-@X%RBxWGOT|@-q~?%(fMY-zIvI6H|#RU4kYTl;RiEKr`0`^{Se6VZgKl)GcAbyaVa-!q^4_@w%`$p}8* zU&5So28luZsE_A%XHu^NB(D}x!YKr-@D!ggNZ>?9MOH+HzkS~$CkK`0p}-G_^-OL> ztOuWGuo@G5HA*pK8+w~M zZ{fjNcP_&?LeJHXdoZ1P9dvzqbFV9xIN4aVYp!n1Z+-({P@!-6^L}b{GV_aIXVC)f z6}(UT^Wom@UmH7jkE6t$L!@k`JE3Q3_j|u0@T{B}_?7R~=RqnPNheU_^%YG>heWO4J5Kii|tk+;(%!B4ReU z9ilvHqiDe}5ST?sBdfSiqxaQwdt#Q2_;U2*(&x;M_^SKz{8bF#G4KGeDi>nijTE}x z-vY3(>nwF(x4PQWUp?KT3hdGl3w}o(v1Z0G%iz86Q0Bp;NvvWEQD^yiZvHKL5HHk< zY%NT)mmznH z2OQjK^)r4IxFwa^J29XRu@;I^OM4bb+Fgsv7l!JaRXj@y}Qs3d5b8(|J zw#C*VXx=_v=0Q_hHKV8m04)$4-6l>ZuYd`3TAmg%<%Y0eF22;%QTE&M zCP}FBtBPS~eqoV?F^5hNAE*c^=N1#sPC?#75hd(=y6>f9MstrnpYDoBJG%;M&b|*L zVM^9(Df*KMFc!kOXp+8f2lSF0GonS8w|HJ|wC@}s32DCGawzyJxsSo(AfhEzc2qS# z->YdPk<>i%4U;@Sb}|!mrFU3?91fymj2Wugb9G%CyUl$v5P+8g0E7 z?ECQmCoNO5cK)FfV;Ka2_{&H#J@vag2JKH3(7D0(pQ zzul{0ExRSnKeJ^n#W-xJcS-0Wp_tLL9L-g(B{E;?mzs7g!v{T4-LE&9L~!+7zO4*A zo{;D1^I~xqD4!V78&7=yCc605sMURT!{nWx97(d@^h2ynw0$IB-KVOt1tH5&gbY$m!Q#>nwq_DZ#=ip} zweTFNYKy?|=0vpAWQx-99`Kj6F9Cd8t|!EFB3-~H{kyV95GdiArT9}nscuB8{?=ql zKCw{mzeWdGD?*B z3o22}FOuSf1&MzmbjCK*_lEv1rH;Y~ni$Zm$A2A4Gr?Hxqe!IXzqdyFnK_PvL~uxv zF4r6@t!+?4pIfP+R*O0h=EsbN5!2f z?Rs7XnM(uBe^MZ0FD0gyaHR4q$DX#p0`fam+2}HT7QnPq&;P8+8S*WZhj*Nr>HLD8 zzU&;~@2Ly*vRO+#Y9guG=%?JV%IfdQUnpj7!w?q%;#qE&5Kzp`0o5E80wC)KhNx}G zC-LRa-OusM2!&1_+xSKNU@OEoRr(o#fXs#X}J!_LtnL$;62%kz)Jt+rPBr zU^Is{yC7FH-?~eLz(suT7hY{TOgt}Vwrh4@FN>!R7q@z+aklf!!5V#@F?%r?Mv6?w zCAP{t;?lZax*9r7e38X-k5ytZWf{gUUF`kX<~NeSo+x_NN?7EfspJd-sx#tWDW|lAJ{y>?t>?o|+Rxu@ z70cfRh|@mP^ZjzkD`pE=cNmaGXP*BaX;!2y^;)7-X^jozUnE2(_1I+%zccWH9nGSg2~X+ImxMu8R?BhvFA4xZ(Vb+Oqnn(#SFV=RH!c_Jia4-o|sHh(ETqlfx zYb2@OYL1Erl5x1O?NOI&9Xw`r>&S&mVoY|FDjvF{ceN1xGsGrRNfjeCosj$S$U>XB zSjkcsNmV}I?1qqvEVJ=bn$=^??z5!TF9?Y~*7+FK}rk}EV{20q}T?_lexbvH;Z?lZ9nB3t1f<6lN5Z(S!U-xrTk{&-Ea{b4rJJrLL=Lf?C3DuXX7ffH$sm?o$ObSVK+jrFYzUJ zVDmFL=-7EN5xU5fCWPtAjlH(ToK069q*anniz`WZH7vPcS&Z!-+u)LF-f;yd`WKMd z$E})9??Fdsp|Zl`@#*Vf*$h%=II-<7U7aTM;Znu|6|CQ(zfSXMp0)zzsxkV_$L)Du zrv&o*1g_!RtdNLE)v`FSdY&-xDJM~TnIe&{YsCk*mUER@&AN7@%`rw~^3vF;`W1Zr zUJ}LXX+>YzgLjp8COQXT>xyU_M9>$J1ii>Or&9(b=+DVrlI*z&!fff~rKD$5Bktr1 z#aZ6o&imgvl73zMhZl z1QaZhFw|z#CX>g?>?i)X>{XbH@ODNK6?^IjVPJ7F|d z%E0}J0lCyv#`C*bq{ie_n5SXy@)hr;M#@<3U|hbkuO1)aMUb1OCS`+1$x-vv4@Le` z8!raix@ksy55^X=RnoDUUI`9CUXb)!C@6)b>vAJ!Ug0?p%b!LVZ71TJHzrOz=8}S! zs_<3<_V%YS+`tCn0S7+^+|4G-^g_d{W9QWD^inC0_4Vbc`UGi0KH*$+3g-1AJ5Vmq zJp-oHCK?h(04gex>-p5)kBFl2pf){R&`Q55CmDqkACD38=!ZDD{TOMgHR^!#i!3t0 zBk=nrogAgU&^vCIOBL7~9J~kxlIgYq!)%=vU9>%FHIEDyNKYSS{4j8$y+TTQQ)9n(*LBm57C+;ulZk;HqNOXlC zLI^KLfjhEU*iW=0*WNTlESNHJ0kRG3l$B`VgqQ5AHL0Z1ke9|OyObC6o`RBxzG z`8|eaTHOtn2iTRlmXe0o3QwQ^Cfkr4%@^#gpR`=(JnuFX0jN8`R_CWnGvM%5;3KJh zO=akG)OZ*dDAZlq=F->QJ#EhST6Ne7*ts(B@+w9ewPlSi}t5`9(2cYsc7=KVuTCPv5!ud27eD z!)t911itv?(=>VV^|xW{RjryxU)_~+WO0z=wcoatnhl+1w`4G9DwIG#OhB8M!}r(Z zPS4iM9V6GPX2^0wPKqy15am%$YQU}2Q-{ZMDuQI*_qIQ^#%x5}iKcV!(^^la4{BU- z?4Umd&aO;%n@o^UVU(R@E;{8AOE6-q$6$gHkU+gv1vqL1UabS-Hd|rdrbH|O#JifK z)X3k##V|DMho&hI!Q2MnpfHoZGeVOD&izC@>5ulIC5ee`c{ROdL_e#<7$a9Ox`zL4 zS7gS)08$SpjHe7yB=RVQoWkt3uM3nbs{Wz0@lyjW&ZdN?VnrmJNoYP;4F8>DNugMk zP~Gtfq4+63d*6cGEPh28NpHv0ebNh|GF&~Rjc-L$N%G^C;^JNGNFEtNF-Hdb1FQSc zMzxcZ2}<{l`8_dpB zCO=bS)P#G_sK;bSKU>2!P!p;QEdlD;LjftGQvngsOAQhkR9QRF!SOoO_Z)f#8~@>S zSZ)L+ZA3zMbi_+6KbX^sexrI5-P9Vj(!C>+#K@-FuWB$+p0!czIt#u`DZrTt$ShKP zAu_e)T46O?)LJ7nLO&8+4*X`RlOcqQmp9OV*{zi6`!cTUe$j`c{>&^1!E0?8T|D+^ zgs?c}up62^-o}F1`S`jBUzO{{81$VfH|6eL@UN}Y`k(^w+Ln1YiMX)PnT}7%w3%nr zdU1cxmUu7!kV&EZUx_oaRXz*Y0vSMzKEy+5<^ z3$Ywl>ZgRzm)j2c)Jj0CXznyp^GY4!WGtOs(cFYE_AQ@$3$zSH_21iW&O{wCbJkO%(sn>sJ8n8!U@g3@Ph*r?6!VV82{xwGPa~ESXyG^vTFMgxa9Z>99ex%| zFwqaw7m{=8&U*6y{?YDnL+kQ&A1ykaB&o165zz)Hnu%`}<_G<7Z~9(&oPim2A})i! z>+!29f2ilJptdhX79ZbLEe-x2iBXVaxi(+VLOY*hDJK_uBrvN&&nVMliE0gGnT%^O zByyx#kXG35U47ryEvyj?u!z6)`Z9HY2C7p1E(%kzXaDf5d)Ps+>}6TmXo+r)swz@X zMq-6jD(1Nl`WtgU(i8JB7v9K9g}7RaXyIL(orzi>{4|wqxvAn~LzhGgroFupOuKn3 zAM>>xcSHUF8_Ub-&-Ud9+&Nuvh!LVzDE}jRvYA5N1CDIPSdzNQ!R`G+Qc4oZ2hrAg z?r`T}gZ2XoTOB5#?m;m7D4nXR1NJw_^sgeXUpUqhTIFc8{5xG)8f7LZDgy78+cBGG zwwILYv^F>czYB^Zkfrm5X@^GZsYe#glOcalqX@L>>Aynxk)@{ZiI*S|6*s`1OSau% zGAH2@!gFmr-t@J2H9>&5fcUn!9Cn$ldLBfRUJp(khzoldQ<)@G6q z-UY3T(Mk7(C&IO6A`V$HXg_O;^@~(7DlQ}QB&(D;RP?_PTaTg8QyaAh!;qT~zUH;> zzpC8S+~gTtmD!}bg?fD)tb&9oH(pmfpGL6ZSigH9YhKy6tXTRDiKpKNG3IrmE%_~R z=w6=?xg0?#b|);}z%g_$%Gjzfg2bu~q*$``5ngJ$fr9t^^aDmNF~BNUV(pg5*SmRISKnypd%vg^tw z?L&TXK$i=D9%?Z+T%J6L7R{qae8IT4W1c2+VmO@C`Y*pyz;`K~q`ej-)+!rm2Wilx z%RI=JtkBLEz1lJ&%JxZ-auwHA&r_#)=Ox|hM5p>_F&cU4!R0iX0j$GR{1N2CDQ{h8;ig~+Sp|%G{_reM-(H z;F^>vM+H`=$-@|03xgSv+brD26Iw2iYH`UlF;0Q7^#N`Nb_z>~Jrzuz_4CgD=kAgN z_nHu`_(IzKT9~$WZ(YI;g7BX&?Rz2ECHg-sTiT<`)49yH>(@!w4AvnD;wDdEJ#CJD zB#Il68?Ywk(I>Cgt&@h8mv$!W!6T!w6Gth7k5*;vPNQwcVnN_()0YqHwK!vzL@nIR zI>J86x6#3E`k?-FcW+Q`*pu-_Y?kT=O*EK4TSqeNZ{w&!%_VR+%vN<3Z{!v1V@|`b(=Kr9Mi` zH+}>fII>p#4NN;~B?HO=RPRGQ(?ea;r9`)XM1I#cZq4IJmAJjv(d@#&>9WFx8hDBy zlax0>zC(Q^UauBRcIDn`~}l+*-s$5NSLq#A_VUU_s}0#D<

    `CB2QUkU(80j z4E|99Y-1#Kt#Cq%<@tP-o?)*xj`0Ip>U|4Jj)afIv;L8eeVcQXKLJN`=Qqnn17&1JQIgi9e++ zmhvAlG6^iB1aaW@$7$dM_cDw96dGD;!-i7h*M;6MCMMvcr|;#QCCEH@Q9hqTrL$cX4Y(r40C5@^W*iZq|n zNL?K0&Fy~d1L5K`{zju{$!UvYRS>7toF%lT_0@K%W}NX5e)P|J^&eKqW5_{O3EnA{ z{wvZTQiI!X6$S5E)i$b?!$c%vO7;?~T$h|VHY?45hPL8vx6pa=yCrS2!EtE0GNGOP z1Oqj({qA3~+-WiEacM&$%-ymY@!#^w-$<1VB$b>p8p#H_n$W5aC<_B_QTZs2TYJbasgf226U_ za4kWG13j%6rwF6QOzL3KfRM z$~Q#gGafNyDW)7j`D!Yw?h=}>p0Q;Cw&&PK3Um3niV#}|PhBsS&ii-bIxQ3M|5T_Q zq342NmYbOKzLXvQI+plt|3@yN*=QV=-k3-TZ(eb^Vx&(9*>IrEvJXG+``UR-N$qDP znUf4k{$IU#toHJMhcl&$O@X3X5JA`a>Z-*)4@MsBd|u~rRj};K zWKadsBH*x-}+H|y{qDt&boepu9)8Mr2O|=ueOZ)5Y+Czxie}EN> zp?0as;*Yh!8PSeS`XBHj#}TLqIK*OnPGMx|Wag|)U`j_?r}E=kQty{nW^PDh#9hSP zic<`E(x?dNP%Qm$FrbP8?TimuWbn3(-a?1*9ZU1bmnORN-7M-?*~XCS4m$1)x6R&^ zuTl@O{<*F!URP6Pbr2iX?05PjJs6PUG>B+(eZv`JyLL(OuX!0E-4{bwW0mRaf6f}I zEzmlDhW36ULV%+b{?9~JxzidwCs1NF!iHq?U)3t&FKHo!6lhNk8aKsa zsIgLdb`=4MOttU$wUL|9TNi#c;$1RSI1FqGKy zgpx_BFB#_7WQe;BUO&tye-YlNQ$7RzAROqgxOs==H!zNH=frn0DQt|0;#MDdl@YM9 z%Fs>aGFe~?2oX13@aQcET5r!#RUE#;lH))x(M#eGEs`25ewdF84-OP>`h;J72GNE! zUl5q_TLS47BE?jQcM}aToNr%{h?8J@PNC(GRXZbq!c0FL}?!JHH0qDguPb?`ZnY7^=eFusTaHI5G z;A%LJLh!MxzP-pookfea;N6Lj=H#Nw(Z5s{BmVD9z;DfcRp!y~uF_+{yc1One?x^qhww)6 zZKjq9=HGuLnkV!&`(h|991vBgg9$;hQG%2!rVg_GMyot>vY?aqea)R<4?xcB$#xXv^px$zvmNH7OvriXs5{(g(cIr>d7 z5=6(FL5AjWkDvm$*hfxGM4)l&1B;~CH=Fcy=TlqOGhQ&5hkiD$cko(2q*awng`Jso zmBf#8Bx;3L4&)#;r^Bm&B+nwaP4n`9qq4@rFYZ+7?rejL5cEnH?Q_7y#DrZG)WL7j zc5og?bjpG#RvhCJ!|LAZvB2d3uhp8F>~dZoJMdA&dVjeqU1rItyN(Wq`oDZk$d9u& z#*RNrcDOEa<>Fn^T~AE>O*~@H%2@v}DX1@~hO~xy+lVKyP1+MUjcTANBubLcF-2kQ zN;LUpV~eqoa~qu%fSpZd4$^&-guj4X27 z>g+YM*jKOOr0eEusRi2+$ilx*)DIx1qIo2xMkKDAZ7z8qq&KNuSR!4M?c>)>V{|f9{UTkwDs^sT8GSVFt6Kr(k6@myn|nkD1}yW5^_Xgy)qNJc zJAmN6{So(KyW^BiHmIkDrS)N1Teb{!UBp0Z`1PU2e8B5r|364C*Sw#08J2kkIQ!QJ zxDDq@R`UHw_BfX;z&?u(0VR!V%7Sl{JC;Y`@WT%pdb(-Dub$d#=Yw{O0z}wGK5I1K z@;jokdJ3Df&b?KYibZAOmvg-xGC6(DTR%@Q{FzsQI%X01|MrFb>jI3vc@-^|SU>{Lc$Y z5N+(lRR z=9p0qo=!z}I2O-KkQ#m=U%Fy03vAq(bR4=J0OtccnEAxBfHm%I=%;>cLhP!XPTXq8 zZ<~WiBn@*O%4@kHuiGX&)ejag8j?HyHBPN<7f&R3sCVNpXi3V>5+_SpuAag)zh6Rz z|3zI5D58deto$hGf6ikdF`>#j7u+$RtR4An(fbo$^Is)6givVEj>KuFt=KXr(g(a|7UZIpmis_NeTBL|u*9vinRw6l3jDDnJIx!BfCwHlx~A#&g2is~muOQgh< z5)1Su6Qw)PZ^Ft$4SSg4SE!b4MI!(4GNc-8P3uNpMs``JfwJIOtwc1AWUMy&eV8v( zCZ1)83>D7>?@|rV*!E;vAc?nz7gQ@xiGMs{OV77f+pOD^pD;j7>^_XrTJa*?+)~FP z7D$`qje_CW@i(DW$DrqPIlC#tUm`CwJXDTjfsuJbAaUmPVq zT927*lFT$FX=5WQ#E;S6efhvFsNY~fHP%4*6)oDc)+7Z|oS?$E1<+sT?Co*L_DOj5 zGjR&45DSo^J=7p^JEOGS$3~ak4sbQUU{^yn1GqlFL2quACBmk&jnUyRIS?bJ8KGp+ z9UD!X^b4mHCIDULj&Fl%X)93?*ha3t6D4$ny~=#*KJWBXv@D!3hR2mL(t+so8%RA| zdCU6=kNA2Hmelr`8dJ;*;LDR^0^pD0j|w?`8&PpJ5JF}@_PSoJ>1-gve&?M@5KdZu zM&o+Q>_$>-(ey#*tWoOze!m(&WWLJoH7xnqc3twQ7E)IKVuR>g;92Xf)k>B-wx)+kHV%TPD1*OCBuR$#AIKl6R z8j9*Tfa_WFeou|VlswPfvRguAFTizE76D_^w(YB;i;Uyj-$nr~rsWcAB@KN>ocmBL zu@djB4PAkg^U#aHgOITZfkO_Eh-Lt^DIs$z+r`P3kUvtb=y4L0QNp6DV6_JTwE{_LmFCyRlt~E>N|^jw$r+x2-6VNR?lI znlwqa`YR!f25e9xy z=0Wu&`h%K|7Cq~4WZ|H#;N(I!dwnsg+z#vWfXH{^lvizkU#P83{I4|!n{=90_#d@7 zP<@E?r%*`#Wog)KaT>XD=x5>iC{?+rL1m;Hw!X&$XY`sujg`$FGWWXlC$$DCg~0&9 z?KqLm|C~7SGVdgZ^qu4!K@$>In@=L_N;xqD?p0tTrTE%D>a-o~@yRi6SKltcTC*kY z(VKBrTl&Y;fr0bX+HmW$b_;piMO;C9Cwp?GzX7-1v+w_5k(V?tb#*R!xuhmpwM%X_9gx*>AwlvwOi)8=|o~9cIg!gI(IE18ca-ciczTNJ+Xc2JItyk=gug^K<#lJQvE?EvoT45GJMQRsBe*5#^w^ezOLjRT%(DQl( zr6Zpx%2^61DV=~c_vLE!BfOuA1a}&C{P}RXG91)X)6(MF+e%p=n~i6^1^@qYq!SON z)T~rS$ksp=`etFH*Jo5TPl&|jSgz!PL21(08+Y!iCj3hb{86ZaX_IOS>S2>s>=jin zN3P<-gVEluFIrIYzuvd@VX<4A)_%RO1B>PggYi0enwO1`n!`%de?(~)`u`H854f1G z-$+$!DHK_^<%@9?gRaHkwdPFadSeU&eo$mBGjE>vMEAk5mP%xj8ZkFwjZm1&hj5t& zocHg`xLD$BnYdN^Y6hrAZB+NkMscp~ycZr)=l?4e{%4kh#bO<$-I4s)9dglxEJ`R6 zdcj0=)nv(#el^UMOi|Ct1P3Ypo379hD`?4Z?tD%DI8YQ&kgtT!y{*7^ainNIyxm?b z2t3$NTjmH${PkWakk0riuUKAExbs0JkZfbmLqL%YcN}DMi7H5m5CLAMT81*(91^X` zPgf$9bn&KEKzA?ENVHS@SPrgS{|*v#BBPcQsG zGzu!~v6(H$0I{iJ`R5O7)^8Sw=sdrfTcd>JFw#Kb#K1(!n9`x-#4ob1iFS*KI)maA z#z!d+QgWwX&f@^R4K{8vY|avo^A+9%x$pMNzaiYrZKl|2yFEGJs)E=1kAD~CCG1{W z{we<5RQM}q$1|uQZmmL<)9u(w>d`0aUEZX-caOW_2aaq$~M2QS3F4A2SRpkmqrTw&*_-f)#`~!O8CdYvsn7=B9pVBw9J0h>~rf zsWi%m2FK=3lYL@TK$NekD%%zr9cRvR0)id($c&JX!yj7P4^iZ#Ji>?D`IT&# znKbN{$WW;Q!$9aE!>db>3dOU1K`Z2@7MGrK2oy}a|?3;_dl{HBvr{W=ZT z;?Wg9;7DC_`0wwxRb`U=*8FDIq0V=FSUcw%4bDo$*D=RfVRn5LnM<$CmK}53pN;eRIu{+*Ga|hH zW@|l*uYXx(YkYcigm}sEtUL3(a-LP{)*hs>sWHJY8Qg882r{CeB&~JM6yP;MCHa1T zbS?$$OAG%a)3;+sv~o?bMBXUque+&!zNTAcn9i5#@g53A;{(B?ztv0xffCxd{ILk3 zrgnsVIgsD1b_YPRO-%n-T)KJ<8xtoRi0)4_WVj8>lyKL_lv_uh&d16YE3 z0*9CIA#$9+>6!4P3lBm%2N5R74qo(+x}VX+4>QR<4nr9PQ^sCPnt|F=G}LtCiS8t$ z&8%}MPJbEMzfP`IQc-Ch!y&Fbu?Tgz*EHZ&GEcaMEOyo5e| zDZRr^;aKydQuC#GM+i3Pnp zT}3cp%&_Dw!-r?{{}^vCdOwy@SoKbyPhId=?G_gveMVFM6xu!HUa}7bdf_|kZEXhw z;1%ZD%-jf2wfH%OJne@-7$P=T`CLaM7k_#~bwp~l1atcSV>tSB{-s|2eRT1qh2SAaw5w}cm*hK z7r_Ebn{-H7D+B)mm1#be&S+A0(1=-+2o#^>pA&GC-zQ^NC)$>Qf{=cF-lEoETJ=?H z|1zZm!EQc8U6xWG@Bh?gJgQG)FAoS#8F&6F<8ES+5Ohl4F9P>R4QQVl4Oow#{2X(R zD{XG)?Ve2Ctp{#Q8tnKk$v40oO*aiSwTJd1PG$oS4$5&23(7j=6XUh^G7X_94A$>4R$MVFgA33!U%#T7Q96jc@S13JwkpV zdatwATITDai)V9+ejRC7f}pe+qzvULQ^4%4?$f&5pgX82FwNc3949XDSMzv?K81x3 zH|Mlk82~Pn6SiSb`-_5_6kK{E~DNL$2JqXx)L}dyc>nhQm(oN70xrS$g&}IO@?`=jWi}3MQ zq|0Kj`7R1lVDkAIN`pa$Rbl*k`AL*;sy4lyEUZzmZ?f*mKpIGsK7oce z9IYssliMd%D6YF~k>TyZoR+92b0cm+*i@E*Qc9b_1C_9j0BgVqDtmc`G3=R{uO-Yi21xsl6$$8y2U5*sbE-AfZ zb8ou7AjC(-e*w}V!Qke*VTm0$(;m@rAd0s62DE9UwWZ|q&Af6RdqMJ++9HXp7sYPDq6%XuXMcVbO;tq!`Ro?>66t=MNjiq(_=Ktw84!O_vuXI1pS5VAktZMA9 zF|WAo1Mt3mGp;kPSbj&d?liPcZ-Ya;j#)hy5b!-AYj%7M@}T#O12!q47Z~OgR(lAE zR>RY}x-c=G=fI=ouKQnxdME42f^b3i*5Uns(x~Ie&nqQ8eZKAjarByRs@`hpCp22d z@wMCL%WOJv5lcI2>oDJ)i995DMo4O2c}qisDtj7*G2&CGDUIg0H0llPLD}W)zvCA| zo*g|H^4N#0uhyFd^uAqv4cooDz$e7+<2&3UjxQfqnt1O(liHNj?$@;ky$@{H8?OSBL7t9k zvXIl+N@r!J^`1;`9D1$W1AVa@odm}dA9@o*%SqDt|phS_J!AG#jF zZ4A0Ur3Vl=1YF+z7C0ZfWLT>=#&@H>oYYK&p3AQ#Y4$V!yBd#5>7u)qFi+9;ur1E` zC{?Hlc~GQWmDFH^1ucFH?kg;sK-*d4`Y7R1$~%XyF>4>% zSyg7Gc@Kos7V#frZn4km)(1b4OctH10sgfY_kzg~hfe0@h2Y!IYK1s73oN7|WC;}a zpU41S8|yirRH~Hh_4yTL3cUXi2r&?}*}v`WNmMB(;OygJxzFcJ3Gga#m<#Wv;2%6s zkC#V?;=_xG*f9S=0)f9pCQpOd{bp7R9KaN7hd+_87K5S+pO50KH&#=@JASh*-WQiq!*p@w>t1`2mHx@MaLy2%UfNssA|X7_Z1C9X z_{}J1-ofXSxJMWOC*wJq()u1F`hwt#orV2WCxYjY82@|+U()&0TXOGlV5Mw&H!}i| zk*0dbXfvyVdgp$;f64VIh-D*~YoHuufhxAUWOayiVX>0N`!FV^FX0PE-NHgU<&_Ma zQJDuhw=^uCZhZGQdqlcj9NO)tUh^2y->VxoR_Y01HShpahg>@9lE)6;)C)eDFVj#E zpe=uqzqQ&QGjaL!B@%zpK;p}z<8>(&fUEoK2JpoV4*W^Ajg4$gnMCoz>&_MhBr9(}BwWaiceKeMh411f?l83%OAxlI8_;J6!A8WZ zKKN48Vd@`Brju=p!__}etn}5x(QOW|IG@4t1JWz`@4RQdk%#d;UUpgUsc66Mma})K zwaFXJFrATI%;e)TTm^XKqDUjP7fGVbp{@+A@JA)vIE_v=n+N-~QL7Q|ZiWsC@0;u*hRia z40mRBXh#oz4VXh(Q6>c1@#r_{KdPK=)P2o!gyn4USVRcSy1FZcX_nzHpRbE|P6wB3Dp|IOCPX?W0*n8M$~0K+1Y{SE`bqOmpJ z0aXI*12U!=nv#7~>S6XM?v(u8KIE)4dGY6LyPI-rkNU*vpAf5qePBc5K>`O0Eu4MMpqqar%kJjnHq>FK6_S++ zhh+KnbhpU#5G$`&zEqeED$rgh>IQ8hv)0rSc(iz4Q`0CT4(2#6_5nH1s$=wC{?cU= zcsERF!uqgCE_o<>j>|PE4>Ni{N=RfT=RL+hg|A7&=Nd90){)WI^Xl~F(If83>hQ+a zVc~BO{%GoTdiwK9$DAddXtCvqaG0j;ns*nErO%=uF08fVz$diUv^s}8H;8)ojcjkx zP7Wo0_`3%6{YBpL#D!wf>Txbc&)Wp=^$yWN&>{QQo=EjRR~c?p6WXdOvAa&V(xAY? z>Tz9BWS%YG7PpF2E0tAIBG2G68i($ZhEmLgo)f%}w$CEEw4u(gl?4|p26Dm^XFLr( ztrLZOo=m7yl>6IuuN9S+8(Za7;8=3{wa@jW)VtnT`NwE^N=PfMve-%TqJ#M=fa<89 z{N!{k?HG)@h0L#fDkAW`s=~p**3J~)QE*8kp1WJjQnHui_YOz?b?Zk|2Ujl&WNEkX zD&BCSc8IM@c@t6s0fK6;{4%&Ex@~~XW0n=#ulq9(={#Y_i8GsX^>bO7`ugE(T&J-C zna${@ZlYlXE-WVK)pg`EjT{zk;y;Rf`-$0@o(__rtmZ?bt+UH}t$9)R_bo_F-Z?$4 z>m#aK1uw`$%F1I}`_X>_lubv0XWudjr4uj$=Ben*k8NR3Wd@(ZtoLudQW4aBL%+VH z(`>*&v;l3y1mA4$JtkW%Z>P3uK^vP=C4Go0EN4l6M>^On=Y}k;S?)73W0?7-{97s= zxH>IoV2;o-H$|p;=w-oP^wnp^gjp-CZPm4qI|J|_M~18~#4 z5|E6c42}1!_Z$Jwz2!=e66`WJ^E|YKn2iz;BjrcKZ*sLilygn$C800z_>s#v&d2do zpDwe#1DW8w(|wx0T`O_@uH^!Wx^>5N05)M3oAoa8r-W#oiMol}pJ^UHEj~(#mBK9P zp=^h6GBTF(O8n#itCe^h6KqKG?IjI|s2D^{%c!c(WKLRTP)SVDg0t zilZ+AdQuH11VM@_%e`f_zpeTroi6u!64$}9ZKwYtQ;1+e143{mAckRUp#;aeHI|plDuYs0ZHl12JMIq+Hkb?PUIJ01En>xU*JQpwuy>#P&$J>M zVj^W>Xo+-B=|@n*o$$Pxc%8#IGw=^`JGH*nwItUOp=T_rH<$NOr?NW8C1_hsN6Rf} z_}Kn_)x%^WvC#8C%tqduCYiMs_tdS$Qf+R46>|N&5)G1(uB+z^(#@&IN}*1XgL-$J zdedmjIe%m^@TkCR0Od=1milmGIqCoxyk>I*bD+kAgR5=t9BiAR()bzwhtA)%t(;25 z|LMg#049APyx2qOflc5PM;9=x#lQQJ(ij)7=_MqioBDl4d!6CoNf5QrD6wwPuLlpJ zb!9Wjq?%bg+j(-cuLX>%@%|H@`VZwp5yFOaOonnl!R{Wnys1x5Z(xnP;mxrpRNedlX&LYg&9T8d8qOv+cQ zntUC$P0Ly4L{$--#3;9}g)>9jBQX_GqJE5|?~|5$EIuST=3fI2ui2dc-TF+lYGi$m zZ8pI0mmsUAbQc7SC|$#@*{zUD5L$v&EflC3jzJ>;louQpa1IZlsfcfbXP(N^Tc1|B zC=u?if5u2Uu9@6IPpwILdXnW7frfl419ARO5l$h!_L+Vj>E-ZoL>&=oD!k$lNLaFP z*RSdK>&v0AUR@Y1M|00)H(C^SuMk%LLQMF;EzAosZ=D3zL&C7<9Y{31cjmbP)-}6Q%_0 z&$gsG&Szpv$~(tid9TmS|7((C|GIY!)o^_VSvaiRv>1qeV@#9$UbLP2EpBgI zivfU(RQlTRmR&=z>;e|$k6{YNuvoFEO_XW zZ9DiCXM@oU%cyys5g~J_#e)-1)qe&A9`W@8OSJoGGV3Xn$Y6%~T6i1FzFTH!$?GjXScO! zFTQloelvZvc`2V=cp&>1YQ%JCsDLe?ZNsdD$+}RIwHr|VR^*3M-hb;9J{QrE?R*9e zjHUFIKMhnwOv8lEyaFlq*e*0&1nX`xH4IQUi0Jdbk^WLkvXgscJS2AS`p-|ZxxZ}2 zO5HYB6iZ!Ok;Vf5+cMadfSEP3s=N!x(%MKP+K7UZMl_80yPMEDY; z#*S?kJKm??(6Xjd#RaU>){i%d1Xvv9UF-w4N1~#th5;|NnB-QVo%wMKZsSO{C}LxA zk4C3bWQJ$(!{Nsj`O1l=k67&!fl{<}<2Z2i4a|Jy^cEOq*Y&RI(XQ<)T}7wcCBY0! zDd648E2Rg%#p3P4h+0HVq~JhNSVIQ&I%cNcJ3)z^aXof)?)9h`GeE3jlL)!9IduoO z?l=@8>-VKVvQuN_rg01|@SU8jc{^aQFZ!oAc@b5sJOIo#G|~8Tug(6$uxa_nowPz~ zH}J?67>N5w#u*EtE2tHD|2-il{4H2g4*x!Q>q6gCa-3DLx8E~V_q@GPrWmTX<4%sN zvCsAXG2#1(%K~``*a<$gcCV~nw}xJ(1#`{Z$!CmevK|xBgs5&-4rW2@R~CRd`$iPj zf2vJPMwh)kg^$|2Ua#oSRvJlu8u9G)?Aq{Ksjw25U_vIrW5<>(OdR?0R88#Ht_7E~{G7FV50mJ?)r z@uIQM82PhXBqa@{gyhHSCloE*v5@#a!|;$ip<`p5R9DsKD9aWX*B68h0~H| zYrEy{3dxoOMR5`CFAE&*VUE}J9|9`yA7dzX%jYt7$z*5tNJz)GgN_%u8#G~ML5C~v zc=ni~0t@TywDleqd$bbI*9Lk!(y-tXAfhu zAkii3>$AUxx7W^c>j;UKJQ*f91)YQenb)VuE})Wm%U&Y{AMIyt(A#(QgC+g6TXU)U zmVt~aV`ECsc{!9EAxt=+Ip=iljYE(xn1{3TV-<4Zu8>C!eHztF6s>W8 zJTSJ>?bgxWwFJ=0BN`l#4?V#&>hioMJMgHu!rlxZ&mCy0Sox3{B_7=vH(;Q(GDB8N z=p;mtZvN6xL)y@(x0<^#Knr3888{FsV{EDuoE?c6feyaO_oR{v zx%sFKmZ_U%e`B-KC-Kxw*olXk-Y1Ru7f%u}qJ_TUn^kW1$Eb`j?!MApPZG^ZW&g`y zuWWUNQGHbwbd5hr0G4(+HFvk)#hHY0j~}Gz7lY5s+KpyWV{a(DIRd7QMhm?58;1aL zsl*tfd(%9|8wq2PwZ~E?Ydpr&J|VOis??jVrY!)B+=Hj2;*O6u;PW$Xb@XTyInfXi zjGm%TTPf~!e^q_J{_Ix;*Ql$+=TKgZpQrEFWb80h{S}@~Dck`mwS>=X8Hg!^DHCdE z4d6XNSk7y~JE$c;5utIRx~d)o<K6i*neni0~0Kvfh8j22)HtbbH$QUvAZ9Jy( zrA*IQ+g`KS@Pt#wiP4O)Ci`X&kYpjJz(L3wGhs$ElQAGg)5|?&K0cbkTrHN!!{9Rp zhp#pj`g$kzJFaxNG|}J;7dBu{Fgb-sFe{CAY~l}DF`HF?{6)(x&~dUED4 zD2V~LEJ*Q!wH!BRgpkT%T=%TE=b{&OJKMgds6o1}^1Jh7^32qm;6|F~qXU{yJ)9Jy z>Cqg-_g(cP#2qkjZ%!v$wJ|HGY*YzlsY<6uHG{yllhMJQMZImJw*R zUPanXFZj*t*@loUY+=$So98bx2|TjW$T9pbR!?k5JZoI2F8ItIZxm5@tZ~_S1@po#hpwq6*XmmM?r1 zBgNzj2Crgu_mzf|?BG!o-mDIm!z+KZ*XLfK2GOy&%Rhb`b2{Hi)5xx-z#|_6;u$PF z-@hiVmk?IG3n8)lp+_gW}luBk>i;eWb~yWz*M zx5UtIoImj%EVLCK$W*2Mlwd%s)NhQp0Q*XMMr+n)k^~Ze=Rj?7K-JjHeiK$d_wM$% zBr&|>v2gz`8!ovqMiBatryIqWaOv!yPA?)6W#8N4i;FS7T8L`I>zFQUC!=eHo*GEa zygP)-=EwjSnJ#d?t#zG{Jh;u~HDY(mgX58WvML7La{R=1qQp)-^kDM{K6zjIb6At< z#+qt}=#7-D)Hsg{)o4?P!$Uqy3b#eQgpkNG=Z-92q;ua^83me>q}Swo-hgXhgc+05 z5lw2>DkNcaQv55>E;mNtdE?wB($rC%TsuacyK9F@bzjhFudP)XbpQ2FWYuzd($jbC z$}#kOh8!V68)Dl?_S7JLt8hzE@Pk4~Wz|BF1pjvjSTlDNLt9Q{F`6 zLca(A4IbM4J^xE&bZJ-e(j%o}!EFtbYNlX04Ik0ZdTv4pv+mcxsh+nt}xESK6z@W~q-ltX|^bjV5YI4d3HQp26dybmG#hr%zIGlUntaedkOV9%aZ0o_h|9qck-hr z=t6EaMDV3|VyTd{OWu8;FMX@6K)q+$Hb;@Oih*}jui*^g2_f%n6=#@ zg|F#~OU|!cp3OVzC?fhf$L@O)fnppe=P7zuE-G!0$-iNZ}2w2k$&d~^Oi4@e1wy6 z0ZPD{VgvqQNHS?k{R%0Ip$?eZ@6hDpn^36*%<6%&+Uomzk55`AzszS-80l!NzU;wD ze57S-Rfod^c75_)!qeDbm{gHoibkvz#4DlXWE2ru422b&HzsX;kY~Mt>&#N(DwKA)m$(T zn$A;bblfo;GX^P>OhQLu-CTovS1_EAOj~)@X`D6ATAJuShltfHI>X zB3``ZId)(BI4msfd=7;}nA5vNqS-RoOYWpI{2LacXESpcJbtzPR^$V` z$Lk_0h-P2t;MG7{sN#y#r1p}Dc;C0fc*k|VQ@oj0w}2@2DR3`c@TmQ;6nmgs48ZpQ zeHYQhnNCj|nC(!rga%x0&lW)qA<_?yk_sMGer$)qn)4dqdu~ z)mBA$p%CeIDA2``F<1ViRGsYK_nwe+l#LcXPSKcv59(aK4q3JT$lK=#%ik&DE$Y}M ze(P%{ic}Zn`TgK-1jBi6-^OqmShkVK*9>dqJf9o0*PuM6ImwE=Jf%}W>^BKX9ruYX zq*=~&vu=+1s}4(0@W{pg%w`2jZ_S~)#`3aIResmIyv#DZd9V{53$^$tqU72CIgPm( z0-@{t#S6w1nfQQwPtVUwMlG!Nya?QBL#u^l6Z$Cj+8~eLdL^j@4;@PZ|29xjyu)__ zpmKa4jWP#`rQ0NvGc49w`BKz!sqy3G$FR-k{TqBSz~o;!T~Huu$R$*Q9#KgkYtxkG zV)z~P3?~PZ;#Ts;kLuI>1^F2K!5m4U?9vDZA{l? zQ$c9FqM!R*Y7q1z^|oHq_wRlYE*V29TANg@m2R*x0#@5iPUJowZz1f-;X5fksv#0j zPfeHe@VO-t_O|Fx96p@+uqdbOET7WJ`yvMQD(l1{MCxLoQks#$o{MCa73 zHtmMY^NbivM`F^p`x1(r+DCK1o@ws*Ku>5`SfCWR!5re%pDD7s;si}-mlfsvGmCpW zL280_d2z!25rJpNWa=DQqpW7~5C{9lD*q@5k#cy@~u={;f`Hsf^DT-&2?F#JMm9tiSrOxjn;c~t9{ z$_~{QHI7#vmvC8~NDocwOD13M2?cM!WKEq!>HOK4v9YNElV26=nj~`R*`ZxODW`ZB z1f)!+OsT2N3}5c{QH$e`B^iex(*=Ygih@Phk+}k5)k09FYaVv+^cwapo>9PGLm^PaB_Tb!iag!KB-rx0N z>$oE^d+jlmQ0wIDUMPi8BNKBi-MaeTxdR3&T%i+r6yU#B@Pd2gDpiat{`5Nwj`k&M z7PGE;Ckvc`nehI`d-A-iND?19LISZ<*F><=4km_!a8MLSh^=Tfkf=z2>YpNQSYf?W#9@u3(hMDI3Y!mrn~nN)r0Ekah=W;HJHeTOwU;Hdoe| zX@$aDzlpf)mJ>TsUv@Z~8V$tDlhN&XI_t1n3NyP7{Vo4V-s?flKm*zBt-c4*x?2OE zWjYy4^xu{C+EHx5=+r^7EM_XRb2z!IK0LDYZ zQxfDb<3|6}w<{CPCrPy~*(gP=30#CoP}@!%;_K7_C)Su>z^hGm?I(W91oT-IN0(4D zO~DR={?fA;H|%eXe-#Ygj1py{8&PZV%rogR}%J};`P4~^Zq5r@y zXa9L-?NR8Y?Xz_c^3?$WYd-WyqEOUjW-}>V{2#WmFp&71QVLG9e9_H(u z6O32FregS>LZ}L`--&Su1r9=aK;vtx=(MCQXvqP;ny6m{Nz-N+y_<~ZN;9-8RxKC@ z&oer(p^Cju%30v77vH8uOt|wyht9Rx`8#`!elG=RqWYO=~8OG5S~@^74K#er)r zB~`q_OS_@ML5~V0e@S``5t^5N$+%v6aUHMH$XK%qt2<)l+rfk@@82HZyRr>%6TnA$ z=V1P<&PZ9s{HGn}UnQ-kuG8b*(r`EG2Sz5=eyOiz_}nhR%fj?J5PYLDvmw(0#G73y zOW}_5^FD{lT9tcOy|~hTOytBx=Yh&A?AqF#EX#+<0?x0U3OPw6?UgxH_q975Nit)q zf%Px&O>R%5rKpC6!tC0g-HLA$i)N7pQO7&JshhKoxo2n|R+}LUb_?BT4zURrX9EDYv4OR}so$Qo)7Voki&5UaxHynD>5-+*nr|3WMbu&O zl-NbSuA?Id6(PP9sC0H+4ZM*f6ieG&(ElVxNtebU@mwc@+RnXB>)?#F@WX+XAVv3O zKB{KE@S?;`IY@Vj0h&~xt81DYRykgX;eli)bNo96ox1J6Ii!zulZ$;&CEXC6;fe5Q zG|zP*5x^uU@Ki-8D`QJQ6B3ltOUUx%Ve&#R9NmS;4aw@5wq`{#eN})7j{>tNWVx;^ zWMJKeJA3kgvA)Y7I6n2|Vc}Tp(aVd-rM^IV+NI51o{UbW!3&oj4O;gSD8XcB;0IOT zZ#Al#(a17L00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D|D{PpK~#8N?0pA- zBt`Xp=k7_HcQ5Ch^N~3YIC2yu2L=CviUb1&3@C^>fg=0_MG(mXA`%oNa~zisF6X>? zCwK1u_o`-RXZJS39h^Gf*7j6aSFTrIz1LBk7>)`#__^N?fk5Oxf*=ZhfFJzQUM{=? z5GqQ6k8%-3Mt~o%Is~#P1b%Chj>!Y|*AsXWAC;iEEPj9%20R=aR=rO02}Cgne9QA3 zpVbTvkt77t0YQ-HD6bq(+er>x0cA@PE51h*=1Rr(SPE*@u9JEIMbCMA1Cg4a^Y^Yk z-2lmbK}6S5eJL~M=?(#8gOvz*VF?O=hWLu2VCy)1#CV_v? z1SyqDdY(svOO8e!o{pszpwkZI@sS(bBQSp;Vc@&Y3ShMnTeIx0d#QR5YZ^jGA^*#z zr(i@71fP`$; z{Oe!;x@*Ta#KD+J2o!{wGiMxs{PCGg25FJXbzKa4C=_D3amo=CMK+93V`GD+X{xHZ zt_P7zr_&ET^l(d4gIuMk6pO@=#05!m!q^8O5qFd}zY_#5ZMe4}xXoch%tHf(9oDZP zB@8_I;n3H4e_=u$ka8Tmv6JUJ^Umlb)i=?p}YLEr^G)tg(pn%LTeUbvh{bBB<;{{uLlJfC@wy@yTv-8O&D zF}e3J@no46m7J5sXf&efTOp{fm%{IEGtDFQDrry zR-0acN5cl>1*X$=Ro8Vz(Xc*YL?V$$Rdv;h<;xI7)ilS(!r^c#l|s&;kO4nJwr<%hSE^Vc*#IzI zh6V?!7X}IyVfE?Jfuy;k_Oe8jAAXPzwTr+r>*!jSDEgs+B5uLH4^>DcKjlP65y}Rb zIi$*wBV#=0G_VFiEH2u|lW-eu!ei$Jaof#Z6-kh zSOk1Vl;(OaxDHznVR=U&p(PO_M+FuX)G0cRzynF{;Xx*tNR$^D2UK;oFU+1w`|$GapR_)J9oVQ{_64L$6`<_Dk@)l^%W{#l6}vOM#6_2 zdMJ1wsZa#C4`nqpG^|>+Y9mr^+EiOxha-tZV&~3X{rmT~Z5wG>WoY82)5*1KR?A^o zb|t}K^BkNRNFWI6JLmu+8JpB9){)d1)VBy}@329*fZm`MQ%2ab4)i5tn&VMY-tvwG zvT){?s7RIw+=lWHmrA7LP`Du%EH-5ihX#J2$r~-jRn6;I$9oj{G z1Rr8^&_MD+nM2$2OFZfK*hN+>f6kY=gj6epx231zdI>6r=koD`bzZN4$RykQ6TE!n z37MgsA-E($xj^ptA$Ao1t$-h~AnDZoEE2*n8=0&Uvq4*fz6M#x)-){_v}a?312_oA zBRvVlLl*c*u>3l4-5=uU5DwQGPLfO>=uFf!_^EY}($+@NE?eJ8ytu}O9i9o*t$nt6 z2VlyvUn&A&OxVfg2$S+7jq$JvVa0F6aZ#peoyi80CbXpGm217`tRNUd$_)1I&X#NP z;1bQv*tY3KbRFF$D5@hWX+erq4K{^{3oQ@XV?sHg1i^6~G|BTEEF+jGj%8}9ykY&? z+S*zyGI~hI@?)AN&5~TbIyhGMb_hIAC@m>{@BQ~1>KjtYq-j~u*T#$)i^x#WUVrUX zQBr*Ywc_^^>9N5x_>kRig$%S!=h zjwmLZ%|Ikptz02%Xn-iWq!b4(^}Xn!$50P+AMp*Dny`7PADOv_b~6nKj%0^Ctz%06CM-M=fY*NknLuj<8)G5t*P6Fg1}s zTPbtt(UWZP%*CP&&proU19kw8r$qx1hX#`+;whOxvb6Xqq&S4|mjAZ{bBlMyegq=| zWZMSFF*Dq#COKkw{ok=mZZyrm3Rj)6xRRoaZAs_zs#}PLBilpwf zX1fr|vJFVWx1G9f4v}MG$KnvsCbWyyhdk}Uk5cS*IdtJTa=SDG$&t9`GGn{+E6f?E zX?_arbX*_iBJ?ouf5tY9lEHxy-m)h-ctrL1(Su49N43(5tYTg=%UJYf#SEl$AcU(1 zWW1>B%gCKNND^x6YN3B2^U|_%(zNJYqU5^%#!Xvx?%37P*l1d&s;Z#NDai+4gwYuAdZ8h2m}L)NCk!iSAzR|4-2pi#ZU^Mi^5o@Rf)Fk973Sm zfu|6Mj&dd>e)PeVP>fj;A~TEw>n8G}*AWf>tgGNaL!@^?50#jvh=$NXiiT7yd8-2# zvqIYiGRF%-O-Nl(6!agOLp{vp3qWg#RB4O4G{zLaEIlXiA8Rl_NOCR*e5XW z_)*M2farhvCI^g?lDM89Yw@?)WwIW+h(L7PMMWwWAuoaX9l1`PBCFHPd*|Mya zm6ULKf@jjvRQ0bPP$? zjWw%Rx3n~)_E5%Csl@ErvrrwFu5Y~l8nbFaPC+;lnLcB>nav`+xw(1m+O=TVp+kp4 zI#Q`LFmT|&0R#G@S0FH}-(TI5h$rIl5hF%m9Yk*6N}@bf2I-JqKI978iiYgzZS?}f@EoMwpAQJ50xDLsLxtFeO?Ej-2Hq<|TaTxawAsrm=d}23U zg9JmH0|g+2&bax0GM%z4D~pxdvJk>YlT`*Xgfn z(Tox!R3b>4?FxxRwy8PM)Ld8HzhcaoQPF6ObnF6pYjf0IY_TEb$ai7XOIX1cFJ884 z)oR!A1`Qg3B#q4t)22;@JU}kqdh-otTcS+@mcd!G=3*6uf6bb;s1KAuh|b218zCw4 z<{dM7G)j+v53C+Yf0E8s)%9G&EVeagF6K+@j!z(EGy$$bKn za1WGdnNGV<+Y!infO@hOEEc$m<`oeD0mXGvAWxOs=@t++7LSGwrINR6P@XI{;$gjH zVLbpb4~C&c4d_H2{SxHXcGz~}%oFFRl9@~-OUufZzPq?IR$5+N8IBDzO2^tkG!PWa zY6^$4{VM!q!;a;PS3$e!Ur|yX(?K(i1bxu3Z_PP`_X>hjanD9y?3qfzP1M88Thx?FLv`kQQ6w6f&GCe;ArFQ=nih zsuJlv`(|P~p2993^FydESGm&J?Ao>K_UzfSaN$C*=UZ>R1szaPR9#m?A>*8L&O?IT zyLaDz-ycNXfbNQ=LUc?EDTfRlbpAP?{C`(nHFn&1*2@1$VI&culexLw0+0&J#~wi6 z(7k%Oz21Q7ynRV}v0%ETf@GXnhQ|tQ!A%J&m=61h)|PYk zaBV@MbB4KHpsho@Mq$?b7Q?yB_5=+|6w5n58+kdoKt`HCK8KyVcE9=d!o}~tvv+SD z6urHBcSEZ?|NIMZ2!u$KCxvxHmtj(fepPwJWfx!iqaXbwXMKRM-IPpSfE|Q@kWr0J z+5*yNl_a$JXjP$lgU-oNK?kFfyry&+7M`}AVL!6swJPbLd<+Q+B#z9TY^#48o9HmMSL)@b8Ll#!euPC zTBFKA)w{Go|Pd$mBX?`dhhxnF*TUopb%%HG+Wqv?PoHtd8D(YVk|gcix#Q3G|4CNLqLi!St0DdCU%heuF~=YQ znA#IvPvFn07_Mm8lByay`qppnKrk*-$EfS+E)Ufc6^X9I^2I`uA)|En3cGoaI~?QN zRtI78IKiQ-xJnlY4)R9^U_dAcm=hk|v5B#y6znVjyI^aBbUdGK0-~dIj}0kwbkUVv zEGCg>qTKPyQ74X0La-DP{yFH5Kpxg5AYOd{Nh7QJf0Cm`l-2$K0K<;{ZC6}3u5UGg zAW`g&nRM#N#6#o*)lQMgNykF>hhv@B4vg~HyrM~&ClJmj+|$m>z$YXK1wn10ZPDN< z2yP4Sf`WMTeI3Bd*cbUEd7u&b>QjT*!y$aPdpNEi4(XDtu3o)5kw^?3Iuv||K1rw3 zD_1NR%SR5evRNmcEsd2t_V6Re9C;MdfHHi^cSO+@WXl&?EC;KxjU_o>BC8JH^L$!m z;8d!YJR~fGij=^Ym}$9hOF9LQ)&bPa?$Y8o2u{I&ff37dqNK!uxzc+qzYu+jT*QA3 zxVRl491KE5DnyQ@3cL&*_j4fqq3gP%!}dwR!PD&vo?_oa2nTob1No!Sbn=wf8!a!F z0n?vA2NQa0U{2i+>$eDaJTXU-W&hb%K> zglNslo%t?c?0rEIsJ@KLsowO9wF-7Bs)DUVWLrS_JRaqY4SEAT!Si5)m)oQBlPtGB zQeIy`CG-UctRe>%t)097(bo>?Q%(4ZiCzKq;M4v9p+G|SGkV{H1-yp3z_k(xW*WA1 z)`ick{8S_JD4@sry6B!l@h5NVZa0*N@WMmzL$!v7&2kE1{6j!6RTCs5NsRt{x-SO5 zoo3B4NBxlsS;?}HN@Xs+^pde-$Em84NF=eXudjdbf%~OsI2w+`V9kX?QScq5L>1_v zFi`@F2|`LzyimClt9HuznbGQ?YLGf`L}csQS) z`5tjRIt7)VtFGfYj*ry}CHo#dM+lE9)4i6kSeYT8bNn;}<;iM?`VuYBsVzcDG(3Fx z2q;U<&CSSM(~MLqiEwfJp>r%V+f>_75{Yi#umM4iR zT7J4InM&B1jAem`=yep}o|15+s(PTQRm)EHxIxnSGoyhesPxJiPoztzzMzCzec08O zK+r&?RL=sS_0U8eW;x4raZjSh*4QPZ0(jIeWQ5ezRD}%^z3+#9so8Y$#$$_8D-anw zZTr0d(;D;WP|7?T|jzgsyz`8oAZ@z@R`T_cxGpFZ+;p zU2A0QwR$m|_UzfSdi82(M*O~U-W3vvP?9H3o-l0quukQ?u)_*xTA#!vpKjs8cZLod zK5#%k+o6jA#KM86sY**czI^$LW9A(VMsqx0<~Q$AwaMs&q3QYoy*G?;HHMMj--l*g zbM5u6>mVOpr^n`&FJJ!3%P)x&4xj70ZmKDP*gF{I*{-W966go@24k&mO#k`SJzmv7 zE7APkYcK5Dx-p_iP}oGn5EaFCz52R_Ime$`GyX^?oj7xJ?EINA-v;G@ZY^2%l65;@ ze(~R#AnXbHurU*6A2K!6+Aq{$Ir0-f?@^7cw-q7DJGIMGzOiyS%KdYWS!jeAb}0$QWIfmo8+DBl*&LiB>V-=xOZe z%5YymgYq8;ww4|c^tD6!R1Rbs%ku!%siU>f}p6fZ8;^Sk>~&Ue5X^PE5o)=9m&qq(WQycec>9*vcLP??+zO> z$aY-hrYTBOJaO}PZ{EIr`%`~?+;T}D)HQ|YkJ4ZT+aNsOr#BGD68H{`4f{{ZQQi%{ z?`j%7V%*r&^zWBmuB+W6>8ch9g*5|uAG=2p84+0$)q{?ZDK_*_izixHXWOc^{OOtWIa})+x76-^{q@() z45ESD=v`cNi;f`v;?~>$`rtoZ3q9sJq&`yrgYU3~L*ZBpxW7-XJvtoh%%Qh>@BTy4 zp%wel^%WhGckf8LdhPl;lznm?%IdWvn-MF##|*fAj#bMcSV-=b*I)kkt1rL!(u*v1XUONkGRdPbxJO6b!&b7N|MaJx>wf3k z-`>7+CzLzzT`HBj@vAp(-Lmx$_udO;QzThaNTtE-CW0a-sj>tTgpNm=AuAgU$b9HG zmtGc%e3GfHo40`PL`jhhLk$_aECrzuQ6AaBWH_>v{M7*TJ_^-z{F2fEhaNh=cEg4T ze)5fbZoc83Z(j4KAKduFufJ1X-GAC)^F2~5T^GEEq>=+Ol@%&UfiZjb(SP~--(Gp` z>BA-ue(IrnGjv;vNT=*zb$d29ZAy%CLoS0ymt{>SyIL0ASV%V&ecqfoKmO6J<>jTm zi#(YCvE`{cTvD!tjF6-XvL+}doyE&_1i(9m?;^bSu02?DXicIpk+wube1AK|`u=ICST4ehYHA@hdkrHa5YGz541e)bFi* z@PP*^%1ae?+d8|DSpa(agkFM#qu@fy#Ycwhox-S5AV5{xvU$t0B}>P|mMqa7NC+w&MQ2xt;X_&wAC5VKIQo!74?p(;Ins|J5JY3ttm8lPSv6eZT5iY) z^FmqcCD}t~AzLl$_`91j2pv13pB>-z%0Hic`n7-W%-DfynTbvJ{OPXdWHWSV#W!#J z`nRsV_L^50t)|{|15K9$*?+&b;r>57=4ZWKJJMuU{;2(v+6f{|rf(L$m z_gAj_{L|0Boyj$m4<_>#02S(uJK*S0-hYZaaOhA_kFHPXkoKT;0L|A<9P|iDkuf=P zQ@t?N2X=+X??SU-s#cB!nWMjsGwHx05)Iw?yWf_Vmw)Fw-@Wd->mA2_=%K&FN+P+# zoq<)FKzzk0i*Ao&?b@(mGO3G{7RwFUwJaOn z1N7sOwr2{C9nvQqcgDyg&k{uTk)UYJ-19zDF=&h`>z)$?9&|c3GQJ}Cs^qh$<9tz9 zrHbk>f;Vm1(672Iq6kku^Zff8x5$G0)?5F0>8;l+EiCEsAAbL9SlF&4E}g>SvIYWbpy@-oecdLq<1`?1F#s^7j{N}6B!(obvmW*Ob0 zx}5d$u81NIZivE9e)Qu@F1qN7%P%ihqdGnFa9>?)Q zA>)=?zJKpM_x|QLxBu*CKMO}f2;@ge&FckFYaVm$+O@0RThY)!Z->`3gYJ5x`-Q3Hz6WrqC1VBPedFt&Jm-_Lpt!Eo zuX^xRU;ENe{_qF0W$&K%>tzr;orNSvwJ4&9{}2otK5WwD$rC0`Ds&SkO&ULb!l;p> zD8~L}A3m`Q0ELd8asv1vc2v>XY4ZaNdTBqqMC*CJs>;b^@=G^-`Pyr*{pL5nb@f$O zx3t6&82Ey1AsWD*>gpCmYOE>z&3X(Xe=9WrTBFxAin&*?gDTiB-!RGpd3YWQvQa6^ zm0N73eE5`#L8Ar17(8UUtPO;{@3;X}GD%YDv;_xK7h#k5CpLD}a6w2}X7bdt&g13Ql&i`5oswjfM9LIV1na4=ppD2` zmtJ}7f>W>g+~;on#Sar?fQRPITM#KPMUs9oNo+~7vZ>TouI8?YA`Wf@!uc0m@QrVN z^Q$-B*uj1M8(+WX+Ak8{k?N9*z8_FHGnfbZkIvo;K*lUT3S*D1fYQ+e3Ui3lE=S}1gFr+M2g8`(@Wz8 z-_@%tMtu76&tCWcE<5Vb>FlbCfBLaAGWAQo|MMS}Pd+48GXi>~u6zG_?g^IAd->(p z4n6u5#}ysdRYV_rCqWzalwl*rfBFm8o^jThn>TG;4?*|(g^C{g zWvBMQcl4nOSqx-XkTS7;(@y!!u(4BZx=>1ISsCZiebPA)3xbU$%hz_tGx1C|EqLi5 z0lm+2{qUdx!^ijAuxr!!2~*T?B`B{cQNMcayEDd*D=RCz?rXP|4-J`)v$wh4hXUzX z@nk&F(sJhyZksrG@D0~~v7(}K_|V}k$)-d)L7zSngm`m1nan9*a-JLkMyqyqzb85Hwe^Mx-A89MYk-~LW@RW<2Z zL7-{c%{SkC)X_(M;uB{h0+=zAF}WSr8}MvNi!8*HspB0VrMlJCRd2oawkx;_d(Rz! z1ZhE7RiC=+`K{UTU@K7QQMW);B*AXl6@|?ism}Ta%3~|&`k|`Y9(WAy}+PtyDJ7UEdQzyEE+dk>#O``14%lPOfJs9IK z#M#}^)Hk<&=X1km9ew(l7ixm5+Lo$ycO80P&>Ib?p{$lfbKQ(ak@AWtqFX@jyCnPw%H`y5eW} z39~!`kea73YV%|(an#uU69$Ip3ybs#GX&Ce7>tktR6`=_Gah{851+d7n)5z+*)MdQOy=3bPG4JCB1)2mR))eFkULqiM;0cZ_xaCq17K9Q(2nC`pidw5PL@^?WF;OfRg(^WP7dYR6D2e4H_R@1O z2(J&j^bM~n(&y)6VGVvn^Fnf;_^yZ|iYVfPgDg*gt`Rd2f$c5t~^t>HWmzNKrsES?Yc17EVN=@27L9N`gqb}VuZ?CLgc@ZSko6x#4M z@;Y|!4t^B0HWyMv5k+)|fS#lX{2av6u&#$A<>eLWY-Y!fU6x}iGJ9WL5V-9A7uhGH zm);ED2^a?v=sp!v0VNMHp$1YoJspA{WRfRJ3Z;iBMD`9s%97^*Es}nE2hpbsEXWm9 z#$OZDd0I)41J|e92z#G*U+MvLyqI&KfhB{~Vro8pR)o0xKZ2->DB{3?i+|xXBxV3N z&}VrjPnh!l+V>Q?O^(3ygg`70=~_5aR#u*|&F$NF(gCtpxnfjA5k(a7p9kBrHC-Dy zbi~#j+cowcK>BL}O)Ts-eH|uNPg{lLeU`dHYb{$@2y!(4#uk7j2~% zx|L_!vZlgdx3Z?H8%*Ea&p?hJ{mS6e)79(~AJAe|Ij?3HQA80Op6AJ`Tv=W@ecJSm zTQ;c@z2%gh3-U?JD+}qNaKwm2MvNNOZ_t2DCPUA2xb&3o2e;bz%Q|y!Rl&AL0!2w= zME4S;pCSp_+Ps$gR5TD&O;cq#l}@kUuzvW+F?1i_0RRf`3srwupe)y;x9B%CHibe) zMMb6S(j&%26j20+D2l06DijLAvv=>F<*Sw}BBwm!J7SGWBLr>8@x942r;i*tl06C` zitI%#t*6^QB)~^K=F&IH>k*V4eT&y~Ja7H_b;CxC`tP7T0CbNvsiC1kQIxW>GAQb~ z14R^31cO9SL@`*sdhN26OW5}y>FHSLM|77-xvCTSN#e}8vxkiyMVD|vcKeg^dV~E< zdEf>5+^_Gr?)vrXhm9Ns`pX^Le?XD{X zBJ@JkoT*FqfY3VzkcLd$j|_b&t;l*s6j4NHXr%{w&lJyaMDNS1Tbu_&|bKY)|4!wh$8-zz{revjNf^}RXLCy{6u-A%>}-MV*&fV57fIH zAr^6vqDc8g6wwX9cbFpF0mN!KFF}G9NO$rxW+V!v5Q&(v6IaAR0iVCDfgu;f^!VPp z;#d~3-$9C1Pc9GFb?pxU`p}u{7T&IaJSl(fhp%CX=&qEwrTE!^O9yxaWxJi=(NwHj0RMbwiI(jgc-obZZATti> z9a!7C!GAI3p-~uwmUs(Rxo|kF$cm<6d{rhr2W)VPDB{BdGbIp9OG`(O9%WfpHk-vf zhTPJ*w%*MnnsE}5qhs5;u9uXQ?AWn$+qSI;)HEGi9?kPzRiV$Jty;ATl-Geu#c|N` z1kdzsXnEr&PYx8-vRqN=qHo++ziTN!!LmN zblp(ZcCUUdqKJbHTy(*A)z#G-Hf-=bk5e8C@9k<0nU`c4@v+$V?_c9M-qx*Kvu0L? zp4j>dJlFH`THf+i%R6d$<4Vc{*|Yp$#F()YCQla>)wFDp;&+_N^j^=tD0!3xn$&u& zq+1{^H6zb)=mSNPQ1v`>_X+z_-u{33f}JU#M^$qB9}#kfEhx`%75V@u2x}qF`>c2fX{-8;W8%qnKS8+0)bR21>Q@iQ?BixwqSl3Yaf{M0O&vH0`ziYV`D{W z1$qnZ*)I-5hdLo={L?Kqyu6PJ=vr*ho37`gi}*Rqpw(yywiPcn0}^hRn=5`p5N5cgkzZD z&Yf|Am^dR@FL)WZI3uGKi_=ot-t^M@6e$_;gIDx;A$SZPe2ic zTHeUv`%TM((u(H5sI)CdHw+3PJ*#6!9XPNHQ({w7lWp4us{jX@tSE9c7Be)%b`JO# z=8GtzufTkSNjqV}#1$)6Fv`oF%Yt1i(k;OqClP5CjJYuDJkS75Y8gyNnEOkXEtcD#G?T)*0k-w1NX|qGNVF?z;}q4S)?)a&N(L%iO~Czpy;(;j@%FEP{j}I zSU0JfriFA>#i+5Mj}rXa7UQ_qAtRv6Ez1Pan~sGDMHF$cAt$N(2~1^U$WH>y2u>HR zq(P^;_kpAv8V-1z@#qdc&!?|j@Tdst;Cc;EvMiTZR#aA1MoMDgXfzxn$Cxk1C|-`V z1{#s@@KGa;kkP+?f0Pjohb2iSz3hWpwFeFuIaua&oe->!@W@=I!a-sY%XCC^YSS+j)aAKwD*g7ZKH0=nfsj0;=tw>l_6|y}&Np#uM z7#{m@PoaZ4NyYX8C>NEpOtWEc-PQl^v!|VU+9%FF`x9r8JLjykPd)kMmtT76x#ym{ z@PZ4@I^#?p4tK!?7c5w?Kvtl=@{f5_qj`o06&%mI;KB><{{8RAjUQ**uyJ9I(?XFu zT!8$TeFPBcTbU7*Xc*c@S#A+U^c|oiA{%H|q+pSzC2E?XD5U6MM$w5Q+m68a^E@aP z-~-=wVBh+V3%idc|KN}u*LFQy@+J0dZV}Z0+tH;+Iu%HHa|iUX98x^NU!|p`l@&RZ z(?7vrC@U-D;T-HpIZ~oCIA5bbu;tkuBtYFlhVjQg{_)*Ki>~?n7eYDgbCy4%$YN5*6f)Kvu4d2GjinA>C+FHI~TjK z|DaU3o+m3RWSpn}V345V34tfd&?zuT~W2-xBE=l&v!D53-S)WG!FwPS~w&4S8QT~lGFFsJHrG!jx2C6!9&FF$_x z*(A{?xjnilA_b1%d6I`r4=&<6*Z_T4)l^B8e)-E^zW3hyH{5Xj*s)_VFc=FsTDcf< zu^I6dS+9s93Xq!)e5PP_n3lD5+qQTj0aY&W>Bc(Ow^dbE6)~Ag?A^Pkwzih$ouZIM z)mMYFJtSES>49Q+qUr?54}6FJ+`%HcfGp9C)4Hzx^rt`Fwsq?bH{4KFRmrcZ^HBsO zcDWf__<5=#iYTHLG)1`c*%b-Pu~)8MlTN#yuhNMkKgeXVX4>4feMd`UgJIB{j73Gp zjLI|S2ZKakZ(zC!%J2mg4#q1|UUvYsIkp2Xb3Hd2jW#wkXqpy@L^?1Vx{-Rd*qKEX z(KRqZWOl(4JSL0Mp1rj#@r0r(kw_T2-lol)TH-A-Oeo?=c1Q7t)*mEjk&Yy|qKqwU zHtY%l99_!DMJb{H=y6aUOjy^pBhkoJS6wx6(xe~#=!ZLZ?#zz{Mv*gJ;rQeOizuQ9 z4onEl5d{`3BQ@7`8yg$5nT#g{w(VG!6;H%fN#^#`{(>aQf-8wxAut8Wm65xv@aNNu z)3Y;RkeJ2lmseC=e9^@N2MxUQcfZ@RWsBoD7(C8#+yiiL`;a1vD1yK=0Hz1P9^$(J z=@Whscn;m9;<|MIif$P6yiqREet@Khj6hK=A+QA5QDjf>HBA;s*DInEfVM2#E-fv+ z@WKlR4;k{iJMY}MVS_BwBWTdW^PrKVdyZ(E1H3f8gj`-l6!AX_qBxk6>`JN6-}i|S zNg*2-_NyXE^fexEpX+AL&Yzwng3SH&Z9++*kSeK)FUbxH7iCzr^vTDM+p0a7SpoDl z_mD$sYHI%Sm%qTCRTZe-^bxsmI1*+E(FXn~3y5MDE)t1onubBn82+S4-%2cW{ACK{Y1OLohkA59L6+q`yZ1c!;DhhK z_a5^0XtX5PbuPN-!Yi-5@`@|2!2hQ|4Tpc)Vi)fJedaUA%$w)f_J=fYJ5-Qb$&lMG zqKJbSTuw0q_MHWEM5ODniA18gxw-WXMQj##He*;GBICO@rs1x8Na?JV&N#M*3>13# z5PklFn2$bz(cYnwJ~_WPj$R9ZRElJ|Rx*{yS{d##RyLVV`T-0*kG)MQAD&5NQt3<@ zb&@q`O`_+!q6|9mKY$ZZ2U1$uV|(alcybk^@Ar1^dh9b*QC6*5xo-VBdUI6k(1D|O z?b@|t$BymWx!blK|J$}=i(MAJy|J;8Q~8GhilahFYPhF$w}>MCGtiNjxDa#NQIw#$ zxpw#Nou*}B<}$+wY{6G`_PRDqZluXgYj(E@W;}hWOoXl`k;c};3>L>#hw2k8CLIRJjG*zBX6kNxhIB_DP zY}&Nh^<0{}EL>AHu={DJopJ58*O->+xK1b(GBf4}ozLv$QI4~I{rXX(Mxh`Uh^%@b z9eM(#rvlOcyjC<2h|c_`Y4Y8!0QC?Q5z5>OJ>%TRk>eP74(y2B4L^iecgiSr~SMXMa=He zqenM2HEr3l1q?%Ck0>I$&yKx3YV)Q|?<{_&Yu{Oxr?NFb&(VPr$wqCsj*zNx#Ju#!sIycg`WMoz&@-DiU2E z?g*x0b`stRpkAW(wqu9GVUSn8a%hzddr%TVd{lAxS)iiGU_}tKnYG{trIVQ+(EZVf z&C~V;NZL-z1DUdNkX3i}r|R`W%lnwog_eglS60&N;EP&b5eFgiTHeZ)(DFKe-;WFR z%!8#WgcL2EO+}25D9VXsG7^pCVleQu$Z+Jykk!hF<8ftH8~QJ378M)NW2%MW6vAE%O;;S~JoAUkrY0smWYw{4n&kU9ZmfU-9D36&bRHM_ z3uCl4!v)8|o6wga?3m!N4iQGzKY9l#sw?HCLYUM>*pPItE}*;f7*Iq9*J)s;9)~NUh=UK9(WYr8lgY}; zO6-ER_J!LD<_%nj5n%4#e!4)HqXqgE!{M-HTX3$6gT4I(jf9yJjc8FtkUUEc*eeWj zr`On~gX=V~Q^(OEu-6W})gh#Bt`+~S4hx4ujMusaJI9u~$(K0K|Y^?gZv{TxSDa zz8H(XW7YX@xO@SotE;QiG_|a(3~k(JaigK{<%(BC5g!d8l*~RAEX%B_sv0?JRKI@x z5C}1atO77l5G5D8Js`_a;<%rmD@&zP*=%OVj-3E@`Jwz==>GDBc>2sTS&pPKf*2_q zGi8P!DoH!GOz*5BBR3a`Uko6Fn%@Z6Td;S_=lmZXsH#j4^6Ac<4I4I$95s?r9)K?C z&gTD5p}gAKT2Nj^MS0$gMRU0a-~(So5eE;5-9!<3o8SwQ0)FeLlyxt(`N%MFVTj7I zB8uR?T(+F-dP#Xw%G0D!g&c~hT1XQm!Oi$qMnl>_mi(L(QA8k%fdZEg?9m|yq>}0N z@*l0Es^%+zl?BFL?vO;6g8zF^C^H!BJaR!r6mif1VhKuuPC*Y=IgV-4i&Fd`U?=T- z7_YYNbm|-j(P7m3WCyeFChB^Ka-(Y)ALJ9#lI`fK8dGHOogqt_j9g7y%*`eIv^n~g zcl(fTTmZfy1?1y#(A3z?DfFTS80fq)MHErQ#|W}OMVgPQuE%0g!!T4u)l@)MRRyXa zdsS#VAc>4{1zMei2&5f?C0&PI)}<96o6gSdbO)&{R2r5dl_dkBYRpduUPg@SF*0c- zPXNiabFL(LqU86+Nun>x!N=#I(FMAuh=S+&Htcd}yUY=77g0nJ9}9@P6j|_n%eJ7y zIj%#OC`kPiBvFC_$leU!=D>nT1zy9R%x^;hy|IHthqRy5AA3)H;%SFWjg?e8wkYZ0 zVPhs_1vhCslB&=Hwe1nGXKZ^(ryyYEV?8D2i9$FOO{Y`K-hF4vm{CxjVf2&oiQdXZ z=>(|uf6%$S^73-F)D=<0e;6ROy(cLMIi0ub3|#&@3~A{G50wIwj$*fQN)1;q;|hhUZ?0ldEh&+9zR5scly!O)lhkJ+V%C4pWpR=4VkPb zYl2MHDXUm+LlDV=?j;*wCSqphc0LvazO1T^4fWr+=JSV+9xiw=Z+nG<{{jc6JYCm7 zd61i2Xc0yH=Kzz8$fVbl*R5^V9wL1cGVlZ4&^K+|xM;~D_HY6v&uz~*WM;IiDxP)g zGTEDMy)AB9cBKENBN|J&P#fV+38%@O@3wH>}^Vc=@|f z@mi-gm{SzzPn-}fuV~3;#ZWXbLN>dBjlLJjBhf|_JGn&=1}?a>OFiym(>>@#SVRJB zRq$m+i5iCNx$Vty?6lj@1EDf>*{%*B1d!;;71a?9bm_6ggSMtc6!CE&5HwxKkLP*~ z4fSum^A@*iL1@qwpfHHjhYX2TR>o85s)0jx*VTt&VGoSQE$4vF`w8p;w0%Jr0&?C? z0Nvx`nTz~%rX;zprK+0ixuASm&esO^c9-?yYBo1)KW3}EYe32OeNSPa82IJjFOWQ6@;utQzKAHT4s#8Gxn0b; zE}ci03_d;wZ4DK`mJ_xVFvqC4YoHH!#~u7=t#A=V6ww}}wdCeGd|buje21;9O1h%R zj$_sIuYsKu3Wq$;5oNhm!K0*%H99)v(;=jT^Y;nq*5y7<);rfB?Y<6iB z)NtySu0UE|w-JgcqKJbT^jrqLIy3|Sp4vV1y+lwzE9FV18BZje{D58sPl5FI6B!0C z`@)$l(IfiM3CYo!ec}-~89c~7kl3cv?d$kk<$LWw$h~){Xout-9H%(M1gNpxk1Yih zQA82{y`ag?ras?tAds`3B#Vw?XMNA5Z@&^3f*>Wvcf@V2XU4cA)?@TXs#1>*d9`!M zu|r5Z$3K?aOV=Uoz79;y6+YT65?v8R{Ewk+&hxYMIT8e|g$_v{r`%MHErQ z{}gf@2hhEE>}x?x4GZM*m~7K+DZ+q3HLmOFA;a~3Spq{*#6p^3*-$c`Pmc~tBDP>o z(hyNDC8jOopnY9O_;e2qyGyQqE zpn?FCKy1JCd_H3?&=y?;76gx}T)lc#azK%RUOeQF7$}VsTpm<@&f5kALUlwXa{K#& zGU`qBI4D2-!xey3B=EsKmoo~B>q9};a*w}#WlI2TO zi9VT+d?0Ur;ERV$>z7QM&B^qXX|o#}noBAwY)8~Vc>&DPcC#1hdr5hy4rorIr=q}I zM6I0uh{d3|b;c?A7UYh!qrA3*tpq}T{Nn&hU{%AOQjkqS%`rh}O<-}6nts_9X!~Vg zx#z0K4)DVAM_YebAMjmjBnn`D2GNIE-FlRHNL>XH=31R=40%~jd9>}d4{r|~W1pd; zo@jm94bPFI%Y+9D&|NY_LYBdFsJTmEFHQ5jcA{0Jy#IO7Q%3auP}rRGOR5{QPci;{ z!gmTBQ4|T}*cIi;g9n6URnd)btfVBHwlrN20*OBV43o5j!a@U&q3?~H(G?InqbI?- zC6*-n6qOM@WZRlYTRvz4F#;n>I*52E8A-^nCC1_^8;gd6684F$sT9f%2P8UwhlrR= z*eY}eFJSK*q;HH+N*v`^W{^+Liyyl7%<`o|iDX%|86*#ZFz+Sw6^wIA!m5b5%DRDW z!J#{O=oMKCvhyhq{K4ry{{kea2XV^P93OCW?#f^Gi*T)$d8#9G?L>-M)XifR>IZ&2kfnH zswk_m+`!Nc9Fw`i(h9H)F&RgpbU=O!;*qcgC=;we6Oes1h~CVOBd+9%f+`Ct1U7)a zN@x3s<)k3@76Slm;?mc{iS=-dX?e(;@~4<|^9uXyJIA;vrdMWHrSa89pOpfxf!K?L|wEsq*QB~Z~w?)frN9$oFB zr}n^%$N@SFtEGn`kOq{83K7j=hnv_)Lmfzk_##vqRFzu5k4YYCLVAu2E+8gFU}3Me z0=c0nXgVZ7H? zj^#M6@1ik~2fASZ>7{^HV@lKkBr7;T!-Zo$E%>Cqv(<(QL%$#v`VmV!`T{b5UScXX z#u@{PI#344hzW7lADGG7hG7t00fi&oI>Mw& zk(`hRnW6?94{kC4kiM`kh1a=#uKQQ z0yc0ZkO~-tSb$hjP?&5Z0%=y5)v_x4o@ZNWN%B-p0UPmmL-~RNN(GgYzD2?g2RXMz z)d|VEkPaO1gd+Q{MU+X?P()&InMhBP&_!zs!R(-CHi)bk{ecSUK17-%=x#|8-9Uws zf+|r|P%f)1%_Sl}{E&)DtOyS%6X`)ii02T)fyp@?(=ect*g|W|NWR5ti|PxJa5$5q zjM($D)GiKEJr?=#;ucwynF!2*8BQWHRu8^4O^u z{tA0Ks;RnVxn$sBhC<8{+0B}E#&!ZtEAbo!DxL~e4huT50Z53xJw~KPb}TK=Bu{KH zCc#4(8M7b=`otPCMa=`>Rb`T3#AB8u`H-HeT$GjqL{YK! zKc#>02sW0LMISnjg)o%a@d`k9;Qf=^*^fYnWla%Xtth4>IOt+Uf&dcrV`ZT~NS^Ou zFwmoP4FkPLjvdq^z9%`EW=(KZEkx%e(BDihumw~sewG+F)0X5V%uGW=gDUv3hyhlD z(nrf`;AuLRL_yNa;%OHvm+xeKH)DCAFoRAYVsxSMkw%CznPN!XhhHp&4rCf#2rZI# z4ez0@`iVNccMjmPP{aoY7k#YpuyA{nb9OST&9J3472S_fW`ik3BBjwtEE+2*E31$t z)$<)$1|dMoC~-%$jv>mQIdkU47hinVS!bPh-gy^Zc;N*XT!8H-Klw?Nm&v9z9W}#p zsyI$)`t+IKyXC9U#zK)$Dx3Yn4cC3)|6Q#+vgbm%#Oxr-6nqCv7Kj;FGzA-zMHM^^ zGsW>e7s{DyqevG@7FJ!)SL6VyYsSug`+GM}nKC(WX&DbNxuADR^cfJEOH{t(d%={k z6MlW$t+L{)u}G7fz3{3lZus)o^gs(7=#zmLSYD77=tD*-7JUb7>e~oJD_vNd;73GZ zhA$>1Y;p9vDvKdQNhVV_ef#DkkDd?B0MrS?2h*C8GiA}1Kwh%!snGL$A2Do?u1vxx z)}ivki#CJz12G#2CK$j+3|Dk~F|36X&8fFudlL$rYDlVPVEGZ1u%d-EL)Q&ShnlX) z(CZXg4@C^HvTmT}F6xazYaOBP9glVZ5D1w}`l~nHbm$R>d&!nkT?-@w`V-T#*w>?2 zxenmkWT>bhCr^|eS{G#1aU+USGHcqD@))#rj5cRO8cMpND~lN+hzIiglh1hm<$rHp zvu4kZtq8PXUFI&5L?wpwp1PALR zfDsq53X+zu+P;kOcLm!gbA$#B!w#{dZ(Y%;32G7teml4#K0;tk$Fzpvq|;dbAb?Z~Tbq4&QdJep%0N}3xUe*x zAd`-#&A5ZLU6zwp$~JAyR}D=MhxL-ulCttLBcx#RJ21obNJ%VI7L9t)spLpSd1XmS zG^E4wgcKSPXryJaXb6k7iA6h`b$tsgNG1y4i%MC5MBno|n&iV-=))G*j?n{xd7Anz8%S%h523QarDr-hK5-y8| zG)eP4B^t%CiqeWwtYS`9H00<}^QP3t_taVyjl>SZLk5BCt8|W; zM2W6s1d`?IdutnSxZ%rx{L2$jT`^4y${@rLTl%F1LP%i&JLagHe|p>UMQ=@*JYmM{ zSwH*L&*|;9suo6fmz9^4mBvDb=-JVdGE)$erh~y2vU{`1l#9hs4_A~SQbdDF2c=FF z^;oE~th6Ljiskg~yMBAs=RQ+W5eY|NNw8DU1Z+v9u-CyAS??nQlm(J*IyVdTriT-G zJ%U+UFaWXCI#6|({m=^%MJ4DnlI^C>%8IUPnq_Ach0a0Jg$Y#O zm&|nbtJhwC-+lM|^@&HHc>2+w|NK_4UMy1co8R64z@L75$FF`UtD#SxfBDmoJ^lE@ zPu=jvYhW4<9ya_3x83sBCm(+Jp$Cqgf28AJZI+EtNJSg4I(yK3bXY5{Wm?&UXJ^T7 z3{+SvW-5gR9JULc!$CcK+00m&2N7D#097P;MSksf8Tur2M+NZu9bYuP!x63 zmUUNL{nhJk{MM*db((z6D)`alq%?A(7JrVc6`h7q)@bK(5Rulm<8SR zE9+lXQ3n0av7iFepdl4Zd96G$dH&p8wcGx3*KbNZ*AS%@Yc_6Zj30jTX^%Yh>_1<5 z<@s0N{OXslligIhsZNJ!lgYR?Oax07{b*_Vx4!fJ7ytSEi+_9an#(W4YBJ%FIrlvD z=jUJj*X=*Q_46yJAP<+O{HQ)V9bi(QIsS|$z<9z9kvcYF`(04s1B^aP*?-ek>MO5 zDj77QuY~mQ+i$*c!bzVTJN|H(*fkYpnqf>HKk}Pj|LQUGj+{1Q*7=uQJa7Jq*MIp- z{rdMiZvMR0YgT{l>)$x%>`y-O;Gaee?O#z*=FtUMnO&ZNl`PtU*OG`c)lzUIG0~C^ z97zw!nuR&7fiIXOubmEC;owDG@uY4Jb=ds5fH*fy2&56XJM;vq9aSOiq z`RiW(_Y2?r&KFNU<&^DPcFHQf{F*xWV@6OKD|_v=*M9NSpMK-!TSko>Wm%3SL!~Rc zYm&g_M3yz^v>A#=2^t>|!&$|0>&%OBC+ozp=TGli@I&(>YvZoqKP5-jG z9h>X6Z;}HiX=WY0B+`G_=Rf{Lu&iNNz_|BrYXHJ}Q!FdsqSft>HdK_Z!G6GmuY$Qt@WABL4nB#_(B0Rls3>|u5)3XHoF zS<#4w=u2ZRWYJgDWMk9fH(s-BGgeu)XK$Tr+n(e!Wxbu-_Kq4huA;KKs#5#E|GW3A zH-0^kRjl^M9e3OvcmC?vcm49@Qx}N71)fS~vVlu&0FT08>_2euEGSNg9Wi>$D39zZ zxQ6~B{vvh|LaVTAUKuaYL9Y`mI=t>Uw zQ1R8k^|x%=@ZQR$u}HLTPvhndyGzTeo8s{e8#XwWHEZ_NjMJ1#*Hu?ni9yLfo_*`^ zBW4=9lQpeGOMFoO>Y+8&cmDp~o4)r$EdpaU9B*n^_~skn?tudaR#w3t4@aXBY(Whu zGr#J5i~z?pB;sQxjJxpMv!D6%eLHs4`m&A@vK<@M>nJ49<6zf{s-*h=_}6n!zxw{} z`es2?H~;gw<*)vG)22;`f`y&Og#iLKwA0Ojml6WgkpfduQi4`iKG15ZTlBA|L#n)f z`>utrzH#iyXR6@}3k#1Zc@PcH3mc*FlP317DZAwd-@E#YSFhW$0SkRti)?y-o#qGS zWtDm~W;#|lrq}eVkrZ0RP$C2+clNP}j~fu4{UzQK3mPKXuXh8#Zq|;rQeJ{O5;e&pG7J4?JX=>=ql* z28YraFS^IUnKo_m_1Asz`s;6)J!`h>@T(mbU8q&7YpRE5Q}GhruZ)Vele7fi^q{2) zv1o}TODWgN299mpfgKoHB$aU-RebgBH&0x!;N;^@xajh(9>e9>i}Ub$jZ?}1w^ofr!V%rI6M zvnZ4q?*A~52M(-3CYbHIuGiPsMItd|+Me=qr!xuxM(fwFUs+ih2u@M35)=6CFq=1T zrfQLmObNXJYFu{Mu#txzdSoOTJ7K{wfJjVr9eCV#M2io zUEbhZ7oL0GL%+Sp&{bCpPCjA&z_Rk`Go}t2F*KgY_Ny5@U`YP~gR732H$T;4Enc_INqNc1{v*w|P{_^m{e_pd@tzm@t4PVe5YidRwb@aS&SUCRJ!w2=N zcIQHK5V2BiZ;|YfZ}J&OB>k|I%On;5$xP|I0pk_VX{j5|ZrG&pYFh zho5+VSMzbl&YL!7IM$WXqsDD-%9ivWG;7L;LDiwss;XV}^~W4NZ_J2sSRc1;+3nJE zoupP0_py_Z`*sygkzRKoU0ON-z5TxfHUf0f7CfVA>=wGN!6!o7O)9N7wa}S1L6j>h zN+43%Y_`0-s-d9)hLY!d^!yeL5g($?^ zW9Nhk6Q@p}s%hG@e|u)h;uX4K#47Y{JGQ2iHWa(^vav zgp3X7P-q>$e(q_m~B5lkH@#-gQ*jyQ7m>^V~h4;pmGuYVJ7aa_+o@8VM)f9$c^J@G9Y z)?RS#*+WK+hUNACdmA=x* zaw{$lF*{SBn^ksg-?eh(ssV!sPnkBkUsYAz-klpZtXsHfNoje%xihCB|$4gD))b7xI!Ntw%+ zuc)uB9W`=9P0fIX3*T{Fx?vy>Cg#%SCl2)_EKROhq4yM89y+g`hgAUb{9!=Y)jP? zO_gEZnx>7aLZ@(T2RWlXX{aE+5Tr7&nte$Og(FZ*95?HFHfD7+9PtGulgUP-QO|{C zZJ|pfE$Tt5G~*sv%W)O8L@~-oj~;sUmFIrxOJ8-xFxsZ8zN{IrT@_!5>V_a2Y12%m zn+;7y4P%iiMXJQI@xs6FKj*wNEmKt_#Yx8%I#qzU;XpPl)3Pno&^2@|Liw2lRD&d= zw`ZQvHFWdtftZ9;QFMh!w@?`&1G*=Lu#)m@41uw2i`~yeC-_<=7{e{dlI(ddhRJnJ zo`6DGwv0{{?3h`Lea(`tlB2_5TVIP6NA<@=76)?xc9SSBM`3_vCWB_bM&(R~cmOQ=BSd`CS9y3XzO1d*P; z=xyX8TETgS1RGlO5Gl1lfTv9O_Up>^NwKC97zWgaqIkY>^%Ymg|Db=$Qd@CEXC^vGd1efjgB|J)ZGsKuHVcn+%IBWtV{ zbpIpe;5Zi62~a9pIeF5YV~;y#+=PK&`21%AU)A)mLoXU}>DoN?GnNV&yHK$aj#i+l zn5D>%-T94bwxj(nfK&&N^4RkdSmeN5I(1#E?DE>e4-b0Dv@A25g{6`gCq$tWc9t0m zf$}ioc~ElXK^IbKB*3UN9F$PbrFAf-0$nzu#!*x~t47zO}8+thkJ=jW5SYk@ioyl1K={OZZ&-Vjd2y^x3L3CCc6`&Ub zu=+4-n~orNl!OTEzGWE3f(A|wM4zS_sMY1K1fYu~>}(D?g!Dd1QlSD9Ns}%^bq8O% zbQhNxfX4$@km(E*T@+DMI|WdJP(@nTz6RyJ(d z;Kv?+v~F*mrfYOlGqhhtrRmO=3#3IlK0t-wgbxq3x@R01!ib-EDV%{F@7EVT-5Efc*FdX#Q4*G&_OTq!V#^FmUTSt%s zJ#c|WIsx6XB(hquF{j?cI*2|+CeRhp$)wXk$7C-lqHd;%M&)+qsA9bDc#C=l>P6WX z(Fd?@#(cq0Lyv&Xq(UtK5K1H6t((a2Tswu|~42@aSX2)BaE32xJ9R#U$LSUrY zv^-uIwmj2)0b%5|;c>W3AS4$~oJ2GM4-W8K0I3!r6-Hp}SWZ4r4#_jhfr^GTo2bv0 z1DL)P1Q90oAaSBBStcxdo*{zxJ4K)Y@`g}U{PPsVlkj1-K+8i`au8-lm5pXQEIWax=YHcr?9^BL5rAw)NsqQV9rz5QTbp^ zdTLGz3{lVm!6B8JY6I>>2Z^w)V1`2>grcGA$b>Xasw==oj+#b6tWgEXH?$W(4hKrh z10bXYGC(}erG=VFWm4y3=&*((CUiX)O9c)ih}7y%z?KU9lETO;PmxKhr#B?Z=zl@P zSYQd%=^8C{wCl?j;?rYe7&)p8dv^qNn}_sBDtoeuYEno*k2-?NNXDolkP0dWwd@=S zr*vF;dkIvdh`s{jK%GoRn5c(B7$OiKu?kK7E_)vX*Mngj3De6wpes(FI>UCH{{8!t zO+hz9aRLEylt;4ET2fa<779vh93Iww%!!Y%WWp%r0;KR$HjYffLGLd?6zF&K6_ufiBJPa9K6-IolXD*q!fg;%0rPtx0hdoK5 zzIAO`v=JgG{EQo~9%+PKg4MBLI&=@@2|+5NZ@~OkFk~b;7#rTzjQ#lGE&(y?f%2j{ z_9e@zD(x3zSE1v?BVDVTK_k zJHvp8NU*QgfWy58>on@g{SM+dHqdmNCk7hk2xNfy1z06);7RjER74{nI%1PtQ3LQ> zC`&lbcM%E|nk8qeWgxlqGAI=~vJ_zLaoI>{)T=ly`JR$SW>`&V0mT48`x7Nua8=)g ziVfut%||>a49MG)Wg@}W^Mai0P$H`u522cHe=9ofcLS0^(n)& ziJ*0kub{lwNpP5_6Chd-lotc#iE^IuYWnwg97~cQJv2;(86!PrBb_*RoQ8%5%d)sc za^xZv0Mnda(-hLedf27qG>3d-@{pg7cmm8lI>iG&Zx7qTwuRV&?{EOsap{T&YC%ng z^i!Mw?LkbI4Z4TIkQ)`3n_78vTFHGuSs-%jmH;0%G~rl5IgpPFGG`AispO}!88dQQ zj3?rZ)ebCKL5_J)CKNwcf3}wcJai$N(QzTj4DS%s9fV|3<@0Ey}_WB>^~K+;I|GFEx$br^MD)_qZtM4PQ7JQk!; zQ3M0A1362tGk_cjnk#BPeY_Mlwyg$cz|I0A3UWiXbV@>mc8*1WxRi?8hw=cXu5#q0 z9UJcJz8@(97@EmLZ-8MbUfu=J_YeklyRR%u_`}5KXGkz^gj~FRfHCQb@(cybp<~;V zrcH%-GRlLR4@0jbB^nxbGIVP_J8iBxf z=!+MwZQIZRahx4tD>)mlJorEp6@s8BCD_=zo0tjNX zX?*^-!3GFg9)tuE5X7QUbT?K_x)j+hAPPNdd9?OAwlihw6i~*1{sXL>mKTsR&W4E% zF>RZho9pZA;fG9f35F~poJ%Bu4=eMttNsqO!bl|2MtM}F+}P(m09Irq;_GT_amXLC z+&b+^b>cqAC!Hzdsty)>@lS0MYbq10J67RA=S>U?zgfI`4X z-r&bHApS&T5*VgB%LQ@-a-(sl3%?Lc$S~rw0${a*#^}^{;9^CT=&}_b?gE> zTNF_ioyCQrz!qSRHu_@{j9=82dD_bE1|+V%#=d7Q{)fQ^n^qxTh3Q}zkfz*`E`UMl zp7P|d4AGP!1pNmL#PCINDTe1uC5Nd7;HY?0M82o14{$r3Mqp8 zkXZ+7ftGqI8(JP)R|!;VPFC8$CSN=4ibbI4FnqYrb79re<0ce607tv19Muasvg%Q6 zM1&)Q5W-Bh2`>gEvfo|+>3bcwuRvvbz0z}Z!rGl8mve93fovoL4KW$4U^zOeryGXv zxj68 z)o3)DTj$~J1t@YaqyG1U`k9^Uz|5!DT*7WJLIq|)=fDVJ+vQCvVY(kU zumgYAv{`=O!LW55$Ct@GAnx$}OeTZ18vF_sZ|~l{jC68>*b0(xc3K&wF{O;&I2*vO z!2#q@R#t|vd=g%v4)Ew@!n_%6c_TU9HN`zp2iOxQi9|wEv{*ETmg5kXM92pgaZDZh zOabWu#L<+5nYYMPrZ%^$aaTa(yl%Vy0ZpP0<|pdXg<-od4i3YXgQOup*7T}sF&qhF za0|wr9&k)&GB||5_OjFg$c+7h&qTp-P180*^f05WL@MK^mr3rajLE8|)3pjx&s9Yz zbzQHnd2>lgD3H|p`lgy#1R5v!ERbXyHn8X0W-1m5)2dFlh35p$@!U`-g!&*jZCaQe zV*U;P)L9U5a`cxwkIdut24KuQxAp*3rFeO_Bd{ncikYQ{og$$KEj?WWquG;|N4H)I zffo$y-_IAkNVL=ebudArfs#P0WRs>+soL6F2q2e1?r87&mqdpK|Qb2nGlJz3i2Lv^?54ratHgfJw>so=FX=n}*Fa!l2db|uH z6$*v1<%ewBG0iLlBUcFowkFvJoRCPM94C9&QHTEa?%!H1@hz)1X57+gN1k%uJ-@P( zo7b*gCCKa%Nnf>6mHn!RFIoPtw-!G)aNxMNUww7ivZcGWZ7D5@1(Fshp)Y*l^Os(9 z!OJiGQ^D#jt7JG}ipWYR8ft86qNgpfOZOSzmtOM+r@~Pbx+ffKE8V|GmygM)fR>q4 z<+^n&Zg0WNlOo!I3kmrI`Z70-b=Lq_VB3|JCzTj_NjMUVgeZVAZPP4p7-9;t!!~!h zZ6BZxILZc|ZE3V9@6JFa`l6h)oMbASj3?9axZs)@JJpzMXlZVQ`UbttbseaasZ_kF zxjEk093Qf;2$qvaH+_LX5@elCERZL(K?)&>)-%9v7rGkRTB#A&z79+Occz z*6q8eOq!qvrsrkHOrBEL)Ua*K){O1fCsPgarg$<*_gB%Xo>nCDg@3;hs~ooYtv6)B zZAm0|*X~Iqla`suB${FFrk$X^DP33F+}v23$;Nl=sQtrz51)7DX=ZbM*0h^aW?fx< zV_jXUx!$$1zGHc|>(hr$@JILG(29;aaZ>Eb74acKa=;|VH0eeWCK4YIQp6X-uBUlH zX*di`fe9McR-c~jVgv?lAGAuZ?QWGpgrjW0w(XXd790Z45HgPKWF6atT8CvZA3qP+ z1##2)+P8oB+q>?6`MHIrjA9WkJd|rWTxd{NLYre&dGq3zsh+J7ScZ z%D%UL-5KYewR+R0RsVV+6K_C6U=N|bFem$X-Jpp51Bi-F(AtE7op})G19yUp;}{eO zv?Qgo*;EEDlgg%&8LWw^tdpUK0imih%?dhK?cVsZm7B+nn>1ulX*imlKDTDm<_#OS z#6NxQH`cA&wr#`CmtJ{Aj=6R5b%LOI8FRrI=Or7rO&mM6vNZOq-~4v_mTjw7FF)gq z1tHlqLgCZT`}BJo*KFCgY1NV?QzwkL@!Pi@dH9^0Z~NK%OJ4PLF!@iUJBMQi9Og3dLVtkDR3O0y*|S2(Sh`f_%Pr^gtbG1BpLZPo_s(^l27MAU?1`e z?pSIWHGoLjirg8YA`m|)vtW@>#=Zb&z^0! zeD52VoG|}{Q%)&~m5W%3efnG^)XU!AB2dJB2a{MbymR{i$r}lhrjQiHlktE3>!r2p z-e0?J_1d*-*R5NJ?S&U!NDFQ5u014|GM2k~&1PRx#!nnKebVp&vC!)G)+SByrI+5A za@66GVMBabJ?^+;s>&jQP$vamT|-NwCxk;KCmeVD(TB}C_tJ|d&N-~MzCNr=u9JQ7 z&9|q{IlZK8_`-#6oPNp)zx&;tE7mst__`}+j2Ts3GvMZHKXvA57tNVCe$wRe-~IMC zUDJ+*Ly9QUN7-b0??A5|R6$Y(dkKo#hv@$UAXQqyhGYl}=ZBuhWL&V*G*g$>-pl)a{aE`Z+UC&`er49 zzET85^$o?>+3DsYK4x@~CG0|w=#D5%aY=sjtv6P#d~eyZmCG2mZr!?L`%XWgNA&21 zbUM|G@ zdC(aTdJ|n6AV=M}o&Z~xKc+=M?mSJdFb1N%4oft04g#>As;b}r{`ZbO_PFEb zk2_()_(`w5_G;jJSl@C{+XMOdfslwdT4u8zmK=}HkX&%VB{c*4mG&Rw7ofF?#g$xBm5_ zrs>I4(s4~FWmYO%U*7^Of&7s@X{m-T%8DMCYnHsWZr$dqzj)Ib zpE&=-1q)`)nh}b?Dhbm!c_bkki5iC9+-$w|_S(^tW}b8TMMoYzW89F^GAX-d&5CV% z>(0LH>I=^Q)VXJ#d-$Pq`t>g(LJb7jP;I(*o(iO=iFnyeP3WB~V*db=1vznD$8id7 zq#_|BH3rgw2y|wQ?!NROOJ!wcm6a86<>lq2rKQl**&Rc$J0#zytMHoV#RPZlhE4jA zks~Kf-MnUnV5Tyuv}-ws&YAOt&s{ZiU}vtWmjETczkPZR?($Exvf>S?7)#I%LzD6}z`@dEw>PB{g*R$tMi1Dqp*1*{XGG zw(P8vMd|Q4GpA3P^}t`BU%G7FIj7G*_0$E^XH9+fZ_hS1rZgjr>Vl|AKv1E!YW8r; z54(XX=kFQx7u;@!o9ON+zIWqBVvQ4XIG;w$i8jrBW-KbnRwI zQw1ezV|~hIO2QE+2C`&mdPE7NL{nYHX$WK?q7Nu79pKq<%Sno{fZp$JYxHI(c8e~S zTJT?MwL3xE0j%8xPqcKIfOQM~6!t`qpj(mqav25dN4^S$$@1082eMm{dkrL`iIUsv z7Wu`mmwCsj$-qg9?FHYe)rY-2@<95G_P2fHLB$j}ey$z3uYU@fx> z_U86-%%OtO>H%~gf6m(@&_C#%UPq_+eW(fV|6Zf_+4c<(5}3EyY&H^(#7bh&^zvf1 zFEBQ$LNB9hYHaX3xfNLuCxkQ~l;=92yv9@pl;$vu9mRZ+k&}V*R8FqV=qua zavaZ<%7hz^@)bo=LFu!20iP|N42aq5^=upA1s>#0V2x$-Is~7fMIUH6!&$fcNf|=%P zFx62bWJ?bSQTbgCNxK8A-rU<|0@nVVkMeHwcMCMGn=JPM)w>miCFJuc2<+n(X;M;h z-fmIY%=VS&95lFW&{;xJH#B%cp^(Sk2+tuYG7OYtB7rKiXdS9fqt!ZC6oo6W*mxqn zLQ!;l&6iafcB^CwsX(_uoQkX=9J$$wpRp`0FhF?_7#KxllS1oPG+7aRJ1c_Y$lAm> zs|LgiLKZjzszh(>QC%yD>W1yu^v*IvOQsqP$u%_1a}|1V3!PMAZ^=gQQ3tY0@|yO5 zp1Y0%nf2-Ei$2gJL$76(&?jkSlG2CFdq#omp_#txM@wRnaM*SnCN`Y|lB3YK#)1a+ z^u^NUOBfUJW3&+`8M-G)X~&&B{A^N$Fu7^E^$aH{A*4G~~L_wxAdf*4phDoN)V_dVK%_S3F_@^ZhO zf-)znV>{jRM{6u}A^+_i=-PZP+rlwsJxRz1;)h;)*;+~uKwZ(`UI;TE`g|$W^99xD z6p(w^d5jKdkjhHRp!F40lSYGOEYL*_k5qVU+0i!OD6NQ8(RM~IKyN|uNq*pG4?_5= zqSEYO4_32Plj><(Rwx{j0>xpJ$5&`xdB|jr+^|D)iquk89GencO8KMWduHAIx3G+JlG0M>Em&_0CLD>f{L@E`CnUj2Owuwd3b5dTf`3)0;RU2 zyh1IniyGy!g5bAii*4>$XW-?c8+lbbt;W6(N!M=m7v!H$o)5&2$NHS__6X{?Ud$C9 zgO`F0wYb}6GQg}*!71!Kgv8D*0BxywX87mgXFDzgqTqNA?7>G=vyk#g{OA%XD2!1a zWC?zi-k48X9{j{)EZnwjPI<0vx%47_vLRUIvA()Ys*$0HJ}acWTXyQke%}wh8<+BVbq{gh>ObR*)nV0|7;bEG_|NtfCU-@z#+2 zLrK_+X}bfHKKfx-CpqAux9H{fJ0MqCHgath-Unc;f}-2FfZjddbsFT!wORbKzpl|b zLb=(}OVIa@S`)G@M~52a4q=7ip56fU>Fe#;y%zpJqi-8QC_wP^n+s)<+E!b#GPswI zPDdav1-F}^AX0%n?nPQ2@D>wIRC zzyS}Wgy}vIO2{ANj5{zL$yaVmXHoDA4{uv{pyNCan>`#<9WKh9Ixe(GfZS0Xl(LWG zcTS=BJm|G++!X}3i$Q3u4LX8X1YOgmqZm1~)xA%k7O*n$n+rngcrCD{uI@|D=oS+F zKDb^2G6IX01{$48m#K1Ky@gK9IrtF+(tshLUThE6y*wE^Wd_IIx~w5D$b?IA1|NOh$j9?p;O z9To?_TyjW=N!5lz!M1d4Uq{`CKBdSUyt~+o2(TzXOTiRnWww^a(fSMUya66Yt@df+ zu(TA6qq***8ez+0<~*z`a-f5Jhqn07#UMqRU&6_uz{AI@J@SY1Xbqt};4g^4_wp`> zb~}9mkpde4_S;tF+=%4C!~s3uvFiH`)agLmguy=DUqU^}I+Oa9{qo~DNk;S<0*?wm zpF99RLBPILAc<=(o4h}tBbQo)(zX>i&Z^4U4FMDZtU(`~=4(5-Tnsu24;hYV2+NoP zSdMghI7b#NK8YXWcE}vHoP{F^&xA`H2A9Pm&V?RJHDLrxb)d;bd;5aksE7Q;fb4e; zRs%Y@O(n7ud&r!MBp)#$DS!}r#-yx7N<)=kHDCoYVL~hD7XkE!8mcxePW%{hB0fX} zpFZ+UkH#^QmFaXjc_>RyR9tRYi>fH;fvh`<;>q+WOi#j5*ln^etAV5hlA7zo918sa z%97d8B3E=Ry}1PCu-ft#?6ts~p=%bIQs2nI39}+fF zIW?Ol=E&8bLfeJsY6RqRX%Dmj<)V98i84)iDmZtH#27XX#+Je`09=NkN3i3pICd%l zwI|gQzZ6Dg^5g6XcmlaD7Q}=cCHY9 zCT0|pOGfSRF+7}iu}cS7^Vk&2rKV6y%4Zj;$t)aOYCo?J&wz3-aIBYDX5?5OwL4s} zcK|@SQcscyu}Y!>XaSuCqbY~_u#uo<<{R5b@Zrt@e%8XAKaWB`heo&4Yv>eNfm~z$ zk{RO#o}wzKs%2WXhlz_fAtj4X?obfi&;k%-r5{J^D%q6ne`9#HkL@2fVwI}cq$ck-#KOkY=| z0-gkfVh*R!)xqUSig4E8M#@-XM-oaln6 z&_t158SO}cqXs_8q7G!!G4D_+Fo{{bps;u5DsmWK~8rA%F_|CU7d7ku+6O>C&Dp ziWWV_tJCB`Ll8|syL1)uq{(!F1${)V!v>2UBu`US1Hwz+N=5^ifQf-igM)tYeA{u* zq3rAo4LqGZq-6?H#BNcR%~sZ<6C>zv2s=ic_zyX?_8}$3ZWll-`alOfjI!aUD|?g* zen=|h9lNgLqgGf{=~-Wrr9f5{Lskvc#S2^-H;_A(ids-%G_R>tj4ApVbCx=vtq>R+ zlH5GUfmwVJ#ve7AF-!p{ew*uX@WTW7$yjtmEa$Q#DuSX|t|=)}xFqC?jz=fx5DR6a zo}N!1-KTqqdD`AXt_G6`k{x)}0|#Yo+h~2@3@Z~nnD!7)v=rbc{{VzIj+0C!R6uoKWL#R3qYPxpelbmJ2_5?^|`1YHne*EHy+6^~ve!1jI7#lLU) zuIG3V95HKq*c5-QuR%?c^dmJy0N zo}XxLi6@c~df1sR2;{OQPcIWg=;*o} z#3tSnPp4DaY!>o^4TLI@NJ7jIA05mFP;_iNn@wZ&Gr}S0ys{RuvZ=rYvmr-JQ{<@H zn6jeM(y+IrB(keM0RlE?k@H*-lz`c;Se6-h7CpK~U-IK8w!ym)B9cj&-mXm4$cB^% zjJ|b714r3{Um(@Z@g^%{S!u^MGtsC4{v?KzF$0l=%mw;5IEflrE5w%6bF@lf%SRs` z`auzNh>jLGMtQUhQ#dF9zw8b*TB2$7z?_7rQHRjS+rW6p%JbFcmUKMPluoypsF`Pn zv>0_+t~|<_6^EXLW~`>YZ5Ai>{}?EJr{%wd*E#E-aTx6B{12; z>d%w|4r&5Z7f^Zb=qTw5WUU_Xbr~dgmv9eusA7-rbE&wf~Lwk1tFcT=?VyC z*r;*e`R>gnx~O1$>BXa}hSbz3Hf6A`yPEGRzy8%PD$0$pp^1u^34+J|_IJ&dB-6J| z3r!-bWve`77rGMD7zC^)pd9)_pzmQ$(xnV`i5A2Q4M^}!-^~mdIOtbDzg@6`xihA| z@XTM%I_20*OVW2$R|+38Z^3Wwy?55^nJ%>yxR0<0n4(%yTPOt^58> zH&#Ss&vbTgul>J!es}l(-H}Mv(KoM2n^u`rv9a$7SOTxU_PU|NhFkH5GDG)8jp-EB zwQP#C0j!5c!CJt|@$+B*eCf)i%U3O@cSkX|bm@{si{5$WnZJPnA#bFl+4ihylW+aj z*9Z2mHf`ThO6+j;_1Ay-tOZADqD9LSwOS0EkY{Rt{p(*^5_?CC9rgETpRFzlD>SpA zjmeJd9Cpa;%PzYJt1?CaQo-sWC>kVG_OYgBJt(L?ED718D}Q8IpbH=uUCSsw5}*OQ_1(U<4Zq4Y(1 z^aOgA^g!Mvxk<>!jNgw2nc*{!5>hZ4NTd$#Q$$Y}eFK?@qUmB4FztlteeU`j-+uj_ zmCM>k_V+uRLRUX%afbA)T3&d}=Gb9Md5dhGh)vimCpXN0b%S2NDdU2&yR*Z(2Zz z1*vEvML5)v>4HoVMCSV$ydo;@&QU;paxBab-jur_zp5%Y8%s+Mg?s5ok;ID(ON z{Fauc=9cDk3d@h5OePu|8=IS2EZfC$lS(HWn;L2x8tUrn&6Wl^z{;*CEU&(9Z(Z%) zcq&s`UPd}u;3Sf%`uc`seY2Cbu^^{2abyeaAeqXPM5C~A95+krayV2|T^5rgLdx1* zyQ`rQ8P#EHX3|*9Q|W9|Q&VF@Lpp1kj?>)KP*=OFxvAE(O|0`RnCSJ5b+z^J_+BwE zp{taZRR*pCD-#koV)(HB)#VVhRK^}TdUSPVWstQX8wu0e-5js4uT3;HKr+I5?>4`gRUmgF3TK^+@8a^&R6lVh?<{)bjW^*(504%_deWpxQKpgurKP3QXG|Y6b_^**4A2V4j2%0C z_;9|<0mW_N#EE0ajx~%B?UqI_{eM?H{mk>{o^twx(c|YGH7}7&uUfTg<;s*-~8jOo}kZZ}CtlIX5c1+p|^_=sYCjvY-+@w%qu z?&kW2L=&B3u-vNBaNv{1cE>Kk?^TN(v2FkCP2Dl7UOb;Qw&7QK7y{A12P?TnxN z;FcYGciW!b(9%?2+Z=C9x@1*Al)Sq7#!@n%JE97##oc70tP3P_|gt}noh+S}M%+nlh> zj22jA$O?4UqolgxN4MVksnbtA>-3W@yYw<}Lvu3K(%gV~XZr#K8*`_jsVKHv5 z&vtUrYa!_t;B@c?))+ z(gXMX;kjp?{mKnDR#sO2?l*TVTD6m%*AV!)R&Lq=VWmC3op$48bc;KLgi{5(f<$tbNwR*|oMQ0v=MBut-Ty*9A4?nhe z;oE1Nc546r1D}2NA1hbA_w-XwR+N{=Q^_Cy;+LydEnD&4%10l(x20t-6cpQ)WF;(z z2ef$Q&1ru?O*EaY8#ZQmy1Bur-CZ3CyOw#)7q3~f_>JYuS3LXN^XQqdsyzGT6OQi= z88Py?=bwN3&DRz$eedlz-#+og1(0E^kf9J%UD)cX$?nu0IB?+CzV@{nZ@lr!E3f?W zm%lu0*s!Tnr(SZ&C4c(U{nuW5{eAb{f8KfLLl-{r#1qdy|ANxevdb^O9MLYi=%Vw^ zI}aRp!U-q*;upU>z##f zE?xKOtG}`G-Nmbxt-AN2yZhIKom4|u(|t!MD~;Uu$3L~CO$hE~7hU|`vUk?6Ui7W+ zd>iXrOEP}SnPfM#gm%Z?>*YCgcmz7~{?h!})>Q}cbFsU7P-f5?P;Y(i*Y@wpG><@qZ19aP0UU_Bs zkl~K${^}P$d-nNfS1gApEx+xX*Vk{`)M$yvo_g-`l`EF4T=|1<--?;=#cRK~V&$T@ zm%n||i3`leIxmwD70*^Of?*17x?$IzY+Pw<@COeWeeb>Z{OkFDy#28e#%UG=$p?tftAiWSd3@nA(nh+FQE$+K51gWb0B zcX#}vp?0sPg;p$kch!o;OO`EOaO^RH=Lqzoj(|=?6*xAs9~@l7RH*NMMh&u>ZAX6g?m0NR~ohS+7;8>xkZRHdiYo2s51wh5|%e z7y;N4;|Z`jjmnDt<+13OZ@B)qci(fy*`Ijsg?|j}SN*GB-FebUXZGtiprX9=?KfYa zeZ;(}GY_41%)GL)(n*si-~NNI9e4E6a}SyJ_*0LLnK(`km7K8Pl)4?;hYzUv<_%vy zY|i0BhYlYzcGUatuQ=nhv;Y0dE1DWIG=uXs)ME6446B*WeJgkT<~P%4&HB~PetO19 z$3>%&;UmYkG$$^);JmlqcCaZ~@{<7P}BuPW{l zN6e*<2e|^BEE2=DO>tNyC!TVmWo3>z>M$%qn>TJSQ)yW1cl`R-gQrX@8Qi}v-hATx z`F1L6XEScrF~TL1rr!F!Z_k)G;?~=KaQtz{LA_HT9CY^5%~+-{DTZM{m4o7W_0?D3 ze*5j&YJ?|tv)dGn4z2nRGZC`b3)a}W6I4}bUr=yJ}SId|Uq z+wXtx``2B2{j{l5M~xaadGe%@BS&0+{g-aL?S~5&E<~z|ii+8@XTR~r8%Tv!YS5rT z2pKnK#DLNgMHY-mIBEGqhmKJddZHfoCY`V3U+DxymkcAW@b>~B24PnWoInROD0x5)#_7%d{TaLPA49>@pO7WHJ9WMFu9)*pTrjZ{4-Ww%sY?Cyp6d z**~H*H8#s77613gKi7<$K5+cl`o{Q-851J9V5QP!;c%v<#V~XwT7LMv`DdJb{Md#+0X~Nh;X3l`N?84}RA}YFjcJFXtn%6WpLa~wbk05J{2_w|UwrPVBZl=KHhf5V%>Zb1=bd);4WGZ}kV6jr^PeA@ICJ)n zts75XaNK~wL%;Ri+osN#UJ;T)vUKGYSDthJdEffMFUCxsbJUUZ7A;(;(Iv0K0cu5O zVSNG8Lqa?)fTC{0X(}`X>#?U_{K+qV`-}g(XTtE2Ru-!l-J%Swj9pXuAVqS@>nl;V zfkYM+pzj0mfE-X6Sl)E4HPGFpvu4S%4QtmLC8a}0jQi%dez3c?{u|%=(u|o?fe}t4Es%two?+T2P@xunMUcVz{WdkMj+N-ax+p<;E!vlv8`1Dm*Y~53L+Z}gJ zn>(kXqO7j2_O(~vtlN_g>6LW9vzO*K&10@&>g=s+Y)&OMZrt#%7oNl7Tw7bWZu1UB z)3WL2cNe|0ZTn6w9Ep~c{@-19?`le%bIGS>O`8g9`zJsB`QEMTmMve~f9wcRG$jpl z)llV#>Si)~)@)e2D(jUUb>xXdDyy2~$z2&oDXqwu<~P53!_HMJ5y{n=dg1v2H8tsUdhhN%VNH?HRkoSQWI$_vAcK`_YHE%?`sh3ExZ|r| z{VIql7K?&(VB>%X!3$frZh;xg*AgI+NTgCJ=!0jTc_vim^73-*rc!Af+O>1n<}F+M z^{eSWV8Hh6JFp7FvO^ExP&gbOFkrw17hHf+KKt3Lrc9Zt>qd1=e>d48yJ;9u?Cmsk zZd(!*dQ4U{*?YjSnj;WG*m~Loqm2>I%M0xmIEbw%wwPJR_b>hAIqTkebKSaa4h#@g zh82b^$do0pwC#cH>B1~P%N7gj08;h*^=sDFw4$bRAlbmQ>ViTeCb&msq8jUU|Ktv0jpcQ%*l~-KxdA zHmtqik}GSf%96hBwP3f9ab`)-QZF z>&lK3Sax92NpROrJ19cc)PX~XeD{_gZQH%$x*M;aIAx+^dbPE+Pd)XxE(@v@G;H4- z7@xpXn8w!E_DnSVULW7p0HAAh!H&;UR1o14??)~!pnv@|v~ zy|ZL-6V?V@T}$6s$kbF;4eA$Kxomk;)*m3Lea1uk!89zLpQ9*^o?GFy|Y`BB|}!-tY!Po#*OQK{N1n4nK=5eDYMQz z`OHO&-Z4TEBWxHE&kIr&mHjKrhxo4Sx~?8%pi!vM=*p{I*Ee(>v9xg1h(!ZQrh8DJ zP9R-bIqa5`PFOH?c)!CZ4Exlj7hZb#WdjEf88~{(qzS{etyvq0VJIBXpaav_j zY}2M)yBqCejy|phytsaiFKa2sJMGM~CQTfBMYI0WMWg8^0Y-FM&p#V>yG)1Uqn7VE$N{ck$s+zLsO z?ba`i0I5{+kw+f+w3MA`$c><)NS1A@`+VpV$>Z_(bI(18QhxNK z+pfL#noXNF?yhZ0XIv@J(kU|>QMc{b;Mz7j=?2Pk>FN%+PmnxjeUmMUo(AhsrK#Gi zN^O$Ffxu)_)58zm-@m%%3)fz!M`K1bmd&J9RV!f1PJm-vmU5B|ur|@d>dY_tK}6TB zbbQP99rI5;=e!Fqv056}u32;Lc^4je)SQ#fy`bO3na{npZ0}y!o3rOHj5$ZnJNC0*xw&-6nEUSeZF55d3c)fEh2+Vqplgr4ymaJ{ zQL`tHo;<$dcX!atWasfV;=G8>J>F1+xQ>o=|)F?`skE<9uV#tm5bwGfsc zDDNU{BTdz0ERVJmHX^nwl$3^FeDT$B<0c$3b=>q}{qFkh9f@>$(jg};S-N7;J8zz_ z;5e+>Z0Pqvcf-36y2!w1_l;p?vOx!>v4&*)uYb5F-B5q+jbAeZ(R6&e+T@dt*P5cw z;KJ1^V(hvv^TU((cLFkf1iGRH1;eteB-1ny?%4F+CsYI`cS#tQrYjh9rO9a69561VD>q(q;hOiC z)F%_Ezz762mB@Gw-OA`G8uSP=kz}_X$j~&W&75({i3?^-9ye>+gaOs%E%Erqt=lF} znY7^KQ-)1A*7IVhx(YeC zJK~tbrc4k*QVMFEulbH(TJdDIIhDaoQRsO)C{C~&9oNu9l8jY??jT0*L2;|9s)E>V z*|G(G-t9w&4xKbXEVFUOJk&zsV-mqcARZSZ;dKCO? zRLC|h zbWTh24%1KiqL;NyOi~xVAW%bcBpO!eEv=#v3HeyPVo^P0pbI_G_vp4Uy4aX^V7Fh~ z`rY!7a@nV@)Jv*Tp6Swk)38D43L)K+Q{dSBCq&rjE8lez$pqM+i4w^YrD_9Y+!ws8 z;+xA>t$TlOsy=DGyYThEH5(dhcWhieq%wTy)N#`$k14OHFe2qy#Yov$-5{q{bxcUM z)Q+2e$gnZv`&WccI_9w9g9kZ|*U+4fl~o^g^l?WWHLt3yA{s)=N{0=pDKV5So3?!N z*qJkDOdCID+}P2xYbuA?rtNxmG@?~jL~ClQMi1_P)U+wprLo<6c1)Tv>+s`G9y@Ku zxJhFNYf^Iarcl{{!P5>?%gawX`_w@bMmc`Ap|P%_tYqZisw_~9qapEPb1Y^8{sP`vDkr+;F~ z>_di+8#7?|C_#&q8Ksp9xw2F#SSVR2> z4tVOBfBg8zzaCIs5%~1zITV==qnR71UZYTK;9#dh?%Cbzk}IjUtnIZ@e}3@KQap9z z=dW|a*2J-3vY7D08lH)o6H1B%B z;2}e9z4Zskg|j}E@#)j2lZURJIvz|rQG~sjN;YMzkShr3ruskr{tsWi{+h?0cnZ-T zxbM%8J@!;xZJpx^Aw6tml1=dhBz@!hwby^?`+t4r8DzV2+xE9!e+^6P-=2P|q%`)> z0;y*OO0e-?jbe zhaUHQ&9xKFjkSU3HYej?uSh7iXZMbOJontj&D%<&WvOI5nMu6%@;~P;tY;&R+(pFp7h-Ja`&8FrCD3ll_+jbLK+ty2b7>jO@%)~{yECLNqUc7km#EBE3 ze>si=t?l;Pf7Q^?0Nv`7g!3>|x7_kQw3?%`vf_#>u875AAUm+$qD70Kv%=23@PZ4& zk?`+-e=pc=_3DZ-oee2b8CQh01rR%?( zJ3xoTapT9slT&z^Y$8yR<%UKeE+o=B_SPC9{oS|TJo}_$et-A>HOG^$z5aS*!(LZ( zp}^X{P!cOKQwhP%zWeSwp^)*&V~_iey<^L|7ypiKdw0;}xj*>U7qTg9{nCY7cJE1> z*599c;)dIP*0O2C376k+_T|?<`M1BKWHX)q%9p;hYV|5zm&z;3uDa^#Bab=)7230B z&(D7T^M!A}y>;8x@7{d#)z^Fxk$?8RTmJp>i=X}cwGaRC0gJB5)V;rSQ8=RS-o0b# zs^xb+@o-af-IC4kFMoSUOS0wHcl`SLuio(Z6Hg%^M%M@6kU!{J57%{Oy_Ne*UXpSCo}M`d6yho3Fp|o7-=%-MNQ8CFD7EJGRv~ z)|n75StU6)Gkf;#%$SZY%1{6GiANuO?4r|8TfK7SE3dp+5{;>fkj5`hN zWf0p9u<&1T`Q?AT|2}3q*k8K(^Jg4$`b8I64c9?brz9}61-m^y@ zg$a`f{&XE&x3rTzLL1@vlUOILzPkEGjXp(DUt;u?kq2^-Xora3l~#O;ZFb?O;t5 zLpC@w-iY~w`GT1o3CBDi+DF#RLXd=LI3|lqD$@kwRuma(x-5lKNxP}3E)s=iXAKxI z$a6H)GLxysit@6oZKCd`mGwPZ$W-Vo64@AllZxwfi;|#*qGq7jfoNMP*d~>+Qc=+y zQGn$2FROxzW;^MU%CeMc3YJqAir9e2Tqp}2uL>ucGV6UfOFql>q zR!~`K3GBwSIeg@}fi*Q|vMHiNFx|SHTUxB#@(6_vnitd@$FZhPopR=xXWw_&&x&c%%8X#KVcpwrY*fg^UG2OsbwQOzN zPo+vKL*ep>kyJ7TB974M0}nMZLIy;_bG>Mk^h8+P`OybZPwZl! z9+2=n*olx63gFf6Aek(_sw$x4TW+~^&YU@Pi+5g@1kte^FzGnW+rLdCTs;oR7#Afs>-fpLbH#AqfJdM;c%396bcF(Is^vlsTz)9 zxy)p3$Ff3d5HSo@Gcu`+kWGfdk*ug$fn>!S!n)@Ac1?9nDx1~~h?dyc1hqZQSc9Gz zLO-CT$QeaIjnx9by1IO?nKm&wy%OI{|Lwuwef7&aW8wE!5t! z98IGeqm!x3|7Y(l;Or{S{_%VC+WKbW?nVN^LIMPLhvF`6DHWg;s0$UKNO^%$q(CVx z6nCdMfh5F`5Rwqr_3Ov~-|x)1ckga?BZVLI{eRwPXV0B8^2{^OJoC&mbLPx}P2u^z z25W`;rnnyyH8L>iLqBjVz8Z(wwfKf0e3%A8?jbZtjNu59XKPAS)4^XLDQJ`7jhlw3SDbS0*bVmLS_iug>#vM)RD1}BA8ifuq#_o#F#3sY6C!>q0Oo8><;5y}EwYU&kA@{^5@iFO zL{v^n7|697VrNI>y9WktP!%A;J^#=|e1F0V6qg1o!&pxjlRefMebR->5(s(eQX<8l zA#k$u-(Zv}6z+f& z<%wkkW_3N)t+*bG>^?t!i1p$_0D`kBjCL(}o$1R_OMkb=XUMy`rh zU{yN`Vn}CTZ6HQHPO2c!>|d zG^mA0K%eH5lZxTlv5G|W>@$wK=kB{;GzSWdGH7GUJ?P}Y%glyZ97yGh5nLT5%^`Ll znu+f}pfpGzWl|JZRu^2s0LeGObJUg-7HDm@B3KkQfEX^g>dK@5u9q<}+MdObsUS=2 z{@|lf_CBaajN{_`1SCd3LLhk$0|Q-1c*$2us(>#|ZpFWsNU{2>>Jj@IjQs3Q$a01}}V(P!y=kwW_ZJRP-eF zC~^SxbznwtX0U{^wJ zQ3GfvA*1vQ5ZnlXRLPve0|yVq7!?ywIK{#~%0nyjQ9SgWOO?v4QYfF&2vgFJ#C-P3 zylz5qMZ_3R_iq zvH<{sTjBMKL8!LC7}AZQ5>ljcP^AW>EJ;S;r&vRp79w1yPN#5t5kq80BSY};PjnOm z3Lo-Ig@yclQ&vb17{eo0SRDpZV=_db6@@Uba1QuuAG&Ky&xWq7oK#Z@~d*XkS>7?Q~_C$WnB?{ zT_A)?G7KE^xZhKuTywwx<>Dk7DHD`uIPNhN4b4Ca@CX}^?=7K~q43e%qQwz~Kw3rI zqDXe?m~cp(G9&-P78Mf6#)IqtA0q^x_`<&|k-8SMX2*_kyGqRVY#x6i8(cIWM;7|o zoah$9%O8ZJlZav<7JRCJ_HZSIh!%Z{EGRmrV?GFp*wroM16LMS1o*||3`q&J;RO!y zD?s38LWZEH@xz%&k9&v-*oFScLy*WTNGyjUpGih&zH%!7uf@<9E`dxpq_0N@id zP#SJZL7>n$q=}3`9SUQJS%UOK?VzuS8&Q%7Bo(qb!y85xeZ`#Y72NGig$^XhODPn^ z(1}FAEK;%<4*B9%6eAq_OPE>|F1#|Q{4L%UL7*3oF@nSrRUseD`DRdpf( zrW6=Uft@RH+yx>wbg0m$;*BK)iZLh*7Pkn-kFN0(MSMh}a}5nCMKHY`!1Ow=Oo|ln z3m2xADda`oD(JaC@Qb?jky5p(q6&$S(b~t|2O1 zkfG{P0~NxBc&YM`jRH*+l2im?!X*qnKp=)?whoYSYD^(U`-G;IpooB6ELey+SPY^_ z8)pzq3Tz@d8&>d{#jz}=houG~R$O83QSlL{@CbhgP^}6@1Q5uOg2tnC$U~r=5cWV^ zNomQ6KnWax*@@^CE(Cdl2&4zVh$}%cz8pdvtQAcM22q|=54^Q$>|$D{!$5(3i>iW0 zbfG2l-vek<*y9nyS263+VYE^nWL5EF1k`#V*M-*WhITXyngh{do<~Qq;&cb7q@|B| zh#Sw@;jUO_f+7opIUL*0pghxvgXP><%;t7!xYNXv zEenry02akUct^5?RVBn2891}q41gr`p&SBkOM(bL0zoTKz|R7Rm_emnfRbON@*PdV zD99ReSf?Q@X%G$>CHKC3K#6EBaeN2p)N~)t*SP0EO#Q-CUjl%SVA21JDhM9ScBP-( z5*G@D2u8z7KU+Y^is=6$Jz~R5f;8E33@FBjjE;7TIULMw@kY(F+O zgo)UYloBs65Pn|Q9@IbNo;BwdI)2Bs&bJ_A`}D?LD5J0I)Idv zIT0lCfq3XsB&F`ALx1bQ0BoXI-~ve+*XhN6OBxfREJ=SkP6;HfgHz#!c+j^+2KEFn zh#DLN3?qmTzs$%CqHKY%M9$X@e2T(@S%opq1y<;7FMRNSE-{fzYrqgf+SF#zi* zQsP%oNRx^j5j{u@0wNO&VkSvONR|BkaslOWgRlZQNBjDU7`?f|AQ(>)zXU*=Y!@Q3 zV5{JX7jD^CdjugBi>Aii^tfF+u<*!bA+izyxwAh?qgZT@l>*3pQb7 z2o*WS7x8QvrlkanCZzn)Iv}OI;9vOZWd+3z2Y(0$6dNfGnZy)fLn9T-2aq0K=|?PO zg^?^*2ph97Wtg!O03quHf;p&$PS}Bh7G@Flhj>!L$vTI6R$pcVWz_e@9!U`Sglb@K z!>x28Gz8>EoF0I;8uTmFhY@jL@xhW7CCcRj0wakuy#0R!MH{Ds#*!bua_}R74)FvD z%;fpfu(x^OH9IHgne3|~DGWUyQz8UGk9Pp;K_Dw-aiS2iRsP_@5dI^Hys-MABjc$A z02~WBhlNDS95CMy!=`}M$Xy8t1VJc>C;%XqH&Sr%L+S`p_+=c6EIMMv4}@9LDXu+$ zKv4qV1yW)c#KSLdWqB-D6d-S@n*kkH{6pm7K@8~@m7u08ItlOyIs9?~_|Tjfv3L$B z3U&Fl15DF>m7^L<{BmG(M6xn$n{Gfb2Vj_n88yWs054&v2-kEj7-4#a+c4LE3Lrvk zP2eV%@R1=dYzH(oqyd8x3?kjo;~ZW!-!OFOyu58g=kjbORRcX3BseP#1%X6`|J{KI zFH1loIK4n&RHhnVI2D4%BV@R#l{$!NK`OkApj`1?UT!1hI*U+WojD;epiyZ-DuJT} zm_wm1LelBbX&g1M(SbCGppQCoW-m+|=HgC7{F4(Qogjj*b47GiT2sUTfMQ_mpae}d zOj8amWEv!xGg}%O1wUeQSinri*L;|JsG99KIW9h-`ADcx)^OVl%mogxc8X;cWMEG~ z&WMf;#)3Q<2#{Qb5RpA0uLwwuiesYXI9A5CayIJWMOCpw8H^H2MTtaBBLUM@(>?iJ zaK~|6c>+}t&~^qt5kNsL0!ZOADFo*8+)G#lQX@b^@gM{(3T&FrU7uoO0~sWS6>yv9 zYKl5BOgLQRAc%Cbx=_+8O2>^{f(R3eI5tqgM@--VoX359jOqylNtDcOge_we&?y1Z zvpK&);CKca*qTZq&@w!fpKrJe$^UXd>t$fPhk@kv?pHbpo^pmF5iM9R#jdzxg%RAg zlFRehcdKCK^92czm28%;ILBf!hy~JwE%Ki_c5yY5&ZKK%3CMcEbv$$gHVPL;*t7U5 zLL6Nt-QF05?E8U(nwV-jldVry@gWwM5=9@B)!hat*G~}2R4NsVaVsX@+!h->$p&!1 z^H5{1I}5IWCh$sJ$)DD?R-}wYqn6_!Lx`>nT$c+v5dH2*>xNjA@}(aHAE?n>!OOH} zf`a3Exn!k*is@o)yRD@)Sy932u*ZW&U=BrM%Yat1a(OfYw7qRRtY8li@=D;$W^vD{2pK+;bx>t?QE& zvF6t1L?Vg2QpHGA(12)G+`@xfcmP5ncpg7-%ibk)F3lUnb2UWR`$*)uK`b7Fw#??T zww*_V136#h6+8HlOGpDvBykH69$bn6L?}KnF2=%AvJhk)P<4nLrAq**=mChXqpYn1 zvxw`qg5cS{%rsz54{4Y=@2HT-4ITrHD_UfGa}S_Yy|Ron}CfND4QPykA_BF zw#3k$0Q6Xv^_>eZeB_Zw9((N3C!Tyvx+kA{{K+Su_}9N4Xm4+aWay!W_|F|!P~WHb zH_y8uD7bFkrd7qa@r9m|6MTTD`>y)qpZuhoBMr0KyK3mO?jx3nP1i@=RL+CGSQ?jNI{0 zH{bm96Hi@w@pqI++H(u3O#X_?ulUVXS7kC8l!~@yQqiwAugK;A!8rA_QwIzf07fM% zlCsZi0iZ_G>FgChzWn|N{(kR$_ug~g-S^yg&)xUk{kQw?{l|m(|- zGtW9TnT%UjUObRRI$ePQ%5EuAmxI6|0c1e7vbmgX*#dKyqzVj(%P+sYp;s^NQQu4_ zb^#$5(z~r7`LI=B+l1b2YWFV(D7ToWQ5g4lt-H`2xiK**2*-SQ_ zN+TRnm4h(0w!(VCV2cF#Tpm$vu!~w-v-tvNVhZ2*Yinz3X>0RUW$5ssal?c(LDpJY zT3g%NY}-OtfjOBu^92hf z=CYagHkO6#j%}forlw{fMQ6Y;p3S721hl6z5M`KYqeqSM0@sM@g9h~vA2)vd1at%1HCDd8t(7mkx2M1=-86pw^It-y)9vjWHmpSvJovt~4c0Kk9h^iO zp;N&{@vQl4Itae1uHpP|etW~p_G_=Y{-FK$+Gn3#VNyKuuZK5m+&E_RXfTBGj&#M2 zCk2C|AnPE0OSjUYyRTcj_RqK6GGO2!Fquz)nFgtg8H$c$JUql1j2Sg%?6|QzOxmFY zV8ys`<1CBslS!5Vk!KZ#59zn-F1uv1PTtZcO`bM+^5k5mxjnTB!qU>*l4{Rj;^Nre z#2qFeFErP0fBRdmEGsZ1GtHu9A(egl_T$%@G8tq-h>$1;*E3E(-Hb*v*&K#D+sY%V z89389F5QW)Veo5Dk$(Mp@4WNmNs}fH8#WXI0LEle+2*G9=BBo6rhw74tu@`;(h8Bo z0DyMJJg5cG+M0v?n#&IxGI;v*X)TZk%ZA8FcA$?yEcwZR#>Sz;hMCbAQrd+)&roP- zLGPe^(irt%5hDoVR47>JN-d0U&SbMFm+b5S!L`tZAS%&0RSysvY$9#w*|L++C2$K) zBo5`GC>;vl|8UX!S*9PgtY}Mn?%F^6X6S(4xxB?CZe$|;%pd-A2SQf)%e0*VAsBR= zfM0q=G zHJiTl$KU_+UvGZnoi`A8<%OrZ?Q7d2@!?bUp7Y+!*{{EP-8EM`mYpwT6ivPG+ZQeP zVD@uQKQ(>&K8dQjv(7o~=KuM_Q;$6`W%9U!)dm(hnyq1o&a>aQ7t}sOhCcl8U+=y5 z&mS&W`1BKx9<=99P+`ZN_N_nNddCxwKYGv+N7VHna?juISup?I2kyTknJ`*%)P#3S<@a6~0#*Lp;tLMGk>TwhM&sp%{`}3Bce8y!jzxu|U zxgXs6*P9f>_Wg|SrOcQgO(rkA@OxH!&Wyy4JMOeObLYPC)|=ls?_49@>U;L|BaeCD z#h2zST=?+)_YSCxpY)AWPCMuP7oK?Fk^ApxE~tYh>@|1p-1ld`{JSg9bz4_dV#@A0 zmg=;7Zhile?FDV!hPL4Y2bf-=xuyNW%dU9!%~$5mf9L!QzL`l|5C7xtS#Q5MXUo-~_n?9I{p*1b z=FNTXx#vezS4Z008y#=#jD6>PFlW{quRZb1BQ*_mftS#N_yy;m`@y`~&%gNCjD7by z^}Gw-ocY1~bLRfyr&J-MMkM?6@q@#Zetq1d$3zg{J4C_PRG-eD1-wKK|*AcT5}@uP&@N#Nh%I zBbMf=P+XhoJ?J}r2?D7CHyY)87m!{~0=Qm*Sn;e6^%se0pMyJM;etvYx2%q=GQCCU zC?*&reehSHVrpR z`7|w@Kri^-4&%nY`s#~^A9MUuPd<6zzSA)&>D_<0qL{z_)vp$QxajQjzjOcn_wPMp z_fJ2YfA~=c_3c0CmfP>zd*9;^J?xNiqX$pfVGKB{tA?gTW6@-5Ym4jU_uXd?yWmWl zwy*DMt5>WEY$vAbPd)MU@!vRY_x<-m*}LqxbE~Ir^xl zpML6q{SJsY9%kGeKD?licLL?>JP3aD(1BG+&4@dJ;kT!A1Nx6dq05$kZaF-%0lA88 zPZ^=)VCKkeK)kYrDWjpk}tA%itDF?H8HPCD_#lTSV8dq23mwW+CJpK3I~d-E5bcJ6nk&p2e! zM;}j{y5l?Vzq?@Jf*)Rd(G@@ZLH|J`Fa62S_up^-L-*OMS7r3@gJw8RPLG;-jQEN^ zaM!%==z$Fl2OM-@TOoJOIcJ^vjc@$(?|=L5cfb4k8?PUAWKZ+I`RI-~9HuLkIR5GHCGQ&%g1Hhn~FXq6=Ps<0U7sUC2OH?N5L9lc%43 z{D8v`z3=aTPYxOETUkes{QCF5zu@$9FF5C$_y6nR-(CAB!;Bw#$f0}eI{Dl)j{E*a z-_F~PVOC!B{fiGhr9I>od3G#N7pG#$D*8;y>AQ2=|T00!btv}yMa3_=4T z%eLq{Iwac+$rc=QPyv-Y6z3^M5JWM`MwCKBWgO<$eGfhT&&OW4?H~8=G-go5wc_zO z#!0aiNucQtSV3{6)+*l0s^Ch=77@5F&WSoL@R2TF>7_?vk$^Z%xWbzo=@lxoTx5SE#P4@f~OW{P~|Q zUYtx+j~_Sc+TUOM=9{yRKIYs#r%zkEX8rfS_oH`Td;G;0UhF?$sQ3^#Od8b>I8q=pG^ z>&i7tAARhJmbM%$l#NX(!_^F5)dIC(!6uEk8qd%8x(GWBS@_XrEz2`+3>+b*ol4wzVI3!jUh&c>mmY-r051t~K#q zg>)_%PgM7>TCbrefl1E{`JmmTYEm0`NzHYoO#~2|8md$bKiX@+q7xGkinBj z4xBUVy?;FP%pu2~H+J|aC)FJB?8Y{v&R7vQ1IG6o6tM~$KA9J!3oktX+UH9aZnWDD z+IL2(sde6mi#}VIe)Y}eib~{Tb4wO4X=?Z0|KQWQx;}rt8cwV;Ib;Ym+N7RIJ1XP_azdH%J;xl;1cPpZ% zy=l_{Q>Ug^tzNWjHH^AkF3Yu2S*;S9?x56ViV&6p?FLuImo5teJp&Pv{LXlb3Kgss zW49L3d_CgDkr0#Oh_+6n&ph?qbt~5=j966DYAPxd$rw+}Hg!9f z-ned!5j9Q2#8{KfW(-YRw|31Re*McGc9^)+?t2`0+;Q_4E~u@pi1>NvXD1T$ZWt6d zD_!3}iB2|+ADB;pVI~X%HU#FgsHWxcu&}6s+IpJ7y&JE;J?HeZPC00wUH6+d>il!g zzTjKm-f`ziJ5D`t{MZSbn%guZ;o6q#z|OEu-D{{ztbkHXxqI%tkDJ=Ke$8q#*()Cy z2Oo0i-cxru;rL_6PuXqWqNSBJHEpdeb~@`hg;>l_R`641Ak5{_;$4*2|+SuWZPQStlzlb5yzc++NnyW zeet42M;&+EUNfeja{5_gr%ikI?OBDK?OUF1n$3-^0S|3()2SS$HSOspGp2!Eo)WP< zd(S=hJoV&LZu-+bqlWGL$OC`NqoplZtOLiO$SN!255D~7^xgM7c=|4fOda=+e?4ea zRYWUl@>bBdcf+ZN9sKM+?tA;C7Y{r38+`^2LQ9^1_Su(Sa_JKH8jf z&2_iVU(&wcKKo#7yZ-)%Mo-@1fPMGaf3Mx|y6bLJj~Irc8wP|iW*Cq#{I<5WrdwMv z4&_~bR=mD^f%y;|M^{a z-jPVeVNjD#MRtO*CEiLuK;Hg00tAiwc|4CV>OuHoo^C8%{@Fu!+&ZGZ`s}mLFGMie ziyNwm0ov!MyP4%b0BO*12bijH`ipsQX$gD_fOPpB8q3o#VJQPM##=)(3kA9G?5ERh zuJ2iv=ev<~CN*g2ps7=*dY+rjWITtP(V%^N+mG0u&m)dq&x|Zww_)m(aVo5ZbZVb{ z_T6>o$w9WIwzg`weGZIO*6`IoC-7|U5z!22(X67|AI$ma+ZX;cl{c5HSarokXRKWD z`P%ljtgq>sQ44+NVt9yX@tAG9zFmmHD2`~$H?G}v-#x~T9d9>h;)~#F7vSD3a zZT-ZtBW>5_an)ubs>gH=R2j>I8LGlyG-7cxS>y3&4h2?^#zj)c`uYxnf9=h;YetM7 zI%cQlP1*BLIXT<9fzOE}dGc}JILYz34i`~PeiI90DYrLeDc|{O+O}i!CFKT4k znkVcwW0UQ+IGGuH?>(^3ASjM?O>5S)t?xUe?+z0uBu&^8@d5n@Dz24nZ&|i_{mBRJ z?I}(s)#}(eO)<2fqBW-_2M!rHY|!1e|8erTq2nh^_~mbYIdSj3MhzVvv#oh^<{W#> zkzh)FT~&K~=7r~8{?4gK9C^gipMSpO{L@dYGh^9Iy4`8_l16o}{#BLrR(sk_<+Xg! z$24;5myH}dp<&dHAFo|LZSN@~$4wfNta|CCSEi01nQLnf+BQrcW=!94;EPW^V@7-L zf7oe3U}T%u#SF`=@IU?Rlka@z!i}362M-#8=7P>Z@BNQd!Pf?$mJUM=t)zk$u`u%p z{MZKDfAZh242&yhA9Dygm94~`Ky^5ULvj^^GlsMd1;5Q81x^-9?a5E|!_zUeb_38k z=s&Q*Fo8PhgcHY)n>c=~aN{O&yBSnolz)Y67WBkpoEVuEwXupS&(7a{`&|Qv4S!?S zJMYeW=Q}^RFjf(Dpb^ZdsmCIGDiXoyw`}R+@BQ?5Gv|Hq-rNP}pLgE8c?$~p>_6`N zN2ZXQ{qEbd-h21zKm4MhPlX$Js#b*>*H$Kf@rz$a&C0jld1mRd1*aT$$|)y*!;BjW zhHN#e20E-fZXm$;fU03o<#D!JTid3~F8Thq&imHuA1;4(&f?S0IQOO-Z`^yvuAj_) z_n!Oie&wYXqlt=$rkS{hX4DW z_uqc``8n?{R55m#QCE*E(F)8IVN_}f6YPveg18=YHC0W5sAw*ick))1X261*GiMHF zg0R2-_P4*?d+)uw@4g%8^u$5%x88c&uwldQzWcA_yMTIe5Ip9m#~*+EiWMtn&6@SX z3ojt$U3cAa^)PqeCxu~K3TS4edDHg-kr(q0YQ+A$6eQjc>-~mHg)Q(neRb?UV6zT_uhNY_;KUz z|HlKEfUCM@>fmZufx`^?=38z$>afGP3~ENX?4oiS%y&x4pd?@@0!TLBz9)|SrKEup z-ZQzcMO7oFuKawNS5PcVU9+J%mW;po*2{JEHBUYIyr20d;gsem%Tdo^I_x0d5#)4wBbYh3>?_|)fZptT~|M#f4}!; z&u(mPJ@vHH-h1=S4;Ll<3f8ZZ`&Di_nd2cWM?4v*b^O-At`m>cQKfms}>ydKi z?2lf3^PSP-#(p?=?ykG+`tr<$Cw}8pEut%)mCv?x$n;WXx4Rq`qO#moSMtEz4g``t?jwjX3l(f&b(j#@)r+1_|K*DKX~TJ z$3OY#H)*%sT65Wo>N*u>SLqGEGT@fABK}M!d(Aa}*mvKKW%Y8H zJb9=3`g$HV>qOdJO>rIFPE}P``hn&KN-ouI*;%wsB2ft|DxKSuOvZi3tgfnSZ{En0 zAQE+$g%xrw71cG(?d_F%tZz-d?N})%D|WF&s_J8AG*W2G#e;;RRVFK{b8aS;$)wu3 z@3*qTtgoxd<}9~$ zuegd^@DeqNL~UYy%ch#TD&6+d*-T|^gQ>=Xywld6uIt+yW=kQHLYL;o1S{|Ap-l~g z4uP2DBJ`^{2p+Lk;J3H5JK0<>RHLRUn{#yCfLZGKzOL()$z(c}hQXCgBr>@y)O2M< z1!oniR##t#aU+}0L-LBVYJdj`L|%;tR`Y0LNx2f?r=IZxDnJZE5RUBfirdy!?&lza zG64O3`}UO>a0R(AsQExFZRwWIy#uhzYxo7C_Ea*NZQ4-ZtJZg;xqLp=zNxlX zwPRa-2K3LQEsXIIzu<7)AnNf1TLZ*{Y|FN@xojequpPTsZCzVyYs672;z`fX8r2m! zXmiI?Qf;s%lvu2yvetJZR;D!)DO6O|8)nkgBKblNl;=}9MN?oAt9Ghy-vK$b5)*`U z>$=LS>TJ%gOvZKJF?J=Z<20Zd_ zvlR%zQXZPnHM|6vXm0yCiQ5aMrbp|F(U8+xw0WTV8efs7DucH0?Oas#^93iUsF(FZ zgi1MriAR0MT?Ctv2!jlRXk%j|I+T2TC(8n$TxDb|PNqlv9d_C+l}lGv^`!Ecm`hA7 zmw%Z|#>!iecc3duy#kxXbKPOXhqbo0C1a+CnWq^GTuc#Q%vlx51g1B69!|~iJMb0A zff*R6}+BAYsPhstK{+IcbJz73_$f47rRsc@Jpcl$P?3mhQPXl9bU~oOybo;2**OSmTrpvEs|h3J z6x@gxkHrnw@?EgsR3i%P@|^7+bi`plzT(mnXK%gkh9_QpKD_CGujn9n7^Id{z;sgu zTO2Y05ol&u#h&A$!iuJOwi}I_XjU%Zsan*4#$cU@5;-Arog{_NjnIS$$`$O&sw%GE z3Z_#)sq)BdnG^*{599}aSSaO7mQc;OMW9g4LO;T8^Id*j#HfftYw6JfNKx{-?&S-% zA9zsKx@x4`+Uu%oP;LMX2tzcQ&=eKwF0Ls#$5KqwwQW5T7-*b`>svM?%uK{nxk6OK zIBK@!(usJ&fJRdkOrFgcr%txx#G*0JO8ZWRpJO*FUG8qTt12rX*N|sa4&#mE*zqVc zMC?eiGTD~RU~sTBCx9wURvLy`u-u5M2k0VR!4Djd=KvYeWYo2-m=O;w9+QaHaa=2r zsIVNx0fBzr)Qz0&SH?}4gUP62pfd%E6HyC3=6T>v5QU8AQ{asmtqu(ICXoEUOyxnf z6a|=1Q88|!ds>-vB=Dk@F^s>C${B;k*Dk5`AWpc2zJp)n>I7R+d4uB#tun4A5(9<~ z%cQc^HPr_CKXG+IMA~F9*^GiI!%V}wA}~zi?14mts?7(QY_sE~N^lo+=qQb9jI z`law#exT&sO2(ix_96%l6SH=#BH!l$i(Dp!AqdzxsSoC<396(OrRq zj0GZKM-LGgnN8*d4@E!bdM59AXbvbB6o9?3T&UK$@kW#dS>wWkcpLDs4vF_ zDiNSj17D+sBgx_(8rX`k+JFT4(bUOgGTPk>6<^Ik@Q^erG5~1dut{A=!w`fDeu75) zf+2kHEFj=Si6X)=@eGuzgp$dFMo=^vSR!fK3Qe3o$ow_qcviS znYyEID=KeTO|_DUW_@qe*zws+uC}UL-Bv! zls<7!gluEc@G=;lqR2~J1Q8(aD23=$sH&7f@R4YdLa-DGapl3E5+zhDmm`^pDak3Z z79~q$5X33OFR}sz@$gc)OAduAS2B-KlMH3Iq0oyz3N=0DOZs0e(DV`>!A3&yw-baF z+fE<@*ntUTVyTHX14>~Ju{}hEcuQ2{7A_QO`e}P|0OAx$Q+Ng<0);9Rd6+=}B5dIvLK1f zFT0iSpw1j!;TOb}CRTtB{G}G-*erhd&#fKgJjwoFr1H9es9+}m31Z$Uy<3MZt2{Ld z+nt}V%ym=L7XXlkW)UI@b0MtU?!OI-H72ZxD(nF3(Oqdb{p&oQHb(b6nl~_wop8gcxgcll3M8g}%ym)I` z)B!@rJ_*tDU=pLHJk1N>s3ehw_6ah=Qbc~tJTYM;FNlp-;3zo`3?*RZ5YXLG6;Jc? z5zlo4BT!BDC)Ex#3kfBil2}3NmjH$jAxdJDBr^g2%X<%^q%LDh z>N_Tr=~!dglDsF#aJCD?udIg){LmnwzGFzSNErtWNx#HK)xkRvDZ(WO$OJedr{oG@ z5+M7Ayb)L6kx~}k;{q|FWlArvGO@Umm(cMY7@&iXKs?gd*}oZpCVB12$z)$Wl-EtV zB9wW*0C3nTZh%J{e3|tW187C4HMfN^%)1;0dv84&8(z zsQa`C2k{hpN7JlTvcn7EhWL!587FPsV6n?~H z5im?#B8e!j60v(G^nX3biV5x3xsGId=>S}04R?YH2< z99u5E1LS~A$A%YD)wPr`WoKYVDjzhvb79i|e}QUQPCjeJqA~Ig0kXq%&!z1JunZ&B ze+VH7_}La>WHJs;#nd8%H$u^r8on4^gs{FKRmLC>q%$-U#B@d2Y+bXJpsYjz-6v!y z{^3MHoaQi_BoIK`j8VeW;KZcZix5v+k9rIyAy31Ux{p_&C;`!hUI=;Te(oU`ruKZw z@^@f^lcLoHkWNmmw&1$U_w_;mBmbwQf3vGuyD+haOJ50gWP>fIhYY8=@n2TLB#aqXb%0 z4*byUWD)Vm!aAH_KxZx>SX@a!Iq;b&#e`^i0hxmNxTP=jmK?Ckz|J57#qz!=o^@p) zh8~tEiIUb17c(%LQQ5%$K@w)cSQmj^BsjwYnG6|lA5`=<}KtW2F28cOq2$e~MU?L(h-ty#rt}PQKFd&pTh>^gm2`$Uc+s!&Ia`|F8 zok*eYxb7pKr))2THNubdiCO`GoI7v00z}&A1d*guRFc(`PSCu~4p@Y}K{*g5711-U zYhvMKDIz(Xgz#2g#q(Sl8-_q?$b7i4S^|S`WnP&|He3mT@Z(3+7cn9MpHkB_Dse-s z!a<-q98fKr|dXhhVvEJ_N(VIag?! zAQAePc&;e2baGn)bUdvp7W0jWqbR-l^tQOMh{wANoy8K%9k5X-L@P@vL|b#kU3^83 z{g#SKJQwvmRnuJ!b19fBoR5WuBy1P4uY^UH9P`kyq!!>0gYbhKP{+0(M58)O;iRsl z8$=3{L}dk)h54GUsh%r7pch0;Lw6mUTLz0_Eiy>;Dl*e%56hFbt%wm-;tkj>X!W7C zcqKfRda<~lZwGefN&-gKpT+cl{<7yskJ*Ck*R1N-4N{+rWB}1437aLRm|!7 z9`_GBe1|L%PdK)tp^l<-W+~>~ngf4SO^f*$m~2_TRS!G;D!qJj`uo=V>mPZ&yIIQ-Cg;N%NY zkjOp)A!avV4MKJaK_PP>h?G?kju`Tjw?qzA2}Q{LV(CoAjK*BgOJ~{@4I0%|G&7=b z|2=ArjL`Rnc*oi2=kD=~()>-Wo8nN_T9j|+Qd@#|u4Eq@#D_Xy%{9=7sIDNY*BQ_# zU;aVx5jE#n*-WO8Nu$CsQ@0AXt{H_q#y;0HOw>*~fq7dTaoR3)iKd&-czNgvuvOF> zfN?8hT|W(ozq$6!Hv04U!EcdbNHoU1Hy340L{%{#YW;F;5if#g`Xu6 z>I_Our-?yjhOXgqgn`Ja{5l-MFccC!ixDCvTt_nr-4R9$Zf*e(Pvx=APGH+I%Ksd| zBI4dg$1a7RZ35X8;f(}hpbCTVcoCf+@7L8-DrM?uNik;vL&52=2w{`4Gs%z+hd`*E za+TMmEM-7#tsm7a#UD3uhg2q0S6OXnn&)r>eV9Z5nn8s$iTypu4~abS++ z>iRY8zt^6xKKiilKmcRVCThfnI%17kS4gQ5`0goZ9rVg8FEp-obFQJp^|>8O@RRpnUcYvQk*x3o*f24^p~8`g(;&7W_Z4+5G(g8Q^wPe(a;lIQ z&CGs}#-`$eGUXJb3kozIT<8J7hY@)1z4zLOshhVscl1iuA z)9JL4i0!(|E=k?MXqvU1w)Rvum2zwgQ}03{n@(r)IexZf@9BFb5+-?uO2o|l58S6V zTB+MXTYGCJpJ{1rYj10J3I%kkoK;9?((Uc3JS+;=Ln&>oO_@})@7mDB*+QYE9kDI> zY;zE?6BWs6)Aj;eYisLf?6c>T9e0T7n(KJ&nf#S;YJkb>!UDcU*DWk1)r+`h(yTmDQ)7d7iE% zUw;18BMv!uhlyig@!fdiO^IY;=bd+!U&Glx;1Cx$f%5BL|Ef=2uUvaZ=cEIw2F3zM z-!33!3D(_Sd+v4MLHiwi$blX1&;t)VX#aec9~+a&@B=%#|FBVYefrIw_1-&gy*hT> z@FNdCD5=I^lcG)A+S+i%1O-H-Qz_iGrCRe24D)Eg_EN35Ys_U^eem4(F%R(b7Kn-{ znw8J{mhF394w9J3Wl|YGfRC2zN`d!VVYxeFtU&{O#TBM>b@vks#XPsC8w%dfa{(0~D6 zE@!|lr@aMIkP3>6L)7+?1#!}0R_Us$nFj4g*VluHmC5U-fk7*5B3dQVhxDO3l)C?= z7hl?W%FgI}vg@Mb9ew06Kl|lRG5Zux6z~&OjEV{4CLFNWq{01%%z6Lg=bwM#yz?*I zXT|}`m#@9;&wp9=`Df=}aQ47~1BMSD6HipU^yI_$|NZZFyw|AlJOAd&OEPw@*>l_1 ztkU^7fz4>;&?n zAyVSxZU`97Z84_yD-d_FgO*4&$Jxn;(_ zdwu_V-*4Qs@v+AqdF=7Wjy(ME)6YCRnM}-_IrEW+A8BlA)Ocvq=JhKFIicBlFWrva zAz&(TZUtp`2nAoeQ_`^3N|qfn7J(MnwvzRq0NY*(G~a^-4cijxDCVaA{nGP;h7JGj z&#t}oS68$&H3e!ER<#GpDIlZ=|7Ak6O`y^scLUYIbQ0#jk2y3ficTmx#xIma0R@O# z-s}pPy6dz(r@>9wVL~ygsDHW879BZ!?4DD1f8n|3=gj-)h@+3q=d+hxcG;4}pYO59 z-idf}=bd+oC(PUL{re3!{?FNGo)T4qx;}${`kUY1dB<(H{?CnTSFad4Y`Ch&r%#_= zTb;c0``>%_?U_68I&DDzA^YyPS3Isg`p84eKVPnC{Q4OTD22xdaE|A|Xp3kw_CN6R z6)XR6?H`vc{^Y>@_r!F0{DfVG4I6<8(W+Iek2&F_ciwsDiXZ;K&1VlfaKF0xJ}Xkpg>bJlB)$Y6RFnZ)b%Z15eVybQGm7AJjWqNz=H9cR*PTg&1JDXj-bXf#^Q}tQ1 z-o5s^Yp?j_&-xA-GGW5lY+GuVopuB>W0f_#?7G{hA1%24n%{l8@(Ydi>k_}~Uzabfb9vE;f9?fv?XG~-F6$z(E{pXRiU03`*h{m*~-^XqTVy!XC; zjvhQDu=A*kYD6~|O-PF`7jgxl6SDgXSCTQ0FWVHQO2st9;__oldm)qU-M4S1;CQNW z<~irS{L(8IUve=r9&+#@C!caM8uw>Ex#I74+_GxP#|{1aoqGCNx8HEvop<~->jx*C zdR8H44<9^WQ14pLc74YfIdoXBno3^@4n6EhXy3p7<<@vb)y;R_b;oUgzT=i#o_hAV z(c{MMxBosry6gv!JpAAe6DA&a^znm-4S(eENB{8K-@W|o^O;nds+kY1M91wBsAE{g zt+_Dywn3M?-MTPo7Z56Ma~H+}(A&EW|9=H6LW#J#4_)NwzSXPB%xANA{PXd*=X`p@ zt#^(aHY{+RSQL{v63;JuljGY>7}cET*tu*@gRRFWUz<;Cw}dvF{y@EmwG0VdM}}?6 z6*o=uqLG5X^3zY>ck#wYL51;Rj!R_0^YO zeJ$0}7L6yyj~yM=)EA$7Y3`iaPd)K?dwb5PY#6`8~f8V|DzVpt)`5#7HHCa)KF1}#l zhi||0u5QMr?J?!DAAI-5Ki|6FVTbNLeOhBv)1gNmb@NTvU;oGJ`}eJ`u1T;%vNmeq zWE)q1yzKL(dZO2uF%w4(8j#Lq*R*GXcxAp|&6vL1wZFUS#vA`MYV??zimId*;kQUe})^^8@Xol`MR<|}nN#998ExSlxhY7>)VECCf z`_Myj4MuH)Ed}um1a0Sj68v@4N^8 z`qx5p*S0nxI4TXJFAZ3da8977i;lXU|!hD4RQF3?l>{}Vt%gNZuy2DCJEwHMLN zL}JtWHDgB%takE^Yu6wwZ{;zr$|pvGvK|zA&!A%vfZ9qIaq*T1=7?kBol;aL904I4DgunS(YqQcX-xQ4EXe!gbq zN;75}QPnM2sZ^V4Mxo&Dy7~HNo_{$Ot>p)E)W`vc?1qV(#_`qbRo^FSRQW+0h;ni% zu2e*Q1Ec9f)Q#{08ByyKl0Q)@qW?R;Y@ck)SR?6vpa z=UsS_msmoWo0^@a$v$a9<+xMjoFrK@a$;CwrutbkQ)i0gM8P|7kFF}YB78E z>_;Dc6lI|oH8(fHQX>}yU?hTmEU5;05d54ubIv&9jN!wF!-GnRO+Ey95PUpN29yJ` z%Y)#B(dVO-4I4Jp_OFg*Gx@xwtATCh)~{XV`~0|SDT^!=+P35oF5RiAFUpE9bI`V#2>{$!8GXUe$H{xMw8t_|uO)aR1-qX57v> zO`BTuWOV)~3%>o$Z)Q(8>CboFv9@`WT0Hmg|KN)OZA$!LrUs!|xo+JZf4+NU-`b15 z^DRuW%xI;Jc`2lb^T=%z$IU=>R3-1&!-fqBxE)V*49(X0YCJc=Nryzjp}TUA2zQ2h zD3OQ41xmPrE>lDzrud4Qs_J&35YvsQ5oE0vU%`lKX|PIjnL+&r4IVJ+v(G;LaN+EA z>(R#|rV;15pX1wh-tY@rV6RxSZuco;a)nH)t$DW{CQTeQBAacDCF4Uzj9V~m)Q_~JRPDz-tkKcc9^(UXStlv;uU$=DW@`Vc*D5_e~XR>1_Vf6;StLc7J zjU=?_=Sw#h{KN(4ofpkFE}H+YqG~PKbiAf&Q%mayv*tFfUq5o-fI{HpFppD`ni`8} z78IK2!gP*vt0U|uLn}Cz?eh3QP1Vt6*4K9s{Cl(J4jepw@ZgCXSGOL0+@UR*H9nV( z6&EvZ9wx{`4dH2SZiZ@*51q2vY*R~9I+NzPhA?$D8)Ff5?`=09w%=ag`Q8uKH?`+c zQ=ws@%cb5d2ZTTsQp&}iB^cAH2Fat#=fclCA^`*rDMfbIgi6meHEvpc#{-W$y+-bP z(2;&?)5KB3Y{&k5+2`};&BxGa8s^(?y>;h3_uYE^pQi77z(*f`I&ReDd~@Js3sc7Q z8BnLqeD_T+n$R2iZOo>l33G=@lQc7)$yhO{G+j&T+Ja9PA93g*x^AvoxjdW6=F*v6 zci#20PnXS{Idk!nPutS1>({M$bz3f@CmhU5p?n|-Dj$f+g}m(rHRsv=1`P-lgX@$0He|7} zgt1O1jALOWqbMnP5$HY5P!sX^(MKOMaooi5W5&b5vvI>l#G0mo{+vsvVLuv%2MthN z*DG!&3c2J5Kpv-h%lbF1+Zw7sg}psF^g3L{(*F!iZJZ_riQ~>5`>a{prp* z3qGE`@Uu%V{n6Uht1`LNBac54OICgG;ld9V&c6EUt9v!{HuZQSnN-w5MV0oeUtBe0 zz=W9}{CoMT&n~{`o9CQ$N+hOh@mNiDFBRr-)YMHgQB{rF#0#n=} z$3LFAV&kie*PMF#8F$=r^MU*B`uT_RAA0by1@Fu;%^F?N>T3Bt9rSqvHlwGkTep7Y z=gT&(U#CEICX+S2>Rx*N)lp-|&VKK`nQy$YV%btHq3elQMNRK`v;tkIrn)j3O{h@4 zW~{2V&WpzNWR)I`!5H!ELY1Myg8RA-f^TeU`Rm<(|KX+IT)g&UUsGnzni+_Fl8Iy@ z5lcY3L8Qk-IpF0iZ^_WK^lGjp?TP z(b5&KzxVMsFZj-+v7@iM=IZONyLR6E4;Fqne~&%(IOn``R;*mMc*$oMUH;=g-t<2$ zO>KAl<*#!;T{!Q<56(XIgumQ!19r|Nn)I6TfSQde7x5e2%w zxv}YQ4?Xhs%$W<9EV=on>mPsgk$?aDwfPGceztV^LytUsF}ZRH#wYQT22t*DFzlo?CFzS|SFU%}uAOpwyEUP3>v$qpr3lm&>EpFn(bQ#h{0y zaXX*WqGnDHf}B;aCsadEM{L+UF(YXgvV~MzG759HP!ZFj_5CE%zWRgUEyXQFOuxOL z<*bTY)2K8vDGMf&?F6P~ShiJJRSDIMeykgM!2)Ro!vN=~jH;@t&>W2Iti?bo?lH^5 zv|ZI$E|eB2fJP|JzDt0_KmtgmQ%F~i3Q?GC*45T=ULnAZ@Kqn*^$g#M>v}e#Sb@q9 zUa5hVFXZxh4`aWsRaI62m7yywEv=4i_wL)rjTm;uHehKd)V!TjG)-01G$cmV5{U$C zI6Y8Ij8hdAZSAd54Enn6#G;xWivVjT1{Jd=&iA3q4s<6FE&{_TjY++v>K$$RpbbC6b1nR^cC$C?(0V)s0 z@F=6=iXJZlSWdCls;Xe(n9t>MGmzVupcPwCy>zmrW$&u-9zp7O?_E)fv%qP;mSrEhf#V zPRz;`P+cRLaA2m}P7(u_s^nC^J?DJm?{1Vrp5( zin)R5s|6?~Ljzm5suhc(5iz^R6w~6nG*QRr$0yOT!5Hct(c(g-idjHs5IQbm<)|?+ z-()g&Omv5?DTzmk04=FkghoUEMfD(m8d}Oj6PE%}4kox7q72O`SZFNQ4{ST1h$noH zo37Eo1-pQTgUZuXei5;@t{yUz&Se8Ph(dTUXZKw+SuU655~-o_I4(?&f&jTRRfFb) zq_{jFmraJLN;DQrr&5$LScaUk7@!AC0AV1W%jiJ>>FtgUWl-9R9Nupk{zH}5GxGl( zDi0v5Ktm2cs*=v;KuBdp1wwqTxro>zX<=e_lbfl4ama}&qykj|v*>+8{q zVI%=_ozU6?A>7d-vhzu1vFEUB6aj-eMO=sghxPz^(+jvk9oYoo0)Ry%0pD%@vO91G z7E%HQdLF|yS`(-ug82-GAT~7cX)wf}JKjYRK)_mpIHDF`M?#3_*_coZqNuD9g4{wd z&~gg=D&IzuJ4RR~B;Y3+gxvw=!fYm4(2v~b4UI?DNkl%ZZr6{v?3FA_JRKI__7@!( zqdtpAw+Fji_Gj2pz^3rClB!zBS(!`*nx2dKK~PmyX~biK#!m3n90bp&+lo)an?CVL zZqy<0bnqn11e~lNY8c)N*&u&~UwXO#>Mq04rqbV&%99{*0?6SaNUe$x`6Z3=K+)(( z3gRIG@Q1NT#bWbbaZs6tw3j$2WjpOdP3N>8WOtEcM`fyT@G7j!Ztuy zg6M~tz}m*!Dj-*Yfq5M7jv5pSAbw@-bq-o5L4_casY>l0l7#@$!%$_r*Z8j&PzC z9JD7o8+8$(jIdI9J-Mxb>e-GffNAmX`Fv1UHe8@c>9!RhZcv~Y*hD^lWsY{4%RpfR zL7IdH4~gSjs1!r$HO+UR5TR!r#gODjK~$L# zM&XC805ci+!2lQ{oPu@dpjo)Pk|6T}(BWlw6o7)rerbav8Deo|ZP4056pZ2xSi&b* zApu_mfFID|k$+|3B|kvkZVgZe4kLoEK0hl5HAt<8AWqOUv2h_xOAlE=&hwV7&Dv4b zkr|5F8M^*oxae2pJpZ?bdx&(52X| zy3GJBfG&e8+6J9Ss08vIu9UnSK~Js=gmP8{)$zC`R!$ih%@RA>7k;TPqzgm03PM_h zX5)}5)Cc=Jf^d;_C;`+9rzr@BL<)0D#3BzYLJr5sgZg6{0}pivX<{sNB_sLnh$X0o zHsUl#2(&;AkR4BmTG7dxFd--ulVzwOgo`Vb2aPsCtxy3H4OJ>tGZHWaS&JnQjo=K+ zq+hx+KR~E5qylQ#3qr+<@Gl3zZ4`vbK-t6)AR9OYu!I2qh*<-CVnG!Agch{o*Bapq!Z5N1wx`9#@XaG{_2gqEKp`sx~fu-OuBSUB}LngpZ)PgTuqP}PkPEJIN zGjEuk04@vQ0u#n@xDXqH*fIjAbiA;s7V?_*y=2F5QoP@Bs5Yh!|d)3n4mT63eNI z6j?2zi}@yO5%xnj!WAXtS3S?wm7Jl$(uun0k3#yO48{3qwDQypkSKn2#EV6Ap7z6| z^&sOe=g~Z73+1sJbIn5x{3ujbgmi#H63HWI5YH~8N4WO_qdUSe6-5XTA_cXDnEtaB zXjZa#bUq}84k1LlF znw5mfHYzL5jXo zDX!~kn%30R6pcn_&6?H46i{mG>TtDPXP2FJ%BIuR)ir!r1~HHlDf?>CTdL8vs62!h zg|7sNk|FQ_6~$O8RFx7a@Da1XqjEKl&wzC$Z$QZfQ3tAxsW?IAK3-(>B3g!p`IQkr zrs_~y^1@qJ7=eNw$^yva4U$QfM;|ls43>^ZYz!dRGm0Itk=E+*HG<8VIC zGWj?)B)l6ycVe?cAoy}+po<2f)l5m{!vU}%%uKy0+nl=!`O z9YE!gHQNT@ceg691c-xtplQVE!)hYI7Yd-7;D_+Y&eapRF27+dRo?sWzh5qR6ok6E zI>?dZ*t<-bl7`BwsnNwJ;=>**I-cMRyW>|0HZy$7X%X+H0mezZb~qaa|SC)B8ILY zvPj@Kk9(oTxG{qj1V3mY2!)R9Y+LdNMyE(66L(R0{9(buoD+V4tQ|l$1BnxMC=3ZQ z5vi%L`52XHB?woB!)P6B|WNokk%&W!iEV0IS9usjL3vd?Yw2OIzcfZvhZ02Bv^ER%9ZaKrs;)y zZrR;IQc>|j6>-xR2nKbyI$#isR!vOS+yd%F!&pF(807Aj%NtPo`A{CTk*F_v z4lD?0Jt!1*ArVTN1y4JvJc$7fW{5-Bi`YtNLl3TeywMfPM5lY`Fsq9IH3u4s#fQMk z!Wz~z9mZ4`MhNkHkbjg<>UFD%_7?+U;RdZZN9;ws? zz%B@7CY|A#V*+i7EhYcvfKV~uV+tbDiIh}Kw8zj$RP{0ti3<6GZiHe93F(1&Wa(fv z8V`+$ysqm2aj}pNzQ_Wd|UzLz{I5 z_NCCrNqQ+KJK1JXN?Q)1^LG04^a;2U|`x9rX4$< z%R_u2C9o4Mt6Yx&kym;*i&;WuQVUBgq6+jW^9S534bGew}g9#!DQ{gJ6 z`LJl9L$D6OyU^PSDDVrb(IVIv6Q8jPnK%nn=mTmJWgd#pnd->B9efI!KMM@p>WyglfBTog$ z_62ZoavboJ{LzGUD;U@%nSfG}2-Lkmvm6)d%qwI9JLh{A_@bExX2jgEj6nxnrEqGH zO=#W{HeT_&xhwv#VEDw07$U?~hs^+~Fz87y|Ah1rMflqZfOPX-j{xuyBPwxqcK9zP zN5)ckx5xqAsuZz0*^TRjq$4Nz&Q8?Dp^{~(J3zyXNA{jFhd(LsNPw)RaG@Z(!_on0 zo2?{~ycR7;)X+{4PISiNnBAj84#)rm4A$7%wQHqKCM5wLt)ij=_9Afgs;_r!J04|6 zB{xX7C>SY2%8-pjz=!$B0S6s$^f5D<{~5c^^BT^UVH5^ebb872=Tk9b zi6=UqyJq!jGChcl7&+pA0}e=KpxoNYF=mjgQY_29@S+Pp`tT!!3!K8rAV($h*npxQ zFetpuo;m;owanAu(6vX89#vgk_2GvLMaS6;$ZT@3!wKawZ1}JN0|s=b@|1$2)zu9; z{-~o4JLHgFy<+P(tbkFN%@mG5;Tw}D?>K+{d<>N$C6KWjlu1I50A04nv^~mUBOl%b7X+nB~vIAIQK7NW11q!G)0iDEOIMq-ckAw8F$9%ryjV^9{cSxtxxaT zH5(gqpbdmci-5TU6b&htDi8kxJFlU>3W2j?8Oa+!5ESxx&-FEShwiJ&HVnO6QF(xF z*@b{GyxfV1j^t(G+l4%&x{K?Aq$4MMf&pbtgm$m;IP4+3+yTl|UU~SJqVgo5b*M;4 zHf?M8#FpDqVVgT-;ZT~(&00LSsrsS1{p$!2qf zJo|%+aof&Wc_7SY^R8oYW94DL6bg10SkgR$#BtnA zhUc_r)9tS3U1~ObCp@R7$?{ z4}dxL)gJ^Ojm5ul^63-CO}4Yv=_j2qZtPG{c*!L{++pGlM;vhkv{F$NDAc8EF|734 z3Bcjrz5D#&l1po!jCjmKGGHuAOqpiYWp!^?q{OWDsAG=0 z_wIXR(b%9tgQBJxkHs2#HC%DUkAHCS_y2tBpR1}X1HS+p##1YY4j+E-p)(FTX#dKJ z+SO~<9(%&E=U#Bmgo)#puUy{L(sIo4N6y%1uj7tA?(idysMhR7A1^4xdkr2w<~LXV zaG!l=jNfsxmCMb1{dGwFj6)9m?svbl)0CYdozRcd_Sk*DefB!yuw&M&TDjA1W8ZrF z6+3Igq%HXBX=j}A=sgctR3=XQ)~S0;+vSwwPv2$Aq-@)|miEk!yU*Bv{{s#ZU2OqsHL`R6byPde%33orc6q)C&{IO9w-^Ww#ek390oJ@?$}qmMp1?X=U6JMK7W zJ!D+CaN&Um9{9r_{;+SKzNejj>WC4;p&6kcul(^9`|Y>yq)C(Z+;h+7=4M!V(5Dw& zbPfe=rP01XmtLEiw6xJ@zz`K?7GXYk3asn z(2NuT6(m#Scqa{QUPK551>q7PZko1g?Zzp)>~g@~d(4^n4#pA~O`d9S-4JO35w7t8 z%Eb}T4mA`)u28_}XhF&oiMY^u)IPXafjMsCl)m+`Ykv8|2mW^dqQ%Pwjhk}%xfkWz z+Ey=Fbn$o39XoF1@Cnl{|H&oOcb+_;q4u4*pZ)O1KgZPlN8kHSpX#bj8ymlM(f7_i z=Zsx;ozmRaynNNleuD>}dDhwIopt8OAwvg^n(+OLzrXLEI}aaF`|kU5f{4L7msJi> zR@pCX<#mB_E3XW;3waN=X=fy5IlCuh%T`_&D7W&;;7hdf01z4;kO3QwPfZof9>Rzo zK&m@Av4xcMOD0fi9=kpefsHTmF0a;6h!g}h4OEz&5;QAZth+&7Lp@stzc z4m^eP_$t_>@xz0B{l+|lC{QJ$B&%FBl?$dV} zHGG(rZ9nFi1B1YdSJfSHSdLbN!8f z?B7u5L3ydBqKh}Ch4O;fg!+zq+_*f7T3>we#kb#n+iidO^KH2N^^UwSCX{Vfe`ZtbJoXoP7>oI*;G=J98 z#UGoAy7SLC_UtpyXkNdnY3({)QCF;5{lwGH#4D4>9CvI@UF`|SA3JHn*ky}9S^4?0 z&sMB;^u)473m4CQSEp$i3iezkv+5d=x zj_O_A8$2y8VGi9)9$Zhiu!8R@d%0Wv3$! zIq;|>j@WzO8N2T}y`guXe7a@!TdzO**rS_TGTc+ZH_br2+&Rnz9wQR@aLFfk-1XPL z|Kt8Q-gpC6OgtXPVD;fgA3gEJ6NQ4e@7~i6J!Jo*k2`j!DUn6}FUc!Y(C z488;9=(?!?%r{?s=81#wQK(L=i4iLH(c?{pTGI?EAPJe>N~H$kuOA^dG6_d zzww5isKn%a)uMTSx%H-3-<_| zYFo>uL@bI~Ogd}nM!Yr=ZCtx5UQt<9Ux)clb8CxXn5k^~`DdQ`+r9T(ef721UU&WH zE0*hOkV`dE`|DbDRfDM~`0`~$vkO^tS!i|LG;`@JkFlz(K&Q!D9`JZ>zO}i@vK%8C z{bcd7haY<6iH9HhWY_{nvZ`zGhQfyrRN_MQyu^Z);is^H-QE zM!eFF7@3@{@Ua({+hZ})j2d2qhcaOrf6IlD-VLlxF&B)fb8-hc$9MW)xZD#_rJSr*;1~bw&(1Er>c6v zwl-{9#}AVi=bOmFLNN_z$@~drqone9BMiNg6PK38#vfgF>F&Evz4V8d75o78w4GdW zlS?O|0eH@Qo!gevR;*fo>M;kjG;V6-p=i3P8x>}hW}m7nh6zS!z8f=i z%{11xHT4-jbmN9iFFpF?yDz@J_`^m0hYwo5apg15KKuF7&nkKk_B?*h0DTTtnXY?@ zgtC0an!HnS_St9q?#7QkoTsYERMu+f-8-Lad-0hkXTCS9wyMDkJO{>Mpeu@Is?Z>o zE7$LRFe9d$3CwFfmsTlEY)x@tCc|+1S`LDrJ#Sw1;9>McmeAMYHRPg$lx4G--~96D#~*w2uYU8p zj~0K%{W+=@crF(@0^j4Y3Y10eh4#65N)w-qz}UNV>C(CL=FVR*Z~pxG^XBoI&E}vk zbwejVFkn-$2PV(QaWVxvS8%cgE7hJl@z~?Nbm8#_A3o%mL#qeXL*LteWYoYRxz?7z zu{($Ds#TGA^@zz+bD4BaObIfDm==#E%%;?O zc}9zPjd$~I@ZSrv=WgzL0>o_YdIA`{n>*;QFuF5vJI_|!7K+*oV6cdX2vnC+VQvi| zT}TOmhoAB$EItXU#)Fagnj#SMX`&d+Ne=^Lb_odW1d7IW#0xI?)}aR-dN3v;2ONCF zAxAVfH6y8E8Yrib%LTrpDZZu|iJD%98Mm_SFFgO;j=Syp-iPyNefYtd=bjafn?}^s zpqLUBG0j9TO;lGbTDJHve|z}-1@qs0=iTpp|NG5NoAT-OOE11yQ{U^u1q&9;pZC)r zUshLN3AL3-RP(uNB6`g=H;fs*<2&!aykOz{AAaY%m;T@)Usobgqqd^fjObC5CSN>R z19q9ZR#}l$b*-(v<)07y{gO*BpZ)3QZ!P-#xMNPb|L^zhyxXLYKb(F0-FJLE|6|=q z8j4<9U4cI91U@QdSzgnIw$}F64UKDTI~z|Vs;a8refM3cr+40c_u0pvYFZD|&ro4< z)HRsVibPbau81n80X{>|R##Q|CS&zz%r01g<5n0ZEV!@hAo#WG*Z%8?C%%2rd7my{ zR9RU$|AX1$AQd$pN5jTpdt&Cj%dWdT``j}lM~^)J+;eZZ=8qVDuD#)g^Da0K%23Dr zmvSQJy~06kprJneX#SO#{pjOQKh|}VZ>z}nS|i+t2!VpsQtZSEojA^d_N)vMD=la$ z0yHwzVws>){?x$Md}qqIu@64^{JiDsul>_4n5v(3(h09U`^dU9>suXBW0i^?Z*Ob)_scIHe&Wfmzx&RV9Vgj^JZ2B~{`0~84?E`L zCF_6kqaO{dubVe();F)b>cMB9fg%?MK8f9?9`;`V?60EdZtf7(Ey!Np#dQm`=GnfR zxo**m)LV5u7Pc9n383;IFc^j*8)4`cLCO^b2v;F@lrf4CJiQZDX4H&TRtz3KER{)D zR##~-XWi%d7V0c$@nL;X^j>UZ^z+6zP(3AC5vBt(tZlWGW#DIpHXob0=vDq&; zX5O^}H(6H`OT^F(93_{{wk3QulK0aEHBnKU$))P*>fJ!scxbuP(%R%Wpx&#hjH1tH zvUXKUQi!T_Nk@eX?qT=%lclm^_B7V#%5JBJlHmYqHCBU z*|E5)=}tChsY*iE9nZ@KenL^>c0R8~m5S|PW2e%N zszFah8hZ6wvu15|RV6qB%dxGkO%=yq=W?0)`g#W@o_NhJm(LTsL=CxsxCpuQT-dRY z3mF4LPmH;g9t^E~WkNic0^#cWQgx@rupbsINrY;o%98X9t$4TfUsim3)(GVbSG+f})InayQk zGuC3J?wKU>^)`Is!WZ$?ej8WFW#e z3r9pC-hS?iXM2!u6QB-T$%!J1ixB@EK&et7RD9frK7!F0bAm9gI}nnoyRO&X-d0yv z_x}6uLrY5CCu5a<@hbF3sJtP=hqXiH)l{K#`!2^hOgY#*62Jw{#=<)Q24o-tly^wj z1%-lbntCeLR#lPoG~L!?RG?15bFHe%O7w(muArzkrg|#00Oog5STv6BYVl~LozFnv zVUhWolCv_fnA&rNs#s;E9<}V8YDQc|gXT0$E220?q{7Q+$#~N7+(7g5cEQjSsZ^$K z?>>%~D-_ywou_0NMgm(Pv=+B}b3)2PqcOSZy2gUKL+j-V7EEBFl%e~O9Xtk! z-0q@AR56`z_k6CdLYjqGhuJq%c_o14$9yH4b5gFKiy8@CNkSp0K0nfjDGH{#&~On) z&F0e)H^og2W?ihZHdV->{ZOP^$SQiE$1s3ez7DDb=w=?N7%{AZ2P082ATTBdv^dW~ zB0S7pgs)oVZ4tgIm4`})z8*kQ zL6TKIg~;b~$z-CcvWh~r1qvZcJP_N%INiO<>l>?7V`d^*F=XWM_AISDD1ws8DkU-_4svET?jSiYp4ql0byu+a;%35K(Pw(^A5j|NuCr) zFVA)2Q6e;^5vsbFckm6EfVp{$2KokB!!w0Qw1R>x9t4l}V;|y+x9qdbO&w^m{xN zL9BjpWs`};8KY33#MK$TqJ!WATEYNSg!=@gf#!LdDn4BnsvEXP(L-RP7sEu5WS0bH z@gO^h*Z8do2mzw0(*)oa3B)R4qyTf5Tcc<#B2Y%*7S|pCSXB&;p6YW>E!&T36b?hJ z7g2c_0|Wy$rU3<+Ny8)4vl!*e!VREA@n(iSiajSqbM5hRE#5rSIh3?5MgAxu_A@mZqm8xw4 zHlFN7J%c#!EA&H|U~UK#Pt`PZ<1n;aK$DA2%kAy$PrF}+~r^|`$h~cU2 zQF+YFsS~eZP!Sl&R>tt_D|!_3Af$nyBMLnV*OHV=B7{Do#8dV{AcoKzwkhRQ{PTin zo{~aAr3ojw2WBvZ=#ny-!~tVO1c)1xa2;8xoG{~_@8?65|nazf=XKnwt#RURt> zkUT1JlHp;Dgiz%Xil2N${N^eTEsnV@gaPKB>x%D+2(&^QcEVT=h~h_<#N!TNqe|tK zg23Y*Fn0Nziom24Zxf*b5xUM*JSs2r7-+pPrh7oM zm8?9dJWNv%NP&@J)?g;hSTtIZ95H%iTP{;sT?69?^D&?nf?ooWrA*~*1$Yh|H65gL z8&w|Clxots5C&5{6mO7P1c(TkSXh4oZ5a-DMIIVfLcNG^shUJZm_VkdaEGZwkUd|{ zD@vVTWG$wHpURWSiA_Y6^#edL9izm8Ev!|c>||m_V_pd5E3`1IRYey?VaA2dB5;T^ zoe-&tPg%q8BpMMyCktTPK#Ry5$w?Y(LVxjOKYqW)^#a{hVnD}J7x>LQC*p}AP)dPLZI@bcz|Gp0GO)>fV8_9jEgFdMjmI|yuwlU zfx%wH@f=7w*yLg6-MNBYpeL2rt?odWY*hj9g*ObBzAhl={7{^zGR9X?Z+Jm#n4m`x zt*{LM3Peu`VOz6pD*(N0PzhfideV*FUfx@~ffBdTl*!6CxCcLmG)@~rVebLNArn&N z&7M8GtIF#YOTx-aCM$=J9?_o3RM*x-z7&-giMYXbt2}1g8h}X{)~P)@lTxbE=1@B1 zxd#Bs&UFnzE~Ox<`_4~Fc4}g?H<%PE)AXLOa;ql3))WANCL~)80v=A*=Z$^*c4JHBBCD1~nZ$gVn$i>3^%JRvp|A=pv;j9EBW@LW&l zo+cH8E_I^Jy%`_^gH5rDWzgLW5lE<9Iyxx=c*AfZbh6=aUn~yFPS|(?&}KzHM7Im> z&7insxGhj#y{#hNZeTAf!uC+LRREv1(aJ+R@<&jD_N4;RFnshRBm$7m_siGvWH7}W zVuOLFP_U>w|JOmc4ctSk_bd!O#mI09uDFW3ZlGtxo#KQyY~wIk{y-(L@u6<`8zw;% zf}ruZREU8sObZ2zX!zOtL`V^!GSHX;r1~gVBG8vyX{3dLx`V>cW8`H1CQ8i0q_JUL_#b6(^42ilT8_0$HMjlIgbv)nwFQU&?Exw}W`Yxv)YZ|H z=m9W+=wOF*$WRWV8gx7j7uuqe*=akvE{Q5pSPTh&i>{blc&Qef!$-ppC z2Z)h%vrqt%QeqI*IhNtnFN_og1Gh{ela{a{qNB)SoB;e33zgWU!a@iQA9zG8?hq&h zhZ*okK<5ej59EqF#E}Db4VUMOrHRz#ASFUDp&V2WmPicc$?71xkZM!BkJk+d901Z4 z`dH95I#E@Tw;Uj9z=JwSgzz9FWI~suWgyebWLtq^l1|u!H_VP}$uTv8g^vvoI{8!d z%ip4tiG>p&eoJ}Tq9V8}bRXJt_*V*F4sqS3{t~KJ#_#er#XY--EFg^E3W$~tLEfra z9>A1uPo+5)_b7hdgT#V@1;S1cQb%Bta=MFtX&Qv{StbOO1{r}EzpOk0;c$ok%Cw=H zU>M`rD;UEC6Xp@IVfEyd-Ca^z0^z0pz-YqET zpbZy{@C-vJ(;iF}kRk|!EC}OPn(z|j0?v&UrxP8WP#SWYCKGf?ExI6V~_koGgYEE{^5sF{vG z%p&L~f$UhET_BJ+i_VRx4xAQo_zaTyp!Ilb@JS*+Zz(Lm4#$J=(QZCWx^lx(;<$6DW)D(Dbs>JlUnfThJcpM^#APatb7%+Um5sIX$SXK_bHxkk90#XE)ZfCI4J0?2_f zfXo0OJXrydrGkJkS^#(~c&*rlyp_+{b^%QT4K0@J3?&k!BBMGI%HDT`I)t{9Lkh$P z3Q!LM1Ikg=be>!r@I0G*E|bl)*@cW_qqqRg%I^x%P=s_r?!*wrWd>Ziyeg**q=Q2% zZ9wQ>YCSnzap9E&Q6>H#Y(JpwXiY>^Pc>mv*f7S_Kr_f&VPmr&p_wqA`HDmPV;g{@ zXt6!u(Js04lD4+?mgeT_x;l(+RaI4xywWp{&LA{dQD~=3*>UO~Q^$`TH+JmUG580- zJ8tZ#5hE5Y`cyNZJzXjSO>-fYQsZ#j6v`IGQ#8UpAntJ|Ls4buN!+nc(TeKvV@9Pn zt%t7RyXiu^fCvg6bL+lmpodP|V{%LTM$d*iF(9yqA92*$&zHgg5D)T1ca!_@gcigt z#TM+P#({M62Nxi2s@ie#PV3gJ>({qozZp}Z5Lz0W(SL0}(z|!>ou*95 zXA8M(4t)c51jqp@{J~y6{)8hIfA%R+V#af59K?Wz312OThU_~6f$d}`>_8$cswqGXQ9xFxVX zf7FXt>(y8`>rKtu7F4Bi2kR2BxR9Ipc983nZ zDNsOWbgq9yRLmt*b?}g3d+sr949goaX~&6UMvq;-V&%U3&RDxPk`X zQlpS`)`mhtWMOY4?S7u96%;*WsN4YpNIcGtc=!+(s9&9YfeaH=ei4I4waWlr+@nMpYAYe2i*7RjlTw{fZh$g z2Mr!{`dO#naQzLn)iwMss$%+D%=TRj_?U~3J}5GmC$PgNgIsF5<~UI0w(UYgIx#JOjlHuv3syMdE)ecD{;MpU2t{szp5TwZbg$W_1n;rs8smTt>w zMk3`${(k4pPu%y4jv0=$Y=ynf-6z6l`C(N-SLxw;%!N9R? z3tSpGauhTsx;?p_$)E|FnwmFlYHV+Bi$>$ah7If2ub)WF{d(2a)#JvEhk|ZzZx=E_ zydy`As;#N1t*b4myks&7ZBkoX1Iye6L7H~NX{R1AeV;*ndhfgUE=v}Dv~gqlgcD9a z?63p(*=NuD?z=k{PecM;s61)tZB2@Kexkqc!AI=1_w>c{-|=nBk0iiVje{4Yhf_rm zhGddR02(rtN?m>R)khzF^xmCe&pr3N@x~h~Dk|96Qt7GD-S^n<*kg~asf_jSQ*8u= z#Vb}e3>pRlE!W-#VFKEmmCZQ?@K!TS6z2tg-m)NCo|V^Z+dwyqIG)N+5)2+XdiPzY zP2FSKf&1@WU13&M)XZJ*(f<4Hvt;R#oK+~;1xRfHa>;G^fmO)ztW$0YLn#q{krJZi z_!<JY)RDK|eCw)Jt8K^HxM5@Crbf&VuDs&PA6)VS zgx6G6@x@BTbhSkPf&HfKI%(=|dqmCZjT_hRyZ>HC9(mNzp(EC=+mK0TX3W@o$}T(Z zJ!7A#d+b#g4VEwcEUPAZ4;=Qbb57l9%8mm^ji`vm-hcfK4BtCVop!=;$BY{_thKc@ zo3o}&p0x8$JMJ=d&o%4U&6u&vyKldiOL^2s5%-&Co&MZEpMeRn&tdyb-esqK_Bmk8 zs1f;8Yg>D2vDT?!3#im!5mMPv8C%cb>dv)#qzhENyB}Cu;h@D&W~0@6B4jVdJFTrXG0M zq5JGPbjDRn=B+*mT63be?)RAMyjA+`pHkB*vG-daxyFz{LwtVGEXi3(Btf0w{p^criST6w` zdZY)~n!e}^UkDv?Zsu?)LMPm1NlFfN#qZ`Iux#1kg1kk?wx@0Fi3KJP6AZhMTDNx1 zK}Vl3boi)G=g#pR%U5+_2J&OAs1%>+g(y0(va-~89V$;O&N87?YZ&hc(0Us;ZiELB zu=u2qbqk0>8g4Sc1Tl!5cka0tUwZKmFaIIjcfR|bFcI+!3!mnHbmu8k&pY#sUez_a z9-TIA`lLxaq|@nf<0kI5+a4G*PdxE>2v#&vfnoWQi@uf6gX&)WzyHI_t1By#33cp* zk@bCh2a)*r2~+l(Ha(wiA3kL8o_oxw@74E&u8zWc7b zYK8%8GlK!%%AbAaNqu_P@>CNG<2)wNiB0XW*b398?d*E_U3Qz2Zf*bkvN*lJ9>zm&+!S4L`W};_>4~Mtp1hxbaYG5y!%;UA%6rIKBs4 z<7+$!e%OG9woU6$v=Ogd@bQY8hQYe2UvtfGmn~bNs&O?EQ=yPmpP%+7faa|O+M>B> z)97as}~_9xmf<76`z|jH{G1-ZPDo$)%RBTD;qC zJACu}(<`g%a=z&YW?YL_s*!~1WG(B|voGjh-@n3$$7^eTaOIVXuh&*oegC5K$Bh}T zEBg3xV^2Q$$m%MSwt)i6T8~#$=<%ek8+FxHu<|t3JolWFYifX2`N1WZ4<0ng)RY#wTSi7Ek)7J=~j`q}MuKQ-jq#fq^X0EKoIsiDh31Z6*iJ*YGI7|d0el&26h-U;= zmEmn#zxMaH{LM@B{lO(a>|a-dnVo4GG$Aqd#qrTpQ#t+)>XMRI|Is~eta`exIbwYUG}FLM?w+*^X{8$SHVzplOhhO4jsoddO(s2n|F=-A$H*nZqGxqD(cOYgfZ@&53ZGZmD+VvZtnNWLAoa`9!`L(vZUC<4! zv2o+=xBunZKmPHB=U>1q&orZmpEqy*t+(E~cFl%E4n26pu%T78)q_Wk+JFE3EKFr0 zYD2I3B<4*6dJP!Z+u_3(@K-e=eyVBJhV^Uu4;j(F-=J|LMqv8emcyLK$YipZi}$Xt z#)Pp~zkY*<4b~!FbIV4tuB5Nu(0z;b<>11Wxz(gp3s&lM@?O@bUbxdi$ zu7lvmju}&*h(%S;FeyXTRrQ(@O~xy91H$J8U?e?04RN<(1dQPTKY7zqxv!{q|ch zfA-=}K7Q)q$8Nv%jz0DE)2HwF=Rg1PxtXmO{{#u_Z`DjQ0c$jckdtm@cWlvd9|j#?sr%H z>Tmbn8TihifrED1dD5=COs=Y|Y-s4a?>_tX>)$`nl^0%q`L^3`Lqo`g&;J#G#@O8T z2wl=i*8@=PZ^?M8tYf6R;}7k{=m+upMGF1sj}9YM=M9)N()lDMC_ zJ1kJ19Zdj#2_SF$VRMVEq3C$H1x7i*3S8w57Yi-_)7Ub>~( zDHJgJHa52|`t;Kc8#X-u!i!Hl`4r4O*L7E~S)GWQiA1cqEfZ)wv3BFym7eV;;uRa# ztZQm))?=}pmHv3)?DcC`z47Whk395bOLIFW*X`{sG()t=paFwov7{I~0^hPw0c3HY zr`j?bH>|I!sC0e5Eo;Ga@(NZO`sxTa*Q>hUbT?dv5 zMl}?{r8h_ttOnHFb|6}9ZEf*bGS!w^y<&M~W!%)YbZgGg&DNHd1q&B!YTESno9{gS z=u>TNtp&?!ZEZ87360OnI{HROZ971Q;o6hiK9Cv8^LKGy7`osqcQW=1Kv!hkkRr}3 z<~EB$MBC8Pa?!b`Pn$IMs-OL|xv7Qy*X6-ULS*pYz2t;aB|!8JLU@l5K2(UPusIGq z=wRD%jc5!Gb5>t$Irl!G$N{ED5?QPuW9YMd~Kh;3l_}1=eGa($6s!G{goG{?6UKwwzgYt zyY>0!UaYC;AMq04gX`Iz>q1kRiuu{HjZHc8#FJ0eoVF#OE$}p@y^!rUc#!M3f4$?b z2mkqC+<@J!JC3gfRhYjze%@E|2g=`1`iKNmg&+~2D$>pG&t@ieGE|=$v<7+165MNa*|THtNHL%cAkV z0|ty5KYmhMDqYvBYWS#ut?e5r&Jh>GyB-*^NJZ30z@){vuW1n#BNNP2CuXWuv3P|M z)#I2McwCo`#j8!T*0yN-E?>U#w%hN#{q{Sbd;X=i_B7ap*)h5oYJkB5CZviE#6AOw zL;K^m1YJ4So!buBE_C28YA#&|ueStUFm3KSny)kZtpdlIP7b-mTWx4-M^!CdOR3%^ zS6p_|!3W*-KexWOaFJtH1elLd7|@$#S+WwPLQAd#gp@Ivlr;Ed5eme&Z@>N&VbN@2 zr0VJ@ckqa4WQ8?=j`53M{PLUUed~gAFMzw~+ZUx%Y2b~TQCKmYIw-#FX9C6RRo@Ve zMf17z?DuBwz4yM)KL657FF$wYStm!MW-?J>8ZkpRpk1mHvACu!S@QWKPrvs3i!VL+ z;JGhMEcEM>pc)L)WIJRU|4j&1`CJdj7d*zx}OmKk?kt zkG$~geg_=z%rj4o8ae9u=bpR%`kU6QX^lo}^@v(ok>HLlRf(F_nOv};DUF%hruA#u zS{qe8V#cHIe=w_|cb|X#^MU*By3@~Qq9iFAi=lfYF+YmN6m9~;c%emNFgCS>VkBZ_ z+;X5v3kjVEYJOb@!LMGo;pNxgJL9a=UVZ&VOotbKI8W^8R?sLF$x38|mYg_o!e9P! z+mIncjz9i{AN}a^0RskJdF7QSobU}HDPmhlnS)&DifW~rZ@K>3*WY?K5{*0Dy~Zcy z9Mc5IT8IDw{J6?*ke6Zsa+_2s4aMB|>+1Vldf5-3dFHX_pMUCCzy8T*ix(~VY}xt^ zP2c|ECD+}0b7f7A3gr)zb^dF1+TyP z;<9C*Vd$X%2fpD&5^7Y}bT?4-C`KbEQBkdZe0o3 zam(B`Ko?Bix)N+VZsh8sU5XCPjkZ=az84WS*KJsP{2^!g1OYii7NwyCwfxgt@MZudryoRp}l+s=T{C9VP7QSxts6H4S*tnS zo^kw!hQ6CtudAu5sIHAKUA@+ zSFnckAGm1wQoq6+(z}2A^0kVtMyg|ata9VVR=be5vl&ANGu>oNH!4s%0S4Vyd=Pxb z^@3Q<*nR`*WARkJaZTguY#K9e9b?I;Q6uNgn}=C*EEa=Nxpe8$WHJdgv~Jxx+=8Um z)>g<2s4dBflqXz~MXvB70ZI|!GD(L-$;9yBidq0Ca+Rtn@gVz0AAKZu7zEt^tzl>! z(0_1sO+4bHe5bH#?fP^sNL17h9neSd-33cO#|Sfa@UUK06;4o?H|N7_CRtk>z53dV zZn@=8)fIi4(=BV)Ew?OJ!(0M(onqJl?A^NF)j{jV6?uzqrHmRiVDXYAzE?M9f6$7nQX3K|9%4p^hXP>U$t_5OKQ-tk!{VJ>|6$V8T7+k z!L?M!{~iE;K_6&>0MkG$zo(0Z_GLghdOjrGES?+p`>*yFz z8W1SRhseRi+-csq9$>pT2tGU_boT7o;nvO~C@;P8Dt;hdn>IE6_P19J8Z-zEyakm9 z-d?##0gC(eaN z_j7bz%Vygf`qX)@Y84y|uzujc;^K}{zM)Y7FEH!m;X)?NP;P~_b6Mm|+a4x?n8iDu?M5*12mkbl!;|Z5hr9V;Bjot>fRjOBhH7waC!fxk zl}StWoov2evIeuJY{Y9RIENg1%q16J6jyD{^%A;r^9|QL{rXJFx-$5R4ubbI16otf z+qx43W}un|pVo-;zF>QTIq*QSLKmYIxHb^s^JVw}h(fy~up}p?9xgq|SXo&q=cip{ z2~e&M;E`Je%9kur5CYNe2oZ@<6E*O8FjT?Hq4mgZeteGKib|*2V+Q87YCMt5rqhXN z6pdI@+q+;@)Yn9RblFKi`N^eDL5G#CC1SoCc$T9Ea_bD_!E>EFpSv4;(*|6mJV*4v zS1l`B$b#4M_GFAg%@!ji^bQkUw`%0SHl|OmeDealmJRfRvu@zeDe!KTG)BIfaoM#2R0OR zZS*HD)x2Cuk6}Y{X(V zfgff;GL);S++^dr7OXtf0}>3Chs1(dnKB6Yqyst+qX>h5mK79xgG9loDm*^-Xzw*@yGAg`9N_a8r!OVty7w^$ja&%9hksvtV1APUYqK=v|oSf;K@sr44}|Hy)FkkR%!$ zlmVtd0uslhjAOF@J^*Qgg@VQ~tP>!-TU~{4*^9~nH5U4y1V!|iT%dt)w*`>R))Sw& zBnn&t1sJVF3{7#YqRK0=S7?E*04Y-W;%w=NP^dgHjLFDAdF_oifi)hF&6@T8U3dKz ziP+eiNvhxlRh}rNXIcdiuL9z5MM7#b2CB#oA;L_DH$pksJcp8JUUC}*IjHEALh_d* zI6R`#LW~433U^!_hTs87C}`pcUkW0~1b&fGs82E4gw`)lz61fB4D#t5^P)n)7Xs81 zaR)j`frbJHFiYkOwn7yv;s`L3$v0sT&dhu&1I*lMD|#&SsGtHG6A3&a5Sk~HDr<)n z94CbKrhv)ybZ;{G&j}OBKmC9 zjl|h(RF)8=Ku6mKK5TVZh(s31mlH8E)5sN%ss$NB%mh6oj6*WY<6*CF9=tatd$gu?=>X6a65!YfKc?Z}klI;WFWydM{yM-;Nyv?Bpl_%d&-!eevI%Vzv zc3u7&qD0Jakua{SPGK{Z2k538Hly2lVhfcgn-ZX2cir`^t*xdRef){1a=9GlW#tPr zn**bIj4T3W6!dZ_7d9zw#lgHF4`M+9W^WHiYT*#*!xD_>zOBKyf<}RXC}cw8V;m-A zT4ZI>Qh5OZ^cN;XJpY3szJclpix_z@dNTyf;)x64rVm*fJ>s+v=vf+;S^%Afo&qBQ zIZdiEh%&V_iWvXdV@UnH@Jfbc{yKAvQ=#?((sRw7qE)5}!J45<+&1s|2<{@wPm?Tael+yy*duKql*wQihac zK%;_x;t(y&6`VkG0*qcf@B|@HJsR{4R37zJ;9^1n`%rOnzH2qLFJO}_Q)kXv3mA;Xn#SD>m| z;BbZ}LNSDt*t9v6@|T7XhM;{_<9t8^(RF#b* z=e)h@t5WUlu|%>xlht(-4JBm^I4}@`ZLsK-KzDV|rNxe>pfHG1g~s6+AVyY}FDXG3 z%aRw050RiiiU%ZF_?e6|5w^W(eq3R7B8Qj_h(L4$PKd#C{4)=5k?}|=R)IpvEl0vI zas5J2!qpS>RECt~F2Fj4UI}5M&B8Ya_KGfv$W8WlbYM1=NsGbb$2rjmn&P|S(EkqE z?is}MI?J-+;)OHhDrG@->IEyGn>&9&G#YapejL|zozm2|90WmItP1Lj!H`-E)j>+? z3L!?M9YP^mP%MqX#}YWMft4T#{hsz8M_81NaNI!GQ;h**0k()7LMf4;Lu3LX(p2E- za*u62|AQa zWYLsUsy_-P#GHu{NX0H>x5I7)kQu0l5L(ulG8{UlVi1aBDV$kSW3gpv5F?aZ_BuY3&^?n%f#Z*O=EAl?-K6}WK_J*lE|*1Z{J_)2mKX3*HX$5vz(WJLRthvKbIAY%x__yggDz7t%f%7X)N zcxGk}s7yz4Nt?#a;A~=`>OdlLAyBrsDEvPKpxbi(o|>P8Y?c#@=o}U%+AMr?5L_%v z1pMrNDu4VF9bCVW;r9m<5POwhUAXycH;7Sp? zv>=z9IE&)qzK`Jn2{`vgA`B;-1EMaZgv<~{m+JGC00<6!ok3Ql6f1`xXllWJv@ zJ_GSI4fr5Jh5izaQOtq?MAN}Zp(+uGrsc|mjKvR!FNzl9iXerDOe)iN#3~5EZOI`3 zQ9?15K^ZDSu^~G_mo#0VyI6!tV*dXOs2&Yov@As)txK`Q#0rAngN*b99jQ5g>I~|T zp+hhRMiWq@s@&+lz2iKn0Y!u`fVa}aZVY_#KkV1+e5ePEINBXN&lXqs!)OWk6}f>L z(;0Do0!KI*DAXUvK$=GZ*Iale5Lb54A29HH5uNAcVE{*3C_&7M!9Z}4&n9U>ag`cu z47En53aDJLgF@ll+~?{H^aVUr-RynBU;}O97sP;5I_)Q#&K#aa-6g;$G@Tf|iV8|_ zr3gU6Y6`Ca>1XY^j-zTm=A`0XSN1E+%V6tL3rO||PYF7ONIVjNK_CI(!W#N~7sTY3 z|KaDCUTr;sxgA&a#L7Nr^Ze`N{vQGeF0Z}>d0VQBB#E<6-+=mtfeKpyR|N1w-kep6 zCL!MdXmGB+!Gjwi09+YCJCaNM(~(PJhog~Cdyxzm73V*~B|$8jLo7tJ(=dZ1(88Di zL$mVP1!+KubYj-P;)I@sB|#r#NQ}z3MPe`-#B(+y3lUeAN+h%lNW2KeMIvDlg08O* zBrPSkMd*@tbJrD6GblXYh@e5K^Bh-0cV>OjE?iOiPk~*c4Agv~Fl^LlDk6}jr@c^ZSv?C3!LJyRn%ug>>guLqs5bZ)2a>mI;JvgCPpe)5K1oD95xN`u# z)WG~e!>l&qd5()}AUon%6)Fj)gcP#wB{44}x*P=gB9TmhdY~@+1vZg_K%-Aqp2@Z6+@H!m@4!*@$z+0U_m^Le>z|* zr~9jha*2T3GNATba)NQ212}~#2@Dh;6IsP@Ri2V0rk~v=?-4}ngdmvT0b0NQ{Sg|E z#Vac-#OycT|(YoP-QD6{xsqaKu3Gi%5`bC27SQrFZyI`1l zU^&oo6mL<1FcLT^GdwuZcJr|)pT)Vp&uzlG=39=zbusn`XbVnqwh7Rd9ZAt`9NRLZ zhOmfT)1*hJJWO!CLO#dsx|%$56@*bMNdOj90b`R6)dXtcYvVCgn0OEi6${;N)@#nhEJm)68bGrcP5%6e5!do&Y)sfiDbn zVKr)cGLf`x+cZoxkfy4+Ts9t$*_MsMO+y#^u0klQg5(k|VTT4r{EGn42A>a{APn+p zS*V|*8#<}wM8kug(^V~%%@$m%kjs5*g4D)o65J@4n5;SECe1$8<&LE=CeL zMaqwPt~X?O@AlRWg`8WkJvVMl8aIB;M~lIu0{5b*a;d5_Af#J%K^Z_yCF>)aVf3#5 z|JeHq0K1Co?|1$A`ew7)BpY`lLP$s;gaAQ;B)A24D5V8j3dJeZfEF(lC{UbID8-!+ zcbDDBW?i3O|9)rYy| zB+1vmq$uRmqKW$I+8rsAR^kj9JXBS^t5>at;GpDa6>}21r&kBya;j&~o{f!7hLKX) zHpPO>hds4Biy_6c@^A(V_3z&w+?nM%+{GC}bM@*p4v29D3BB(NhWnS6YL11%o7-9| zYwKNAb9CBx8{&?{wCEZJZJ9$d3rZ3cMs8{{@gQnN0ElFM5J!xM;vtfV^DWz}sVUk> zLQyoSPoF+JckN6jW9Tv3c?^Rw(+rL+>nB`M-|{JDDwKW!Fj)`;6M06BrY(4ZQ6v&e zCKHh4O|1=W(TJvc`<3=-XlM|;N^#E~^a`Zw*|Kd5kO9|7qLMUBl*h*%0SY0p&o90+ z0NZ_MMuI(g>wsau#b<#xqccYlo1x207E&#bny{swJ@QhmJ5$kUAe;~JmwDlgk`w7U zwOQ_V0HHf9MgI2NZ_{j?fp(GCtE4m`$RDMR}0a{yHo_hMJ0RsnA zZmX2l^ghc-qe#-g!GlJR99i0{%wy^3EE|Ufd(c2D!NlMy+FBa}i|s`UyT~*RunJlC zt_!WKKmmFPW7|mTu03Gbh#RiB=DwSLo-p;K;Og|YhCn+oK`fg#)V$~h5%Ki%zrXvQ zTXt=!)*Zpj^L_j7hvy!1ax4+8w&SYbXT}W(dX;jaWXLA+i9}iP2(W8VyFzK*ix5yJxa`1%X&Nyk-G`|A5Q}?Ui-nnyU%cxP4&!2x` zaZ%ARM<0`y$KU@IY|(~Z>x2+10?;KgnM}^V@M7IC-hBB53EeMBw4;v5W+B;;%|Rjn z7lP2z((>ACul4Ik8>4oCF=NK`=+T3O3somXEoav8$N%C-*EMY1por4al`EcpB$CIL{{iMG2$NgNM<9KZJH-6v>xGoUb zT~$SE;9*^=KA0GaCcppQd$VR8h2ap3waKyyDF{Rq@E_a=c%c@(y$H5JJcO+U9)0PU0^Iv=I#qB#QA(nSmR;^sIV%)gVE7mM|?X}mZOr1Js*72{s`pQu! z9edD(31%_@Lw)DY?T$3!3U8`~9P1h#s*1Y@nYp%y{(t0a;D}aU>@FeR2(;lmH23LS zQjnWhnA2zB;^l2^&4!gwRmtPXh9kxZNzLbTryn$0_W5$WxyfkTmi4RaTN9;y1|wT2 zsBGL;+1S)N`JhP!Il;EpmT#9VOX${!QRDmfD-#{JZs+<%%a&QL)f!2;rjkl}s%q+0 zN$69QTh$cv_zE;{Fw)#$C*x>)`QRbF`lqI3@{EC zEm{nPgv6Sr_3qspXC#irVu;Df$>~=eUb8v=nq-@bh<%h;LPPwP(zw)z4_W3x8Hq}>JPs6*JtTFPIAa3 zW`yNVoRxt+>jfXBBeMYjXE1st9uN)(dzO?S7DFY&id})mPx~Fh3l`Zg@3?)?pn>T) zkLUH*UdI_G4Dh0d53X!U;e!sIeD0Y?ZrM_?bkW9OxM=2))4g6PCpSlyy&rz~(Z!cs z6bJ&EfK@D`wkp5^Vnk`tHQatMJ0W{ z{pRcW^G_#f)#$EXyVem5SX3BQibru0f=}?Y#;xL>`M=n%yVyjHg57E^$o2%E4FHq2%ELAqz{H(j@KM9v|q*gn()N?*b^{WV7|kIgni-C`dGKLwDh8jF5=(%fol5m zpPz;ZJLQzQKAir;Hpq@~pGYLW@w~qD2c| ze)+GZJ;K#B8=G2o-T{>;1{x9b!j#oT*!KzF=QG@ zYb-%ph&YQ2hyfF8gr=ENwVVbVyqog+URyr96@E`EW`m-ImGb`^P!P#64 zRco3~JgN^LKH{>gE(PUQZ`@pO22MHo)Wrn_s~3KJ*+pk9Sh{q3BpmF~Z`VH zuZ`Vt_dQF#{sH|gjjrUu=3 zNp2YSH1453G0d_8%{9|-tG3kMb zi*~AY5(M1<#7rj*wLj=s+yPjBopIR@xU|B)6EJ3S{fKo1OBT!=)vDRC^R9>feARjL z=AWPZ$LnwGPB^lp8L*@%J-5udsgxSo0kU&>;3e>z7$s=iy=zxpT|I^hyjo_xcMDWB zir^Ont_R|h2QpniKxAbT8uY-yl{7_;)bGCU?mIvE@|zh)&ML^wU$%Iusq3?6&MwX^ zHj~M}z46MG*IskMg%{@(^$7SwBL@yVYUaTgU4Hr1*Z&CPKNt$D!JI>5*xXh+rB<(lBB6c)!1IU-U04EAaUPehtQ~q^bo4 zppP612BFD#UA(8cH3zW3knqoG2czc_l#u%G<=CksCR`sHU{eDjUhD|a{D zc;gMfd-!2VQ%&1_@(+*w;lYP=kGpy6w$&?F*EiIcl$G@>?>TyO|Ia`9=$ebKyz`g$ zzWD4bm0Py{=7IZe`Nc1FOE6q|4W zLOF0MfQZ?HUv`F$_q!bY?stQ1&i?|S$@JJ-ke~x?kL~xWA+NS^#hQ)lHqM!Ms;Z?w zCqU$2?rpc08Qt#yS+3)?ypVv_tarzqU7;f}XauBx3CKcaw^0k+TRqWQ zyUR=@v|uv!(}X++KI^@T(iCNYMVWLPP(eI>!G zYP)t+ZQi;yHz&ukoz_??5DdY+s;jSs)X2%nZ)|Q+WNFZV{;QTRgV{J>z~D7927*5UKcI=!T%XHISphc?W2o9lN}*X>qAIk|Vn&QpL314~DReyi??bg;-Pz(Y$P2a5A`CkH@J@#>Q z17IqeVuw}F7BISs?z)jk%Q?p#Gi&mMhwuH(&bk&+QE3A@8bY+D2e2RRVQwo25_bGN zY4RZ_pECENOD-KWXb_@c=<#(G=^T3pi@rtcXzT+z%)h2znxRLK9t*%9p|@&MW&-vW zJUQ2K6T0rW?&5F1z2nwj-v0ADUi!<+k=8a%Q&maPBn5^VIMJgBI~p2F`}X#jh8a%` z7&y4Jq*ySMrlBuhx%!sdetFw3Z~yb3pR1~>RuxI6*F+6lu-aNv)2GdjB!ud^#%be6 z#NvslW$J<)fGpI!3^lMGePm1WSgHicBQ?dNwxYiM_B(go{EOe*e(zhaygqU2pckPau+G(esVJ53LZdfC$;b_7dGHj?<5$?bD zuDkBJHxaiW$daj)ZO{nUWLr^ek4y^;9S~erCDjK315(gFoV0TS&3426{9e9&v1;u) zIX6ELE{e3K#*H4)P`^{4Roc*{V5#(~bU-u_hpl9$EGwZKy3v-5#o_Z=whQ~VGoJuy z2#C|?opSB9SN-knzyIx>f5^1Ipx1Rw`UvmM<4*y1JM-f+WB zpMCt9CU{eEDL=1okK*2`c%-eZ%5YkwP$)(3=~_N?w-u8e-RsprNYzzU(O=wiKuO;r z&GBTf-o--(lr%Q(c4hVR&%U_p=Iidc=|^w8^upH43d=_3AK{BQ@?+vodg8=e^o#Y=~cU>OaFzVfR->I*!1FHoB;Y1?I z({&5TNps{hZk0bg^oL$$z4#LkpU)qU(MIs}hyzqTb=#7qzvu>;VPw1ON6# zLqo%!-@Yg*Ddpe37(RSBvcu5p+qZn{mP%wnc*FV)rKLU3pMQRCULM-L=eIAC$@s8g z!!=FYxOL07t5(lDR)tCPI=39S*?QKI{kYx)ahL*H}@3Op} zOZU*H<(hfASfNzWn6t&)&QJ zwx3+_lWTAO{j*iOYJPS9Z`Lha_~tju!Z~4xyl5;56?OWVrwu48F3S(MG}I=N;=QB6W{F{nYllnv1Wze)s0}Pdxar<`HxkO5K3;cTIG@*t7S5Yj3#ONr?eP zU%m8$%5CfO%ZAQ5V&<%A2T8X6!H1u{{K?XkuJ`RzDp`p^{Z45{&()qE)G^K5HWcP60iWUzgdct4ndg3c$7PpY z`rAjJHf>90J0Xxy&tHH1o`A$mI@lH3`>X>%sO<-s8Nwl*mOKXVpCv<8ID!eYNmRTc z-?L9V^wlRHc=Ph%5V{6f0JmkZDLhDIq`>|l%W2>xh&<_<>#jo-Lg=HlYu5$>K_oy- zNB-l0Yno7CIvIAyNvE7R``FnfJ$m%(->-lFemM8;T{iEuQ!(%!d*rb|ARtR3I9_*z zL?X7cva+c)3Vds8Y8x9GqKQa#U3JCwipJK)-E}*vYIY|R7?6Rwx|+($ok_!8w`zr7 z5$fQ>E?W5MC!e&`Ho?8Esjq>jR#RP7T~pcExU+iK&YhLDtr0uu `~(bU{R)4ugh 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 z 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 Date: Wed, 27 Jul 2022 10:10:08 +0200 Subject: [PATCH 057/282] moved abstract template loader into openpype/pipeline/workfile --- openpype/{lib => pipeline/workfile}/abstract_template_loader.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename openpype/{lib => pipeline/workfile}/abstract_template_loader.py (100%) diff --git a/openpype/lib/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py similarity index 100% rename from openpype/lib/abstract_template_loader.py rename to openpype/pipeline/workfile/abstract_template_loader.py From b1f2831868001431ab5b949cf2a85729a9adfb04 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:12:04 +0200 Subject: [PATCH 058/282] moved 'get_loaders_by_name' to load utils --- openpype/lib/avalon_context.py | 15 --------------- openpype/pipeline/load/__init__.py | 2 ++ openpype/pipeline/load/utils.py | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 316c8ad67e..86902cac56 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -943,21 +943,6 @@ def collect_last_version_repres(asset_entities): return output -@with_pipeline_io -def get_loaders_by_name(): - from openpype.pipeline import discover_loader_plugins - - loaders_by_name = {} - for loader in discover_loader_plugins(): - loader_name = loader.__name__ - if loader_name in loaders_by_name: - raise KeyError( - "Duplicated loader name {} !".format(loader_name) - ) - loaders_by_name[loader_name] = loader - return loaders_by_name - - class BuildWorkfile: """Wrapper for build workfile process. diff --git a/openpype/pipeline/load/__init__.py b/openpype/pipeline/load/__init__.py index e46d9f152b..b6bdd13d50 100644 --- a/openpype/pipeline/load/__init__.py +++ b/openpype/pipeline/load/__init__.py @@ -16,6 +16,7 @@ from .utils import ( switch_container, get_loader_identifier, + get_loaders_by_name, get_representation_path_from_context, get_representation_path, @@ -61,6 +62,7 @@ __all__ = ( "switch_container", "get_loader_identifier", + "get_loaders_by_name", "get_representation_path_from_context", "get_representation_path", diff --git a/openpype/pipeline/load/utils.py b/openpype/pipeline/load/utils.py index fe5102353d..9945e1fce4 100644 --- a/openpype/pipeline/load/utils.py +++ b/openpype/pipeline/load/utils.py @@ -369,6 +369,20 @@ def get_loader_identifier(loader): return loader.__name__ +def get_loaders_by_name(): + from .plugins import discover_loader_plugins + + loaders_by_name = {} + for loader in discover_loader_plugins(): + loader_name = loader.__name__ + if loader_name in loaders_by_name: + raise KeyError( + "Duplicated loader name {} !".format(loader_name) + ) + loaders_by_name[loader_name] = loader + return loaders_by_name + + def _get_container_loader(container): """Return the Loader corresponding to the container""" from .plugins import discover_loader_plugins From b2b6ffe0e4290840fc1ca1b5c98174f2bdfcbfaf Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:13:56 +0200 Subject: [PATCH 059/282] updated 'collect_last_version_repres' with latest develop --- openpype/lib/avalon_context.py | 68 +++++++++++++++------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 86902cac56..4b552d13ed 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -847,7 +847,7 @@ def save_workfile_data_to_doc(workfile_doc, data, dbcon=None): @with_pipeline_io -def collect_last_version_repres(asset_entities): +def collect_last_version_repres(asset_docs): """Collect subsets, versions and representations for asset_entities. Args: @@ -880,64 +880,56 @@ def collect_last_version_repres(asset_entities): ``` """ - if not asset_entities: - return {} + output = {} + if not asset_docs: + return output - asset_entity_by_ids = {asset["_id"]: asset for asset in asset_entities} + asset_docs_by_ids = {asset["_id"]: asset for asset in asset_docs} - subsets = list(legacy_io.find({ - "type": "subset", - "parent": {"$in": list(asset_entity_by_ids.keys())} - })) + project_name = legacy_io.active_project() + subsets = list(get_subsets( + project_name, asset_ids=asset_docs_by_ids.keys() + )) subset_entity_by_ids = {subset["_id"]: subset for subset in subsets} - sorted_versions = list(legacy_io.find({ - "type": "version", - "parent": {"$in": list(subset_entity_by_ids.keys())} - }).sort("name", -1)) + last_version_by_subset_id = get_last_versions( + project_name, subset_entity_by_ids.keys() + ) + last_version_docs_by_id = { + version["_id"]: version + for version in last_version_by_subset_id.values() + } + repre_docs = get_representations( + project_name, version_ids=last_version_docs_by_id.keys() + ) - subset_id_with_latest_version = [] - last_versions_by_id = {} - for version in sorted_versions: - subset_id = version["parent"] - if subset_id in subset_id_with_latest_version: - continue - subset_id_with_latest_version.append(subset_id) - last_versions_by_id[version["_id"]] = version + for repre_doc in repre_docs: + version_id = repre_doc["parent"] + version_doc = last_version_docs_by_id[version_id] - repres = legacy_io.find({ - "type": "representation", - "parent": {"$in": list(last_versions_by_id.keys())} - }) + subset_id = version_doc["parent"] + subset_doc = subset_entity_by_ids[subset_id] - output = {} - for repre in repres: - version_id = repre["parent"] - version = last_versions_by_id[version_id] - - subset_id = version["parent"] - subset = subset_entity_by_ids[subset_id] - - asset_id = subset["parent"] - asset = asset_entity_by_ids[asset_id] + asset_id = subset_doc["parent"] + asset_doc = asset_docs_by_ids[asset_id] if asset_id not in output: output[asset_id] = { - "asset_entity": asset, + "asset_entity": asset_doc, "subsets": {} } if subset_id not in output[asset_id]["subsets"]: output[asset_id]["subsets"][subset_id] = { - "subset_entity": subset, + "subset_entity": subset_doc, "version": { - "version_entity": version, + "version_entity": version_doc, "repres": [] } } output[asset_id]["subsets"][subset_id]["version"]["repres"].append( - repre + repre_doc ) return output From 9b4b44ef3bdf490fca2a4df0f3451143a09e555c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:17:26 +0200 Subject: [PATCH 060/282] moved build template code into workfile --- openpype/{lib => pipeline/workfile}/build_template.py | 0 openpype/{lib => pipeline/workfile}/build_template_exceptions.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename openpype/{lib => pipeline/workfile}/build_template.py (100%) rename openpype/{lib => pipeline/workfile}/build_template_exceptions.py (100%) diff --git a/openpype/lib/build_template.py b/openpype/pipeline/workfile/build_template.py similarity index 100% rename from openpype/lib/build_template.py rename to openpype/pipeline/workfile/build_template.py diff --git a/openpype/lib/build_template_exceptions.py b/openpype/pipeline/workfile/build_template_exceptions.py similarity index 100% rename from openpype/lib/build_template_exceptions.py rename to openpype/pipeline/workfile/build_template_exceptions.py From 6462bf15d04ad53eaed484069e70f2c2312f0a2f Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:24:16 +0200 Subject: [PATCH 061/282] fixed imports --- .../workfile/abstract_template_loader.py | 24 ++++++++++--------- openpype/pipeline/workfile/build_template.py | 4 ++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index e296e3207f..e95b89b518 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -4,23 +4,25 @@ from abc import ABCMeta, abstractmethod import traceback import six - -from openpype.settings import get_project_settings -from openpype.lib import Anatomy, get_linked_assets, get_loaders_by_name -from openpype.api import PypeLogger as Logger -from openpype.pipeline import legacy_io, load - +import logging from functools import reduce -from openpype.lib.build_template_exceptions import ( +from openpype.settings import get_project_settings +from openpype.lib import get_linked_assets, PypeLogger as Logger +from openpype.pipeline import legacy_io, Anatomy +from openpype.pipeline.load import ( + get_loaders_by_name, + get_representation_context, + load_with_repre_context, +) + +from .build_template_exceptions import ( TemplateAlreadyImported, TemplateLoadingFailed, TemplateProfileNotFound, TemplateNotFound ) -import logging - log = logging.getLogger(__name__) @@ -289,8 +291,8 @@ class AbstractTemplateLoader: pass def load(self, placeholder, loaders_by_name, last_representation): - repre = load.get_representation_context(last_representation) - return load.load_with_repre_context( + repre = get_representation_context(last_representation) + return load_with_repre_context( loaders_by_name[placeholder.loader], repre, options=parse_loader_args(placeholder.data['loader_args'])) diff --git a/openpype/pipeline/workfile/build_template.py b/openpype/pipeline/workfile/build_template.py index 7f749cbec2..f4b57218fb 100644 --- a/openpype/pipeline/workfile/build_template.py +++ b/openpype/pipeline/workfile/build_template.py @@ -1,6 +1,6 @@ -from openpype.pipeline import registered_host -from openpype.lib import classes_from_module from importlib import import_module +from openpype.lib import classes_from_module +from openpype.pipeline import registered_host from .abstract_template_loader import ( AbstractPlaceholder, From 5dfb12a217f24e5551ec3f4a982823254efdb00e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:24:44 +0200 Subject: [PATCH 062/282] logger is created dynamically on demand and is using class name --- openpype/pipeline/workfile/abstract_template_loader.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index e95b89b518..27823479cf 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -72,6 +72,7 @@ class AbstractTemplateLoader: """ def __init__(self, placeholder_class): + self._log = None self.loaders_by_name = get_loaders_by_name() self.current_asset = legacy_io.Session["AVALON_ASSET"] @@ -91,8 +92,6 @@ class AbstractTemplateLoader: .get("type") ) - self.log = Logger().get_logger("BUILD TEMPLATE") - self.log.info( "BUILDING ASSET FROM TEMPLATE :\n" "Starting templated build for {asset} in {project}\n\n" @@ -112,6 +111,12 @@ class AbstractTemplateLoader: "There is no registered loaders. No assets will be loaded") return + @property + def log(self): + if self._log is None: + self._log = Logger.get_logger(self.__class__.__name__) + return self._log + def template_already_imported(self, err_msg): """In case template was already loaded. Raise the error as a default action. From 764207d033fc049f6726f901a99732c928595768 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:25:04 +0200 Subject: [PATCH 063/282] fix missing import 'get_loaders_by_name' --- openpype/lib/avalon_context.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 4b552d13ed..e60dbb9e8f 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -992,6 +992,9 @@ class BuildWorkfile: ... }] """ + + from openpype.pipeline.load import get_loaders_by_name + # Get current asset name and entity project_name = legacy_io.active_project() current_asset_name = legacy_io.Session["AVALON_ASSET"] From fe38df50bff954993570cd113371044dde4a5e43 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:26:18 +0200 Subject: [PATCH 064/282] removed 'get_loaders_by_name' from openpype lib init file --- openpype/lib/__init__.py | 2 -- openpype/pipeline/workfile/__init__.py | 0 2 files changed, 2 deletions(-) create mode 100644 openpype/pipeline/workfile/__init__.py diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index f4efffd726..fb52a9aca7 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -135,7 +135,6 @@ from .avalon_context import ( create_workfile_doc, save_workfile_data_to_doc, get_workfile_doc, - get_loaders_by_name, BuildWorkfile, @@ -307,7 +306,6 @@ __all__ = [ "create_workfile_doc", "save_workfile_data_to_doc", "get_workfile_doc", - "get_loaders_by_name", "BuildWorkfile", diff --git a/openpype/pipeline/workfile/__init__.py b/openpype/pipeline/workfile/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From c9ac330e2ebedc6e9900e0d2e6207a20326d0139 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:31:18 +0200 Subject: [PATCH 065/282] fixed imports in maya --- openpype/hosts/maya/api/menu.py | 6 +++--- openpype/hosts/maya/api/template_loader.py | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/api/menu.py b/openpype/hosts/maya/api/menu.py index c0bad7092f..833fbae881 100644 --- a/openpype/hosts/maya/api/menu.py +++ b/openpype/hosts/maya/api/menu.py @@ -8,12 +8,12 @@ import maya.cmds as cmds from openpype.api import BuildWorkfile -from openpype.lib.build_template import ( +from openpype.settings import get_project_settings +from openpype.pipeline import legacy_io +from openpype.pipeline.workfile.build_template import ( build_workfile_template, update_workfile_template ) -from openpype.settings import get_project_settings -from openpype.pipeline import legacy_io from openpype.tools.utils import host_tools from openpype.hosts.maya.api import lib diff --git a/openpype/hosts/maya/api/template_loader.py b/openpype/hosts/maya/api/template_loader.py index c7946b6ad3..6b225442e7 100644 --- a/openpype/hosts/maya/api/template_loader.py +++ b/openpype/hosts/maya/api/template_loader.py @@ -1,11 +1,13 @@ from maya import cmds from openpype.pipeline import legacy_io -from openpype.lib.abstract_template_loader import ( +from openpype.pipeline.workfile.abstract_template_loader import ( AbstractPlaceholder, AbstractTemplateLoader ) -from openpype.lib.build_template_exceptions import TemplateAlreadyImported +from openpype.pipeline.workfile.build_template_exceptions import ( + TemplateAlreadyImported +) PLACEHOLDER_SET = 'PLACEHOLDERS_SET' From 1e8cf2a6ea87ded1131d5d3012cdd5980dc2f183 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 27 Jul 2022 10:36:04 +0200 Subject: [PATCH 066/282] make sure '_log' attribute is available before abc init --- openpype/pipeline/workfile/abstract_template_loader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 27823479cf..3d942a0bdd 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -71,9 +71,9 @@ class AbstractTemplateLoader: as placeholders. Depending on current host """ - def __init__(self, placeholder_class): - self._log = None + _log = None + def __init__(self, placeholder_class): self.loaders_by_name = get_loaders_by_name() self.current_asset = legacy_io.Session["AVALON_ASSET"] self.project_name = legacy_io.Session["AVALON_PROJECT"] From 6bb28d16df22e4d5c4cf6e763a85a545ba6da833 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 28 Jul 2022 11:53:51 +0200 Subject: [PATCH 067/282] fix build template and added few comments --- .../workfile/abstract_template_loader.py | 30 +++++++++++++------ openpype/pipeline/workfile/build_template.py | 9 +++++- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 3d942a0bdd..00bc8f15a7 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -7,6 +7,7 @@ import six import logging from functools import reduce +from openpype.client import get_asset_by_name from openpype.settings import get_project_settings from openpype.lib import get_linked_assets, PypeLogger as Logger from openpype.pipeline import legacy_io, Anatomy @@ -74,18 +75,25 @@ class AbstractTemplateLoader: _log = None def __init__(self, placeholder_class): + # TODO template loader should expect host as and argument + # - host have all responsibility for most of code (also provide + # placeholder class) + # - also have responsibility for current context + # - this won't work in DCCs where multiple workfiles with + # different contexts can be opened at single time + # - template loader should have ability to change context + project_name = legacy_io.active_project() + asset_name = legacy_io.Session["AVALON_ASSET"] + self.loaders_by_name = get_loaders_by_name() - self.current_asset = legacy_io.Session["AVALON_ASSET"] - self.project_name = legacy_io.Session["AVALON_PROJECT"] + self.current_asset = asset_name + self.project_name = project_name self.host_name = legacy_io.Session["AVALON_APP"] self.task_name = legacy_io.Session["AVALON_TASK"] self.placeholder_class = placeholder_class - self.current_asset_docs = legacy_io.find_one({ - "type": "asset", - "name": self.current_asset - }) + self.current_asset_doc = get_asset_by_name(project_name, asset_name) self.task_type = ( - self.current_asset_docs + self.current_asset_doc .get("data", {}) .get("tasks", {}) .get(self.task_name, {}) @@ -218,7 +226,7 @@ class AbstractTemplateLoader: loaders_by_name = self.loaders_by_name current_asset = self.current_asset linked_assets = [asset['name'] for asset - in get_linked_assets(self.current_asset_docs)] + in get_linked_assets(self.current_asset_doc)] ignored_ids = ignored_ids or [] placeholders = self.get_placeholders() @@ -270,7 +278,11 @@ class AbstractTemplateLoader: self.postload(placeholder) def get_placeholder_representations( - self, placeholder, current_asset, linked_assets): + self, placeholder, current_asset, linked_assets + ): + # TODO This approach must be changed. Placeholders should return + # already prepared data and not query them here. + # - this is impossible to handle using query functions placeholder_db_filters = placeholder.convert_to_db_filters( current_asset, linked_assets) diff --git a/openpype/pipeline/workfile/build_template.py b/openpype/pipeline/workfile/build_template.py index f4b57218fb..df6fe3514a 100644 --- a/openpype/pipeline/workfile/build_template.py +++ b/openpype/pipeline/workfile/build_template.py @@ -1,5 +1,6 @@ from importlib import import_module from openpype.lib import classes_from_module +from openpype.host import HostBase from openpype.pipeline import registered_host from .abstract_template_loader import ( @@ -35,7 +36,13 @@ def update_workfile_template(args): def build_template_loader(): - host_name = registered_host().__name__.partition('.')[2] + # TODO refactor to use advantage of 'HostBase' and don't import dynamically + # - hosts should have methods that gives option to return builders + host = registered_host() + if isinstance(host, HostBase): + host_name = host.name + else: + host_name = host.__name__.partition('.')[2] module_path = _module_path_format.format(host=host_name) module = import_module(module_path) if not module: From 628833be97308401e3279929a9866da03c6d8d9d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 28 Jul 2022 14:48:37 +0200 Subject: [PATCH 068/282] flame: adding timewarp effect scraping --- openpype/hosts/flame/api/lib.py | 153 ++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index d59308ad6c..02481a1d2e 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -1,14 +1,16 @@ import sys import os import re +import sys import json import pickle import clique import tempfile +import traceback import itertools import contextlib import xml.etree.cElementTree as cET -from copy import deepcopy +from copy import deepcopy, copy from xml.etree import ElementTree as ET from pprint import pformat from .constants import ( @@ -266,7 +268,7 @@ def get_current_sequence(selection): def rescan_hooks(): import flame try: - flame.execute_shortcut('Rescan Python Hooks') + flame.execute_shortcut("Rescan Python Hooks") except Exception: pass @@ -1082,21 +1084,21 @@ class MediaInfoFile(object): xml_data (ET.Element): clip data """ try: - for out_track in xml_data.iter('track'): - for out_feed in out_track.iter('feed'): + for out_track in xml_data.iter("track"): + for out_feed in out_track.iter("feed"): # start frame out_feed_nb_ticks_obj = out_feed.find( - 'startTimecode/nbTicks') + "startTimecode/nbTicks") self.start_frame = out_feed_nb_ticks_obj.text # fps out_feed_fps_obj = out_feed.find( - 'startTimecode/rate') + "startTimecode/rate") self.fps = out_feed_fps_obj.text # drop frame mode out_feed_drop_mode_obj = out_feed.find( - 'startTimecode/dropMode') + "startTimecode/dropMode") self.drop_mode = out_feed_drop_mode_obj.text break except Exception as msg: @@ -1118,8 +1120,143 @@ class MediaInfoFile(object): tree = cET.ElementTree(xml_element_data) tree.write( fpath, xml_declaration=True, - method='xml', encoding='UTF-8' + method="xml", encoding="UTF-8" ) except IOError as error: raise IOError( "Not able to write data to file: {}".format(error)) + + +class TimeEffectMetadata(object): + log = log + temp_setup_path = "/var/tmp/temp_timewarp_setup.timewarp_node" + _data = {} + _retime_modes = { + 0: "speed", + 1: "timewarp", + 2: "duration" + } + + def __init__(self, segment=None, logger=None): + if logger: + self.log = logger + if segment: + self._data = self._get_metadata(segment) + + def _get_metadata(self, segment): + effects = segment.effects or [] + for effect in effects: + if effect.type == "Timewarp": + effect.save_setup(self.temp_setup_path) + + self._data = self._get_attributes_from_xml() + os.remove(self.temp_setup_path) + + def _get_attributes_from_xml(self): + with open(self.temp_setup_path, "r") as tw_setup_file: + tw_setup_string = tw_setup_file.read() + tw_setup_file.close() + + tw_setup_xml = ET.fromstring(tw_setup_string) + tw_setup = self._dictify(tw_setup_xml) + # pprint(tw_setup) + try: + tw_setup_state = tw_setup["Setup"]["State"][0] + mode = int( + tw_setup_state["TW_RetimerMode"][0]["_text"] + ) + r_data = { + "type": self._retime_modes[mode], + "effectStart": int( + tw_setup["Setup"]["Base"][0]["Range"][0]["Start"]), + "effectEnd": int( + tw_setup["Setup"]["Base"][0]["Range"][0]["End"]) + } + + if mode == 0: # speed + r_data[self._retime_modes[mode]] = int( + tw_setup_state["TW_Speed"] + [0]["Channel"][0]["Value"][0]["_text"] + ) / 100 + elif mode == 1: # timewarp + print("timing") + r_data[self._retime_modes[mode]] = self._get_anim_keys( + tw_setup_state["TW_Timing"] + ) + elif mode == 2: # duration + r_data[self._retime_modes[mode]] = { + "start": { + "source": int( + tw_setup_state["TW_DurationTiming"][0]["Channel"] + [0]["KFrames"][0]["Key"][0]["Value"][0]["_text"] + ), + "timeline": int( + tw_setup_state["TW_DurationTiming"][0]["Channel"] + [0]["KFrames"][0]["Key"][0]["Frame"][0]["_text"] + ) + }, + "end": { + "source": int( + tw_setup_state["TW_DurationTiming"][0]["Channel"] + [0]["KFrames"][0]["Key"][1]["Value"][0]["_text"] + ), + "timeline": int( + tw_setup_state["TW_DurationTiming"][0]["Channel"] + [0]["KFrames"][0]["Key"][1]["Frame"][0]["_text"] + ) + } + } + except Exception: + lines = traceback.format_exception(*sys.exc_info()) + self.log.error("\n".join(lines)) + return + + return r_data + + def _get_anim_keys(self, setup_cat, index=None): + return_data = { + "extrapolation": ( + setup_cat[0]["Channel"][0]["Extrap"][0]["_text"] + ), + "animKeys": [] + } + for key in setup_cat[0]["Channel"][0]["KFrames"][0]["Key"]: + if index and int(key["Index"]) != index: + continue + key_data = { + "source": float(key["Value"][0]["_text"]), + "timeline": float(key["Frame"][0]["_text"]), + "index": int(key["Index"]), + "curveMode": key["CurveMode"][0]["_text"], + "curveOrder": key["CurveOrder"][0]["_text"] + } + if key.get("TangentMode"): + key_data["tangentMode"] = key["TangentMode"][0]["_text"] + + return_data["animKeys"].append(key_data) + + return return_data + + def _dictify(self, xml_, root=True): + """ Convert xml object to dictionary + + Args: + xml_ (xml.etree.ElementTree.Element): xml data + root (bool, optional): is root available. Defaults to True. + + Returns: + dict: dictionarized xml + """ + + if root: + return {xml_.tag: self._dictify(xml_, False)} + + d = copy(xml_.attrib) + if xml_.text: + d["_text"] = xml_.text + + for x in xml_.findall("./*"): + if x.tag not in d: + d[x.tag] = [] + d[x.tag].append(self._dictify(x, False)) + return d From 2998253832daf43f62fc901de6dd11eccb2708fd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 28 Jul 2022 14:58:43 +0200 Subject: [PATCH 069/282] flame: adding property to return data --- openpype/hosts/flame/api/lib.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index 02481a1d2e..a02acd85a7 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -1129,7 +1129,6 @@ class MediaInfoFile(object): class TimeEffectMetadata(object): log = log - temp_setup_path = "/var/tmp/temp_timewarp_setup.timewarp_node" _data = {} _retime_modes = { 0: "speed", @@ -1137,23 +1136,34 @@ class TimeEffectMetadata(object): 2: "duration" } - def __init__(self, segment=None, logger=None): + def __init__(self, segment, logger=None): if logger: self.log = logger - if segment: - self._data = self._get_metadata(segment) + + self._data = self._get_metadata(segment) + + @property + def data(self): + """ Returns timewarp effect data + + Returns: + dict: retime data + """ + return self._data def _get_metadata(self, segment): effects = segment.effects or [] for effect in effects: if effect.type == "Timewarp": - effect.save_setup(self.temp_setup_path) + with maintained_temp_file_path(".timewarp_node") as tmp_path: + self.log.info("Temp File: {}".format(tmp_path)) + effect.save_setup(tmp_path) + return self._get_attributes_from_xml(tmp_path) - self._data = self._get_attributes_from_xml() - os.remove(self.temp_setup_path) + return {} - def _get_attributes_from_xml(self): - with open(self.temp_setup_path, "r") as tw_setup_file: + def _get_attributes_from_xml(self, tmp_path): + with open(tmp_path, "r") as tw_setup_file: tw_setup_string = tw_setup_file.read() tw_setup_file.close() From 7f9948eaad87d144db2fc58c5083798ebf34482f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 28 Jul 2022 15:09:06 +0200 Subject: [PATCH 070/282] flame: adding timewarp class to api --- openpype/hosts/flame/api/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/flame/api/__init__.py b/openpype/hosts/flame/api/__init__.py index 2c461e5f16..76c1c93379 100644 --- a/openpype/hosts/flame/api/__init__.py +++ b/openpype/hosts/flame/api/__init__.py @@ -30,7 +30,8 @@ from .lib import ( maintained_temp_file_path, get_clip_segment, get_batch_group_from_desktop, - MediaInfoFile + MediaInfoFile, + TimeEffectMetadata ) from .utils import ( setup, @@ -107,6 +108,7 @@ __all__ = [ "get_clip_segment", "get_batch_group_from_desktop", "MediaInfoFile", + "TimeEffectMetadata", # pipeline "install", From 42fa3dd2097cf7d1b9c9442b042600981be64bb9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 28 Jul 2022 15:09:25 +0200 Subject: [PATCH 071/282] flame: implementing timewarpmetadata class --- openpype/hosts/flame/otio/flame_export.py | 25 +++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index 1e4ef866ed..a111176e29 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -275,7 +275,7 @@ def create_otio_reference(clip_data, fps=None): def create_otio_clip(clip_data): - from openpype.hosts.flame.api import MediaInfoFile + from openpype.hosts.flame.api import MediaInfoFile, TimeEffectMetadata segment = clip_data["PySegment"] @@ -284,14 +284,27 @@ def create_otio_clip(clip_data): media_timecode_start = media_info.start_frame media_fps = media_info.fps + # Timewarp metadata + tw_data = TimeEffectMetadata(segment, logger=log).data + log.debug("__ tw_data: {}".format(tw_data)) + # define first frame first_frame = media_timecode_start or utils.get_frame_from_filename( clip_data["fpath"]) or 0 _clip_source_in = int(clip_data["source_in"]) _clip_source_out = int(clip_data["source_out"]) + _clip_source_duration = clip_data["source_duration"] + _clip_record_in = clip_data["record_in"] + _clip_record_out = clip_data["record_out"] _clip_record_duration = int(clip_data["record_duration"]) + log.debug("_ first_frame: {}".format(first_frame)) + log.debug("_ _clip_source_in: {}".format(_clip_source_in)) + log.debug("_ _clip_source_out: {}".format(_clip_source_out)) + log.debug("_ _clip_record_in: {}".format(_clip_record_in)) + log.debug("_ _clip_record_out: {}".format(_clip_record_out)) + # first solve if the reverse timing speed = 1 if clip_data["source_in"] > clip_data["source_out"]: @@ -307,13 +320,17 @@ def create_otio_clip(clip_data): # secondly check if any change of speed if source_duration != _clip_record_duration: retime_speed = float(source_duration) / float(_clip_record_duration) - log.debug("_ retime_speed: {}".format(retime_speed)) + log.debug("_ calculated speed: {}".format(retime_speed)) speed *= retime_speed - log.debug("_ source_in: {}".format(source_in)) - log.debug("_ source_out: {}".format(source_out)) + # get speed from metadata if available + if tw_data.get("speed"): + speed = tw_data["speed"] + log.debug("_ metadata speed: {}".format(speed)) + log.debug("_ speed: {}".format(speed)) log.debug("_ source_duration: {}".format(source_duration)) + log.debug("_ _clip_source_duration: {}".format(_clip_source_duration)) log.debug("_ _clip_record_duration: {}".format(_clip_record_duration)) # create media reference From 009d7fc1fb765f18cadf1782bd66a5c3b95c38ee Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 28 Jul 2022 15:18:07 +0200 Subject: [PATCH 072/282] flame: speed should be float --- openpype/hosts/flame/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index a02acd85a7..a5ae3c4468 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -1184,7 +1184,7 @@ class TimeEffectMetadata(object): } if mode == 0: # speed - r_data[self._retime_modes[mode]] = int( + r_data[self._retime_modes[mode]] = float( tw_setup_state["TW_Speed"] [0]["Channel"][0]["Value"][0]["_text"] ) / 100 From 8eb5c1ccb30c6fb7bfb6cddd2eb82d3697a652c1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 28 Jul 2022 15:37:16 +0200 Subject: [PATCH 073/282] flame: more frame debug printing --- openpype/hosts/flame/otio/flame_export.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/flame/otio/flame_export.py b/openpype/hosts/flame/otio/flame_export.py index a111176e29..6d6b33d2a1 100644 --- a/openpype/hosts/flame/otio/flame_export.py +++ b/openpype/hosts/flame/otio/flame_export.py @@ -289,16 +289,20 @@ def create_otio_clip(clip_data): log.debug("__ tw_data: {}".format(tw_data)) # define first frame - first_frame = media_timecode_start or utils.get_frame_from_filename( - clip_data["fpath"]) or 0 + file_first_frame = utils.get_frame_from_filename( + clip_data["fpath"]) + if file_first_frame: + file_first_frame = int(file_first_frame) + + first_frame = media_timecode_start or file_first_frame or 0 _clip_source_in = int(clip_data["source_in"]) _clip_source_out = int(clip_data["source_out"]) - _clip_source_duration = clip_data["source_duration"] _clip_record_in = clip_data["record_in"] _clip_record_out = clip_data["record_out"] _clip_record_duration = int(clip_data["record_duration"]) + log.debug("_ file_first_frame: {}".format(file_first_frame)) log.debug("_ first_frame: {}".format(first_frame)) log.debug("_ _clip_source_in: {}".format(_clip_source_in)) log.debug("_ _clip_source_out: {}".format(_clip_source_out)) @@ -315,6 +319,15 @@ def create_otio_clip(clip_data): source_in = _clip_source_in - int(first_frame) source_out = _clip_source_out - int(first_frame) + log.debug("_ source_in: {}".format(source_in)) + log.debug("_ source_out: {}".format(source_out)) + + if file_first_frame: + log.debug("_ file_source_in: {}".format( + file_first_frame + source_in)) + log.debug("_ file_source_in: {}".format( + file_first_frame + source_out)) + source_duration = (source_out - source_in + 1) # secondly check if any change of speed @@ -330,7 +343,6 @@ def create_otio_clip(clip_data): log.debug("_ speed: {}".format(speed)) log.debug("_ source_duration: {}".format(source_duration)) - log.debug("_ _clip_source_duration: {}".format(_clip_source_duration)) log.debug("_ _clip_record_duration: {}".format(_clip_record_duration)) # create media reference From 2d601d051a9b59509c6af159c06f8424591af444 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 16:42:54 +0200 Subject: [PATCH 074/282] give ability to query by representation context and regex --- openpype/client/entities.py | 108 +++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 14 deletions(-) diff --git a/openpype/client/entities.py b/openpype/client/entities.py index dd5d831ecf..57c38784b0 100644 --- a/openpype/client/entities.py +++ b/openpype/client/entities.py @@ -7,6 +7,7 @@ that has project name as a context (e.g. on 'ProjectEntity'?). """ import os +import re import collections import six @@ -1035,17 +1036,70 @@ def get_representation_by_name( return conn.find_one(query_filter, _prepare_fields(fields)) +def _flatten_dict(data): + flatten_queue = collections.deque() + flatten_queue.append(data) + output = {} + while flatten_queue: + item = flatten_queue.popleft() + for key, value in item.items(): + if not isinstance(value, dict): + output[key] = value + continue + + tmp = {} + for subkey, subvalue in value.items(): + new_key = "{}.{}".format(key, subkey) + tmp[new_key] = subvalue + flatten_queue.append(tmp) + return output + + +def _regex_filters(filters): + output = [] + for key, value in filters.items(): + regexes = [] + a_values = [] + if isinstance(value, re.Pattern): + regexes.append(value) + elif isinstance(value, (list, tuple, set)): + for item in value: + if isinstance(item, re.Pattern): + regexes.append(item) + else: + a_values.append(item) + else: + a_values.append(value) + + key_filters = [] + if len(a_values) == 1: + key_filters.append({key: a_values[0]}) + elif a_values: + key_filters.append({key: {"$in": a_values}}) + + for regex in regexes: + key_filters.append({key: {"$regex": regex}}) + + if len(key_filters) == 1: + output.append(key_filters[0]) + else: + output.append({"$or": key_filters}) + + return output + + def _get_representations( project_name, representation_ids, representation_names, version_ids, - extensions, + context_filters, names_by_version_ids, standard, archived, fields ): + default_output = [] repre_types = [] if standard: repre_types.append("representation") @@ -1053,7 +1107,7 @@ def _get_representations( repre_types.append("archived_representation") if not repre_types: - return [] + return default_output if len(repre_types) == 1: query_filter = {"type": repre_types[0]} @@ -1063,25 +1117,21 @@ def _get_representations( if representation_ids is not None: representation_ids = _convert_ids(representation_ids) if not representation_ids: - return [] + return default_output query_filter["_id"] = {"$in": representation_ids} if representation_names is not None: if not representation_names: - return [] + return default_output query_filter["name"] = {"$in": list(representation_names)} if version_ids is not None: version_ids = _convert_ids(version_ids) if not version_ids: - return [] + return default_output query_filter["parent"] = {"$in": version_ids} - if extensions is not None: - if not extensions: - return [] - query_filter["context.ext"] = {"$in": list(extensions)} - + or_queries = [] if names_by_version_ids is not None: or_query = [] for version_id, names in names_by_version_ids.items(): @@ -1091,8 +1141,35 @@ def _get_representations( "name": {"$in": list(names)} }) if not or_query: + return default_output + or_queries.append(or_query) + + if context_filters is not None: + if not context_filters: return [] - query_filter["$or"] = or_query + _flatten_filters = _flatten_dict(context_filters) + flatten_filters = {} + for key, value in _flatten_filters.items(): + if not key.startswith("context"): + key = "context.{}".format(key) + flatten_filters[key] = value + + for item in _regex_filters(flatten_filters): + for key, value in item.items(): + if key == "$or": + or_queries.append(value) + else: + query_filter[key] = value + + if len(or_queries) == 1: + query_filter["$or"] = or_queries[0] + elif or_queries: + and_query = [] + for or_query in or_queries: + if isinstance(or_query, list): + or_query = {"$or": or_query} + and_query.append(or_query) + query_filter["$and"] = and_query conn = get_project_connection(project_name) @@ -1104,7 +1181,7 @@ def get_representations( representation_ids=None, representation_names=None, version_ids=None, - extensions=None, + context_filters=None, names_by_version_ids=None, archived=False, standard=True, @@ -1122,8 +1199,8 @@ def get_representations( as filter. Filter ignored if 'None' is passed. version_ids (Iterable[str]): Subset ids used as parent filter. Filter ignored if 'None' is passed. - extensions (Iterable[str]): Filter by extension of main representation - file (without dot). + context_filters (Dict[str, List[str, re.Pattern]]): Filter by + representation context fields. names_by_version_ids (dict[ObjectId, list[str]]): Complex filtering using version ids and list of names under the version. archived (bool): Output will also contain archived representations. @@ -1140,6 +1217,7 @@ def get_representations( representation_names=representation_names, version_ids=version_ids, extensions=extensions, + context_filters=context_filters, names_by_version_ids=names_by_version_ids, standard=True, archived=archived, @@ -1153,6 +1231,7 @@ def get_archived_representations( representation_names=None, version_ids=None, extensions=None, + context_filters=None, names_by_version_ids=None, fields=None ): @@ -1185,6 +1264,7 @@ def get_archived_representations( representation_names=representation_names, version_ids=version_ids, extensions=extensions, + context_filters=context_filters, names_by_version_ids=names_by_version_ids, standard=False, archived=True, From 5c8eac6b6357fa80859ffbed45be41cf8ae106da Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 29 Jul 2022 17:07:57 +0200 Subject: [PATCH 075/282] OP-3405 - replaced find with get_representations --- .../modules/sync_server/sync_server_module.py | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index 4027561d22..81aff9368f 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -25,6 +25,8 @@ from .providers import lib from .utils import time_function, SyncStatus, SiteAlreadyPresentError +from openpype.client import get_representations + log = PypeLogger.get_logger("SyncServer") @@ -344,6 +346,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): "files.sites.name": site_name } + # TODO currently not possible to replace with get_representations representations = list( self.connection.database[collection].find(query)) if not representations: @@ -391,12 +394,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): """ self.log.debug("Validation of {} for {} started".format(collection, site_name)) - query = { - "type": "representation" - } - - representations = list( - self.connection.database[collection].find(query)) + representations = list(get_representations(collection)) if not representations: self.log.debug("No repre found") return @@ -1593,14 +1591,11 @@ class SyncServerModule(OpenPypeModule, ITrayModule): not 'force' ValueError - other errors (repre not found, misconfiguration) """ - query = { - "_id": ObjectId(representation_id) - } - - representation = self.connection.database[collection].find_one(query) - if not representation: + representations = get_representations(collection, [representation_id]) + if not representations: raise ValueError("Representation {} not found in {}". format(representation_id, collection)) + representation = representations[0] if side and site_name: raise ValueError("Misconfiguration, only one of side and " + "site_name arguments should be passed.") @@ -1808,18 +1803,15 @@ class SyncServerModule(OpenPypeModule, ITrayModule): provider_name = self.get_provider_for_site(site=site_name) if provider_name == 'local_drive': - query = { - "_id": ObjectId(representation_id) - } - - representation = list( - self.connection.database[collection].find(query)) - if not representation: + representations = list(get_representations(collection, + [representation_id], + fields=["files"])) + if not representations: self.log.debug("No repre {} found".format( representation_id)) return - representation = representation.pop() + representation = representations.pop() local_file_path = '' for file in representation.get("files"): local_file_path = self.get_local_file_path(collection, From c65dd9747f5197868a9153fc109915ed654122ab Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 17:15:13 +0200 Subject: [PATCH 076/282] added new method 'get_representations' to get representations from placeholder --- .../workfile/abstract_template_loader.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 00bc8f15a7..0a422f5cca 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -456,8 +456,25 @@ class AbstractPlaceholder: @abstractmethod def clean(self): - """Clean placeholder from hierarchy after loading assets. + """Clean placeholder from hierarchy after loading assets.""" + + pass + + @abstractmethod + def get_representations(self, current_asset, linked_assets): + """Query representations based on placeholder data. + + Args: + current_asset (str): Name of current + context asset. + linked_assets (List[str]): Names of assets + linked to current context asset. + + Returns: + Iterable[Dict[str, Any]]: Representations that are matching + placeholder filters. """ + pass @abstractmethod From da8e25f4a1b7ea89bf9c7cac62c8a3ea10fbb9e6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 17:16:23 +0200 Subject: [PATCH 077/282] use 'get_representations' instead of 'convert_to_db_filters' --- .../workfile/abstract_template_loader.py | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 0a422f5cca..a2505c061e 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -280,19 +280,16 @@ class AbstractTemplateLoader: def get_placeholder_representations( self, placeholder, current_asset, linked_assets ): - # TODO This approach must be changed. Placeholders should return - # already prepared data and not query them here. - # - this is impossible to handle using query functions - placeholder_db_filters = placeholder.convert_to_db_filters( + placeholder_representations = placeholder.get_representations( current_asset, - linked_assets) - # get representation by assets - for db_filter in placeholder_db_filters: - placeholder_representations = list(legacy_io.find(db_filter)) - for representation in reduce(update_representations, - placeholder_representations, - dict()).values(): - yield representation + linked_assets + ) + for repre_doc in reduce( + update_representations, + placeholder_representations, + dict() + ).values(): + yield repre_doc def load_data_is_incorrect( self, placeholder, last_representation, ignored_ids): From c944ae35c9848045cfb73ccfc1b93f30f7af2989 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 29 Jul 2022 17:17:03 +0200 Subject: [PATCH 078/282] OP-3405 - replaced find with get_representation_by_id --- openpype/modules/sync_server/tray/models.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openpype/modules/sync_server/tray/models.py b/openpype/modules/sync_server/tray/models.py index 6d1e85c17a..a97797c920 100644 --- a/openpype/modules/sync_server/tray/models.py +++ b/openpype/modules/sync_server/tray/models.py @@ -11,6 +11,7 @@ from openpype.tools.utils.delegates import pretty_timestamp from openpype.lib import PypeLogger from openpype.api import get_local_site_id +from openpype.client import get_representation_by_id from . import lib @@ -919,8 +920,7 @@ class SyncRepresentationSummaryModel(_SyncRepresentationModel): repre_id = self.data(index, Qt.UserRole) - representation = list(self.dbcon.find({"type": "representation", - "_id": repre_id})) + representation = get_representation_by_id(self.project, repre_id) if representation: self.sync_server.update_db(self.project, None, None, representation.pop(), @@ -1357,11 +1357,10 @@ class SyncRepresentationDetailModel(_SyncRepresentationModel): file_id = self.data(index, Qt.UserRole) updated_file = None - # conversion from cursor to list - representations = list(self.dbcon.find({"type": "representation", - "_id": self._id})) + representation = get_representation_by_id(self.project, self._id) + if not representation: + return - representation = representations.pop() for repre_file in representation["files"]: if repre_file["_id"] == file_id: updated_file = repre_file From 0e0cec5e0146a3001a4a349360324346fd0ab961 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 17:19:47 +0200 Subject: [PATCH 079/282] pass asset documents instead of just names --- .../workfile/abstract_template_loader.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index a2505c061e..96012eba36 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -223,10 +223,10 @@ class AbstractTemplateLoader: Returns: None """ + loaders_by_name = self.loaders_by_name - current_asset = self.current_asset - linked_assets = [asset['name'] for asset - in get_linked_assets(self.current_asset_doc)] + current_asset_doc = self.current_asset_doc + linked_assets = get_linked_assets(current_asset_doc) ignored_ids = ignored_ids or [] placeholders = self.get_placeholders() @@ -239,7 +239,7 @@ class AbstractTemplateLoader: )) placeholder_representations = self.get_placeholder_representations( placeholder, - current_asset, + current_asset_doc, linked_assets ) @@ -278,11 +278,11 @@ class AbstractTemplateLoader: self.postload(placeholder) def get_placeholder_representations( - self, placeholder, current_asset, linked_assets + self, placeholder, current_asset_doc, linked_asset_docs ): placeholder_representations = placeholder.get_representations( - current_asset, - linked_assets + current_asset_doc, + linked_asset_docs ) for repre_doc in reduce( update_representations, @@ -458,13 +458,13 @@ class AbstractPlaceholder: pass @abstractmethod - def get_representations(self, current_asset, linked_assets): + def get_representations(self, current_asset_doc, linked_asset_docs): """Query representations based on placeholder data. Args: - current_asset (str): Name of current + current_asset_doc (Dict[str, Any]): Document of current context asset. - linked_assets (List[str]): Names of assets + linked_asset_docs (List[Dict[str, Any]]): Documents of assets linked to current context asset. Returns: From ef674857f85f360954b4d6e2c6f6c0c4acf3f711 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 17:29:34 +0200 Subject: [PATCH 080/282] implemented get_representations for maya placeholder --- openpype/hosts/maya/api/template_loader.py | 80 +++++++++++----------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/openpype/hosts/maya/api/template_loader.py b/openpype/hosts/maya/api/template_loader.py index 6b225442e7..f553730186 100644 --- a/openpype/hosts/maya/api/template_loader.py +++ b/openpype/hosts/maya/api/template_loader.py @@ -1,5 +1,7 @@ +import re from maya import cmds +from openpype.client import get_representations from openpype.pipeline import legacy_io from openpype.pipeline.workfile.abstract_template_loader import ( AbstractPlaceholder, @@ -191,48 +193,48 @@ class MayaPlaceholder(AbstractPlaceholder): cmds.hide(node) cmds.setAttr(node + '.hiddenInOutliner', True) - def convert_to_db_filters(self, current_asset, linked_asset): - if self.data['builder_type'] == "context_asset": - return [ - { - "type": "representation", - "context.asset": { - "$eq": current_asset, - "$regex": self.data['asset'] - }, - "context.subset": {"$regex": self.data['subset']}, - "context.hierarchy": {"$regex": self.data['hierarchy']}, - "context.representation": self.data['representation'], - "context.family": self.data['family'], - } - ] + def get_representations(self, current_asset_doc, linked_asset_docs): + project_name = legacy_io.active_project() - elif self.data['builder_type'] == "linked_asset": - return [ - { - "type": "representation", - "context.asset": { - "$eq": asset_name, - "$regex": self.data['asset'] - }, - "context.subset": {"$regex": self.data['subset']}, - "context.hierarchy": {"$regex": self.data['hierarchy']}, - "context.representation": self.data['representation'], - "context.family": self.data['family'], - } for asset_name in linked_asset - ] + builder_type = self.data["builder_type"] + if builder_type == "context_asset": + context_filters = { + "asset": [current_asset_doc["name"]], + "subset": [re.compile(self.data["subset"])], + "hierarchy": [re.compile(self.data["hierarchy"])], + "representations": [self.data["representation"]], + "family": [self.data["family"]] + } + + elif builder_type != "linked_asset": + context_filters = { + "asset": [re.compile(self.data["asset"])], + "subset": [re.compile(self.data["subset"])], + "hierarchy": [re.compile(self.data["hierarchy"])], + "representation": [self.data["representation"]], + "family": [self.data["family"]] + } else: - return [ - { - "type": "representation", - "context.asset": {"$regex": self.data['asset']}, - "context.subset": {"$regex": self.data['subset']}, - "context.hierarchy": {"$regex": self.data['hierarchy']}, - "context.representation": self.data['representation'], - "context.family": self.data['family'], - } - ] + asset_regex = re.compile(self.data["asset"]) + linked_asset_names = [] + for asset_doc in linked_asset_docs: + asset_name = asset_doc["name"] + if asset_regex.match(asset_name): + linked_asset_names.append(asset_name) + + context_filters = { + "asset": linked_asset_names, + "subset": [re.compile(self.data["subset"])], + "hierarchy": [re.compile(self.data["hierarchy"])], + "representation": [self.data["representation"]], + "family": [self.data["family"]], + } + + return list(get_representations( + project_name, + context_filters=context_filters + )) def err_message(self): return ( From a6406f72d36d8eb748404af8fc6e6d61c6c6b451 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 17:39:57 +0200 Subject: [PATCH 081/282] added logger to placeholder --- .../pipeline/workfile/abstract_template_loader.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 96012eba36..d934c50daf 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -397,8 +397,19 @@ class AbstractPlaceholder: optional_attributes = {} def __init__(self, node): + self._log = None self.get_data(node) + @property + def log(self): + if self._log is None: + self._log = Logger.get_logger(repr(self)) + return self._log + + def __repr__(self): + return "< {} {} >".format(self.__class__.__name__, self.name) + + def order(self): """Get placeholder order. Order is used to sort them by priority @@ -436,9 +447,9 @@ class AbstractPlaceholder: Bool: True if every attributes are a key of data """ if set(self.attributes).issubset(self.data.keys()): - print("Valid placeholder : {}".format(self.data["node"])) + self.log.debug("Valid placeholder: {}".format(self.data["node"])) return True - print("Placeholder is not valid : {}".format(self.data["node"])) + self.log.info("Placeholder is not valid: {}".format(self.data["node"])) return False @abstractmethod From 292d071f442a494cabd2161512012b13e391a9f8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 29 Jul 2022 17:39:59 +0200 Subject: [PATCH 082/282] OP-3405 - query is required for updates --- openpype/modules/sync_server/sync_server_module.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index 81aff9368f..6a3dbf6095 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -1611,6 +1611,10 @@ class SyncServerModule(OpenPypeModule, ITrayModule): elem = {"name": site_name} + query = { + "_id": ObjectId(representation_id) + } + if file_id: # reset site for particular file self._reset_site_for_file(collection, query, elem, file_id, site_name) From 8b7531b97775d3facefde41682dd19e9dd3e11f6 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 17:44:03 +0200 Subject: [PATCH 083/282] added helper attributes to placeholder so there is no need to access it's 'data' --- .../workfile/abstract_template_loader.py | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index d934c50daf..5ecc154ea4 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -231,11 +231,11 @@ class AbstractTemplateLoader: ignored_ids = ignored_ids or [] placeholders = self.get_placeholders() self.log.debug("Placeholders found in template: {}".format( - [placeholder.data['node'] for placeholder in placeholders] + [placeholder.name] for placeholder in placeholders] )) for placeholder in placeholders: self.log.debug("Start to processing placeholder {}".format( - placeholder.data['node'] + placeholder.name )) placeholder_representations = self.get_placeholder_representations( placeholder, @@ -246,7 +246,7 @@ class AbstractTemplateLoader: if not placeholder_representations: self.log.info( "There's no representation for this placeholder: " - "{}".format(placeholder.data['node']) + "{}".format(placeholder.name) ) continue @@ -264,8 +264,8 @@ class AbstractTemplateLoader: "Loader arguments used : {}".format( representation['context']['asset'], representation['context']['subset'], - placeholder.loader, - placeholder.data['loader_args'])) + placeholder.loader_name, + placeholder.loader_args)) try: container = self.load( @@ -307,19 +307,22 @@ class AbstractTemplateLoader: def load(self, placeholder, loaders_by_name, last_representation): repre = get_representation_context(last_representation) return load_with_repre_context( - loaders_by_name[placeholder.loader], + loaders_by_name[placeholder.loader_name], repre, - options=parse_loader_args(placeholder.data['loader_args'])) + options=parse_loader_args(placeholder.loader_args)) def load_succeed(self, placeholder, container): placeholder.parent_in_hierarchy(container) def load_failed(self, placeholder, last_representation): - self.log.warning("Got error trying to load {}:{} with {}\n\n" - "{}".format(last_representation['context']['asset'], - last_representation['context']['subset'], - placeholder.loader, - traceback.format_exc())) + self.log.warning( + "Got error trying to load {}:{} with {}".format( + last_representation['context']['asset'], + last_representation['context']['subset'], + placeholder.loader_name + ), + exc_info=True + ) def postload(self, placeholder): placeholder.clean() @@ -398,6 +401,7 @@ class AbstractPlaceholder: def __init__(self, node): self._log = None + self._name = node self.get_data(node) @property @@ -409,6 +413,17 @@ class AbstractPlaceholder: def __repr__(self): return "< {} {} >".format(self.__class__.__name__, self.name) + @property + def name(self): + return self._name + + @property + def loader_args(self): + return self.data["loader_args"] + + @property + def builder_type(self): + return self.data["builder_type"] def order(self): """Get placeholder order. @@ -423,12 +438,15 @@ class AbstractPlaceholder: return self.data.get('order') @property - def loader(self): - """Return placeholder loader type + def loader_name(self): + """Return placeholder loader type. + Returns: - string: Loader name + str: Loader name that will be used to load placeholder + representations. """ - return self.data.get('loader') + + return self.data["loader"] @property def is_context(self): From 2d7910a26410936f1d23282b9011780cccfc8680 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 17:46:14 +0200 Subject: [PATCH 084/282] renamed 'attributes' to 'required_keys' and 'optional_attributes' to 'optional_keys' --- openpype/hosts/maya/api/template_loader.py | 8 +++-- .../workfile/abstract_template_loader.py | 35 ++++++++++++------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/openpype/hosts/maya/api/template_loader.py b/openpype/hosts/maya/api/template_loader.py index f553730186..ecffafc93d 100644 --- a/openpype/hosts/maya/api/template_loader.py +++ b/openpype/hosts/maya/api/template_loader.py @@ -98,11 +98,11 @@ class MayaPlaceholder(AbstractPlaceholder): """Concrete implementation of AbstractPlaceholder for maya """ - optional_attributes = {'asset', 'subset', 'hierarchy'} + optional_keys = {'asset', 'subset', 'hierarchy'} def get_data(self, node): user_data = dict() - for attr in self.attributes.union(self.optional_attributes): + for attr in self.required_keys.union(self.optional_keys): attribute_name = '{}.{}'.format(node, attr) if not cmds.attributeQuery(attr, node=node, exists=True): print("{} not found".format(attribute_name)) @@ -112,7 +112,9 @@ class MayaPlaceholder(AbstractPlaceholder): asString=True) user_data['parent'] = ( cmds.getAttr(node + '.parent', asString=True) - or node.rpartition('|')[0] or "") + or node.rpartition('|')[0] + or "" + ) user_data['node'] = node if user_data['parent']: siblings = cmds.listRelatives(user_data['parent'], children=True) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 5ecc154ea4..56fb31fa0c 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -377,15 +377,17 @@ class AbstractTemplateLoader: @six.add_metaclass(ABCMeta) class AbstractPlaceholder: - """Abstraction of placeholders logic + """Abstraction of placeholders logic. + Properties: - attributes: A list of mandatory attribute to decribe placeholder + required_keys: A list of mandatory keys to decribe placeholder and assets to load. - optional_attributes: A list of optional attribute to decribe + optional_keys: A list of optional keys to decribe placeholder and assets to load loader: Name of linked loader to use while loading assets is_context: Is placeholder linked to context asset (or to linked assets) + Methods: is_repres_valid: loader: @@ -395,9 +397,15 @@ class AbstractPlaceholder: parent_in_hierachy: """ - attributes = {'builder_type', 'family', 'representation', - 'order', 'loader', 'loader_args'} - optional_attributes = {} + required_keys = { + "builder_type", + "family", + "representation", + "order", + "loader", + "loader_args" + } + optional_keys = {} def __init__(self, node): self._log = None @@ -459,15 +467,18 @@ class AbstractPlaceholder: return self.data.get('builder_type') == 'context_asset' def is_valid(self): - """Test validity of placeholder - i.e.: every attributes exists in placeholder data + """Test validity of placeholder. + + i.e.: every required key exists in placeholder data + Returns: - Bool: True if every attributes are a key of data + bool: True if every key is in data """ - if set(self.attributes).issubset(self.data.keys()): - self.log.debug("Valid placeholder: {}".format(self.data["node"])) + + if set(self.required_keys).issubset(self.data.keys()): + self.log.debug("Valid placeholder : {}".format(self.name)) return True - self.log.info("Placeholder is not valid: {}".format(self.data["node"])) + self.log.info("Placeholder is not valid : {}".format(self.name)) return False @abstractmethod From 736123d1c2496df1604d1b0c84df5a2646cc51f9 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 29 Jul 2022 17:48:47 +0200 Subject: [PATCH 085/282] modified 'is_context' property --- .../pipeline/workfile/abstract_template_loader.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 56fb31fa0c..a1d188ea6c 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -458,14 +458,22 @@ class AbstractPlaceholder: @property def is_context(self): - """Return placeholder type + """Check if is placeholder context type. + context_asset: For loading current asset linked_asset: For loading linked assets + + Question: + There seems to be more build options and this property is not used, + should be removed? + Returns: bool: true if placeholder is a context placeholder """ - return self.data.get('builder_type') == 'context_asset' + return self.builder_type == "context_asset" + + @property def is_valid(self): """Test validity of placeholder. From 0f5ec0f0c4cbd4db8c4968db75f6375b6bdf7f59 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 29 Jul 2022 17:54:51 +0200 Subject: [PATCH 086/282] OP-3405 - used get_representation_by_id --- .../modules/sync_server/sync_server_module.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index 6a3dbf6095..71e35c7839 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -25,7 +25,7 @@ from .providers import lib from .utils import time_function, SyncStatus, SiteAlreadyPresentError -from openpype.client import get_representations +from openpype.client import get_representations, get_representation_by_id log = PypeLogger.get_logger("SyncServer") @@ -1591,11 +1591,12 @@ class SyncServerModule(OpenPypeModule, ITrayModule): not 'force' ValueError - other errors (repre not found, misconfiguration) """ - representations = get_representations(collection, [representation_id]) - if not representations: + representation = get_representation_by_id(collection, + representation_id) + if not representation: raise ValueError("Representation {} not found in {}". format(representation_id, collection)) - representation = representations[0] + if side and site_name: raise ValueError("Misconfiguration, only one of side and " + "site_name arguments should be passed.") @@ -1807,15 +1808,14 @@ class SyncServerModule(OpenPypeModule, ITrayModule): provider_name = self.get_provider_for_site(site=site_name) if provider_name == 'local_drive': - representations = list(get_representations(collection, - [representation_id], - fields=["files"])) - if not representations: + representation = get_representation_by_id(collection, + representation_id, + fields=["files"]) + if not representation: self.log.debug("No repre {} found".format( representation_id)) return - representation = representations.pop() local_file_path = '' for file in representation.get("files"): local_file_path = self.get_local_file_path(collection, From 89bd23856c30e39f2493d99b2c743d3b918cccda Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 2 Aug 2022 12:25:51 +0200 Subject: [PATCH 087/282] OP-3405 - refactor - updated methods signature Renamed collection to project_name as when we are leaving MongoDB, collection doesnt make much sense. --- .../providers/abstract_provider.py | 8 +- .../modules/sync_server/providers/dropbox.py | 12 +- .../modules/sync_server/providers/gdrive.py | 16 +- .../sync_server/providers/local_drive.py | 12 +- .../modules/sync_server/providers/sftp.py | 16 +- openpype/modules/sync_server/sync_server.py | 71 +++---- .../modules/sync_server/sync_server_module.py | 189 +++++++++--------- openpype/modules/sync_server/tray/models.py | 2 +- 8 files changed, 164 insertions(+), 162 deletions(-) diff --git a/openpype/modules/sync_server/providers/abstract_provider.py b/openpype/modules/sync_server/providers/abstract_provider.py index 688a17f14f..8c2fe1cad9 100644 --- a/openpype/modules/sync_server/providers/abstract_provider.py +++ b/openpype/modules/sync_server/providers/abstract_provider.py @@ -62,7 +62,7 @@ class AbstractProvider: @abc.abstractmethod def upload_file(self, source_path, path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Copy file from 'source_path' to 'target_path' on provider. @@ -75,7 +75,7 @@ class AbstractProvider: arguments for saving progress: server (SyncServer): server instance to call update_db on - collection (str): name of collection + project_name (str): name of project_name file (dict): info about uploaded file (matches structure from db) representation (dict): complete repre containing 'file' site (str): site name @@ -87,7 +87,7 @@ class AbstractProvider: @abc.abstractmethod def download_file(self, source_path, local_path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Download file from provider into local system @@ -99,7 +99,7 @@ class AbstractProvider: arguments for saving progress: server (SyncServer): server instance to call update_db on - collection (str): name of collection + project_name (str): file (dict): info about uploaded file (matches structure from db) representation (dict): complete repre containing 'file' site (str): site name diff --git a/openpype/modules/sync_server/providers/dropbox.py b/openpype/modules/sync_server/providers/dropbox.py index dfc42fed75..89d6990841 100644 --- a/openpype/modules/sync_server/providers/dropbox.py +++ b/openpype/modules/sync_server/providers/dropbox.py @@ -224,7 +224,7 @@ class DropboxHandler(AbstractProvider): return False def upload_file(self, source_path, path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Copy file from 'source_path' to 'target_path' on provider. @@ -237,7 +237,7 @@ class DropboxHandler(AbstractProvider): arguments for saving progress: server (SyncServer): server instance to call update_db on - collection (str): name of collection + project_name (str): file (dict): info about uploaded file (matches structure from db) representation (dict): complete repre containing 'file' site (str): site name @@ -290,7 +290,7 @@ class DropboxHandler(AbstractProvider): cursor.offset = f.tell() server.update_db( - collection=collection, + project_name=project_name, new_file_id=None, file=file, representation=representation, @@ -301,7 +301,7 @@ class DropboxHandler(AbstractProvider): return path def download_file(self, source_path, local_path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Download file from provider into local system @@ -313,7 +313,7 @@ class DropboxHandler(AbstractProvider): arguments for saving progress: server (SyncServer): server instance to call update_db on - collection (str): name of collection + project_name (str): file (dict): info about uploaded file (matches structure from db) representation (dict): complete repre containing 'file' site (str): site name @@ -337,7 +337,7 @@ class DropboxHandler(AbstractProvider): self.dbx.files_download_to_file(local_path, source_path) server.update_db( - collection=collection, + project_name=project_name, new_file_id=None, file=file, representation=representation, diff --git a/openpype/modules/sync_server/providers/gdrive.py b/openpype/modules/sync_server/providers/gdrive.py index aa7329b104..bef707788b 100644 --- a/openpype/modules/sync_server/providers/gdrive.py +++ b/openpype/modules/sync_server/providers/gdrive.py @@ -251,7 +251,7 @@ class GDriveHandler(AbstractProvider): return folder_id def upload_file(self, source_path, path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Uploads single file from 'source_path' to destination 'path'. @@ -264,7 +264,7 @@ class GDriveHandler(AbstractProvider): arguments for saving progress: server (SyncServer): server instance to call update_db on - collection (str): name of collection + project_name (str): file (dict): info about uploaded file (matches structure from db) representation (dict): complete repre containing 'file' site (str): site name @@ -324,7 +324,7 @@ class GDriveHandler(AbstractProvider): while response is None: if server.is_representation_paused(representation['_id'], check_parents=True, - project_name=collection): + project_name=project_name): raise ValueError("Paused during process, please redo.") if status: status_val = float(status.progress()) @@ -333,7 +333,7 @@ class GDriveHandler(AbstractProvider): last_tick = time.time() log.debug("Uploaded %d%%." % int(status_val * 100)) - server.update_db(collection=collection, + server.update_db(project_name=project_name, new_file_id=None, file=file, representation=representation, @@ -358,7 +358,7 @@ class GDriveHandler(AbstractProvider): return response['id'] def download_file(self, source_path, local_path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Downloads single file from 'source_path' (remote) to 'local_path'. @@ -372,7 +372,7 @@ class GDriveHandler(AbstractProvider): arguments for saving progress: server (SyncServer): server instance to call update_db on - collection (str): name of collection + project_name (str): file (dict): info about uploaded file (matches structure from db) representation (dict): complete repre containing 'file' site (str): site name @@ -410,7 +410,7 @@ class GDriveHandler(AbstractProvider): while response is None: if server.is_representation_paused(representation['_id'], check_parents=True, - project_name=collection): + project_name=project_name): raise ValueError("Paused during process, please redo.") if status: status_val = float(status.progress()) @@ -419,7 +419,7 @@ class GDriveHandler(AbstractProvider): last_tick = time.time() log.debug("Downloaded %d%%." % int(status_val * 100)) - server.update_db(collection=collection, + server.update_db(project_name=project_name, new_file_id=None, file=file, representation=representation, diff --git a/openpype/modules/sync_server/providers/local_drive.py b/openpype/modules/sync_server/providers/local_drive.py index 172cb338cf..4951ef4d1a 100644 --- a/openpype/modules/sync_server/providers/local_drive.py +++ b/openpype/modules/sync_server/providers/local_drive.py @@ -82,7 +82,7 @@ class LocalDriveHandler(AbstractProvider): return editable def upload_file(self, source_path, target_path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False, direction="Upload"): """ Copies file from 'source_path' to 'target_path' @@ -95,7 +95,7 @@ class LocalDriveHandler(AbstractProvider): thread = threading.Thread(target=self._copy, args=(source_path, target_path)) thread.start() - self._mark_progress(collection, file, representation, server, + self._mark_progress(project_name, file, representation, server, site, source_path, target_path, direction) else: if os.path.exists(target_path): @@ -105,13 +105,13 @@ class LocalDriveHandler(AbstractProvider): return os.path.basename(target_path) def download_file(self, source_path, local_path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Download a file form 'source_path' to 'local_path' """ return self.upload_file(source_path, local_path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite, direction="Download") def delete_file(self, path): @@ -188,7 +188,7 @@ class LocalDriveHandler(AbstractProvider): except shutil.SameFileError: print("same files, skipping") - def _mark_progress(self, collection, file, representation, server, site, + def _mark_progress(self, project_name, file, representation, server, site, source_path, target_path, direction): """ Updates progress field in DB by values 0-1. @@ -204,7 +204,7 @@ class LocalDriveHandler(AbstractProvider): status_val = target_file_size / source_file_size last_tick = time.time() log.debug(direction + "ed %d%%." % int(status_val * 100)) - server.update_db(collection=collection, + server.update_db(project_name=project_name, new_file_id=None, file=file, representation=representation, diff --git a/openpype/modules/sync_server/providers/sftp.py b/openpype/modules/sync_server/providers/sftp.py index 49b87b14ec..302ffae3e6 100644 --- a/openpype/modules/sync_server/providers/sftp.py +++ b/openpype/modules/sync_server/providers/sftp.py @@ -222,7 +222,7 @@ class SFTPHandler(AbstractProvider): return os.path.basename(path) def upload_file(self, source_path, target_path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Uploads single file from 'source_path' to destination 'path'. @@ -235,7 +235,7 @@ class SFTPHandler(AbstractProvider): arguments for saving progress: server (SyncServer): server instance to call update_db on - collection (str): name of collection + project_name (str): file (dict): info about uploaded file (matches structure from db) representation (dict): complete repre containing 'file' site (str): site name @@ -256,7 +256,7 @@ class SFTPHandler(AbstractProvider): thread = threading.Thread(target=self._upload, args=(source_path, target_path)) thread.start() - self._mark_progress(collection, file, representation, server, + self._mark_progress(project_name, file, representation, server, site, source_path, target_path, "upload") return os.path.basename(target_path) @@ -267,7 +267,7 @@ class SFTPHandler(AbstractProvider): conn.put(source_path, target_path) def download_file(self, source_path, target_path, - server, collection, file, representation, site, + server, project_name, file, representation, site, overwrite=False): """ Downloads single file from 'source_path' (remote) to 'target_path'. @@ -281,7 +281,7 @@ class SFTPHandler(AbstractProvider): arguments for saving progress: server (SyncServer): server instance to call update_db on - collection (str): name of collection + project_name (str): file (dict): info about uploaded file (matches structure from db) representation (dict): complete repre containing 'file' site (str): site name @@ -302,7 +302,7 @@ class SFTPHandler(AbstractProvider): thread = threading.Thread(target=self._download, args=(source_path, target_path)) thread.start() - self._mark_progress(collection, file, representation, server, + self._mark_progress(project_name, file, representation, server, site, source_path, target_path, "download") return os.path.basename(target_path) @@ -425,7 +425,7 @@ class SFTPHandler(AbstractProvider): pysftp.exceptions.ConnectionException): log.warning("Couldn't connect", exc_info=True) - def _mark_progress(self, collection, file, representation, server, site, + def _mark_progress(self, project_name, file, representation, server, site, source_path, target_path, direction): """ Updates progress field in DB by values 0-1. @@ -446,7 +446,7 @@ class SFTPHandler(AbstractProvider): status_val = target_file_size / source_file_size last_tick = time.time() log.debug(direction + "ed %d%%." % int(status_val * 100)) - server.update_db(collection=collection, + server.update_db(project_name=project_name, new_file_id=None, file=file, representation=representation, diff --git a/openpype/modules/sync_server/sync_server.py b/openpype/modules/sync_server/sync_server.py index 356a75f99d..9cc55ec562 100644 --- a/openpype/modules/sync_server/sync_server.py +++ b/openpype/modules/sync_server/sync_server.py @@ -14,7 +14,7 @@ from .utils import SyncStatus, ResumableError log = PypeLogger().get_logger("SyncServer") -async def upload(module, collection, file, representation, provider_name, +async def upload(module, project_name, file, representation, provider_name, remote_site_name, tree=None, preset=None): """ Upload single 'file' of a 'representation' to 'provider'. @@ -31,7 +31,7 @@ async def upload(module, collection, file, representation, provider_name, Args: module(SyncServerModule): object to run SyncServerModule API - collection (str): source collection + project_name (str): source db file (dictionary): of file from representation in Mongo representation (dictionary): of representation provider_name (string): gdrive, gdc etc. @@ -47,7 +47,7 @@ async def upload(module, collection, file, representation, provider_name, # thread can do that at a time, upload/download to prepared # structure should be run in parallel remote_handler = lib.factory.get_provider(provider_name, - collection, + project_name, remote_site_name, tree=tree, presets=preset) @@ -55,7 +55,7 @@ async def upload(module, collection, file, representation, provider_name, file_path = file.get("path", "") try: local_file_path, remote_file_path = resolve_paths(module, - file_path, collection, remote_site_name, remote_handler + file_path, project_name, remote_site_name, remote_handler ) except Exception as exp: print(exp) @@ -74,27 +74,28 @@ async def upload(module, collection, file, representation, provider_name, local_file_path, remote_file_path, module, - collection, + project_name, file, representation, remote_site_name, True ) - module.handle_alternate_site(collection, representation, remote_site_name, + module.handle_alternate_site(project_name, representation, + remote_site_name, file["_id"], file_id) return file_id -async def download(module, collection, file, representation, provider_name, +async def download(module, project_name, file, representation, provider_name, remote_site_name, tree=None, preset=None): """ Downloads file to local folder denoted in representation.Context. Args: module(SyncServerModule): object to run SyncServerModule API - collection (str): source collection + project_name (str): source file (dictionary) : info about processed file representation (dictionary): repr that 'file' belongs to provider_name (string): 'gdrive' etc @@ -108,20 +109,20 @@ async def download(module, collection, file, representation, provider_name, """ with module.lock: remote_handler = lib.factory.get_provider(provider_name, - collection, + project_name, remote_site_name, tree=tree, presets=preset) file_path = file.get("path", "") local_file_path, remote_file_path = resolve_paths( - module, file_path, collection, remote_site_name, remote_handler + module, file_path, project_name, remote_site_name, remote_handler ) local_folder = os.path.dirname(local_file_path) os.makedirs(local_folder, exist_ok=True) - local_site = module.get_active_site(collection) + local_site = module.get_active_site(project_name) loop = asyncio.get_running_loop() file_id = await loop.run_in_executor(None, @@ -129,20 +130,20 @@ async def download(module, collection, file, representation, provider_name, remote_file_path, local_file_path, module, - collection, + project_name, file, representation, local_site, True ) - module.handle_alternate_site(collection, representation, local_site, + module.handle_alternate_site(project_name, representation, local_site, file["_id"], file_id) return file_id -def resolve_paths(module, file_path, collection, +def resolve_paths(module, file_path, project_name, remote_site_name=None, remote_handler=None): """ Returns tuple of local and remote file paths with {root} @@ -153,7 +154,7 @@ def resolve_paths(module, file_path, collection, Args: module(SyncServerModule): object to run SyncServerModule API file_path(string): path with {root} - collection(string): project name + project_name(string): project name remote_site_name(string): remote site remote_handler(AbstractProvider): implementation Returns: @@ -164,7 +165,7 @@ def resolve_paths(module, file_path, collection, remote_file_path = remote_handler.resolve_path(file_path) local_handler = lib.factory.get_provider( - 'local_drive', collection, module.get_active_site(collection)) + 'local_drive', project_name, module.get_active_site(project_name)) local_file_path = local_handler.resolve_path(file_path) return local_file_path, remote_file_path @@ -269,7 +270,7 @@ class SyncServerThread(threading.Thread): - gets list of collections in DB - gets list of active remote providers (has configuration, credentials) - - for each collection it looks for representations that should + - for each project_name it looks for representations that should be synced - synchronize found collections - update representations - fills error messages for exceptions @@ -282,17 +283,17 @@ class SyncServerThread(threading.Thread): import time start_time = time.time() self.module.set_sync_project_settings() # clean cache - collection = None + project_name = None enabled_projects = self.module.get_enabled_projects() - for collection in enabled_projects: - preset = self.module.sync_project_settings[collection] + for project_name in enabled_projects: + preset = self.module.sync_project_settings[project_name] - local_site, remote_site = self._working_sites(collection) + local_site, remote_site = self._working_sites(project_name) if not all([local_site, remote_site]): continue sync_repres = self.module.get_sync_representations( - collection, + project_name, local_site, remote_site ) @@ -310,7 +311,7 @@ class SyncServerThread(threading.Thread): remote_provider = \ self.module.get_provider_for_site(site=remote_site) handler = lib.factory.get_provider(remote_provider, - collection, + project_name, remote_site, presets=site_preset) limit = lib.factory.get_provider_batch_limit( @@ -341,7 +342,7 @@ class SyncServerThread(threading.Thread): limit -= 1 task = asyncio.create_task( upload(self.module, - collection, + project_name, file, sync, remote_provider, @@ -353,7 +354,7 @@ class SyncServerThread(threading.Thread): files_processed_info.append((file, sync, remote_site, - collection + project_name )) processed_file_path.add(file_path) if status == SyncStatus.DO_DOWNLOAD: @@ -361,7 +362,7 @@ class SyncServerThread(threading.Thread): limit -= 1 task = asyncio.create_task( download(self.module, - collection, + project_name, file, sync, remote_provider, @@ -373,7 +374,7 @@ class SyncServerThread(threading.Thread): files_processed_info.append((file, sync, local_site, - collection + project_name )) processed_file_path.add(file_path) @@ -384,12 +385,12 @@ class SyncServerThread(threading.Thread): return_exceptions=True) for file_id, info in zip(files_created, files_processed_info): - file, representation, site, collection = info + file, representation, site, project_name = info error = None if isinstance(file_id, BaseException): error = str(file_id) file_id = None - self.module.update_db(collection, + self.module.update_db(project_name, file_id, file, representation, @@ -399,7 +400,7 @@ class SyncServerThread(threading.Thread): duration = time.time() - start_time log.debug("One loop took {:.2f}s".format(duration)) - delay = self.module.get_loop_delay(collection) + delay = self.module.get_loop_delay(project_name) log.debug("Waiting for {} seconds to new loop".format(delay)) self.timer = asyncio.create_task(self.run_timer(delay)) await asyncio.gather(self.timer) @@ -458,19 +459,19 @@ class SyncServerThread(threading.Thread): self.timer.cancel() self.timer = None - def _working_sites(self, collection): - if self.module.is_project_paused(collection): + def _working_sites(self, project_name): + if self.module.is_project_paused(project_name): log.debug("Both sites same, skipping") return None, None - local_site = self.module.get_active_site(collection) - remote_site = self.module.get_remote_site(collection) + local_site = self.module.get_active_site(project_name) + remote_site = self.module.get_remote_site(project_name) if local_site == remote_site: log.debug("{}-{} sites same, skipping".format(local_site, remote_site)) return None, None - configured_sites = _get_configured_sites(self.module, collection) + configured_sites = _get_configured_sites(self.module, project_name) if not all([local_site in configured_sites, remote_site in configured_sites]): log.debug("Some of the sites {} - {} is not ".format(local_site, diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index 71e35c7839..c4d90416bb 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -130,12 +130,12 @@ class SyncServerModule(OpenPypeModule, ITrayModule): self.projects_processed = set() """ Start of Public API """ - def add_site(self, collection, representation_id, site_name=None, + def add_site(self, project_name, representation_id, site_name=None, force=False): """ Adds new site to representation to be synced. - 'collection' must have synchronization enabled (globally or + 'project_name' must have synchronization enabled (globally or project only) Used as a API endpoint from outside applications (Loader etc). @@ -143,7 +143,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): Use 'force' to reset existing site. Args: - collection (string): project name (must match DB) + project_name (string): project name (must match DB) representation_id (string): MongoDB _id value site_name (string): name of configured and active site force (bool): reset site if exists @@ -153,25 +153,25 @@ class SyncServerModule(OpenPypeModule, ITrayModule): not 'force' ValueError - other errors (repre not found, misconfiguration) """ - if not self.get_sync_project_setting(collection): + if not self.get_sync_project_setting(project_name): raise ValueError("Project not configured") if not site_name: site_name = self.DEFAULT_SITE - self.reset_site_on_representation(collection, + self.reset_site_on_representation(project_name, representation_id, site_name=site_name, force=force) - def remove_site(self, collection, representation_id, site_name, + def remove_site(self, project_name, representation_id, site_name, remove_local_files=False): """ Removes 'site_name' for particular 'representation_id' on - 'collection' + 'project_name' Args: - collection (string): project name (must match DB) + project_name (string): project name (must match DB) representation_id (string): MongoDB _id value site_name (string): name of configured and active site remove_local_files (bool): remove only files for 'local_id' @@ -180,15 +180,15 @@ class SyncServerModule(OpenPypeModule, ITrayModule): Returns: throws ValueError if any issue """ - if not self.get_sync_project_setting(collection): + if not self.get_sync_project_setting(project_name): raise ValueError("Project not configured") - self.reset_site_on_representation(collection, + self.reset_site_on_representation(project_name, representation_id, site_name=site_name, remove=True) if remove_local_files: - self._remove_local_file(collection, representation_id, site_name) + self._remove_local_file(project_name, representation_id, site_name) def compute_resource_sync_sites(self, project_name): """Get available resource sync sites state for publish process. @@ -335,9 +335,9 @@ class SyncServerModule(OpenPypeModule, ITrayModule): return alt_site_pairs - def clear_project(self, collection, site_name): + def clear_project(self, project_name, site_name): """ - Clear 'collection' of 'site_name' and its local files + Clear 'project_name' of 'site_name' and its local files Works only on real local sites, not on 'studio' """ @@ -348,15 +348,15 @@ class SyncServerModule(OpenPypeModule, ITrayModule): # TODO currently not possible to replace with get_representations representations = list( - self.connection.database[collection].find(query)) + self.connection.database[project_name].find(query)) if not representations: self.log.debug("No repre found") return for repre in representations: - self.remove_site(collection, repre.get("_id"), site_name, True) + self.remove_site(project_name, repre.get("_id"), site_name, True) - def create_validate_project_task(self, collection, site_name): + def create_validate_project_task(self, project_name, site_name): """Adds metadata about project files validation on a queue. This process will loop through all representation and check if @@ -373,28 +373,28 @@ class SyncServerModule(OpenPypeModule, ITrayModule): """ task = { "type": "validate", - "project_name": collection, - "func": lambda: self.validate_project(collection, site_name, + "project_name": project_name, + "func": lambda: self.validate_project(project_name, site_name, reset_missing=True) } - self.projects_processed.add(collection) + self.projects_processed.add(project_name) self.long_running_tasks.append(task) - def validate_project(self, collection, site_name, reset_missing=False): - """Validate 'collection' of 'site_name' and its local files + def validate_project(self, project_name, site_name, reset_missing=False): + """Validate 'project_name' of 'site_name' and its local files If file present and not marked with a 'site_name' in DB, DB is updated with site name and file modified date. Args: - collection (string): project name + project_name (string): project name site_name (string): active site name reset_missing (bool): if True reset site in DB if missing physically """ - self.log.debug("Validation of {} for {} started".format(collection, + self.log.debug("Validation of {} for {} started".format(project_name, site_name)) - representations = list(get_representations(collection)) + representations = list(get_representations(project_name)) if not representations: self.log.debug("No repre found") return @@ -414,7 +414,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): continue file_path = repre_file.get("path", "") - local_file_path = self.get_local_file_path(collection, + local_file_path = self.get_local_file_path(project_name, site_name, file_path) @@ -426,14 +426,11 @@ class SyncServerModule(OpenPypeModule, ITrayModule): "Adding site {} for {}".format(site_name, repre_id)) - query = { - "_id": repre_id - } created_dt = datetime.fromtimestamp( os.path.getmtime(local_file_path)) elem = {"name": site_name, "created_dt": created_dt} - self._add_site(collection, query, repre, elem, + self._add_site(project_name, repre, elem, site_name=site_name, file_id=repre_file["_id"], force=True) @@ -443,41 +440,42 @@ class SyncServerModule(OpenPypeModule, ITrayModule): self.log.debug("Resetting site {} for {}". format(site_name, repre_id)) self.reset_site_on_representation( - collection, repre_id, site_name=site_name, + project_name, repre_id, site_name=site_name, file_id=repre_file["_id"]) sites_reset += 1 if sites_added % 100 == 0: self.log.debug("Sites added {}".format(sites_added)) - self.log.debug("Validation of {} for {} ended".format(collection, + self.log.debug("Validation of {} for {} ended".format(project_name, site_name)) self.log.info("Sites added {}, sites reset {}".format(sites_added, reset_missing)) - def pause_representation(self, collection, representation_id, site_name): + def pause_representation(self, project_name, representation_id, site_name): """ Sets 'representation_id' as paused, eg. no syncing should be happening on it. Args: - collection (string): project name + project_name (string): project name representation_id (string): MongoDB objectId value site_name (string): 'gdrive', 'studio' etc. """ log.info("Pausing SyncServer for {}".format(representation_id)) self._paused_representations.add(representation_id) - self.reset_site_on_representation(collection, representation_id, + self.reset_site_on_representation(project_name, representation_id, site_name=site_name, pause=True) - def unpause_representation(self, collection, representation_id, site_name): + def unpause_representation(self, project_name, + representation_id, site_name): """ Sets 'representation_id' as unpaused. Does not fail or warn if repre wasn't paused. Args: - collection (string): project name + project_name (string): project name representation_id (string): MongoDB objectId value site_name (string): 'gdrive', 'studio' etc. """ @@ -487,7 +485,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): except KeyError: pass # self.paused_representations is not persistent - self.reset_site_on_representation(collection, representation_id, + self.reset_site_on_representation(project_name, representation_id, site_name=site_name, pause=False) def is_representation_paused(self, representation_id, @@ -518,7 +516,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): happening on all representation inside. Args: - project_name (string): collection name + project_name (string): project_name name """ log.info("Pausing SyncServer for {}".format(project_name)) self._paused_projects.add(project_name) @@ -530,7 +528,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): Does not fail or warn if project wasn't paused. Args: - project_name (string): collection name + project_name (string): """ log.info("Unpausing SyncServer for {}".format(project_name)) try: @@ -543,7 +541,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): Returns if 'project_name' is paused or not. Args: - project_name (string): collection name + project_name (string): check_parents (bool): check if server itself is not paused Returns: @@ -942,8 +940,8 @@ class SyncServerModule(OpenPypeModule, ITrayModule): return True return False - def handle_alternate_site(self, collection, representation, processed_site, - file_id, synced_file_id): + def handle_alternate_site(self, project_name, representation, + processed_site, file_id, synced_file_id): """ For special use cases where one site vendors another. @@ -956,7 +954,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): same location >> file is accesible on 'sftp' site right away. Args: - collection (str): name of project + project_name (str): name of project representation (dict) processed_site (str): real site_name of published/uploaded file file_id (ObjectId): DB id of file handled @@ -980,26 +978,23 @@ class SyncServerModule(OpenPypeModule, ITrayModule): alternate_sites = set(alternate_sites) for alt_site in alternate_sites: - query = { - "_id": representation["_id"] - } elem = {"name": alt_site, "created_dt": datetime.now(), "id": synced_file_id} self.log.debug("Adding alternate {} to {}".format( alt_site, representation["_id"])) - self._add_site(collection, query, + self._add_site(project_name, representation, elem, alt_site, file_id=file_id, force=True) """ End of Public API """ - def get_local_file_path(self, collection, site_name, file_path): + def get_local_file_path(self, project_name, site_name, file_path): """ Externalized for app """ - handler = LocalDriveHandler(collection, site_name) + handler = LocalDriveHandler(project_name, site_name) local_file_path = handler.resolve_path(file_path) return local_file_path @@ -1286,7 +1281,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): return sites.get(site, 'N/A') @time_function - def get_sync_representations(self, collection, active_site, remote_site): + def get_sync_representations(self, project_name, active_site, remote_site): """ Get representations that should be synced, these could be recognised by presence of document in 'files.sites', where key is @@ -1297,8 +1292,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): better performance. Goal is to get as few representations as possible. Args: - collection (string): name of collection (in most cases matches - project name + project_name (string): active_site (string): identifier of current active site (could be 'local_0' when working from home, 'studio' when working in the studio (default) @@ -1307,10 +1301,10 @@ class SyncServerModule(OpenPypeModule, ITrayModule): Returns: (list) of dictionaries """ - log.debug("Check representations for : {}".format(collection)) - self.connection.Session["AVALON_PROJECT"] = collection + log.debug("Check representations for : {}".format(project_name)) + self.connection.Session["AVALON_PROJECT"] = project_name # retry_cnt - number of attempts to sync specific file before giving up - retries_arr = self._get_retries_arr(collection) + retries_arr = self._get_retries_arr(project_name) match = { "type": "representation", "$or": [ @@ -1447,14 +1441,14 @@ class SyncServerModule(OpenPypeModule, ITrayModule): return SyncStatus.DO_NOTHING - def update_db(self, collection, new_file_id, file, representation, + def update_db(self, project_name, new_file_id, file, representation, site, error=None, progress=None, priority=None): """ Update 'provider' portion of records in DB with success (file_id) or error (exception) Args: - collection (string): name of project - force to db connection as + project_name (string): name of project - force to db connection as each file might come from different collection new_file_id (string): file (dictionary): info about processed file (pulled from DB) @@ -1497,7 +1491,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): if file_id: arr_filter.append({'f._id': ObjectId(file_id)}) - self.connection.database[collection].update_one( + self.connection.database[project_name].update_one( query, update, upsert=True, @@ -1560,7 +1554,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): return -1, None - def reset_site_on_representation(self, collection, representation_id, + def reset_site_on_representation(self, project_name, representation_id, side=None, file_id=None, site_name=None, remove=False, pause=None, force=False): """ @@ -1577,7 +1571,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): Should be used when repre should be synced to new site. Args: - collection (string): name of project (eg. collection) in DB + project_name (string): name of project (eg. collection) in DB representation_id(string): _id of representation file_id (string): file _id in representation side (string): local or remote side @@ -1591,18 +1585,18 @@ class SyncServerModule(OpenPypeModule, ITrayModule): not 'force' ValueError - other errors (repre not found, misconfiguration) """ - representation = get_representation_by_id(collection, + representation = get_representation_by_id(project_name, representation_id) if not representation: raise ValueError("Representation {} not found in {}". - format(representation_id, collection)) + format(representation_id, project_name)) if side and site_name: raise ValueError("Misconfiguration, only one of side and " + "site_name arguments should be passed.") - local_site = self.get_active_site(collection) - remote_site = self.get_remote_site(collection) + local_site = self.get_active_site(project_name) + remote_site = self.get_remote_site(project_name) if side: if side == 'local': @@ -1612,42 +1606,44 @@ class SyncServerModule(OpenPypeModule, ITrayModule): elem = {"name": site_name} - query = { - "_id": ObjectId(representation_id) - } - if file_id: # reset site for particular file - self._reset_site_for_file(collection, query, + self._reset_site_for_file(project_name, representation_id, elem, file_id, site_name) elif side: # reset site for whole representation - self._reset_site(collection, query, elem, site_name) + self._reset_site(project_name, representation_id, elem, site_name) elif remove: # remove site for whole representation - self._remove_site(collection, query, representation, site_name) + self._remove_site(project_name, + representation, site_name) elif pause is not None: - self._pause_unpause_site(collection, query, + self._pause_unpause_site(project_name, representation, site_name, pause) else: # add new site to all files for representation - self._add_site(collection, query, representation, elem, site_name, + self._add_site(project_name, representation, elem, site_name, force=force) - def _update_site(self, collection, query, update, arr_filter): + def _update_site(self, project_name, representation_id, + update, arr_filter): """ Auxiliary method to call update_one function on DB Used for refactoring ugly reset_provider_for_file """ - self.connection.database[collection].update_one( + query = { + "_id": ObjectId(representation_id) + } + + self.connection.database[project_name].update_one( query, update, upsert=True, array_filters=arr_filter ) - def _reset_site_for_file(self, collection, query, + def _reset_site_for_file(self, project_name, representation_id, elem, file_id, site_name): """ Resets 'site_name' for 'file_id' on representation in 'query' on - 'collection' + 'project_name' """ update = { "$set": {"files.$[f].sites.$[s]": elem} @@ -1660,9 +1656,9 @@ class SyncServerModule(OpenPypeModule, ITrayModule): {'f._id': file_id} ] - self._update_site(collection, query, update, arr_filter) + self._update_site(project_name, representation_id, update, arr_filter) - def _reset_site(self, collection, query, elem, site_name): + def _reset_site(self, project_name, representation_id, elem, site_name): """ Resets 'site_name' for all files of representation in 'query' """ @@ -1674,9 +1670,9 @@ class SyncServerModule(OpenPypeModule, ITrayModule): {'s.name': site_name} ] - self._update_site(collection, query, update, arr_filter) + self._update_site(project_name, representation_id, update, arr_filter) - def _remove_site(self, collection, query, representation, site_name): + def _remove_site(self, project_name, representation, site_name): """ Removes 'site_name' for 'representation' in 'query' @@ -1698,10 +1694,11 @@ class SyncServerModule(OpenPypeModule, ITrayModule): } arr_filter = [] - self._update_site(collection, query, update, arr_filter) + self._update_site(project_name, representation["_id"], + update, arr_filter) - def _pause_unpause_site(self, collection, query, - representation, site_name, pause): + def _pause_unpause_site(self, project_name, representation, + site_name, pause): """ Pauses/unpauses all files for 'representation' based on 'pause' @@ -1733,12 +1730,13 @@ class SyncServerModule(OpenPypeModule, ITrayModule): {'s.name': site_name} ] - self._update_site(collection, query, update, arr_filter) + self._update_site(project_name, representation["_id"], + update, arr_filter) - def _add_site(self, collection, query, representation, elem, site_name, + def _add_site(self, project_name, representation, elem, site_name, force=False, file_id=None): """ - Adds 'site_name' to 'representation' on 'collection' + Adds 'site_name' to 'representation' on 'project_name' Args: representation (dict) @@ -1746,10 +1744,11 @@ class SyncServerModule(OpenPypeModule, ITrayModule): Use 'force' to remove existing or raises ValueError """ + representation_id = representation["_id"] reset_existing = False files = representation.get("files", []) if not files: - log.debug("No files for {}".format(representation["_id"])) + log.debug("No files for {}".format(representation_id)) return for repre_file in files: @@ -1759,7 +1758,8 @@ class SyncServerModule(OpenPypeModule, ITrayModule): for site in repre_file.get("sites"): if site["name"] == site_name: if force or site.get("error"): - self._reset_site_for_file(collection, query, + self._reset_site_for_file(project_name, + representation_id, elem, repre_file["_id"], site_name) reset_existing = True @@ -1785,14 +1785,15 @@ class SyncServerModule(OpenPypeModule, ITrayModule): {'f._id': file_id} ] - self._update_site(collection, query, update, arr_filter) + self._update_site(project_name, representation_id, + update, arr_filter) - def _remove_local_file(self, collection, representation_id, site_name): + def _remove_local_file(self, project_name, representation_id, site_name): """ Removes all local files for 'site_name' of 'representation_id' Args: - collection (string): project name (must match DB) + project_name (string): project name (must match DB) representation_id (string): MongoDB _id value site_name (string): name of configured and active site @@ -1808,7 +1809,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): provider_name = self.get_provider_for_site(site=site_name) if provider_name == 'local_drive': - representation = get_representation_by_id(collection, + representation = get_representation_by_id(project_name, representation_id, fields=["files"]) if not representation: @@ -1818,7 +1819,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): local_file_path = '' for file in representation.get("files"): - local_file_path = self.get_local_file_path(collection, + local_file_path = self.get_local_file_path(project_name, site_name, file.get("path", "") ) diff --git a/openpype/modules/sync_server/tray/models.py b/openpype/modules/sync_server/tray/models.py index a97797c920..f05a5bd8ea 100644 --- a/openpype/modules/sync_server/tray/models.py +++ b/openpype/modules/sync_server/tray/models.py @@ -441,7 +441,7 @@ class SyncRepresentationSummaryModel(_SyncRepresentationModel): full text filtering. Allows pagination, most of heavy lifting is being done on DB side. - Single model matches to single collection. When project is changed, + Single model matches to single project. When project is changed, model is reset and refreshed. Args: From eb2c82558888fe5650bdab4bee1a60a498b685fa Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 2 Aug 2022 16:09:59 +0200 Subject: [PATCH 088/282] OP-3405 - extracted aggregate query from Loader to Site Sync module --- .../modules/sync_server/sync_server_module.py | 89 +++++++++++++++++ openpype/tools/loader/model.py | 95 ++----------------- 2 files changed, 98 insertions(+), 86 deletions(-) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index c4d90416bb..8fdfab9c2e 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -988,6 +988,95 @@ class SyncServerModule(OpenPypeModule, ITrayModule): representation, elem, alt_site, file_id=file_id, force=True) + def get_repre_info_for_versions(self, project_name, version_ids, + active_site, remote_site): + """Returns representation documents for versions and sites combi + + Args: + project_name (str) + version_ids (list): of version[_id] + active_site (string): 'local', 'studio' etc + remote_site (string): dtto + Returns: + + """ + self.connection.Session["AVALON_PROJECT"] = project_name + query = [ + {"$match": {"parent": {"$in": version_ids}, + "type": "representation", + "files.sites.name": {"$exists": 1}}}, + {"$unwind": "$files"}, + {'$addFields': { + 'order_local': { + '$filter': { + 'input': '$files.sites', 'as': 'p', + 'cond': {'$eq': ['$$p.name', active_site]} + } + } + }}, + {'$addFields': { + 'order_remote': { + '$filter': { + 'input': '$files.sites', 'as': 'p', + 'cond': {'$eq': ['$$p.name', remote_site]} + } + } + }}, + {'$addFields': { + 'progress_local': {"$arrayElemAt": [{ + '$cond': [ + {'$size': "$order_local.progress"}, + "$order_local.progress", + # if exists created_dt count is as available + {'$cond': [ + {'$size': "$order_local.created_dt"}, + [1], + [0] + ]} + ]}, + 0 + ]} + }}, + {'$addFields': { + 'progress_remote': {"$arrayElemAt": [{ + '$cond': [ + {'$size': "$order_remote.progress"}, + "$order_remote.progress", + # if exists created_dt count is as available + {'$cond': [ + {'$size': "$order_remote.created_dt"}, + [1], + [0] + ]} + ]}, + 0 + ]} + }}, + {'$group': { # first group by repre + '_id': '$_id', + 'parent': {'$first': '$parent'}, + 'avail_ratio_local': { + '$first': { + '$divide': [{'$sum': "$progress_local"}, {'$sum': 1}] + } + }, + 'avail_ratio_remote': { + '$first': { + '$divide': [{'$sum': "$progress_remote"}, {'$sum': 1}] + } + } + }}, + {'$group': { # second group by parent, eg version_id + '_id': '$parent', + 'repre_count': {'$sum': 1}, # total representations + # fully available representation for site + 'avail_repre_local': {'$sum': "$avail_ratio_local"}, + 'avail_repre_remote': {'$sum': "$avail_ratio_remote"}, + }}, + ] + # docs = list(self.connection.aggregate(query)) + return self.connection.aggregate(query) + """ End of Public API """ def get_local_file_path(self, project_name, site_name, file_path): diff --git a/openpype/tools/loader/model.py b/openpype/tools/loader/model.py index a5174bd804..3ce44ea6c8 100644 --- a/openpype/tools/loader/model.py +++ b/openpype/tools/loader/model.py @@ -272,15 +272,15 @@ class SubsetsModel(TreeModel, BaseRepresentationModel): # update availability on active site when version changes if self.sync_server.enabled and version_doc: - query = self._repre_per_version_pipeline( + repre_info = self.sync_server.get_repre_info_for_versions( + project_name, [version_doc["_id"]], self.active_site, self.remote_site ) - docs = list(self.dbcon.aggregate(query)) - if docs: - repre = docs.pop() - version_doc["data"].update(self._get_repre_dict(repre)) + if repre_info: + version_doc["data"].update( + self._get_repre_dict(repre_info[0])) self.set_version(index, version_doc) @@ -478,16 +478,16 @@ class SubsetsModel(TreeModel, BaseRepresentationModel): for _subset_id, doc in last_versions_by_subset_id.items(): version_ids.add(doc["_id"]) - query = self._repre_per_version_pipeline( + repres = self.sync_server.get_repre_info_for_versions( + project_name, list(version_ids), self.active_site, self.remote_site ) - - for doc in self.dbcon.aggregate(query): + for repre in repres: if self._doc_fetching_stop: return doc["active_provider"] = self.active_provider doc["remote_provider"] = self.remote_provider - repre_info[doc["_id"]] = doc + repre_info[repre["_id"]] = repre self._doc_payload = { "asset_docs_by_id": asset_docs_by_id, @@ -827,83 +827,6 @@ class SubsetsModel(TreeModel, BaseRepresentationModel): return data - def _repre_per_version_pipeline(self, version_ids, - active_site, remote_site): - query = [ - {"$match": {"parent": {"$in": version_ids}, - "type": "representation", - "files.sites.name": {"$exists": 1}}}, - {"$unwind": "$files"}, - {'$addFields': { - 'order_local': { - '$filter': { - 'input': '$files.sites', 'as': 'p', - 'cond': {'$eq': ['$$p.name', active_site]} - } - } - }}, - {'$addFields': { - 'order_remote': { - '$filter': { - 'input': '$files.sites', 'as': 'p', - 'cond': {'$eq': ['$$p.name', remote_site]} - } - } - }}, - {'$addFields': { - 'progress_local': {"$arrayElemAt": [{ - '$cond': [ - {'$size': "$order_local.progress"}, - "$order_local.progress", - # if exists created_dt count is as available - {'$cond': [ - {'$size': "$order_local.created_dt"}, - [1], - [0] - ]} - ]}, - 0 - ]} - }}, - {'$addFields': { - 'progress_remote': {"$arrayElemAt": [{ - '$cond': [ - {'$size': "$order_remote.progress"}, - "$order_remote.progress", - # if exists created_dt count is as available - {'$cond': [ - {'$size': "$order_remote.created_dt"}, - [1], - [0] - ]} - ]}, - 0 - ]} - }}, - {'$group': { # first group by repre - '_id': '$_id', - 'parent': {'$first': '$parent'}, - 'avail_ratio_local': { - '$first': { - '$divide': [{'$sum': "$progress_local"}, {'$sum': 1}] - } - }, - 'avail_ratio_remote': { - '$first': { - '$divide': [{'$sum': "$progress_remote"}, {'$sum': 1}] - } - } - }}, - {'$group': { # second group by parent, eg version_id - '_id': '$parent', - 'repre_count': {'$sum': 1}, # total representations - # fully available representation for site - 'avail_repre_local': {'$sum': "$avail_ratio_local"}, - 'avail_repre_remote': {'$sum': "$avail_ratio_remote"}, - }}, - ] - return query - class GroupMemberFilterProxyModel(QtCore.QSortFilterProxyModel): """Provide the feature of filtering group by the acceptance of members From 26c4a0f8ca19eeb4faaa85ceac1524c3bed71b7d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 2 Aug 2022 16:15:17 +0200 Subject: [PATCH 089/282] OP-3405 - Hound --- openpype/modules/sync_server/providers/local_drive.py | 3 ++- openpype/modules/sync_server/sync_server.py | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openpype/modules/sync_server/providers/local_drive.py b/openpype/modules/sync_server/providers/local_drive.py index 4951ef4d1a..01bc891d08 100644 --- a/openpype/modules/sync_server/providers/local_drive.py +++ b/openpype/modules/sync_server/providers/local_drive.py @@ -111,7 +111,8 @@ class LocalDriveHandler(AbstractProvider): Download a file form 'source_path' to 'local_path' """ return self.upload_file(source_path, local_path, - server, project_name, file, representation, site, + server, project_name, file, + representation, site, overwrite, direction="Download") def delete_file(self, path): diff --git a/openpype/modules/sync_server/sync_server.py b/openpype/modules/sync_server/sync_server.py index 9cc55ec562..97538fcd4e 100644 --- a/openpype/modules/sync_server/sync_server.py +++ b/openpype/modules/sync_server/sync_server.py @@ -54,8 +54,9 @@ async def upload(module, project_name, file, representation, provider_name, file_path = file.get("path", "") try: - local_file_path, remote_file_path = resolve_paths(module, - file_path, project_name, remote_site_name, remote_handler + local_file_path, remote_file_path = resolve_paths( + module, file_path, project_name, + remote_site_name, remote_handler ) except Exception as exp: print(exp) @@ -270,8 +271,8 @@ class SyncServerThread(threading.Thread): - gets list of collections in DB - gets list of active remote providers (has configuration, credentials) - - for each project_name it looks for representations that should - be synced + - for each project_name it looks for representations that + should be synced - synchronize found collections - update representations - fills error messages for exceptions - waits X seconds and repeat From d7d8d45ee5589741092a66187f42f2332296420a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 3 Aug 2022 18:27:08 +0200 Subject: [PATCH 090/282] OP-3405 - representation is not a list Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/modules/sync_server/tray/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/sync_server/tray/models.py b/openpype/modules/sync_server/tray/models.py index f05a5bd8ea..629c4cbbf1 100644 --- a/openpype/modules/sync_server/tray/models.py +++ b/openpype/modules/sync_server/tray/models.py @@ -923,7 +923,7 @@ class SyncRepresentationSummaryModel(_SyncRepresentationModel): representation = get_representation_by_id(self.project, repre_id) if representation: self.sync_server.update_db(self.project, None, None, - representation.pop(), + representation, get_local_site_id(), priority=value) self.is_editing = False From 49799c2d8871a52fb1fd8210b31a1e51fd5f3f2b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 4 Aug 2022 18:26:38 +0200 Subject: [PATCH 091/282] fix merge conflict --- openpype/pipeline/workfile/abstract_template_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index a1d188ea6c..5d8d79397a 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -231,7 +231,7 @@ class AbstractTemplateLoader: ignored_ids = ignored_ids or [] placeholders = self.get_placeholders() self.log.debug("Placeholders found in template: {}".format( - [placeholder.name] for placeholder in placeholders] + [placeholder.name for placeholder in placeholders] )) for placeholder in placeholders: self.log.debug("Start to processing placeholder {}".format( From 7d1f1bb064190873beee61c0a4eb4df598747c88 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 5 Aug 2022 09:50:11 +0200 Subject: [PATCH 092/282] remove extensions arguments --- openpype/client/entities.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openpype/client/entities.py b/openpype/client/entities.py index 57c38784b0..a3fcd01f80 100644 --- a/openpype/client/entities.py +++ b/openpype/client/entities.py @@ -1216,7 +1216,6 @@ def get_representations( representation_ids=representation_ids, representation_names=representation_names, version_ids=version_ids, - extensions=extensions, context_filters=context_filters, names_by_version_ids=names_by_version_ids, standard=True, @@ -1230,7 +1229,6 @@ def get_archived_representations( representation_ids=None, representation_names=None, version_ids=None, - extensions=None, context_filters=None, names_by_version_ids=None, fields=None @@ -1247,8 +1245,6 @@ def get_archived_representations( as filter. Filter ignored if 'None' is passed. version_ids (Iterable[str]): Subset ids used as parent filter. Filter ignored if 'None' is passed. - extensions (Iterable[str]): Filter by extension of main representation - file (without dot). names_by_version_ids (dict[ObjectId, List[str]]): Complex filtering using version ids and list of names under the version. fields (Iterable[str]): Fields that should be returned. All fields are @@ -1263,7 +1259,6 @@ def get_archived_representations( representation_ids=representation_ids, representation_names=representation_names, version_ids=version_ids, - extensions=extensions, context_filters=context_filters, names_by_version_ids=names_by_version_ids, standard=False, From 8db8ada9642bcdf2c5f364fbf78c902344b1613e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 8 Aug 2022 17:46:32 +0200 Subject: [PATCH 093/282] changed 'node' variable to 'identifier' and added it's docstrings --- .../workfile/abstract_template_loader.py | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 5d8d79397a..16287bbd4e 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -384,17 +384,11 @@ class AbstractPlaceholder: and assets to load. optional_keys: A list of optional keys to decribe placeholder and assets to load - loader: Name of linked loader to use while loading assets - is_context: Is placeholder linked - to context asset (or to linked assets) + loader_name: Name of linked loader to use while loading assets - Methods: - is_repres_valid: - loader: - order: - is_valid: - get_data: - parent_in_hierachy: + Args: + identifier (str): Placeholder identifier. Should be possible to be + used as identifier in "a scene" (e.g. unique node name). """ required_keys = { @@ -407,10 +401,10 @@ class AbstractPlaceholder: } optional_keys = {} - def __init__(self, node): + def __init__(self, identifier): self._log = None - self._name = node - self.get_data(node) + self._name = identifier + self.get_data(identifier) @property def log(self): From 5d0cd42a8133bcf7d65bbcef0c7b093ef058d7b2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 8 Aug 2022 17:47:01 +0200 Subject: [PATCH 094/282] renamed 'order' method to 'get_order' --- .../pipeline/workfile/abstract_template_loader.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 16287bbd4e..fe1f15c140 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -336,7 +336,7 @@ class AbstractTemplateLoader: placeholders = map(placeholder_class, self.get_template_nodes()) valid_placeholders = filter(placeholder_class.is_valid, placeholders) sorted_placeholders = sorted(valid_placeholders, - key=placeholder_class.order) + key=placeholder_class.get_order) return sorted_placeholders @abstractmethod @@ -427,17 +427,24 @@ class AbstractPlaceholder: def builder_type(self): return self.data["builder_type"] + @property def order(self): - """Get placeholder order. + return self.data["order"] + + def get_order(self): + """Placeholder order. + Order is used to sort them by priority Priority is lowset first, highest last (ex: 1: First to load 100: Last to load) + Returns: - Int: Order priority + int: Order priority """ - return self.data.get('order') + + return self.order @property def loader_name(self): From 7e8e61c0e4d51334d6de0d1f9cd672fa0dae5313 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 8 Aug 2022 17:48:14 +0200 Subject: [PATCH 095/282] changed 'get_data' docstring --- openpype/pipeline/workfile/abstract_template_loader.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index fe1f15c140..66943eafe7 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -537,10 +537,12 @@ class AbstractPlaceholder: pass @abstractmethod - def get_data(self, node): - """ - Collect placeholders information. + def get_data(self, identifier): + """Collect information about placeholder by identifier. + Args: - node (AnyNode): A unique node decided by Placeholder implementation + identifier (str): A unique placeholder identifier defined by + implementation. """ + pass From a1cd1890d6db952e4feee357e204444aed0015ed Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 8 Aug 2022 17:48:28 +0200 Subject: [PATCH 096/282] modified 'parent_in_hierarchy' docstring --- openpype/pipeline/workfile/abstract_template_loader.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 66943eafe7..a1629d9b79 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -491,13 +491,13 @@ class AbstractPlaceholder: return False @abstractmethod - def parent_in_hierarchy(self, containers): - """Place container in correct hierarchy - given by placeholder + def parent_in_hierarchy(self, container): + """Place loaded container in correct hierarchy given by placeholder + Args: - containers (String): Container name returned back by - placeholder's loader. + container (Dict[str, Any]): Loaded container created by loader. """ + pass @abstractmethod From 56150d4abb72d8b0025a7724e002eab792aa34a0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 8 Aug 2022 17:48:48 +0200 Subject: [PATCH 097/282] removed unused method 'convert_to_db_filters' --- .../pipeline/workfile/abstract_template_loader.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index a1629d9b79..c36e489017 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -523,19 +523,6 @@ class AbstractPlaceholder: pass - @abstractmethod - def convert_to_db_filters(self, current_asset, linked_asset): - """map current placeholder data as a db filter - args: - current_asset (String): Name of current asset in context - linked asset (list[String]) : Names of assets linked to - current asset in context - Returns: - dict: a dictionnary describing a filter to look for asset in - a database - """ - pass - @abstractmethod def get_data(self, identifier): """Collect information about placeholder by identifier. From 56bbbdbd583b51ba07bac08e753fb5a2050a768f Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 8 Aug 2022 17:49:20 +0200 Subject: [PATCH 098/282] removed unused import --- openpype/pipeline/workfile/abstract_template_loader.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index c36e489017..725ab1dab3 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -1,8 +1,6 @@ import os from abc import ABCMeta, abstractmethod -import traceback - import six import logging from functools import reduce From 0528494d9e53368275754befa73bea7dcf7948dd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 10 Aug 2022 16:10:52 +0200 Subject: [PATCH 099/282] extract review can scale to match pixel ratio --- openpype/plugins/publish/extract_review.py | 63 ++++++++-------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/openpype/plugins/publish/extract_review.py b/openpype/plugins/publish/extract_review.py index 7442d3aacb..e16f324e0a 100644 --- a/openpype/plugins/publish/extract_review.py +++ b/openpype/plugins/publish/extract_review.py @@ -1210,7 +1210,6 @@ class ExtractReview(pyblish.api.InstancePlugin): # Get instance data pixel_aspect = temp_data["pixel_aspect"] - if reformat_in_baking: self.log.debug(( "Using resolution from input. It is already " @@ -1230,6 +1229,10 @@ class ExtractReview(pyblish.api.InstancePlugin): # - settings value can't have None but has value of 0 output_width = output_def.get("width") or output_width or None output_height = output_def.get("height") or output_height or None + # Force to use input resolution if output resolution was not defined + # in settings. Resolution from instance is not used when + # 'use_input_res' is set to 'True'. + use_input_res = False # Overscal color overscan_color_value = "black" @@ -1241,6 +1244,17 @@ class ExtractReview(pyblish.api.InstancePlugin): ) self.log.debug("Overscan color: `{}`".format(overscan_color_value)) + # Scale input to have proper pixel aspect ratio + # - scale width by the pixel aspect ratio + scale_pixel_aspect = output_def.get("scale_pixel_aspect", True) + if scale_pixel_aspect and pixel_aspect != 1: + # Change input width after pixel aspect + input_width = int(input_width * pixel_aspect) + use_input_res = True + filters.append(( + "scale={}x{}:flags=lanczos".format(input_width, input_height) + )) + # Convert overscan value video filters overscan_crop = output_def.get("overscan_crop") overscan = OverscanCrop( @@ -1251,13 +1265,10 @@ class ExtractReview(pyblish.api.InstancePlugin): # resolution by it's values if overscan_crop_filters: filters.extend(overscan_crop_filters) + # Change input resolution after overscan crop input_width = overscan.width() input_height = overscan.height() - # Use output resolution as inputs after cropping to skip usage of - # instance data resolution - if output_width is None or output_height is None: - output_width = input_width - output_height = input_height + use_input_res = True # Make sure input width and height is not an odd number input_width_is_odd = bool(input_width % 2 != 0) @@ -1283,8 +1294,10 @@ class ExtractReview(pyblish.api.InstancePlugin): self.log.debug("input_width: `{}`".format(input_width)) self.log.debug("input_height: `{}`".format(input_height)) - # Use instance resolution if output definition has not set it. - if output_width is None or output_height is None: + # Use instance resolution if output definition has not set it + # - use instance resolution only if there were not scale changes + # that may massivelly affect output 'use_input_res' + if not use_input_res and output_width is None or output_height is None: output_width = temp_data["resolution_width"] output_height = temp_data["resolution_height"] @@ -1326,7 +1339,6 @@ class ExtractReview(pyblish.api.InstancePlugin): output_width == input_width and output_height == input_height and not letter_box_enabled - and pixel_aspect == 1 ): self.log.debug( "Output resolution is same as input's" @@ -1336,39 +1348,8 @@ class ExtractReview(pyblish.api.InstancePlugin): new_repre["resolutionHeight"] = input_height return filters - # defining image ratios - input_res_ratio = ( - (float(input_width) * pixel_aspect) / input_height - ) - output_res_ratio = float(output_width) / float(output_height) - self.log.debug("input_res_ratio: `{}`".format(input_res_ratio)) - self.log.debug("output_res_ratio: `{}`".format(output_res_ratio)) - - # Round ratios to 2 decimal places for comparing - input_res_ratio = round(input_res_ratio, 2) - output_res_ratio = round(output_res_ratio, 2) - - # get scale factor - scale_factor_by_width = ( - float(output_width) / (input_width * pixel_aspect) - ) - scale_factor_by_height = ( - float(output_height) / input_height - ) - - self.log.debug( - "scale_factor_by_with: `{}`".format(scale_factor_by_width) - ) - self.log.debug( - "scale_factor_by_height: `{}`".format(scale_factor_by_height) - ) - # scaling none square pixels and 1920 width - if ( - input_height != output_height - or input_width != output_width - or pixel_aspect != 1 - ): + if input_height != output_height or input_width != output_width: filters.extend([ ( "scale={}x{}" From 3d62093224be2b3786823b175f1bfd1ffa3aad3d Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 10 Aug 2022 16:14:50 +0200 Subject: [PATCH 100/282] Refactor moved usage of CreateRender settings --- openpype/hosts/maya/api/lib_rendersettings.py | 3 +-- .../hosts/maya/plugins/publish/validate_render_image_rule.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/api/lib_rendersettings.py b/openpype/hosts/maya/api/lib_rendersettings.py index 9aea55a03b..7cd2193086 100644 --- a/openpype/hosts/maya/api/lib_rendersettings.py +++ b/openpype/hosts/maya/api/lib_rendersettings.py @@ -60,8 +60,7 @@ class RenderSettings(object): try: aov_separator = self._aov_chars[( self._project_settings["maya"] - ["create"] - ["CreateRender"] + ["RenderSettings"] ["aov_separator"] )] except KeyError: diff --git a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py index 642ca9e25d..0abcf2f12a 100644 --- a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -41,6 +41,5 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): def get_default_render_image_folder(instance): return instance.context.data.get('project_settings')\ .get('maya') \ - .get('create') \ - .get('CreateRender') \ + .get('RenderSettings') \ .get('default_render_image_folder') From 7a16cb723b8329d493697c153881533808a2c0e2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 10 Aug 2022 16:42:34 +0200 Subject: [PATCH 101/282] added settings for rescaling when pixel aspect ratio is not 1 --- openpype/settings/defaults/project_settings/global.json | 1 + .../projects_schema/schemas/schema_global_publish.json | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index e509db2791..0ff9363ba7 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -85,6 +85,7 @@ ], "width": 0, "height": 0, + "scale_pixel_aspect": true, "bg_color": [ 0, 0, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index b9d0b7daba..e1aa230b49 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -319,6 +319,15 @@ "minimum": 0, "maximum": 100000 }, + { + "type": "label", + "label": "Rescale input when it's pixel aspect ratio is not 1. Usefull for anamorph reviews." + }, + { + "key": "scale_pixel_aspect", + "label": "Scale pixel aspect", + "type": "boolean" + }, { "type": "label", "label": "Background color is used only when input have transparency and Alpha is higher than 0." From f74101be342ced01df8057f353123692fb559ff3 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 10 Aug 2022 16:45:19 +0200 Subject: [PATCH 102/282] Remove unused get current renderer logic The `renderer` variable wasn't used --- openpype/hosts/maya/plugins/publish/collect_render.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index e6fc8a01e5..e1f4efcc07 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -154,12 +154,6 @@ class CollectMayaRender(pyblish.api.ContextPlugin): layer_name = "rs_{}".format(expected_layer_name) # collect all frames we are expecting to be rendered - renderer = self.get_render_attribute("currentRenderer", - layer=layer_name) - # handle various renderman names - if renderer.startswith("renderman"): - renderer = "renderman" - # return all expected files for all cameras and aovs in given # frame range layer_render_products = get_layer_render_products(layer_name) From 74a91f4d22ebcacbab07f05ca44fd8e1dbf1d6c2 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Wed, 10 Aug 2022 17:01:42 +0200 Subject: [PATCH 103/282] Fix more missing refactors --- openpype/hosts/maya/plugins/publish/collect_render.py | 3 +-- .../modules/deadline/plugins/publish/submit_maya_deadline.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index e6fc8a01e5..085403bdf7 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -203,8 +203,7 @@ class CollectMayaRender(pyblish.api.ContextPlugin): aov_dict = {} default_render_file = context.data.get('project_settings')\ .get('maya')\ - .get('create')\ - .get('CreateRender')\ + .get('RenderSettings')\ .get('default_render_image_folder') or "" # replace relative paths with absolute. Render products are # returned as list of dictionaries. diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index f253ceb21a..13dfc0183a 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -413,8 +413,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): # Gather needed data ------------------------------------------------ default_render_file = instance.context.data.get('project_settings')\ .get('maya')\ - .get('create')\ - .get('CreateRender')\ + .get('RenderSettings')\ .get('default_render_image_folder') filename = os.path.basename(filepath) comment = context.data.get("comment", "") From 02edebad41f26680f0f7ceb3b2b21fe6cfebebab Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 10 Aug 2022 18:33:03 +0200 Subject: [PATCH 104/282] fix import string --- openpype/pipeline/workfile/build_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/build_template.py b/openpype/pipeline/workfile/build_template.py index df6fe3514a..e6396578c5 100644 --- a/openpype/pipeline/workfile/build_template.py +++ b/openpype/pipeline/workfile/build_template.py @@ -15,7 +15,7 @@ from .build_template_exceptions import ( MissingTemplateLoaderClass ) -_module_path_format = 'openpype.{host}.template_loader' +_module_path_format = 'openpype.hosts.{host}.api.template_loader' def build_workfile_template(*args): From bbf113cac4c8dd0dde7cca18646641107a505b44 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 11 Aug 2022 11:54:07 +0200 Subject: [PATCH 105/282] Set default value for default render image folder to "renders" --- openpype/settings/defaults/project_settings/maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index ac0f161cf2..ce9cd4d606 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -33,7 +33,7 @@ }, "RenderSettings": { "apply_render_settings": true, - "default_render_image_folder": "", + "default_render_image_folder": "renders", "aov_separator": "underscore", "reset_current_frame": false, "arnold_renderer": { From f0a6a6414ea86178f0d02ed83d8816919a86beb1 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 11 Aug 2022 11:54:35 +0200 Subject: [PATCH 106/282] Tweak ValidateRenderImageRule docstring and invalidation error message --- .../publish/validate_render_image_rule.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py index 0abcf2f12a..a9be996e0c 100644 --- a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -11,7 +11,11 @@ def get_file_rule(rule): class ValidateRenderImageRule(pyblish.api.InstancePlugin): - """Validates "images" file rule is set to "renders/" + """Validates Maya Workpace "images" file rule matches project settings. + + This validates against the configured default render image folder: + Studio Settings > Project > Maya > + Render Settings > Default render image folder. """ @@ -23,11 +27,13 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): def process(self, instance): - default_render_file = self.get_default_render_image_folder(instance) + required_images_rule = self.get_default_render_image_folder(instance) + current_images_rule = get_file_rule("images") - assert get_file_rule("images") == default_render_file, ( - "Workspace's `images` file rule must be set to: {}".format( - default_render_file + assert current_images_rule == required_images_rule, ( + "Invalid workspace `images` file rule value: '{}'. " + "Must be set to: '{}'".format( + current_images_rule, required_images_rule ) ) From 4f9d1c34e22d22729fc99fc92abcfaeb16ca253b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 12:39:27 +0200 Subject: [PATCH 107/282] added IHostModule to be able identify module representing a host --- openpype/modules/interfaces.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/openpype/modules/interfaces.py b/openpype/modules/interfaces.py index 334485cab2..424dd158fd 100644 --- a/openpype/modules/interfaces.py +++ b/openpype/modules/interfaces.py @@ -1,4 +1,4 @@ -from abc import abstractmethod +from abc import abstractmethod, abstractproperty from openpype import resources @@ -320,3 +320,13 @@ class ISettingsChangeListener(OpenPypeInterface): self, old_value, new_value, changes, project_name, new_value_metadata ): pass + + +class IHostModule(OpenPypeInterface): + """Module which also contain a host implementation.""" + + @abstractproperty + def host_name(self): + """Name of host which module represents.""" + + pass From c86ab4fecfbb6e502723bb86dbbf0748a8135753 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 12:40:08 +0200 Subject: [PATCH 108/282] added ability to inmport host modules on load modules --- openpype/modules/base.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 1bd343fd07..32fa4d2f31 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -140,7 +140,7 @@ class _LoadCache: def get_default_modules_dir(): """Path to default OpenPype modules.""" - current_dir = os.path.abspath(os.path.dirname(__file__)) + current_dir = os.path.dirname(os.path.abspath(__file__)) output = [] for folder_name in ("default_modules", ): @@ -298,6 +298,8 @@ def _load_modules(): # Add current directory at first place # - has small differences in import logic current_dir = os.path.abspath(os.path.dirname(__file__)) + hosts_dir = os.path.join(os.path.dirname(current_dir), "hosts") + module_dirs.insert(0, hosts_dir) module_dirs.insert(0, current_dir) processed_paths = set() @@ -314,6 +316,7 @@ def _load_modules(): continue is_in_current_dir = dirpath == current_dir + is_in_host_dir = dirpath == hosts_dir for filename in os.listdir(dirpath): # Ignore filenames if filename in IGNORED_FILENAMES: @@ -353,6 +356,24 @@ def _load_modules(): sys.modules[new_import_str] = default_module setattr(openpype_modules, basename, default_module) + elif is_in_host_dir: + import_str = "openpype.hosts.{}".format(basename) + new_import_str = "{}.{}".format(modules_key, basename) + # Until all hosts are converted to be able use them as + # modules is this error check needed + try: + default_module = __import__( + import_str, fromlist=("", ) + ) + sys.modules[new_import_str] = default_module + setattr(openpype_modules, basename, default_module) + + except Exception: + log.warning( + "Failed to import host folder {}".format(basename), + exc_info=True + ) + elif os.path.isdir(fullpath): import_module_from_dirpath(dirpath, filename, modules_key) From 5736b9133cd8f2b2a62146cf6c9fb8310a74f4b5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 12:40:32 +0200 Subject: [PATCH 109/282] added helper methods to be able get host module by host name --- openpype/modules/base.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 32fa4d2f31..ef577e5aa2 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -825,6 +825,45 @@ class ModulesManager: output.extend(hook_paths) return output + def get_host_module(self, host_name): + """Find host module by host name. + + Args: + host_name (str): Host name for which is found host module. + + Returns: + OpenPypeModule: Found host module by name. + None: There was not found module inheriting IHostModule which has + host name set to passed 'host_name'. + """ + + from openpype_interfaces import IHostModule + + for module in self.get_enabled_modules(): + if ( + isinstance(module, IHostModule) + and module.host_name == host_name + ): + return module + return None + + def get_host_names(self): + """List of available host names based on host modules. + + Returns: + Iterable[str]: All available host names based on enabled modules + inheriting 'IHostModule'. + """ + + from openpype_interfaces import IHostModule + + host_names = { + module.host_name + for module in self.get_enabled_modules() + if isinstance(module, IHostModule) + } + return host_names + def print_report(self): """Print out report of time spent on modules initialization parts. From a2dadc85bd51c2fc25baf5098ec5fdcf08e00269 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 12:42:54 +0200 Subject: [PATCH 110/282] added 'OpenPypeMaya' module --- openpype/hosts/maya/__init__.py | 7 +++++++ openpype/hosts/maya/module.py | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100644 openpype/hosts/maya/module.py diff --git a/openpype/hosts/maya/__init__.py b/openpype/hosts/maya/__init__.py index c1c82c62e5..2178534b89 100644 --- a/openpype/hosts/maya/__init__.py +++ b/openpype/hosts/maya/__init__.py @@ -1,4 +1,5 @@ import os +from .module import OpenPypeMaya def add_implementation_envs(env, _app): @@ -25,3 +26,9 @@ def add_implementation_envs(env, _app): for key, value in defaults.items(): if not env.get(key): env[key] = value + + +__all__ = ( + "OpenPypeMaya", + "add_implementation_envs", +) diff --git a/openpype/hosts/maya/module.py b/openpype/hosts/maya/module.py new file mode 100644 index 0000000000..8dfd96d4ab --- /dev/null +++ b/openpype/hosts/maya/module.py @@ -0,0 +1,10 @@ +from openpype.modules import OpenPypeModule +from openpype.modules.interfaces import IHostModule + + +class OpenPypeMaya(OpenPypeModule, IHostModule): + name = "openpype_maya" + host_name = "maya" + + def initialize(self, module_settings): + self.enabled = True From 88be0405986196894b16ae5cb98d303d3d0e9598 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 12:43:50 +0200 Subject: [PATCH 111/282] modev 'add_implementation_envs' to maya module and application knows that it should look there --- openpype/hosts/maya/__init__.py | 28 ---------------------------- openpype/hosts/maya/module.py | 27 +++++++++++++++++++++++++++ openpype/lib/applications.py | 6 ++++-- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/openpype/hosts/maya/__init__.py b/openpype/hosts/maya/__init__.py index 2178534b89..72b4d5853c 100644 --- a/openpype/hosts/maya/__init__.py +++ b/openpype/hosts/maya/__init__.py @@ -1,34 +1,6 @@ -import os from .module import OpenPypeMaya -def add_implementation_envs(env, _app): - # Add requirements to PYTHONPATH - pype_root = os.environ["OPENPYPE_REPOS_ROOT"] - new_python_paths = [ - os.path.join(pype_root, "openpype", "hosts", "maya", "startup") - ] - old_python_path = env.get("PYTHONPATH") or "" - for path in old_python_path.split(os.pathsep): - if not path: - continue - - norm_path = os.path.normpath(path) - if norm_path not in new_python_paths: - new_python_paths.append(norm_path) - - env["PYTHONPATH"] = os.pathsep.join(new_python_paths) - - # Set default values if are not already set via settings - defaults = { - "OPENPYPE_LOG_NO_COLORS": "Yes" - } - for key, value in defaults.items(): - if not env.get(key): - env[key] = value - - __all__ = ( "OpenPypeMaya", - "add_implementation_envs", ) diff --git a/openpype/hosts/maya/module.py b/openpype/hosts/maya/module.py index 8dfd96d4ab..0af68788bc 100644 --- a/openpype/hosts/maya/module.py +++ b/openpype/hosts/maya/module.py @@ -1,6 +1,9 @@ +import os from openpype.modules import OpenPypeModule from openpype.modules.interfaces import IHostModule +MAYA_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) + class OpenPypeMaya(OpenPypeModule, IHostModule): name = "openpype_maya" @@ -8,3 +11,27 @@ class OpenPypeMaya(OpenPypeModule, IHostModule): def initialize(self, module_settings): self.enabled = True + + def add_implementation_envs(self, env, _app): + # Add requirements to PYTHONPATH + new_python_paths = [ + os.path.join(MAYA_ROOT_DIR, "startup") + ] + old_python_path = env.get("PYTHONPATH") or "" + for path in old_python_path.split(os.pathsep): + if not path: + continue + + norm_path = os.path.normpath(path) + if norm_path not in new_python_paths: + new_python_paths.append(norm_path) + + env["PYTHONPATH"] = os.pathsep.join(new_python_paths) + + # Set default values if are not already set via settings + defaults = { + "OPENPYPE_LOG_NO_COLORS": "Yes" + } + for key, value in defaults.items(): + if not env.get(key): + env[key] = value diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index da8623ea13..e47ec8cd11 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1508,8 +1508,10 @@ def prepare_app_environments( final_env = None # Add host specific environments if app.host_name and implementation_envs: - module = __import__("openpype.hosts", fromlist=[app.host_name]) - host_module = getattr(module, app.host_name, None) + host_module = modules_manager.get_host_module(app.host_name) + if not host_module: + module = __import__("openpype.hosts", fromlist=[app.host_name]) + host_module = getattr(module, app.host_name, None) add_implementation_envs = None if host_module: add_implementation_envs = getattr( From 8fe20486a91a8943b847b610d342df163dee3e1b Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 11 Aug 2022 12:51:01 +0200 Subject: [PATCH 112/282] Remove usage of mel eval and pymel --- .../plugins/publish/validate_render_image_rule.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py index a9be996e0c..b94bdb0b14 100644 --- a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -1,15 +1,9 @@ -import maya.mel as mel -import pymel.core as pm +from maya import cmds import pyblish.api import openpype.api -def get_file_rule(rule): - """Workaround for a bug in python with cmds.workspace""" - return mel.eval('workspace -query -fileRuleEntry "{}"'.format(rule)) - - class ValidateRenderImageRule(pyblish.api.InstancePlugin): """Validates Maya Workpace "images" file rule matches project settings. @@ -28,7 +22,7 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): def process(self, instance): required_images_rule = self.get_default_render_image_folder(instance) - current_images_rule = get_file_rule("images") + current_images_rule = cmds.workspace(fileRuleEntry="images") assert current_images_rule == required_images_rule, ( "Invalid workspace `images` file rule value: '{}'. " @@ -40,8 +34,8 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): @classmethod def repair(cls, instance): default = cls.get_default_render_image_folder(instance) - pm.workspace.fileRules["images"] = default - pm.system.Workspace.save() + cmds.workspace(fileRule=("images", default)) + cmds.workspace(saveWorkspace=True) @staticmethod def get_default_render_image_folder(instance): From 7cd47ff6c4641d7e78c8d3e9823f4d58fdea1135 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Thu, 11 Aug 2022 12:54:33 +0200 Subject: [PATCH 113/282] Only update and save the workspace once This avoids saving it many times on repair in scenes with many renderlayers and thus many renderlayer instances since repair runs per instance. --- .../maya/plugins/publish/validate_render_image_rule.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py index b94bdb0b14..4d3796e429 100644 --- a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -33,9 +33,13 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): @classmethod def repair(cls, instance): - default = cls.get_default_render_image_folder(instance) - cmds.workspace(fileRule=("images", default)) - cmds.workspace(saveWorkspace=True) + + required_images_rule = cls.get_default_render_image_folder(instance) + current_images_rule = cmds.workspace(fileRuleEntry="images") + + if current_images_rule != required_images_rule: + cmds.workspace(fileRule=("images", required_images_rule)) + cmds.workspace(saveWorkspace=True) @staticmethod def get_default_render_image_folder(instance): From 32176ba234cf1bff28e15c4efce51cc00d641037 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 13:29:06 +0200 Subject: [PATCH 114/282] modules does not have to inherit from ILaunchHookPaths and application is passed to 'collect_launch_hook_paths --- openpype/lib/applications.py | 4 +++- openpype/modules/base.py | 38 ++++++++++++++++++++++++++++------ openpype/modules/interfaces.py | 33 ++++++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index e47ec8cd11..5443320960 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -996,7 +996,9 @@ class ApplicationLaunchContext: paths.append(path) # Load modules paths - paths.extend(self.modules_manager.collect_launch_hook_paths()) + paths.extend( + self.modules_manager.collect_launch_hook_paths(self.application) + ) return paths diff --git a/openpype/modules/base.py b/openpype/modules/base.py index ef577e5aa2..e26075283d 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -789,24 +789,50 @@ class ModulesManager: output.extend(paths) return output - def collect_launch_hook_paths(self): - """Helper to collect hooks from modules inherited ILaunchHookPaths. + def collect_launch_hook_paths(self, app): + """Helper to collect application launch hooks. + + It used to be based on 'ILaunchHookPaths' which is not true anymore. + Module just have to have implemented 'get_launch_hook_paths' method. + + Args: + app (Application): Application object which can be used for + filtering of which launch hook paths are returned. Returns: list: Paths to launch hook directories. """ - from openpype_interfaces import ILaunchHookPaths str_type = type("") expected_types = (list, tuple, set) output = [] for module in self.get_enabled_modules(): - # Skip module that do not inherit from `ILaunchHookPaths` - if not isinstance(module, ILaunchHookPaths): + # Skip module if does not have implemented 'get_launch_hook_paths' + func = getattr(module, "get_launch_hook_paths", None) + if func is None: + continue + + func = module.get_launch_hook_paths + if hasattr(inspect, "signature"): + sig = inspect.signature(func) + expect_args = len(sig.parameters) > 0 + else: + expect_args = len(inspect.getargspec(func)[0]) > 0 + + # Pass application argument if method expect it. + try: + if expect_args: + hook_paths = func(app) + else: + hook_paths = func() + except Exception: + self.log.warning( + "Failed to call 'get_launch_hook_paths'", + exc_info=True + ) continue - hook_paths = module.get_launch_hook_paths() if not hook_paths: continue diff --git a/openpype/modules/interfaces.py b/openpype/modules/interfaces.py index 424dd158fd..de9ba13800 100644 --- a/openpype/modules/interfaces.py +++ b/openpype/modules/interfaces.py @@ -50,12 +50,32 @@ class IPluginPaths(OpenPypeInterface): class ILaunchHookPaths(OpenPypeInterface): """Module has launch hook paths to return. + Modules does not have to inherit from this interface (changed 8.11.2022). + Module just have to have implemented 'get_launch_hook_paths' to be able use + the advantage. + Expected result is list of paths. ["path/to/launch_hooks_dir"] """ @abstractmethod - def get_launch_hook_paths(self): + def get_launch_hook_paths(self, app): + """Paths to directory with application launch hooks. + + Method can be also defined without arguments. + ```python + def get_launch_hook_paths(self): + return [] + ``` + + Args: + app (Application): Application object which can be used for + filtering of which launch hook paths are returned. + + Returns: + Iterable[str]: Path to directories where launch hooks can be found. + """ + pass @@ -66,6 +86,7 @@ class ITrayModule(OpenPypeInterface): The module still must be usable if is not used in tray even if would do nothing. """ + tray_initialized = False _tray_manager = None @@ -78,16 +99,19 @@ class ITrayModule(OpenPypeInterface): This is where GUIs should be loaded or tray specific parts should be prepared. """ + pass @abstractmethod def tray_menu(self, tray_menu): """Add module's action to tray menu.""" + pass @abstractmethod def tray_start(self): """Start procedure in Pype tray.""" + pass @abstractmethod @@ -96,6 +120,7 @@ class ITrayModule(OpenPypeInterface): This is place where all threads should be shut. """ + pass def execute_in_main_thread(self, callback): @@ -104,6 +129,7 @@ class ITrayModule(OpenPypeInterface): Some callbacks need to be processed on main thread (menu actions must be added on main thread or they won't get triggered etc.) """ + if not self.tray_initialized: # TODO Called without initialized tray, still main thread needed try: @@ -128,6 +154,7 @@ class ITrayModule(OpenPypeInterface): msecs (int): Duration of message visibility in miliseconds. Default is 10000 msecs, may differ by Qt version. """ + if self._tray_manager: self._tray_manager.show_tray_message(title, message, icon, msecs) @@ -280,16 +307,19 @@ class ITrayService(ITrayModule): def set_service_running_icon(self): """Change icon of an QAction to green circle.""" + if self.menu_action: self.menu_action.setIcon(self.get_icon_running()) def set_service_failed_icon(self): """Change icon of an QAction to red circle.""" + if self.menu_action: self.menu_action.setIcon(self.get_icon_failed()) def set_service_idle_icon(self): """Change icon of an QAction to orange circle.""" + if self.menu_action: self.menu_action.setIcon(self.get_icon_idle()) @@ -303,6 +333,7 @@ class ISettingsChangeListener(OpenPypeInterface): "publish": ["path/to/publish_plugins"] } """ + @abstractmethod def on_system_settings_save( self, old_value, new_value, changes, new_value_metadata From 0ae844401cc271ef0edf9b16a5dda4893dd7bcfd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 13:29:35 +0200 Subject: [PATCH 115/282] maya is registering it's launch hooks --- openpype/hosts/maya/module.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openpype/hosts/maya/module.py b/openpype/hosts/maya/module.py index 0af68788bc..e058f1cef5 100644 --- a/openpype/hosts/maya/module.py +++ b/openpype/hosts/maya/module.py @@ -35,3 +35,10 @@ class OpenPypeMaya(OpenPypeModule, IHostModule): for key, value in defaults.items(): if not env.get(key): env[key] = value + + def get_launch_hook_paths(self, app): + if app.host_name != self.host_name: + return [] + return [ + os.path.join(MAYA_ROOT_DIR, "hooks") + ] From 58af54c4437d0495f2f00c7962455bd8cdbf1a1a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 13:33:35 +0200 Subject: [PATCH 116/282] let host module add it's prelaunch hooks and don't guess it --- openpype/lib/applications.py | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 5443320960..e23cc6215f 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -962,32 +962,24 @@ class ApplicationLaunchContext: # TODO load additional studio paths from settings import openpype - pype_dir = os.path.dirname(os.path.abspath(openpype.__file__)) + openpype_dir = os.path.dirname(os.path.abspath(openpype.__file__)) - # --- START: Backwards compatibility --- - hooks_dir = os.path.join(pype_dir, "hooks") + global_hooks_dir = os.path.join(openpype_dir, "hooks") - subfolder_names = ["global"] - if self.host_name: - subfolder_names.append(self.host_name) - for subfolder_name in subfolder_names: - path = os.path.join(hooks_dir, subfolder_name) - if ( - os.path.exists(path) - and os.path.isdir(path) - and path not in paths - ): - paths.append(path) - # --- END: Backwards compatibility --- - - subfolders_list = [ - ["hooks"] + hooks_dirs = [ + global_hooks_dir ] if self.host_name: - subfolders_list.append(["hosts", self.host_name, "hooks"]) + # If host requires launch hooks and is module then launch hooks + # should be collected using 'collect_launch_hook_paths' + # - module have to implement 'get_launch_hook_paths' + host_module = self.modules_manager.get_host_module(self.host_name) + if not host_module: + hooks_dirs.append(os.path.join( + openpype_dir, "hosts", self.host_name, "hooks" + )) - for subfolders in subfolders_list: - path = os.path.join(pype_dir, *subfolders) + for path in hooks_dirs: if ( os.path.exists(path) and os.path.isdir(path) From 7d304d0f8695775e6f3e49d2b0271ac2b8564883 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 13:39:32 +0200 Subject: [PATCH 117/282] host module can define workfile extensions --- openpype/lib/applications.py | 23 ++++++++++++++++------- openpype/modules/interfaces.py | 11 +++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index e23cc6215f..0f380d0f4b 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1303,6 +1303,7 @@ def get_app_environments_for_context( dict: Environments for passed context and application. """ + from openpype.modules import ModulesManager from openpype.pipeline import AvalonMongoDB, Anatomy # Avalon database connection @@ -1315,8 +1316,6 @@ def get_app_environments_for_context( asset_doc = get_asset_by_name(project_name, asset_name) if modules_manager is None: - from openpype.modules import ModulesManager - modules_manager = ModulesManager() # Prepare app object which can be obtained only from ApplciationManager @@ -1343,7 +1342,7 @@ def get_app_environments_for_context( }) prepare_app_environments(data, env_group, modules_manager) - prepare_context_environments(data, env_group) + prepare_context_environments(data, env_group, modules_manager) # Discard avalon connection dbcon.uninstall() @@ -1564,7 +1563,7 @@ def apply_project_environments_value( return env -def prepare_context_environments(data, env_group=None): +def prepare_context_environments(data, env_group=None, modules_manager=None): """Modify launch environments with context data for launched host. Args: @@ -1652,10 +1651,10 @@ def prepare_context_environments(data, env_group=None): data["env"]["AVALON_APP"] = app.host_name data["env"]["AVALON_WORKDIR"] = workdir - _prepare_last_workfile(data, workdir) + _prepare_last_workfile(data, workdir, modules_manager) -def _prepare_last_workfile(data, workdir): +def _prepare_last_workfile(data, workdir, modules_manager): """last workfile workflow preparation. Function check if should care about last workfile workflow and tries @@ -1670,8 +1669,13 @@ def _prepare_last_workfile(data, workdir): result will be stored. workdir (str): Path to folder where workfiles should be stored. """ + + from openpype.modules import ModulesManager from openpype.pipeline import HOST_WORKFILE_EXTENSIONS + if not modules_manager: + modules_manager = ModulesManager() + log = data["log"] _workdir_data = data.get("workdir_data") @@ -1719,7 +1723,12 @@ def _prepare_last_workfile(data, workdir): # Last workfile path last_workfile_path = data.get("last_workfile_path") or "" if not last_workfile_path: - extensions = HOST_WORKFILE_EXTENSIONS.get(app.host_name) + host_module = modules_manager.get_host_module(app.host_name) + if host_module: + extensions = host_module.get_workfile_extensions() + else: + extensions = HOST_WORKFILE_EXTENSIONS.get(app.host_name) + if extensions: anatomy = data["anatomy"] project_settings = data["project_settings"] diff --git a/openpype/modules/interfaces.py b/openpype/modules/interfaces.py index de9ba13800..14f49204ee 100644 --- a/openpype/modules/interfaces.py +++ b/openpype/modules/interfaces.py @@ -361,3 +361,14 @@ class IHostModule(OpenPypeInterface): """Name of host which module represents.""" pass + + def get_workfile_extensions(self): + """Define workfile extensions for host. + + Not all hosts support workfiles thus this is optional implementation. + + Returns: + List[str]: Extensions used for workfiles with dot. + """ + + return [] From 9b623c1dd3e335aeb48d3428f6a0cba5e5793e51 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 14:14:21 +0200 Subject: [PATCH 118/282] maya define it's workfile extensions only in module itself --- openpype/hosts/maya/api/workio.py | 4 +--- openpype/hosts/maya/module.py | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/api/workio.py b/openpype/hosts/maya/api/workio.py index fd4961c4bf..8c31974c73 100644 --- a/openpype/hosts/maya/api/workio.py +++ b/openpype/hosts/maya/api/workio.py @@ -2,11 +2,9 @@ import os from maya import cmds -from openpype.pipeline import HOST_WORKFILE_EXTENSIONS - def file_extensions(): - return HOST_WORKFILE_EXTENSIONS["maya"] + return [".ma", ".mb"] def has_unsaved_changes(): diff --git a/openpype/hosts/maya/module.py b/openpype/hosts/maya/module.py index e058f1cef5..5a215be8d2 100644 --- a/openpype/hosts/maya/module.py +++ b/openpype/hosts/maya/module.py @@ -42,3 +42,6 @@ class OpenPypeMaya(OpenPypeModule, IHostModule): return [ os.path.join(MAYA_ROOT_DIR, "hooks") ] + + def get_workfile_extensions(self): + return [".ma", ".mb"] From 25616886bff2b6fda0b4c9646ea9256389ba248f Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 15:08:14 +0200 Subject: [PATCH 119/282] raise and error when nothing is selected --- openpype/hosts/maya/api/lib_template_builder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/hosts/maya/api/lib_template_builder.py b/openpype/hosts/maya/api/lib_template_builder.py index 855c72e361..34a8450a26 100644 --- a/openpype/hosts/maya/api/lib_template_builder.py +++ b/openpype/hosts/maya/api/lib_template_builder.py @@ -40,6 +40,9 @@ def create_placeholder(): placeholder_name = create_placeholder_name(args, options) selection = cmds.ls(selection=True) + if not selection: + raise ValueError("Nothing is selected") + placeholder = cmds.spaceLocator(name=placeholder_name)[0] # get the long name of the placeholder (with the groups) From 683468c5633a42b8c5e80510ab060f981452d02c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 15:22:08 +0200 Subject: [PATCH 120/282] use 'filter_profiles' function for profiles filtering --- .../workfile/abstract_template_loader.py | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 725ab1dab3..51d06cdb3f 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -7,7 +7,11 @@ from functools import reduce from openpype.client import get_asset_by_name from openpype.settings import get_project_settings -from openpype.lib import get_linked_assets, PypeLogger as Logger +from openpype.lib import ( + Logger, + filter_profiles, + get_linked_assets, +) from openpype.pipeline import legacy_io, Anatomy from openpype.pipeline.load import ( get_loaders_by_name, @@ -167,22 +171,23 @@ class AbstractTemplateLoader: anatomy = Anatomy(project_name) project_settings = get_project_settings(project_name) - build_info = project_settings[host_name]['templated_workfile_build'] - profiles = build_info['profiles'] + build_info = project_settings[host_name]["templated_workfile_build"] + profile = filter_profiles( + build_info["profiles"], + { + "task_types": task_type, + "tasks": task_name + } + ) - for prf in profiles: - if prf['task_types'] and task_type not in prf['task_types']: - continue - if prf['tasks'] and task_name not in prf['tasks']: - continue - path = prf['path'] - break - else: # IF no template were found (no break happened) + if not profile: raise TemplateProfileNotFound( "No matching profile found for task '{}' of type '{}' " "with host '{}'".format(task_name, task_type, host_name) ) - if path is None: + + path = profile["path"] + if not path: raise TemplateLoadingFailed( "Template path is not set.\n" "Path need to be set in {}\\Template Workfile Build " From bb9a16100acd9a7d94ec6ff6ea15891916eea580 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 15:22:23 +0200 Subject: [PATCH 121/282] removed unnecessary finally statement --- openpype/pipeline/workfile/abstract_template_loader.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 51d06cdb3f..0ed32033af 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -205,9 +205,8 @@ class AbstractTemplateLoader: raise KeyError( "Could not solve key '{}' in template path '{}'".format( missing_key, path)) - finally: - solved_path = os.path.normpath(solved_path) + solved_path = os.path.normpath(solved_path) if not os.path.exists(solved_path): raise TemplateNotFound( "Template found in openPype settings for task '{}' with host " From 12a8307a8331334ee9700efba2127211ea332ff0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 15:40:02 +0200 Subject: [PATCH 122/282] simplified path formatting --- .../workfile/abstract_template_loader.py | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 0ed32033af..5afec56d71 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -8,6 +8,7 @@ from functools import reduce from openpype.client import get_asset_by_name from openpype.settings import get_project_settings from openpype.lib import ( + StringTemplate, Logger, filter_profiles, get_linked_assets, @@ -192,19 +193,35 @@ class AbstractTemplateLoader: "Template path is not set.\n" "Path need to be set in {}\\Template Workfile Build " "Settings\\Profiles".format(host_name.title())) - try: - solved_path = None - while True: + + # Try fill path with environments and anatomy roots + fill_data = { + key: value + for key, value in os.environ.items() + } + fill_data["root"] = anatomy.roots + result = StringTemplate.format_template(path, fill_data) + if result.solved: + path = result.normalized() + + if path and os.path.exists(path): + self.log.info("Found template at: '{}'".format(path)) + return path + + solved_path = None + while True: + try: solved_path = anatomy.path_remapper(path) - if solved_path is None: - solved_path = path - if solved_path == path: - break - path = solved_path - except KeyError as missing_key: - raise KeyError( - "Could not solve key '{}' in template path '{}'".format( - missing_key, path)) + except KeyError as missing_key: + raise KeyError( + "Could not solve key '{}' in template path '{}'".format( + missing_key, path)) + + if solved_path is None: + solved_path = path + if solved_path == path: + break + path = solved_path solved_path = os.path.normpath(solved_path) if not os.path.exists(solved_path): @@ -213,7 +230,7 @@ class AbstractTemplateLoader: "'{}' does not exists. (Not found : {})".format( task_name, host_name, solved_path)) - self.log.info("Found template at : '{}'".format(solved_path)) + self.log.info("Found template at: '{}'".format(solved_path)) return solved_path From 748dcf1ad207edd3dbf3bc98120d9e46bf9b39e0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 15:51:27 +0200 Subject: [PATCH 123/282] fix filter and sort --- .../workfile/abstract_template_loader.py | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 5afec56d71..1c8ede25e6 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -351,11 +351,15 @@ class AbstractTemplateLoader: self.populate_template(ignored_ids=loaded_containers_ids) def get_placeholders(self): - placeholder_class = self.placeholder_class - placeholders = map(placeholder_class, self.get_template_nodes()) - valid_placeholders = filter(placeholder_class.is_valid, placeholders) - sorted_placeholders = sorted(valid_placeholders, - key=placeholder_class.get_order) + placeholders = map(self.placeholder_class, self.get_template_nodes()) + valid_placeholders = filter( + lambda i: i.is_valid, + placeholders + ) + sorted_placeholders = list(sorted( + valid_placeholders, + key=lambda i: i.order + )) return sorted_placeholders @abstractmethod @@ -450,21 +454,6 @@ class AbstractPlaceholder: def order(self): return self.data["order"] - def get_order(self): - """Placeholder order. - - Order is used to sort them by priority - Priority is lowset first, highest last - (ex: - 1: First to load - 100: Last to load) - - Returns: - int: Order priority - """ - - return self.order - @property def loader_name(self): """Return placeholder loader type. From 7eaa278c741ceaa30daf056dd17ec9e4b4ceed10 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 15:54:19 +0200 Subject: [PATCH 124/282] removed invalid default setting for templates --- openpype/settings/defaults/project_settings/maya.json | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 9c2c737ece..e9109abd22 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -123,7 +123,6 @@ "defaults": [ "Main" ] - }, "CreateAss": { "enabled": true, @@ -969,13 +968,7 @@ ] }, "templated_workfile_build": { - "profiles": [ - { - "task_types": [], - "tasks": [], - "path": "/path/to/your/template" - } - ] + "profiles": [] }, "filters": { "preset 1": { From 66ee0beaf6d0e09eae6a8a9887a90651618a73f2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 17:43:47 +0200 Subject: [PATCH 125/282] fix empty or query --- openpype/client/entities.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/client/entities.py b/openpype/client/entities.py index f9d3badb1a..c798c0ad6d 100644 --- a/openpype/client/entities.py +++ b/openpype/client/entities.py @@ -1130,11 +1130,12 @@ def _get_representations( for item in _regex_filters(flatten_filters): for key, value in item.items(): - if key == "$or": - or_queries.append(value) - else: + if key != "$or": query_filter[key] = value + elif value: + or_queries.append(value) + if len(or_queries) == 1: query_filter["$or"] = or_queries[0] elif or_queries: From cd167a9055723c941e34c15fd3d5cc8edbaf481e Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 11 Aug 2022 18:00:34 +0200 Subject: [PATCH 126/282] Removed submodule vendor/configs/OpenColorIO-Configs --- .gitmodules | 5 +---- vendor/configs/OpenColorIO-Configs | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) delete mode 160000 vendor/configs/OpenColorIO-Configs diff --git a/.gitmodules b/.gitmodules index bac3132b77..fe93791c4e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,7 +4,4 @@ [submodule "tools/modules/powershell/PSWriteColor"] path = tools/modules/powershell/PSWriteColor - url = https://github.com/EvotecIT/PSWriteColor.git -[submodule "vendor/configs/OpenColorIO-Configs"] - path = vendor/configs/OpenColorIO-Configs - url = https://github.com/imageworks/OpenColorIO-Configs + url = https://github.com/EvotecIT/PSWriteColor.git \ No newline at end of file diff --git a/vendor/configs/OpenColorIO-Configs b/vendor/configs/OpenColorIO-Configs deleted file mode 160000 index 0bb079c08b..0000000000 --- a/vendor/configs/OpenColorIO-Configs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0bb079c08be410030669cbf5f19ff869b88af953 From 37ed6bc897168e42159fb656f06d413b11c601da Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 11 Aug 2022 18:02:21 +0200 Subject: [PATCH 127/282] :recycle: change location of ocio configs --- .../maya/plugins/publish/extract_look.py | 18 +- poetry.lock | 821 +++--------------- pyproject.toml | 4 +- 3 files changed, 131 insertions(+), 712 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index 0b26e922d5..b425efba6f 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -40,15 +40,15 @@ def get_ocio_config_path(profile_folder): Returns: str: Path to vendorized config file. """ - return os.path.join( - os.environ["OPENPYPE_ROOT"], - "vendor", - "configs", - "OpenColorIO-Configs", - profile_folder, - "config.ocio" - ) - + try: + import OpenColorIOConfigs + return os.path.join( + os.path.dirname(OpenColorIOConfigs.__file__), + profile_folder, + "config.ocio" + ) + except ImportError: + return None def find_paths_by_hash(texture_hash): """Find the texture hash key in the dictionary. diff --git a/poetry.lock b/poetry.lock index 919a352505..df8d8ab14a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -48,7 +48,7 @@ aiohttp = ">=3,<4" [[package]] name = "aiohttp-middlewares" -version = "2.0.0" +version = "2.1.0" description = "Collection of useful middlewares for aiohttp applications." category = "main" optional = false @@ -114,7 +114,7 @@ python-dateutil = ">=2.7.0" [[package]] name = "astroid" -version = "2.11.5" +version = "2.11.7" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false @@ -147,7 +147,7 @@ python-versions = ">=3.5" [[package]] name = "atomicwrites" -version = "1.4.0" +version = "1.4.1" description = "Atomic file writes." category = "dev" optional = false @@ -155,17 +155,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "21.4.0" +version = "22.1.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.5" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +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)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] +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"] [[package]] name = "autopep8" @@ -181,11 +181,11 @@ toml = "*" [[package]] name = "babel" -version = "2.9.1" +version = "2.10.3" description = "Internationalization utilities" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.dependencies] pytz = ">=2015.7" @@ -236,7 +236,7 @@ python-versions = ">=3.6" [[package]] name = "cffi" -version = "1.15.0" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -279,7 +279,7 @@ test = ["pytest-runner (>=2.7,<3)", "pytest (>=2.3.5,<5)", "pytest-cov (>=2,<3)" [[package]] name = "colorama" -version = "0.4.4" +version = "0.4.5" description = "Cross-platform colored terminal text." category = "dev" optional = false @@ -306,7 +306,7 @@ python-versions = "*" [[package]] name = "coverage" -version = "6.4.1" +version = "6.4.3" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -320,7 +320,7 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "37.0.2" +version = "37.0.4" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -408,7 +408,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "dropbox" -version = "11.31.0" +version = "11.33.0" description = "Official Dropbox API Client" category = "main" optional = false @@ -433,7 +433,7 @@ prefixed = ">=0.3.2" [[package]] name = "evdev" -version = "1.5.0" +version = "1.6.0" description = "Bindings to the Linux input handling subsystem" category = "main" optional = false @@ -455,7 +455,7 @@ pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "frozenlist" -version = "1.3.0" +version = "1.3.1" description = "A list-like structure which implements collections.abc.MutableSequence" category = "main" optional = false @@ -490,7 +490,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "gazu" -version = "0.8.28" +version = "0.8.30" description = "Gazu is a client for Zou, the API to store the data of your CG production." category = "main" optional = false @@ -530,7 +530,7 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\"" [[package]] name = "google-api-core" -version = "2.8.1" +version = "2.8.2" description = "Google API client core library" category = "main" optional = false @@ -539,13 +539,11 @@ python-versions = ">=3.6" [package.dependencies] google-auth = ">=1.25.0,<3.0dev" googleapis-common-protos = ">=1.56.2,<2.0dev" -protobuf = ">=3.15.0,<4.0.0dev" +protobuf = ">=3.15.0,<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)"] -grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0dev)"] -grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0dev)"] [[package]] name = "google-api-python-client" @@ -565,7 +563,7 @@ uritemplate = ">=3.0.0,<4dev" [[package]] name = "google-auth" -version = "2.7.0" +version = "2.10.0" description = "Google Authentication Library" category = "main" optional = false @@ -598,14 +596,14 @@ six = "*" [[package]] name = "googleapis-common-protos" -version = "1.56.2" +version = "1.56.4" description = "Common protobufs used in Google APIs" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -protobuf = ">=3.15.0,<4.0.0dev" +protobuf = ">=3.15.0,<5.0.0dev" [package.extras] grpc = ["grpcio (>=1.0.0,<2.0.0dev)"] @@ -631,7 +629,7 @@ python-versions = ">=3.5" [[package]] name = "imagesize" -version = "1.3.0" +version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" category = "dev" optional = false @@ -639,7 +637,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.11.4" +version = "4.12.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -652,7 +650,7 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] +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)"] [[package]] name = "iniconfig" @@ -692,15 +690,15 @@ testing = ["colorama", "docopt", "pytest (>=3.1.0)"] [[package]] name = "jeepney" -version = "0.7.1" +version = "0.8.0" description = "Low-level, pure Python DBus protocol wrapper." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -test = ["pytest", "pytest-trio", "pytest-asyncio", "testpath", "trio", "async-timeout"] -trio = ["trio", "async-generator"] +trio = ["async-generator", "trio"] +test = ["async-timeout", "trio", "testpath", "pytest-asyncio (>=0.17)", "pytest-trio", "pytest"] [[package]] name = "jinja2" @@ -799,6 +797,21 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "opencolorio-configs" +version = "1.0.2" +description = "Curated set of OpenColorIO Configs for use in OpenPype" +category = "main" +optional = false +python-versions = "*" +develop = false + +[package.source] +type = "git" +url = "https://github.com/pypeclub/OpenColorIO-Configs.git" +reference = "main" +resolved_reference = "07c5e865bf2b115b589dd2876ae632cd410821b5" + [[package]] name = "opentimelineio" version = "0.14.0.dev1" @@ -875,14 +888,14 @@ six = "*" [[package]] name = "pillow" -version = "9.1.1" +version = "9.2.0" description = "Python Imaging Library (Fork)" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinx-rtd-theme (>=1.0)", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "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]] @@ -930,11 +943,11 @@ python-versions = "*" [[package]] name = "protobuf" -version = "3.19.4" -description = "Protocol Buffers" +version = "4.21.5" +description = "" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [[package]] name = "py" @@ -1354,7 +1367,7 @@ use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "rsa" -version = "4.8" +version = "4.9" description = "Pure-Python RSA implementation" category = "main" optional = false @@ -1408,7 +1421,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "slack-sdk" -version = "3.17.0" +version = "3.18.1" description = "The Slack API Platform SDK for Python" category = "main" optional = false @@ -1487,9 +1500,9 @@ 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" @@ -1638,11 +1651,11 @@ python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "4.0.1" -description = "Backported and Experimental Type Hints for Python 3.6+" +version = "4.3.0" +description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "uritemplate" @@ -1654,11 +1667,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "urllib3" -version = "1.26.9" +version = "1.26.11" 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.*, <4" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" [package.extras] brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] @@ -1711,11 +1724,11 @@ ujson = ["ujson"] [[package]] name = "yarl" -version = "1.7.2" +version = "1.8.1" description = "Yet another URL library" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] idna = ">=2.0" @@ -1724,20 +1737,20 @@ typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [[package]] name = "zipp" -version = "3.8.0" +version = "3.8.1" 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)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] +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)"] [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "bd8e0a03668c380c6e76c8cd6c71020692f4ea9f32de7a4f09433564faa9dad0" +content-hash = "89fb7e8ad310b5048bf78561f1146194c8779e286d839cc000f04e88be87f3f3" [metadata.files] acre = [] @@ -1819,10 +1832,7 @@ 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 = [ - {file = "aiohttp-middlewares-2.0.0.tar.gz", hash = "sha256:e08ba04dc0e8fe379aa5e9444a68485c275677ee1e18c55cbb855de0c3629502"}, - {file = "aiohttp_middlewares-2.0.0-py3-none-any.whl", hash = "sha256:29cf1513176b4013844711975ff520e26a8a5d8f9fefbbddb5e91224a86b043e"}, -] +aiohttp-middlewares = [] aiosignal = [ {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"}, {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"}, @@ -1840,10 +1850,7 @@ arrow = [ {file = "arrow-0.17.0-py2.py3-none-any.whl", hash = "sha256:e098abbd9af3665aea81bdd6c869e93af4feb078e98468dd351c383af187aac5"}, {file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"}, ] -astroid = [ - {file = "astroid-2.11.5-py3-none-any.whl", hash = "sha256:14ffbb4f6aa2cf474a0834014005487f7ecd8924996083ab411e7fa0b508ce0b"}, - {file = "astroid-2.11.5.tar.gz", hash = "sha256:f4e4ec5294c4b07ac38bab9ca5ddd3914d4bf46f9006eb5c0ae755755061044e"}, -] +astroid = [] async-timeout = [ {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, @@ -1852,99 +1859,21 @@ asynctest = [ {file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"}, {file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"}, ] -atomicwrites = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, -] -attrs = [ - {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, - {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, -] +atomicwrites = [] +attrs = [] 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 = [ - {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"}, - {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, -] -bcrypt = [ - {file = "bcrypt-3.2.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40"}, - {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa"}, - {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa"}, - {file = "bcrypt-3.2.2-cp36-abi3-win32.whl", hash = "sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e"}, - {file = "bcrypt-3.2.2-cp36-abi3-win_amd64.whl", hash = "sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129"}, - {file = "bcrypt-3.2.2.tar.gz", hash = "sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb"}, -] +babel = [] +bcrypt = [] 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 = [ - {file = "cachetools-5.2.0-py3-none-any.whl", hash = "sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db"}, - {file = "cachetools-5.2.0.tar.gz", hash = "sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757"}, -] -certifi = [ - {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, - {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"}, -] -cffi = [ - {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, - {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, - {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, - {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, - {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, - {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, - {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, - {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, - {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, - {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, - {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, - {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, - {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, - {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, - {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, - {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, - {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, -] +cachetools = [] +certifi = [] +cffi = [] 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"}, @@ -1957,10 +1886,7 @@ 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 = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] +colorama = [] commonmark = [ {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, @@ -1969,73 +1895,8 @@ coolname = [ {file = "coolname-1.1.0-py2.py3-none-any.whl", hash = "sha256:e6a83a0ac88640f4f3d2070438dbe112fe80cfebc119c93bd402976ec84c0978"}, {file = "coolname-1.1.0.tar.gz", hash = "sha256:410fe6ea9999bf96f2856ef0c726d5f38782bbefb7bb1aca0e91e0dc98ed09e3"}, ] -coverage = [ - {file = "coverage-6.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b"}, - {file = "coverage-6.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068"}, - {file = "coverage-6.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4"}, - {file = "coverage-6.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84"}, - {file = "coverage-6.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad"}, - {file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc"}, - {file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749"}, - {file = "coverage-6.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4"}, - {file = "coverage-6.4.1-cp310-cp310-win32.whl", hash = "sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df"}, - {file = "coverage-6.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6"}, - {file = "coverage-6.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46"}, - {file = "coverage-6.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982"}, - {file = "coverage-6.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4"}, - {file = "coverage-6.4.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb"}, - {file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b"}, - {file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3"}, - {file = "coverage-6.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6"}, - {file = "coverage-6.4.1-cp37-cp37m-win32.whl", hash = "sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e"}, - {file = "coverage-6.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28"}, - {file = "coverage-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54"}, - {file = "coverage-6.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9"}, - {file = "coverage-6.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13"}, - {file = "coverage-6.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9"}, - {file = "coverage-6.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605"}, - {file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d"}, - {file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428"}, - {file = "coverage-6.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83"}, - {file = "coverage-6.4.1-cp38-cp38-win32.whl", hash = "sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b"}, - {file = "coverage-6.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c"}, - {file = "coverage-6.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df"}, - {file = "coverage-6.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d"}, - {file = "coverage-6.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4"}, - {file = "coverage-6.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3"}, - {file = "coverage-6.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3"}, - {file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8"}, - {file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72"}, - {file = "coverage-6.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264"}, - {file = "coverage-6.4.1-cp39-cp39-win32.whl", hash = "sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9"}, - {file = "coverage-6.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397"}, - {file = "coverage-6.4.1-pp36.pp37.pp38-none-any.whl", hash = "sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815"}, - {file = "coverage-6.4.1.tar.gz", hash = "sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c"}, -] -cryptography = [ - {file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181"}, - {file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3c81599befb4d4f3d7648ed3217e00d21a9341a9a688ecdd615ff72ffbed7336"}, - {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2bd1096476aaac820426239ab534b636c77d71af66c547b9ddcd76eb9c79e004"}, - {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:31fe38d14d2e5f787e0aecef831457da6cec68e0bb09a35835b0b44ae8b988fe"}, - {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:093cb351031656d3ee2f4fa1be579a8c69c754cf874206be1d4cf3b542042804"}, - {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59b281eab51e1b6b6afa525af2bd93c16d49358404f814fe2c2410058623928c"}, - {file = "cryptography-37.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:0cc20f655157d4cfc7bada909dc5cc228211b075ba8407c46467f63597c78178"}, - {file = "cryptography-37.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a"}, - {file = "cryptography-37.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:46f4c544f6557a2fefa7ac8ac7d1b17bf9b647bd20b16decc8fbcab7117fbc15"}, - {file = "cryptography-37.0.2-cp36-abi3-win32.whl", hash = "sha256:731c8abd27693323b348518ed0e0705713a36d79fdbd969ad968fbef0979a7e0"}, - {file = "cryptography-37.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:471e0d70201c069f74c837983189949aa0d24bb2d751b57e26e3761f2f782b8d"}, - {file = "cryptography-37.0.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a68254dd88021f24a68b613d8c51d5c5e74d735878b9e32cc0adf19d1f10aaf9"}, - {file = "cryptography-37.0.2-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:a7d5137e556cc0ea418dca6186deabe9129cee318618eb1ffecbd35bee55ddc1"}, - {file = "cryptography-37.0.2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aeaba7b5e756ea52c8861c133c596afe93dd716cbcacae23b80bc238202dc023"}, - {file = "cryptography-37.0.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95e590dd70642eb2079d280420a888190aa040ad20f19ec8c6e097e38aa29e06"}, - {file = "cryptography-37.0.2-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1b9362d34363f2c71b7853f6251219298124aa4cc2075ae2932e64c91a3e2717"}, - {file = "cryptography-37.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e53258e69874a306fcecb88b7534d61820db8a98655662a3dd2ec7f1afd9132f"}, - {file = "cryptography-37.0.2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:1f3bfbd611db5cb58ca82f3deb35e83af34bb8cf06043fa61500157d50a70982"}, - {file = "cryptography-37.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:419c57d7b63f5ec38b1199a9521d77d7d1754eb97827bbb773162073ccd8c8d4"}, - {file = "cryptography-37.0.2-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:dc26bb134452081859aa21d4990474ddb7e863aa39e60d1592800a8865a702de"}, - {file = "cryptography-37.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b8398b3d0efc420e777c40c16764d6870bcef2eb383df9c6dbb9ffe12c64452"}, - {file = "cryptography-37.0.2.tar.gz", hash = "sha256:f224ad253cc9cea7568f49077007d2263efa57396a2f2f78114066fd54b5c68e"}, -] +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"}, @@ -2064,14 +1925,8 @@ cx-logging = [ {file = "cx_Logging-3.0-cp39-cp39-win_amd64.whl", hash = "sha256:302e9c4f65a936c288a4fa59a90e7e142d9ef994aa29676731acafdcccdbb3f5"}, {file = "cx_Logging-3.0.tar.gz", hash = "sha256:ba8a7465facf7b98d8f494030fb481a2e8aeee29dc191e10383bb54ed42bdb34"}, ] -deprecated = [ - {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, - {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, -] -dill = [ - {file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"}, - {file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"}, -] +deprecated = [] +dill = [] dnspython = [ {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, @@ -2080,90 +1935,22 @@ 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 = [ - {file = "dropbox-11.31.0-py2-none-any.whl", hash = "sha256:393a99dfe30d42fd73c265b9b7d24bb21c9a961739cd097c3541e709eb2a209c"}, - {file = "dropbox-11.31.0-py3-none-any.whl", hash = "sha256:5f924102fd6464def81573320c6aa4ea9cd3368e1b1c13d838403dd4c9ffc919"}, - {file = "dropbox-11.31.0.tar.gz", hash = "sha256:f483d65b702775b9abf7b9328f702c68c6397fc01770477c6ddbfb1d858a5bcf"}, -] +dropbox = [] enlighten = [ {file = "enlighten-1.10.2-py2.py3-none-any.whl", hash = "sha256:b237fe562b320bf9f1d4bb76d0c98e0daf914372a76ab87c35cd02f57aa9d8c1"}, {file = "enlighten-1.10.2.tar.gz", hash = "sha256:7a5b83cd0f4d095e59d80c648ebb5f7ffca0cd8bcf7ae6639828ee1ad000632a"}, ] -evdev = [ - {file = "evdev-1.5.0.tar.gz", hash = "sha256:5b33b174f7c84576e7dd6071e438bf5ad227da95efd4356a39fe4c8355412fe6"}, -] +evdev = [] 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 = [ - {file = "frozenlist-1.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2257aaba9660f78c7b1d8fea963b68f3feffb1a9d5d05a18401ca9eb3e8d0a3"}, - {file = "frozenlist-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4a44ebbf601d7bac77976d429e9bdb5a4614f9f4027777f9e54fd765196e9d3b"}, - {file = "frozenlist-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:45334234ec30fc4ea677f43171b18a27505bfb2dba9aca4398a62692c0ea8868"}, - {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47be22dc27ed933d55ee55845d34a3e4e9f6fee93039e7f8ebadb0c2f60d403f"}, - {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03a7dd1bfce30216a3f51a84e6dd0e4a573d23ca50f0346634916ff105ba6e6b"}, - {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:691ddf6dc50480ce49f68441f1d16a4c3325887453837036e0fb94736eae1e58"}, - {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bde99812f237f79eaf3f04ebffd74f6718bbd216101b35ac7955c2d47c17da02"}, - {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a202458d1298ced3768f5a7d44301e7c86defac162ace0ab7434c2e961166e8"}, - {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9e3e9e365991f8cc5f5edc1fd65b58b41d0514a6a7ad95ef5c7f34eb49b3d3e"}, - {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:04cb491c4b1c051734d41ea2552fde292f5f3a9c911363f74f39c23659c4af78"}, - {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:436496321dad302b8b27ca955364a439ed1f0999311c393dccb243e451ff66aa"}, - {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:754728d65f1acc61e0f4df784456106e35afb7bf39cfe37227ab00436fb38676"}, - {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6eb275c6385dd72594758cbe96c07cdb9bd6becf84235f4a594bdf21e3596c9d"}, - {file = "frozenlist-1.3.0-cp310-cp310-win32.whl", hash = "sha256:e30b2f9683812eb30cf3f0a8e9f79f8d590a7999f731cf39f9105a7c4a39489d"}, - {file = "frozenlist-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f7353ba3367473d1d616ee727945f439e027f0bb16ac1a750219a8344d1d5d3c"}, - {file = "frozenlist-1.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88aafd445a233dbbf8a65a62bc3249a0acd0d81ab18f6feb461cc5a938610d24"}, - {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4406cfabef8f07b3b3af0f50f70938ec06d9f0fc26cbdeaab431cbc3ca3caeaa"}, - {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf829bd2e2956066dd4de43fd8ec881d87842a06708c035b37ef632930505a2"}, - {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:603b9091bd70fae7be28bdb8aa5c9990f4241aa33abb673390a7f7329296695f"}, - {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25af28b560e0c76fa41f550eacb389905633e7ac02d6eb3c09017fa1c8cdfde1"}, - {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c7a8a9fc9383b52c410a2ec952521906d355d18fccc927fca52ab575ee8b93"}, - {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:65bc6e2fece04e2145ab6e3c47428d1bbc05aede61ae365b2c1bddd94906e478"}, - {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3f7c935c7b58b0d78c0beea0c7358e165f95f1fd8a7e98baa40d22a05b4a8141"}, - {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd89acd1b8bb4f31b47072615d72e7f53a948d302b7c1d1455e42622de180eae"}, - {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6983a31698490825171be44ffbafeaa930ddf590d3f051e397143a5045513b01"}, - {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:adac9700675cf99e3615eb6a0eb5e9f5a4143c7d42c05cea2e7f71c27a3d0846"}, - {file = "frozenlist-1.3.0-cp37-cp37m-win32.whl", hash = "sha256:0c36e78b9509e97042ef869c0e1e6ef6429e55817c12d78245eb915e1cca7468"}, - {file = "frozenlist-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:57f4d3f03a18facacb2a6bcd21bccd011e3b75d463dc49f838fd699d074fabd1"}, - {file = "frozenlist-1.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8c905a5186d77111f02144fab5b849ab524f1e876a1e75205cd1386a9be4b00a"}, - {file = "frozenlist-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5009062d78a8c6890d50b4e53b0ddda31841b3935c1937e2ed8c1bda1c7fb9d"}, - {file = "frozenlist-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2fdc3cd845e5a1f71a0c3518528bfdbfe2efaf9886d6f49eacc5ee4fd9a10953"}, - {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e650bd09b5dda929523b9f8e7f99b24deac61240ecc1a32aeba487afcd970f"}, - {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40dff8962b8eba91fd3848d857203f0bd704b5f1fa2b3fc9af64901a190bba08"}, - {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:768efd082074bb203c934e83a61654ed4931ef02412c2fbdecea0cff7ecd0274"}, - {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:006d3595e7d4108a12025ddf415ae0f6c9e736e726a5db0183326fd191b14c5e"}, - {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:871d42623ae15eb0b0e9df65baeee6976b2e161d0ba93155411d58ff27483ad8"}, - {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aff388be97ef2677ae185e72dc500d19ecaf31b698986800d3fc4f399a5e30a5"}, - {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9f892d6a94ec5c7b785e548e42722e6f3a52f5f32a8461e82ac3e67a3bd073f1"}, - {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e982878792c971cbd60ee510c4ee5bf089a8246226dea1f2138aa0bb67aff148"}, - {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c6c321dd013e8fc20735b92cb4892c115f5cdb82c817b1e5b07f6b95d952b2f0"}, - {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:30530930410855c451bea83f7b272fb1c495ed9d5cc72895ac29e91279401db3"}, - {file = "frozenlist-1.3.0-cp38-cp38-win32.whl", hash = "sha256:40ec383bc194accba825fbb7d0ef3dda5736ceab2375462f1d8672d9f6b68d07"}, - {file = "frozenlist-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:f20baa05eaa2bcd5404c445ec51aed1c268d62600362dc6cfe04fae34a424bd9"}, - {file = "frozenlist-1.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0437fe763fb5d4adad1756050cbf855bbb2bf0d9385c7bb13d7a10b0dd550486"}, - {file = "frozenlist-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b684c68077b84522b5c7eafc1dc735bfa5b341fb011d5552ebe0968e22ed641c"}, - {file = "frozenlist-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93641a51f89473837333b2f8100f3f89795295b858cd4c7d4a1f18e299dc0a4f"}, - {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6d32ff213aef0fd0bcf803bffe15cfa2d4fde237d1d4838e62aec242a8362fa"}, - {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31977f84828b5bb856ca1eb07bf7e3a34f33a5cddce981d880240ba06639b94d"}, - {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c62964192a1c0c30b49f403495911298810bada64e4f03249ca35a33ca0417a"}, - {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4eda49bea3602812518765810af732229b4291d2695ed24a0a20e098c45a707b"}, - {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acb267b09a509c1df5a4ca04140da96016f40d2ed183cdc356d237286c971b51"}, - {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e1e26ac0a253a2907d654a37e390904426d5ae5483150ce3adedb35c8c06614a"}, - {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f96293d6f982c58ebebb428c50163d010c2f05de0cde99fd681bfdc18d4b2dc2"}, - {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e84cb61b0ac40a0c3e0e8b79c575161c5300d1d89e13c0e02f76193982f066ed"}, - {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:ff9310f05b9d9c5c4dd472983dc956901ee6cb2c3ec1ab116ecdde25f3ce4951"}, - {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d26b650b71fdc88065b7a21f8ace70175bcf3b5bdba5ea22df4bfd893e795a3b"}, - {file = "frozenlist-1.3.0-cp39-cp39-win32.whl", hash = "sha256:01a73627448b1f2145bddb6e6c2259988bb8aee0fb361776ff8604b99616cd08"}, - {file = "frozenlist-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:772965f773757a6026dea111a15e6e2678fbd6216180f82a48a40b27de1ee2ab"}, - {file = "frozenlist-1.3.0.tar.gz", hash = "sha256:ce6f2ba0edb7b0c1d8976565298ad2deba6f8064d2bebb6ffce2ca896eb35b0b"}, -] +frozenlist = [] ftrack-python-api = [] future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, ] -gazu = [ - {file = "gazu-0.8.28-py2.py3-none-any.whl", hash = "sha256:ec4f7c2688a2b37ee8a77737e4e30565ad362428c3ade9046136a998c043e51c"}, -] +gazu = [] gitdb = [ {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, @@ -2172,42 +1959,24 @@ gitpython = [ {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, ] -google-api-core = [ - {file = "google-api-core-2.8.1.tar.gz", hash = "sha256:958024c6aa3460b08f35741231076a4dd9a4c819a6a39d44da9627febe8b28f0"}, - {file = "google_api_core-2.8.1-py3-none-any.whl", hash = "sha256:ce1daa49644b50398093d2a9ad886501aa845e2602af70c3001b9f402a9d7359"}, -] +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 = [ - {file = "google-auth-2.7.0.tar.gz", hash = "sha256:8a954960f852d5f19e6af14dd8e75c20159609e85d8db37e4013cc8c3824a7e1"}, - {file = "google_auth-2.7.0-py2.py3-none-any.whl", hash = "sha256:df549a1433108801b11bdcc0e312eaf0d5f0500db42f0523e4d65c78722e8475"}, -] +google-auth = [] 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 = [ - {file = "googleapis-common-protos-1.56.2.tar.gz", hash = "sha256:b09b56f5463070c2153753ef123f07d2e49235e89148e9b2459ec8ed2f68d7d3"}, - {file = "googleapis_common_protos-1.56.2-py2.py3-none-any.whl", hash = "sha256:023eaea9d8c1cceccd9587c6af6c20f33eeeb05d4148670f2b0322dc1511700c"}, -] +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"}, ] -idna = [ - {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, - {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, -] -imagesize = [ - {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"}, - {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, -] -importlib-metadata = [ - {file = "importlib_metadata-4.11.4-py3-none-any.whl", hash = "sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"}, - {file = "importlib_metadata-4.11.4.tar.gz", hash = "sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700"}, -] +idna = [] +imagesize = [] +importlib-metadata = [] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, @@ -2220,18 +1989,12 @@ jedi = [ {file = "jedi-0.13.3-py2.py3-none-any.whl", hash = "sha256:2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c"}, {file = "jedi-0.13.3.tar.gz", hash = "sha256:2bb0603e3506f708e792c7f4ad8fc2a7a9d9c2d292a358fbbd58da531695595b"}, ] -jeepney = [ - {file = "jeepney-0.7.1-py3-none-any.whl", hash = "sha256:1b5a0ea5c0e7b166b2f5895b91a08c14de8915afda4407fb5022a195224958ac"}, - {file = "jeepney-0.7.1.tar.gz", hash = "sha256:fa9e232dfa0c498bd0b8a3a73b8d8a31978304dcef0515adc859d4e096f96f4f"}, -] +jeepney = [] jinja2 = [ {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, ] -jinxed = [ - {file = "jinxed-1.2.0-py2.py3-none-any.whl", hash = "sha256:cfc2b2e4e3b4326954d546ba6d6b9a7a796ddcb0aef8d03161d005177eb0d48b"}, - {file = "jinxed-1.2.0.tar.gz", hash = "sha256:032acda92d5c57cd216033cbbd53de731e6ed50deb63eb4781336ca55f72cda5"}, -] +jinxed = [] jsonschema = [ {file = "jsonschema-2.6.0-py2.py3-none-any.whl", hash = "sha256:000e68abd33c972a5248544925a0cae7d1125f9bf6c58280d37546b946769a08"}, {file = "jsonschema-2.6.0.tar.gz", hash = "sha256:6ff5f3180870836cae40f06fa10419f557208175f13ad7bc26caa77beb1f6e02"}, @@ -2283,28 +2046,12 @@ log4mongo = [ {file = "log4mongo-1.7.0.tar.gz", hash = "sha256:dc374617206162a0b14167fbb5feac01dbef587539a235dadba6200362984a68"}, ] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, @@ -2313,27 +2060,14 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, @@ -2343,12 +2077,6 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, @@ -2418,15 +2146,13 @@ multidict = [ {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, ] +opencolorio-configs = [] opentimelineio = [] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] -paramiko = [ - {file = "paramiko-2.11.0-py2.py3-none-any.whl", hash = "sha256:655f25dc8baf763277b933dfcea101d636581df8d6b9774d1fb653426b72c270"}, - {file = "paramiko-2.11.0.tar.gz", hash = "sha256:003e6bee7c034c21fbb051bf83dc0a9ee4106204dd3c53054c71452cc4ec3938"}, -] +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"}, @@ -2435,50 +2161,8 @@ 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 = [ - {file = "Pillow-9.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:42dfefbef90eb67c10c45a73a9bc1599d4dac920f7dfcbf4ec6b80cb620757fe"}, - {file = "Pillow-9.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffde4c6fabb52891d81606411cbfaf77756e3b561b566efd270b3ed3791fde4e"}, - {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c857532c719fb30fafabd2371ce9b7031812ff3889d75273827633bca0c4602"}, - {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59789a7d06c742e9d13b883d5e3569188c16acb02eeed2510fd3bfdbc1bd1530"}, - {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d45dbe4b21a9679c3e8b3f7f4f42a45a7d3ddff8a4a16109dff0e1da30a35b2"}, - {file = "Pillow-9.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e9ed59d1b6ee837f4515b9584f3d26cf0388b742a11ecdae0d9237a94505d03a"}, - {file = "Pillow-9.1.1-cp310-cp310-win32.whl", hash = "sha256:b3fe2ff1e1715d4475d7e2c3e8dabd7c025f4410f79513b4ff2de3d51ce0fa9c"}, - {file = "Pillow-9.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5b650dbbc0969a4e226d98a0b440c2f07a850896aed9266b6fedc0f7e7834108"}, - {file = "Pillow-9.1.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:0b4d5ad2cd3a1f0d1df882d926b37dbb2ab6c823ae21d041b46910c8f8cd844b"}, - {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9370d6744d379f2de5d7fa95cdbd3a4d92f0b0ef29609b4b1687f16bc197063d"}, - {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b761727ed7d593e49671d1827044b942dd2f4caae6e51bab144d4accf8244a84"}, - {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a66fe50386162df2da701b3722781cbe90ce043e7d53c1fd6bd801bca6b48d4"}, - {file = "Pillow-9.1.1-cp37-cp37m-win32.whl", hash = "sha256:2b291cab8a888658d72b575a03e340509b6b050b62db1f5539dd5cd18fd50578"}, - {file = "Pillow-9.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1d4331aeb12f6b3791911a6da82de72257a99ad99726ed6b63f481c0184b6fb9"}, - {file = "Pillow-9.1.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8844217cdf66eabe39567118f229e275f0727e9195635a15e0e4b9227458daaf"}, - {file = "Pillow-9.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b6617221ff08fbd3b7a811950b5c3f9367f6e941b86259843eab77c8e3d2b56b"}, - {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20d514c989fa28e73a5adbddd7a171afa5824710d0ab06d4e1234195d2a2e546"}, - {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088df396b047477dd1bbc7de6e22f58400dae2f21310d9e2ec2933b2ef7dfa4f"}, - {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53c27bd452e0f1bc4bfed07ceb235663a1df7c74df08e37fd6b03eb89454946a"}, - {file = "Pillow-9.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3f6c1716c473ebd1649663bf3b42702d0d53e27af8b64642be0dd3598c761fb1"}, - {file = "Pillow-9.1.1-cp38-cp38-win32.whl", hash = "sha256:c67db410508b9de9c4694c57ed754b65a460e4812126e87f5052ecf23a011a54"}, - {file = "Pillow-9.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:f054b020c4d7e9786ae0404278ea318768eb123403b18453e28e47cdb7a0a4bf"}, - {file = "Pillow-9.1.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:c17770a62a71718a74b7548098a74cd6880be16bcfff5f937f900ead90ca8e92"}, - {file = "Pillow-9.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3f6a6034140e9e17e9abc175fc7a266a6e63652028e157750bd98e804a8ed9a"}, - {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f372d0f08eff1475ef426344efe42493f71f377ec52237bf153c5713de987251"}, - {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09e67ef6e430f90caa093528bd758b0616f8165e57ed8d8ce014ae32df6a831d"}, - {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66daa16952d5bf0c9d5389c5e9df562922a59bd16d77e2a276e575d32e38afd1"}, - {file = "Pillow-9.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d78ca526a559fb84faaaf84da2dd4addef5edb109db8b81677c0bb1aad342601"}, - {file = "Pillow-9.1.1-cp39-cp39-win32.whl", hash = "sha256:55e74faf8359ddda43fee01bffbc5bd99d96ea508d8a08c527099e84eb708f45"}, - {file = "Pillow-9.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c150dbbb4a94ea4825d1e5f2c5501af7141ea95825fadd7829f9b11c97aaf6c"}, - {file = "Pillow-9.1.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:769a7f131a2f43752455cc72f9f7a093c3ff3856bf976c5fb53a59d0ccc704f6"}, - {file = "Pillow-9.1.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:488f3383cf5159907d48d32957ac6f9ea85ccdcc296c14eca1a4e396ecc32098"}, - {file = "Pillow-9.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b525a356680022b0af53385944026d3486fc8c013638cf9900eb87c866afb4c"}, - {file = "Pillow-9.1.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6e760cf01259a1c0a50f3c845f9cad1af30577fd8b670339b1659c6d0e7a41dd"}, - {file = "Pillow-9.1.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4165205a13b16a29e1ac57efeee6be2dfd5b5408122d59ef2145bc3239fa340"}, - {file = "Pillow-9.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937a54e5694684f74dcbf6e24cc453bfc5b33940216ddd8f4cd8f0f79167f765"}, - {file = "Pillow-9.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:baf3be0b9446a4083cc0c5bb9f9c964034be5374b5bc09757be89f5d2fa247b8"}, - {file = "Pillow-9.1.1.tar.gz", hash = "sha256:7502539939b53d7565f3d11d87c78e7ec900d3c72945d4ee0e2f250d598309a0"}, -] -platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] +pillow = [] +platformdirs = [] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, @@ -2491,34 +2175,7 @@ prefixed = [ {file = "prefixed-0.3.2-py2.py3-none-any.whl", hash = "sha256:5e107306462d63f2f03c529dbf11b0026fdfec621a9a008ca639d71de22995c3"}, {file = "prefixed-0.3.2.tar.gz", hash = "sha256:ca48277ba5fa8346dd4b760847da930c7b84416387c39e93affef086add2c029"}, ] -protobuf = [ - {file = "protobuf-3.19.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f51d5a9f137f7a2cec2d326a74b6e3fc79d635d69ffe1b036d39fc7d75430d37"}, - {file = "protobuf-3.19.4-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:09297b7972da685ce269ec52af761743714996b4381c085205914c41fcab59fb"}, - {file = "protobuf-3.19.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072fbc78d705d3edc7ccac58a62c4c8e0cec856987da7df8aca86e647be4e35c"}, - {file = "protobuf-3.19.4-cp310-cp310-win32.whl", hash = "sha256:7bb03bc2873a2842e5ebb4801f5c7ff1bfbdf426f85d0172f7644fcda0671ae0"}, - {file = "protobuf-3.19.4-cp310-cp310-win_amd64.whl", hash = "sha256:f358aa33e03b7a84e0d91270a4d4d8f5df6921abe99a377828839e8ed0c04e07"}, - {file = "protobuf-3.19.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1c91ef4110fdd2c590effb5dca8fdbdcb3bf563eece99287019c4204f53d81a4"}, - {file = "protobuf-3.19.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c438268eebb8cf039552897d78f402d734a404f1360592fef55297285f7f953f"}, - {file = "protobuf-3.19.4-cp36-cp36m-win32.whl", hash = "sha256:835a9c949dc193953c319603b2961c5c8f4327957fe23d914ca80d982665e8ee"}, - {file = "protobuf-3.19.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4276cdec4447bd5015453e41bdc0c0c1234eda08420b7c9a18b8d647add51e4b"}, - {file = "protobuf-3.19.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6cbc312be5e71869d9d5ea25147cdf652a6781cf4d906497ca7690b7b9b5df13"}, - {file = "protobuf-3.19.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:54a1473077f3b616779ce31f477351a45b4fef8c9fd7892d6d87e287a38df368"}, - {file = "protobuf-3.19.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:435bb78b37fc386f9275a7035fe4fb1364484e38980d0dd91bc834a02c5ec909"}, - {file = "protobuf-3.19.4-cp37-cp37m-win32.whl", hash = "sha256:16f519de1313f1b7139ad70772e7db515b1420d208cb16c6d7858ea989fc64a9"}, - {file = "protobuf-3.19.4-cp37-cp37m-win_amd64.whl", hash = "sha256:cdc076c03381f5c1d9bb1abdcc5503d9ca8b53cf0a9d31a9f6754ec9e6c8af0f"}, - {file = "protobuf-3.19.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:69da7d39e39942bd52848438462674c463e23963a1fdaa84d88df7fbd7e749b2"}, - {file = "protobuf-3.19.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:48ed3877fa43e22bcacc852ca76d4775741f9709dd9575881a373bd3e85e54b2"}, - {file = "protobuf-3.19.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd95d1dfb9c4f4563e6093a9aa19d9c186bf98fa54da5252531cc0d3a07977e7"}, - {file = "protobuf-3.19.4-cp38-cp38-win32.whl", hash = "sha256:b38057450a0c566cbd04890a40edf916db890f2818e8682221611d78dc32ae26"}, - {file = "protobuf-3.19.4-cp38-cp38-win_amd64.whl", hash = "sha256:7ca7da9c339ca8890d66958f5462beabd611eca6c958691a8fe6eccbd1eb0c6e"}, - {file = "protobuf-3.19.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:36cecbabbda242915529b8ff364f2263cd4de7c46bbe361418b5ed859677ba58"}, - {file = "protobuf-3.19.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c1068287025f8ea025103e37d62ffd63fec8e9e636246b89c341aeda8a67c934"}, - {file = "protobuf-3.19.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96bd766831596d6014ca88d86dc8fe0fb2e428c0b02432fd9db3943202bf8c5e"}, - {file = "protobuf-3.19.4-cp39-cp39-win32.whl", hash = "sha256:84123274d982b9e248a143dadd1b9815049f4477dc783bf84efe6250eb4b836a"}, - {file = "protobuf-3.19.4-cp39-cp39-win_amd64.whl", hash = "sha256:3112b58aac3bac9c8be2b60a9daf6b558ca3f7681c130dcdd788ade7c9ffbdca"}, - {file = "protobuf-3.19.4-py2.py3-none-any.whl", hash = "sha256:8961c3a78ebfcd000920c9060a262f082f29838682b1f7201889300c1fbe0616"}, - {file = "protobuf-3.19.4.tar.gz", hash = "sha256:9df0c10adf3e83015ced42a9a7bd64e13d06c4cf45c340d2c63020ea04499d0a"}, -] +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"}, @@ -2577,14 +2234,8 @@ 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 = [ - {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"}, - {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, -] -pylint = [ - {file = "pylint-2.13.9-py3-none-any.whl", hash = "sha256:705c620d388035bdd9ff8b44c5bcdd235bfb49d276d488dd2c8ff1736aa42526"}, - {file = "pylint-2.13.9.tar.gz", hash = "sha256:095567c96e19e6f57b5b907e67d265ff535e588fe26b12b5ebe1fc5645b2c731"}, -] +pygments = [] +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"}, @@ -2711,42 +2362,10 @@ pynput = [ {file = "pynput-1.7.6-py3.9.egg", hash = "sha256:264429fbe676e98e9050ad26a7017453bdd08768adb25cafb918347cf9f1eb4a"}, {file = "pynput-1.7.6.tar.gz", hash = "sha256:3a5726546da54116b687785d38b1db56997ce1d28e53e8d22fc656d8b92e533c"}, ] -pyobjc-core = [ - {file = "pyobjc-core-8.5.tar.gz", hash = "sha256:704c275439856c0d1287469f0d589a7d808d48b754a93d9ce5415d4eaf06d576"}, - {file = "pyobjc_core-8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0c234143b48334443f5adcf26e668945a6d47bc1fa6223e80918c6c735a029d9"}, - {file = "pyobjc_core-8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1486ee533f0d76f666804ce89723ada4db56bfde55e56151ba512d3f849857f8"}, - {file = "pyobjc_core-8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:412de06dfa728301c04b3e46fd7453320a8ae8b862e85236e547cd797a73b490"}, - {file = "pyobjc_core-8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b3e09cccb1be574a82cc9f929ae27fc4283eccc75496cb5d51534caa6bb83a3"}, - {file = "pyobjc_core-8.5-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:eeafe21f879666ab7f57efcc6b007c9f5f8733d367b7e380c925203ed83f000d"}, - {file = "pyobjc_core-8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c0071686976d7ea8c14690950e504a13cb22b4ebb2bc7b5ec47c1c1c0f6eff41"}, -] -pyobjc-framework-applicationservices = [ - {file = "pyobjc-framework-ApplicationServices-8.5.tar.gz", hash = "sha256:fa3015ef8e3add90af3447d7fdcc7f8dd083cc2a1d58f99a569480a2df10d2b1"}, - {file = "pyobjc_framework_ApplicationServices-8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:436b16ebe448a829a8312e10208eec81a2adcae1fff674dbcc3262e1bd76e0ca"}, - {file = "pyobjc_framework_ApplicationServices-8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:408958d14aa7fcf46f2163754c211078bc63be1368934d86188202914dce077d"}, - {file = "pyobjc_framework_ApplicationServices-8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1d6cd4ce192859a22e208da4d7177a1c3ceb1ef2f64c339fd881102b1210cadd"}, - {file = "pyobjc_framework_ApplicationServices-8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0251d092adb1d2d116fd9f147ceef0e53b158a46c21245131c40b9d7b786d0db"}, - {file = "pyobjc_framework_ApplicationServices-8.5-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:9742e69fe6d4545d0e02b0ad0a7a2432bc9944569ee07d6e90ffa5ef614df9f7"}, - {file = "pyobjc_framework_ApplicationServices-8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16f5677c14ea903c6aaca1dd121521825c39e816cae696d6ae32c0b287252ab2"}, -] -pyobjc-framework-cocoa = [ - {file = "pyobjc-framework-Cocoa-8.5.tar.gz", hash = "sha256:569bd3a020f64b536fb2d1c085b37553e50558c9f907e08b73ffc16ae68e1861"}, - {file = "pyobjc_framework_Cocoa-8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7a7c160416696bf6035dfcdf0e603aaa52858d6afcddfcc5ab41733619ac2529"}, - {file = "pyobjc_framework_Cocoa-8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6ceba444282030be8596b812260e8d28b671254a51052ad778d32da6e17db847"}, - {file = "pyobjc_framework_Cocoa-8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f46b2b161b8dd40c7b9e00bc69636c3e6480b2704a69aee22ee0154befbe163a"}, - {file = "pyobjc_framework_Cocoa-8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b31d425aee8698cbf62b187338f5ca59427fa4dca2153a73866f7cb410713119"}, - {file = "pyobjc_framework_Cocoa-8.5-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:898359ac1f76eedec8aa156847682378a8950824421c40edb89391286e607dc4"}, - {file = "pyobjc_framework_Cocoa-8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:baa2947f76b119a3360973d74d57d6dada87ac527bab9a88f31596af392f123c"}, -] -pyobjc-framework-quartz = [ - {file = "pyobjc-framework-Quartz-8.5.tar.gz", hash = "sha256:d2bc5467a792ddc04814f12a1e9c2fcaf699a1c3ad3d4264cfdce6b9c7b10624"}, - {file = "pyobjc_framework_Quartz-8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e9f0fb663f7872c9de94169031ac42b91ad01bd4cad49a9f1a0164be8f028426"}, - {file = "pyobjc_framework_Quartz-8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:567eec91287cfe9a1b6433717192c585935de8f3daa28d82ce72fdd6c7ac00f6"}, - {file = "pyobjc_framework_Quartz-8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f910ab41a712ffc7a8c3e3716a2d6f39ea4419004b26a2fd2d2f740ff5c262c"}, - {file = "pyobjc_framework_Quartz-8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29d07066781628278bf0e5278abcfc96ef6724c66c5629a0b4c214d319a82e55"}, - {file = "pyobjc_framework_Quartz-8.5-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:72abcde1a3d72be11f2c881c9b9872044c8f2de86d2047b67fe771713638b107"}, - {file = "pyobjc_framework_Quartz-8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8809b9a2df2f461697bdb45b6d1b5a4f881f88f09450e3990858e64e3e26c530"}, -] +pyobjc-core = [] +pyobjc-framework-applicationservices = [] +pyobjc-framework-cocoa = [] +pyobjc-framework-quartz = [] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, @@ -2770,14 +2389,8 @@ python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] -python-engineio = [ - {file = "python-engineio-3.14.2.tar.gz", hash = "sha256:eab4553f2804c1ce97054c8b22cf0d5a9ab23128075248b97e1a5b2f29553085"}, - {file = "python_engineio-3.14.2-py2.py3-none-any.whl", hash = "sha256:5a9e6086d192463b04a1428ff1f85b6ba631bbb19d453b144ffc04f530542b84"}, -] -python-socketio = [ - {file = "python-socketio-4.6.1.tar.gz", hash = "sha256:cd1f5aa492c1eb2be77838e837a495f117e17f686029ebc03d62c09e33f4fa10"}, - {file = "python_socketio-4.6.1-py2.py3-none-any.whl", hash = "sha256:5a21da53fdbdc6bb6c8071f40e13d100e0b279ad997681c2492478e06f370523"}, -] +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"}, @@ -2805,10 +2418,7 @@ 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"}, ] -"qt.py" = [ - {file = "Qt.py-1.3.7-py2.py3-none-any.whl", hash = "sha256:150099d1c6f64c9621a2c9d79d45102ec781c30ee30ee69fc082c6e9be7324fe"}, - {file = "Qt.py-1.3.7.tar.gz", hash = "sha256:803c7bdf4d6230f9a466be19d55934a173eabb61406d21cb91e80c2a3f773b1f"}, -] +"qt.py" = [] qtawesome = [ {file = "QtAwesome-0.7.3-py2.py3-none-any.whl", hash = "sha256:ddf4530b4af71cec13b24b88a4cdb56ec85b1e44c43c42d0698804c7137b09b0"}, {file = "QtAwesome-0.7.3.tar.gz", hash = "sha256:b98b9038d19190e83ab26d91c4d8fc3a36591ee2bc7f5016d4438b8240d097bd"}, @@ -2821,18 +2431,9 @@ recommonmark = [ {file = "recommonmark-0.7.1-py2.py3-none-any.whl", hash = "sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f"}, {file = "recommonmark-0.7.1.tar.gz", hash = "sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67"}, ] -requests = [ - {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, - {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, -] -rsa = [ - {file = "rsa-4.8-py3-none-any.whl", hash = "sha256:95c5d300c4e879ee69708c428ba566c59478fd653cc3a22243eeb8ed846950bb"}, - {file = "rsa-4.8.tar.gz", hash = "sha256:5c6bd9dc7a543b7fe4304a631f8a8a3b674e2bbfc49c2ae96200cdbe55df6b17"}, -] -secretstorage = [ - {file = "SecretStorage-3.3.2-py3-none-any.whl", hash = "sha256:755dc845b6ad76dcbcbc07ea3da75ae54bb1ea529eb72d15f83d26499a5df319"}, - {file = "SecretStorage-3.3.2.tar.gz", hash = "sha256:0a8eb9645b320881c222e827c26f4cfcf55363e8b374a021981ef886657a912f"}, -] +requests = [] +rsa = [] +secretstorage = [] semver = [ {file = "semver-2.13.0-py2.py3-none-any.whl", hash = "sha256:ced8b23dceb22134307c1b8abfa523da14198793d9787ac838e70e29e77458d4"}, {file = "semver-2.13.0.tar.gz", hash = "sha256:fa0fe2722ee1c3f57eac478820c3a5ae2f624af8264cbdf9000c980ff7f75e3f"}, @@ -2842,10 +2443,7 @@ 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 = [ - {file = "slack_sdk-3.17.0-py2.py3-none-any.whl", hash = "sha256:0816efc43d1d2db8286e8dbcbb2e86fd0f71c206c01c521c2cb054ecb40f9ced"}, - {file = "slack_sdk-3.17.0.tar.gz", hash = "sha256:860cd0e50c454b955f14321c8c5486a47cc1e0e84116acdb009107f836752feb"}, -] +slack-sdk = [] smmap = [ {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, @@ -2854,18 +2452,9 @@ snowballstemmer = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] -speedcopy = [ - {file = "speedcopy-2.1.4-py3-none-any.whl", hash = "sha256:e09eb1de67ae0e0b51d5b99a28882009d565a37a3cb3c6bae121e3a5d3cccb17"}, - {file = "speedcopy-2.1.4.tar.gz", hash = "sha256:eff007a97e49ec1934df4fa8074f4bd1cf4a3b14c5499d914988785cff0c199a"}, -] -sphinx = [ - {file = "Sphinx-5.0.1-py3-none-any.whl", hash = "sha256:36aa2a3c2f6d5230be94585bc5d74badd5f9ed8f3388b8eedc1726fe45b1ad30"}, - {file = "Sphinx-5.0.1.tar.gz", hash = "sha256:f4da1187785a5bc7312cc271b0e867a93946c319d106363e102936a3d9857306"}, -] -sphinx-qt-documentation = [ - {file = "sphinx_qt_documentation-0.4-py3-none-any.whl", hash = "sha256:fa131093f75cd1bd48699cd132e18e4d46ba9eaadc070e6026867cea75ecdb7b"}, - {file = "sphinx_qt_documentation-0.4.tar.gz", hash = "sha256:f43ba17baa93e353fb94045027fb67f9d935ed158ce8662de93f08b88eec6774"}, -] +speedcopy = [] +sphinx = [] +sphinx-qt-documentation = [] 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"}, @@ -2914,44 +2503,13 @@ tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -typed-ast = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, -] -typing-extensions = [ - {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, - {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, -] +typed-ast = [] +typing-extensions = [] 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 = [ - {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, - {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, -] +urllib3 = [] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, @@ -2960,151 +2518,10 @@ websocket-client = [ {file = "websocket-client-0.59.0.tar.gz", hash = "sha256:d376bd60eace9d437ab6d7ee16f4ab4e821c9dae591e1b783c58ebd8aaf80c5c"}, {file = "websocket_client-0.59.0-py2.py3-none-any.whl", hash = "sha256:2e50d26ca593f70aba7b13a489435ef88b8fc3b5c5643c1ce8808ff9b40f0b32"}, ] -wrapt = [ - {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, - {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, - {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, - {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, - {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, - {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, - {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, - {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, - {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, - {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, - {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, - {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, - {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, - {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, - {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, - {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, -] +wrapt = [] 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 = [ - {file = "yarl-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95"}, - {file = "yarl-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da6df107b9ccfe52d3a48165e48d72db0eca3e3029b5b8cb4fe6ee3cb870ba8b"}, - {file = "yarl-1.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1d0894f238763717bdcfea74558c94e3bc34aeacd3351d769460c1a586a8b05"}, - {file = "yarl-1.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4b95b7e00c6635a72e2d00b478e8a28bfb122dc76349a06e20792eb53a523"}, - {file = "yarl-1.7.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c145ab54702334c42237a6c6c4cc08703b6aa9b94e2f227ceb3d477d20c36c63"}, - {file = "yarl-1.7.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ca56f002eaf7998b5fcf73b2421790da9d2586331805f38acd9997743114e98"}, - {file = "yarl-1.7.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1d3d5ad8ea96bd6d643d80c7b8d5977b4e2fb1bab6c9da7322616fd26203d125"}, - {file = "yarl-1.7.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:167ab7f64e409e9bdd99333fe8c67b5574a1f0495dcfd905bc7454e766729b9e"}, - {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:95a1873b6c0dd1c437fb3bb4a4aaa699a48c218ac7ca1e74b0bee0ab16c7d60d"}, - {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6152224d0a1eb254f97df3997d79dadd8bb2c1a02ef283dbb34b97d4f8492d23"}, - {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:5bb7d54b8f61ba6eee541fba4b83d22b8a046b4ef4d8eb7f15a7e35db2e1e245"}, - {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:9c1f083e7e71b2dd01f7cd7434a5f88c15213194df38bc29b388ccdf1492b739"}, - {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f44477ae29025d8ea87ec308539f95963ffdc31a82f42ca9deecf2d505242e72"}, - {file = "yarl-1.7.2-cp310-cp310-win32.whl", hash = "sha256:cff3ba513db55cc6a35076f32c4cdc27032bd075c9faef31fec749e64b45d26c"}, - {file = "yarl-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:c9c6d927e098c2d360695f2e9d38870b2e92e0919be07dbe339aefa32a090265"}, - {file = "yarl-1.7.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9b4c77d92d56a4c5027572752aa35082e40c561eec776048330d2907aead891d"}, - {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c01a89a44bb672c38f42b49cdb0ad667b116d731b3f4c896f72302ff77d71656"}, - {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c19324a1c5399b602f3b6e7db9478e5b1adf5cf58901996fc973fe4fccd73eed"}, - {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3abddf0b8e41445426d29f955b24aeecc83fa1072be1be4e0d194134a7d9baee"}, - {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6a1a9fe17621af43e9b9fcea8bd088ba682c8192d744b386ee3c47b56eaabb2c"}, - {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b0915ee85150963a9504c10de4e4729ae700af11df0dc5550e6587ed7891e92"}, - {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:29e0656d5497733dcddc21797da5a2ab990c0cb9719f1f969e58a4abac66234d"}, - {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:bf19725fec28452474d9887a128e98dd67eee7b7d52e932e6949c532d820dc3b"}, - {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d6f3d62e16c10e88d2168ba2d065aa374e3c538998ed04996cd373ff2036d64c"}, - {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ac10bbac36cd89eac19f4e51c032ba6b412b3892b685076f4acd2de18ca990aa"}, - {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aa32aaa97d8b2ed4e54dc65d241a0da1c627454950f7d7b1f95b13985afd6c5d"}, - {file = "yarl-1.7.2-cp36-cp36m-win32.whl", hash = "sha256:87f6e082bce21464857ba58b569370e7b547d239ca22248be68ea5d6b51464a1"}, - {file = "yarl-1.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:ac35ccde589ab6a1870a484ed136d49a26bcd06b6a1c6397b1967ca13ceb3913"}, - {file = "yarl-1.7.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a467a431a0817a292121c13cbe637348b546e6ef47ca14a790aa2fa8cc93df63"}, - {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ab0c3274d0a846840bf6c27d2c60ba771a12e4d7586bf550eefc2df0b56b3b4"}, - {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d260d4dc495c05d6600264a197d9d6f7fc9347f21d2594926202fd08cf89a8ba"}, - {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc4dd8b01a8112809e6b636b00f487846956402834a7fd59d46d4f4267181c41"}, - {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c1164a2eac148d85bbdd23e07dfcc930f2e633220f3eb3c3e2a25f6148c2819e"}, - {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:67e94028817defe5e705079b10a8438b8cb56e7115fa01640e9c0bb3edf67332"}, - {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:89ccbf58e6a0ab89d487c92a490cb5660d06c3a47ca08872859672f9c511fc52"}, - {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8cce6f9fa3df25f55521fbb5c7e4a736683148bcc0c75b21863789e5185f9185"}, - {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:211fcd65c58bf250fb994b53bc45a442ddc9f441f6fec53e65de8cba48ded986"}, - {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c10ea1e80a697cf7d80d1ed414b5cb8f1eec07d618f54637067ae3c0334133c4"}, - {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:52690eb521d690ab041c3919666bea13ab9fbff80d615ec16fa81a297131276b"}, - {file = "yarl-1.7.2-cp37-cp37m-win32.whl", hash = "sha256:695ba021a9e04418507fa930d5f0704edbce47076bdcfeeaba1c83683e5649d1"}, - {file = "yarl-1.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c17965ff3706beedafd458c452bf15bac693ecd146a60a06a214614dc097a271"}, - {file = "yarl-1.7.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fce78593346c014d0d986b7ebc80d782b7f5e19843ca798ed62f8e3ba8728576"}, - {file = "yarl-1.7.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c2a1ac41a6aa980db03d098a5531f13985edcb451bcd9d00670b03129922cd0d"}, - {file = "yarl-1.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:39d5493c5ecd75c8093fa7700a2fb5c94fe28c839c8e40144b7ab7ccba6938c8"}, - {file = "yarl-1.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1eb6480ef366d75b54c68164094a6a560c247370a68c02dddb11f20c4c6d3c9d"}, - {file = "yarl-1.7.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ba63585a89c9885f18331a55d25fe81dc2d82b71311ff8bd378fc8004202ff6"}, - {file = "yarl-1.7.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e39378894ee6ae9f555ae2de332d513a5763276a9265f8e7cbaeb1b1ee74623a"}, - {file = "yarl-1.7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c0910c6b6c31359d2f6184828888c983d54d09d581a4a23547a35f1d0b9484b1"}, - {file = "yarl-1.7.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6feca8b6bfb9eef6ee057628e71e1734caf520a907b6ec0d62839e8293e945c0"}, - {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8300401dc88cad23f5b4e4c1226f44a5aa696436a4026e456fe0e5d2f7f486e6"}, - {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:788713c2896f426a4e166b11f4ec538b5736294ebf7d5f654ae445fd44270832"}, - {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fd547ec596d90c8676e369dd8a581a21227fe9b4ad37d0dc7feb4ccf544c2d59"}, - {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:737e401cd0c493f7e3dd4db72aca11cfe069531c9761b8ea474926936b3c57c8"}, - {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baf81561f2972fb895e7844882898bda1eef4b07b5b385bcd308d2098f1a767b"}, - {file = "yarl-1.7.2-cp38-cp38-win32.whl", hash = "sha256:ede3b46cdb719c794427dcce9d8beb4abe8b9aa1e97526cc20de9bd6583ad1ef"}, - {file = "yarl-1.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:cc8b7a7254c0fc3187d43d6cb54b5032d2365efd1df0cd1749c0c4df5f0ad45f"}, - {file = "yarl-1.7.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:580c1f15500e137a8c37053e4cbf6058944d4c114701fa59944607505c2fe3a0"}, - {file = "yarl-1.7.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ec1d9a0d7780416e657f1e405ba35ec1ba453a4f1511eb8b9fbab81cb8b3ce1"}, - {file = "yarl-1.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3bf8cfe8856708ede6a73907bf0501f2dc4e104085e070a41f5d88e7faf237f3"}, - {file = "yarl-1.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1be4bbb3d27a4e9aa5f3df2ab61e3701ce8fcbd3e9846dbce7c033a7e8136746"}, - {file = "yarl-1.7.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:534b047277a9a19d858cde163aba93f3e1677d5acd92f7d10ace419d478540de"}, - {file = "yarl-1.7.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6ddcd80d79c96eb19c354d9dca95291589c5954099836b7c8d29278a7ec0bda"}, - {file = "yarl-1.7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9bfcd43c65fbb339dc7086b5315750efa42a34eefad0256ba114cd8ad3896f4b"}, - {file = "yarl-1.7.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f64394bd7ceef1237cc604b5a89bf748c95982a84bcd3c4bbeb40f685c810794"}, - {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044daf3012e43d4b3538562da94a88fb12a6490652dbc29fb19adfa02cf72eac"}, - {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:368bcf400247318382cc150aaa632582d0780b28ee6053cd80268c7e72796dec"}, - {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:bab827163113177aee910adb1f48ff7af31ee0289f434f7e22d10baf624a6dfe"}, - {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0cba38120db72123db7c58322fa69e3c0efa933040ffb586c3a87c063ec7cae8"}, - {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:59218fef177296451b23214c91ea3aba7858b4ae3306dde120224cfe0f7a6ee8"}, - {file = "yarl-1.7.2-cp39-cp39-win32.whl", hash = "sha256:1edc172dcca3f11b38a9d5c7505c83c1913c0addc99cd28e993efeaafdfaa18d"}, - {file = "yarl-1.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:797c2c412b04403d2da075fb93c123df35239cd7b4cc4e0cd9e5839b73f52c58"}, - {file = "yarl-1.7.2.tar.gz", hash = "sha256:45399b46d60c253327a460e99856752009fcee5f5d3c80b2f7c0cae1c38d56dd"}, -] -zipp = [ - {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, - {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, -] +yarl = [] +zipp = [] diff --git a/pyproject.toml b/pyproject.toml index 994c83d369..1d757deaa0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,7 @@ requests = "^2.25.1" pysftp = "^0.2.9" dropbox = "^11.20.0" aiohttp-middlewares = "^2.0.0" +OpenColorIO-Configs = { git = "https://github.com/pypeclub/OpenColorIO-Configs.git", branch = "main" } [tool.poetry.dev-dependencies] @@ -80,13 +81,14 @@ cx_freeze = "~6.9" GitPython = "^3.1.17" jedi = "^0.13" Jinja2 = "^2.11" +markupsafe = "2.0.1" pycodestyle = "^2.5.0" pydocstyle = "^3.0.0" pylint = "^2.4.4" pytest = "^6.1" pytest-cov = "*" pytest-print = "*" -Sphinx = "*" +Sphinx = "5.0.1" sphinx-rtd-theme = "*" sphinxcontrib-websupport = "*" sphinx-qt-documentation = "*" From 8ba5d0079952731a2e7a98490701750bffa28a9e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 18:59:43 +0200 Subject: [PATCH 128/282] move env setup function used in prelaunch hook from api higher --- openpype/hosts/resolve/utils.py | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 openpype/hosts/resolve/utils.py diff --git a/openpype/hosts/resolve/utils.py b/openpype/hosts/resolve/utils.py new file mode 100644 index 0000000000..382a7cf344 --- /dev/null +++ b/openpype/hosts/resolve/utils.py @@ -0,0 +1,54 @@ +import os +import shutil +from openpype.lib import Logger + +RESOLVE_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) + + +def setup(env): + log = Logger.get_logger("ResolveSetup") + scripts = {} + us_env = env.get("RESOLVE_UTILITY_SCRIPTS_SOURCE_DIR") + us_dir = env.get("RESOLVE_UTILITY_SCRIPTS_DIR", "") + us_paths = [os.path.join( + RESOLVE_ROOT_DIR, + "utility_scripts" + )] + + # collect script dirs + if us_env: + log.info(f"Utility Scripts Env: `{us_env}`") + us_paths = us_env.split( + os.pathsep) + us_paths + + # collect scripts from dirs + for path in us_paths: + scripts.update({path: os.listdir(path)}) + + log.info(f"Utility Scripts Dir: `{us_paths}`") + log.info(f"Utility Scripts: `{scripts}`") + + # make sure no script file is in folder + for s in os.listdir(us_dir): + path = os.path.join(us_dir, s) + log.info(f"Removing `{path}`...") + if os.path.isdir(path): + shutil.rmtree(path, onerror=None) + else: + os.remove(path) + + # copy scripts into Resolve's utility scripts dir + for d, sl in scripts.items(): + # directory and scripts list + for s in sl: + # script in script list + src = os.path.join(d, s) + dst = os.path.join(us_dir, s) + log.info(f"Copying `{src}` to `{dst}`...") + if os.path.isdir(src): + shutil.copytree( + src, dst, symlinks=False, + ignore=None, ignore_dangling_symlinks=False + ) + else: + shutil.copy2(src, dst) From 07d89fc23b593890d10f7094af2be04399f8dedd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 19:01:24 +0200 Subject: [PATCH 129/282] fixed imports to use in-DCC imports from resolve.api --- openpype/hosts/resolve/__init__.py | 129 ----------------- openpype/hosts/resolve/api/__init__.py | 134 +++++++++++++++++- openpype/hosts/resolve/api/action.py | 2 +- openpype/hosts/resolve/api/lib.py | 6 +- openpype/hosts/resolve/api/menu.py | 4 +- openpype/hosts/resolve/api/pipeline.py | 13 +- openpype/hosts/resolve/api/preload_console.py | 4 +- openpype/hosts/resolve/api/utils.py | 96 ++----------- openpype/hosts/resolve/api/workio.py | 19 +-- .../hosts/resolve/hooks/pre_resolve_setup.py | 20 +-- .../plugins/create/create_shot_clip.py | 15 +- .../hosts/resolve/plugins/load/load_clip.py | 21 +-- .../plugins/publish/extract_workfile.py | 4 +- .../plugins/publish/precollect_instances.py | 26 ++-- .../OpenPype_sync_util_scripts.py | 5 +- .../utility_scripts/__OpenPype__Menu__.py | 6 +- .../utility_scripts/tests/test_otio_as_edl.py | 4 +- .../testing_create_timeline_item_from_path.py | 15 +- .../tests/testing_load_media_pool_item.py | 10 +- 19 files changed, 233 insertions(+), 300 deletions(-) diff --git a/openpype/hosts/resolve/__init__.py b/openpype/hosts/resolve/__init__.py index 3e49ce3b9b..e69de29bb2 100644 --- a/openpype/hosts/resolve/__init__.py +++ b/openpype/hosts/resolve/__init__.py @@ -1,129 +0,0 @@ -from .api.utils import ( - setup, - get_resolve_module -) - -from .api.pipeline import ( - install, - uninstall, - ls, - containerise, - update_container, - publish, - launch_workfiles_app, - maintained_selection, - remove_instance, - list_instances -) - -from .api.lib import ( - maintain_current_timeline, - publish_clip_color, - get_project_manager, - get_current_project, - get_current_timeline, - create_bin, - get_media_pool_item, - create_media_pool_item, - create_timeline_item, - get_timeline_item, - get_video_track_names, - get_current_timeline_items, - get_pype_timeline_item_by_name, - get_timeline_item_pype_tag, - set_timeline_item_pype_tag, - imprint, - set_publish_attribute, - get_publish_attribute, - create_compound_clip, - swap_clips, - get_pype_clip_metadata, - set_project_manager_to_folder_name, - get_otio_clip_instance_data, - get_reformated_path -) - -from .api.menu import launch_pype_menu - -from .api.plugin import ( - ClipLoader, - TimelineItemLoader, - Creator, - PublishClip -) - -from .api.workio import ( - open_file, - save_file, - current_file, - has_unsaved_changes, - file_extensions, - work_root -) - -from .api.testing_utils import TestGUI - - -__all__ = [ - # pipeline - "install", - "uninstall", - "ls", - "containerise", - "update_container", - "reload_pipeline", - "publish", - "launch_workfiles_app", - "maintained_selection", - "remove_instance", - "list_instances", - - # utils - "setup", - "get_resolve_module", - - # lib - "maintain_current_timeline", - "publish_clip_color", - "get_project_manager", - "get_current_project", - "get_current_timeline", - "create_bin", - "get_media_pool_item", - "create_media_pool_item", - "create_timeline_item", - "get_timeline_item", - "get_video_track_names", - "get_current_timeline_items", - "get_pype_timeline_item_by_name", - "get_timeline_item_pype_tag", - "set_timeline_item_pype_tag", - "imprint", - "set_publish_attribute", - "get_publish_attribute", - "create_compound_clip", - "swap_clips", - "get_pype_clip_metadata", - "set_project_manager_to_folder_name", - "get_otio_clip_instance_data", - "get_reformated_path", - - # menu - "launch_pype_menu", - - # plugin - "ClipLoader", - "TimelineItemLoader", - "Creator", - "PublishClip", - - # workio - "open_file", - "save_file", - "current_file", - "has_unsaved_changes", - "file_extensions", - "work_root", - - "TestGUI" -] diff --git a/openpype/hosts/resolve/api/__init__.py b/openpype/hosts/resolve/api/__init__.py index 48bd938e57..cf1edb4c35 100644 --- a/openpype/hosts/resolve/api/__init__.py +++ b/openpype/hosts/resolve/api/__init__.py @@ -1,11 +1,137 @@ """ resolve api """ -import os bmdvr = None bmdvf = None -API_DIR = os.path.dirname(os.path.abspath(__file__)) -HOST_DIR = os.path.dirname(API_DIR) -PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") +from .utils import ( + get_resolve_module +) + +from .pipeline import ( + install, + uninstall, + ls, + containerise, + update_container, + publish, + launch_workfiles_app, + maintained_selection, + remove_instance, + list_instances +) + +from .lib import ( + maintain_current_timeline, + publish_clip_color, + get_project_manager, + get_current_project, + get_current_timeline, + create_bin, + get_media_pool_item, + create_media_pool_item, + create_timeline_item, + get_timeline_item, + get_video_track_names, + get_current_timeline_items, + get_pype_timeline_item_by_name, + get_timeline_item_pype_tag, + set_timeline_item_pype_tag, + imprint, + set_publish_attribute, + get_publish_attribute, + create_compound_clip, + swap_clips, + get_pype_clip_metadata, + set_project_manager_to_folder_name, + get_otio_clip_instance_data, + get_reformated_path +) + +from .menu import launch_pype_menu + +from .plugin import ( + ClipLoader, + TimelineItemLoader, + Creator, + PublishClip +) + +from .workio import ( + open_file, + save_file, + current_file, + has_unsaved_changes, + file_extensions, + work_root +) + +from .testing_utils import TestGUI + + +__all__ = [ + "bmdvr", + "bmdvf", + + # pipeline + "install", + "uninstall", + "ls", + "containerise", + "update_container", + "reload_pipeline", + "publish", + "launch_workfiles_app", + "maintained_selection", + "remove_instance", + "list_instances", + + # utils + "get_resolve_module", + + # lib + "maintain_current_timeline", + "publish_clip_color", + "get_project_manager", + "get_current_project", + "get_current_timeline", + "create_bin", + "get_media_pool_item", + "create_media_pool_item", + "create_timeline_item", + "get_timeline_item", + "get_video_track_names", + "get_current_timeline_items", + "get_pype_timeline_item_by_name", + "get_timeline_item_pype_tag", + "set_timeline_item_pype_tag", + "imprint", + "set_publish_attribute", + "get_publish_attribute", + "create_compound_clip", + "swap_clips", + "get_pype_clip_metadata", + "set_project_manager_to_folder_name", + "get_otio_clip_instance_data", + "get_reformated_path", + + # menu + "launch_pype_menu", + + # plugin + "ClipLoader", + "TimelineItemLoader", + "Creator", + "PublishClip", + + # workio + "open_file", + "save_file", + "current_file", + "has_unsaved_changes", + "file_extensions", + "work_root", + + "TestGUI" +] diff --git a/openpype/hosts/resolve/api/action.py b/openpype/hosts/resolve/api/action.py index f8f338a850..d55a24a39a 100644 --- a/openpype/hosts/resolve/api/action.py +++ b/openpype/hosts/resolve/api/action.py @@ -4,7 +4,7 @@ from __future__ import absolute_import import pyblish.api -from ...action import get_errored_instances_from_context +from openpype.action import get_errored_instances_from_context class SelectInvalidAction(pyblish.api.Action): diff --git a/openpype/hosts/resolve/api/lib.py b/openpype/hosts/resolve/api/lib.py index 93ccdaf812..f41eb36caf 100644 --- a/openpype/hosts/resolve/api/lib.py +++ b/openpype/hosts/resolve/api/lib.py @@ -4,13 +4,13 @@ import re import os import contextlib from opentimelineio import opentime + +from openpype.lib import Logger from openpype.pipeline.editorial import is_overlapping_otio_ranges from ..otio import davinci_export as otio_export -from openpype.api import Logger - -log = Logger().get_logger(__name__) +log = Logger.get_logger(__name__) self = sys.modules[__name__] self.project_manager = None diff --git a/openpype/hosts/resolve/api/menu.py b/openpype/hosts/resolve/api/menu.py index 9e0dd12376..2c7678ee5b 100644 --- a/openpype/hosts/resolve/api/menu.py +++ b/openpype/hosts/resolve/api/menu.py @@ -3,13 +3,13 @@ import sys from Qt import QtWidgets, QtCore +from openpype.tools.utils import host_tools + from .pipeline import ( publish, launch_workfiles_app ) -from openpype.tools.utils import host_tools - def load_stylesheet(): path = os.path.join(os.path.dirname(__file__), "menu_style.qss") diff --git a/openpype/hosts/resolve/api/pipeline.py b/openpype/hosts/resolve/api/pipeline.py index 4a7d1c5bea..1c8d9dc01c 100644 --- a/openpype/hosts/resolve/api/pipeline.py +++ b/openpype/hosts/resolve/api/pipeline.py @@ -7,7 +7,7 @@ from collections import OrderedDict from pyblish import api as pyblish -from openpype.api import Logger +from openpype.lib import Logger from openpype.pipeline import ( schema, register_loader_plugin_path, @@ -16,11 +16,15 @@ from openpype.pipeline import ( deregister_creator_plugin_path, AVALON_CONTAINER_ID, ) -from . import lib -from . import PLUGINS_DIR from openpype.tools.utils import host_tools -log = Logger().get_logger(__name__) +from . import lib +from .utils import get_resolve_module + +log = Logger.get_logger(__name__) + +HOST_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) +PLUGINS_DIR = os.path.join(HOST_DIR, "plugins") PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish") LOAD_PATH = os.path.join(PLUGINS_DIR, "load") CREATE_PATH = os.path.join(PLUGINS_DIR, "create") @@ -39,7 +43,6 @@ def install(): See the Maya equivalent for inspiration on how to implement this. """ - from .. import get_resolve_module log.info("openpype.hosts.resolve installed") diff --git a/openpype/hosts/resolve/api/preload_console.py b/openpype/hosts/resolve/api/preload_console.py index 1e3a56b4dd..a822ea2460 100644 --- a/openpype/hosts/resolve/api/preload_console.py +++ b/openpype/hosts/resolve/api/preload_console.py @@ -1,9 +1,9 @@ #!/usr/bin/env python import time from openpype.hosts.resolve.utils import get_resolve_module -from openpype.api import Logger +from openpype.lib import Logger -log = Logger().get_logger(__name__) +log = Logger.get_logger(__name__) wait_delay = 2.5 wait = 0.00 diff --git a/openpype/hosts/resolve/api/utils.py b/openpype/hosts/resolve/api/utils.py index 9b3762f328..871b3af38d 100644 --- a/openpype/hosts/resolve/api/utils.py +++ b/openpype/hosts/resolve/api/utils.py @@ -4,21 +4,21 @@ Resolve's tools for setting environment """ -import sys import os -import shutil -from . import HOST_DIR -from openpype.api import Logger -log = Logger().get_logger(__name__) +import sys + +from openpype.lib import Logger + +log = Logger.get_logger(__name__) def get_resolve_module(): - from openpype.hosts import resolve + from openpype.hosts.resolve import api # dont run if already loaded - if resolve.api.bmdvr: + if api.bmdvr: log.info(("resolve module is assigned to " - f"`pype.hosts.resolve.api.bmdvr`: {resolve.api.bmdvr}")) - return resolve.api.bmdvr + f"`pype.hosts.resolve.api.bmdvr`: {api.bmdvr}")) + return api.bmdvr try: """ The PYTHONPATH needs to be set correctly for this import @@ -71,79 +71,9 @@ def get_resolve_module(): # assign global var and return bmdvr = bmd.scriptapp("Resolve") bmdvf = bmd.scriptapp("Fusion") - resolve.api.bmdvr = bmdvr - resolve.api.bmdvf = bmdvf + api.bmdvr = bmdvr + api.bmdvf = bmdvf log.info(("Assigning resolve module to " - f"`pype.hosts.resolve.api.bmdvr`: {resolve.api.bmdvr}")) + f"`pype.hosts.resolve.api.bmdvr`: {api.bmdvr}")) log.info(("Assigning resolve module to " - f"`pype.hosts.resolve.api.bmdvf`: {resolve.api.bmdvf}")) - - -def _sync_utility_scripts(env=None): - """ Synchronizing basic utlility scripts for resolve. - - To be able to run scripts from inside `Resolve/Workspace/Scripts` menu - all scripts has to be accessible from defined folder. - """ - if not env: - env = os.environ - - # initiate inputs - scripts = {} - us_env = env.get("RESOLVE_UTILITY_SCRIPTS_SOURCE_DIR") - us_dir = env.get("RESOLVE_UTILITY_SCRIPTS_DIR", "") - us_paths = [os.path.join( - HOST_DIR, - "utility_scripts" - )] - - # collect script dirs - if us_env: - log.info(f"Utility Scripts Env: `{us_env}`") - us_paths = us_env.split( - os.pathsep) + us_paths - - # collect scripts from dirs - for path in us_paths: - scripts.update({path: os.listdir(path)}) - - log.info(f"Utility Scripts Dir: `{us_paths}`") - log.info(f"Utility Scripts: `{scripts}`") - - # make sure no script file is in folder - if next((s for s in os.listdir(us_dir)), None): - for s in os.listdir(us_dir): - path = os.path.join(us_dir, s) - log.info(f"Removing `{path}`...") - if os.path.isdir(path): - shutil.rmtree(path, onerror=None) - else: - os.remove(path) - - # copy scripts into Resolve's utility scripts dir - for d, sl in scripts.items(): - # directory and scripts list - for s in sl: - # script in script list - src = os.path.join(d, s) - dst = os.path.join(us_dir, s) - log.info(f"Copying `{src}` to `{dst}`...") - if os.path.isdir(src): - shutil.copytree( - src, dst, symlinks=False, - ignore=None, ignore_dangling_symlinks=False - ) - else: - shutil.copy2(src, dst) - - -def setup(env=None): - """ Wrapper installer started from pype.hooks.resolve.ResolvePrelaunch() - """ - if not env: - env = os.environ - - # synchronize resolve utility scripts - _sync_utility_scripts(env) - - log.info("Resolve OpenPype wrapper has been installed") + f"`pype.hosts.resolve.api.bmdvf`: {api.bmdvf}")) diff --git a/openpype/hosts/resolve/api/workio.py b/openpype/hosts/resolve/api/workio.py index f175769387..5a742ecf7e 100644 --- a/openpype/hosts/resolve/api/workio.py +++ b/openpype/hosts/resolve/api/workio.py @@ -2,14 +2,14 @@ import os from openpype.api import Logger -from .. import ( +from .lib import ( get_project_manager, get_current_project, set_project_manager_to_folder_name ) -log = Logger().get_logger(__name__) +log = Logger.get_logger(__name__) exported_projet_ext = ".drp" @@ -60,7 +60,7 @@ def open_file(filepath): # load project from input path project = pm.LoadProject(fname) log.info(f"Project {project.GetName()} opened...") - return True + except AttributeError: log.warning((f"Project with name `{fname}` does not exist! It will " f"be imported from {filepath} and then loaded...")) @@ -69,9 +69,8 @@ def open_file(filepath): project = pm.LoadProject(fname) log.info(f"Project imported/loaded {project.GetName()}...") return True - else: - return False - + return False + return True def current_file(): pm = get_project_manager() @@ -80,13 +79,9 @@ def current_file(): name = project.GetName() fname = name + exported_projet_ext current_file = os.path.join(current_dir, fname) - normalised = os.path.normpath(current_file) - - # Unsaved current file - if normalised == "": + if not current_file: return None - - return normalised + return os.path.normpath(current_file) def work_root(session): diff --git a/openpype/hosts/resolve/hooks/pre_resolve_setup.py b/openpype/hosts/resolve/hooks/pre_resolve_setup.py index 978e3760fd..1d977e2d8e 100644 --- a/openpype/hosts/resolve/hooks/pre_resolve_setup.py +++ b/openpype/hosts/resolve/hooks/pre_resolve_setup.py @@ -1,7 +1,7 @@ import os -import importlib + from openpype.lib import PreLaunchHook -from openpype.hosts.resolve.api import utils +from openpype.hosts.resolve.utils import setup class ResolvePrelaunch(PreLaunchHook): @@ -43,18 +43,6 @@ class ResolvePrelaunch(PreLaunchHook): self.launch_context.env.get("PRE_PYTHON_SCRIPT", "")) self.launch_context.env["PRE_PYTHON_SCRIPT"] = pre_py_sc self.log.debug(f"-- pre_py_sc: `{pre_py_sc}`...") - try: - __import__("openpype.hosts.resolve") - __import__("pyblish") - except ImportError: - self.log.warning( - "pyblish: Could not load Resolve integration.", - exc_info=True - ) - - else: - # Resolve Setup integration - importlib.reload(utils) - self.log.debug(f"-- utils.__file__: `{utils.__file__}`") - utils.setup(self.launch_context.env) + # Resolve Setup integration + setup(self.launch_context.env) diff --git a/openpype/hosts/resolve/plugins/create/create_shot_clip.py b/openpype/hosts/resolve/plugins/create/create_shot_clip.py index dbf10c5163..4b14f2493f 100644 --- a/openpype/hosts/resolve/plugins/create/create_shot_clip.py +++ b/openpype/hosts/resolve/plugins/create/create_shot_clip.py @@ -1,9 +1,12 @@ # from pprint import pformat -from openpype.hosts import resolve -from openpype.hosts.resolve.api import lib +from openpype.hosts.resolve.api import plugin, lib +from openpype.hosts.resolve.api.lib import ( + get_video_track_names, + create_bin, +) -class CreateShotClip(resolve.Creator): +class CreateShotClip(plugin.Creator): """Publishable clip""" label = "Create Publishable Clip" @@ -11,7 +14,7 @@ class CreateShotClip(resolve.Creator): icon = "film" defaults = ["Main"] - gui_tracks = resolve.get_video_track_names() + gui_tracks = get_video_track_names() gui_name = "OpenPype publish attributes creator" gui_info = "Define sequential rename and fill hierarchy data." gui_inputs = { @@ -250,7 +253,7 @@ class CreateShotClip(resolve.Creator): sq_markers = self.timeline.GetMarkers() # create media bin for compound clips (trackItems) - mp_folder = resolve.create_bin(self.timeline.GetName()) + mp_folder = create_bin(self.timeline.GetName()) kwargs = { "ui_inputs": widget.result, @@ -264,6 +267,6 @@ class CreateShotClip(resolve.Creator): self.rename_index = i self.log.info(track_item_data) # convert track item to timeline media pool item - track_item = resolve.PublishClip( + track_item = plugin.PublishClip( self, track_item_data, **kwargs).convert() track_item.SetClipColor(lib.publish_clip_color) diff --git a/openpype/hosts/resolve/plugins/load/load_clip.py b/openpype/hosts/resolve/plugins/load/load_clip.py index 190a5a7206..a0c78c182f 100644 --- a/openpype/hosts/resolve/plugins/load/load_clip.py +++ b/openpype/hosts/resolve/plugins/load/load_clip.py @@ -1,21 +1,22 @@ from copy import deepcopy -from importlib import reload from openpype.client import ( get_version_by_id, get_last_version_by_subset_id, ) -from openpype.hosts import resolve +# from openpype.hosts import resolve from openpype.pipeline import ( get_representation_path, legacy_io, ) from openpype.hosts.resolve.api import lib, plugin -reload(plugin) -reload(lib) +from openpype.hosts.resolve.api.pipeline import ( + containerise, + update_container, +) -class LoadClip(resolve.TimelineItemLoader): +class LoadClip(plugin.TimelineItemLoader): """Load a subset to timeline as clip Place clip to timeline on its asset origin timings collected @@ -46,7 +47,7 @@ class LoadClip(resolve.TimelineItemLoader): }) # load clip to timeline and get main variables - timeline_item = resolve.ClipLoader( + timeline_item = plugin.ClipLoader( self, context, **options).load() namespace = namespace or timeline_item.GetName() version = context['version'] @@ -80,7 +81,7 @@ class LoadClip(resolve.TimelineItemLoader): self.log.info("Loader done: `{}`".format(name)) - return resolve.containerise( + return containerise( timeline_item, name, namespace, context, self.__class__.__name__, @@ -98,7 +99,7 @@ class LoadClip(resolve.TimelineItemLoader): context.update({"representation": representation}) name = container['name'] namespace = container['namespace'] - timeline_item_data = resolve.get_pype_timeline_item_by_name(namespace) + timeline_item_data = lib.get_pype_timeline_item_by_name(namespace) timeline_item = timeline_item_data["clip"]["item"] project_name = legacy_io.active_project() version = get_version_by_id(project_name, representation["parent"]) @@ -109,7 +110,7 @@ class LoadClip(resolve.TimelineItemLoader): self.fname = get_representation_path(representation) context["version"] = {"data": version_data} - loader = resolve.ClipLoader(self, context) + loader = plugin.ClipLoader(self, context) timeline_item = loader.update(timeline_item) # add additional metadata from the version to imprint Avalon knob @@ -136,7 +137,7 @@ class LoadClip(resolve.TimelineItemLoader): # update color of clip regarding the version order self.set_item_color(timeline_item, version) - return resolve.update_container(timeline_item, data_imprint) + return update_container(timeline_item, data_imprint) @classmethod def set_item_color(cls, timeline_item, version): diff --git a/openpype/hosts/resolve/plugins/publish/extract_workfile.py b/openpype/hosts/resolve/plugins/publish/extract_workfile.py index e3d60465a2..ea8f19cd8c 100644 --- a/openpype/hosts/resolve/plugins/publish/extract_workfile.py +++ b/openpype/hosts/resolve/plugins/publish/extract_workfile.py @@ -1,7 +1,7 @@ import os import pyblish.api import openpype.api -from openpype.hosts import resolve +from openpype.hosts.resolve.api.lib import get_project_manager class ExtractWorkfile(openpype.api.Extractor): @@ -29,7 +29,7 @@ class ExtractWorkfile(openpype.api.Extractor): os.path.join(staging_dir, drp_file_name)) # write out the drp workfile - resolve.get_project_manager().ExportProject( + get_project_manager().ExportProject( project.GetName(), drp_file_path) # create drp workfile representation diff --git a/openpype/hosts/resolve/plugins/publish/precollect_instances.py b/openpype/hosts/resolve/plugins/publish/precollect_instances.py index ee51998c0d..8ec169ad65 100644 --- a/openpype/hosts/resolve/plugins/publish/precollect_instances.py +++ b/openpype/hosts/resolve/plugins/publish/precollect_instances.py @@ -1,9 +1,15 @@ -import pyblish -from openpype.hosts import resolve - -# # developer reload modules from pprint import pformat +import pyblish + +from openpype.hosts.resolve.api.lib import ( + get_current_timeline_items, + get_timeline_item_pype_tag, + publish_clip_color, + get_publish_attribute, + get_otio_clip_instance_data, +) + class PrecollectInstances(pyblish.api.ContextPlugin): """Collect all Track items selection.""" @@ -14,8 +20,8 @@ class PrecollectInstances(pyblish.api.ContextPlugin): def process(self, context): otio_timeline = context.data["otioTimeline"] - selected_timeline_items = resolve.get_current_timeline_items( - filter=True, selecting_color=resolve.publish_clip_color) + selected_timeline_items = get_current_timeline_items( + filter=True, selecting_color=publish_clip_color) self.log.info( "Processing enabled track items: {}".format( @@ -27,7 +33,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin): timeline_item = timeline_item_data["clip"]["item"] # get pype tag data - tag_data = resolve.get_timeline_item_pype_tag(timeline_item) + tag_data = get_timeline_item_pype_tag(timeline_item) self.log.debug(f"__ tag_data: {pformat(tag_data)}") if not tag_data: @@ -67,7 +73,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin): "asset": asset, "item": timeline_item, "families": families, - "publish": resolve.get_publish_attribute(timeline_item), + "publish": get_publish_attribute(timeline_item), "fps": context.data["fps"], "handleStart": handle_start, "handleEnd": handle_end, @@ -75,7 +81,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin): }) # otio clip data - otio_data = resolve.get_otio_clip_instance_data( + otio_data = get_otio_clip_instance_data( otio_timeline, timeline_item_data) or {} data.update(otio_data) @@ -134,7 +140,7 @@ class PrecollectInstances(pyblish.api.ContextPlugin): "asset": asset, "family": family, "families": [], - "publish": resolve.get_publish_attribute(timeline_item) + "publish": get_publish_attribute(timeline_item) }) context.create_instance(**data) diff --git a/openpype/hosts/resolve/utility_scripts/OpenPype_sync_util_scripts.py b/openpype/hosts/resolve/utility_scripts/OpenPype_sync_util_scripts.py index 3a16b9c966..8f3917bece 100644 --- a/openpype/hosts/resolve/utility_scripts/OpenPype_sync_util_scripts.py +++ b/openpype/hosts/resolve/utility_scripts/OpenPype_sync_util_scripts.py @@ -6,10 +6,11 @@ from openpype.pipeline import install_host def main(env): - import openpype.hosts.resolve as bmdvr + from openpype.hosts.resolve.utils import setup + import openpype.hosts.resolve.api as bmdvr # Registers openpype's Global pyblish plugins install_host(bmdvr) - bmdvr.setup(env) + setup(env) if __name__ == "__main__": diff --git a/openpype/hosts/resolve/utility_scripts/__OpenPype__Menu__.py b/openpype/hosts/resolve/utility_scripts/__OpenPype__Menu__.py index 89ade9238b..1087a7b7a0 100644 --- a/openpype/hosts/resolve/utility_scripts/__OpenPype__Menu__.py +++ b/openpype/hosts/resolve/utility_scripts/__OpenPype__Menu__.py @@ -2,13 +2,13 @@ import os import sys from openpype.pipeline import install_host -from openpype.api import Logger +from openpype.lib import Logger -log = Logger().get_logger(__name__) +log = Logger.get_logger(__name__) def main(env): - import openpype.hosts.resolve as bmdvr + import openpype.hosts.resolve.api as bmdvr # activate resolve from openpype install_host(bmdvr) diff --git a/openpype/hosts/resolve/utility_scripts/tests/test_otio_as_edl.py b/openpype/hosts/resolve/utility_scripts/tests/test_otio_as_edl.py index 8433bd9172..92f2e43a72 100644 --- a/openpype/hosts/resolve/utility_scripts/tests/test_otio_as_edl.py +++ b/openpype/hosts/resolve/utility_scripts/tests/test_otio_as_edl.py @@ -6,8 +6,8 @@ import opentimelineio as otio from openpype.pipeline import install_host -from openpype.hosts.resolve import TestGUI -import openpype.hosts.resolve as bmdvr +import openpype.hosts.resolve.api as bmdvr +from openpype.hosts.resolve.api.testing_utils import TestGUI from openpype.hosts.resolve.otio import davinci_export as otio_export diff --git a/openpype/hosts/resolve/utility_scripts/tests/testing_create_timeline_item_from_path.py b/openpype/hosts/resolve/utility_scripts/tests/testing_create_timeline_item_from_path.py index 477955d527..91a361ec08 100644 --- a/openpype/hosts/resolve/utility_scripts/tests/testing_create_timeline_item_from_path.py +++ b/openpype/hosts/resolve/utility_scripts/tests/testing_create_timeline_item_from_path.py @@ -2,11 +2,16 @@ import os import sys -from openpype.pipeline import install_host -from openpype.hosts.resolve import TestGUI -import openpype.hosts.resolve as bmdvr import clique +from openpype.pipeline import install_host +from openpype.hosts.resolve.api.testing_utils import TestGUI +import openpype.hosts.resolve.api as bmdvr +from openpype.hosts.resolve.api.lib import ( + create_media_pool_item, + create_timeline_item, +) + class ThisTestGUI(TestGUI): extensions = [".exr", ".jpg", ".mov", ".png", ".mp4", ".ari", ".arx"] @@ -55,10 +60,10 @@ class ThisTestGUI(TestGUI): # skip if unwanted extension if ext not in self.extensions: return - media_pool_item = bmdvr.create_media_pool_item(fpath) + media_pool_item = create_media_pool_item(fpath) print(media_pool_item) - track_item = bmdvr.create_timeline_item(media_pool_item) + track_item = create_timeline_item(media_pool_item) print(track_item) diff --git a/openpype/hosts/resolve/utility_scripts/tests/testing_load_media_pool_item.py b/openpype/hosts/resolve/utility_scripts/tests/testing_load_media_pool_item.py index 872d620162..2e83188bde 100644 --- a/openpype/hosts/resolve/utility_scripts/tests/testing_load_media_pool_item.py +++ b/openpype/hosts/resolve/utility_scripts/tests/testing_load_media_pool_item.py @@ -1,13 +1,17 @@ #! python3 from openpype.pipeline import install_host -import openpype.hosts.resolve as bmdvr +from openpype.hosts.resolve import api as bmdvr +from openpype.hosts.resolve.api.lib import ( + create_media_pool_item, + create_timeline_item, +) def file_processing(fpath): - media_pool_item = bmdvr.create_media_pool_item(fpath) + media_pool_item = create_media_pool_item(fpath) print(media_pool_item) - track_item = bmdvr.create_timeline_item(media_pool_item) + track_item = create_timeline_item(media_pool_item) print(track_item) From a777238d83282e24c6238b92143b3a424ccde40d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 11 Aug 2022 19:11:49 +0200 Subject: [PATCH 130/282] fix handling of host name in error message --- openpype/host/host.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openpype/host/host.py b/openpype/host/host.py index 48907e7ec7..9cdbb819e1 100644 --- a/openpype/host/host.py +++ b/openpype/host/host.py @@ -19,8 +19,15 @@ class MissingMethodsError(ValueError): joined_missing = ", ".join( ['"{}"'.format(item) for item in missing_methods] ) + if isinstance(host, HostBase): + host_name = host.name + else: + try: + host_name = host.__file__.replace("\\", "/").split("/")[-3] + except Exception: + host_name = str(host) message = ( - "Host \"{}\" miss methods {}".format(host.name, joined_missing) + "Host \"{}\" miss methods {}".format(host_name, joined_missing) ) super(MissingMethodsError, self).__init__(message) From 312b6d3243ce66bc2e2749c964fd1b178369f9ec Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 12 Aug 2022 13:00:41 +0200 Subject: [PATCH 131/282] :bug: fix finding of last version --- igniter/bootstrap_repos.py | 73 ++++++++++++++++++-------------------- start.py | 3 ++ 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 750b2f1bf7..73ef8283a7 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -514,6 +514,9 @@ class OpenPypeVersion(semver.VersionInfo): ValueError: if invalid path is specified. """ + installed_version = OpenPypeVersion.get_installed_version() + if not compatible_with: + compatible_with = installed_version _openpype_versions = [] if not openpype_dir.exists() and not openpype_dir.is_dir(): return _openpype_versions @@ -540,8 +543,7 @@ class OpenPypeVersion(semver.VersionInfo): )[0]: continue - if compatible_with and not detected_version.is_compatible( - compatible_with): + if not detected_version.is_compatible(compatible_with): continue detected_version.path = item @@ -610,6 +612,8 @@ class OpenPypeVersion(semver.VersionInfo): remote = True installed_version = OpenPypeVersion.get_installed_version() + if not compatible_with: + compatible_with = installed_version local_versions = [] remote_versions = [] if local: @@ -630,8 +634,7 @@ class OpenPypeVersion(semver.VersionInfo): all_versions.sort() latest_version: OpenPypeVersion latest_version = all_versions[-1] - if compatible_with and not latest_version.is_compatible( - compatible_with): + if not latest_version.is_compatible(compatible_with): return None return latest_version @@ -1153,10 +1156,12 @@ class BootstrapRepos: versions compatible with specified one. """ + installed_version = OpenPypeVersion.get_installed_version() + if not compatible_with: + compatible_with = installed_version if isinstance(version, str): version = OpenPypeVersion(version=version) - installed_version = OpenPypeVersion.get_installed_version() if installed_version == version: return installed_version @@ -1250,51 +1255,41 @@ class BootstrapRepos: ok install it as normal version. """ + installed_version = OpenPypeVersion.get_installed_version() + if not compatible_with: + compatible_with = installed_version if openpype_path and not isinstance(openpype_path, Path): raise NotImplementedError( ("Finding OpenPype in non-filesystem locations is" " not implemented yet.")) - version_dir = "" - if compatible_with: - version_dir = f"{compatible_with.major}.{compatible_with.minor}" + version_dir = f"{compatible_with.major}.{compatible_with.minor}" # if checks bellow for OPENPYPE_PATH and registry fails, use data_dir # DEPRECATED: lookup in root of this folder is deprecated in favour # of major.minor sub-folders. - dirs_to_search = [ - self.data_dir - ] - if compatible_with: - dirs_to_search.append(self.data_dir / version_dir) + dirs_to_search = [self.data_dir, self.data_dir / version_dir] if openpype_path: - dirs_to_search = [openpype_path] - - if compatible_with: - dirs_to_search.append(openpype_path / version_dir) - else: + dirs_to_search = [openpype_path, openpype_path / version_dir] + elif os.getenv("OPENPYPE_PATH") \ + and Path(os.getenv("OPENPYPE_PATH")).exists(): # first try OPENPYPE_PATH and if that is not available, # try registry. - if os.getenv("OPENPYPE_PATH") \ - and Path(os.getenv("OPENPYPE_PATH")).exists(): - dirs_to_search = [Path(os.getenv("OPENPYPE_PATH"))] + dirs_to_search = [Path(os.getenv("OPENPYPE_PATH")), + Path(os.getenv("OPENPYPE_PATH")) / version_dir] + else: + try: + registry_dir = Path( + str(self.registry.get_item("openPypePath"))) + if registry_dir.exists(): + dirs_to_search = [ + registry_dir, registry_dir / version_dir + ] - if compatible_with: - dirs_to_search.append( - Path(os.getenv("OPENPYPE_PATH")) / version_dir) - else: - try: - registry_dir = Path( - str(self.registry.get_item("openPypePath"))) - if registry_dir.exists(): - dirs_to_search = [registry_dir] - if compatible_with: - dirs_to_search.append(registry_dir / version_dir) - - except ValueError: - # nothing found in registry, we'll use data dir - pass + except ValueError: + # nothing found in registry, we'll use data dir + pass openpype_versions = [] for dir_to_search in dirs_to_search: @@ -1685,6 +1680,9 @@ class BootstrapRepos: ValueError: if invalid path is specified. """ + installed_version = OpenPypeVersion.get_installed_version() + if not compatible_with: + compatible_with = installed_version if not openpype_dir.exists() and not openpype_dir.is_dir(): raise ValueError(f"specified directory {openpype_dir} is invalid") @@ -1711,8 +1709,7 @@ class BootstrapRepos: ): continue - if compatible_with and \ - not detected_version.is_compatible(compatible_with): + if not detected_version.is_compatible(compatible_with): continue detected_version.path = item diff --git a/start.py b/start.py index 5cdffafb6e..c7bced20bd 100644 --- a/start.py +++ b/start.py @@ -629,6 +629,9 @@ def _determine_mongodb() -> str: def _initialize_environment(openpype_version: OpenPypeVersion) -> None: version_path = openpype_version.path + if not version_path: + _print(f"!!! Version {openpype_version} doesn't have path set.") + raise ValueError("No path set in specified OpenPype version.") os.environ["OPENPYPE_VERSION"] = str(openpype_version) # set OPENPYPE_REPOS_ROOT to point to currently used OpenPype version. os.environ["OPENPYPE_REPOS_ROOT"] = os.path.normpath( From 089cd3f9fa3587178c9fe73371b4470588b8467b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 13:55:00 +0200 Subject: [PATCH 132/282] added missing docstring for 'context_filters' argument --- openpype/client/entities.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/client/entities.py b/openpype/client/entities.py index c798c0ad6d..67ddb09ddb 100644 --- a/openpype/client/entities.py +++ b/openpype/client/entities.py @@ -1220,6 +1220,8 @@ def get_archived_representations( as filter. Filter ignored if 'None' is passed. version_ids (Iterable[str]): Subset ids used as parent filter. Filter ignored if 'None' is passed. + context_filters (Dict[str, List[str, re.Pattern]]): Filter by + representation context fields. names_by_version_ids (dict[ObjectId, List[str]]): Complex filtering using version ids and list of names under the version. fields (Iterable[str]): Fields that should be returned. All fields are From aefb992ce55145f94790bbaa5cdbf17136684e1e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 13:55:35 +0200 Subject: [PATCH 133/282] removed unused 'is_context' property --- .../workfile/abstract_template_loader.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index 1c8ede25e6..e2f9fdba0f 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -465,23 +465,6 @@ class AbstractPlaceholder: return self.data["loader"] - @property - def is_context(self): - """Check if is placeholder context type. - - context_asset: For loading current asset - linked_asset: For loading linked assets - - Question: - There seems to be more build options and this property is not used, - should be removed? - - Returns: - bool: true if placeholder is a context placeholder - """ - - return self.builder_type == "context_asset" - @property def is_valid(self): """Test validity of placeholder. From 32c2440e4a6d5d5ec3d54c2d1a44ffc5f0f81ae5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 13:55:55 +0200 Subject: [PATCH 134/282] fix docstring header --- openpype/pipeline/workfile/abstract_template_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/workfile/abstract_template_loader.py b/openpype/pipeline/workfile/abstract_template_loader.py index e2f9fdba0f..05a98a1ddc 100644 --- a/openpype/pipeline/workfile/abstract_template_loader.py +++ b/openpype/pipeline/workfile/abstract_template_loader.py @@ -456,7 +456,7 @@ class AbstractPlaceholder: @property def loader_name(self): - """Return placeholder loader type. + """Return placeholder loader name. Returns: str: Loader name that will be used to load placeholder From 0c72b8e278d3e0ac2af5b69ff09b115908a4b632 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 12 Aug 2022 15:31:56 +0200 Subject: [PATCH 135/282] :recycle: refactor compatibility check --- igniter/bootstrap_repos.py | 143 +++++++++++++++++++------------------ igniter/install_thread.py | 19 ++++- openpype/version.py | 2 +- start.py | 24 +++---- 4 files changed, 104 insertions(+), 84 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 73ef8283a7..3a2dbe81c4 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -411,16 +411,7 @@ class OpenPypeVersion(semver.VersionInfo): # DEPRECATED: backwards compatible way to look for versions in root dir_to_search = Path(user_data_dir("openpype", "pypeclub")) - versions = OpenPypeVersion.get_versions_from_directory( - dir_to_search, compatible_with=compatible_with - ) - if compatible_with: - dir_to_search = Path( - user_data_dir("openpype", "pypeclub")) / f"{compatible_with.major}.{compatible_with.minor}" # noqa - versions += OpenPypeVersion.get_versions_from_directory( - dir_to_search, compatible_with=compatible_with - ) - + versions = OpenPypeVersion.get_versions_from_directory(dir_to_search) filtered_versions = [] for version in versions: @@ -498,14 +489,11 @@ class OpenPypeVersion(semver.VersionInfo): @staticmethod def get_versions_from_directory( - openpype_dir: Path, - compatible_with: OpenPypeVersion = None) -> List: + openpype_dir: Path) -> List: """Get all detected OpenPype versions in directory. Args: openpype_dir (Path): Directory to scan. - compatible_with (OpenPypeVersion): Return only versions compatible - with build version specified as OpenPypeVersion. Returns: list of OpenPypeVersion @@ -515,17 +503,27 @@ class OpenPypeVersion(semver.VersionInfo): """ installed_version = OpenPypeVersion.get_installed_version() - if not compatible_with: - compatible_with = installed_version - _openpype_versions = [] + openpype_versions = [] if not openpype_dir.exists() and not openpype_dir.is_dir(): - return _openpype_versions + return openpype_versions # iterate over directory in first level and find all that might # contain OpenPype. for item in openpype_dir.iterdir(): - - # if file, strip extension, in case of dir not. + # if the item is directory with major.minor version, dive deeper + try: + ver_dir = item.name.split(".")[ + 0] == installed_version.major and \ + item.name.split(".")[ + 1] == installed_version.minor # noqa: E051 + if item.is_dir() and ver_dir: + _versions = OpenPypeVersion.get_versions_from_directory( + item) + if _versions: + openpype_versions.append(_versions) + except IndexError: + pass + # if file exists, strip extension, in case of dir don't. name = item.name if item.is_dir() else item.stem result = OpenPypeVersion.version_in_str(name) @@ -543,13 +541,10 @@ class OpenPypeVersion(semver.VersionInfo): )[0]: continue - if not detected_version.is_compatible(compatible_with): - continue - detected_version.path = item - _openpype_versions.append(detected_version) + openpype_versions.append(detected_version) - return sorted(_openpype_versions) + return sorted(openpype_versions) @staticmethod def get_installed_version_str() -> str: @@ -577,15 +572,14 @@ class OpenPypeVersion(semver.VersionInfo): def get_latest_version( staging: bool = False, local: bool = None, - remote: bool = None, - compatible_with: OpenPypeVersion = None + remote: bool = None ) -> Union[OpenPypeVersion, None]: - """Get latest available version. + """Get the latest available version. The version does not contain information about path and source. - This is utility version to get latest version from all found. Build - version is not listed if staging is enabled. + This is utility version to get the latest version from all found. + Build version is not listed if staging is enabled. Arguments 'local' and 'remote' define if local and remote repository versions are used. All versions are used if both are not set (or set @@ -597,8 +591,9 @@ class OpenPypeVersion(semver.VersionInfo): staging (bool, optional): List staging versions if True. local (bool, optional): List local versions if True. remote (bool, optional): List remote versions if True. - compatible_with (OpenPypeVersion, optional) Return only version - compatible with compatible_with. + + Returns: + Latest OpenPypeVersion or None """ if local is None and remote is None: @@ -612,8 +607,6 @@ class OpenPypeVersion(semver.VersionInfo): remote = True installed_version = OpenPypeVersion.get_installed_version() - if not compatible_with: - compatible_with = installed_version local_versions = [] remote_versions = [] if local: @@ -633,10 +626,7 @@ class OpenPypeVersion(semver.VersionInfo): all_versions.sort() latest_version: OpenPypeVersion - latest_version = all_versions[-1] - if not latest_version.is_compatible(compatible_with): - return None - return latest_version + return all_versions[-1] @classmethod def get_expected_studio_version(cls, staging=False, global_settings=None): @@ -1191,13 +1181,27 @@ class BootstrapRepos: @staticmethod def find_latest_openpype_version( - staging, compatible_with: OpenPypeVersion = None): + staging: bool, + compatible_with: OpenPypeVersion = None + ) -> Union[OpenPypeVersion, None]: + """Find the latest available OpenPype version in all location. + + Args: + staging (bool): True to look for staging versions. + compatible_with (OpenPypeVersion, optional): If set, it will + try to find the latest version compatible with the + one specified. + + Returns: + Latest OpenPype version on None if nothing was found. + + """ installed_version = OpenPypeVersion.get_installed_version() local_versions = OpenPypeVersion.get_local_versions( - staging=staging, compatible_with=compatible_with + staging=staging ) remote_versions = OpenPypeVersion.get_remote_versions( - staging=staging, compatible_with=compatible_with + staging=staging ) all_versions = local_versions + remote_versions if not staging: @@ -1206,6 +1210,12 @@ class BootstrapRepos: if not all_versions: return None + if compatible_with: + all_versions = [ + version for version in all_versions + if version.is_compatible(installed_version) + ] + all_versions.sort() latest_version = all_versions[-1] if latest_version == installed_version: @@ -1222,8 +1232,7 @@ class BootstrapRepos: self, openpype_path: Union[Path, str] = None, staging: bool = False, - include_zips: bool = False, - compatible_with: OpenPypeVersion = None + include_zips: bool = False ) -> Union[List[OpenPypeVersion], None]: """Get ordered dict of detected OpenPype version. @@ -1256,36 +1265,29 @@ class BootstrapRepos: """ installed_version = OpenPypeVersion.get_installed_version() - if not compatible_with: - compatible_with = installed_version if openpype_path and not isinstance(openpype_path, Path): raise NotImplementedError( ("Finding OpenPype in non-filesystem locations is" " not implemented yet.")) - version_dir = f"{compatible_with.major}.{compatible_with.minor}" - # if checks bellow for OPENPYPE_PATH and registry fails, use data_dir # DEPRECATED: lookup in root of this folder is deprecated in favour # of major.minor sub-folders. - dirs_to_search = [self.data_dir, self.data_dir / version_dir] + dirs_to_search = [self.data_dir] if openpype_path: - dirs_to_search = [openpype_path, openpype_path / version_dir] + dirs_to_search = [openpype_path] elif os.getenv("OPENPYPE_PATH") \ and Path(os.getenv("OPENPYPE_PATH")).exists(): # first try OPENPYPE_PATH and if that is not available, # try registry. - dirs_to_search = [Path(os.getenv("OPENPYPE_PATH")), - Path(os.getenv("OPENPYPE_PATH")) / version_dir] + dirs_to_search = [Path(os.getenv("OPENPYPE_PATH"))] else: try: registry_dir = Path( str(self.registry.get_item("openPypePath"))) if registry_dir.exists(): - dirs_to_search = [ - registry_dir, registry_dir / version_dir - ] + dirs_to_search = [registry_dir] except ValueError: # nothing found in registry, we'll use data dir @@ -1295,7 +1297,7 @@ class BootstrapRepos: for dir_to_search in dirs_to_search: try: openpype_versions += self.get_openpype_versions( - dir_to_search, staging, compatible_with=compatible_with) + dir_to_search, staging) except ValueError: # location is invalid, skip it pass @@ -1663,15 +1665,12 @@ class BootstrapRepos: def get_openpype_versions( self, openpype_dir: Path, - staging: bool = False, - compatible_with: OpenPypeVersion = None) -> list: + staging: bool = False) -> list: """Get all detected OpenPype versions in directory. Args: openpype_dir (Path): Directory to scan. staging (bool, optional): Find staging versions if True. - compatible_with (OpenPypeVersion, optional): Get only versions - compatible with the one specified. Returns: list of OpenPypeVersion @@ -1681,17 +1680,24 @@ class BootstrapRepos: """ installed_version = OpenPypeVersion.get_installed_version() - if not compatible_with: - compatible_with = installed_version if not openpype_dir.exists() and not openpype_dir.is_dir(): raise ValueError(f"specified directory {openpype_dir} is invalid") - _openpype_versions = [] + openpype_versions = [] # iterate over directory in first level and find all that might # contain OpenPype. for item in openpype_dir.iterdir(): - - # if file, strip extension, in case of dir not. + # if the item is directory with major.minor version, dive deeper + try: + ver_dir = item.name.split(".")[0] == installed_version.major and item.name.split(".")[1] == installed_version.minor # noqa: E051 + if item.is_dir() and ver_dir: + _versions = self.get_openpype_versions( + item, staging=staging) + if _versions: + openpype_versions.append(_versions) + except IndexError: + pass + # if it is file, strip extension, in case of dir don't. name = item.name if item.is_dir() else item.stem result = OpenPypeVersion.version_in_str(name) @@ -1709,17 +1715,14 @@ class BootstrapRepos: ): continue - if not detected_version.is_compatible(compatible_with): - continue - detected_version.path = item if staging and detected_version.is_staging(): - _openpype_versions.append(detected_version) + openpype_versions.append(detected_version) if not staging and not detected_version.is_staging(): - _openpype_versions.append(detected_version) + openpype_versions.append(detected_version) - return sorted(_openpype_versions) + return sorted(openpype_versions) class OpenPypeVersionExists(Exception): diff --git a/igniter/install_thread.py b/igniter/install_thread.py index 8e31f8cb8f..0cccf664e7 100644 --- a/igniter/install_thread.py +++ b/igniter/install_thread.py @@ -62,7 +62,7 @@ class InstallThread(QThread): progress_callback=self.set_progress, message=self.message) local_version = OpenPypeVersion.get_installed_version_str() - # if user did entered nothing, we install OpenPype from local version. + # if user did enter nothing, we install OpenPype from local version. # zip content of `repos`, copy it to user data dir and append # version to it. if not self._path: @@ -93,6 +93,23 @@ class InstallThread(QThread): detected = bs.find_openpype(include_zips=True) if detected: + if not OpenPypeVersion.get_installed_version().is_compatible( + detected[-1]): + self.message.emit(( + f"Latest detected version {detected[-1]} " + "is not compatible with the currently running " + f"{local_version}" + ), True) + self.message.emit(( + "Filtering detected versions to compatible ones..." + ), False) + + detected = [ + version for version in detected + if version.is_compatible( + OpenPypeVersion.get_installed_version()) + ] + if OpenPypeVersion( version=local_version, path=Path()) < detected[-1]: self.message.emit(( diff --git a/openpype/version.py b/openpype/version.py index c41e69d00d..d85f9f60ed 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -"""Package declaring Pype version.""" +"""Package declaring OpenPype version.""" __version__ = "3.13.1-nightly.1" diff --git a/start.py b/start.py index c7bced20bd..52e98bb6e1 100644 --- a/start.py +++ b/start.py @@ -699,8 +699,7 @@ def _find_frozen_openpype(use_version: str = None, # Version says to use latest version _print(">>> Finding latest version defined by use version") openpype_version = bootstrap.find_latest_openpype_version( - use_staging, compatible_with=installed_version - ) + use_staging) else: _print(f">>> Finding specified version \"{use_version}\"") openpype_version = bootstrap.find_openpype_version( @@ -712,18 +711,11 @@ def _find_frozen_openpype(use_version: str = None, f"Requested version \"{use_version}\" was not found." ) - if not openpype_version.is_compatible(installed_version): - raise OpenPypeVersionIncompatible(( - f"Requested version \"{use_version}\" is not compatible " - f"with installed version \"{installed_version}\"" - )) - elif studio_version is not None: # Studio has defined a version to use _print(f">>> Finding studio version \"{studio_version}\"") openpype_version = bootstrap.find_openpype_version( - studio_version, use_staging, compatible_with=installed_version - ) + studio_version, use_staging) if openpype_version is None: raise OpenPypeVersionNotFound(( "Requested OpenPype version " @@ -737,8 +729,8 @@ def _find_frozen_openpype(use_version: str = None, ">>> Finding latest version compatible " f"with [ {installed_version} ]")) openpype_version = bootstrap.find_latest_openpype_version( - use_staging, compatible_with=installed_version - ) + use_staging, compatible_with=installed_version) + if openpype_version is None: if use_staging: reason = "Didn't find any staging versions." @@ -756,6 +748,14 @@ def _find_frozen_openpype(use_version: str = None, _initialize_environment(openpype_version) return version_path + if not installed_version.is_compatible(openpype_version): + raise OpenPypeVersionIncompatible( + ( + f"Latest version found {openpype_version} is not " + f"compatible with currently running {installed_version}" + ) + ) + # test if latest detected is installed (in user data dir) is_inside = False try: From c1d3d704106638e1d28ef338a958496790578c40 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 12 Aug 2022 15:40:17 +0200 Subject: [PATCH 136/282] :rotating_light: fix hound :dog: --- igniter/bootstrap_repos.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 3a2dbe81c4..6a04198fc9 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -1264,7 +1264,6 @@ class BootstrapRepos: ok install it as normal version. """ - installed_version = OpenPypeVersion.get_installed_version() if openpype_path and not isinstance(openpype_path, Path): raise NotImplementedError( ("Finding OpenPype in non-filesystem locations is" @@ -1689,7 +1688,7 @@ class BootstrapRepos: for item in openpype_dir.iterdir(): # if the item is directory with major.minor version, dive deeper try: - ver_dir = item.name.split(".")[0] == installed_version.major and item.name.split(".")[1] == installed_version.minor # noqa: E051 + ver_dir = item.name.split(".")[0] == installed_version.major and item.name.split(".")[1] == installed_version.minor # noqa: E501 if item.is_dir() and ver_dir: _versions = self.get_openpype_versions( item, staging=staging) From 7176723aa5f8710ca422d9fd40577a6b85bc7b81 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 12 Aug 2022 17:26:46 +0200 Subject: [PATCH 137/282] :bug: fix arguments and recursive folders --- igniter/bootstrap_repos.py | 44 +++++++++++++------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 6a04198fc9..01d7c4bb7e 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -425,7 +425,7 @@ class OpenPypeVersion(semver.VersionInfo): @classmethod def get_remote_versions( cls, production: bool = None, - staging: bool = None, compatible_with: OpenPypeVersion = None + staging: bool = None ) -> List: """Get all versions available in OpenPype Path. @@ -470,13 +470,7 @@ class OpenPypeVersion(semver.VersionInfo): if not dir_to_search: return [] - # DEPRECATED: look for version in root directory - versions = cls.get_versions_from_directory( - dir_to_search, compatible_with=compatible_with) - if compatible_with: - dir_to_search = dir_to_search / f"{compatible_with.major}.{compatible_with.minor}" # noqa - versions += cls.get_versions_from_directory( - dir_to_search, compatible_with=compatible_with) + versions = cls.get_versions_from_directory(dir_to_search) filtered_versions = [] for version in versions: @@ -511,18 +505,13 @@ class OpenPypeVersion(semver.VersionInfo): # contain OpenPype. for item in openpype_dir.iterdir(): # if the item is directory with major.minor version, dive deeper - try: - ver_dir = item.name.split(".")[ - 0] == installed_version.major and \ - item.name.split(".")[ - 1] == installed_version.minor # noqa: E051 - if item.is_dir() and ver_dir: - _versions = OpenPypeVersion.get_versions_from_directory( - item) - if _versions: - openpype_versions.append(_versions) - except IndexError: - pass + + if item.is_dir() and re.match(r"^\d+\.\d+$", item.name): + _versions = OpenPypeVersion.get_versions_from_directory( + item) + if _versions: + openpype_versions += _versions + # if file exists, strip extension, in case of dir don't. name = item.name if item.is_dir() else item.stem result = OpenPypeVersion.version_in_str(name) @@ -1687,15 +1676,12 @@ class BootstrapRepos: # contain OpenPype. for item in openpype_dir.iterdir(): # if the item is directory with major.minor version, dive deeper - try: - ver_dir = item.name.split(".")[0] == installed_version.major and item.name.split(".")[1] == installed_version.minor # noqa: E501 - if item.is_dir() and ver_dir: - _versions = self.get_openpype_versions( - item, staging=staging) - if _versions: - openpype_versions.append(_versions) - except IndexError: - pass + if item.is_dir() and re.match(r"^\d+\.\d+$", item.name): + _versions = self.get_openpype_versions( + item, staging=staging) + if _versions: + openpype_versions += _versions + # if it is file, strip extension, in case of dir don't. name = item.name if item.is_dir() else item.stem result = OpenPypeVersion.version_in_str(name) From 7676827644c385991e35687b303032dd491e9361 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 17:27:47 +0200 Subject: [PATCH 138/282] initial commit of settings dev --- website/docs/dev_settings.md | 890 +++++++++++++++++++++++++++++++++++ website/sidebars.js | 1 + 2 files changed, 891 insertions(+) create mode 100644 website/docs/dev_settings.md diff --git a/website/docs/dev_settings.md b/website/docs/dev_settings.md new file mode 100644 index 0000000000..483bd18535 --- /dev/null +++ b/website/docs/dev_settings.md @@ -0,0 +1,890 @@ +--- +id: dev_settings +title: Settings +sidebar_label: Settings +--- + +Settings gives ability to change how OpenPype behaves in certain situations. Settings are split into 3 categories **system settings**, **project anatomy** and **project settings**. Project anatomy and project settings are in grouped into single category but there is a technical difference (explained later). Only difference in system and project settings is that system settings can't be technically handled on a project level or their values must be available no matter in which project are values received. Settings have headless entities or settings UI. + +There is one more category **local settings** but they don't have ability to be changed or defined easily. Local settings can change how settings work per machine, can affect both system and project settings but they're hardcoded for predefined values at this moment. + +## Settings schemas +System and project settings are defined by settings schemas. Schema define structure of output value, what value types output will contain, how settings are stored and how it's UI input will look. + +## Settings values +Output of settings is a json serializable value. There are 3 possible types of value **default values**, **studio overrides** and **project overrides**. Default values must be always available for all settings schemas, their values are stored to code. Default values is what everyone who just installed OpenPype will use as default values. It is good practice to set example values but they should be relevant. + +Setting overrides is what makes settings powerful tool. Overrides contain only a part of settings with additional metadata which describe which parts of settings values that should be replaced from overrides values. Using overrides gives ability to save only specific values and use default values for rest. It is super useful in project settings which have up to 2 levels of overrides. In project settings are used **default values** as base on which are applied **studio overrides** and then **project overrides**. In practice it is possible to save only studio overrides which affect all projects. Changes in studio overrides are then propagated to all projects without project overrides. But values can be locked on project level so studio overrides are not used. + +## Settings storage +As was mentined default values are stored into repository files. Overrides are stored to Mongo database. The value in mongo contain only overrides with metadata so their content on it's own is useless and must be used with combination of default values. System settings and project settings are stored into special collection. Single document represents one set of overrides with OpenPype version for which is stored. Settings are versioned and are loaded in specific order - current OpenPype version overrides or first lower available. If there are any overrides with same or lower version then first higher version is used. If there are any overrides then no overrides are applied. + +Project anatomy is stored into project document thus is not versioned and it's values are always overriden. Any changes in anatomy schema may have drastic effect on production and OpenPype updates. + +## Settings schema items +As was mentioned schema items define output type of values, how they are stored and how they look in UI. +- schemas are (by default) defined by a json files +- OpenPype core system settings schemas are stored in `~/openpype/settings/entities/schemas/system_schema/` and project settings in `~/openpype/settings/entities/schemas/projects_schema/` + - both contain `schema_main.json` which are entry points +- OpenPype modules/addons can define their settings schemas using `BaseModuleSettingsDef` in that case some functionality may be slightly modified +- single schema item is represented by dictionary (object) in json which has `"type"` key. + - **type** is only common key which is required for all schema items +- each item may have "input modifiers" (other keys in dictionary) and they may be required or optional based on the type +- there are special keys across all items + - `"is_file"` - this key is used when defaults values are stored which define that this key is a filename where it's values are stored + - key is validated must be once in hierarchy else it won't be possible to store default values + - make sense to fill it only if it's value if `true` + - `"is_group"` - define that all values under a key in settings hierarchy will be overridden if any value is modified + - this key is not allowed for all inputs as they may not have technical ability to handle it + - key is validated can be only once in hierarchy and is automatically filled on last possible item if is not defined in schemas + - make sense to fill it only if it's value if `true` +- all entities can have set `"tooltip"` key with description which will be shown in UI on hover + +### Inner schema +Settings schemas are big json files which would became unmanageable if would be in single file. To be able to split them into multiple files to help organize them special types `schema` and `template` were added. Both types are relating to a different file by filename. If json file contains dictionary it is considered as `schema` if contains list it is considered as `template`. + +#### schema +Schema item is replaced by content of entered schema name. It is recommended that schema file is used only once in settings hierarchy. Templates are meant for reusing. +- schema must have `"name"` key which is name of schema that should be used + +```javascript +{ + "type": "schema", + "name": "my_schema_name" +} +``` + +#### template +Templates are almost the same as schema items but can contain one or more items which can be formatted with additional data or some keys can be skipped if needed. Templates are meant for reusing the same schemas with ability to modify content. + +- legacy name is `schema_template` (still usable) +- template must have `"name"` key which is name of template file that should be used +- to fill formatting keys use `"template_data"` +- all items in template, except `__default_values__`, will replace `template` item in original schema +- template may contain other templates + +```javascript +// Example template json file content +[ + { + // Define default values for formatting values + // - gives ability to set the value but have default value + "__default_values__": { + "multipath_executables": true + } + }, { + "type": "raw-json", + "label": "{host_label} Environments", + "key": "{host_name}_environments" + }, { + "type": "path", + "key": "{host_name}_executables", + "label": "{host_label} - Full paths to executables", + "multiplatform": "{multipath_executables}", + "multipath": true + } +] +``` +```javascript +// Example usage of the template in schema +{ + "type": "dict", + "key": "template_examples", + "label": "Schema template examples", + "children": [ + { + "type": "template", + "name": "example_template", + "template_data": [ + { + "host_label": "Maya 2019", + "host_name": "maya_2019", + "multipath_executables": false + }, + { + "host_label": "Maya 2020", + "host_name": "maya_2020" + }, + { + "host_label": "Maya 2021", + "host_name": "maya_2021" + } + ] + } + ] +} +``` +```javascript +// The same schema defined without templates +{ + "type": "dict", + "key": "template_examples", + "label": "Schema template examples", + "children": [ + { + "type": "raw-json", + "label": "Maya 2019 Environments", + "key": "maya_2019_environments" + }, { + "type": "path", + "key": "maya_2019_executables", + "label": "Maya 2019 - Full paths to executables", + "multiplatform": false, + "multipath": true + }, { + "type": "raw-json", + "label": "Maya 2020 Environments", + "key": "maya_2020_environments" + }, { + "type": "path", + "key": "maya_2020_executables", + "label": "Maya 2020 - Full paths to executables", + "multiplatform": true, + "multipath": true + }, { + "type": "raw-json", + "label": "Maya 2021 Environments", + "key": "maya_2021_environments" + }, { + "type": "path", + "key": "maya_2021_executables", + "label": "Maya 2021 - Full paths to executables", + "multiplatform": true, + "multipath": true + } + ] +} +``` + +Template data can be used only to fill templates in values but not in keys. It is also possible to define default values for unfilled fields to do so one of items in list must be dictionary with key `"__default_values__"` and value as dictionary with default key: values (as in example above). +```javascript +{ + ... + // Allowed + "key": "{to_fill}" + ... + // Not allowed + "{to_fill}": "value" + ... +} +``` + +Because formatting value can be only string it is possible to use formatting values which are replaced with different type. +```javascript +// Template data +{ + "template_data": { + "executable_multiplatform": { + "type": "schema", + "name": "my_multiplatform_schema" + } + } +} +// Template content +{ + ... + // Allowed - value is replaced with dictionary + "multiplatform": "{executable_multiplatform}" + ... + // Not allowed - there is no way how it could be replaced + "multiplatform": "{executable_multiplatform}_enhanced_string" + ... +} +``` + +#### dynamic_schema +Dynamic schema item marks a place in settings schema where schemas defined by `BaseModuleSettingsDef` can be placed. +- example: +``` +{ + "type": "dynamic_schema", + "name": "project_settings/global" +} +``` +- `BaseModuleSettingsDef` with implemented `get_settings_schemas` can return a dictionary where key define a dynamic schema name and value schemas that will be put there +- dynamic schemas work almost the same way as templates + - one item can be replaced by multiple items (or by 0 items) +- goal is to dynamically load settings of OpenPype modules without having their schemas or default values in core repository + - values of these schemas are saved using the `BaseModuleSettingsDef` methods +- we recommend to use `JsonFilesSettingsDef` which has full implementation of storing default values to json files + - requires only to implement method `get_settings_root_path` which should return path to root directory where settings schema can be found and default values will be saved + +### Basic Dictionary inputs +These inputs wraps another inputs into {key: value} relation + +#### dict +- this is dictionary type wrapping more inputs with keys defined in schema +- may be used as dynamic children (e.g. in `list` or `dict-modifiable`) + - in that case the only key modifier is `children` which is list of it's keys + - USAGE: e.g. List of dictionaries where each dictionary have same structure. +- if is not used as dynamic children then must have defined `"key"` under which are it's values stored +- may be with or without `"label"` (only for GUI) + - `"label"` must be set to be able mark item as group with `"is_group"` key set to True +- item with label can visually wrap it's children + - this option is enabled by default to turn off set `"use_label_wrap"` to `False` + - label wrap is by default collapsible + - that can be set with key `"collapsible"` to `True`/`False` + - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) + - it is possible to add lighter background with `"highlight_content"` (Default: `False`) + - lighter background has limits of maximum applies after 3-4 nested highlighted items there is not much difference in the color + - output is dictionary `{the "key": children values}` +``` +# Example +{ + "key": "applications", + "type": "dict", + "label": "Applications", + "collapsible": true, + "highlight_content": true, + "is_group": true, + "is_file": true, + "children": [ + ...ITEMS... + ] +} + +# Without label +{ + "type": "dict", + "key": "global", + "children": [ + ...ITEMS... + ] +} + +# When used as widget +{ + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": { + "type": "dict", + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + } + ... + ] + } +} +``` + +#### dict-roots +- entity can be used only in Project settings +- keys of dictionary are based on current project roots +- they are not updated "live" it is required to save root changes and then + modify values on this entity + # TODO do live updates +``` +{ + "type": "dict-roots", + "key": "roots", + "label": "Roots", + "object_type": { + "type": "path", + "multiplatform": true, + "multipath": false + } +} +``` + +#### dict-conditional +- is similar to `dict` but has always available one enum entity + - the enum entity has single selection and it's value define other children entities +- each value of enumerator have defined children that will be used + - there is no way how to have shared entities across multiple enum items +- value from enumerator is also stored next to other values + - to define the key under which will be enum value stored use `enum_key` + - `enum_key` must match key regex and any enum item can't have children with same key + - `enum_label` is label of the entity for UI purposes +- enum items are define with `enum_children` + - it's a list where each item represents single item for the enum + - all items in `enum_children` must have at least `key` key which represents value stored under `enum_key` + - enum items can define `label` for UI purposes + - most important part is that item can define `children` key where are definitions of it's children (`children` value works the same way as in `dict`) +- to set default value for `enum_key` set it with `enum_default` +- entity must have defined `"label"` if is not used as widget +- is set as group if any parent is not group (can't have children as group) +- may be with or without `"label"` (only for GUI) + - `"label"` must be set to be able mark item as group with `"is_group"` key set to True +- item with label can visually wrap it's children + - this option is enabled by default to turn off set `"use_label_wrap"` to `False` + - label wrap is by default collapsible + - that can be set with key `"collapsible"` to `True`/`False` + - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) + - it is possible to add lighter background with `"highlight_content"` (Default: `False`) + - lighter background has limits of maximum applies after 3-4 nested highlighted items there is not much difference in the color +- for UI porposes was added `enum_is_horizontal` which will make combobox appear next to children inputs instead of on top of them (Default: `False`) + - this has extended ability of `enum_on_right` which will move combobox to right side next to children widgets (Default: `False`) +- output is dictionary `{the "key": children values}` +- using this type as template item for list type can be used to create infinite hierarchies + +``` +# Example +{ + "type": "dict-conditional", + "key": "my_key", + "label": "My Key", + "enum_key": "type", + "enum_label": "label", + "enum_children": [ + # Each item must be a dictionary with 'key' + { + "key": "action", + "label": "Action", + "children": [ + { + "type": "text", + "key": "key", + "label": "Key" + }, + { + "type": "text", + "key": "label", + "label": "Label" + }, + { + "type": "text", + "key": "command", + "label": "Comand" + } + ] + }, + { + "key": "menu", + "label": "Menu", + "children": [ + { + "key": "children", + "label": "Children", + "type": "list", + "object_type": "text" + } + ] + }, + { + # Separator does not have children as "separator" value is enough + "key": "separator", + "label": "Separator" + } + ] +} +``` + +How output of the schema could look like on save: +``` +{ + "type": "separator" +} + +{ + "type": "action", + "key": "action_1", + "label": "Action 1", + "command": "run command -arg" +} + +{ + "type": "menu", + "children": [ + "child_1", + "child_2" + ] +} +``` + +### Inputs for setting any kind of value (`Pure` inputs) +- all inputs must have defined `"key"` if are not used as dynamic item + - they can also have defined `"label"` + +#### boolean +- simple checkbox, nothing more to set +``` +{ + "type": "boolean", + "key": "my_boolean_key", + "label": "Do you want to use Pype?" +} +``` + +#### number +- number input, can be used for both integer and float + - key `"decimal"` defines how many decimal places will be used, 0 is for integer input (Default: `0`) + - key `"minimum"` as minimum allowed number to enter (Default: `-99999`) + - key `"maxium"` as maximum allowed number to enter (Default: `99999`) +- key `"steps"` will change single step value of UI inputs (using arrows and wheel scroll) +- for UI it is possible to show slider to enable this option set `show_slider` to `true` +``` +{ + "type": "number", + "key": "fps", + "label": "Frame rate (FPS)" + "decimal": 2, + "minimum": 1, + "maximum": 300000 +} +``` + +``` +{ + "type": "number", + "key": "ratio", + "label": "Ratio" + "decimal": 3, + "minimum": 0, + "maximum": 1, + "show_slider": true +} +``` + +#### text +- simple text input + - key `"multiline"` allows to enter multiple lines of text (Default: `False`) + - key `"placeholder"` allows to show text inside input when is empty (Default: `None`) + +``` +{ + "type": "text", + "key": "deadline_pool", + "label": "Deadline pool" +} +``` + +#### path-input +- Do not use this input in schema please (use `path` instead) +- this input is implemented to add additional features to text input +- this is meant to be used in proxy input `path` + +#### raw-json +- a little bit enhanced text input for raw json +- can store dictionary (`{}`) or list (`[]`) but not both + - by default stores dictionary to change it to list set `is_list` to `True` +- has validations of json format +- output can be stored as string + - this is to allow any keys in dictionary + - set key `store_as_string` to `true` + - code using that setting must expected that value is string and use json module to convert it to python types + +``` +{ + "type": "raw-json", + "key": "profiles", + "label": "Extract Review profiles", + "is_list": true +} +``` + +#### enum +- enumeration of values that are predefined in schema +- multiselection can be allowed with setting key `"multiselection"` to `True` (Default: `False`) +- values are defined under value of key `"enum_items"` as list + - each item in list is simple dictionary where value is label and key is value which will be stored + - should be possible to enter single dictionary if order of items doesn't matter +- it is possible to set default selected value/s with `default` attribute + - it is recommended to use this option only in single selection mode + - at the end this option is used only when defying default settings value or in dynamic items + +``` +{ + "key": "tags", + "label": "Tags", + "type": "enum", + "multiselection": true, + "enum_items": [ + {"burnin": "Add burnins"}, + {"ftrackreview": "Add to Ftrack"}, + {"delete": "Delete output"}, + {"slate-frame": "Add slate frame"}, + {"no-handles": "Skip handle frames"} + ] +} +``` + +#### anatomy-templates-enum +- enumeration of all available anatomy template keys +- have only single selection mode +- it is possible to define default value `default` + - `"work"` is used if default value is not specified +- enum values are not updated on the fly it is required to save templates and + reset settings to recache values +``` +{ + "key": "host", + "label": "Host name", + "type": "anatomy-templates-enum", + "default": "publish" +} +``` + +#### hosts-enum +- enumeration of available hosts +- multiselection can be allowed with setting key `"multiselection"` to `True` (Default: `False`) +- it is possible to add empty value (represented with empty string) with setting `"use_empty_value"` to `True` (Default: `False`) +- it is possible to set `"custom_labels"` for host names where key `""` is empty value (Default: `{}`) +- to filter host names it is required to define `"hosts_filter"` which is list of host names that will be available + - do not pass empty string if `use_empty_value` is enabled + - ignoring host names would be more dangerous in some cases +``` +{ + "key": "host", + "label": "Host name", + "type": "hosts-enum", + "multiselection": false, + "use_empty_value": true, + "custom_labels": { + "": "N/A", + "nuke": "Nuke" + }, + "hosts_filter": [ + "nuke" + ] +} +``` + +#### apps-enum +- enumeration of available application and their variants from system settings + - applications without host name are excluded +- can be used only in project settings +- has only `multiselection` +- used only in project anatomy +``` +{ + "type": "apps-enum", + "key": "applications", + "label": "Applications" +} +``` + +#### tools-enum +- enumeration of available tools and their variants from system settings +- can be used only in project settings +- has only `multiselection` +- used only in project anatomy +``` +{ + "type": "tools-enum", + "key": "tools_env", + "label": "Tools" +} +``` + +#### task-types-enum +- enumeration of task types from current project +- enum values are not updated on the fly and modifications of task types on project require save and reset to be propagated to this enum +- has set `multiselection` to `True` but can be changed to `False` in schema + +#### deadline_url-enum +- deadline module specific enumerator using deadline system settings to fill it's values +- TODO: move this type to deadline module + +### Inputs for setting value using Pure inputs +- these inputs also have required `"key"` +- attribute `"label"` is required in few conditions + - when item is marked `as_group` or when `use_label_wrap` +- they use Pure inputs "as widgets" + +#### list +- output is list +- items can be added and removed +- items in list must be the same type +- to wrap item in collapsible widget with label on top set `use_label_wrap` to `True` + - when this is used `collapsible` and `collapsed` can be set (same as `dict` item does) +- type of items is defined with key `"object_type"` +- there are 2 possible ways how to set the type: + 1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below) + 2.) item type name as string without modifiers (e.g. `text`) + 3.) enhancement of 1.) there is also support of `template` type but be carefull about endless loop of templates + - goal of using `template` is to easily change same item definitions in multiple lists + +1.) with item modifiers +``` +{ + "type": "list", + "key": "exclude_ports", + "label": "Exclude ports", + "object_type": { + "type": "number", # number item type + "minimum": 1, # minimum modifier + "maximum": 65535 # maximum modifier + } +} +``` + +2.) without modifiers +``` +{ + "type": "list", + "key": "exclude_ports", + "label": "Exclude ports", + "object_type": "text" +} +``` + +3.) with template definition +``` +# Schema of list item where template is used +{ + "type": "list", + "key": "menu_items", + "label": "Menu Items", + "object_type": { + "type": "template", + "name": "template_object_example" + } +} + +# WARNING: +# In this example the template use itself inside which will work in `list` +# but may cause an issue in other entity types (e.g. `dict`). + +'template_object_example.json' : +[ + { + "type": "dict-conditional", + "use_label_wrap": true, + "collapsible": true, + "key": "menu_items", + "label": "Menu items", + "enum_key": "type", + "enum_label": "Type", + "enum_children": [ + { + "key": "action", + "label": "Action", + "children": [ + { + "type": "text", + "key": "key", + "label": "Key" + } + ] + }, { + "key": "menu", + "label": "Menu", + "children": [ + { + "key": "children", + "label": "Children", + "type": "list", + "object_type": { + "type": "template", + "name": "template_object_example" + } + } + ] + } + ] + } +] +``` + +#### dict-modifiable +- one of dictionary inputs, this is only used as value input +- items in this input can be removed and added same way as in `list` input +- value items in dictionary must be the same type +- type of items is defined with key `"object_type"` +- required keys may be defined under `"required_keys"` + - required keys must be defined as a list (e.g. `["key_1"]`) and are moved to the top + - these keys can't be removed or edited (it is possible to edit label if item is collapsible) +- there are 2 possible ways how to set the type: + 1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below) + 2.) item type name as string without modifiers (e.g. `text`) +- this input can be collapsible + - that can be set with key `"collapsible"` as `True`/`False` (Default: `True`) + - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) + +1.) with item modifiers +``` +{ + "type": "dict-modifiable", + "object_type": { + "type": "number", + "minimum": 0, + "maximum": 300 + }, + "is_group": true, + "key": "templates_mapping", + "label": "Muster - Templates mapping", + "is_file": true +} +``` + +2.) without modifiers +``` +{ + "type": "dict-modifiable", + "object_type": "text", + "is_group": true, + "key": "templates_mapping", + "label": "Muster - Templates mapping", + "is_file": true +} +``` + +#### path +- input for paths, use `path-input` internally +- has 2 input modifiers `"multiplatform"` and `"multipath"` + - `"multiplatform"` - adds `"windows"`, `"linux"` and `"darwin"` path inputs result is dictionary + - `"multipath"` - it is possible to enter multiple paths + - if both are enabled result is dictionary with lists + +``` +{ + "type": "path", + "key": "ffmpeg_path", + "label": "FFmpeg path", + "multiplatform": true, + "multipath": true +} +``` + +#### list-strict +- input for strict number of items in list +- each child item can be different type with different possible modifiers +- it is possible to display them in horizontal or vertical layout + - key `"horizontal"` as `True`/`False` (Default: `True`) +- each child may have defined `"label"` which is shown next to input + - label does not reflect modifications or overrides (TODO) +- children item are defined under key `"object_types"` which is list of dictionaries + - key `"children"` is not used because is used for hierarchy validations in schema +- USAGE: For colors, transformations, etc. Custom number and different modifiers + give ability to define if color is HUE or RGB, 0-255, 0-1, 0-100 etc. + +``` +{ + "type": "list-strict", + "key": "color", + "label": "Color", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Alpha", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] +} +``` + +#### color +- preimplemented entity to store and load color values +- entity store and expect list of 4 integers in range 0-255 + - integers represents rgba [Red, Green, Blue, Alpha] + +``` +{ + "type": "color", + "key": "bg_color", + "label": "Background Color" +} +``` + +### Noninteractive items +Items used only for UI purposes. + +#### label +- add label with note or explanations +- it is possible to use html tags inside the label +- set `work_wrap` to `true`/`false` if you want to enable word wrapping in UI (default: `false`) + +``` +{ + "type": "label", + "label": "RED LABEL: Normal label" +} +``` + +#### separator +- legacy name is `splitter` (still usable) +- visual separator of items (more divider than separator) + +``` +{ + "type": "separator" +} +``` + +### Anatomy +Anatomy represents data stored on project document. + +#### anatomy +- entity works similarly to `dict` +- anatomy has always all keys overridden with overrides + - overrides are not applied as all anatomy data must be available from project document + - all children must be groups + +### Proxy wrappers +- should wraps multiple inputs only visually +- these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled +- can't be used as widget (first item in e.g. `list`, `dict-modifiable`, etc.) + +#### form +- wraps inputs into form look layout +- should be used only for Pure inputs + +``` +{ + "type": "dict-form", + "children": [ + { + "type": "text", + "key": "deadline_department", + "label": "Deadline apartment" + }, { + "type": "number", + "key": "deadline_priority", + "label": "Deadline priority" + }, { + ... + } + ] +} +``` + + +#### collapsible-wrap +- wraps inputs into collapsible widget + - looks like `dict` but does not hold `"key"` +- should be used only for Pure inputs + +``` +{ + "type": "collapsible-wrap", + "label": "Collapsible example" + "children": [ + { + "type": "text", + "key": "_example_input_collapsible", + "label": "Example input in collapsible wrapper" + }, { + ... + } + ] +} diff --git a/website/sidebars.js b/website/sidebars.js index 9d60a5811c..b7b44bbada 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -152,6 +152,7 @@ module.exports = { "dev_build", "dev_testing", "dev_contribute", + "dev_settings", { type: "category", label: "Hosts integrations", From 60ea9728f63afa2c0ec2c32bd619fec8e64993ec Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 12 Aug 2022 17:43:02 +0200 Subject: [PATCH 139/282] :rotating_light: fix hound :dog: --- igniter/bootstrap_repos.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 01d7c4bb7e..3dab67ebf1 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -496,7 +496,6 @@ class OpenPypeVersion(semver.VersionInfo): ValueError: if invalid path is specified. """ - installed_version = OpenPypeVersion.get_installed_version() openpype_versions = [] if not openpype_dir.exists() and not openpype_dir.is_dir(): return openpype_versions @@ -1667,7 +1666,6 @@ class BootstrapRepos: ValueError: if invalid path is specified. """ - installed_version = OpenPypeVersion.get_installed_version() if not openpype_dir.exists() and not openpype_dir.is_dir(): raise ValueError(f"specified directory {openpype_dir} is invalid") From c3b69e86d4a64d63865dbdb55a06b3a1f7a67c38 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 17:52:33 +0200 Subject: [PATCH 140/282] small tweaks --- website/docs/dev_settings.md | 64 ++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/website/docs/dev_settings.md b/website/docs/dev_settings.md index 483bd18535..cb16ae76ca 100644 --- a/website/docs/dev_settings.md +++ b/website/docs/dev_settings.md @@ -214,7 +214,7 @@ These inputs wraps another inputs into {key: value} relation #### dict - this is dictionary type wrapping more inputs with keys defined in schema -- may be used as dynamic children (e.g. in `list` or `dict-modifiable`) +- may be used as dynamic children (e.g. in [list](#list) or [dict-modifiable](#dict-modifiable)) - in that case the only key modifier is `children` which is list of it's keys - USAGE: e.g. List of dictionaries where each dictionary have same structure. - if is not used as dynamic children then must have defined `"key"` under which are it's values stored @@ -600,7 +600,7 @@ How output of the schema could look like on save: - type of items is defined with key `"object_type"` - there are 2 possible ways how to set the type: 1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below) - 2.) item type name as string without modifiers (e.g. `text`) + 2.) item type name as string without modifiers (e.g. [text](#text)) 3.) enhancement of 1.) there is also support of `template` type but be carefull about endless loop of templates - goal of using `template` is to easily change same item definitions in multiple lists @@ -690,18 +690,31 @@ How output of the schema could look like on save: - one of dictionary inputs, this is only used as value input - items in this input can be removed and added same way as in `list` input - value items in dictionary must be the same type -- type of items is defined with key `"object_type"` - required keys may be defined under `"required_keys"` - required keys must be defined as a list (e.g. `["key_1"]`) and are moved to the top - these keys can't be removed or edited (it is possible to edit label if item is collapsible) -- there are 2 possible ways how to set the type: - 1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below) - 2.) item type name as string without modifiers (e.g. `text`) +- type of items is defined with key `"object_type"` + - there are 2 possible ways how to set the object type (Examples below): + 1. just a type name as string without modifiers (e.g. `"text"`) + 2. full types with modifiers as dictionary(`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` - this input can be collapsible + - `"use_label_wrap"` must be set to `True` (Default behavior) - that can be set with key `"collapsible"` as `True`/`False` (Default: `True`) - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) -1.) with item modifiers +1. **Object type** without modifiers +``` +{ + "type": "dict-modifiable", + "object_type": "text", + "is_group": true, + "key": "templates_mapping", + "label": "Muster - Templates mapping", + "is_file": true +} +``` + +2. **Object type** with item modifiers ``` { "type": "dict-modifiable", @@ -717,22 +730,10 @@ How output of the schema could look like on save: } ``` -2.) without modifiers -``` -{ - "type": "dict-modifiable", - "object_type": "text", - "is_group": true, - "key": "templates_mapping", - "label": "Muster - Templates mapping", - "is_file": true -} -``` - #### path - input for paths, use `path-input` internally - has 2 input modifiers `"multiplatform"` and `"multipath"` - - `"multiplatform"` - adds `"windows"`, `"linux"` and `"darwin"` path inputs result is dictionary + - `"multiplatform"` - adds `"windows"`, `"linux"` and `"darwin"` path inputs (result is dictionary) - `"multipath"` - it is possible to enter multiple paths - if both are enabled result is dictionary with lists @@ -797,6 +798,8 @@ How output of the schema could look like on save: - preimplemented entity to store and load color values - entity store and expect list of 4 integers in range 0-255 - integers represents rgba [Red, Green, Blue, Alpha] +- has modifier `"use_alpha"` which can be `True`/`False` + - alpha is always `255` if set to `True` and alpha slider is not visible in UI ``` { @@ -806,6 +809,13 @@ How output of the schema could look like on save: } ``` +### Anatomy +Anatomy represents data stored on project document. Item cares about **Project Anatomy**. + +#### anatomy +- entity is just enhanced [dict](#dict) item +- anatomy has always all keys overridden with overrides + ### Noninteractive items Items used only for UI purposes. @@ -831,15 +841,6 @@ Items used only for UI purposes. } ``` -### Anatomy -Anatomy represents data stored on project document. - -#### anatomy -- entity works similarly to `dict` -- anatomy has always all keys overridden with overrides - - overrides are not applied as all anatomy data must be available from project document - - all children must be groups - ### Proxy wrappers - should wraps multiple inputs only visually - these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled @@ -888,3 +889,8 @@ Anatomy represents data stored on project document. } ] } +``` + + +## How to add new settings +Always start with modifying or adding new schema and don't worry about values. When you think schema is ready to use launch OpenPype settings in development mode using `poetry run python ./start.py settings --dev` or prepared script in `~/openpype/tools/run_settings(.sh|.ps1)`. Settings opened in development mode have checkbox `Modify defaults` available in bottom left corner. When checked default values are modified and saved on `Save`. This is recommended approach how default settings should be created instead of direct modification of files. From 8b94d746e5595caa42bafae6184663683fd8e4f4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 18:00:26 +0200 Subject: [PATCH 141/282] show outdated build dialog when expected version can't be used with current build --- openpype/tools/tray/pype_tray.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/openpype/tools/tray/pype_tray.py b/openpype/tools/tray/pype_tray.py index 4e5db06a92..2f3e1bcab3 100644 --- a/openpype/tools/tray/pype_tray.py +++ b/openpype/tools/tray/pype_tray.py @@ -10,19 +10,19 @@ from Qt import QtCore, QtGui, QtWidgets import openpype.version from openpype.api import ( - Logger, resources, get_system_settings ) -from openpype.lib import ( - get_openpype_execute_args, +from openpype.lib import get_openpype_execute_args, Logger +from openpype.lib.openpype_version import ( op_version_control_available, + get_expected_version, + get_installed_version, is_current_version_studio_latest, is_current_version_higher_than_expected, is_running_from_build, is_running_staging, - get_expected_version, - get_openpype_version + get_openpype_version, ) from openpype.modules import TrayModulesManager from openpype import style @@ -329,6 +329,21 @@ class TrayManager: self._version_dialog.close() return + installed_version = get_installed_version() + expected_version = get_expected_version() + + # Request new build if is needed + if not expected_version.is_compatible(installed_version): + if ( + self._version_dialog is not None + and self._version_dialog.isVisible() + ): + self._version_dialog.close() + + dialog = BuildVersionDialog() + dialog.exec_() + return + if self._version_dialog is None: self._version_dialog = VersionUpdateDialog() self._version_dialog.restart_requested.connect( @@ -338,7 +353,6 @@ class TrayManager: self._outdated_version_ignored ) - expected_version = get_expected_version() current_version = get_openpype_version() current_is_higher = is_current_version_higher_than_expected() From ad64c3a66e10c2c34ecd4fe3549f636ce5777959 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 18:02:08 +0200 Subject: [PATCH 142/282] added backwards compatibility for 'is_compatible' method --- openpype/tools/tray/pype_tray.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/tools/tray/pype_tray.py b/openpype/tools/tray/pype_tray.py index 2f3e1bcab3..85bc00ead6 100644 --- a/openpype/tools/tray/pype_tray.py +++ b/openpype/tools/tray/pype_tray.py @@ -333,7 +333,11 @@ class TrayManager: expected_version = get_expected_version() # Request new build if is needed - if not expected_version.is_compatible(installed_version): + if ( + # Backwards compatibility + not hasattr(expected_version, "is_compatible") + or not expected_version.is_compatible(installed_version) + ): if ( self._version_dialog is not None and self._version_dialog.isVisible() From 1469c471d15c5556e4f0b2f5d06f1e07dcc74724 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 18:23:12 +0200 Subject: [PATCH 143/282] added javascript notation --- website/docs/dev_settings.md | 74 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/website/docs/dev_settings.md b/website/docs/dev_settings.md index cb16ae76ca..e5917c7549 100644 --- a/website/docs/dev_settings.md +++ b/website/docs/dev_settings.md @@ -195,7 +195,7 @@ Because formatting value can be only string it is possible to use formatting val #### dynamic_schema Dynamic schema item marks a place in settings schema where schemas defined by `BaseModuleSettingsDef` can be placed. - example: -``` +```javascript { "type": "dynamic_schema", "name": "project_settings/global" @@ -228,8 +228,8 @@ These inputs wraps another inputs into {key: value} relation - it is possible to add lighter background with `"highlight_content"` (Default: `False`) - lighter background has limits of maximum applies after 3-4 nested highlighted items there is not much difference in the color - output is dictionary `{the "key": children values}` -``` -# Example +```javascript +// Example { "key": "applications", "type": "dict", @@ -243,7 +243,7 @@ These inputs wraps another inputs into {key: value} relation ] } -# Without label +// Without label { "type": "dict", "key": "global", @@ -252,7 +252,7 @@ These inputs wraps another inputs into {key: value} relation ] } -# When used as widget +// When used as widget { "type": "list", "key": "profiles", @@ -283,7 +283,7 @@ These inputs wraps another inputs into {key: value} relation - they are not updated "live" it is required to save root changes and then modify values on this entity # TODO do live updates -``` +```javascript { "type": "dict-roots", "key": "roots", @@ -327,8 +327,8 @@ These inputs wraps another inputs into {key: value} relation - output is dictionary `{the "key": children values}` - using this type as template item for list type can be used to create infinite hierarchies -``` -# Example +```javascript +// Example { "type": "dict-conditional", "key": "my_key", @@ -336,7 +336,7 @@ These inputs wraps another inputs into {key: value} relation "enum_key": "type", "enum_label": "label", "enum_children": [ - # Each item must be a dictionary with 'key' + // Each item must be a dictionary with 'key' { "key": "action", "label": "Action", @@ -371,7 +371,7 @@ These inputs wraps another inputs into {key: value} relation ] }, { - # Separator does not have children as "separator" value is enough + // Separator does not have children as "separator" value is enough "key": "separator", "label": "Separator" } @@ -380,7 +380,7 @@ These inputs wraps another inputs into {key: value} relation ``` How output of the schema could look like on save: -``` +```javascript { "type": "separator" } @@ -407,7 +407,7 @@ How output of the schema could look like on save: #### boolean - simple checkbox, nothing more to set -``` +```javascript { "type": "boolean", "key": "my_boolean_key", @@ -422,7 +422,7 @@ How output of the schema could look like on save: - key `"maxium"` as maximum allowed number to enter (Default: `99999`) - key `"steps"` will change single step value of UI inputs (using arrows and wheel scroll) - for UI it is possible to show slider to enable this option set `show_slider` to `true` -``` +```javascript { "type": "number", "key": "fps", @@ -433,7 +433,7 @@ How output of the schema could look like on save: } ``` -``` +```javascript { "type": "number", "key": "ratio", @@ -450,7 +450,7 @@ How output of the schema could look like on save: - key `"multiline"` allows to enter multiple lines of text (Default: `False`) - key `"placeholder"` allows to show text inside input when is empty (Default: `None`) -``` +```javascript { "type": "text", "key": "deadline_pool", @@ -473,7 +473,7 @@ How output of the schema could look like on save: - set key `store_as_string` to `true` - code using that setting must expected that value is string and use json module to convert it to python types -``` +```javascript { "type": "raw-json", "key": "profiles", @@ -492,7 +492,7 @@ How output of the schema could look like on save: - it is recommended to use this option only in single selection mode - at the end this option is used only when defying default settings value or in dynamic items -``` +```javascript { "key": "tags", "label": "Tags", @@ -515,7 +515,7 @@ How output of the schema could look like on save: - `"work"` is used if default value is not specified - enum values are not updated on the fly it is required to save templates and reset settings to recache values -``` +```javascript { "key": "host", "label": "Host name", @@ -532,7 +532,7 @@ How output of the schema could look like on save: - to filter host names it is required to define `"hosts_filter"` which is list of host names that will be available - do not pass empty string if `use_empty_value` is enabled - ignoring host names would be more dangerous in some cases -``` +```javascript { "key": "host", "label": "Host name", @@ -555,7 +555,7 @@ How output of the schema could look like on save: - can be used only in project settings - has only `multiselection` - used only in project anatomy -``` +```javascript { "type": "apps-enum", "key": "applications", @@ -568,7 +568,7 @@ How output of the schema could look like on save: - can be used only in project settings - has only `multiselection` - used only in project anatomy -``` +```javascript { "type": "tools-enum", "key": "tools_env", @@ -605,7 +605,7 @@ How output of the schema could look like on save: - goal of using `template` is to easily change same item definitions in multiple lists 1.) with item modifiers -``` +```javascript { "type": "list", "key": "exclude_ports", @@ -619,7 +619,7 @@ How output of the schema could look like on save: ``` 2.) without modifiers -``` +```javascript { "type": "list", "key": "exclude_ports", @@ -629,8 +629,8 @@ How output of the schema could look like on save: ``` 3.) with template definition -``` -# Schema of list item where template is used +```javascript +// Schema of list item where template is used { "type": "list", "key": "menu_items", @@ -641,9 +641,9 @@ How output of the schema could look like on save: } } -# WARNING: -# In this example the template use itself inside which will work in `list` -# but may cause an issue in other entity types (e.g. `dict`). +// WARNING: +// In this example the template use itself inside which will work in `list` +// but may cause an issue in other entity types (e.g. `dict`). 'template_object_example.json' : [ @@ -703,7 +703,7 @@ How output of the schema could look like on save: - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) 1. **Object type** without modifiers -``` +```javascript { "type": "dict-modifiable", "object_type": "text", @@ -715,7 +715,7 @@ How output of the schema could look like on save: ``` 2. **Object type** with item modifiers -``` +```javascript { "type": "dict-modifiable", "object_type": { @@ -737,7 +737,7 @@ How output of the schema could look like on save: - `"multipath"` - it is possible to enter multiple paths - if both are enabled result is dictionary with lists -``` +```javascript { "type": "path", "key": "ffmpeg_path", @@ -759,7 +759,7 @@ How output of the schema could look like on save: - USAGE: For colors, transformations, etc. Custom number and different modifiers give ability to define if color is HUE or RGB, 0-255, 0-1, 0-100 etc. -``` +```javascript { "type": "list-strict", "key": "color", @@ -801,7 +801,7 @@ How output of the schema could look like on save: - has modifier `"use_alpha"` which can be `True`/`False` - alpha is always `255` if set to `True` and alpha slider is not visible in UI -``` +```javascript { "type": "color", "key": "bg_color", @@ -824,7 +824,7 @@ Items used only for UI purposes. - it is possible to use html tags inside the label - set `work_wrap` to `true`/`false` if you want to enable word wrapping in UI (default: `false`) -``` +```javascript { "type": "label", "label": "RED LABEL: Normal label" @@ -835,7 +835,7 @@ Items used only for UI purposes. - legacy name is `splitter` (still usable) - visual separator of items (more divider than separator) -``` +```javascript { "type": "separator" } @@ -850,7 +850,7 @@ Items used only for UI purposes. - wraps inputs into form look layout - should be used only for Pure inputs -``` +```javascript { "type": "dict-form", "children": [ @@ -875,7 +875,7 @@ Items used only for UI purposes. - looks like `dict` but does not hold `"key"` - should be used only for Pure inputs -``` +```javascript { "type": "collapsible-wrap", "label": "Collapsible example" From cbff5972a2b1c6aa7ebd9b19d519f122c955fe61 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 12 Aug 2022 18:23:24 +0200 Subject: [PATCH 144/282] added screenshot of settings UI in dev mode --- website/docs/assets/settings_dev.png | Bin 0 -> 15237 bytes website/docs/dev_settings.md | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 website/docs/assets/settings_dev.png diff --git a/website/docs/assets/settings_dev.png b/website/docs/assets/settings_dev.png new file mode 100644 index 0000000000000000000000000000000000000000..4d0359461e570163925bda6b3a2f5dd1c87c3e7b GIT binary patch literal 15237 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 a Date: Fri, 12 Aug 2022 18:41:55 +0200 Subject: [PATCH 145/282] :recycle: distribute ocio as zips --- .../maya/plugins/publish/extract_look.py | 6 ++++- poetry.lock | 25 +++---------------- pyproject.toml | 6 +++-- tools/fetch_thirdparty_libs.py | 23 +++++++++++++---- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index b425efba6f..b416669b87 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -43,7 +43,11 @@ def get_ocio_config_path(profile_folder): try: import OpenColorIOConfigs return os.path.join( - os.path.dirname(OpenColorIOConfigs.__file__), + os.environ["OPENPYPE_ROOT"], + "vendor", + "bin", + "ocioconfig" + "OpenColorIOConfigs", profile_folder, "config.ocio" ) diff --git a/poetry.lock b/poetry.lock index df8d8ab14a..21b6bda880 100644 --- a/poetry.lock +++ b/poetry.lock @@ -797,21 +797,6 @@ category = "main" optional = false python-versions = ">=3.7" -[[package]] -name = "opencolorio-configs" -version = "1.0.2" -description = "Curated set of OpenColorIO Configs for use in OpenPype" -category = "main" -optional = false -python-versions = "*" -develop = false - -[package.source] -type = "git" -url = "https://github.com/pypeclub/OpenColorIO-Configs.git" -reference = "main" -resolved_reference = "07c5e865bf2b115b589dd2876ae632cd410821b5" - [[package]] name = "opentimelineio" version = "0.14.0.dev1" @@ -1284,7 +1269,7 @@ python-versions = "*" [[package]] name = "pytz" -version = "2022.1" +version = "2022.2" description = "World timezone definitions, modern and historical" category = "dev" optional = false @@ -1750,7 +1735,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "89fb7e8ad310b5048bf78561f1146194c8779e286d839cc000f04e88be87f3f3" +content-hash = "de7422afb6aed02f75e1696afdda9ad6c7bf32da76b5022ee3e8f71a1ac4bae2" [metadata.files] acre = [] @@ -2146,7 +2131,6 @@ multidict = [ {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, ] -opencolorio-configs = [] opentimelineio = [] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, @@ -2398,10 +2382,7 @@ python-xlib = [ python3-xlib = [ {file = "python3-xlib-0.15.tar.gz", hash = "sha256:dc4245f3ae4aa5949c1d112ee4723901ade37a96721ba9645f2bfa56e5b383f8"}, ] -pytz = [ - {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, - {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, -] +pytz = [] pywin32 = [ {file = "pywin32-301-cp35-cp35m-win32.whl", hash = "sha256:93367c96e3a76dfe5003d8291ae16454ca7d84bb24d721e0b74a07610b7be4a7"}, {file = "pywin32-301-cp35-cp35m-win_amd64.whl", hash = "sha256:9635df6998a70282bd36e7ac2a5cef9ead1627b0a63b17c731312c7a0daebb72"}, diff --git a/pyproject.toml b/pyproject.toml index 1d757deaa0..b7b3fb967f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,8 +70,6 @@ requests = "^2.25.1" pysftp = "^0.2.9" dropbox = "^11.20.0" aiohttp-middlewares = "^2.0.0" -OpenColorIO-Configs = { git = "https://github.com/pypeclub/OpenColorIO-Configs.git", branch = "main" } - [tool.poetry.dev-dependencies] flake8 = "^3.7" @@ -144,6 +142,10 @@ hash = "3894dec7e4e521463891a869586850e8605f5fd604858b674c87323bf33e273d" url = "https://distribute.openpype.io/thirdparty/oiio-2.2.0-darwin.tgz" hash = "sha256:..." +[openpype.thirdparty.ocioconfig] +url = "https://distribute.openpype.io/thirdparty/OpenColorIO-Configs-1.0.2.zip" +hash = "4ac17c1f7de83465e6f51dd352d7117e07e765b66d00443257916c828e35b6ce" + [tool.pyright] include = [ "igniter", diff --git a/tools/fetch_thirdparty_libs.py b/tools/fetch_thirdparty_libs.py index b616beab27..421cc32dbd 100644 --- a/tools/fetch_thirdparty_libs.py +++ b/tools/fetch_thirdparty_libs.py @@ -109,13 +109,20 @@ except AttributeError: for k, v in thirdparty.items(): _print(f"processing {k}") - destination_path = openpype_root / "vendor" / "bin" / k / platform_name - url = v.get(platform_name).get("url") + destination_path = openpype_root / "vendor" / "bin" / k + if not v.get(platform_name): _print(("missing definition for current " - f"platform [ {platform_name} ]"), 1) - sys.exit(1) + f"platform [ {platform_name} ]"), 2) + _print("trying to get universal url for all platforms") + url = v.get("url") + if not url: + _print("cannot get url", 1) + sys.exit(1) + else: + url = v.get(platform_name).get("url") + destination_path = destination_path / platform_name parsed_url = urlparse(url) @@ -147,7 +154,13 @@ for k, v in thirdparty.items(): # get file with checksum _print("Calculating sha256 ...", 2) calc_checksum = sha256_sum(temp_file) - if v.get(platform_name).get("hash") != calc_checksum: + + if v.get(platform_name): + item_hash = v.get(platform_name).get("hash") + else: + item_hash = v.get("hash") + + if item_hash != calc_checksum: _print("Downloaded files checksum invalid.") sys.exit(1) From 5a2e8f6d8f814bd0d7f6707580edd08e0098fec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Fri, 12 Aug 2022 18:44:16 +0200 Subject: [PATCH 146/282] :bug: remove import --- .../maya/plugins/publish/extract_look.py | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index b416669b87..cece8ee22b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -40,19 +40,17 @@ def get_ocio_config_path(profile_folder): Returns: str: Path to vendorized config file. """ - try: - import OpenColorIOConfigs - return os.path.join( - os.environ["OPENPYPE_ROOT"], - "vendor", - "bin", - "ocioconfig" - "OpenColorIOConfigs", - profile_folder, - "config.ocio" - ) - except ImportError: - return None + + return os.path.join( + os.environ["OPENPYPE_ROOT"], + "vendor", + "bin", + "ocioconfig" + "OpenColorIOConfigs", + profile_folder, + "config.ocio" + ) + def find_paths_by_hash(texture_hash): """Find the texture hash key in the dictionary. From 1ad9728962b92e55fa4d16601a7a48add381a456 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 12 Aug 2022 19:32:13 +0200 Subject: [PATCH 147/282] :recycle: remove forgotten args, fix typos --- igniter/bootstrap_repos.py | 35 +++++++++++++++-------------------- start.py | 2 +- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 3dab67ebf1..56ec2749ca 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -381,7 +381,7 @@ class OpenPypeVersion(semver.VersionInfo): @classmethod def get_local_versions( cls, production: bool = None, - staging: bool = None, compatible_with: OpenPypeVersion = None + staging: bool = None ) -> List: """Get all versions available on this machine. @@ -391,8 +391,10 @@ class OpenPypeVersion(semver.VersionInfo): Args: production (bool): Return production versions. staging (bool): Return staging versions. - compatible_with (OpenPypeVersion): Return only those compatible - with specified version. + + Returns: + list: of compatible versions available on the machine. + """ # Return all local versions if arguments are set to None if production is None and staging is None: @@ -435,8 +437,7 @@ class OpenPypeVersion(semver.VersionInfo): Args: production (bool): Return production versions. staging (bool): Return staging versions. - compatible_with (OpenPypeVersion): Return only those compatible - with specified version. + """ # Return all local versions if arguments are set to None if production is None and staging is None: @@ -745,9 +746,9 @@ class BootstrapRepos: self, repo_dir: Path = None) -> Union[OpenPypeVersion, None]: """Copy zip created from OpenPype repositories to user data dir. - This detect OpenPype version either in local "live" OpenPype + This detects OpenPype version either in local "live" OpenPype repository or in user provided path. Then it will zip it in temporary - directory and finally it will move it to destination which is user + directory, and finally it will move it to destination which is user data directory. Existing files will be replaced. Args: @@ -758,7 +759,7 @@ class BootstrapRepos: """ # if repo dir is not set, we detect local "live" OpenPype repository - # version and use it as a source. Otherwise repo_dir is user + # version and use it as a source. Otherwise, repo_dir is user # entered location. if repo_dir: version = self.get_version(repo_dir) @@ -1122,21 +1123,19 @@ class BootstrapRepos: @staticmethod def find_openpype_version( version: Union[str, OpenPypeVersion], - staging: bool, - compatible_with: OpenPypeVersion = None + staging: bool ) -> Union[OpenPypeVersion, None]: """Find location of specified OpenPype version. Args: version (Union[str, OpenPypeVersion): Version to find. staging (bool): Filter staging versions. - compatible_with (OpenPypeVersion, optional): Find only - versions compatible with specified one. + + Returns: + requested OpenPypeVersion. """ installed_version = OpenPypeVersion.get_installed_version() - if not compatible_with: - compatible_with = installed_version if isinstance(version, str): version = OpenPypeVersion(version=version) @@ -1144,8 +1143,7 @@ class BootstrapRepos: return installed_version local_versions = OpenPypeVersion.get_local_versions( - staging=staging, production=not staging, - compatible_with=compatible_with + staging=staging, production=not staging ) zip_version = None for local_version in local_versions: @@ -1159,8 +1157,7 @@ class BootstrapRepos: return zip_version remote_versions = OpenPypeVersion.get_remote_versions( - staging=staging, production=not staging, - compatible_with=compatible_with + staging=staging, production=not staging ) for remote_version in remote_versions: if remote_version == version: @@ -1237,8 +1234,6 @@ class BootstrapRepos: otherwise. include_zips (bool, optional): If set True it will try to find OpenPype in zip files in given directory. - compatible_with (OpenPypeVersion, optional): Find only those - versions compatible with the one specified. Returns: dict of Path: Dictionary of detected OpenPype version. diff --git a/start.py b/start.py index 52e98bb6e1..bfbcc77bc9 100644 --- a/start.py +++ b/start.py @@ -689,7 +689,7 @@ def _find_frozen_openpype(use_version: str = None, # Collect OpenPype versions installed_version = OpenPypeVersion.get_installed_version() # Expected version that should be used by studio settings - # - this option is used only if version is not explictly set and if + # - this option is used only if version is not explicitly set and if # studio has set explicit version in settings studio_version = OpenPypeVersion.get_expected_studio_version(use_staging) From b61e47a15d4ea7f843aa5a17963f8f4d0d73c77f Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 12 Aug 2022 19:45:26 +0200 Subject: [PATCH 148/282] :recycle: don't look for compatible version automatically --- igniter/bootstrap_repos.py | 12 +----------- start.py | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 56ec2749ca..dfcca2cf33 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -1166,16 +1166,12 @@ class BootstrapRepos: @staticmethod def find_latest_openpype_version( - staging: bool, - compatible_with: OpenPypeVersion = None + staging: bool ) -> Union[OpenPypeVersion, None]: """Find the latest available OpenPype version in all location. Args: staging (bool): True to look for staging versions. - compatible_with (OpenPypeVersion, optional): If set, it will - try to find the latest version compatible with the - one specified. Returns: Latest OpenPype version on None if nothing was found. @@ -1195,12 +1191,6 @@ class BootstrapRepos: if not all_versions: return None - if compatible_with: - all_versions = [ - version for version in all_versions - if version.is_compatible(installed_version) - ] - all_versions.sort() latest_version = all_versions[-1] if latest_version == installed_version: diff --git a/start.py b/start.py index bfbcc77bc9..9837252a1f 100644 --- a/start.py +++ b/start.py @@ -729,7 +729,7 @@ def _find_frozen_openpype(use_version: str = None, ">>> Finding latest version compatible " f"with [ {installed_version} ]")) openpype_version = bootstrap.find_latest_openpype_version( - use_staging, compatible_with=installed_version) + use_staging) if openpype_version is None: if use_staging: From aa0fe93a504a3a513239c541e698a99600de9736 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 12 Aug 2022 19:50:07 +0200 Subject: [PATCH 149/282] :bug: fix version list --- start.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/start.py b/start.py index 9837252a1f..084eb7451a 100644 --- a/start.py +++ b/start.py @@ -726,7 +726,7 @@ def _find_frozen_openpype(use_version: str = None, else: # Default behavior to use latest version _print(( - ">>> Finding latest version compatible " + ">>> Finding latest version " f"with [ {installed_version} ]")) openpype_version = bootstrap.find_latest_openpype_version( use_staging) @@ -947,7 +947,12 @@ def _boot_print_versions(use_staging, local_version, openpype_root): openpype_versions = bootstrap.find_openpype( include_zips=True, staging=use_staging, - compatible_with=compatible_with) + ) + openpype_versions = [ + version for version in openpype_versions + if version.is_compatible( + OpenPypeVersion.get_installed_version()) + ] list_versions(openpype_versions, local_version) From ae491af33b234f6ef7130c7f52f8a9e67cd032a4 Mon Sep 17 00:00:00 2001 From: Allan Ihsan Date: Mon, 15 Aug 2022 01:58:36 +0300 Subject: [PATCH 150/282] Adjust schema to include all lights flag. --- openpype/settings/defaults/project_settings/maya.json | 5 +++-- .../projects_schema/schemas/schema_maya_render_settings.json | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index ac0f161cf2..c95d47d576 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -33,7 +33,8 @@ }, "RenderSettings": { "apply_render_settings": true, - "default_render_image_folder": "", + "default_render_image_folder": "renders", + "enable_all_lights": false, "aov_separator": "underscore", "reset_current_frame": false, "arnold_renderer": { @@ -976,4 +977,4 @@ "ValidateNoAnimation": false } } -} \ No newline at end of file +} diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_render_settings.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_render_settings.json index af197604f8..6ee02ca78f 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_render_settings.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_render_settings.json @@ -14,6 +14,11 @@ "key": "default_render_image_folder", "label": "Default render image folder" }, + { + "type": "boolean", + "key": "enable_all_lights", + "label": "Include all lights in Render Setup Layers by default" + }, { "key": "aov_separator", "label": "AOV Separator character", From bbe7bc2fdb533375d9acc48a8c6b2f5c1538ecc1 Mon Sep 17 00:00:00 2001 From: Allan Ihsan Date: Mon, 15 Aug 2022 01:59:20 +0300 Subject: [PATCH 151/282] Include `RenderSetupIncludeLights` flag in plugin info, grab value from render instance. --- .../modules/deadline/plugins/publish/submit_maya_deadline.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py index f253ceb21a..7966861358 100644 --- a/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/deadline/plugins/publish/submit_maya_deadline.py @@ -62,6 +62,7 @@ payload_skeleton_template = { "RenderLayer": None, # Render only this layer "Renderer": None, "ProjectPath": None, # Resolve relative references + "RenderSetupIncludeLights": None, # Include all lights flag. }, "AuxFiles": [] # Mandatory for Deadline, may be empty } @@ -413,8 +414,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): # Gather needed data ------------------------------------------------ default_render_file = instance.context.data.get('project_settings')\ .get('maya')\ - .get('create')\ - .get('CreateRender')\ + .get('RenderSettings')\ .get('default_render_image_folder') filename = os.path.basename(filepath) comment = context.data.get("comment", "") @@ -505,6 +505,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): self.payload_skeleton["JobInfo"]["Comment"] = comment self.payload_skeleton["PluginInfo"]["RenderLayer"] = renderlayer + self.payload_skeleton["PluginInfo"]["RenderSetupIncludeLights"] = instance.data.get("renderSetupIncludeLights") # noqa # Adding file dependencies. dependencies = instance.context.data["fileDependencies"] dependencies.append(filepath) From d7aba60460ce19af1c9a4c2bb629c967f8d06750 Mon Sep 17 00:00:00 2001 From: Allan Ihsan Date: Mon, 15 Aug 2022 01:59:36 +0300 Subject: [PATCH 152/282] Validate lights flag --- .../hosts/maya/plugins/publish/validate_rendersettings.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py index 1dab3274a0..93ef7d7af7 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py @@ -242,6 +242,14 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): instance.context.data["project_settings"]["maya"]["publish"]["ValidateRenderSettings"].get( # noqa: E501 "{}_render_attributes".format(renderer)) or [] ) + settings_lights_flag = instance.context.data["project_settings"].get( + "maya", {}).get( + "RenderSettings", {}).get( + "enable_all_lights", {}) + + instance_lights_flag = instance.data.get("renderSetupIncludeLights") + if settings_lights_flag != instance_lights_flag: + cls.log.warning('Instance flag for "Render Setup Include Lights" is set to {0} and Settings flag is set to {1}'.format(instance_lights_flag, settings_lights_flag)) # noqa # go through definitions and test if such node.attribute exists. # if so, compare its value from the one required. From 5322527226344498aec2b830847b42a60e91eca8 Mon Sep 17 00:00:00 2001 From: Allan Ihsan Date: Mon, 15 Aug 2022 01:59:56 +0300 Subject: [PATCH 153/282] add flag attribute to render creator --- openpype/hosts/maya/plugins/create/create_render.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index fbe670b1ea..2f09aaee87 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -71,7 +71,7 @@ class CreateRender(plugin.Creator): label = "Render" family = "rendering" icon = "eye" - + enable_all_lights = True _token = None _user = None _password = None @@ -220,6 +220,12 @@ class CreateRender(plugin.Creator): self.data["tilesY"] = 2 self.data["convertToScanline"] = False self.data["useReferencedAovs"] = False + self.data["renderSetupIncludeLights"] = ( + self._project_settings.get( + "maya", {}).get( + "RenderSettings", {}).get( + "enable_all_lights", {}) + ) # Disable for now as this feature is not working yet # self.data["assScene"] = False From 5146c5a7e7f83032ba5d512a6861fb8f9b1b47f1 Mon Sep 17 00:00:00 2001 From: Allan Ihsan Date: Mon, 15 Aug 2022 02:00:15 +0300 Subject: [PATCH 154/282] Add flag to collector, fix settings path bug --- openpype/hosts/maya/api/lib_rendersettings.py | 3 +- .../maya/plugins/publish/collect_render.py | 8 +++-- .../publish/validate_render_image_rule.py | 31 +++++++++++-------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/maya/api/lib_rendersettings.py b/openpype/hosts/maya/api/lib_rendersettings.py index 9aea55a03b..7cd2193086 100644 --- a/openpype/hosts/maya/api/lib_rendersettings.py +++ b/openpype/hosts/maya/api/lib_rendersettings.py @@ -60,8 +60,7 @@ class RenderSettings(object): try: aov_separator = self._aov_chars[( self._project_settings["maya"] - ["create"] - ["CreateRender"] + ["RenderSettings"] ["aov_separator"] )] except KeyError: diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index e132cffe53..7035da2ec7 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -202,8 +202,7 @@ class CollectMayaRender(pyblish.api.ContextPlugin): aov_dict = {} default_render_file = context.data.get('project_settings')\ .get('maya')\ - .get('create')\ - .get('CreateRender')\ + .get('RenderSettings')\ .get('default_render_image_folder') or "" # replace relative paths with absolute. Render products are # returned as list of dictionaries. @@ -318,7 +317,10 @@ class CollectMayaRender(pyblish.api.ContextPlugin): "useReferencedAovs": render_instance.data.get( "useReferencedAovs") or render_instance.data.get( "vrayUseReferencedAovs") or False, - "aovSeparator": layer_render_products.layer_data.aov_separator # noqa: E501 + "aovSeparator": layer_render_products.layer_data.aov_separator, # noqa: E501 + "renderSetupIncludeLights": render_instance.data.get( + "renderSetupIncludeLights" + ) } # Collect Deadline url if Deadline module is enabled diff --git a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py index 642ca9e25d..353d0ad63a 100644 --- a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -1,6 +1,6 @@ import maya.mel as mel -import pymel.core as pm +from maya import cmds import pyblish.api import openpype.api @@ -11,8 +11,10 @@ def get_file_rule(rule): class ValidateRenderImageRule(pyblish.api.InstancePlugin): - """Validates "images" file rule is set to "renders/" - + """Validates Maya Workpace "images" file rule matches project settings. + This validates against the configured default render image folder: + Studio Settings > Project > Maya > + Render Settings > Default render image folder. """ order = openpype.api.ValidateContentsOrder @@ -22,25 +24,28 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): actions = [openpype.api.RepairAction] def process(self, instance): + required_images_rule = self.get_default_render_image_folder(instance) + current_images_rule = cmds.workspace(fileRuleEntry="images") - default_render_file = self.get_default_render_image_folder(instance) - - assert get_file_rule("images") == default_render_file, ( - "Workspace's `images` file rule must be set to: {}".format( - default_render_file + assert current_images_rule == required_images_rule, ( + "Invalid workspace `images` file rule value: '{}'. " + "Must be set to: '{}'".format( + current_images_rule, required_images_rule ) ) @classmethod def repair(cls, instance): - default = cls.get_default_render_image_folder(instance) - pm.workspace.fileRules["images"] = default - pm.system.Workspace.save() + required_images_rule = cls.get_default_render_image_folder(instance) + current_images_rule = cmds.workspace(fileRuleEntry="images") + + if current_images_rule != required_images_rule: + cmds.workspace(fileRule=("images", required_images_rule)) + cmds.workspace(saveWorkspace=True) @staticmethod def get_default_render_image_folder(instance): return instance.context.data.get('project_settings')\ .get('maya') \ - .get('create') \ - .get('CreateRender') \ + .get('RenderSettings') \ .get('default_render_image_folder') From 8fcf5ffa28ae615219d2d3a31b0419bec3a746b6 Mon Sep 17 00:00:00 2001 From: Allan Ihsan Date: Mon, 15 Aug 2022 02:19:02 +0300 Subject: [PATCH 155/282] Revert "Add flag to collector, fix settings path bug" This reverts part of commit 5146c5a7e7f83032ba5d512a6861fb8f9b1b47f1. --- .../publish/validate_render_image_rule.py | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py index 353d0ad63a..642ca9e25d 100644 --- a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -1,6 +1,6 @@ import maya.mel as mel +import pymel.core as pm -from maya import cmds import pyblish.api import openpype.api @@ -11,10 +11,8 @@ def get_file_rule(rule): class ValidateRenderImageRule(pyblish.api.InstancePlugin): - """Validates Maya Workpace "images" file rule matches project settings. - This validates against the configured default render image folder: - Studio Settings > Project > Maya > - Render Settings > Default render image folder. + """Validates "images" file rule is set to "renders/" + """ order = openpype.api.ValidateContentsOrder @@ -24,28 +22,25 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): actions = [openpype.api.RepairAction] def process(self, instance): - required_images_rule = self.get_default_render_image_folder(instance) - current_images_rule = cmds.workspace(fileRuleEntry="images") - assert current_images_rule == required_images_rule, ( - "Invalid workspace `images` file rule value: '{}'. " - "Must be set to: '{}'".format( - current_images_rule, required_images_rule + default_render_file = self.get_default_render_image_folder(instance) + + assert get_file_rule("images") == default_render_file, ( + "Workspace's `images` file rule must be set to: {}".format( + default_render_file ) ) @classmethod def repair(cls, instance): - required_images_rule = cls.get_default_render_image_folder(instance) - current_images_rule = cmds.workspace(fileRuleEntry="images") - - if current_images_rule != required_images_rule: - cmds.workspace(fileRule=("images", required_images_rule)) - cmds.workspace(saveWorkspace=True) + default = cls.get_default_render_image_folder(instance) + pm.workspace.fileRules["images"] = default + pm.system.Workspace.save() @staticmethod def get_default_render_image_folder(instance): return instance.context.data.get('project_settings')\ .get('maya') \ - .get('RenderSettings') \ + .get('create') \ + .get('CreateRender') \ .get('default_render_image_folder') From d2f9c100c35edbe9cafd59db6e732c9ba058e309 Mon Sep 17 00:00:00 2001 From: Allan Ihsan Date: Mon, 15 Aug 2022 02:19:42 +0300 Subject: [PATCH 156/282] Fix correct path bug --- .../hosts/maya/plugins/publish/validate_render_image_rule.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py index 642ca9e25d..0abcf2f12a 100644 --- a/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py +++ b/openpype/hosts/maya/plugins/publish/validate_render_image_rule.py @@ -41,6 +41,5 @@ class ValidateRenderImageRule(pyblish.api.InstancePlugin): def get_default_render_image_folder(instance): return instance.context.data.get('project_settings')\ .get('maya') \ - .get('create') \ - .get('CreateRender') \ + .get('RenderSettings') \ .get('default_render_image_folder') From e6584a9b940782bb6927e807b6a19412a1fd2fe4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 12:08:20 +0200 Subject: [PATCH 157/282] removed pype 2 compatibility --- .../custom/plugins/GlobalJobPreLoad.py | 48 ------------------- 1 file changed, 48 deletions(-) diff --git a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py index 172649c951..cd36e45921 100644 --- a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py +++ b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py @@ -260,52 +260,6 @@ def pype_command_line(executable, arguments, workingDirectory): return executable, arguments, workingDirectory -def pype(deadlinePlugin): - """Remaps `PYPE_METADATA_FILE` and `PYPE_PYTHON_EXE` environment vars. - - `PYPE_METADATA_FILE` is used on farm to point to rendered data. This path - originates on platform from which this job was published. To be able to - publish on different platform, this path needs to be remapped. - - `PYPE_PYTHON_EXE` can be used to specify custom location of python - interpreter to use for Pype. This is remappeda also if present even - though it probably doesn't make much sense. - - Arguments: - deadlinePlugin: Deadline job plugin passed by Deadline - - """ - print(">>> Getting job ...") - job = deadlinePlugin.GetJob() - # PYPE should be here, not OPENPYPE - backward compatibility!! - pype_metadata = job.GetJobEnvironmentKeyValue("PYPE_METADATA_FILE") - pype_python = job.GetJobEnvironmentKeyValue("PYPE_PYTHON_EXE") - print(">>> Having backward compatible env vars {}/{}".format(pype_metadata, - pype_python)) - # test if it is pype publish job. - if pype_metadata: - pype_metadata = RepositoryUtils.CheckPathMapping(pype_metadata) - if platform.system().lower() == "linux": - pype_metadata = pype_metadata.replace("\\", "/") - - print("- remapping PYPE_METADATA_FILE: {}".format(pype_metadata)) - job.SetJobEnvironmentKeyValue("PYPE_METADATA_FILE", pype_metadata) - deadlinePlugin.SetProcessEnvironmentVariable( - "PYPE_METADATA_FILE", pype_metadata) - - if pype_python: - pype_python = RepositoryUtils.CheckPathMapping(pype_python) - if platform.system().lower() == "linux": - pype_python = pype_python.replace("\\", "/") - - print("- remapping PYPE_PYTHON_EXE: {}".format(pype_python)) - job.SetJobEnvironmentKeyValue("PYPE_PYTHON_EXE", pype_python) - deadlinePlugin.SetProcessEnvironmentVariable( - "PYPE_PYTHON_EXE", pype_python) - - deadlinePlugin.ModifyCommandLineCallback += pype_command_line - - def __main__(deadlinePlugin): print("*** GlobalJobPreload start ...") print(">>> Getting job ...") @@ -329,5 +283,3 @@ def __main__(deadlinePlugin): inject_render_job_id(deadlinePlugin) elif openpype_render_job == '1' or openpype_remote_job == '1': inject_openpype_environment(deadlinePlugin) - else: - pype(deadlinePlugin) # backward compatibility with Pype2 From 919a6146c6c16d5f98caff3eb79792e876b2de49 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 12:08:32 +0200 Subject: [PATCH 158/282] removed unused function --- .../custom/plugins/GlobalJobPreLoad.py | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py index cd36e45921..98c727f618 100644 --- a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py +++ b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py @@ -234,32 +234,6 @@ def inject_render_job_id(deadlinePlugin): print(">>> Injection end.") -def pype_command_line(executable, arguments, workingDirectory): - """Remap paths in comand line argument string. - - Using Deadline rempper it will remap all path found in command-line. - - Args: - executable (str): path to executable - arguments (str): arguments passed to executable - workingDirectory (str): working directory path - - Returns: - Tuple(executable, arguments, workingDirectory) - - """ - print("-" * 40) - print("executable: {}".format(executable)) - print("arguments: {}".format(arguments)) - print("workingDirectory: {}".format(workingDirectory)) - print("-" * 40) - print("Remapping arguments ...") - arguments = RepositoryUtils.CheckPathMapping(arguments) - print("* {}".format(arguments)) - print("-" * 40) - return executable, arguments, workingDirectory - - def __main__(deadlinePlugin): print("*** GlobalJobPreload start ...") print(">>> Getting job ...") From 963b66eb5808249dd47ae5e6bd62a53972352655 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 12:15:35 +0200 Subject: [PATCH 159/282] fixed python 2 compatibility --- .../custom/plugins/GlobalJobPreLoad.py | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py index 98c727f618..61b95cf06d 100644 --- a/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py +++ b/openpype/modules/deadline/repository/custom/plugins/GlobalJobPreLoad.py @@ -34,7 +34,7 @@ def get_openpype_version_from_path(path, build=True): # if only builds are requested if build and not os.path.isfile(exe): # noqa: E501 - print(f" ! path is not a build: {path}") + print(" ! path is not a build: {}".format(path)) return None version = {} @@ -70,11 +70,12 @@ def inject_openpype_environment(deadlinePlugin): # lets go over all available and find compatible build. requested_version = job.GetJobEnvironmentKeyValue("OPENPYPE_VERSION") if requested_version: - print((">>> Scanning for compatible requested " - f"version {requested_version}")) + print(( + ">>> Scanning for compatible requested version {}" + ).format(requested_version)) install_dir = DirectoryUtils.SearchDirectoryList(dir_list) if install_dir: - print(f"--- Looking for OpenPype at: {install_dir}") + print("--- Looking for OpenPype at: {}".format(install_dir)) sub_dirs = [ f.path for f in os.scandir(install_dir) if f.is_dir() @@ -83,18 +84,20 @@ def inject_openpype_environment(deadlinePlugin): version = get_openpype_version_from_path(subdir) if not version: continue - print(f" - found: {version} - {subdir}") + print(" - found: {} - {}".format(version, subdir)) openpype_versions.append((version, subdir)) exe = FileUtils.SearchFileList(exe_list) if openpype_versions: # if looking for requested compatible version, # add the implicitly specified to the list too. - print(f"Looking for OpenPype at: {os.path.dirname(exe)}") + print("Looking for OpenPype at: {}".format(os.path.dirname(exe))) version = get_openpype_version_from_path( os.path.dirname(exe)) if version: - print(f" - found: {version} - {os.path.dirname(exe)}") + print(" - found: {} - {}".format( + version, os.path.dirname(exe) + )) openpype_versions.append((version, os.path.dirname(exe))) if requested_version: @@ -106,8 +109,9 @@ def inject_openpype_environment(deadlinePlugin): int(t) if t.isdigit() else t.lower() for t in re.split(r"(\d+)", ver[0]) ]) - print(("*** Latest available version found is " - f"{openpype_versions[-1][0]}")) + print(( + "*** Latest available version found is {}" + ).format(openpype_versions[-1][0])) requested_major, requested_minor, _ = requested_version.split(".")[:3] # noqa: E501 compatible_versions = [] for version in openpype_versions: @@ -127,8 +131,9 @@ def inject_openpype_environment(deadlinePlugin): int(t) if t.isdigit() else t.lower() for t in re.split(r"(\d+)", ver[0]) ]) - print(("*** Latest compatible version found is " - f"{compatible_versions[-1][0]}")) + print(( + "*** Latest compatible version found is {}" + ).format(compatible_versions[-1][0])) # create list of executables for different platform and let # Deadline decide. exe_list = [ From 553fcdff538178019d76d73ccb0b83119a816ef4 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 13:22:25 +0200 Subject: [PATCH 160/282] added python 2 compatible attrs to vendor --- .../vendor/python/python_2/attr/__init__.py | 80 + .../vendor/python/python_2/attr/__init__.pyi | 484 +++ openpype/vendor/python/python_2/attr/_cmp.py | 154 + openpype/vendor/python/python_2/attr/_cmp.pyi | 13 + .../vendor/python/python_2/attr/_compat.py | 261 ++ .../vendor/python/python_2/attr/_config.py | 33 + .../vendor/python/python_2/attr/_funcs.py | 422 +++ openpype/vendor/python/python_2/attr/_make.py | 3173 +++++++++++++++++ .../vendor/python/python_2/attr/_next_gen.py | 216 ++ .../python/python_2/attr/_version_info.py | 87 + .../python/python_2/attr/_version_info.pyi | 9 + .../vendor/python/python_2/attr/converters.py | 155 + .../python/python_2/attr/converters.pyi | 13 + .../vendor/python/python_2/attr/exceptions.py | 94 + .../python/python_2/attr/exceptions.pyi | 17 + .../vendor/python/python_2/attr/filters.py | 54 + .../vendor/python/python_2/attr/filters.pyi | 6 + openpype/vendor/python/python_2/attr/py.typed | 0 .../vendor/python/python_2/attr/setters.py | 79 + .../vendor/python/python_2/attr/setters.pyi | 19 + .../vendor/python/python_2/attr/validators.py | 561 +++ .../python/python_2/attr/validators.pyi | 78 + .../vendor/python/python_2/attrs/__init__.py | 70 + .../vendor/python/python_2/attrs/__init__.pyi | 63 + .../python/python_2/attrs/converters.py | 3 + .../python/python_2/attrs/exceptions.py | 3 + .../vendor/python/python_2/attrs/filters.py | 3 + .../vendor/python/python_2/attrs/py.typed | 0 .../vendor/python/python_2/attrs/setters.py | 3 + .../python/python_2/attrs/validators.py | 3 + 30 files changed, 6156 insertions(+) create mode 100644 openpype/vendor/python/python_2/attr/__init__.py create mode 100644 openpype/vendor/python/python_2/attr/__init__.pyi create mode 100644 openpype/vendor/python/python_2/attr/_cmp.py create mode 100644 openpype/vendor/python/python_2/attr/_cmp.pyi create mode 100644 openpype/vendor/python/python_2/attr/_compat.py create mode 100644 openpype/vendor/python/python_2/attr/_config.py create mode 100644 openpype/vendor/python/python_2/attr/_funcs.py create mode 100644 openpype/vendor/python/python_2/attr/_make.py create mode 100644 openpype/vendor/python/python_2/attr/_next_gen.py create mode 100644 openpype/vendor/python/python_2/attr/_version_info.py create mode 100644 openpype/vendor/python/python_2/attr/_version_info.pyi create mode 100644 openpype/vendor/python/python_2/attr/converters.py create mode 100644 openpype/vendor/python/python_2/attr/converters.pyi create mode 100644 openpype/vendor/python/python_2/attr/exceptions.py create mode 100644 openpype/vendor/python/python_2/attr/exceptions.pyi create mode 100644 openpype/vendor/python/python_2/attr/filters.py create mode 100644 openpype/vendor/python/python_2/attr/filters.pyi create mode 100644 openpype/vendor/python/python_2/attr/py.typed create mode 100644 openpype/vendor/python/python_2/attr/setters.py create mode 100644 openpype/vendor/python/python_2/attr/setters.pyi create mode 100644 openpype/vendor/python/python_2/attr/validators.py create mode 100644 openpype/vendor/python/python_2/attr/validators.pyi create mode 100644 openpype/vendor/python/python_2/attrs/__init__.py create mode 100644 openpype/vendor/python/python_2/attrs/__init__.pyi create mode 100644 openpype/vendor/python/python_2/attrs/converters.py create mode 100644 openpype/vendor/python/python_2/attrs/exceptions.py create mode 100644 openpype/vendor/python/python_2/attrs/filters.py create mode 100644 openpype/vendor/python/python_2/attrs/py.typed create mode 100644 openpype/vendor/python/python_2/attrs/setters.py create mode 100644 openpype/vendor/python/python_2/attrs/validators.py diff --git a/openpype/vendor/python/python_2/attr/__init__.py b/openpype/vendor/python/python_2/attr/__init__.py new file mode 100644 index 0000000000..f95c96dd57 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/__init__.py @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import sys + +from functools import partial + +from . import converters, exceptions, filters, setters, validators +from ._cmp import cmp_using +from ._config import get_run_validators, set_run_validators +from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types +from ._make import ( + NOTHING, + Attribute, + Factory, + attrib, + attrs, + fields, + fields_dict, + make_class, + validate, +) +from ._version_info import VersionInfo + + +__version__ = "21.4.0" +__version_info__ = VersionInfo._from_version_string(__version__) + +__title__ = "attrs" +__description__ = "Classes Without Boilerplate" +__url__ = "https://www.attrs.org/" +__uri__ = __url__ +__doc__ = __description__ + " <" + __uri__ + ">" + +__author__ = "Hynek Schlawack" +__email__ = "hs@ox.cx" + +__license__ = "MIT" +__copyright__ = "Copyright (c) 2015 Hynek Schlawack" + + +s = attributes = attrs +ib = attr = attrib +dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) + +__all__ = [ + "Attribute", + "Factory", + "NOTHING", + "asdict", + "assoc", + "astuple", + "attr", + "attrib", + "attributes", + "attrs", + "cmp_using", + "converters", + "evolve", + "exceptions", + "fields", + "fields_dict", + "filters", + "get_run_validators", + "has", + "ib", + "make_class", + "resolve_types", + "s", + "set_run_validators", + "setters", + "validate", + "validators", +] + +if sys.version_info[:2] >= (3, 6): + from ._next_gen import define, field, frozen, mutable # noqa: F401 + + __all__.extend(("define", "field", "frozen", "mutable")) diff --git a/openpype/vendor/python/python_2/attr/__init__.pyi b/openpype/vendor/python/python_2/attr/__init__.pyi new file mode 100644 index 0000000000..c0a2126503 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/__init__.pyi @@ -0,0 +1,484 @@ +import sys + +from typing import ( + Any, + Callable, + Dict, + Generic, + List, + Mapping, + Optional, + Sequence, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +# `import X as X` is required to make these public +from . import converters as converters +from . import exceptions as exceptions +from . import filters as filters +from . import setters as setters +from . import validators as validators +from ._version_info import VersionInfo + +__version__: str +__version_info__: VersionInfo +__title__: str +__description__: str +__url__: str +__uri__: str +__author__: str +__email__: str +__license__: str +__copyright__: str + +_T = TypeVar("_T") +_C = TypeVar("_C", bound=type) + +_EqOrderType = Union[bool, Callable[[Any], Any]] +_ValidatorType = Callable[[Any, Attribute[_T], _T], Any] +_ConverterType = Callable[[Any], Any] +_FilterType = Callable[[Attribute[_T], _T], bool] +_ReprType = Callable[[Any], str] +_ReprArgType = Union[bool, _ReprType] +_OnSetAttrType = Callable[[Any, Attribute[Any], Any], Any] +_OnSetAttrArgType = Union[ + _OnSetAttrType, List[_OnSetAttrType], setters._NoOpType +] +_FieldTransformer = Callable[ + [type, List[Attribute[Any]]], List[Attribute[Any]] +] +_CompareWithType = Callable[[Any, Any], bool] +# FIXME: in reality, if multiple validators are passed they must be in a list +# or tuple, but those are invariant and so would prevent subtypes of +# _ValidatorType from working when passed in a list or tuple. +_ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]] + +# _make -- + +NOTHING: object + +# NOTE: Factory lies about its return type to make this possible: +# `x: List[int] # = Factory(list)` +# Work around mypy issue #4554 in the common case by using an overload. +if sys.version_info >= (3, 8): + from typing import Literal + @overload + def Factory(factory: Callable[[], _T]) -> _T: ... + @overload + def Factory( + factory: Callable[[Any], _T], + takes_self: Literal[True], + ) -> _T: ... + @overload + def Factory( + factory: Callable[[], _T], + takes_self: Literal[False], + ) -> _T: ... + +else: + @overload + def Factory(factory: Callable[[], _T]) -> _T: ... + @overload + def Factory( + factory: Union[Callable[[Any], _T], Callable[[], _T]], + takes_self: bool = ..., + ) -> _T: ... + +# Static type inference support via __dataclass_transform__ implemented as per: +# https://github.com/microsoft/pyright/blob/1.1.135/specs/dataclass_transforms.md +# This annotation must be applied to all overloads of "define" and "attrs" +# +# NOTE: This is a typing construct and does not exist at runtime. Extensions +# wrapping attrs decorators should declare a separate __dataclass_transform__ +# signature in the extension module using the specification linked above to +# provide pyright support. +def __dataclass_transform__( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + field_descriptors: Tuple[Union[type, Callable[..., Any]], ...] = (()), +) -> Callable[[_T], _T]: ... + +class Attribute(Generic[_T]): + name: str + default: Optional[_T] + validator: Optional[_ValidatorType[_T]] + repr: _ReprArgType + cmp: _EqOrderType + eq: _EqOrderType + order: _EqOrderType + hash: Optional[bool] + init: bool + converter: Optional[_ConverterType] + metadata: Dict[Any, Any] + type: Optional[Type[_T]] + kw_only: bool + on_setattr: _OnSetAttrType + def evolve(self, **changes: Any) -> "Attribute[Any]": ... + +# NOTE: We had several choices for the annotation to use for type arg: +# 1) Type[_T] +# - Pros: Handles simple cases correctly +# - Cons: Might produce less informative errors in the case of conflicting +# TypeVars e.g. `attr.ib(default='bad', type=int)` +# 2) Callable[..., _T] +# - Pros: Better error messages than #1 for conflicting TypeVars +# - Cons: Terrible error messages for validator checks. +# e.g. attr.ib(type=int, validator=validate_str) +# -> error: Cannot infer function type argument +# 3) type (and do all of the work in the mypy plugin) +# - Pros: Simple here, and we could customize the plugin with our own errors. +# - Cons: Would need to write mypy plugin code to handle all the cases. +# We chose option #1. + +# `attr` lies about its return type to make the following possible: +# attr() -> Any +# attr(8) -> int +# attr(validator=) -> Whatever the callable expects. +# This makes this type of assignments possible: +# x: int = attr(8) +# +# This form catches explicit None or no default but with no other arguments +# returns Any. +@overload +def attrib( + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: None = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def attrib( + default: None = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: Optional[Type[_T]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def attrib( + default: _T, + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: Optional[Type[_T]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def attrib( + default: Optional[_T] = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: object = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> Any: ... +@overload +def field( + *, + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def field( + *, + default: None = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def field( + *, + default: _T, + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def field( + *, + default: Optional[_T] = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> Any: ... +@overload +@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field)) +def attrs( + maybe_cls: _C, + these: Optional[Dict[str, Any]] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field)) +def attrs( + maybe_cls: None = ..., + these: Optional[Dict[str, Any]] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... +@overload +@__dataclass_transform__(field_descriptors=(attrib, field)) +def define( + maybe_cls: _C, + *, + these: Optional[Dict[str, Any]] = ..., + repr: bool = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + auto_detect: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@__dataclass_transform__(field_descriptors=(attrib, field)) +def define( + maybe_cls: None = ..., + *, + these: Optional[Dict[str, Any]] = ..., + repr: bool = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + auto_detect: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... + +mutable = define +frozen = define # they differ only in their defaults + +# TODO: add support for returning NamedTuple from the mypy plugin +class _Fields(Tuple[Attribute[Any], ...]): + def __getattr__(self, name: str) -> Attribute[Any]: ... + +def fields(cls: type) -> _Fields: ... +def fields_dict(cls: type) -> Dict[str, Attribute[Any]]: ... +def validate(inst: Any) -> None: ... +def resolve_types( + cls: _C, + globalns: Optional[Dict[str, Any]] = ..., + localns: Optional[Dict[str, Any]] = ..., + attribs: Optional[List[Attribute[Any]]] = ..., +) -> _C: ... + +# TODO: add support for returning a proper attrs class from the mypy plugin +# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', +# [attr.ib()])` is valid +def make_class( + name: str, + attrs: Union[List[str], Tuple[str, ...], Dict[str, Any]], + bases: Tuple[type, ...] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + collect_by_mro: bool = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., +) -> type: ... + +# _funcs -- + +# TODO: add support for returning TypedDict from the mypy plugin +# FIXME: asdict/astuple do not honor their factory args. Waiting on one of +# these: +# https://github.com/python/mypy/issues/4236 +# https://github.com/python/typing/issues/253 +# XXX: remember to fix attrs.asdict/astuple too! +def asdict( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + dict_factory: Type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Optional[ + Callable[[type, Attribute[Any], Any], Any] + ] = ..., + tuple_keys: Optional[bool] = ..., +) -> Dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + tuple_factory: Type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> Tuple[Any, ...]: ... +def has(cls: type) -> bool: ... +def assoc(inst: _T, **changes: Any) -> _T: ... +def evolve(inst: _T, **changes: Any) -> _T: ... + +# _config -- + +def set_run_validators(run: bool) -> None: ... +def get_run_validators() -> bool: ... + +# aliases -- + +s = attributes = attrs +ib = attr = attrib +dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/openpype/vendor/python/python_2/attr/_cmp.py b/openpype/vendor/python/python_2/attr/_cmp.py new file mode 100644 index 0000000000..6cffa4dbab --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_cmp.py @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import functools + +from ._compat import new_class +from ._make import _make_ne + + +_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} + + +def cmp_using( + eq=None, + lt=None, + le=None, + gt=None, + ge=None, + require_same_type=True, + class_name="Comparable", +): + """ + Create a class that can be passed into `attr.ib`'s ``eq``, ``order``, and + ``cmp`` arguments to customize field comparison. + + The resulting class will have a full set of ordering methods if + at least one of ``{lt, le, gt, ge}`` and ``eq`` are provided. + + :param Optional[callable] eq: `callable` used to evaluate equality + of two objects. + :param Optional[callable] lt: `callable` used to evaluate whether + one object is less than another object. + :param Optional[callable] le: `callable` used to evaluate whether + one object is less than or equal to another object. + :param Optional[callable] gt: `callable` used to evaluate whether + one object is greater than another object. + :param Optional[callable] ge: `callable` used to evaluate whether + one object is greater than or equal to another object. + + :param bool require_same_type: When `True`, equality and ordering methods + will return `NotImplemented` if objects are not of the same type. + + :param Optional[str] class_name: Name of class. Defaults to 'Comparable'. + + See `comparison` for more details. + + .. versionadded:: 21.1.0 + """ + + body = { + "__slots__": ["value"], + "__init__": _make_init(), + "_requirements": [], + "_is_comparable_to": _is_comparable_to, + } + + # Add operations. + num_order_functions = 0 + has_eq_function = False + + if eq is not None: + has_eq_function = True + body["__eq__"] = _make_operator("eq", eq) + body["__ne__"] = _make_ne() + + if lt is not None: + num_order_functions += 1 + body["__lt__"] = _make_operator("lt", lt) + + if le is not None: + num_order_functions += 1 + body["__le__"] = _make_operator("le", le) + + if gt is not None: + num_order_functions += 1 + body["__gt__"] = _make_operator("gt", gt) + + if ge is not None: + num_order_functions += 1 + body["__ge__"] = _make_operator("ge", ge) + + type_ = new_class(class_name, (object,), {}, lambda ns: ns.update(body)) + + # Add same type requirement. + if require_same_type: + type_._requirements.append(_check_same_type) + + # Add total ordering if at least one operation was defined. + if 0 < num_order_functions < 4: + if not has_eq_function: + # functools.total_ordering requires __eq__ to be defined, + # so raise early error here to keep a nice stack. + raise ValueError( + "eq must be define is order to complete ordering from " + "lt, le, gt, ge." + ) + type_ = functools.total_ordering(type_) + + return type_ + + +def _make_init(): + """ + Create __init__ method. + """ + + def __init__(self, value): + """ + Initialize object with *value*. + """ + self.value = value + + return __init__ + + +def _make_operator(name, func): + """ + Create operator method. + """ + + def method(self, other): + if not self._is_comparable_to(other): + return NotImplemented + + result = func(self.value, other.value) + if result is NotImplemented: + return NotImplemented + + return result + + method.__name__ = "__%s__" % (name,) + method.__doc__ = "Return a %s b. Computed by attrs." % ( + _operation_names[name], + ) + + return method + + +def _is_comparable_to(self, other): + """ + Check whether `other` is comparable to `self`. + """ + for func in self._requirements: + if not func(self, other): + return False + return True + + +def _check_same_type(self, other): + """ + Return True if *self* and *other* are of the same type, False otherwise. + """ + return other.value.__class__ is self.value.__class__ diff --git a/openpype/vendor/python/python_2/attr/_cmp.pyi b/openpype/vendor/python/python_2/attr/_cmp.pyi new file mode 100644 index 0000000000..e71aaff7a1 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_cmp.pyi @@ -0,0 +1,13 @@ +from typing import Type + +from . import _CompareWithType + +def cmp_using( + eq: Optional[_CompareWithType], + lt: Optional[_CompareWithType], + le: Optional[_CompareWithType], + gt: Optional[_CompareWithType], + ge: Optional[_CompareWithType], + require_same_type: bool, + class_name: str, +) -> Type: ... diff --git a/openpype/vendor/python/python_2/attr/_compat.py b/openpype/vendor/python/python_2/attr/_compat.py new file mode 100644 index 0000000000..dc0cb02b64 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_compat.py @@ -0,0 +1,261 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import platform +import sys +import threading +import types +import warnings + + +PY2 = sys.version_info[0] == 2 +PYPY = platform.python_implementation() == "PyPy" +PY36 = sys.version_info[:2] >= (3, 6) +HAS_F_STRINGS = PY36 +PY310 = sys.version_info[:2] >= (3, 10) + + +if PYPY or PY36: + ordered_dict = dict +else: + from collections import OrderedDict + + ordered_dict = OrderedDict + + +if PY2: + from collections import Mapping, Sequence + + from UserDict import IterableUserDict + + # We 'bundle' isclass instead of using inspect as importing inspect is + # fairly expensive (order of 10-15 ms for a modern machine in 2016) + def isclass(klass): + return isinstance(klass, (type, types.ClassType)) + + def new_class(name, bases, kwds, exec_body): + """ + A minimal stub of types.new_class that we need for make_class. + """ + ns = {} + exec_body(ns) + + return type(name, bases, ns) + + # TYPE is used in exceptions, repr(int) is different on Python 2 and 3. + TYPE = "type" + + def iteritems(d): + return d.iteritems() + + # Python 2 is bereft of a read-only dict proxy, so we make one! + class ReadOnlyDict(IterableUserDict): + """ + Best-effort read-only dict wrapper. + """ + + def __setitem__(self, key, val): + # We gently pretend we're a Python 3 mappingproxy. + raise TypeError( + "'mappingproxy' object does not support item assignment" + ) + + def update(self, _): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'update'" + ) + + def __delitem__(self, _): + # We gently pretend we're a Python 3 mappingproxy. + raise TypeError( + "'mappingproxy' object does not support item deletion" + ) + + def clear(self): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'clear'" + ) + + def pop(self, key, default=None): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'pop'" + ) + + def popitem(self): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'popitem'" + ) + + def setdefault(self, key, default=None): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'setdefault'" + ) + + def __repr__(self): + # Override to be identical to the Python 3 version. + return "mappingproxy(" + repr(self.data) + ")" + + def metadata_proxy(d): + res = ReadOnlyDict() + res.data.update(d) # We blocked update, so we have to do it like this. + return res + + def just_warn(*args, **kw): # pragma: no cover + """ + We only warn on Python 3 because we are not aware of any concrete + consequences of not setting the cell on Python 2. + """ + +else: # Python 3 and later. + from collections.abc import Mapping, Sequence # noqa + + def just_warn(*args, **kw): + """ + We only warn on Python 3 because we are not aware of any concrete + consequences of not setting the cell on Python 2. + """ + warnings.warn( + "Running interpreter doesn't sufficiently support code object " + "introspection. Some features like bare super() or accessing " + "__class__ will not work with slotted classes.", + RuntimeWarning, + stacklevel=2, + ) + + def isclass(klass): + return isinstance(klass, type) + + TYPE = "class" + + def iteritems(d): + return d.items() + + new_class = types.new_class + + def metadata_proxy(d): + return types.MappingProxyType(dict(d)) + + +def make_set_closure_cell(): + """Return a function of two arguments (cell, value) which sets + the value stored in the closure cell `cell` to `value`. + """ + # pypy makes this easy. (It also supports the logic below, but + # why not do the easy/fast thing?) + if PYPY: + + def set_closure_cell(cell, value): + cell.__setstate__((value,)) + + return set_closure_cell + + # Otherwise gotta do it the hard way. + + # Create a function that will set its first cellvar to `value`. + def set_first_cellvar_to(value): + x = value + return + + # This function will be eliminated as dead code, but + # not before its reference to `x` forces `x` to be + # represented as a closure cell rather than a local. + def force_x_to_be_a_cell(): # pragma: no cover + return x + + try: + # Extract the code object and make sure our assumptions about + # the closure behavior are correct. + if PY2: + co = set_first_cellvar_to.func_code + else: + co = set_first_cellvar_to.__code__ + if co.co_cellvars != ("x",) or co.co_freevars != (): + raise AssertionError # pragma: no cover + + # Convert this code object to a code object that sets the + # function's first _freevar_ (not cellvar) to the argument. + if sys.version_info >= (3, 8): + # CPython 3.8+ has an incompatible CodeType signature + # (added a posonlyargcount argument) but also added + # CodeType.replace() to do this without counting parameters. + set_first_freevar_code = co.replace( + co_cellvars=co.co_freevars, co_freevars=co.co_cellvars + ) + else: + args = [co.co_argcount] + if not PY2: + args.append(co.co_kwonlyargcount) + args.extend( + [ + co.co_nlocals, + co.co_stacksize, + co.co_flags, + co.co_code, + co.co_consts, + co.co_names, + co.co_varnames, + co.co_filename, + co.co_name, + co.co_firstlineno, + co.co_lnotab, + # These two arguments are reversed: + co.co_cellvars, + co.co_freevars, + ] + ) + set_first_freevar_code = types.CodeType(*args) + + def set_closure_cell(cell, value): + # Create a function using the set_first_freevar_code, + # whose first closure cell is `cell`. Calling it will + # change the value of that cell. + setter = types.FunctionType( + set_first_freevar_code, {}, "setter", (), (cell,) + ) + # And call it to set the cell. + setter(value) + + # Make sure it works on this interpreter: + def make_func_with_cell(): + x = None + + def func(): + return x # pragma: no cover + + return func + + if PY2: + cell = make_func_with_cell().func_closure[0] + else: + cell = make_func_with_cell().__closure__[0] + set_closure_cell(cell, 100) + if cell.cell_contents != 100: + raise AssertionError # pragma: no cover + + except Exception: + return just_warn + else: + return set_closure_cell + + +set_closure_cell = make_set_closure_cell() + +# Thread-local global to track attrs instances which are already being repr'd. +# This is needed because there is no other (thread-safe) way to pass info +# about the instances that are already being repr'd through the call stack +# in order to ensure we don't perform infinite recursion. +# +# For instance, if an instance contains a dict which contains that instance, +# we need to know that we're already repr'ing the outside instance from within +# the dict's repr() call. +# +# This lives here rather than in _make.py so that the functions in _make.py +# don't have a direct reference to the thread-local in their globals dict. +# If they have such a reference, it breaks cloudpickle. +repr_context = threading.local() diff --git a/openpype/vendor/python/python_2/attr/_config.py b/openpype/vendor/python/python_2/attr/_config.py new file mode 100644 index 0000000000..fc9be29d00 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_config.py @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +__all__ = ["set_run_validators", "get_run_validators"] + +_run_validators = True + + +def set_run_validators(run): + """ + Set whether or not validators are run. By default, they are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` + instead. + """ + if not isinstance(run, bool): + raise TypeError("'run' must be bool.") + global _run_validators + _run_validators = run + + +def get_run_validators(): + """ + Return whether or not validators are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` + instead. + """ + return _run_validators diff --git a/openpype/vendor/python/python_2/attr/_funcs.py b/openpype/vendor/python/python_2/attr/_funcs.py new file mode 100644 index 0000000000..4c90085a40 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_funcs.py @@ -0,0 +1,422 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import copy + +from ._compat import iteritems +from ._make import NOTHING, _obj_setattr, fields +from .exceptions import AttrsAttributeNotFoundError + + +def asdict( + inst, + recurse=True, + filter=None, + dict_factory=dict, + retain_collection_types=False, + value_serializer=None, +): + """ + Return the ``attrs`` attribute values of *inst* as a dict. + + Optionally recurse into other ``attrs``-decorated classes. + + :param inst: Instance of an ``attrs``-decorated class. + :param bool recurse: Recurse into classes that are also + ``attrs``-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is + called with the `attrs.Attribute` as the first argument and the + value as the second argument. + :param callable dict_factory: A callable to produce dictionaries from. For + example, to produce ordered dictionaries instead of normal Python + dictionaries, pass in ``collections.OrderedDict``. + :param bool retain_collection_types: Do not convert to ``list`` when + encountering an attribute whose type is ``tuple`` or ``set``. Only + meaningful if ``recurse`` is ``True``. + :param Optional[callable] value_serializer: A hook that is called for every + attribute or dict key/value. It receives the current instance, field + and value and must return the (updated) value. The hook is run *after* + the optional *filter* has been applied. + + :rtype: return type of *dict_factory* + + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 16.0.0 *dict_factory* + .. versionadded:: 16.1.0 *retain_collection_types* + .. versionadded:: 20.3.0 *value_serializer* + .. versionadded:: 21.3.0 If a dict has a collection for a key, it is + serialized as a tuple. + """ + attrs = fields(inst.__class__) + rv = dict_factory() + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + + if value_serializer is not None: + v = value_serializer(inst, a, v) + + if recurse is True: + if has(v.__class__): + rv[a.name] = asdict( + v, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif isinstance(v, (tuple, list, set, frozenset)): + cf = v.__class__ if retain_collection_types is True else list + rv[a.name] = cf( + [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in v + ] + ) + elif isinstance(v, dict): + df = dict_factory + rv[a.name] = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in iteritems(v) + ) + else: + rv[a.name] = v + else: + rv[a.name] = v + return rv + + +def _asdict_anything( + val, + is_key, + filter, + dict_factory, + retain_collection_types, + value_serializer, +): + """ + ``asdict`` only works on attrs instances, this works on anything. + """ + if getattr(val.__class__, "__attrs_attrs__", None) is not None: + # Attrs class. + rv = asdict( + val, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif isinstance(val, (tuple, list, set, frozenset)): + if retain_collection_types is True: + cf = val.__class__ + elif is_key: + cf = tuple + else: + cf = list + + rv = cf( + [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in val + ] + ) + elif isinstance(val, dict): + df = dict_factory + rv = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in iteritems(val) + ) + else: + rv = val + if value_serializer is not None: + rv = value_serializer(None, None, rv) + + return rv + + +def astuple( + inst, + recurse=True, + filter=None, + tuple_factory=tuple, + retain_collection_types=False, +): + """ + Return the ``attrs`` attribute values of *inst* as a tuple. + + Optionally recurse into other ``attrs``-decorated classes. + + :param inst: Instance of an ``attrs``-decorated class. + :param bool recurse: Recurse into classes that are also + ``attrs``-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is + called with the `attrs.Attribute` as the first argument and the + value as the second argument. + :param callable tuple_factory: A callable to produce tuples from. For + example, to produce lists instead of tuples. + :param bool retain_collection_types: Do not convert to ``list`` + or ``dict`` when encountering an attribute which type is + ``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is + ``True``. + + :rtype: return type of *tuple_factory* + + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 16.2.0 + """ + attrs = fields(inst.__class__) + rv = [] + retain = retain_collection_types # Very long. :/ + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + if recurse is True: + if has(v.__class__): + rv.append( + astuple( + v, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + ) + elif isinstance(v, (tuple, list, set, frozenset)): + cf = v.__class__ if retain is True else list + rv.append( + cf( + [ + astuple( + j, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(j.__class__) + else j + for j in v + ] + ) + ) + elif isinstance(v, dict): + df = v.__class__ if retain is True else dict + rv.append( + df( + ( + astuple( + kk, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(kk.__class__) + else kk, + astuple( + vv, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(vv.__class__) + else vv, + ) + for kk, vv in iteritems(v) + ) + ) + else: + rv.append(v) + else: + rv.append(v) + + return rv if tuple_factory is list else tuple_factory(rv) + + +def has(cls): + """ + Check whether *cls* is a class with ``attrs`` attributes. + + :param type cls: Class to introspect. + :raise TypeError: If *cls* is not a class. + + :rtype: bool + """ + return getattr(cls, "__attrs_attrs__", None) is not None + + +def assoc(inst, **changes): + """ + Copy *inst* and apply *changes*. + + :param inst: Instance of a class with ``attrs`` attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise attr.exceptions.AttrsAttributeNotFoundError: If *attr_name* couldn't + be found on *cls*. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. deprecated:: 17.1.0 + Use `attrs.evolve` instead if you can. + This function will not be removed du to the slightly different approach + compared to `attrs.evolve`. + """ + import warnings + + warnings.warn( + "assoc is deprecated and will be removed after 2018/01.", + DeprecationWarning, + stacklevel=2, + ) + new = copy.copy(inst) + attrs = fields(inst.__class__) + for k, v in iteritems(changes): + a = getattr(attrs, k, NOTHING) + if a is NOTHING: + raise AttrsAttributeNotFoundError( + "{k} is not an attrs attribute on {cl}.".format( + k=k, cl=new.__class__ + ) + ) + _obj_setattr(new, k, v) + return new + + +def evolve(inst, **changes): + """ + Create a new instance, based on *inst* with *changes* applied. + + :param inst: Instance of a class with ``attrs`` attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise TypeError: If *attr_name* couldn't be found in the class + ``__init__``. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 17.1.0 + """ + cls = inst.__class__ + attrs = fields(cls) + for a in attrs: + if not a.init: + continue + attr_name = a.name # To deal with private attributes. + init_name = attr_name if attr_name[0] != "_" else attr_name[1:] + if init_name not in changes: + changes[init_name] = getattr(inst, attr_name) + + return cls(**changes) + + +def resolve_types(cls, globalns=None, localns=None, attribs=None): + """ + Resolve any strings and forward annotations in type annotations. + + This is only required if you need concrete types in `Attribute`'s *type* + field. In other words, you don't need to resolve your types if you only + use them for static type checking. + + With no arguments, names will be looked up in the module in which the class + was created. If this is not what you want, e.g. if the name only exists + inside a method, you may pass *globalns* or *localns* to specify other + dictionaries in which to look up these names. See the docs of + `typing.get_type_hints` for more details. + + :param type cls: Class to resolve. + :param Optional[dict] globalns: Dictionary containing global variables. + :param Optional[dict] localns: Dictionary containing local variables. + :param Optional[list] attribs: List of attribs for the given class. + This is necessary when calling from inside a ``field_transformer`` + since *cls* is not an ``attrs`` class yet. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class and you didn't pass any attribs. + :raise NameError: If types cannot be resolved because of missing variables. + + :returns: *cls* so you can use this function also as a class decorator. + Please note that you have to apply it **after** `attrs.define`. That + means the decorator has to come in the line **before** `attrs.define`. + + .. versionadded:: 20.1.0 + .. versionadded:: 21.1.0 *attribs* + + """ + # Since calling get_type_hints is expensive we cache whether we've + # done it already. + if getattr(cls, "__attrs_types_resolved__", None) != cls: + import typing + + hints = typing.get_type_hints(cls, globalns=globalns, localns=localns) + for field in fields(cls) if attribs is None else attribs: + if field.name in hints: + # Since fields have been frozen we must work around it. + _obj_setattr(field, "type", hints[field.name]) + # We store the class we resolved so that subclasses know they haven't + # been resolved. + cls.__attrs_types_resolved__ = cls + + # Return the class so you can use it as a decorator too. + return cls diff --git a/openpype/vendor/python/python_2/attr/_make.py b/openpype/vendor/python/python_2/attr/_make.py new file mode 100644 index 0000000000..d46f8a3e7a --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_make.py @@ -0,0 +1,3173 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import copy +import inspect +import linecache +import sys +import warnings + +from operator import itemgetter + +# We need to import _compat itself in addition to the _compat members to avoid +# having the thread-local in the globals here. +from . import _compat, _config, setters +from ._compat import ( + HAS_F_STRINGS, + PY2, + PY310, + PYPY, + isclass, + iteritems, + metadata_proxy, + new_class, + ordered_dict, + set_closure_cell, +) +from .exceptions import ( + DefaultAlreadySetError, + FrozenInstanceError, + NotAnAttrsClassError, + PythonTooOldError, + UnannotatedAttributeError, +) + + +if not PY2: + import typing + + +# This is used at least twice, so cache it here. +_obj_setattr = object.__setattr__ +_init_converter_pat = "__attr_converter_%s" +_init_factory_pat = "__attr_factory_{}" +_tuple_property_pat = ( + " {attr_name} = _attrs_property(_attrs_itemgetter({index}))" +) +_classvar_prefixes = ( + "typing.ClassVar", + "t.ClassVar", + "ClassVar", + "typing_extensions.ClassVar", +) +# we don't use a double-underscore prefix because that triggers +# name mangling when trying to create a slot for the field +# (when slots=True) +_hash_cache_field = "_attrs_cached_hash" + +_empty_metadata_singleton = metadata_proxy({}) + +# Unique object for unequivocal getattr() defaults. +_sentinel = object() + +_ng_default_on_setattr = setters.pipe(setters.convert, setters.validate) + + +class _Nothing(object): + """ + Sentinel class to indicate the lack of a value when ``None`` is ambiguous. + + ``_Nothing`` is a singleton. There is only ever one of it. + + .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. + """ + + _singleton = None + + def __new__(cls): + if _Nothing._singleton is None: + _Nothing._singleton = super(_Nothing, cls).__new__(cls) + return _Nothing._singleton + + def __repr__(self): + return "NOTHING" + + def __bool__(self): + return False + + def __len__(self): + return 0 # __bool__ for Python 2 + + +NOTHING = _Nothing() +""" +Sentinel to indicate the lack of a value when ``None`` is ambiguous. +""" + + +class _CacheHashWrapper(int): + """ + An integer subclass that pickles / copies as None + + This is used for non-slots classes with ``cache_hash=True``, to avoid + serializing a potentially (even likely) invalid hash value. Since ``None`` + is the default value for uncalculated hashes, whenever this is copied, + the copy's value for the hash should automatically reset. + + See GH #613 for more details. + """ + + if PY2: + # For some reason `type(None)` isn't callable in Python 2, but we don't + # actually need a constructor for None objects, we just need any + # available function that returns None. + def __reduce__(self, _none_constructor=getattr, _args=(0, "", None)): + return _none_constructor, _args + + else: + + def __reduce__(self, _none_constructor=type(None), _args=()): + return _none_constructor, _args + + +def attrib( + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=None, + init=True, + metadata=None, + type=None, + converter=None, + factory=None, + kw_only=False, + eq=None, + order=None, + on_setattr=None, +): + """ + Create a new attribute on a class. + + .. warning:: + + Does *not* do anything unless the class is also decorated with + `attr.s`! + + :param default: A value that is used if an ``attrs``-generated ``__init__`` + is used and no value is passed while instantiating or the attribute is + excluded using ``init=False``. + + If the value is an instance of `attrs.Factory`, its callable will be + used to construct a new value (useful for mutable data types like lists + or dicts). + + If a default is not set (or set manually to `attrs.NOTHING`), a value + *must* be supplied when instantiating; otherwise a `TypeError` + will be raised. + + The default can also be set using decorator notation as shown below. + + :type default: Any value + + :param callable factory: Syntactic sugar for + ``default=attr.Factory(factory)``. + + :param validator: `callable` that is called by ``attrs``-generated + ``__init__`` methods after the instance has been initialized. They + receive the initialized instance, the :func:`~attrs.Attribute`, and the + passed value. + + The return value is *not* inspected so the validator has to throw an + exception itself. + + If a `list` is passed, its items are treated as validators and must + all pass. + + Validators can be globally disabled and re-enabled using + `get_run_validators`. + + The validator can also be set using decorator notation as shown below. + + :type validator: `callable` or a `list` of `callable`\\ s. + + :param repr: Include this attribute in the generated ``__repr__`` + method. If ``True``, include the attribute; if ``False``, omit it. By + default, the built-in ``repr()`` function is used. To override how the + attribute value is formatted, pass a ``callable`` that takes a single + value and returns a string. Note that the resulting string is used + as-is, i.e. it will be used directly *instead* of calling ``repr()`` + (the default). + :type repr: a `bool` or a `callable` to use a custom function. + + :param eq: If ``True`` (default), include this attribute in the + generated ``__eq__`` and ``__ne__`` methods that check two instances + for equality. To override how the attribute value is compared, + pass a ``callable`` that takes a single value and returns the value + to be compared. + :type eq: a `bool` or a `callable`. + + :param order: If ``True`` (default), include this attributes in the + generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. + To override how the attribute value is ordered, + pass a ``callable`` that takes a single value and returns the value + to be ordered. + :type order: a `bool` or a `callable`. + + :param cmp: Setting *cmp* is equivalent to setting *eq* and *order* to the + same value. Must not be mixed with *eq* or *order*. + :type cmp: a `bool` or a `callable`. + + :param Optional[bool] hash: Include this attribute in the generated + ``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This + is the correct behavior according the Python spec. Setting this value + to anything else than ``None`` is *discouraged*. + :param bool init: Include this attribute in the generated ``__init__`` + method. It is possible to set this to ``False`` and set a default + value. In that case this attributed is unconditionally initialized + with the specified default value or factory. + :param callable converter: `callable` that is called by + ``attrs``-generated ``__init__`` methods to convert attribute's value + to the desired format. It is given the passed-in value, and the + returned value will be used as the new value of the attribute. The + value is converted before being passed to the validator, if any. + :param metadata: An arbitrary mapping, to be used by third-party + components. See `extending_metadata`. + :param type: The type of the attribute. In Python 3.6 or greater, the + preferred method to specify the type is using a variable annotation + (see `PEP 526 `_). + This argument is provided for backward compatibility. + Regardless of the approach used, the type will be stored on + ``Attribute.type``. + + Please note that ``attrs`` doesn't do anything with this metadata by + itself. You can use it as part of your own code or for + `static type checking `. + :param kw_only: Make this attribute keyword-only (Python 3+) + in the generated ``__init__`` (if ``init`` is ``False``, this + parameter is ignored). + :param on_setattr: Allows to overwrite the *on_setattr* setting from + `attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used. + Set to `attrs.setters.NO_OP` to run **no** `setattr` hooks for this + attribute -- regardless of the setting in `attr.s`. + :type on_setattr: `callable`, or a list of callables, or `None`, or + `attrs.setters.NO_OP` + + .. versionadded:: 15.2.0 *convert* + .. versionadded:: 16.3.0 *metadata* + .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. + .. versionchanged:: 17.1.0 + *hash* is ``None`` and therefore mirrors *eq* by default. + .. versionadded:: 17.3.0 *type* + .. deprecated:: 17.4.0 *convert* + .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated + *convert* to achieve consistency with other noun-based arguments. + .. versionadded:: 18.1.0 + ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. + .. versionadded:: 18.2.0 *kw_only* + .. versionchanged:: 19.2.0 *convert* keyword argument removed. + .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 + .. versionchanged:: 21.1.0 + *eq*, *order*, and *cmp* also accept a custom callable + .. versionchanged:: 21.1.0 *cmp* undeprecated + """ + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq, order, True + ) + + if hash is not None and hash is not True and hash is not False: + raise TypeError( + "Invalid value for hash. Must be True, False, or None." + ) + + if factory is not None: + if default is not NOTHING: + raise ValueError( + "The `default` and `factory` arguments are mutually " + "exclusive." + ) + if not callable(factory): + raise ValueError("The `factory` argument must be a callable.") + default = Factory(factory) + + if metadata is None: + metadata = {} + + # Apply syntactic sugar by auto-wrapping. + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + if validator and isinstance(validator, (list, tuple)): + validator = and_(*validator) + + if converter and isinstance(converter, (list, tuple)): + converter = pipe(*converter) + + return _CountingAttr( + default=default, + validator=validator, + repr=repr, + cmp=None, + hash=hash, + init=init, + converter=converter, + metadata=metadata, + type=type, + kw_only=kw_only, + eq=eq, + eq_key=eq_key, + order=order, + order_key=order_key, + on_setattr=on_setattr, + ) + + +def _compile_and_eval(script, globs, locs=None, filename=""): + """ + "Exec" the script with the given global (globs) and local (locs) variables. + """ + bytecode = compile(script, filename, "exec") + eval(bytecode, globs, locs) + + +def _make_method(name, script, filename, globs=None): + """ + Create the method with the script given and return the method object. + """ + locs = {} + if globs is None: + globs = {} + + # In order of debuggers like PDB being able to step through the code, + # we add a fake linecache entry. + count = 1 + base_filename = filename + while True: + linecache_tuple = ( + len(script), + None, + script.splitlines(True), + filename, + ) + old_val = linecache.cache.setdefault(filename, linecache_tuple) + if old_val == linecache_tuple: + break + else: + filename = "{}-{}>".format(base_filename[:-1], count) + count += 1 + + _compile_and_eval(script, globs, locs, filename) + + return locs[name] + + +def _make_attr_tuple_class(cls_name, attr_names): + """ + Create a tuple subclass to hold `Attribute`s for an `attrs` class. + + The subclass is a bare tuple with properties for names. + + class MyClassAttributes(tuple): + __slots__ = () + x = property(itemgetter(0)) + """ + attr_class_name = "{}Attributes".format(cls_name) + attr_class_template = [ + "class {}(tuple):".format(attr_class_name), + " __slots__ = ()", + ] + if attr_names: + for i, attr_name in enumerate(attr_names): + attr_class_template.append( + _tuple_property_pat.format(index=i, attr_name=attr_name) + ) + else: + attr_class_template.append(" pass") + globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property} + _compile_and_eval("\n".join(attr_class_template), globs) + return globs[attr_class_name] + + +# Tuple class for extracted attributes from a class definition. +# `base_attrs` is a subset of `attrs`. +_Attributes = _make_attr_tuple_class( + "_Attributes", + [ + # all attributes to build dunder methods for + "attrs", + # attributes that have been inherited + "base_attrs", + # map inherited attributes to their originating classes + "base_attrs_map", + ], +) + + +def _is_class_var(annot): + """ + Check whether *annot* is a typing.ClassVar. + + The string comparison hack is used to avoid evaluating all string + annotations which would put attrs-based classes at a performance + disadvantage compared to plain old classes. + """ + annot = str(annot) + + # Annotation can be quoted. + if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): + annot = annot[1:-1] + + return annot.startswith(_classvar_prefixes) + + +def _has_own_attribute(cls, attrib_name): + """ + Check whether *cls* defines *attrib_name* (and doesn't just inherit it). + + Requires Python 3. + """ + attr = getattr(cls, attrib_name, _sentinel) + if attr is _sentinel: + return False + + for base_cls in cls.__mro__[1:]: + a = getattr(base_cls, attrib_name, None) + if attr is a: + return False + + return True + + +def _get_annotations(cls): + """ + Get annotations for *cls*. + """ + if _has_own_attribute(cls, "__annotations__"): + return cls.__annotations__ + + return {} + + +def _counter_getter(e): + """ + Key function for sorting to avoid re-creating a lambda for every class. + """ + return e[1].counter + + +def _collect_base_attrs(cls, taken_attr_names): + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in reversed(cls.__mro__[1:-1]): + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.inherited or a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + # For each name, only keep the freshest definition i.e. the furthest at the + # back. base_attr_map is fine because it gets overwritten with every new + # instance. + filtered = [] + seen = set() + for a in reversed(base_attrs): + if a.name in seen: + continue + filtered.insert(0, a) + seen.add(a.name) + + return filtered, base_attr_map + + +def _collect_base_attrs_broken(cls, taken_attr_names): + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + + N.B. *taken_attr_names* will be mutated. + + Adhere to the old incorrect behavior. + + Notably it collects from the front and considers inherited attributes which + leads to the buggy behavior reported in #428. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in cls.__mro__[1:-1]: + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) + taken_attr_names.add(a.name) + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + return base_attrs, base_attr_map + + +def _transform_attrs( + cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer +): + """ + Transform all `_CountingAttr`s on a class into `Attribute`s. + + If *these* is passed, use that and don't look for them on the class. + + *collect_by_mro* is True, collect them in the correct MRO order, otherwise + use the old -- incorrect -- order. See #428. + + Return an `_Attributes`. + """ + cd = cls.__dict__ + anns = _get_annotations(cls) + + if these is not None: + ca_list = [(name, ca) for name, ca in iteritems(these)] + + if not isinstance(these, ordered_dict): + ca_list.sort(key=_counter_getter) + elif auto_attribs is True: + ca_names = { + name + for name, attr in cd.items() + if isinstance(attr, _CountingAttr) + } + ca_list = [] + annot_names = set() + for attr_name, type in anns.items(): + if _is_class_var(type): + continue + annot_names.add(attr_name) + a = cd.get(attr_name, NOTHING) + + if not isinstance(a, _CountingAttr): + if a is NOTHING: + a = attrib() + else: + a = attrib(default=a) + ca_list.append((attr_name, a)) + + unannotated = ca_names - annot_names + if len(unannotated) > 0: + raise UnannotatedAttributeError( + "The following `attr.ib`s lack a type annotation: " + + ", ".join( + sorted(unannotated, key=lambda n: cd.get(n).counter) + ) + + "." + ) + else: + ca_list = sorted( + ( + (name, attr) + for name, attr in cd.items() + if isinstance(attr, _CountingAttr) + ), + key=lambda e: e[1].counter, + ) + + own_attrs = [ + Attribute.from_counting_attr( + name=attr_name, ca=ca, type=anns.get(attr_name) + ) + for attr_name, ca in ca_list + ] + + if collect_by_mro: + base_attrs, base_attr_map = _collect_base_attrs( + cls, {a.name for a in own_attrs} + ) + else: + base_attrs, base_attr_map = _collect_base_attrs_broken( + cls, {a.name for a in own_attrs} + ) + + if kw_only: + own_attrs = [a.evolve(kw_only=True) for a in own_attrs] + base_attrs = [a.evolve(kw_only=True) for a in base_attrs] + + attrs = base_attrs + own_attrs + + # Mandatory vs non-mandatory attr order only matters when they are part of + # the __init__ signature and when they aren't kw_only (which are moved to + # the end and can be mandatory or non-mandatory in any order, as they will + # be specified as keyword args anyway). Check the order of those attrs: + had_default = False + for a in (a for a in attrs if a.init is not False and a.kw_only is False): + if had_default is True and a.default is NOTHING: + raise ValueError( + "No mandatory attributes allowed after an attribute with a " + "default value or factory. Attribute in question: %r" % (a,) + ) + + if had_default is False and a.default is not NOTHING: + had_default = True + + if field_transformer is not None: + attrs = field_transformer(cls, attrs) + + # Create AttrsClass *after* applying the field_transformer since it may + # add or remove attributes! + attr_names = [a.name for a in attrs] + AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) + + return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map)) + + +if PYPY: + + def _frozen_setattrs(self, name, value): + """ + Attached to frozen classes as __setattr__. + """ + if isinstance(self, BaseException) and name in ( + "__cause__", + "__context__", + ): + BaseException.__setattr__(self, name, value) + return + + raise FrozenInstanceError() + +else: + + def _frozen_setattrs(self, name, value): + """ + Attached to frozen classes as __setattr__. + """ + raise FrozenInstanceError() + + +def _frozen_delattrs(self, name): + """ + Attached to frozen classes as __delattr__. + """ + raise FrozenInstanceError() + + +class _ClassBuilder(object): + """ + Iteratively build *one* class. + """ + + __slots__ = ( + "_attr_names", + "_attrs", + "_base_attr_map", + "_base_names", + "_cache_hash", + "_cls", + "_cls_dict", + "_delete_attribs", + "_frozen", + "_has_pre_init", + "_has_post_init", + "_is_exc", + "_on_setattr", + "_slots", + "_weakref_slot", + "_wrote_own_setattr", + "_has_custom_setattr", + ) + + def __init__( + self, + cls, + these, + slots, + frozen, + weakref_slot, + getstate_setstate, + auto_attribs, + kw_only, + cache_hash, + is_exc, + collect_by_mro, + on_setattr, + has_custom_setattr, + field_transformer, + ): + attrs, base_attrs, base_map = _transform_attrs( + cls, + these, + auto_attribs, + kw_only, + collect_by_mro, + field_transformer, + ) + + self._cls = cls + self._cls_dict = dict(cls.__dict__) if slots else {} + self._attrs = attrs + self._base_names = set(a.name for a in base_attrs) + self._base_attr_map = base_map + self._attr_names = tuple(a.name for a in attrs) + self._slots = slots + self._frozen = frozen + self._weakref_slot = weakref_slot + self._cache_hash = cache_hash + self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) + self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) + self._delete_attribs = not bool(these) + self._is_exc = is_exc + self._on_setattr = on_setattr + + self._has_custom_setattr = has_custom_setattr + self._wrote_own_setattr = False + + self._cls_dict["__attrs_attrs__"] = self._attrs + + if frozen: + self._cls_dict["__setattr__"] = _frozen_setattrs + self._cls_dict["__delattr__"] = _frozen_delattrs + + self._wrote_own_setattr = True + elif on_setattr in ( + _ng_default_on_setattr, + setters.validate, + setters.convert, + ): + has_validator = has_converter = False + for a in attrs: + if a.validator is not None: + has_validator = True + if a.converter is not None: + has_converter = True + + if has_validator and has_converter: + break + if ( + ( + on_setattr == _ng_default_on_setattr + and not (has_validator or has_converter) + ) + or (on_setattr == setters.validate and not has_validator) + or (on_setattr == setters.convert and not has_converter) + ): + # If class-level on_setattr is set to convert + validate, but + # there's no field to convert or validate, pretend like there's + # no on_setattr. + self._on_setattr = None + + if getstate_setstate: + ( + self._cls_dict["__getstate__"], + self._cls_dict["__setstate__"], + ) = self._make_getstate_setstate() + + def __repr__(self): + return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__) + + def build_class(self): + """ + Finalize class based on the accumulated configuration. + + Builder cannot be used after calling this method. + """ + if self._slots is True: + return self._create_slots_class() + else: + return self._patch_original_class() + + def _patch_original_class(self): + """ + Apply accumulated methods and return the class. + """ + cls = self._cls + base_names = self._base_names + + # Clean class of attribute definitions (`attr.ib()`s). + if self._delete_attribs: + for name in self._attr_names: + if ( + name not in base_names + and getattr(cls, name, _sentinel) is not _sentinel + ): + try: + delattr(cls, name) + except AttributeError: + # This can happen if a base class defines a class + # variable and we want to set an attribute with the + # same name by using only a type annotation. + pass + + # Attach our dunder methods. + for name, value in self._cls_dict.items(): + setattr(cls, name, value) + + # If we've inherited an attrs __setattr__ and don't write our own, + # reset it to object's. + if not self._wrote_own_setattr and getattr( + cls, "__attrs_own_setattr__", False + ): + cls.__attrs_own_setattr__ = False + + if not self._has_custom_setattr: + cls.__setattr__ = object.__setattr__ + + return cls + + def _create_slots_class(self): + """ + Build and return a new class with a `__slots__` attribute. + """ + cd = { + k: v + for k, v in iteritems(self._cls_dict) + if k not in tuple(self._attr_names) + ("__dict__", "__weakref__") + } + + # If our class doesn't have its own implementation of __setattr__ + # (either from the user or by us), check the bases, if one of them has + # an attrs-made __setattr__, that needs to be reset. We don't walk the + # MRO because we only care about our immediate base classes. + # XXX: This can be confused by subclassing a slotted attrs class with + # XXX: a non-attrs class and subclass the resulting class with an attrs + # XXX: class. See `test_slotted_confused` for details. For now that's + # XXX: OK with us. + if not self._wrote_own_setattr: + cd["__attrs_own_setattr__"] = False + + if not self._has_custom_setattr: + for base_cls in self._cls.__bases__: + if base_cls.__dict__.get("__attrs_own_setattr__", False): + cd["__setattr__"] = object.__setattr__ + break + + # Traverse the MRO to collect existing slots + # and check for an existing __weakref__. + existing_slots = dict() + weakref_inherited = False + for base_cls in self._cls.__mro__[1:-1]: + if base_cls.__dict__.get("__weakref__", None) is not None: + weakref_inherited = True + existing_slots.update( + { + name: getattr(base_cls, name) + for name in getattr(base_cls, "__slots__", []) + } + ) + + base_names = set(self._base_names) + + names = self._attr_names + if ( + self._weakref_slot + and "__weakref__" not in getattr(self._cls, "__slots__", ()) + and "__weakref__" not in names + and not weakref_inherited + ): + names += ("__weakref__",) + + # We only add the names of attributes that aren't inherited. + # Setting __slots__ to inherited attributes wastes memory. + slot_names = [name for name in names if name not in base_names] + # There are slots for attributes from current class + # that are defined in parent classes. + # As their descriptors may be overriden by a child class, + # we collect them here and update the class dict + reused_slots = { + slot: slot_descriptor + for slot, slot_descriptor in iteritems(existing_slots) + if slot in slot_names + } + slot_names = [name for name in slot_names if name not in reused_slots] + cd.update(reused_slots) + if self._cache_hash: + slot_names.append(_hash_cache_field) + cd["__slots__"] = tuple(slot_names) + + qualname = getattr(self._cls, "__qualname__", None) + if qualname is not None: + cd["__qualname__"] = qualname + + # Create new class based on old class and our methods. + cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) + + # The following is a fix for + # . On Python 3, + # if a method mentions `__class__` or uses the no-arg super(), the + # compiler will bake a reference to the class in the method itself + # as `method.__closure__`. Since we replace the class with a + # clone, we rewrite these references so it keeps working. + for item in cls.__dict__.values(): + if isinstance(item, (classmethod, staticmethod)): + # Class- and staticmethods hide their functions inside. + # These might need to be rewritten as well. + closure_cells = getattr(item.__func__, "__closure__", None) + elif isinstance(item, property): + # Workaround for property `super()` shortcut (PY3-only). + # There is no universal way for other descriptors. + closure_cells = getattr(item.fget, "__closure__", None) + else: + closure_cells = getattr(item, "__closure__", None) + + if not closure_cells: # Catch None or the empty list. + continue + for cell in closure_cells: + try: + match = cell.cell_contents is self._cls + except ValueError: # ValueError: Cell is empty + pass + else: + if match: + set_closure_cell(cell, cls) + + return cls + + def add_repr(self, ns): + self._cls_dict["__repr__"] = self._add_method_dunders( + _make_repr(self._attrs, ns, self._cls) + ) + return self + + def add_str(self): + repr = self._cls_dict.get("__repr__") + if repr is None: + raise ValueError( + "__str__ can only be generated if a __repr__ exists." + ) + + def __str__(self): + return self.__repr__() + + self._cls_dict["__str__"] = self._add_method_dunders(__str__) + return self + + def _make_getstate_setstate(self): + """ + Create custom __setstate__ and __getstate__ methods. + """ + # __weakref__ is not writable. + state_attr_names = tuple( + an for an in self._attr_names if an != "__weakref__" + ) + + def slots_getstate(self): + """ + Automatically created by attrs. + """ + return tuple(getattr(self, name) for name in state_attr_names) + + hash_caching_enabled = self._cache_hash + + def slots_setstate(self, state): + """ + Automatically created by attrs. + """ + __bound_setattr = _obj_setattr.__get__(self, Attribute) + for name, value in zip(state_attr_names, state): + __bound_setattr(name, value) + + # The hash code cache is not included when the object is + # serialized, but it still needs to be initialized to None to + # indicate that the first call to __hash__ should be a cache + # miss. + if hash_caching_enabled: + __bound_setattr(_hash_cache_field, None) + + return slots_getstate, slots_setstate + + def make_unhashable(self): + self._cls_dict["__hash__"] = None + return self + + def add_hash(self): + self._cls_dict["__hash__"] = self._add_method_dunders( + _make_hash( + self._cls, + self._attrs, + frozen=self._frozen, + cache_hash=self._cache_hash, + ) + ) + + return self + + def add_init(self): + self._cls_dict["__init__"] = self._add_method_dunders( + _make_init( + self._cls, + self._attrs, + self._has_pre_init, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=False, + ) + ) + + return self + + def add_match_args(self): + self._cls_dict["__match_args__"] = tuple( + field.name + for field in self._attrs + if field.init and not field.kw_only + ) + + def add_attrs_init(self): + self._cls_dict["__attrs_init__"] = self._add_method_dunders( + _make_init( + self._cls, + self._attrs, + self._has_pre_init, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=True, + ) + ) + + return self + + def add_eq(self): + cd = self._cls_dict + + cd["__eq__"] = self._add_method_dunders( + _make_eq(self._cls, self._attrs) + ) + cd["__ne__"] = self._add_method_dunders(_make_ne()) + + return self + + def add_order(self): + cd = self._cls_dict + + cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( + self._add_method_dunders(meth) + for meth in _make_order(self._cls, self._attrs) + ) + + return self + + def add_setattr(self): + if self._frozen: + return self + + sa_attrs = {} + for a in self._attrs: + on_setattr = a.on_setattr or self._on_setattr + if on_setattr and on_setattr is not setters.NO_OP: + sa_attrs[a.name] = a, on_setattr + + if not sa_attrs: + return self + + if self._has_custom_setattr: + # We need to write a __setattr__ but there already is one! + raise ValueError( + "Can't combine custom __setattr__ with on_setattr hooks." + ) + + # docstring comes from _add_method_dunders + def __setattr__(self, name, val): + try: + a, hook = sa_attrs[name] + except KeyError: + nval = val + else: + nval = hook(self, a, val) + + _obj_setattr(self, name, nval) + + self._cls_dict["__attrs_own_setattr__"] = True + self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) + self._wrote_own_setattr = True + + return self + + def _add_method_dunders(self, method): + """ + Add __module__ and __qualname__ to a *method* if possible. + """ + try: + method.__module__ = self._cls.__module__ + except AttributeError: + pass + + try: + method.__qualname__ = ".".join( + (self._cls.__qualname__, method.__name__) + ) + except AttributeError: + pass + + try: + method.__doc__ = "Method generated by attrs for class %s." % ( + self._cls.__qualname__, + ) + except AttributeError: + pass + + return method + + +_CMP_DEPRECATION = ( + "The usage of `cmp` is deprecated and will be removed on or after " + "2021-06-01. Please use `eq` and `order` instead." +) + + +def _determine_attrs_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + raise ValueError("Don't mix `cmp` with `eq' and `order`.") + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + return cmp, cmp + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq = default_eq + + if order is None: + order = eq + + if eq is False and order is True: + raise ValueError("`order` can only be True if `eq` is True too.") + + return eq, order + + +def _determine_attrib_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + raise ValueError("Don't mix `cmp` with `eq' and `order`.") + + def decide_callable_or_boolean(value): + """ + Decide whether a key function is used. + """ + if callable(value): + value, key = True, value + else: + key = None + return value, key + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + cmp, cmp_key = decide_callable_or_boolean(cmp) + return cmp, cmp_key, cmp, cmp_key + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq, eq_key = default_eq, None + else: + eq, eq_key = decide_callable_or_boolean(eq) + + if order is None: + order, order_key = eq, eq_key + else: + order, order_key = decide_callable_or_boolean(order) + + if eq is False and order is True: + raise ValueError("`order` can only be True if `eq` is True too.") + + return eq, eq_key, order, order_key + + +def _determine_whether_to_implement( + cls, flag, auto_detect, dunders, default=True +): + """ + Check whether we should implement a set of methods for *cls*. + + *flag* is the argument passed into @attr.s like 'init', *auto_detect* the + same as passed into @attr.s and *dunders* is a tuple of attribute names + whose presence signal that the user has implemented it themselves. + + Return *default* if no reason for either for or against is found. + + auto_detect must be False on Python 2. + """ + if flag is True or flag is False: + return flag + + if flag is None and auto_detect is False: + return default + + # Logically, flag is None and auto_detect is True here. + for dunder in dunders: + if _has_own_attribute(cls, dunder): + return False + + return default + + +def attrs( + maybe_cls=None, + these=None, + repr_ns=None, + repr=None, + cmp=None, + hash=None, + init=None, + slots=False, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=False, + kw_only=False, + cache_hash=False, + auto_exc=False, + eq=None, + order=None, + auto_detect=False, + collect_by_mro=False, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, +): + r""" + A class decorator that adds `dunder + `_\ -methods according to the + specified attributes using `attr.ib` or the *these* argument. + + :param these: A dictionary of name to `attr.ib` mappings. This is + useful to avoid the definition of your attributes within the class body + because you can't (e.g. if you want to add ``__repr__`` methods to + Django models) or don't want to. + + If *these* is not ``None``, ``attrs`` will *not* search the class body + for attributes and will *not* remove any attributes from it. + + If *these* is an ordered dict (`dict` on Python 3.6+, + `collections.OrderedDict` otherwise), the order is deduced from + the order of the attributes inside *these*. Otherwise the order + of the definition of the attributes is used. + + :type these: `dict` of `str` to `attr.ib` + + :param str repr_ns: When using nested classes, there's no way in Python 2 + to automatically detect that. Therefore it's possible to set the + namespace explicitly for a more meaningful ``repr`` output. + :param bool auto_detect: Instead of setting the *init*, *repr*, *eq*, + *order*, and *hash* arguments explicitly, assume they are set to + ``True`` **unless any** of the involved methods for one of the + arguments is implemented in the *current* class (i.e. it is *not* + inherited from some base class). + + So for example by implementing ``__eq__`` on a class yourself, + ``attrs`` will deduce ``eq=False`` and will create *neither* + ``__eq__`` *nor* ``__ne__`` (but Python classes come with a sensible + ``__ne__`` by default, so it *should* be enough to only implement + ``__eq__`` in most cases). + + .. warning:: + + If you prevent ``attrs`` from creating the ordering methods for you + (``order=False``, e.g. by implementing ``__le__``), it becomes + *your* responsibility to make sure its ordering is sound. The best + way is to use the `functools.total_ordering` decorator. + + + Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*, + *cmp*, or *hash* overrides whatever *auto_detect* would determine. + + *auto_detect* requires Python 3. Setting it ``True`` on Python 2 raises + an `attrs.exceptions.PythonTooOldError`. + + :param bool repr: Create a ``__repr__`` method with a human readable + representation of ``attrs`` attributes.. + :param bool str: Create a ``__str__`` method that is identical to + ``__repr__``. This is usually not necessary except for + `Exception`\ s. + :param Optional[bool] eq: If ``True`` or ``None`` (default), add ``__eq__`` + and ``__ne__`` methods that check two instances for equality. + + They compare the instances as if they were tuples of their ``attrs`` + attributes if and only if the types of both classes are *identical*! + :param Optional[bool] order: If ``True``, add ``__lt__``, ``__le__``, + ``__gt__``, and ``__ge__`` methods that behave like *eq* above and + allow instances to be ordered. If ``None`` (default) mirror value of + *eq*. + :param Optional[bool] cmp: Setting *cmp* is equivalent to setting *eq* + and *order* to the same value. Must not be mixed with *eq* or *order*. + :param Optional[bool] hash: If ``None`` (default), the ``__hash__`` method + is generated according how *eq* and *frozen* are set. + + 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you. + 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set to + None, marking it unhashable (which it is). + 3. If *eq* is False, ``__hash__`` will be left untouched meaning the + ``__hash__`` method of the base class will be used (if base class is + ``object``, this means it will fall back to id-based hashing.). + + Although not recommended, you can decide for yourself and force + ``attrs`` to create one (e.g. if the class is immutable even though you + didn't freeze it programmatically) by passing ``True`` or not. Both of + these cases are rather special and should be used carefully. + + See our documentation on `hashing`, Python's documentation on + `object.__hash__`, and the `GitHub issue that led to the default \ + behavior `_ for more + details. + :param bool init: Create a ``__init__`` method that initializes the + ``attrs`` attributes. Leading underscores are stripped for the argument + name. If a ``__attrs_pre_init__`` method exists on the class, it will + be called before the class is initialized. If a ``__attrs_post_init__`` + method exists on the class, it will be called after the class is fully + initialized. + + If ``init`` is ``False``, an ``__attrs_init__`` method will be + injected instead. This allows you to define a custom ``__init__`` + method that can do pre-init work such as ``super().__init__()``, + and then call ``__attrs_init__()`` and ``__attrs_post_init__()``. + :param bool slots: Create a `slotted class ` that's more + memory-efficient. Slotted classes are generally superior to the default + dict classes, but have some gotchas you should know about, so we + encourage you to read the `glossary entry `. + :param bool frozen: Make instances immutable after initialization. If + someone attempts to modify a frozen instance, + `attr.exceptions.FrozenInstanceError` is raised. + + .. note:: + + 1. This is achieved by installing a custom ``__setattr__`` method + on your class, so you can't implement your own. + + 2. True immutability is impossible in Python. + + 3. This *does* have a minor a runtime performance `impact + ` when initializing new instances. In other words: + ``__init__`` is slightly slower with ``frozen=True``. + + 4. If a class is frozen, you cannot modify ``self`` in + ``__attrs_post_init__`` or a self-written ``__init__``. You can + circumvent that limitation by using + ``object.__setattr__(self, "attribute_name", value)``. + + 5. Subclasses of a frozen class are frozen too. + + :param bool weakref_slot: Make instances weak-referenceable. This has no + effect unless ``slots`` is also enabled. + :param bool auto_attribs: If ``True``, collect `PEP 526`_-annotated + attributes (Python 3.6 and later only) from the class body. + + In this case, you **must** annotate every field. If ``attrs`` + encounters a field that is set to an `attr.ib` but lacks a type + annotation, an `attr.exceptions.UnannotatedAttributeError` is + raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't + want to set a type. + + If you assign a value to those attributes (e.g. ``x: int = 42``), that + value becomes the default value like if it were passed using + ``attr.ib(default=42)``. Passing an instance of `attrs.Factory` also + works as expected in most cases (see warning below). + + Attributes annotated as `typing.ClassVar`, and attributes that are + neither annotated nor set to an `attr.ib` are **ignored**. + + .. warning:: + For features that use the attribute name to create decorators (e.g. + `validators `), you still *must* assign `attr.ib` to + them. Otherwise Python will either not find the name or try to use + the default value to call e.g. ``validator`` on it. + + These errors can be quite confusing and probably the most common bug + report on our bug tracker. + + .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/ + :param bool kw_only: Make all attributes keyword-only (Python 3+) + in the generated ``__init__`` (if ``init`` is ``False``, this + parameter is ignored). + :param bool cache_hash: Ensure that the object's hash code is computed + only once and stored on the object. If this is set to ``True``, + hashing must be either explicitly or implicitly enabled for this + class. If the hash code is cached, avoid any reassignments of + fields involved in hash code computation or mutations of the objects + those fields point to after object creation. If such changes occur, + the behavior of the object's hash code is undefined. + :param bool auto_exc: If the class subclasses `BaseException` + (which implicitly includes any subclass of any exception), the + following happens to behave like a well-behaved Python exceptions + class: + + - the values for *eq*, *order*, and *hash* are ignored and the + instances compare and hash by the instance's ids (N.B. ``attrs`` will + *not* remove existing implementations of ``__hash__`` or the equality + methods. It just won't add own ones.), + - all attributes that are either passed into ``__init__`` or have a + default value are additionally available as a tuple in the ``args`` + attribute, + - the value of *str* is ignored leaving ``__str__`` to base classes. + :param bool collect_by_mro: Setting this to `True` fixes the way ``attrs`` + collects attributes from base classes. The default behavior is + incorrect in certain cases of multiple inheritance. It should be on by + default but is kept off for backward-compatibility. + + See issue `#428 `_ for + more details. + + :param Optional[bool] getstate_setstate: + .. note:: + This is usually only interesting for slotted classes and you should + probably just set *auto_detect* to `True`. + + If `True`, ``__getstate__`` and + ``__setstate__`` are generated and attached to the class. This is + necessary for slotted classes to be pickleable. If left `None`, it's + `True` by default for slotted classes and ``False`` for dict classes. + + If *auto_detect* is `True`, and *getstate_setstate* is left `None`, + and **either** ``__getstate__`` or ``__setstate__`` is detected directly + on the class (i.e. not inherited), it is set to `False` (this is usually + what you want). + + :param on_setattr: A callable that is run whenever the user attempts to set + an attribute (either by assignment like ``i.x = 42`` or by using + `setattr` like ``setattr(i, "x", 42)``). It receives the same arguments + as validators: the instance, the attribute that is being modified, and + the new value. + + If no exception is raised, the attribute is set to the return value of + the callable. + + If a list of callables is passed, they're automatically wrapped in an + `attrs.setters.pipe`. + + :param Optional[callable] field_transformer: + A function that is called with the original class object and all + fields right before ``attrs`` finalizes the class. You can use + this, e.g., to automatically add converters or validators to + fields based on their types. See `transform-fields` for more details. + + :param bool match_args: + If `True` (default), set ``__match_args__`` on the class to support + `PEP 634 `_ (Structural + Pattern Matching). It is a tuple of all positional-only ``__init__`` + parameter names on Python 3.10 and later. Ignored on older Python + versions. + + .. versionadded:: 16.0.0 *slots* + .. versionadded:: 16.1.0 *frozen* + .. versionadded:: 16.3.0 *str* + .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. + .. versionchanged:: 17.1.0 + *hash* supports ``None`` as value which is also the default now. + .. versionadded:: 17.3.0 *auto_attribs* + .. versionchanged:: 18.1.0 + If *these* is passed, no attributes are deleted from the class body. + .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. + .. versionadded:: 18.2.0 *weakref_slot* + .. deprecated:: 18.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a + `DeprecationWarning` if the classes compared are subclasses of + each other. ``__eq`` and ``__ne__`` never tried to compared subclasses + to each other. + .. versionchanged:: 19.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider + subclasses comparable anymore. + .. versionadded:: 18.2.0 *kw_only* + .. versionadded:: 18.2.0 *cache_hash* + .. versionadded:: 19.1.0 *auto_exc* + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *auto_detect* + .. versionadded:: 20.1.0 *collect_by_mro* + .. versionadded:: 20.1.0 *getstate_setstate* + .. versionadded:: 20.1.0 *on_setattr* + .. versionadded:: 20.3.0 *field_transformer* + .. versionchanged:: 21.1.0 + ``init=False`` injects ``__attrs_init__`` + .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` + .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 21.3.0 *match_args* + """ + if auto_detect and PY2: + raise PythonTooOldError( + "auto_detect only works on Python 3 and later." + ) + + eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) + hash_ = hash # work around the lack of nonlocal + + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + def wrap(cls): + + if getattr(cls, "__class__", None) is None: + raise TypeError("attrs only works with new-style classes.") + + is_frozen = frozen or _has_frozen_base_class(cls) + is_exc = auto_exc is True and issubclass(cls, BaseException) + has_own_setattr = auto_detect and _has_own_attribute( + cls, "__setattr__" + ) + + if has_own_setattr and is_frozen: + raise ValueError("Can't freeze a class with a custom __setattr__.") + + builder = _ClassBuilder( + cls, + these, + slots, + is_frozen, + weakref_slot, + _determine_whether_to_implement( + cls, + getstate_setstate, + auto_detect, + ("__getstate__", "__setstate__"), + default=slots, + ), + auto_attribs, + kw_only, + cache_hash, + is_exc, + collect_by_mro, + on_setattr, + has_own_setattr, + field_transformer, + ) + if _determine_whether_to_implement( + cls, repr, auto_detect, ("__repr__",) + ): + builder.add_repr(repr_ns) + if str is True: + builder.add_str() + + eq = _determine_whether_to_implement( + cls, eq_, auto_detect, ("__eq__", "__ne__") + ) + if not is_exc and eq is True: + builder.add_eq() + if not is_exc and _determine_whether_to_implement( + cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") + ): + builder.add_order() + + builder.add_setattr() + + if ( + hash_ is None + and auto_detect is True + and _has_own_attribute(cls, "__hash__") + ): + hash = False + else: + hash = hash_ + if hash is not True and hash is not False and hash is not None: + # Can't use `hash in` because 1 == True for example. + raise TypeError( + "Invalid value for hash. Must be True, False, or None." + ) + elif hash is False or (hash is None and eq is False) or is_exc: + # Don't do anything. Should fall back to __object__'s __hash__ + # which is by id. + if cache_hash: + raise TypeError( + "Invalid value for cache_hash. To use hash caching," + " hashing must be either explicitly or implicitly " + "enabled." + ) + elif hash is True or ( + hash is None and eq is True and is_frozen is True + ): + # Build a __hash__ if told so, or if it's safe. + builder.add_hash() + else: + # Raise TypeError on attempts to hash. + if cache_hash: + raise TypeError( + "Invalid value for cache_hash. To use hash caching," + " hashing must be either explicitly or implicitly " + "enabled." + ) + builder.make_unhashable() + + if _determine_whether_to_implement( + cls, init, auto_detect, ("__init__",) + ): + builder.add_init() + else: + builder.add_attrs_init() + if cache_hash: + raise TypeError( + "Invalid value for cache_hash. To use hash caching," + " init must be True." + ) + + if ( + PY310 + and match_args + and not _has_own_attribute(cls, "__match_args__") + ): + builder.add_match_args() + + return builder.build_class() + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but ``None`` if used as `@attrs()`. + if maybe_cls is None: + return wrap + else: + return wrap(maybe_cls) + + +_attrs = attrs +""" +Internal alias so we can use it in functions that take an argument called +*attrs*. +""" + + +if PY2: + + def _has_frozen_base_class(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return ( + getattr(cls.__setattr__, "__module__", None) + == _frozen_setattrs.__module__ + and cls.__setattr__.__name__ == _frozen_setattrs.__name__ + ) + +else: + + def _has_frozen_base_class(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return cls.__setattr__ == _frozen_setattrs + + +def _generate_unique_filename(cls, func_name): + """ + Create a "filename" suitable for a function being generated. + """ + unique_filename = "".format( + func_name, + cls.__module__, + getattr(cls, "__qualname__", cls.__name__), + ) + return unique_filename + + +def _make_hash(cls, attrs, frozen, cache_hash): + attrs = tuple( + a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) + ) + + tab = " " + + unique_filename = _generate_unique_filename(cls, "hash") + type_hash = hash(unique_filename) + + hash_def = "def __hash__(self" + hash_func = "hash((" + closing_braces = "))" + if not cache_hash: + hash_def += "):" + else: + if not PY2: + hash_def += ", *" + + hash_def += ( + ", _cache_wrapper=" + + "__import__('attr._make')._make._CacheHashWrapper):" + ) + hash_func = "_cache_wrapper(" + hash_func + closing_braces += ")" + + method_lines = [hash_def] + + def append_hash_computation_lines(prefix, indent): + """ + Generate the code for actually computing the hash code. + Below this will either be returned directly or used to compute + a value which is then cached, depending on the value of cache_hash + """ + + method_lines.extend( + [ + indent + prefix + hash_func, + indent + " %d," % (type_hash,), + ] + ) + + for a in attrs: + method_lines.append(indent + " self.%s," % a.name) + + method_lines.append(indent + " " + closing_braces) + + if cache_hash: + method_lines.append(tab + "if self.%s is None:" % _hash_cache_field) + if frozen: + append_hash_computation_lines( + "object.__setattr__(self, '%s', " % _hash_cache_field, tab * 2 + ) + method_lines.append(tab * 2 + ")") # close __setattr__ + else: + append_hash_computation_lines( + "self.%s = " % _hash_cache_field, tab * 2 + ) + method_lines.append(tab + "return self.%s" % _hash_cache_field) + else: + append_hash_computation_lines("return ", tab) + + script = "\n".join(method_lines) + return _make_method("__hash__", script, unique_filename) + + +def _add_hash(cls, attrs): + """ + Add a hash method to *cls*. + """ + cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False) + return cls + + +def _make_ne(): + """ + Create __ne__ method. + """ + + def __ne__(self, other): + """ + Check equality and either forward a NotImplemented or + return the result negated. + """ + result = self.__eq__(other) + if result is NotImplemented: + return NotImplemented + + return not result + + return __ne__ + + +def _make_eq(cls, attrs): + """ + Create __eq__ method for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.eq] + + unique_filename = _generate_unique_filename(cls, "eq") + lines = [ + "def __eq__(self, other):", + " if other.__class__ is not self.__class__:", + " return NotImplemented", + ] + + # We can't just do a big self.x = other.x and... clause due to + # irregularities like nan == nan is false but (nan,) == (nan,) is true. + globs = {} + if attrs: + lines.append(" return (") + others = [" ) == ("] + for a in attrs: + if a.eq_key: + cmp_name = "_%s_key" % (a.name,) + # Add the key function to the global namespace + # of the evaluated function. + globs[cmp_name] = a.eq_key + lines.append( + " %s(self.%s)," + % ( + cmp_name, + a.name, + ) + ) + others.append( + " %s(other.%s)," + % ( + cmp_name, + a.name, + ) + ) + else: + lines.append(" self.%s," % (a.name,)) + others.append(" other.%s," % (a.name,)) + + lines += others + [" )"] + else: + lines.append(" return True") + + script = "\n".join(lines) + + return _make_method("__eq__", script, unique_filename, globs) + + +def _make_order(cls, attrs): + """ + Create ordering methods for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.order] + + def attrs_to_tuple(obj): + """ + Save us some typing. + """ + return tuple( + key(value) if key else value + for value, key in ( + (getattr(obj, a.name), a.order_key) for a in attrs + ) + ) + + def __lt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) < attrs_to_tuple(other) + + return NotImplemented + + def __le__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) <= attrs_to_tuple(other) + + return NotImplemented + + def __gt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) > attrs_to_tuple(other) + + return NotImplemented + + def __ge__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) >= attrs_to_tuple(other) + + return NotImplemented + + return __lt__, __le__, __gt__, __ge__ + + +def _add_eq(cls, attrs=None): + """ + Add equality methods to *cls* with *attrs*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + cls.__eq__ = _make_eq(cls, attrs) + cls.__ne__ = _make_ne() + + return cls + + +if HAS_F_STRINGS: + + def _make_repr(attrs, ns, cls): + unique_filename = _generate_unique_filename(cls, "repr") + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, (repr if a.repr is True else a.repr), a.init) + for a in attrs + if a.repr is not False + ) + globs = { + name + "_repr": r + for name, r, _ in attr_names_with_reprs + if r != repr + } + globs["_compat"] = _compat + globs["AttributeError"] = AttributeError + globs["NOTHING"] = NOTHING + attribute_fragments = [] + for name, r, i in attr_names_with_reprs: + accessor = ( + "self." + name + if i + else 'getattr(self, "' + name + '", NOTHING)' + ) + fragment = ( + "%s={%s!r}" % (name, accessor) + if r == repr + else "%s={%s_repr(%s)}" % (name, name, accessor) + ) + attribute_fragments.append(fragment) + repr_fragment = ", ".join(attribute_fragments) + + if ns is None: + cls_name_fragment = ( + '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' + ) + else: + cls_name_fragment = ns + ".{self.__class__.__name__}" + + lines = [ + "def __repr__(self):", + " try:", + " already_repring = _compat.repr_context.already_repring", + " except AttributeError:", + " already_repring = {id(self),}", + " _compat.repr_context.already_repring = already_repring", + " else:", + " if id(self) in already_repring:", + " return '...'", + " else:", + " already_repring.add(id(self))", + " try:", + " return f'%s(%s)'" % (cls_name_fragment, repr_fragment), + " finally:", + " already_repring.remove(id(self))", + ] + + return _make_method( + "__repr__", "\n".join(lines), unique_filename, globs=globs + ) + +else: + + def _make_repr(attrs, ns, _): + """ + Make a repr method that includes relevant *attrs*, adding *ns* to the + full name. + """ + + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, repr if a.repr is True else a.repr) + for a in attrs + if a.repr is not False + ) + + def __repr__(self): + """ + Automatically created by attrs. + """ + try: + already_repring = _compat.repr_context.already_repring + except AttributeError: + already_repring = set() + _compat.repr_context.already_repring = already_repring + + if id(self) in already_repring: + return "..." + real_cls = self.__class__ + if ns is None: + qualname = getattr(real_cls, "__qualname__", None) + if qualname is not None: # pragma: no cover + # This case only happens on Python 3.5 and 3.6. We exclude + # it from coverage, because we don't want to slow down our + # test suite by running them under coverage too for this + # one line. + class_name = qualname.rsplit(">.", 1)[-1] + else: + class_name = real_cls.__name__ + else: + class_name = ns + "." + real_cls.__name__ + + # Since 'self' remains on the stack (i.e.: strongly referenced) + # for the duration of this call, it's safe to depend on id(...) + # stability, and not need to track the instance and therefore + # worry about properties like weakref- or hash-ability. + already_repring.add(id(self)) + try: + result = [class_name, "("] + first = True + for name, attr_repr in attr_names_with_reprs: + if first: + first = False + else: + result.append(", ") + result.extend( + (name, "=", attr_repr(getattr(self, name, NOTHING))) + ) + return "".join(result) + ")" + finally: + already_repring.remove(id(self)) + + return __repr__ + + +def _add_repr(cls, ns=None, attrs=None): + """ + Add a repr method to *cls*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + cls.__repr__ = _make_repr(attrs, ns, cls) + return cls + + +def fields(cls): + """ + Return the tuple of ``attrs`` attributes for a class. + + The tuple also allows accessing the fields by their names (see below for + examples). + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + :rtype: tuple (with name accessors) of `attrs.Attribute` + + .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields + by name. + """ + if not isclass(cls): + raise TypeError("Passed object must be a class.") + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + raise NotAnAttrsClassError( + "{cls!r} is not an attrs-decorated class.".format(cls=cls) + ) + return attrs + + +def fields_dict(cls): + """ + Return an ordered dictionary of ``attrs`` attributes for a class, whose + keys are the attribute names. + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + :rtype: an ordered dict where keys are attribute names and values are + `attrs.Attribute`\\ s. This will be a `dict` if it's + naturally ordered like on Python 3.6+ or an + :class:`~collections.OrderedDict` otherwise. + + .. versionadded:: 18.1.0 + """ + if not isclass(cls): + raise TypeError("Passed object must be a class.") + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + raise NotAnAttrsClassError( + "{cls!r} is not an attrs-decorated class.".format(cls=cls) + ) + return ordered_dict(((a.name, a) for a in attrs)) + + +def validate(inst): + """ + Validate all attributes on *inst* that have a validator. + + Leaves all exceptions through. + + :param inst: Instance of a class with ``attrs`` attributes. + """ + if _config._run_validators is False: + return + + for a in fields(inst.__class__): + v = a.validator + if v is not None: + v(inst, a, getattr(inst, a.name)) + + +def _is_slot_cls(cls): + return "__slots__" in cls.__dict__ + + +def _is_slot_attr(a_name, base_attr_map): + """ + Check if the attribute name comes from a slot class. + """ + return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name]) + + +def _make_init( + cls, + attrs, + pre_init, + post_init, + frozen, + slots, + cache_hash, + base_attr_map, + is_exc, + cls_on_setattr, + attrs_init, +): + has_cls_on_setattr = ( + cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP + ) + + if frozen and has_cls_on_setattr: + raise ValueError("Frozen classes can't use on_setattr.") + + needs_cached_setattr = cache_hash or frozen + filtered_attrs = [] + attr_dict = {} + for a in attrs: + if not a.init and a.default is NOTHING: + continue + + filtered_attrs.append(a) + attr_dict[a.name] = a + + if a.on_setattr is not None: + if frozen is True: + raise ValueError("Frozen classes can't use on_setattr.") + + needs_cached_setattr = True + elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: + needs_cached_setattr = True + + unique_filename = _generate_unique_filename(cls, "init") + + script, globs, annotations = _attrs_to_init_script( + filtered_attrs, + frozen, + slots, + pre_init, + post_init, + cache_hash, + base_attr_map, + is_exc, + needs_cached_setattr, + has_cls_on_setattr, + attrs_init, + ) + if cls.__module__ in sys.modules: + # This makes typing.get_type_hints(CLS.__init__) resolve string types. + globs.update(sys.modules[cls.__module__].__dict__) + + globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) + + if needs_cached_setattr: + # Save the lookup overhead in __init__ if we need to circumvent + # setattr hooks. + globs["_cached_setattr"] = _obj_setattr + + init = _make_method( + "__attrs_init__" if attrs_init else "__init__", + script, + unique_filename, + globs, + ) + init.__annotations__ = annotations + + return init + + +def _setattr(attr_name, value_var, has_on_setattr): + """ + Use the cached object.setattr to set *attr_name* to *value_var*. + """ + return "_setattr('%s', %s)" % (attr_name, value_var) + + +def _setattr_with_converter(attr_name, value_var, has_on_setattr): + """ + Use the cached object.setattr to set *attr_name* to *value_var*, but run + its converter first. + """ + return "_setattr('%s', %s(%s))" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + +def _assign(attr_name, value, has_on_setattr): + """ + Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise + relegate to _setattr. + """ + if has_on_setattr: + return _setattr(attr_name, value, True) + + return "self.%s = %s" % (attr_name, value) + + +def _assign_with_converter(attr_name, value_var, has_on_setattr): + """ + Unless *attr_name* has an on_setattr hook, use normal assignment after + conversion. Otherwise relegate to _setattr_with_converter. + """ + if has_on_setattr: + return _setattr_with_converter(attr_name, value_var, True) + + return "self.%s = %s(%s)" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + +if PY2: + + def _unpack_kw_only_py2(attr_name, default=None): + """ + Unpack *attr_name* from _kw_only dict. + """ + if default is not None: + arg_default = ", %s" % default + else: + arg_default = "" + return "%s = _kw_only.pop('%s'%s)" % ( + attr_name, + attr_name, + arg_default, + ) + + def _unpack_kw_only_lines_py2(kw_only_args): + """ + Unpack all *kw_only_args* from _kw_only dict and handle errors. + + Given a list of strings "{attr_name}" and "{attr_name}={default}" + generates list of lines of code that pop attrs from _kw_only dict and + raise TypeError similar to builtin if required attr is missing or + extra key is passed. + + >>> print("\n".join(_unpack_kw_only_lines_py2(["a", "b=42"]))) + try: + a = _kw_only.pop('a') + b = _kw_only.pop('b', 42) + except KeyError as _key_error: + raise TypeError( + ... + if _kw_only: + raise TypeError( + ... + """ + lines = ["try:"] + lines.extend( + " " + _unpack_kw_only_py2(*arg.split("=")) + for arg in kw_only_args + ) + lines += """\ +except KeyError as _key_error: + raise TypeError( + '__init__() missing required keyword-only argument: %s' % _key_error + ) +if _kw_only: + raise TypeError( + '__init__() got an unexpected keyword argument %r' + % next(iter(_kw_only)) + ) +""".split( + "\n" + ) + return lines + + +def _attrs_to_init_script( + attrs, + frozen, + slots, + pre_init, + post_init, + cache_hash, + base_attr_map, + is_exc, + needs_cached_setattr, + has_cls_on_setattr, + attrs_init, +): + """ + Return a script of an initializer for *attrs* and a dict of globals. + + The globals are expected by the generated script. + + If *frozen* is True, we cannot set the attributes directly so we use + a cached ``object.__setattr__``. + """ + lines = [] + if pre_init: + lines.append("self.__attrs_pre_init__()") + + if needs_cached_setattr: + lines.append( + # Circumvent the __setattr__ descriptor to save one lookup per + # assignment. + # Note _setattr will be used again below if cache_hash is True + "_setattr = _cached_setattr.__get__(self, self.__class__)" + ) + + if frozen is True: + if slots is True: + fmt_setter = _setattr + fmt_setter_with_converter = _setattr_with_converter + else: + # Dict frozen classes assign directly to __dict__. + # But only if the attribute doesn't come from an ancestor slot + # class. + # Note _inst_dict will be used again below if cache_hash is True + lines.append("_inst_dict = self.__dict__") + + def fmt_setter(attr_name, value_var, has_on_setattr): + if _is_slot_attr(attr_name, base_attr_map): + return _setattr(attr_name, value_var, has_on_setattr) + + return "_inst_dict['%s'] = %s" % (attr_name, value_var) + + def fmt_setter_with_converter( + attr_name, value_var, has_on_setattr + ): + if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): + return _setattr_with_converter( + attr_name, value_var, has_on_setattr + ) + + return "_inst_dict['%s'] = %s(%s)" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + else: + # Not frozen. + fmt_setter = _assign + fmt_setter_with_converter = _assign_with_converter + + args = [] + kw_only_args = [] + attrs_to_validate = [] + + # This is a dictionary of names to validator and converter callables. + # Injecting this into __init__ globals lets us avoid lookups. + names_for_globals = {} + annotations = {"return": None} + + for a in attrs: + if a.validator: + attrs_to_validate.append(a) + + attr_name = a.name + has_on_setattr = a.on_setattr is not None or ( + a.on_setattr is not setters.NO_OP and has_cls_on_setattr + ) + arg_name = a.name.lstrip("_") + + has_factory = isinstance(a.default, Factory) + if has_factory and a.default.takes_self: + maybe_self = "self" + else: + maybe_self = "" + + if a.init is False: + if has_factory: + init_factory_name = _init_factory_pat.format(a.name) + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + init_factory_name + "(%s)" % (maybe_self,), + has_on_setattr, + ) + ) + conv_name = _init_converter_pat % (a.name,) + names_for_globals[conv_name] = a.converter + else: + lines.append( + fmt_setter( + attr_name, + init_factory_name + "(%s)" % (maybe_self,), + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + else: + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + "attr_dict['%s'].default" % (attr_name,), + has_on_setattr, + ) + ) + conv_name = _init_converter_pat % (a.name,) + names_for_globals[conv_name] = a.converter + else: + lines.append( + fmt_setter( + attr_name, + "attr_dict['%s'].default" % (attr_name,), + has_on_setattr, + ) + ) + elif a.default is not NOTHING and not has_factory: + arg = "%s=attr_dict['%s'].default" % (arg_name, attr_name) + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + elif has_factory: + arg = "%s=NOTHING" % (arg_name,) + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + lines.append("if %s is not NOTHING:" % (arg_name,)) + + init_factory_name = _init_factory_pat.format(a.name) + if a.converter is not None: + lines.append( + " " + + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter_with_converter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append( + " " + fmt_setter(attr_name, arg_name, has_on_setattr) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + else: + if a.kw_only: + kw_only_args.append(arg_name) + else: + args.append(arg_name) + + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + if a.init is True: + if a.type is not None and a.converter is None: + annotations[arg_name] = a.type + elif a.converter is not None and not PY2: + # Try to get the type from the converter. + sig = None + try: + sig = inspect.signature(a.converter) + except (ValueError, TypeError): # inspect failed + pass + if sig: + sig_params = list(sig.parameters.values()) + if ( + sig_params + and sig_params[0].annotation + is not inspect.Parameter.empty + ): + annotations[arg_name] = sig_params[0].annotation + + if attrs_to_validate: # we can skip this if there are no validators. + names_for_globals["_config"] = _config + lines.append("if _config._run_validators is True:") + for a in attrs_to_validate: + val_name = "__attr_validator_" + a.name + attr_name = "__attr_" + a.name + lines.append( + " %s(self, %s, self.%s)" % (val_name, attr_name, a.name) + ) + names_for_globals[val_name] = a.validator + names_for_globals[attr_name] = a + + if post_init: + lines.append("self.__attrs_post_init__()") + + # because this is set only after __attrs_post_init is called, a crash + # will result if post-init tries to access the hash code. This seemed + # preferable to setting this beforehand, in which case alteration to + # field values during post-init combined with post-init accessing the + # hash code would result in silent bugs. + if cache_hash: + if frozen: + if slots: + # if frozen and slots, then _setattr defined above + init_hash_cache = "_setattr('%s', %s)" + else: + # if frozen and not slots, then _inst_dict defined above + init_hash_cache = "_inst_dict['%s'] = %s" + else: + init_hash_cache = "self.%s = %s" + lines.append(init_hash_cache % (_hash_cache_field, "None")) + + # For exceptions we rely on BaseException.__init__ for proper + # initialization. + if is_exc: + vals = ",".join("self." + a.name for a in attrs if a.init) + + lines.append("BaseException.__init__(self, %s)" % (vals,)) + + args = ", ".join(args) + if kw_only_args: + if PY2: + lines = _unpack_kw_only_lines_py2(kw_only_args) + lines + + args += "%s**_kw_only" % (", " if args else "",) # leading comma + else: + args += "%s*, %s" % ( + ", " if args else "", # leading comma + ", ".join(kw_only_args), # kw_only args + ) + return ( + """\ +def {init_name}(self, {args}): + {lines} +""".format( + init_name=("__attrs_init__" if attrs_init else "__init__"), + args=args, + lines="\n ".join(lines) if lines else "pass", + ), + names_for_globals, + annotations, + ) + + +class Attribute(object): + """ + *Read-only* representation of an attribute. + + The class has *all* arguments of `attr.ib` (except for ``factory`` + which is only syntactic sugar for ``default=Factory(...)`` plus the + following: + + - ``name`` (`str`): The name of the attribute. + - ``inherited`` (`bool`): Whether or not that attribute has been inherited + from a base class. + - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The callables + that are used for comparing and ordering objects by this attribute, + respectively. These are set by passing a callable to `attr.ib`'s ``eq``, + ``order``, or ``cmp`` arguments. See also :ref:`comparison customization + `. + + Instances of this class are frequently used for introspection purposes + like: + + - `fields` returns a tuple of them. + - Validators get them passed as the first argument. + - The :ref:`field transformer ` hook receives a list of + them. + + .. versionadded:: 20.1.0 *inherited* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.2.0 *inherited* is not taken into account for + equality checks and hashing anymore. + .. versionadded:: 21.1.0 *eq_key* and *order_key* + + For the full version history of the fields, see `attr.ib`. + """ + + __slots__ = ( + "name", + "default", + "validator", + "repr", + "eq", + "eq_key", + "order", + "order_key", + "hash", + "init", + "metadata", + "type", + "converter", + "kw_only", + "inherited", + "on_setattr", + ) + + def __init__( + self, + name, + default, + validator, + repr, + cmp, # XXX: unused, remove along with other cmp code. + hash, + init, + inherited, + metadata=None, + type=None, + converter=None, + kw_only=False, + eq=None, + eq_key=None, + order=None, + order_key=None, + on_setattr=None, + ): + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq_key or eq, order_key or order, True + ) + + # Cache this descriptor here to speed things up later. + bound_setattr = _obj_setattr.__get__(self, Attribute) + + # Despite the big red warning, people *do* instantiate `Attribute` + # themselves. + bound_setattr("name", name) + bound_setattr("default", default) + bound_setattr("validator", validator) + bound_setattr("repr", repr) + bound_setattr("eq", eq) + bound_setattr("eq_key", eq_key) + bound_setattr("order", order) + bound_setattr("order_key", order_key) + bound_setattr("hash", hash) + bound_setattr("init", init) + bound_setattr("converter", converter) + bound_setattr( + "metadata", + ( + metadata_proxy(metadata) + if metadata + else _empty_metadata_singleton + ), + ) + bound_setattr("type", type) + bound_setattr("kw_only", kw_only) + bound_setattr("inherited", inherited) + bound_setattr("on_setattr", on_setattr) + + def __setattr__(self, name, value): + raise FrozenInstanceError() + + @classmethod + def from_counting_attr(cls, name, ca, type=None): + # type holds the annotated value. deal with conflicts: + if type is None: + type = ca.type + elif ca.type is not None: + raise ValueError( + "Type annotation and type argument cannot both be present" + ) + inst_dict = { + k: getattr(ca, k) + for k in Attribute.__slots__ + if k + not in ( + "name", + "validator", + "default", + "type", + "inherited", + ) # exclude methods and deprecated alias + } + return cls( + name=name, + validator=ca._validator, + default=ca._default, + type=type, + cmp=None, + inherited=False, + **inst_dict + ) + + @property + def cmp(self): + """ + Simulate the presence of a cmp attribute and warn. + """ + warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=2) + + return self.eq and self.order + + # Don't use attr.evolve since fields(Attribute) doesn't work + def evolve(self, **changes): + """ + Copy *self* and apply *changes*. + + This works similarly to `attr.evolve` but that function does not work + with ``Attribute``. + + It is mainly meant to be used for `transform-fields`. + + .. versionadded:: 20.3.0 + """ + new = copy.copy(self) + + new._setattrs(changes.items()) + + return new + + # Don't use _add_pickle since fields(Attribute) doesn't work + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple( + getattr(self, name) if name != "metadata" else dict(self.metadata) + for name in self.__slots__ + ) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + self._setattrs(zip(self.__slots__, state)) + + def _setattrs(self, name_values_pairs): + bound_setattr = _obj_setattr.__get__(self, Attribute) + for name, value in name_values_pairs: + if name != "metadata": + bound_setattr(name, value) + else: + bound_setattr( + name, + metadata_proxy(value) + if value + else _empty_metadata_singleton, + ) + + +_a = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=(name != "metadata"), + init=True, + inherited=False, + ) + for name in Attribute.__slots__ +] + +Attribute = _add_hash( + _add_eq( + _add_repr(Attribute, attrs=_a), + attrs=[a for a in _a if a.name != "inherited"], + ), + attrs=[a for a in _a if a.hash and a.name != "inherited"], +) + + +class _CountingAttr(object): + """ + Intermediate representation of attributes that uses a counter to preserve + the order in which the attributes have been defined. + + *Internal* data structure of the attrs library. Running into is most + likely the result of a bug like a forgotten `@attr.s` decorator. + """ + + __slots__ = ( + "counter", + "_default", + "repr", + "eq", + "eq_key", + "order", + "order_key", + "hash", + "init", + "metadata", + "_validator", + "converter", + "type", + "kw_only", + "on_setattr", + ) + __attrs_attrs__ = tuple( + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=True, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ) + for name in ( + "counter", + "_default", + "repr", + "eq", + "order", + "hash", + "init", + "on_setattr", + ) + ) + ( + Attribute( + name="metadata", + default=None, + validator=None, + repr=True, + cmp=None, + hash=False, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ), + ) + cls_counter = 0 + + def __init__( + self, + default, + validator, + repr, + cmp, + hash, + init, + converter, + metadata, + type, + kw_only, + eq, + eq_key, + order, + order_key, + on_setattr, + ): + _CountingAttr.cls_counter += 1 + self.counter = _CountingAttr.cls_counter + self._default = default + self._validator = validator + self.converter = converter + self.repr = repr + self.eq = eq + self.eq_key = eq_key + self.order = order + self.order_key = order_key + self.hash = hash + self.init = init + self.metadata = metadata + self.type = type + self.kw_only = kw_only + self.on_setattr = on_setattr + + def validator(self, meth): + """ + Decorator that adds *meth* to the list of validators. + + Returns *meth* unchanged. + + .. versionadded:: 17.1.0 + """ + if self._validator is None: + self._validator = meth + else: + self._validator = and_(self._validator, meth) + return meth + + def default(self, meth): + """ + Decorator that allows to set the default for an attribute. + + Returns *meth* unchanged. + + :raises DefaultAlreadySetError: If default has been set before. + + .. versionadded:: 17.1.0 + """ + if self._default is not NOTHING: + raise DefaultAlreadySetError() + + self._default = Factory(meth, takes_self=True) + + return meth + + +_CountingAttr = _add_eq(_add_repr(_CountingAttr)) + + +class Factory(object): + """ + Stores a factory callable. + + If passed as the default value to `attrs.field`, the factory is used to + generate a new value. + + :param callable factory: A callable that takes either none or exactly one + mandatory positional argument depending on *takes_self*. + :param bool takes_self: Pass the partially initialized instance that is + being initialized as a positional argument. + + .. versionadded:: 17.1.0 *takes_self* + """ + + __slots__ = ("factory", "takes_self") + + def __init__(self, factory, takes_self=False): + """ + `Factory` is part of the default machinery so if we want a default + value here, we have to implement it ourselves. + """ + self.factory = factory + self.takes_self = takes_self + + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple(getattr(self, name) for name in self.__slots__) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + for name, value in zip(self.__slots__, state): + setattr(self, name, value) + + +_f = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=True, + init=True, + inherited=False, + ) + for name in Factory.__slots__ +] + +Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) + + +def make_class(name, attrs, bases=(object,), **attributes_arguments): + """ + A quick way to create a new class called *name* with *attrs*. + + :param str name: The name for the new class. + + :param attrs: A list of names or a dictionary of mappings of names to + attributes. + + If *attrs* is a list or an ordered dict (`dict` on Python 3.6+, + `collections.OrderedDict` otherwise), the order is deduced from + the order of the names or attributes inside *attrs*. Otherwise the + order of the definition of the attributes is used. + :type attrs: `list` or `dict` + + :param tuple bases: Classes that the new class will subclass. + + :param attributes_arguments: Passed unmodified to `attr.s`. + + :return: A new class with *attrs*. + :rtype: type + + .. versionadded:: 17.1.0 *bases* + .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. + """ + if isinstance(attrs, dict): + cls_dict = attrs + elif isinstance(attrs, (list, tuple)): + cls_dict = dict((a, attrib()) for a in attrs) + else: + raise TypeError("attrs argument must be a dict or a list.") + + pre_init = cls_dict.pop("__attrs_pre_init__", None) + post_init = cls_dict.pop("__attrs_post_init__", None) + user_init = cls_dict.pop("__init__", None) + + body = {} + if pre_init is not None: + body["__attrs_pre_init__"] = pre_init + if post_init is not None: + body["__attrs_post_init__"] = post_init + if user_init is not None: + body["__init__"] = user_init + + type_ = new_class(name, bases, {}, lambda ns: ns.update(body)) + + # For pickling to work, the __module__ variable needs to be set to the + # frame where the class is created. Bypass this step in environments where + # sys._getframe is not defined (Jython for example) or sys._getframe is not + # defined for arguments greater than 0 (IronPython). + try: + type_.__module__ = sys._getframe(1).f_globals.get( + "__name__", "__main__" + ) + except (AttributeError, ValueError): + pass + + # We do it here for proper warnings with meaningful stacklevel. + cmp = attributes_arguments.pop("cmp", None) + ( + attributes_arguments["eq"], + attributes_arguments["order"], + ) = _determine_attrs_eq_order( + cmp, + attributes_arguments.get("eq"), + attributes_arguments.get("order"), + True, + ) + + return _attrs(these=cls_dict, **attributes_arguments)(type_) + + +# These are required by within this module so we define them here and merely +# import into .validators / .converters. + + +@attrs(slots=True, hash=True) +class _AndValidator(object): + """ + Compose many validators to a single one. + """ + + _validators = attrib() + + def __call__(self, inst, attr, value): + for v in self._validators: + v(inst, attr, value) + + +def and_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators. + + :param callables validators: Arbitrary number of validators. + + .. versionadded:: 17.1.0 + """ + vals = [] + for validator in validators: + vals.extend( + validator._validators + if isinstance(validator, _AndValidator) + else [validator] + ) + + return _AndValidator(tuple(vals)) + + +def pipe(*converters): + """ + A converter that composes multiple converters into one. + + When called on a value, it runs all wrapped converters, returning the + *last* value. + + Type annotations will be inferred from the wrapped converters', if + they have any. + + :param callables converters: Arbitrary number of converters. + + .. versionadded:: 20.1.0 + """ + + def pipe_converter(val): + for converter in converters: + val = converter(val) + + return val + + if not PY2: + if not converters: + # If the converter list is empty, pipe_converter is the identity. + A = typing.TypeVar("A") + pipe_converter.__annotations__ = {"val": A, "return": A} + else: + # Get parameter type. + sig = None + try: + sig = inspect.signature(converters[0]) + except (ValueError, TypeError): # inspect failed + pass + if sig: + params = list(sig.parameters.values()) + if ( + params + and params[0].annotation is not inspect.Parameter.empty + ): + pipe_converter.__annotations__["val"] = params[ + 0 + ].annotation + # Get return type. + sig = None + try: + sig = inspect.signature(converters[-1]) + except (ValueError, TypeError): # inspect failed + pass + if sig and sig.return_annotation is not inspect.Signature().empty: + pipe_converter.__annotations__[ + "return" + ] = sig.return_annotation + + return pipe_converter diff --git a/openpype/vendor/python/python_2/attr/_next_gen.py b/openpype/vendor/python/python_2/attr/_next_gen.py new file mode 100644 index 0000000000..068253688c --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_next_gen.py @@ -0,0 +1,216 @@ +# SPDX-License-Identifier: MIT + +""" +These are Python 3.6+-only and keyword-only APIs that call `attr.s` and +`attr.ib` with different default values. +""" + + +from functools import partial + +from . import setters +from ._funcs import asdict as _asdict +from ._funcs import astuple as _astuple +from ._make import ( + NOTHING, + _frozen_setattrs, + _ng_default_on_setattr, + attrib, + attrs, +) +from .exceptions import UnannotatedAttributeError + + +def define( + maybe_cls=None, + *, + these=None, + repr=None, + hash=None, + init=None, + slots=True, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=None, + kw_only=False, + cache_hash=False, + auto_exc=True, + eq=None, + order=False, + auto_detect=True, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, +): + r""" + Define an ``attrs`` class. + + Differences to the classic `attr.s` that it uses underneath: + + - Automatically detect whether or not *auto_attribs* should be `True` + (c.f. *auto_attribs* parameter). + - If *frozen* is `False`, run converters and validators when setting an + attribute by default. + - *slots=True* (see :term:`slotted classes` for potentially surprising + behaviors) + - *auto_exc=True* + - *auto_detect=True* + - *order=False* + - *match_args=True* + - Some options that were only relevant on Python 2 or were kept around for + backwards-compatibility have been removed. + + Please note that these are all defaults and you can change them as you + wish. + + :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves + exactly like `attr.s`. If left `None`, `attr.s` will try to guess: + + 1. If any attributes are annotated and no unannotated `attrs.fields`\ s + are found, it assumes *auto_attribs=True*. + 2. Otherwise it assumes *auto_attribs=False* and tries to collect + `attrs.fields`\ s. + + For now, please refer to `attr.s` for the rest of the parameters. + + .. versionadded:: 20.1.0 + .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. + """ + + def do_it(cls, auto_attribs): + return attrs( + maybe_cls=cls, + these=these, + repr=repr, + hash=hash, + init=init, + slots=slots, + frozen=frozen, + weakref_slot=weakref_slot, + str=str, + auto_attribs=auto_attribs, + kw_only=kw_only, + cache_hash=cache_hash, + auto_exc=auto_exc, + eq=eq, + order=order, + auto_detect=auto_detect, + collect_by_mro=True, + getstate_setstate=getstate_setstate, + on_setattr=on_setattr, + field_transformer=field_transformer, + match_args=match_args, + ) + + def wrap(cls): + """ + Making this a wrapper ensures this code runs during class creation. + + We also ensure that frozen-ness of classes is inherited. + """ + nonlocal frozen, on_setattr + + had_on_setattr = on_setattr not in (None, setters.NO_OP) + + # By default, mutable classes convert & validate on setattr. + if frozen is False and on_setattr is None: + on_setattr = _ng_default_on_setattr + + # However, if we subclass a frozen class, we inherit the immutability + # and disable on_setattr. + for base_cls in cls.__bases__: + if base_cls.__setattr__ is _frozen_setattrs: + if had_on_setattr: + raise ValueError( + "Frozen classes can't use on_setattr " + "(frozen-ness was inherited)." + ) + + on_setattr = setters.NO_OP + break + + if auto_attribs is not None: + return do_it(cls, auto_attribs) + + try: + return do_it(cls, True) + except UnannotatedAttributeError: + return do_it(cls, False) + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but ``None`` if used as `@attrs()`. + if maybe_cls is None: + return wrap + else: + return wrap(maybe_cls) + + +mutable = define +frozen = partial(define, frozen=True, on_setattr=None) + + +def field( + *, + default=NOTHING, + validator=None, + repr=True, + hash=None, + init=True, + metadata=None, + converter=None, + factory=None, + kw_only=False, + eq=None, + order=None, + on_setattr=None, +): + """ + Identical to `attr.ib`, except keyword-only and with some arguments + removed. + + .. versionadded:: 20.1.0 + """ + return attrib( + default=default, + validator=validator, + repr=repr, + hash=hash, + init=init, + metadata=metadata, + converter=converter, + factory=factory, + kw_only=kw_only, + eq=eq, + order=order, + on_setattr=on_setattr, + ) + + +def asdict(inst, *, recurse=True, filter=None, value_serializer=None): + """ + Same as `attr.asdict`, except that collections types are always retained + and dict is always used as *dict_factory*. + + .. versionadded:: 21.3.0 + """ + return _asdict( + inst=inst, + recurse=recurse, + filter=filter, + value_serializer=value_serializer, + retain_collection_types=True, + ) + + +def astuple(inst, *, recurse=True, filter=None): + """ + Same as `attr.astuple`, except that collections types are always retained + and `tuple` is always used as the *tuple_factory*. + + .. versionadded:: 21.3.0 + """ + return _astuple( + inst=inst, recurse=recurse, filter=filter, retain_collection_types=True + ) diff --git a/openpype/vendor/python/python_2/attr/_version_info.py b/openpype/vendor/python/python_2/attr/_version_info.py new file mode 100644 index 0000000000..cdaeec37a1 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_version_info.py @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +from functools import total_ordering + +from ._funcs import astuple +from ._make import attrib, attrs + + +@total_ordering +@attrs(eq=False, order=False, slots=True, frozen=True) +class VersionInfo(object): + """ + A version object that can be compared to tuple of length 1--4: + + >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) + True + >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) + True + >>> vi = attr.VersionInfo(19, 2, 0, "final") + >>> vi < (19, 1, 1) + False + >>> vi < (19,) + False + >>> vi == (19, 2,) + True + >>> vi == (19, 2, 1) + False + + .. versionadded:: 19.2 + """ + + year = attrib(type=int) + minor = attrib(type=int) + micro = attrib(type=int) + releaselevel = attrib(type=str) + + @classmethod + def _from_version_string(cls, s): + """ + Parse *s* and return a _VersionInfo. + """ + v = s.split(".") + if len(v) == 3: + v.append("final") + + return cls( + year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] + ) + + def _ensure_tuple(self, other): + """ + Ensure *other* is a tuple of a valid length. + + Returns a possibly transformed *other* and ourselves as a tuple of + the same length as *other*. + """ + + if self.__class__ is other.__class__: + other = astuple(other) + + if not isinstance(other, tuple): + raise NotImplementedError + + if not (1 <= len(other) <= 4): + raise NotImplementedError + + return astuple(self)[: len(other)], other + + def __eq__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + return us == them + + def __lt__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't + # have to do anything special with releaselevel for now. + return us < them diff --git a/openpype/vendor/python/python_2/attr/_version_info.pyi b/openpype/vendor/python/python_2/attr/_version_info.pyi new file mode 100644 index 0000000000..45ced08633 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/_version_info.pyi @@ -0,0 +1,9 @@ +class VersionInfo: + @property + def year(self) -> int: ... + @property + def minor(self) -> int: ... + @property + def micro(self) -> int: ... + @property + def releaselevel(self) -> str: ... diff --git a/openpype/vendor/python/python_2/attr/converters.py b/openpype/vendor/python/python_2/attr/converters.py new file mode 100644 index 0000000000..1fb6c05d7b --- /dev/null +++ b/openpype/vendor/python/python_2/attr/converters.py @@ -0,0 +1,155 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful converters. +""" + +from __future__ import absolute_import, division, print_function + +from ._compat import PY2 +from ._make import NOTHING, Factory, pipe + + +if not PY2: + import inspect + import typing + + +__all__ = [ + "default_if_none", + "optional", + "pipe", + "to_bool", +] + + +def optional(converter): + """ + A converter that allows an attribute to be optional. An optional attribute + is one which can be set to ``None``. + + Type annotations will be inferred from the wrapped converter's, if it + has any. + + :param callable converter: the converter that is used for non-``None`` + values. + + .. versionadded:: 17.1.0 + """ + + def optional_converter(val): + if val is None: + return None + return converter(val) + + if not PY2: + sig = None + try: + sig = inspect.signature(converter) + except (ValueError, TypeError): # inspect failed + pass + if sig: + params = list(sig.parameters.values()) + if params and params[0].annotation is not inspect.Parameter.empty: + optional_converter.__annotations__["val"] = typing.Optional[ + params[0].annotation + ] + if sig.return_annotation is not inspect.Signature.empty: + optional_converter.__annotations__["return"] = typing.Optional[ + sig.return_annotation + ] + + return optional_converter + + +def default_if_none(default=NOTHING, factory=None): + """ + A converter that allows to replace ``None`` values by *default* or the + result of *factory*. + + :param default: Value to be used if ``None`` is passed. Passing an instance + of `attrs.Factory` is supported, however the ``takes_self`` option + is *not*. + :param callable factory: A callable that takes no parameters whose result + is used if ``None`` is passed. + + :raises TypeError: If **neither** *default* or *factory* is passed. + :raises TypeError: If **both** *default* and *factory* are passed. + :raises ValueError: If an instance of `attrs.Factory` is passed with + ``takes_self=True``. + + .. versionadded:: 18.2.0 + """ + if default is NOTHING and factory is None: + raise TypeError("Must pass either `default` or `factory`.") + + if default is not NOTHING and factory is not None: + raise TypeError( + "Must pass either `default` or `factory` but not both." + ) + + if factory is not None: + default = Factory(factory) + + if isinstance(default, Factory): + if default.takes_self: + raise ValueError( + "`takes_self` is not supported by default_if_none." + ) + + def default_if_none_converter(val): + if val is not None: + return val + + return default.factory() + + else: + + def default_if_none_converter(val): + if val is not None: + return val + + return default + + return default_if_none_converter + + +def to_bool(val): + """ + Convert "boolean" strings (e.g., from env. vars.) to real booleans. + + Values mapping to :code:`True`: + + - :code:`True` + - :code:`"true"` / :code:`"t"` + - :code:`"yes"` / :code:`"y"` + - :code:`"on"` + - :code:`"1"` + - :code:`1` + + Values mapping to :code:`False`: + + - :code:`False` + - :code:`"false"` / :code:`"f"` + - :code:`"no"` / :code:`"n"` + - :code:`"off"` + - :code:`"0"` + - :code:`0` + + :raises ValueError: for any other value. + + .. versionadded:: 21.3.0 + """ + if isinstance(val, str): + val = val.lower() + truthy = {True, "true", "t", "yes", "y", "on", "1", 1} + falsy = {False, "false", "f", "no", "n", "off", "0", 0} + try: + if val in truthy: + return True + if val in falsy: + return False + except TypeError: + # Raised when "val" is not hashable (e.g., lists) + pass + raise ValueError("Cannot convert value to bool: {}".format(val)) diff --git a/openpype/vendor/python/python_2/attr/converters.pyi b/openpype/vendor/python/python_2/attr/converters.pyi new file mode 100644 index 0000000000..0f58088a37 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/converters.pyi @@ -0,0 +1,13 @@ +from typing import Callable, Optional, TypeVar, overload + +from . import _ConverterType + +_T = TypeVar("_T") + +def pipe(*validators: _ConverterType) -> _ConverterType: ... +def optional(converter: _ConverterType) -> _ConverterType: ... +@overload +def default_if_none(default: _T) -> _ConverterType: ... +@overload +def default_if_none(*, factory: Callable[[], _T]) -> _ConverterType: ... +def to_bool(val: str) -> bool: ... diff --git a/openpype/vendor/python/python_2/attr/exceptions.py b/openpype/vendor/python/python_2/attr/exceptions.py new file mode 100644 index 0000000000..b2f1edc32a --- /dev/null +++ b/openpype/vendor/python/python_2/attr/exceptions.py @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +class FrozenError(AttributeError): + """ + A frozen/immutable instance or attribute have been attempted to be + modified. + + It mirrors the behavior of ``namedtuples`` by using the same error message + and subclassing `AttributeError`. + + .. versionadded:: 20.1.0 + """ + + msg = "can't set attribute" + args = [msg] + + +class FrozenInstanceError(FrozenError): + """ + A frozen instance has been attempted to be modified. + + .. versionadded:: 16.1.0 + """ + + +class FrozenAttributeError(FrozenError): + """ + A frozen attribute has been attempted to be modified. + + .. versionadded:: 20.1.0 + """ + + +class AttrsAttributeNotFoundError(ValueError): + """ + An ``attrs`` function couldn't find an attribute that the user asked for. + + .. versionadded:: 16.2.0 + """ + + +class NotAnAttrsClassError(ValueError): + """ + A non-``attrs`` class has been passed into an ``attrs`` function. + + .. versionadded:: 16.2.0 + """ + + +class DefaultAlreadySetError(RuntimeError): + """ + A default has been set using ``attr.ib()`` and is attempted to be reset + using the decorator. + + .. versionadded:: 17.1.0 + """ + + +class UnannotatedAttributeError(RuntimeError): + """ + A class with ``auto_attribs=True`` has an ``attr.ib()`` without a type + annotation. + + .. versionadded:: 17.3.0 + """ + + +class PythonTooOldError(RuntimeError): + """ + It was attempted to use an ``attrs`` feature that requires a newer Python + version. + + .. versionadded:: 18.2.0 + """ + + +class NotCallableError(TypeError): + """ + A ``attr.ib()`` requiring a callable has been set with a value + that is not callable. + + .. versionadded:: 19.2.0 + """ + + def __init__(self, msg, value): + super(TypeError, self).__init__(msg, value) + self.msg = msg + self.value = value + + def __str__(self): + return str(self.msg) diff --git a/openpype/vendor/python/python_2/attr/exceptions.pyi b/openpype/vendor/python/python_2/attr/exceptions.pyi new file mode 100644 index 0000000000..f2680118b4 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/exceptions.pyi @@ -0,0 +1,17 @@ +from typing import Any + +class FrozenError(AttributeError): + msg: str = ... + +class FrozenInstanceError(FrozenError): ... +class FrozenAttributeError(FrozenError): ... +class AttrsAttributeNotFoundError(ValueError): ... +class NotAnAttrsClassError(ValueError): ... +class DefaultAlreadySetError(RuntimeError): ... +class UnannotatedAttributeError(RuntimeError): ... +class PythonTooOldError(RuntimeError): ... + +class NotCallableError(TypeError): + msg: str = ... + value: Any = ... + def __init__(self, msg: str, value: Any) -> None: ... diff --git a/openpype/vendor/python/python_2/attr/filters.py b/openpype/vendor/python/python_2/attr/filters.py new file mode 100644 index 0000000000..a1978a8775 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/filters.py @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful filters for `attr.asdict`. +""" + +from __future__ import absolute_import, division, print_function + +from ._compat import isclass +from ._make import Attribute + + +def _split_what(what): + """ + Returns a tuple of `frozenset`s of classes and attributes. + """ + return ( + frozenset(cls for cls in what if isclass(cls)), + frozenset(cls for cls in what if isinstance(cls, Attribute)), + ) + + +def include(*what): + """ + Include *what*. + + :param what: What to include. + :type what: `list` of `type` or `attrs.Attribute`\\ s + + :rtype: `callable` + """ + cls, attrs = _split_what(what) + + def include_(attribute, value): + return value.__class__ in cls or attribute in attrs + + return include_ + + +def exclude(*what): + """ + Exclude *what*. + + :param what: What to exclude. + :type what: `list` of classes or `attrs.Attribute`\\ s. + + :rtype: `callable` + """ + cls, attrs = _split_what(what) + + def exclude_(attribute, value): + return value.__class__ not in cls and attribute not in attrs + + return exclude_ diff --git a/openpype/vendor/python/python_2/attr/filters.pyi b/openpype/vendor/python/python_2/attr/filters.pyi new file mode 100644 index 0000000000..993866865e --- /dev/null +++ b/openpype/vendor/python/python_2/attr/filters.pyi @@ -0,0 +1,6 @@ +from typing import Any, Union + +from . import Attribute, _FilterType + +def include(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ... +def exclude(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ... diff --git a/openpype/vendor/python/python_2/attr/py.typed b/openpype/vendor/python/python_2/attr/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/attr/setters.py b/openpype/vendor/python/python_2/attr/setters.py new file mode 100644 index 0000000000..b1cbb5d83e --- /dev/null +++ b/openpype/vendor/python/python_2/attr/setters.py @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly used hooks for on_setattr. +""" + +from __future__ import absolute_import, division, print_function + +from . import _config +from .exceptions import FrozenAttributeError + + +def pipe(*setters): + """ + Run all *setters* and return the return value of the last one. + + .. versionadded:: 20.1.0 + """ + + def wrapped_pipe(instance, attrib, new_value): + rv = new_value + + for setter in setters: + rv = setter(instance, attrib, rv) + + return rv + + return wrapped_pipe + + +def frozen(_, __, ___): + """ + Prevent an attribute to be modified. + + .. versionadded:: 20.1.0 + """ + raise FrozenAttributeError() + + +def validate(instance, attrib, new_value): + """ + Run *attrib*'s validator on *new_value* if it has one. + + .. versionadded:: 20.1.0 + """ + if _config._run_validators is False: + return new_value + + v = attrib.validator + if not v: + return new_value + + v(instance, attrib, new_value) + + return new_value + + +def convert(instance, attrib, new_value): + """ + Run *attrib*'s converter -- if it has one -- on *new_value* and return the + result. + + .. versionadded:: 20.1.0 + """ + c = attrib.converter + if c: + return c(new_value) + + return new_value + + +NO_OP = object() +""" +Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. + +Does not work in `pipe` or within lists. + +.. versionadded:: 20.1.0 +""" diff --git a/openpype/vendor/python/python_2/attr/setters.pyi b/openpype/vendor/python/python_2/attr/setters.pyi new file mode 100644 index 0000000000..3f5603c2b0 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/setters.pyi @@ -0,0 +1,19 @@ +from typing import Any, NewType, NoReturn, TypeVar, cast + +from . import Attribute, _OnSetAttrType + +_T = TypeVar("_T") + +def frozen( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> NoReturn: ... +def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... +def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... + +# convert is allowed to return Any, because they can be chained using pipe. +def convert( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> Any: ... + +_NoOpType = NewType("_NoOpType", object) +NO_OP: _NoOpType diff --git a/openpype/vendor/python/python_2/attr/validators.py b/openpype/vendor/python/python_2/attr/validators.py new file mode 100644 index 0000000000..0b0c8342f2 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/validators.py @@ -0,0 +1,561 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful validators. +""" + +from __future__ import absolute_import, division, print_function + +import operator +import re + +from contextlib import contextmanager + +from ._config import get_run_validators, set_run_validators +from ._make import _AndValidator, and_, attrib, attrs +from .exceptions import NotCallableError + + +try: + Pattern = re.Pattern +except AttributeError: # Python <3.7 lacks a Pattern type. + Pattern = type(re.compile("")) + + +__all__ = [ + "and_", + "deep_iterable", + "deep_mapping", + "disabled", + "ge", + "get_disabled", + "gt", + "in_", + "instance_of", + "is_callable", + "le", + "lt", + "matches_re", + "max_len", + "optional", + "provides", + "set_disabled", +] + + +def set_disabled(disabled): + """ + Globally disable or enable running validators. + + By default, they are run. + + :param disabled: If ``True``, disable running all validators. + :type disabled: bool + + .. warning:: + + This function is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(not disabled) + + +def get_disabled(): + """ + Return a bool indicating whether validators are currently disabled or not. + + :return: ``True`` if validators are currently disabled. + :rtype: bool + + .. versionadded:: 21.3.0 + """ + return not get_run_validators() + + +@contextmanager +def disabled(): + """ + Context manager that disables running validators within its context. + + .. warning:: + + This context manager is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(False) + try: + yield + finally: + set_run_validators(True) + + +@attrs(repr=False, slots=True, hash=True) +class _InstanceOfValidator(object): + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not isinstance(value, self.type): + raise TypeError( + "'{name}' must be {type!r} (got {value!r} that is a " + "{actual!r}).".format( + name=attr.name, + type=self.type, + actual=value.__class__, + value=value, + ), + attr, + self.type, + value, + ) + + def __repr__(self): + return "".format( + type=self.type + ) + + +def instance_of(type): + """ + A validator that raises a `TypeError` if the initializer is called + with a wrong type for this particular attribute (checks are performed using + `isinstance` therefore it's also valid to pass a tuple of types). + + :param type: The type to check for. + :type type: type or tuple of types + + :raises TypeError: With a human readable error message, the attribute + (of type `attrs.Attribute`), the expected type, and the value it + got. + """ + return _InstanceOfValidator(type) + + +@attrs(repr=False, frozen=True, slots=True) +class _MatchesReValidator(object): + pattern = attrib() + match_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.match_func(value): + raise ValueError( + "'{name}' must match regex {pattern!r}" + " ({value!r} doesn't)".format( + name=attr.name, pattern=self.pattern.pattern, value=value + ), + attr, + self.pattern, + value, + ) + + def __repr__(self): + return "".format( + pattern=self.pattern + ) + + +def matches_re(regex, flags=0, func=None): + r""" + A validator that raises `ValueError` if the initializer is called + with a string that doesn't match *regex*. + + :param regex: a regex string or precompiled pattern to match against + :param int flags: flags that will be passed to the underlying re function + (default 0) + :param callable func: which underlying `re` function to call (options + are `re.fullmatch`, `re.search`, `re.match`, default + is ``None`` which means either `re.fullmatch` or an emulation of + it on Python 2). For performance reasons, they won't be used directly + but on a pre-`re.compile`\ ed pattern. + + .. versionadded:: 19.2.0 + .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. + """ + fullmatch = getattr(re, "fullmatch", None) + valid_funcs = (fullmatch, None, re.search, re.match) + if func not in valid_funcs: + raise ValueError( + "'func' must be one of {}.".format( + ", ".join( + sorted( + e and e.__name__ or "None" for e in set(valid_funcs) + ) + ) + ) + ) + + if isinstance(regex, Pattern): + if flags: + raise TypeError( + "'flags' can only be used with a string pattern; " + "pass flags to re.compile() instead" + ) + pattern = regex + else: + pattern = re.compile(regex, flags) + + if func is re.match: + match_func = pattern.match + elif func is re.search: + match_func = pattern.search + elif fullmatch: + match_func = pattern.fullmatch + else: # Python 2 fullmatch emulation (https://bugs.python.org/issue16203) + pattern = re.compile( + r"(?:{})\Z".format(pattern.pattern), pattern.flags + ) + match_func = pattern.match + + return _MatchesReValidator(pattern, match_func) + + +@attrs(repr=False, slots=True, hash=True) +class _ProvidesValidator(object): + interface = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.interface.providedBy(value): + raise TypeError( + "'{name}' must provide {interface!r} which {value!r} " + "doesn't.".format( + name=attr.name, interface=self.interface, value=value + ), + attr, + self.interface, + value, + ) + + def __repr__(self): + return "".format( + interface=self.interface + ) + + +def provides(interface): + """ + A validator that raises a `TypeError` if the initializer is called + with an object that does not provide the requested *interface* (checks are + performed using ``interface.providedBy(value)`` (see `zope.interface + `_). + + :param interface: The interface to check for. + :type interface: ``zope.interface.Interface`` + + :raises TypeError: With a human readable error message, the attribute + (of type `attrs.Attribute`), the expected interface, and the + value it got. + """ + return _ProvidesValidator(interface) + + +@attrs(repr=False, slots=True, hash=True) +class _OptionalValidator(object): + validator = attrib() + + def __call__(self, inst, attr, value): + if value is None: + return + + self.validator(inst, attr, value) + + def __repr__(self): + return "".format( + what=repr(self.validator) + ) + + +def optional(validator): + """ + A validator that makes an attribute optional. An optional attribute is one + which can be set to ``None`` in addition to satisfying the requirements of + the sub-validator. + + :param validator: A validator (or a list of validators) that is used for + non-``None`` values. + :type validator: callable or `list` of callables. + + .. versionadded:: 15.1.0 + .. versionchanged:: 17.1.0 *validator* can be a list of validators. + """ + if isinstance(validator, list): + return _OptionalValidator(_AndValidator(validator)) + return _OptionalValidator(validator) + + +@attrs(repr=False, slots=True, hash=True) +class _InValidator(object): + options = attrib() + + def __call__(self, inst, attr, value): + try: + in_options = value in self.options + except TypeError: # e.g. `1 in "abc"` + in_options = False + + if not in_options: + raise ValueError( + "'{name}' must be in {options!r} (got {value!r})".format( + name=attr.name, options=self.options, value=value + ) + ) + + def __repr__(self): + return "".format( + options=self.options + ) + + +def in_(options): + """ + A validator that raises a `ValueError` if the initializer is called + with a value that does not belong in the options provided. The check is + performed using ``value in options``. + + :param options: Allowed options. + :type options: list, tuple, `enum.Enum`, ... + + :raises ValueError: With a human readable error message, the attribute (of + type `attrs.Attribute`), the expected options, and the value it + got. + + .. versionadded:: 17.1.0 + """ + return _InValidator(options) + + +@attrs(repr=False, slots=False, hash=True) +class _IsCallableValidator(object): + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not callable(value): + message = ( + "'{name}' must be callable " + "(got {value!r} that is a {actual!r})." + ) + raise NotCallableError( + msg=message.format( + name=attr.name, value=value, actual=value.__class__ + ), + value=value, + ) + + def __repr__(self): + return "" + + +def is_callable(): + """ + A validator that raises a `attr.exceptions.NotCallableError` if the + initializer is called with a value for this particular attribute + that is not callable. + + .. versionadded:: 19.1.0 + + :raises `attr.exceptions.NotCallableError`: With a human readable error + message containing the attribute (`attrs.Attribute`) name, + and the value it got. + """ + return _IsCallableValidator() + + +@attrs(repr=False, slots=True, hash=True) +class _DeepIterable(object): + member_validator = attrib(validator=is_callable()) + iterable_validator = attrib( + default=None, validator=optional(is_callable()) + ) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.iterable_validator is not None: + self.iterable_validator(inst, attr, value) + + for member in value: + self.member_validator(inst, attr, member) + + def __repr__(self): + iterable_identifier = ( + "" + if self.iterable_validator is None + else " {iterable!r}".format(iterable=self.iterable_validator) + ) + return ( + "" + ).format( + iterable_identifier=iterable_identifier, + member=self.member_validator, + ) + + +def deep_iterable(member_validator, iterable_validator=None): + """ + A validator that performs deep validation of an iterable. + + :param member_validator: Validator to apply to iterable members + :param iterable_validator: Validator to apply to iterable itself + (optional) + + .. versionadded:: 19.1.0 + + :raises TypeError: if any sub-validators fail + """ + return _DeepIterable(member_validator, iterable_validator) + + +@attrs(repr=False, slots=True, hash=True) +class _DeepMapping(object): + key_validator = attrib(validator=is_callable()) + value_validator = attrib(validator=is_callable()) + mapping_validator = attrib(default=None, validator=optional(is_callable())) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.mapping_validator is not None: + self.mapping_validator(inst, attr, value) + + for key in value: + self.key_validator(inst, attr, key) + self.value_validator(inst, attr, value[key]) + + def __repr__(self): + return ( + "" + ).format(key=self.key_validator, value=self.value_validator) + + +def deep_mapping(key_validator, value_validator, mapping_validator=None): + """ + A validator that performs deep validation of a dictionary. + + :param key_validator: Validator to apply to dictionary keys + :param value_validator: Validator to apply to dictionary values + :param mapping_validator: Validator to apply to top-level mapping + attribute (optional) + + .. versionadded:: 19.1.0 + + :raises TypeError: if any sub-validators fail + """ + return _DeepMapping(key_validator, value_validator, mapping_validator) + + +@attrs(repr=False, frozen=True, slots=True) +class _NumberValidator(object): + bound = attrib() + compare_op = attrib() + compare_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.compare_func(value, self.bound): + raise ValueError( + "'{name}' must be {op} {bound}: {value}".format( + name=attr.name, + op=self.compare_op, + bound=self.bound, + value=value, + ) + ) + + def __repr__(self): + return "".format( + op=self.compare_op, bound=self.bound + ) + + +def lt(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number larger or equal to *val*. + + :param val: Exclusive upper bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<", operator.lt) + + +def le(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number greater than *val*. + + :param val: Inclusive upper bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<=", operator.le) + + +def ge(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number smaller than *val*. + + :param val: Inclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">=", operator.ge) + + +def gt(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number smaller or equal to *val*. + + :param val: Exclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">", operator.gt) + + +@attrs(repr=False, frozen=True, slots=True) +class _MaxLengthValidator(object): + max_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) > self.max_length: + raise ValueError( + "Length of '{name}' must be <= {max}: {len}".format( + name=attr.name, max=self.max_length, len=len(value) + ) + ) + + def __repr__(self): + return "".format(max=self.max_length) + + +def max_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is longer than *length*. + + :param int length: Maximum length of the string or iterable + + .. versionadded:: 21.3.0 + """ + return _MaxLengthValidator(length) diff --git a/openpype/vendor/python/python_2/attr/validators.pyi b/openpype/vendor/python/python_2/attr/validators.pyi new file mode 100644 index 0000000000..5e00b85433 --- /dev/null +++ b/openpype/vendor/python/python_2/attr/validators.pyi @@ -0,0 +1,78 @@ +from typing import ( + Any, + AnyStr, + Callable, + Container, + ContextManager, + Iterable, + List, + Mapping, + Match, + Optional, + Pattern, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +from . import _ValidatorType + +_T = TypeVar("_T") +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") +_T3 = TypeVar("_T3") +_I = TypeVar("_I", bound=Iterable) +_K = TypeVar("_K") +_V = TypeVar("_V") +_M = TypeVar("_M", bound=Mapping) + +def set_disabled(run: bool) -> None: ... +def get_disabled() -> bool: ... +def disabled() -> ContextManager[None]: ... + +# To be more precise on instance_of use some overloads. +# If there are more than 3 items in the tuple then we fall back to Any +@overload +def instance_of(type: Type[_T]) -> _ValidatorType[_T]: ... +@overload +def instance_of(type: Tuple[Type[_T]]) -> _ValidatorType[_T]: ... +@overload +def instance_of( + type: Tuple[Type[_T1], Type[_T2]] +) -> _ValidatorType[Union[_T1, _T2]]: ... +@overload +def instance_of( + type: Tuple[Type[_T1], Type[_T2], Type[_T3]] +) -> _ValidatorType[Union[_T1, _T2, _T3]]: ... +@overload +def instance_of(type: Tuple[type, ...]) -> _ValidatorType[Any]: ... +def provides(interface: Any) -> _ValidatorType[Any]: ... +def optional( + validator: Union[_ValidatorType[_T], List[_ValidatorType[_T]]] +) -> _ValidatorType[Optional[_T]]: ... +def in_(options: Container[_T]) -> _ValidatorType[_T]: ... +def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... +def matches_re( + regex: Union[Pattern[AnyStr], AnyStr], + flags: int = ..., + func: Optional[ + Callable[[AnyStr, AnyStr, int], Optional[Match[AnyStr]]] + ] = ..., +) -> _ValidatorType[AnyStr]: ... +def deep_iterable( + member_validator: _ValidatorType[_T], + iterable_validator: Optional[_ValidatorType[_I]] = ..., +) -> _ValidatorType[_I]: ... +def deep_mapping( + key_validator: _ValidatorType[_K], + value_validator: _ValidatorType[_V], + mapping_validator: Optional[_ValidatorType[_M]] = ..., +) -> _ValidatorType[_M]: ... +def is_callable() -> _ValidatorType[_T]: ... +def lt(val: _T) -> _ValidatorType[_T]: ... +def le(val: _T) -> _ValidatorType[_T]: ... +def ge(val: _T) -> _ValidatorType[_T]: ... +def gt(val: _T) -> _ValidatorType[_T]: ... +def max_len(length: int) -> _ValidatorType[_T]: ... diff --git a/openpype/vendor/python/python_2/attrs/__init__.py b/openpype/vendor/python/python_2/attrs/__init__.py new file mode 100644 index 0000000000..a704b8b56b --- /dev/null +++ b/openpype/vendor/python/python_2/attrs/__init__.py @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: MIT + +from attr import ( + NOTHING, + Attribute, + Factory, + __author__, + __copyright__, + __description__, + __doc__, + __email__, + __license__, + __title__, + __url__, + __version__, + __version_info__, + assoc, + cmp_using, + define, + evolve, + field, + fields, + fields_dict, + frozen, + has, + make_class, + mutable, + resolve_types, + validate, +) +from attr._next_gen import asdict, astuple + +from . import converters, exceptions, filters, setters, validators + + +__all__ = [ + "__author__", + "__copyright__", + "__description__", + "__doc__", + "__email__", + "__license__", + "__title__", + "__url__", + "__version__", + "__version_info__", + "asdict", + "assoc", + "astuple", + "Attribute", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "Factory", + "field", + "fields_dict", + "fields", + "filters", + "frozen", + "has", + "make_class", + "mutable", + "NOTHING", + "resolve_types", + "setters", + "validate", + "validators", +] diff --git a/openpype/vendor/python/python_2/attrs/__init__.pyi b/openpype/vendor/python/python_2/attrs/__init__.pyi new file mode 100644 index 0000000000..7426fa5ddb --- /dev/null +++ b/openpype/vendor/python/python_2/attrs/__init__.pyi @@ -0,0 +1,63 @@ +from typing import ( + Any, + Callable, + Dict, + Mapping, + Optional, + Sequence, + Tuple, + Type, +) + +# Because we need to type our own stuff, we have to make everything from +# attr explicitly public too. +from attr import __author__ as __author__ +from attr import __copyright__ as __copyright__ +from attr import __description__ as __description__ +from attr import __email__ as __email__ +from attr import __license__ as __license__ +from attr import __title__ as __title__ +from attr import __url__ as __url__ +from attr import __version__ as __version__ +from attr import __version_info__ as __version_info__ +from attr import _FilterType +from attr import assoc as assoc +from attr import Attribute as Attribute +from attr import define as define +from attr import evolve as evolve +from attr import Factory as Factory +from attr import exceptions as exceptions +from attr import field as field +from attr import fields as fields +from attr import fields_dict as fields_dict +from attr import frozen as frozen +from attr import has as has +from attr import make_class as make_class +from attr import mutable as mutable +from attr import NOTHING as NOTHING +from attr import resolve_types as resolve_types +from attr import setters as setters +from attr import validate as validate +from attr import validators as validators + +# TODO: see definition of attr.asdict/astuple +def asdict( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + dict_factory: Type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Optional[ + Callable[[type, Attribute[Any], Any], Any] + ] = ..., + tuple_keys: bool = ..., +) -> Dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + tuple_factory: Type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> Tuple[Any, ...]: ... diff --git a/openpype/vendor/python/python_2/attrs/converters.py b/openpype/vendor/python/python_2/attrs/converters.py new file mode 100644 index 0000000000..edfa8d3c16 --- /dev/null +++ b/openpype/vendor/python/python_2/attrs/converters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.converters import * # noqa diff --git a/openpype/vendor/python/python_2/attrs/exceptions.py b/openpype/vendor/python/python_2/attrs/exceptions.py new file mode 100644 index 0000000000..bd9efed202 --- /dev/null +++ b/openpype/vendor/python/python_2/attrs/exceptions.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.exceptions import * # noqa diff --git a/openpype/vendor/python/python_2/attrs/filters.py b/openpype/vendor/python/python_2/attrs/filters.py new file mode 100644 index 0000000000..52959005b0 --- /dev/null +++ b/openpype/vendor/python/python_2/attrs/filters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.filters import * # noqa diff --git a/openpype/vendor/python/python_2/attrs/py.typed b/openpype/vendor/python/python_2/attrs/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/vendor/python/python_2/attrs/setters.py b/openpype/vendor/python/python_2/attrs/setters.py new file mode 100644 index 0000000000..9b50770804 --- /dev/null +++ b/openpype/vendor/python/python_2/attrs/setters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.setters import * # noqa diff --git a/openpype/vendor/python/python_2/attrs/validators.py b/openpype/vendor/python/python_2/attrs/validators.py new file mode 100644 index 0000000000..ab2c9b3024 --- /dev/null +++ b/openpype/vendor/python/python_2/attrs/validators.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.validators import * # noqa From c6383837e0c094a4172c6895db768a3d3ccebc34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:00:46 +0200 Subject: [PATCH 161/282] :recycle: remove unnecessary type hint Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- igniter/bootstrap_repos.py | 1 - 1 file changed, 1 deletion(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index dfcca2cf33..c5003b062e 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -614,7 +614,6 @@ class OpenPypeVersion(semver.VersionInfo): return None all_versions.sort() - latest_version: OpenPypeVersion return all_versions[-1] @classmethod From e5b1cc59bdccc2175364ae24cdddb7eb40a7c2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Mon, 15 Aug 2022 17:37:40 +0200 Subject: [PATCH 162/282] :bug: missing comma Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/maya/plugins/publish/extract_look.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index cece8ee22b..67b5f2496b 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -45,7 +45,7 @@ def get_ocio_config_path(profile_folder): os.environ["OPENPYPE_ROOT"], "vendor", "bin", - "ocioconfig" + "ocioconfig", "OpenColorIOConfigs", profile_folder, "config.ocio" From 4193b54700c42405ffa22e5353985202ce858ee2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 18:36:33 +0200 Subject: [PATCH 163/282] added more information when auto sync is turned on/off --- .../event_sync_to_avalon.py | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/openpype/modules/ftrack/event_handlers_server/event_sync_to_avalon.py b/openpype/modules/ftrack/event_handlers_server/event_sync_to_avalon.py index a4e791aaf0..738181dc9a 100644 --- a/openpype/modules/ftrack/event_handlers_server/event_sync_to_avalon.py +++ b/openpype/modules/ftrack/event_handlers_server/event_sync_to_avalon.py @@ -697,13 +697,22 @@ class SyncToAvalonEvent(BaseEvent): continue auto_sync = changes[CUST_ATTR_AUTO_SYNC]["new"] - if auto_sync == "1": + turned_on = auto_sync == "1" + ft_project = self.cur_project + username = self._get_username(session, event) + message = ( + "Auto sync was turned {} for project \"{}\" by \"{}\"." + ).format( + "on" if turned_on else "off", + ft_project["full_name"], + username + ) + if turned_on: + message += " Triggering syncToAvalon action." + self.log.debug(message) + + if turned_on: # Trigger sync to avalon action if auto sync was turned on - ft_project = self.cur_project - self.log.debug(( - "Auto sync was turned on for project <{}>." - " Triggering syncToAvalon action." - ).format(ft_project["full_name"])) selection = [{ "entityId": ft_project["id"], "entityType": "show" @@ -851,6 +860,26 @@ class SyncToAvalonEvent(BaseEvent): self.report() return True + def _get_username(self, session, event): + username = "Unknown" + event_source = event.get("source") + if not event_source: + return username + user_info = event_source.get("user") + if not user_info: + return username + user_id = user_info.get("id") + if not user_id: + return username + + user_entity = session.query( + "User where id is {}".format(user_id) + ).first() + if user_entity: + username = user_entity["username"] or username + return username + + def process_removed(self): """ Handles removed entities (not removed tasks - handle separately). From 61e8d7e9f1fbffd91e268ef3ff721cc136395f27 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 19:14:01 +0200 Subject: [PATCH 164/282] use 'get_projects' instead of 'projects' method on AvalonMongoDB --- .../modules/kitsu/utils/update_zou_with_op.py | 8 +++- .../modules/sync_server/sync_server_module.py | 9 ++-- openpype/tools/launcher/models.py | 3 +- openpype/tools/libraryloader/app.py | 4 +- .../project_manager/project_manager/model.py | 7 +--- openpype/tools/sceneinventory/window.py | 6 +-- openpype/tools/utils/models.py | 41 ++++++++++--------- 7 files changed, 39 insertions(+), 39 deletions(-) diff --git a/openpype/modules/kitsu/utils/update_zou_with_op.py b/openpype/modules/kitsu/utils/update_zou_with_op.py index 57d7094e95..da924aa5ee 100644 --- a/openpype/modules/kitsu/utils/update_zou_with_op.py +++ b/openpype/modules/kitsu/utils/update_zou_with_op.py @@ -6,7 +6,11 @@ from typing import List import gazu from pymongo import UpdateOne -from openpype.client import get_project, get_assets +from openpype.client import ( + get_projects, + get_project, + get_assets, +) from openpype.pipeline import AvalonMongoDB from openpype.api import get_project_settings from openpype.modules.kitsu.utils.credentials import validate_credentials @@ -37,7 +41,7 @@ def sync_zou(login: str, password: str): dbcon = AvalonMongoDB() dbcon.install() - op_projects = [p for p in dbcon.projects()] + op_projects = list(get_projects()) for project_doc in op_projects: sync_zou_from_op_project(project_doc["name"], dbcon, project_doc) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index 8fdfab9c2e..c7f9484e55 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -6,7 +6,7 @@ import platform import copy from collections import deque, defaultdict - +from openpype.client import get_projects from openpype.modules import OpenPypeModule from openpype_interfaces import ITrayModule from openpype.settings import ( @@ -913,7 +913,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): enabled_projects = [] if self.enabled: - for project in self.connection.projects(projection={"name": 1}): + for project in get_projects(fields=["name"]): project_name = project["name"] if self.is_project_enabled(project_name): enabled_projects.append(project_name) @@ -1242,10 +1242,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule): def _prepare_sync_project_settings(self, exclude_locals): sync_project_settings = {} system_sites = self.get_all_site_configs() - project_docs = self.connection.projects( - projection={"name": 1}, - only_active=True - ) + project_docs = get_projects(fields=["name"]) for project_doc in project_docs: project_name = project_doc["name"] sites = copy.deepcopy(system_sites) # get all configured sites diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py index 3f899cc05e..6d40d21f96 100644 --- a/openpype/tools/launcher/models.py +++ b/openpype/tools/launcher/models.py @@ -10,6 +10,7 @@ from Qt import QtCore, QtGui import qtawesome from openpype.client import ( + get_projects, get_project, get_assets, ) @@ -527,7 +528,7 @@ class LauncherModel(QtCore.QObject): current_project = self.project_name project_names = set() project_docs_by_name = {} - for project_doc in self._dbcon.projects(only_active=True): + for project_doc in get_projects(): project_name = project_doc["name"] project_names.add(project_name) project_docs_by_name[project_name] = project_doc diff --git a/openpype/tools/libraryloader/app.py b/openpype/tools/libraryloader/app.py index 5f4d10d796..d2af1b7151 100644 --- a/openpype/tools/libraryloader/app.py +++ b/openpype/tools/libraryloader/app.py @@ -3,7 +3,7 @@ import sys from Qt import QtWidgets, QtCore, QtGui from openpype import style -from openpype.client import get_project +from openpype.client import get_projects, get_project from openpype.pipeline import AvalonMongoDB from openpype.tools.utils import lib as tools_lib from openpype.tools.loader.widgets import ( @@ -239,7 +239,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog): def get_filtered_projects(self): projects = list() - for project in self.dbcon.projects(): + for project in get_projects(fields=["name", "data.library_project"]): is_library = project.get("data", {}).get("library_project", False) if ( (is_library and self.show_libraries) or diff --git a/openpype/tools/project_manager/project_manager/model.py b/openpype/tools/project_manager/project_manager/model.py index c5bde5aaec..3aaee75698 100644 --- a/openpype/tools/project_manager/project_manager/model.py +++ b/openpype/tools/project_manager/project_manager/model.py @@ -8,6 +8,7 @@ from pymongo import UpdateOne, DeleteOne from Qt import QtCore, QtGui from openpype.client import ( + get_projects, get_project, get_assets, get_asset_ids_with_subsets, @@ -54,12 +55,8 @@ class ProjectModel(QtGui.QStandardItemModel): self._items_by_name[None] = none_project new_project_items.append(none_project) - project_docs = self.dbcon.projects( - projection={"name": 1}, - only_active=True - ) project_names = set() - for project_doc in project_docs: + for project_doc in get_projects(fields=["name"]): project_name = project_doc.get("name") if not project_name: continue diff --git a/openpype/tools/sceneinventory/window.py b/openpype/tools/sceneinventory/window.py index 054c2a2daa..463280b71c 100644 --- a/openpype/tools/sceneinventory/window.py +++ b/openpype/tools/sceneinventory/window.py @@ -4,8 +4,9 @@ import sys from Qt import QtWidgets, QtCore import qtawesome -from openpype.pipeline import legacy_io from openpype import style +from openpype.client import get_projects +from openpype.pipeline import legacy_io from openpype.tools.utils.delegates import VersionDelegate from openpype.tools.utils.lib import ( qt_app_context, @@ -195,8 +196,7 @@ def show(root=None, debug=False, parent=None, items=None): if not os.environ.get("AVALON_PROJECT"): any_project = next( - project for project in legacy_io.projects() - if project.get("active", True) is not False + project for project in get_projects() ) project_name = any_project["name"] diff --git a/openpype/tools/utils/models.py b/openpype/tools/utils/models.py index 8991614fe1..1faccef4dd 100644 --- a/openpype/tools/utils/models.py +++ b/openpype/tools/utils/models.py @@ -3,6 +3,7 @@ import logging import Qt from Qt import QtCore, QtGui +from openpype.client import get_projects from .constants import ( PROJECT_IS_ACTIVE_ROLE, PROJECT_NAME_ROLE, @@ -296,29 +297,29 @@ class ProjectModel(QtGui.QStandardItemModel): self._default_item = item project_names = set() - if self.dbcon is not None: - for project_doc in self.dbcon.projects( - projection={"name": 1, "data.active": 1}, - only_active=self._only_active - ): - project_name = project_doc["name"] - project_names.add(project_name) - if project_name in self._items_by_name: - item = self._items_by_name[project_name] - else: - item = QtGui.QStandardItem(project_name) + project_docs = get_projects( + inactive=not self._only_active, + fields=["name", "data.active"] + ) + for project_doc in project_docs: + project_name = project_doc["name"] + project_names.add(project_name) + if project_name in self._items_by_name: + item = self._items_by_name[project_name] + else: + item = QtGui.QStandardItem(project_name) - self._items_by_name[project_name] = item - new_items.append(item) + self._items_by_name[project_name] = item + new_items.append(item) - is_active = project_doc.get("data", {}).get("active", True) - item.setData(project_name, PROJECT_NAME_ROLE) - item.setData(is_active, PROJECT_IS_ACTIVE_ROLE) + is_active = project_doc.get("data", {}).get("active", True) + item.setData(project_name, PROJECT_NAME_ROLE) + item.setData(is_active, PROJECT_IS_ACTIVE_ROLE) - if not is_active: - font = item.font() - font.setItalic(True) - item.setFont(font) + if not is_active: + font = item.font() + font.setItalic(True) + item.setFont(font) root_item = self.invisibleRootItem() for project_name in tuple(self._items_by_name.keys()): From 260ef9999516d437ad399a0b746ff73632106314 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 19:15:42 +0200 Subject: [PATCH 165/282] removed unused code --- openpype/tools/utils/lib.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openpype/tools/utils/lib.py b/openpype/tools/utils/lib.py index 2169cf8ef1..99d8c75ab4 100644 --- a/openpype/tools/utils/lib.py +++ b/openpype/tools/utils/lib.py @@ -443,10 +443,6 @@ class FamilyConfigCache: if profiles: # Make sure connection is installed # - accessing attribute which does not have auto-install - self.dbcon.install() - database = getattr(self.dbcon, "database", None) - if database is None: - database = self.dbcon._database asset_doc = get_asset_by_name( project_name, asset_name, fields=["data.tasks"] ) or {} From e86ea84da897f0ecd6608bdfff460c742a10042e Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 19:18:37 +0200 Subject: [PATCH 166/282] use 'get_projects' in standalone publisher --- openpype/tools/standalonepublish/widgets/widget_asset.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openpype/tools/standalonepublish/widgets/widget_asset.py b/openpype/tools/standalonepublish/widgets/widget_asset.py index 73114f7960..77d756a606 100644 --- a/openpype/tools/standalonepublish/widgets/widget_asset.py +++ b/openpype/tools/standalonepublish/widgets/widget_asset.py @@ -3,6 +3,7 @@ from Qt import QtWidgets, QtCore import qtawesome from openpype.client import ( + get_projects, get_project, get_asset_by_id, ) @@ -291,9 +292,7 @@ class AssetWidget(QtWidgets.QWidget): def _set_projects(self): project_names = list() - for doc in self.dbcon.projects(projection={"name": 1}, - only_active=True): - + for doc in get_projects(fields=["name"]): project_name = doc.get("name") if project_name: project_names.append(project_name) @@ -320,8 +319,7 @@ class AssetWidget(QtWidgets.QWidget): def on_project_change(self): projects = list() - for project in self.dbcon.projects(projection={"name": 1}, - only_active=True): + for project in get_projects(fields=["name"]): projects.append(project['name']) project_name = self.combo_projects.currentText() if project_name in projects: From 68ca5898920d79c93bc51e699f319e5987019063 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 15 Aug 2022 19:18:50 +0200 Subject: [PATCH 167/282] use 'get_projects' in settings --- openpype/tools/settings/settings/widgets.py | 60 ++++++++------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index 88d923c16a..1a4a6877b0 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -3,6 +3,7 @@ import uuid from Qt import QtWidgets, QtCore, QtGui import qtawesome +from openpype.client import get_projects from openpype.pipeline import AvalonMongoDB from openpype.style import get_objected_colors from openpype.tools.utils.widgets import ImageButton @@ -783,8 +784,6 @@ class ProjectModel(QtGui.QStandardItemModel): self.setColumnCount(2) - self.dbcon = None - self._only_active = only_active self._default_item = None self._items_by_name = {} @@ -828,9 +827,6 @@ class ProjectModel(QtGui.QStandardItemModel): index = self.index(index.row(), 0, index.parent()) return super(ProjectModel, self).flags(index) - def set_dbcon(self, dbcon): - self.dbcon = dbcon - def refresh(self): # Change id of versions refresh self._version_refresh_id = uuid.uuid4() @@ -846,31 +842,30 @@ class ProjectModel(QtGui.QStandardItemModel): self._default_item.setData("", PROJECT_VERSION_ROLE) project_names = set() - if self.dbcon is not None: - for project_doc in self.dbcon.projects( - projection={"name": 1, "data.active": 1}, - only_active=self._only_active - ): - project_name = project_doc["name"] - project_names.add(project_name) - if project_name in self._items_by_name: - item = self._items_by_name[project_name] - else: - item = QtGui.QStandardItem(project_name) + for project_doc in get_projects( + inactive=not self._only_active, + fields=["name", "data.active"] + ): + project_name = project_doc["name"] + project_names.add(project_name) + if project_name in self._items_by_name: + item = self._items_by_name[project_name] + else: + item = QtGui.QStandardItem(project_name) - self._items_by_name[project_name] = item - new_items.append(item) + self._items_by_name[project_name] = item + new_items.append(item) - is_active = project_doc.get("data", {}).get("active", True) - item.setData(project_name, PROJECT_NAME_ROLE) - item.setData(is_active, PROJECT_IS_ACTIVE_ROLE) - item.setData("", PROJECT_VERSION_ROLE) - item.setData(False, PROJECT_IS_SELECTED_ROLE) + is_active = project_doc.get("data", {}).get("active", True) + item.setData(project_name, PROJECT_NAME_ROLE) + item.setData(is_active, PROJECT_IS_ACTIVE_ROLE) + item.setData("", PROJECT_VERSION_ROLE) + item.setData(False, PROJECT_IS_SELECTED_ROLE) - if not is_active: - font = item.font() - font.setItalic(True) - item.setFont(font) + if not is_active: + font = item.font() + font.setItalic(True) + item.setFont(font) root_item = self.invisibleRootItem() for project_name in tuple(self._items_by_name.keys()): @@ -1067,8 +1062,6 @@ class ProjectListWidget(QtWidgets.QWidget): self.project_model = project_model self.inactive_chk = inactive_chk - self.dbcon = None - def set_entity(self, entity): self._entity = entity @@ -1211,15 +1204,6 @@ class ProjectListWidget(QtWidgets.QWidget): selected_project = index.data(PROJECT_NAME_ROLE) break - if not self.dbcon: - try: - self.dbcon = AvalonMongoDB() - self.dbcon.install() - except Exception: - self.dbcon = None - self.current_project = None - - self.project_model.set_dbcon(self.dbcon) self.project_model.refresh() self.project_proxy.sort(0) From 874d95270f35f305650a05649a6344379ccbe4e1 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 16 Aug 2022 10:11:45 +0200 Subject: [PATCH 168/282] Fix logic --- openpype/tools/loader/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index 48c038418a..bb943303bc 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -584,9 +584,9 @@ class SubsetWidget(QtWidgets.QWidget): for repre_doc in repre_docs: repre_ids.append(repre_doc["_id"]) + # keep only version ids without representation with that name version_id = repre_doc["parent"] - if version_id not in version_ids: - version_ids.remove(version_id) + version_ids.remove(version_id) for version_id in version_ids: joined_subset_names = ", ".join([ From 48706101137e544dc0ad66eb3f36e153a77ed699 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 16 Aug 2022 10:17:11 +0200 Subject: [PATCH 169/282] Report subsets without representation in one go --- openpype/tools/loader/widgets.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index bb943303bc..48a23e053a 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -567,12 +567,12 @@ class SubsetWidget(QtWidgets.QWidget): # Trigger project_name = self.dbcon.active_project() - subset_names_by_version_id = collections.defaultdict(set) + subset_name_by_version_id = dict() for item in items: version_id = item["version_document"]["_id"] - subset_names_by_version_id[version_id].add(item["subset"]) + subset_name_by_version_id[version_id] = item["subset"] - version_ids = set(subset_names_by_version_id.keys()) + version_ids = set(subset_name_by_version_id.keys()) repre_docs = get_representations( project_name, representation_names=[representation_name], @@ -588,10 +588,11 @@ class SubsetWidget(QtWidgets.QWidget): version_id = repre_doc["parent"] version_ids.remove(version_id) - for version_id in version_ids: + if version_ids: + # report versions that didn't have valid representation joined_subset_names = ", ".join([ - '"{}"'.format(subset) - for subset in subset_names_by_version_id[version_id] + '"{}"'.format(subset_name_by_version_id[version_id]) + for version_id in version_ids ]) self.echo("Subsets {} don't have representation '{}'".format( joined_subset_names, representation_name From 345a476159ed6d0f684f89316a488bba52347d93 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 16 Aug 2022 11:55:09 +0200 Subject: [PATCH 170/282] prepared settings to be able change task status on creation --- .../defaults/project_settings/ftrack.json | 3 ++ .../schema_project_ftrack.json | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index 3e86581a03..9847e58cfa 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -434,6 +434,9 @@ "enabled": false, "custom_attribute_keys": [] }, + "IntegrateHierarchyToFtrack": { + "create_task_status_profiles": [] + }, "IntegrateFtrackNote": { "enabled": true, "note_template": "{intent}: {comment}", diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index c06bec0f58..3f472c6c6a 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -841,6 +841,44 @@ } ] }, + { + "type": "dict", + "key": "IntegrateHierarchyToFtrack", + "label": "Integrate Hierarchy to ftrack", + "is_group": true, + "collapsible": true, + "children": [ + { + "type": "label", + "label": "Set task status on new task creation. Ftrack's default status is used otherwise." + }, + { + "type": "list", + "key": "create_task_status_profiles", + "object_type": { + "type": "dict", + "children": [ + { + "key": "task_types", + "label": "Task types", + "type": "task-types-enum" + }, + { + "key": "task_names", + "label": "Task names", + "type": "list", + "object_type": "text" + }, + { + "type": "text", + "key": "status_name", + "label": "Status name" + } + ] + } + } + ] + }, { "type": "dict", "collapsible": true, From 63e6088391b59f575c5406d4183e041d4f38c724 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Tue, 16 Aug 2022 11:55:23 +0200 Subject: [PATCH 171/282] Refactor `.remove` to `.discard` to fix bug if version wasn't in version_ids --- openpype/tools/loader/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index 48a23e053a..2d8b4b048d 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -586,7 +586,7 @@ class SubsetWidget(QtWidgets.QWidget): # keep only version ids without representation with that name version_id = repre_doc["parent"] - version_ids.remove(version_id) + version_ids.discard(version_id) if version_ids: # report versions that didn't have valid representation From 088a2d2003e111769084821ac1e2c2ece3cf2e35 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 16 Aug 2022 11:55:23 +0200 Subject: [PATCH 172/282] use task status profiles to change task status id on creation --- .../publish/integrate_hierarchy_ftrack.py | 62 ++++++++++++++----- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py b/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py index b8855ee2bd..8d39baa8d7 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_hierarchy_ftrack.py @@ -1,9 +1,12 @@ import sys import collections import six -import pyblish.api from copy import deepcopy + +import pyblish.api + from openpype.client import get_asset_by_id +from openpype.lib import filter_profiles # Copy of constant `openpype_modules.ftrack.lib.avalon_sync.CUST_ATTR_AUTO_SYNC` @@ -73,6 +76,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): "traypublisher" ] optional = False + create_task_status_profiles = [] def process(self, context): self.context = context @@ -82,14 +86,16 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): hierarchy_context = self._get_active_assets(context) self.log.debug("__ hierarchy_context: {}".format(hierarchy_context)) - self.session = self.context.data["ftrackSession"] + session = self.context.data["ftrackSession"] project_name = self.context.data["projectEntity"]["name"] query = 'Project where full_name is "{}"'.format(project_name) - project = self.session.query(query).one() - auto_sync_state = project[ - "custom_attributes"][CUST_ATTR_AUTO_SYNC] + project = session.query(query).one() + auto_sync_state = project["custom_attributes"][CUST_ATTR_AUTO_SYNC] - self.ft_project = None + self.session = session + self.ft_project = project + self.task_types = self.get_all_task_types(project) + self.task_statuses = self.get_task_statuses(project) # disable termporarily ftrack project's autosyncing if auto_sync_state: @@ -121,10 +127,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.log.debug(entity_type) if entity_type.lower() == 'project': - query = 'Project where full_name is "{}"'.format(entity_name) - entity = self.session.query(query).one() - self.ft_project = entity - self.task_types = self.get_all_task_types(entity) + entity = self.ft_project elif self.ft_project is None or parent is None: raise AssertionError( @@ -217,13 +220,6 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): task_type=task_type, parent=entity ) - try: - self.session.commit() - except Exception: - tp, value, tb = sys.exc_info() - self.session.rollback() - self.session._configure_locations() - six.reraise(tp, value, tb) # Incoming links. self.create_links(project_name, entity_data, entity) @@ -303,7 +299,37 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): return tasks + def get_task_statuses(self, project_entity): + project_schema = project_entity["project_schema"] + task_workflow_statuses = project_schema["_task_workflow"]["statuses"] + return { + status["id"]: status + for status in task_workflow_statuses + } + def create_task(self, name, task_type, parent): + filter_data = { + "task_names": name, + "task_types": task_type + } + profile = filter_profiles( + self.create_task_status_profiles, + filter_data + ) + status_id = None + if profile: + status_name = profile["status_name"] + status_name_low = status_name.lower() + for _status_id, status in self.task_statuses.items(): + if status["name"].lower() == status_name_low: + status_id = _status_id + break + + if status_id is None: + self.log.warning( + "Task status \"{}\" was not found".format(status_name) + ) + task = self.session.create('Task', { 'name': name, 'parent': parent @@ -312,6 +338,8 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.log.info(task_type) self.log.info(self.task_types) task['type'] = self.task_types[task_type] + if status_id is not None: + task["status_id"] = status_id try: self.session.commit() From c9f3340f3c750c0b64790607a254d43e76dfb134 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 16 Aug 2022 12:18:53 +0200 Subject: [PATCH 173/282] OP-3723 - resize saved images in PS for ffmpeg Ffmpeg cannot handle pictures higher than 16384x16384. Uses PIL to resize to max size(with aspect ratio). In the future this plugin should be refactored (to use general ExtractThumbnail and ExtractReview). --- .../plugins/publish/extract_review.py | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_review.py b/openpype/hosts/photoshop/plugins/publish/extract_review.py index d076610ead..7f78a46527 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_review.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_review.py @@ -1,5 +1,6 @@ import os import shutil +from PIL import Image import openpype.api import openpype.lib @@ -8,10 +9,17 @@ from openpype.hosts.photoshop import api as photoshop class ExtractReview(openpype.api.Extractor): """ - Produce a flattened or sequence image file from all 'image' instances. + Produce a flattened or sequence image files from all 'image' instances. If no 'image' instance is created, it produces flattened image from all visible layers. + + It creates review, thumbnail and mov representations. + + 'review' family could be used in other steps as a reference, as it + contains flattened image by default. (Eg. artist could load this + review as a single item and see full image. In most cases 'image' + family is separated by layers to better usage in animation or comp.) """ label = "Extract Review" @@ -49,7 +57,7 @@ class ExtractReview(openpype.api.Extractor): "stagingDir": staging_dir, "tags": self.jpg_options['tags'], }) - + processed_img_names = img_list else: self.log.info("Extract layers to flatten image.") img_list = self._saves_flattened_layers(staging_dir, layers) @@ -57,26 +65,33 @@ class ExtractReview(openpype.api.Extractor): instance.data["representations"].append({ "name": "jpg", "ext": "jpg", - "files": img_list, + "files": img_list, # cannot be [] for single frame "stagingDir": staging_dir, "tags": self.jpg_options['tags'] }) + processed_img_names = [img_list] ffmpeg_path = openpype.lib.get_ffmpeg_tool_path("ffmpeg") instance.data["stagingDir"] = staging_dir - # Generate thumbnail. + source_files_pattern = os.path.join(staging_dir, + self.output_seq_filename) + source_files_pattern = self._check_and_resize(processed_img_names, + source_files_pattern, + staging_dir) + # Generate thumbnail thumbnail_path = os.path.join(staging_dir, "thumbnail.jpg") self.log.info(f"Generate thumbnail {thumbnail_path}") args = [ ffmpeg_path, "-y", - "-i", os.path.join(staging_dir, self.output_seq_filename), + "-i", source_files_pattern, "-vf", "scale=300:-1", "-vframes", "1", thumbnail_path ] + self.log.debug("thumbnail args:: {}".format(args)) output = openpype.lib.run_subprocess(args) instance.data["representations"].append({ @@ -94,11 +109,12 @@ class ExtractReview(openpype.api.Extractor): args = [ ffmpeg_path, "-y", - "-i", os.path.join(staging_dir, self.output_seq_filename), + "-i", source_files_pattern, "-vf", "pad=ceil(iw/2)*2:ceil(ih/2)*2", "-vframes", str(img_number), mov_path ] + self.log.debug("mov args:: {}".format(args)) output = openpype.lib.run_subprocess(args) self.log.debug(output) instance.data["representations"].append({ @@ -120,6 +136,33 @@ class ExtractReview(openpype.api.Extractor): self.log.info(f"Extracted {instance} to {staging_dir}") + def _check_and_resize(self, processed_img_names, source_files_pattern, + staging_dir): + """Check if saved image could be used in ffmpeg. + + Ffmpeg has max size 16384x16384. Saved image(s) must be resized to be + used as a source for thumbnail or review mov. + """ + max_ffmpeg_size = 16384 + first_url = os.path.join(staging_dir, processed_img_names[0]) + with Image.open(first_url) as im: + width, height = im.size + + if width > max_ffmpeg_size or height > max_ffmpeg_size: + resized_dir = os.path.join(staging_dir, "resized") + os.mkdir(resized_dir) + source_files_pattern = os.path.join(resized_dir, + self.output_seq_filename) + for file_name in processed_img_names: + source_url = os.path.join(staging_dir, file_name) + with Image.open(source_url) as res_img: + # 'thumbnail' automatically keeps aspect ratio + res_img.thumbnail((max_ffmpeg_size, max_ffmpeg_size), + Image.ANTIALIAS) + res_img.save(os.path.join(resized_dir, file_name)) + + return source_files_pattern + def _get_image_path_from_instances(self, instance): img_list = [] From cfb14d32b50920d06fbfc6d1f74da2798910b3da Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 16 Aug 2022 15:42:25 +0200 Subject: [PATCH 174/282] Show dialog if installed version is not compatible in UI mode --- start.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/start.py b/start.py index 084eb7451a..d1198a85e4 100644 --- a/start.py +++ b/start.py @@ -748,12 +748,21 @@ def _find_frozen_openpype(use_version: str = None, _initialize_environment(openpype_version) return version_path + in_headless_mode = os.getenv("OPENPYPE_HEADLESS_MODE") == "1" if not installed_version.is_compatible(openpype_version): - raise OpenPypeVersionIncompatible( - ( - f"Latest version found {openpype_version} is not " - f"compatible with currently running {installed_version}" + message = "Version {} is not compatible with installed version {}." + # Show UI to user + if not in_headless_mode: + igniter.show_message_dialog( + "Incompatible OpenPype installation", + message.format( + "{}".format(openpype_version), + "{}".format(installed_version) + ) ) + # Raise incompatible error + raise OpenPypeVersionIncompatible( + message.format(openpype_version, installed_version) ) # test if latest detected is installed (in user data dir) @@ -768,7 +777,7 @@ def _find_frozen_openpype(use_version: str = None, if not is_inside: # install latest version to user data dir - if os.getenv("OPENPYPE_HEADLESS_MODE") == "1": + if in_headless_mode: version_path = bootstrap.install_version( openpype_version, force=True ) From e0c7ba861733e0cf4ec9087fdadcfe6b0d729aea Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 16 Aug 2022 17:53:16 +0200 Subject: [PATCH 175/282] added new plugin which change task status for instances if they are rendered on farm --- .../publish/integrate_ftrack_farm_status.py | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py new file mode 100644 index 0000000000..ecf258a870 --- /dev/null +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -0,0 +1,129 @@ +import pyblish.api +from openpype.lib import profiles_filtering + + +class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): + """Change task status when should be published on farm. + + Instance which has set "farm" key in data to 'True' is considered as will + be rendered on farm thus it's status should be changed. + """ + + order = pyblish.api.IntegratorOrder + 0.48 + label = "Integrate Ftrack Component" + families = ["ftrack"] + + farm_status_profiles = [] + + def process(self, context): + # Quick end + if not self.farm_status_profiles: + project_name = context.data["projectName"] + self.log.info(( + "Status profiles are not filled for project \"{}\". Skipping" + ).format(project_name)) + return + + filtered_instances = self.filter_instances(context) + instances_with_status_names = self.get_instances_with_statuse_names( + context, filtered_instances + ) + if instances_with_status_names: + self.fill_statuses(context, instances_with_status_names) + + def filter_instances(self, context): + filtered_instances = [] + for instance in context: + subset_name = instance.data["subset"] + msg_start = "SKipping instance {}.".format(subset_name) + if not instance.data.get("farm"): + self.log.debug( + "{} Won't be rendered on farm.".format(msg_start) + ) + continue + + task_entity = instance.data.get("ftrackTask") + if not task_entity: + self.log.debug( + "{} Does not have filled task".format(msg_start) + ) + continue + + filtered_instances.append(instance) + return filtered_instances + + def get_instances_with_statuse_names(self, context, instances): + instances_with_status_names = [] + for instance in instances: + family = instance.data["family"] + subset_name = instance.data["subset"] + task_entity = instance.data["ftrackTask"] + host_name = context.data["hostName"] + task_name = task_entity["name"] + task_type = task_entity["type"]["name"] + status_profile = profiles_filtering( + self.farm_status_profiles, + { + "hosts": host_name, + "task_types": task_type, + "task_names": task_name, + "families": family, + "subsets": subset_name, + }, + logger=self.log + ) + if not status_profile: + # There already is log in 'profiles_filtering' + continue + + status_name = status_profile["status_name"] + if status_name: + instances_with_status_names.append((instance, status_name)) + return instances_with_status_names + + def fill_statuses(self, context, instances_with_status_names): + # Prepare available task statuses on the project + project_name = context.data["projectName"] + session = context.data["ftrackSession"] + project_entity = session.query(( + "select project_schema from Project where full_name is \"{}\"" + ).format(project_name)).one() + project_schema = project_entity["project_schema"] + task_workflow_statuses = project_schema["_task_workflow"]["statuses"] + + # Keep track if anything has changed + status_changed = False + found_status_id_by_status_name = {} + for item in instances_with_status_names: + instance, status_name = item + + status_name_low = status_name.lower() + status_id = found_status_id_by_status_name.get(status_name_low) + + if status_id is None: + # Skip if status name was already tried to be found + if status_name_low in found_status_id_by_status_name: + continue + + for status in task_workflow_statuses: + if status["name"].lower() == status_name_low: + status_id = status["id"] + break + + # Store the result to be reused in following instances + found_status_id_by_status_name[status_name_low] = status_id + + if status_id is None: + self.log.warning(( + "Status \"{}\" is not available on project \"{}\"" + ).format(status_name, project_name)) + continue + + # Change task status id + task_entity = instance.data["ftrackTask"] + if status_id != task_entity["status_id"]: + task_entity["status_id"] = status_id + status_changed = True + + if status_changed: + session.commit() From 41dd9e84f574663aef840596fa4e4c8a37a6a49b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 16 Aug 2022 17:53:27 +0200 Subject: [PATCH 176/282] added settings schema for new plugin --- .../defaults/project_settings/ftrack.json | 3 + .../schema_project_ftrack.json | 60 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index 3e86581a03..610c85d232 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -489,6 +489,9 @@ }, "keep_first_subset_name_for_review": true, "asset_versions_status_profiles": [] + }, + "IntegrateFtrackFarmStatus": { + "farm_status_profiles": [] } } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index c06bec0f58..a821b1de76 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -1003,6 +1003,66 @@ } } ] + }, + { + "type": "dict", + "key": "IntegrateFtrackFarmStatus", + "label": "Integrate Ftrack Farm Status", + "children": [ + { + "type": "label", + "label": "Change status of task when it's subset is rendered on farm" + }, + { + "type": "list", + "collapsible": true, + "key": "farm_status_profiles", + "label": "Farm status profiles", + "use_label_wrap": true, + "object_type": { + "type": "dict", + "children": [ + { + "key": "hosts", + "label": "Host names", + "type": "hosts-enum", + "multiselection": true + }, + { + "key": "task_types", + "label": "Task types", + "type": "task-types-enum" + }, + { + "key": "task_names", + "label": "Task names", + "type": "list", + "object_type": "text" + }, + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "key": "subsets", + "label": "Subset names", + "type": "list", + "object_type": "text" + }, + { + "type": "separator" + }, + { + "key": "status_name", + "label": "Status name", + "type": "text" + } + ] + } + } + ] } ] } From b36b8ebee0ae424ab1189bc3d9629ef672097bb4 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 17 Aug 2022 04:12:09 +0000 Subject: [PATCH 177/282] [Automated] Bump version --- CHANGELOG.md | 19 ++++++++----------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2adb4ac154..80673e9f8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,15 @@ # Changelog -## [3.13.1-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.13.1-nightly.3](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.13.0...HEAD) **🐛 Bug fixes** +- General: Extract Review can scale with pixel aspect ratio [\#3644](https://github.com/pypeclub/OpenPype/pull/3644) +- Maya: Refactor moved usage of CreateRender settings [\#3643](https://github.com/pypeclub/OpenPype/pull/3643) - General: Hero version representations have full context [\#3638](https://github.com/pypeclub/OpenPype/pull/3638) +- Nuke: color settings for render write node is working now [\#3632](https://github.com/pypeclub/OpenPype/pull/3632) - Maya: FBX support for update in reference loader [\#3631](https://github.com/pypeclub/OpenPype/pull/3631) **🔀 Refactored code** @@ -16,7 +19,10 @@ **Merged pull requests:** +- Deadline: Global job pre load is not Pype 2 compatible [\#3666](https://github.com/pypeclub/OpenPype/pull/3666) +- Maya: Remove unused get current renderer logic [\#3645](https://github.com/pypeclub/OpenPype/pull/3645) - Kitsu|Fix: Movie project type fails & first loop children names [\#3636](https://github.com/pypeclub/OpenPype/pull/3636) +- fix the bug of failing to extract look when UDIMs format used in AiImage [\#3628](https://github.com/pypeclub/OpenPype/pull/3628) ## [3.13.0](https://github.com/pypeclub/OpenPype/tree/3.13.0) (2022-08-09) @@ -55,7 +61,6 @@ - General: Update imports in start script [\#3579](https://github.com/pypeclub/OpenPype/pull/3579) - Nuke: render family integration consistency [\#3576](https://github.com/pypeclub/OpenPype/pull/3576) - Ftrack: Handle missing published path in integrator [\#3570](https://github.com/pypeclub/OpenPype/pull/3570) -- Maya: fix Review image plane attribute [\#3569](https://github.com/pypeclub/OpenPype/pull/3569) - Nuke: publish existing frames with slate with correct range [\#3555](https://github.com/pypeclub/OpenPype/pull/3555) **🔀 Refactored code** @@ -85,11 +90,10 @@ - General: Global thumbnail extractor is ready for more cases [\#3561](https://github.com/pypeclub/OpenPype/pull/3561) - Maya: add additional validators to Settings [\#3540](https://github.com/pypeclub/OpenPype/pull/3540) -- General: Interactive console in cli [\#3526](https://github.com/pypeclub/OpenPype/pull/3526) -- Ftrack: Automatic daily review session creation can define trigger hour [\#3516](https://github.com/pypeclub/OpenPype/pull/3516) **🐛 Bug fixes** +- Maya: fix Review image plane attribute [\#3569](https://github.com/pypeclub/OpenPype/pull/3569) - Maya: Fix animated attributes \(ie. overscan\) on loaded cameras breaking review publishing. [\#3562](https://github.com/pypeclub/OpenPype/pull/3562) - NewPublisher: Python 2 compatible html escape [\#3559](https://github.com/pypeclub/OpenPype/pull/3559) - Remove invalid submodules from `/vendor` [\#3557](https://github.com/pypeclub/OpenPype/pull/3557) @@ -98,12 +102,6 @@ - Module interfaces: Fix import error [\#3547](https://github.com/pypeclub/OpenPype/pull/3547) - Workfiles tool: Show of tool and it's flags [\#3539](https://github.com/pypeclub/OpenPype/pull/3539) - General: Create workfile documents works again [\#3538](https://github.com/pypeclub/OpenPype/pull/3538) -- Additional fixes for powershell scripts [\#3525](https://github.com/pypeclub/OpenPype/pull/3525) -- Maya: Added wrapper around cmds.setAttr [\#3523](https://github.com/pypeclub/OpenPype/pull/3523) -- Nuke: double slate [\#3521](https://github.com/pypeclub/OpenPype/pull/3521) -- General: Fix hash of centos oiio archive [\#3519](https://github.com/pypeclub/OpenPype/pull/3519) -- Maya: Renderman display output fix [\#3514](https://github.com/pypeclub/OpenPype/pull/3514) -- TrayPublisher: Simple creation enhancements and fixes [\#3513](https://github.com/pypeclub/OpenPype/pull/3513) **🔀 Refactored code** @@ -112,7 +110,6 @@ - Refactor Integrate Asset [\#3530](https://github.com/pypeclub/OpenPype/pull/3530) - General: Client docstrings cleanup [\#3529](https://github.com/pypeclub/OpenPype/pull/3529) - General: Move load related functions into pipeline [\#3527](https://github.com/pypeclub/OpenPype/pull/3527) -- General: Get current context document functions [\#3522](https://github.com/pypeclub/OpenPype/pull/3522) **Merged pull requests:** diff --git a/openpype/version.py b/openpype/version.py index 6ff5dfb7b5..9ae52e8370 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.13.1-nightly.2" +__version__ = "3.13.1-nightly.3" diff --git a/pyproject.toml b/pyproject.toml index 9cbdc295ff..83ccf233d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.13.1-nightly.2" # OpenPype +version = "3.13.1-nightly.3" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From ccaef43535dd0d80c3184a325f51bfaea8409d75 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 10:32:11 +0200 Subject: [PATCH 178/282] changed description label --- .../entities/schemas/projects_schema/schema_project_ftrack.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index a821b1de76..1967a1150f 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -1011,7 +1011,7 @@ "children": [ { "type": "label", - "label": "Change status of task when it's subset is rendered on farm" + "label": "Change status of task when it's subset is submitted to farm" }, { "type": "list", From 8d65c65fc9ebcccc8d58fe3b55e7cb81b4706106 Mon Sep 17 00:00:00 2001 From: "Allan I. A" <76656700+Allan-I@users.noreply.github.com> Date: Wed, 17 Aug 2022 11:34:00 +0300 Subject: [PATCH 179/282] Remove unused attribute. Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/create/create_render.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index 2f09aaee87..668cb57292 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -71,7 +71,6 @@ class CreateRender(plugin.Creator): label = "Render" family = "rendering" icon = "eye" - enable_all_lights = True _token = None _user = None _password = None From 41ac0d65c4c7fe145cf4347e1faf5af6b5b7dfa6 Mon Sep 17 00:00:00 2001 From: "Allan I. A" <76656700+Allan-I@users.noreply.github.com> Date: Wed, 17 Aug 2022 11:35:10 +0300 Subject: [PATCH 180/282] Fix bug in default. Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/create/create_render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_render.py b/openpype/hosts/maya/plugins/create/create_render.py index 668cb57292..5418ec1f2f 100644 --- a/openpype/hosts/maya/plugins/create/create_render.py +++ b/openpype/hosts/maya/plugins/create/create_render.py @@ -223,7 +223,7 @@ class CreateRender(plugin.Creator): self._project_settings.get( "maya", {}).get( "RenderSettings", {}).get( - "enable_all_lights", {}) + "enable_all_lights", False) ) # Disable for now as this feature is not working yet # self.data["assScene"] = False From 7deb3079247f56ba606b008c462099f18a73ae74 Mon Sep 17 00:00:00 2001 From: "Allan I. A" <76656700+Allan-I@users.noreply.github.com> Date: Wed, 17 Aug 2022 11:35:26 +0300 Subject: [PATCH 181/282] Fix bug in default. Co-authored-by: Roy Nieterau --- openpype/hosts/maya/plugins/publish/validate_rendersettings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py index 93ef7d7af7..f19c0bff36 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py @@ -245,7 +245,7 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): settings_lights_flag = instance.context.data["project_settings"].get( "maya", {}).get( "RenderSettings", {}).get( - "enable_all_lights", {}) + "enable_all_lights", False) instance_lights_flag = instance.data.get("renderSetupIncludeLights") if settings_lights_flag != instance_lights_flag: From 2f3e6a73e3f8d130fc639cd1c5c1429e4957ea2a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 10:48:50 +0200 Subject: [PATCH 182/282] Change label of plugin --- .../ftrack/plugins/publish/integrate_ftrack_farm_status.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py index ecf258a870..f725de3144 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -10,7 +10,7 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): """ order = pyblish.api.IntegratorOrder + 0.48 - label = "Integrate Ftrack Component" + label = "Integrate Ftrack Farm Status" families = ["ftrack"] farm_status_profiles = [] @@ -35,7 +35,7 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): filtered_instances = [] for instance in context: subset_name = instance.data["subset"] - msg_start = "SKipping instance {}.".format(subset_name) + msg_start = "Skipping instance {}.".format(subset_name) if not instance.data.get("farm"): self.log.debug( "{} Won't be rendered on farm.".format(msg_start) From 7095bff502f13498bb1dd7a7a173693bf43e72dd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 11:04:58 +0200 Subject: [PATCH 183/282] set "farm" to true in maya render colletor --- openpype/hosts/maya/plugins/publish/collect_render.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index c3e6c98020..0d45ad4f9e 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -354,6 +354,7 @@ class CollectMayaRender(pyblish.api.ContextPlugin): instance = context.create_instance(expected_layer_name) instance.data["label"] = label + instance.data["farm"] = True instance.data.update(data) self.log.debug("data: {}".format(json.dumps(data, indent=4))) From 58f19f15f4a2c3d4ad6d0dd71089c0357904dcd9 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 11:05:04 +0200 Subject: [PATCH 184/282] skip disabled instances --- .../ftrack/plugins/publish/integrate_ftrack_farm_status.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py index f725de3144..fcbe71e0ac 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -34,6 +34,9 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): def filter_instances(self, context): filtered_instances = [] for instance in context: + # Skip disabled instances + if instance.data.get("publish") is False: + continue subset_name = instance.data["subset"] msg_start = "Skipping instance {}.".format(subset_name) if not instance.data.get("farm"): From 346e3b8300e01ac8b3ab4e2c52a7d0c25a169d33 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 11:11:39 +0200 Subject: [PATCH 185/282] removed families filter --- .../ftrack/plugins/publish/integrate_ftrack_farm_status.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py index fcbe71e0ac..24f784f83d 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -11,7 +11,6 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): order = pyblish.api.IntegratorOrder + 0.48 label = "Integrate Ftrack Farm Status" - families = ["ftrack"] farm_status_profiles = [] From 95c19cc412ecbfd0caf42e06ada91640e8da5885 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 11:22:56 +0200 Subject: [PATCH 186/282] fill context entities in all instances --- .../plugins/publish/collect_ftrack_api.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py b/openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py index 14da188150..99a555014e 100644 --- a/openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py +++ b/openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py @@ -105,11 +105,17 @@ class CollectFtrackApi(pyblish.api.ContextPlugin): context.data["ftrackEntity"] = asset_entity context.data["ftrackTask"] = task_entity - self.per_instance_process(context, asset_name, task_name) + self.per_instance_process(context, asset_entity, task_entity) def per_instance_process( - self, context, context_asset_name, context_task_name + self, context, context_asset_entity, context_task_entity ): + context_task_name = None + context_asset_name = None + if context_asset_entity: + context_asset_name = context_asset_entity["name"] + if context_task_entity: + context_task_name = context_task_entity["name"] instance_by_asset_and_task = {} for instance in context: self.log.debug( @@ -120,6 +126,8 @@ class CollectFtrackApi(pyblish.api.ContextPlugin): if not instance_asset_name and not instance_task_name: self.log.debug("Instance does not have set context keys.") + instance.data["ftrackEntity"] = context_asset_entity + instance.data["ftrackTask"] = context_task_entity continue elif instance_asset_name and instance_task_name: @@ -131,6 +139,8 @@ class CollectFtrackApi(pyblish.api.ContextPlugin): "Instance's context is same as in publish context." " Asset: {} | Task: {}" ).format(context_asset_name, context_task_name)) + instance.data["ftrackEntity"] = context_asset_entity + instance.data["ftrackTask"] = context_task_entity continue asset_name = instance_asset_name task_name = instance_task_name @@ -141,6 +151,8 @@ class CollectFtrackApi(pyblish.api.ContextPlugin): "Instance's context task is same as in publish" " context. Task: {}" ).format(context_task_name)) + instance.data["ftrackEntity"] = context_asset_entity + instance.data["ftrackTask"] = context_task_entity continue asset_name = context_asset_name @@ -152,6 +164,8 @@ class CollectFtrackApi(pyblish.api.ContextPlugin): "Instance's context asset is same as in publish" " context. Asset: {}" ).format(context_asset_name)) + instance.data["ftrackEntity"] = context_asset_entity + instance.data["ftrackTask"] = None continue # Do not use context's task name From 51c27f28c0791633819f935e230a179ea20ff00b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 12:20:06 +0200 Subject: [PATCH 187/282] added ability to add additional metadata to components --- .../publish/integrate_ftrack_instances.py | 134 +++++++++++------- 1 file changed, 85 insertions(+), 49 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py index a1e5922730..3f0cc176a2 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py @@ -3,6 +3,7 @@ import json import copy import pyblish.api +from openpype.lib.openpype_version import get_openpype_version from openpype.lib.transcoding import ( get_ffprobe_streams, convert_ffprobe_fps_to_float, @@ -20,6 +21,17 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): label = "Integrate Ftrack Component" families = ["ftrack"] + metadata_keys_to_label = { + "openpype_version": "OpenPype version", + "frame_start": "Frame start", + "frame_end": "Frame end", + "duration": "Duration", + "width": "Resolution width", + "height": "Resolution height", + "fps": "FPS", + "code": "Codec" + } + family_mapping = { "camera": "cam", "look": "look", @@ -43,6 +55,7 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): } keep_first_subset_name_for_review = True asset_versions_status_profiles = {} + additional_metadata_keys = [] def process(self, instance): self.log.debug("instance {}".format(instance)) @@ -105,7 +118,8 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): "component_data": None, "component_path": None, "component_location": None, - "component_location_name": None + "component_location_name": None, + "additional_data": {} } # Filter types of representations @@ -152,6 +166,7 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): "name": "thumbnail" } thumbnail_item["thumbnail"] = True + # Create copy of item before setting location src_components_to_add.append(copy.deepcopy(thumbnail_item)) # Create copy of first thumbnail @@ -248,19 +263,15 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): first_thumbnail_component[ "asset_data"]["name"] = extended_asset_name - component_meta = self._prepare_component_metadata( - instance, repre, repre_path, True - ) - # Change location review_item["component_path"] = repre_path # Change component data review_item["component_data"] = { # Default component name is "main". "name": "ftrackreview-mp4", - "metadata": { - "ftr_meta": json.dumps(component_meta) - } + "metadata": self._prepare_component_metadata( + instance, repre, repre_path, True + ) } if is_first_review_repre: @@ -302,13 +313,9 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): component_data = copy_src_item["component_data"] component_name = component_data["name"] component_data["name"] = component_name + "_src" - component_meta = self._prepare_component_metadata( + component_data["metadata"] = self._prepare_component_metadata( instance, repre, copy_src_item["component_path"], False ) - if component_meta: - component_data["metadata"] = { - "ftr_meta": json.dumps(component_meta) - } component_list.append(copy_src_item) # Add others representations as component @@ -326,16 +333,12 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): ): other_item["asset_data"]["name"] = extended_asset_name - component_meta = self._prepare_component_metadata( - instance, repre, published_path, False - ) component_data = { - "name": repre["name"] + "name": repre["name"], + "metadata": self._prepare_component_metadata( + instance, repre, published_path, False + ) } - if component_meta: - component_data["metadata"] = { - "ftr_meta": json.dumps(component_meta) - } other_item["component_data"] = component_data other_item["component_location_name"] = unmanaged_location_name other_item["component_path"] = published_path @@ -354,6 +357,9 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): )) instance.data["ftrackComponentsList"] = component_list + def _collect_additional_metadata(self, streams): + pass + def _get_repre_path(self, instance, repre, only_published): """Get representation path that can be used for integration. @@ -423,6 +429,11 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): def _prepare_component_metadata( self, instance, repre, component_path, is_review ): + metadata = {} + if "openpype_version" in self.additional_metadata_keys: + label = self.metadata_keys_to_label["openpype_version"] + metadata[label] = get_openpype_version() + extension = os.path.splitext(component_path)[-1] streams = [] try: @@ -442,13 +453,23 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): # - exr is special case which can have issues with reading through # ffmpegh but we want to set fps for it if not video_streams and extension not in [".exr"]: - return {} + return metadata stream_width = None stream_height = None stream_fps = None frame_out = None + codec_label = None for video_stream in video_streams: + codec_label = video_stream.get("codec_long_name") + if not codec_label: + codec_label = video_stream.get("codec") + + if codec_label: + pix_fmt = video_stream.get("pix_fmt") + if pix_fmt: + codec_label += " ({})".format(pix_fmt) + tmp_width = video_stream.get("width") tmp_height = video_stream.get("height") if tmp_width and tmp_height: @@ -456,8 +477,8 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): stream_height = tmp_height input_framerate = video_stream.get("r_frame_rate") - duration = video_stream.get("duration") - if input_framerate is None or duration is None: + stream_duration = video_stream.get("duration") + if input_framerate is None or stream_duration is None: continue try: stream_fps = convert_ffprobe_fps_to_float( @@ -473,9 +494,9 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): stream_height = tmp_height self.log.debug("FPS from stream is {} and duration is {}".format( - input_framerate, duration + input_framerate, stream_duration )) - frame_out = float(duration) * stream_fps + frame_out = float(stream_duration) * stream_fps break # Prepare FPS @@ -483,43 +504,58 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): if instance_fps is None: instance_fps = instance.context.data["fps"] - if not is_review: - output = {} - fps = stream_fps or instance_fps - if fps: - output["frameRate"] = fps - - if stream_width and stream_height: - output["width"] = int(stream_width) - output["height"] = int(stream_height) - return output - - frame_start = repre.get("frameStartFtrack") - frame_end = repre.get("frameEndFtrack") - if frame_start is None or frame_end is None: - frame_start = instance.data["frameStart"] - frame_end = instance.data["frameEnd"] - - fps = None repre_fps = repre.get("fps") if repre_fps is not None: repre_fps = float(repre_fps) fps = stream_fps or repre_fps or instance_fps + # Prepare frame ranges + frame_start = repre.get("frameStartFtrack") + frame_end = repre.get("frameEndFtrack") + if frame_start is None or frame_end is None: + frame_start = instance.data["frameStart"] + frame_end = instance.data["frameEnd"] + duration = (frame_end - frame_start) + 1 + + for key, value in [ + ("fps", fps), + ("frame_start", frame_start), + ("frame_end", frame_end), + ("duration", duration), + ("width", stream_width), + ("height", stream_height), + ("fps", fps), + ("code", codec_label) + ]: + if not value or key not in self.additional_metadata_keys: + continue + label = self.metadata_keys_to_label[key] + metadata[label] = value + + if not is_review: + ftr_meta = {} + if fps: + ftr_meta["frameRate"] = fps + + if stream_width and stream_height: + ftr_meta["width"] = int(stream_width) + ftr_meta["height"] = int(stream_height) + metadata["ftr_meta"] = json.dumps(ftr_meta) + return metadata + # Frame end of uploaded video file should be duration in frames # - frame start is always 0 # - frame end is duration in frames if not frame_out: - frame_out = frame_end - frame_start + 1 + frame_out = duration # Ftrack documentation says that it is required to have # 'width' and 'height' in review component. But with those values # review video does not play. - component_meta = { + metadata["ftr_meta"] = json.dumps({ "frameIn": 0, "frameOut": frame_out, "frameRate": float(fps) - } - - return component_meta + }) + return metadata From b66c8088c3c9fcde06cdcf6cb837c1deb2c5cc1b Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 12:24:01 +0200 Subject: [PATCH 188/282] added settings for 'additional_metadata_keys' --- .../defaults/project_settings/ftrack.json | 3 ++- .../projects_schema/schema_project_ftrack.json | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index 9847e58cfa..952657251c 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -491,7 +491,8 @@ "usd": "usd" }, "keep_first_subset_name_for_review": true, - "asset_versions_status_profiles": [] + "asset_versions_status_profiles": [], + "additional_metadata_keys": [] } } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json index 3f472c6c6a..1a63e589b2 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json @@ -1039,6 +1039,22 @@ } ] } + }, + { + "key": "additional_metadata_keys", + "label": "Additional metadata keys on components", + "type": "enum", + "multiselection": true, + "enum_items": [ + {"openpype_version": "OpenPype version"}, + {"frame_start": "Frame start"}, + {"frame_end": "Frame end"}, + {"duration": "Duration"}, + {"width": "Resolution width"}, + {"height": "Resolution height"}, + {"fps": "FPS"}, + {"code": "Codec"} + ] } ] } From 05f1b732b6edd1732139350528ad614095da5b70 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 13:22:34 +0200 Subject: [PATCH 189/282] fill context task entity in collect ftrack api --- openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py b/openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py index 99a555014e..e13b7e65cd 100644 --- a/openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py +++ b/openpype/modules/ftrack/plugins/publish/collect_ftrack_api.py @@ -165,7 +165,7 @@ class CollectFtrackApi(pyblish.api.ContextPlugin): " context. Asset: {}" ).format(context_asset_name)) instance.data["ftrackEntity"] = context_asset_entity - instance.data["ftrackTask"] = None + instance.data["ftrackTask"] = context_task_entity continue # Do not use context's task name From 4dba68c5bdade98048dd1ca15d7f03ac004dcf28 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 13:30:14 +0200 Subject: [PATCH 190/282] fix function import and call --- .../ftrack/plugins/publish/integrate_ftrack_farm_status.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py index 24f784f83d..0a7ad0b532 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -1,5 +1,5 @@ import pyblish.api -from openpype.lib import profiles_filtering +from openpype.lib import filter_profiles class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): @@ -63,7 +63,7 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): host_name = context.data["hostName"] task_name = task_entity["name"] task_type = task_entity["type"]["name"] - status_profile = profiles_filtering( + status_profile = filter_profiles( self.farm_status_profiles, { "hosts": host_name, @@ -75,7 +75,7 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): logger=self.log ) if not status_profile: - # There already is log in 'profiles_filtering' + # There already is log in 'filter_profiles' continue status_name = status_profile["status_name"] From cb34f4619e54ae887bc1ea38a0e1ec106d228167 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 13:30:20 +0200 Subject: [PATCH 191/282] log availabl status names --- .../plugins/publish/integrate_ftrack_farm_status.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py index 0a7ad0b532..8bebfd8485 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -93,6 +93,10 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): project_schema = project_entity["project_schema"] task_workflow_statuses = project_schema["_task_workflow"]["statuses"] + joined_status_names = ", ".join({ + '"{}"'.format(status["name"]) + for status in task_workflow_statuses + }) # Keep track if anything has changed status_changed = False found_status_id_by_status_name = {} @@ -117,8 +121,9 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): if status_id is None: self.log.warning(( - "Status \"{}\" is not available on project \"{}\"" - ).format(status_name, project_name)) + "Status \"{}\" is not available on project \"{}\"." + " Available statuses are {}" + ).format(status_name, project_name, joined_status_names)) continue # Change task status id From bc3aa4b1609e067e7b4a31a9874e8a415bcfcc71 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 13:54:06 +0200 Subject: [PATCH 192/282] fix getting of task statuses --- .../plugins/publish/integrate_ftrack_farm_status.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py index 8bebfd8485..658df70895 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -90,12 +90,17 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): project_entity = session.query(( "select project_schema from Project where full_name is \"{}\"" ).format(project_name)).one() + task_type = session.query( + "select id from ObjectType where name is \"Task\"" + ).first() project_schema = project_entity["project_schema"] - task_workflow_statuses = project_schema["_task_workflow"]["statuses"] + task_statuses = project_schema.get_statuses( + "Task", task_type["id"] + ) joined_status_names = ", ".join({ '"{}"'.format(status["name"]) - for status in task_workflow_statuses + for status in task_statuses }) # Keep track if anything has changed status_changed = False @@ -111,7 +116,7 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): if status_name_low in found_status_id_by_status_name: continue - for status in task_workflow_statuses: + for status in task_statuses: if status["name"].lower() == status_name_low: status_id = status["id"] break From 671cf183fd73629e7a140784e518bc7718fa5431 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 14:18:13 +0200 Subject: [PATCH 193/282] fix statuses lookup by task type --- .../publish/integrate_ftrack_farm_status.py | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py index 658df70895..c5fc3dd68f 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -90,49 +90,49 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): project_entity = session.query(( "select project_schema from Project where full_name is \"{}\"" ).format(project_name)).one() - task_type = session.query( - "select id from ObjectType where name is \"Task\"" - ).first() project_schema = project_entity["project_schema"] - task_statuses = project_schema.get_statuses( - "Task", task_type["id"] - ) - joined_status_names = ", ".join({ - '"{}"'.format(status["name"]) - for status in task_statuses - }) + task_type_ids = set() + for item in instances_with_status_names: + instance, _ = item + task_entity = instance.data["ftrackTask"] + task_type_ids.add(task_entity["type"]["id"]) + + task_statuses_by_type_id = { + task_type_id: project_schema.get_statuses("Task", task_type_id) + for task_type_id in task_type_ids + } + # Keep track if anything has changed + skipped_status_names = set() status_changed = False - found_status_id_by_status_name = {} for item in instances_with_status_names: instance, status_name = item - + task_entity = instance.data["ftrackTask"] + task_statuses = task_statuses_by_type_id[task_entity["type"]["id"]] status_name_low = status_name.lower() - status_id = found_status_id_by_status_name.get(status_name_low) + + status_id = None + # Skip if status name was already tried to be found + for status in task_statuses: + if status["name"].lower() == status_name_low: + status_id = status["id"] + break if status_id is None: - # Skip if status name was already tried to be found - if status_name_low in found_status_id_by_status_name: - continue - - for status in task_statuses: - if status["name"].lower() == status_name_low: - status_id = status["id"] - break - - # Store the result to be reused in following instances - found_status_id_by_status_name[status_name_low] = status_id - - if status_id is None: - self.log.warning(( - "Status \"{}\" is not available on project \"{}\"." - " Available statuses are {}" - ).format(status_name, project_name, joined_status_names)) + if status_name_low not in skipped_status_names: + skipped_status_names.add(status_name_low) + joined_status_names = ", ".join({ + '"{}"'.format(status["name"]) + for status in task_statuses + }) + self.log.warning(( + "Status \"{}\" is not available on project \"{}\"." + " Available statuses are {}" + ).format(status_name, project_name, joined_status_names)) continue # Change task status id - task_entity = instance.data["ftrackTask"] if status_id != task_entity["status_id"]: task_entity["status_id"] = status_id status_changed = True From 6d4a80cd30b8adf926a44b46c2c8f70ee04217f0 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 14:28:27 +0200 Subject: [PATCH 194/282] added some logs related to status changes --- .../plugins/publish/integrate_ftrack_farm_status.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py index c5fc3dd68f..ab5738c33f 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_farm_status.py @@ -113,10 +113,12 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): status_name_low = status_name.lower() status_id = None + status_name = None # Skip if status name was already tried to be found for status in task_statuses: if status["name"].lower() == status_name_low: status_id = status["id"] + status_name = status["name"] break if status_id is None: @@ -136,6 +138,13 @@ class IntegrateFtrackFarmStatus(pyblish.api.ContextPlugin): if status_id != task_entity["status_id"]: task_entity["status_id"] = status_id status_changed = True + path = "/".join([ + item["name"] + for item in task_entity["link"] + ]) + self.log.debug("Set status \"{}\" to \"{}\"".format( + status_name, path + )) if status_changed: session.commit() From 5a0b15c63b90a97417d43d9a3cfff7ba927dd4e1 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 17 Aug 2022 15:35:46 +0200 Subject: [PATCH 195/282] fix typo in codec --- .../ftrack/plugins/publish/integrate_ftrack_instances.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py index 3f0cc176a2..1bf4caac77 100644 --- a/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py +++ b/openpype/modules/ftrack/plugins/publish/integrate_ftrack_instances.py @@ -29,7 +29,7 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): "width": "Resolution width", "height": "Resolution height", "fps": "FPS", - "code": "Codec" + "codec": "Codec" } family_mapping = { @@ -526,7 +526,7 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): ("width", stream_width), ("height", stream_height), ("fps", fps), - ("code", codec_label) + ("codec", codec_label) ]: if not value or key not in self.additional_metadata_keys: continue From db6f46895b9c2a3659bfb5803705388b7d2f7dfd Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 17 Aug 2022 16:01:31 +0200 Subject: [PATCH 196/282] OP-3723 - remove PIL limit High resolution could trigger " could be decompression bomb DOS attack". --- openpype/hosts/photoshop/plugins/publish/extract_review.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_review.py b/openpype/hosts/photoshop/plugins/publish/extract_review.py index 7f78a46527..151440b914 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_review.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_review.py @@ -144,6 +144,7 @@ class ExtractReview(openpype.api.Extractor): used as a source for thumbnail or review mov. """ max_ffmpeg_size = 16384 + Image.MAX_IMAGE_PIXELS = None first_url = os.path.join(staging_dir, processed_img_names[0]) with Image.open(first_url) as im: width, height = im.size From 09af23e2d789dcb02450cbd6eed9be53c062c416 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 17 Aug 2022 17:26:10 +0200 Subject: [PATCH 197/282] resolve: fixing import in collector --- .../hosts/resolve/plugins/publish/precollect_workfile.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/resolve/plugins/publish/precollect_workfile.py b/openpype/hosts/resolve/plugins/publish/precollect_workfile.py index 53e67aee0e..0f94216556 100644 --- a/openpype/hosts/resolve/plugins/publish/precollect_workfile.py +++ b/openpype/hosts/resolve/plugins/publish/precollect_workfile.py @@ -1,11 +1,9 @@ import pyblish.api from pprint import pformat -from importlib import reload -from openpype.hosts import resolve +from openpype.hosts.resolve import api as rapi from openpype.pipeline import legacy_io from openpype.hosts.resolve.otio import davinci_export -reload(davinci_export) class PrecollectWorkfile(pyblish.api.ContextPlugin): @@ -18,9 +16,9 @@ class PrecollectWorkfile(pyblish.api.ContextPlugin): asset = legacy_io.Session["AVALON_ASSET"] subset = "workfile" - project = resolve.get_current_project() + project = rapi.get_current_project() fps = project.GetSetting("timelineFrameRate") - video_tracks = resolve.get_video_track_names() + video_tracks = rapi.get_video_track_names() # adding otio timeline to context otio_timeline = davinci_export.create_otio_timeline(project) From ebdf8a348a3eb4e34162564c719a872b5e30b71e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 17 Aug 2022 17:41:23 +0200 Subject: [PATCH 198/282] OP-3723 - changed max limit Official 16384x16384 actually didn't work because int overflow. 16000 tested and worked. --- openpype/hosts/photoshop/plugins/publish/extract_review.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_review.py b/openpype/hosts/photoshop/plugins/publish/extract_review.py index 151440b914..64decbb957 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_review.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_review.py @@ -143,7 +143,8 @@ class ExtractReview(openpype.api.Extractor): Ffmpeg has max size 16384x16384. Saved image(s) must be resized to be used as a source for thumbnail or review mov. """ - max_ffmpeg_size = 16384 + # 16384x16384 actually didn't work because int overflow + max_ffmpeg_size = 16000 Image.MAX_IMAGE_PIXELS = None first_url = os.path.join(staging_dir, processed_img_names[0]) with Image.open(first_url) as im: From da3268c9a75e04a8464589fc1c1153e264fec60a Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 09:51:45 +0200 Subject: [PATCH 199/282] resave default settings --- openpype/settings/defaults/project_settings/ftrack.json | 2 +- openpype/settings/defaults/project_settings/shotgrid.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json index 58b6a55958..2d5f889aa5 100644 --- a/openpype/settings/defaults/project_settings/ftrack.json +++ b/openpype/settings/defaults/project_settings/ftrack.json @@ -498,4 +498,4 @@ "farm_status_profiles": [] } } -} +} \ No newline at end of file diff --git a/openpype/settings/defaults/project_settings/shotgrid.json b/openpype/settings/defaults/project_settings/shotgrid.json index 83b6f69074..774bce714b 100644 --- a/openpype/settings/defaults/project_settings/shotgrid.json +++ b/openpype/settings/defaults/project_settings/shotgrid.json @@ -19,4 +19,4 @@ "step": "step" } } -} +} \ No newline at end of file From ec405eb9130c6fe9c8b13dde34983fb43341507d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 11:52:46 +0200 Subject: [PATCH 200/282] prepared some classes to handle settings locks --- openpype/settings/handlers.py | 162 ++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 15ae2351fd..8d13875d0b 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -22,6 +22,168 @@ from .constants import ( ) +class SettingsStateInfo: + """Helper state information for Settings state. + + Is used to hold information about last save and last opened UI. Keep + information about the time when that happened and on which machine under + which user. + + To create currrent machine and time information use 'create_new' method. + """ + + timestamp_format = "%Y-%m-%d %H:%M:%S.%f" + + def __init__( + self, timestamp, hostname, hostip, username, system_name, local_id + ): + self.timestamp = timestamp + self._timestamp_obj = datetime.datetime.strptime( + timestamp, self.timestamp_format + ) + self.hostname = hostname + self.hostip = hostip + self.username = username + self.system_name = system_name + self.local_id = local_id + + def copy(self): + return self.from_data(self.to_data()) + + @property + def timestamp_obj(self): + return self._timestamp_obj + + @classmethod + def create_new(cls): + """Create information about this machine for current time.""" + + from openpype.lib.pype_info import get_workstation_info + + now = datetime.datetime.now() + workstation_info = get_workstation_info() + + return cls( + now.strftime(cls.timestamp_format), + workstation_info["hostname"], + workstation_info["hostip"], + workstation_info["username"], + workstation_info["system_name"], + workstation_info["local_id"] + ) + + @classmethod + def from_data(cls, data): + """Create object from data.""" + + return cls( + data["timestamp"], + data["hostname"], + data["hostip"], + data["username"], + data["system_name"], + data["local_id"] + ) + + def to_data(self): + return { + "timestamp": self.timestamp, + "hostname": self.hostname, + "hostip": self.hostip, + "username": self.username, + "system_name": self.system_name, + "local_id": self.local_id, + } + + def __eq__(self, other): + if not isinstance(other, SettingsStateInfo): + return False + + if other.timestamp_obj != self.timestamp_obj: + return False + + return ( + self.hostname == other.hostname + and self.hostip == other.hostip + and self.username == other.username + and self.system_name == other.system_name + and self.local_id == other.local_id + ) + + +class SettingsState: + """State of settings with last saved and last opened. + + Args: + openpype_version (str): OpenPype version string. + settings_type (str): Type of settings. System or project settings. + last_saved_info (Union[None, SettingsStateInfo]): Information about + machine and time when were settings saved last time. + last_opened_info (Union[None, SettingsStateInfo]): This is settings UI + specific information similar to last saved describes who had opened + settings as last. + project_name (Union[None, str]): Identifier for project settings. + """ + + def __init__( + self, + openpype_version, + settings_type, + last_saved_info, + last_opened_info, + project_name=None + ): + self.openpype_version = openpype_version + self.settings_type = settings_type + self.last_saved_info = last_saved_info + self.last_opened_info = last_opened_info + self.project_name = project_name + + def __eq__(self, other): + if not isinstance(other, SettingsState): + return False + + return ( + self.openpype_version == other.openpype_version + and self.settings_type == other.settings_type + and self.last_saved_info == other.last_saved_info + and self.last_opened_info == other.last_opened_info + and self.project_name == other.project_name + ) + + def copy(self): + return self.__class__( + self.openpype_version, + self.settings_type, + self.last_saved_info.copy(), + self.last_opened_info.copy(), + self.project_name + ) + + def on_save(self, openpype_version): + self.openpype_version = openpype_version + self.last_saved_info = SettingsStateInfo.create_new() + + @classmethod + def from_document(cls, openpype_version, settings_type, document): + document = document or {} + last_saved_info = document.get("last_saved_info") + if last_saved_info: + last_saved_info = SettingsStateInfo.from_data(last_saved_info) + + last_opened_info = document.get("last_opened_info") + if last_opened_info: + last_opened_info = SettingsStateInfo.from_data(last_opened_info) + + return cls( + openpype_version, + settings_type, + last_saved_info, + last_opened_info, + document.get("project_name") + ) + + @six.add_metaclass(ABCMeta) class SettingsHandler: @abstractmethod From 17957a760c4c75ded01e944605f164ce058b252c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 11:53:24 +0200 Subject: [PATCH 201/282] 'update_data' and 'update_from_document' always require version --- openpype/settings/handlers.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 8d13875d0b..5a0a30e4a6 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -453,13 +453,12 @@ class CacheValues: return {} return copy.deepcopy(self.data) - def update_data(self, data, version=None): + def update_data(self, data, version): self.data = data self.creation_time = datetime.datetime.now() - if version is not None: - self.version = version + self.version = version - def update_from_document(self, document, version=None): + def update_from_document(self, document, version): data = {} if document: if "data" in document: @@ -468,9 +467,9 @@ class CacheValues: value = document["value"] if value: data = json.loads(value) + self.data = data - if version is not None: - self.version = version + self.version = version def to_json_string(self): return json.dumps(self.data or {}) @@ -1567,7 +1566,7 @@ class MongoLocalSettingsHandler(LocalSettingsHandler): """ data = data or {} - self.local_settings_cache.update_data(data) + self.local_settings_cache.update_data(data, None) self.collection.replace_one( { @@ -1590,6 +1589,6 @@ class MongoLocalSettingsHandler(LocalSettingsHandler): "site_id": self.local_site_id }) - self.local_settings_cache.update_from_document(document) + self.local_settings_cache.update_from_document(document, None) return self.local_settings_cache.data_copy() From 0dc4f1a78622edf932d8623b8ecafdae8c18afc7 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 11:53:49 +0200 Subject: [PATCH 202/282] cache also can have settings state --- openpype/settings/handlers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 5a0a30e4a6..0ee1f74692 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -447,6 +447,7 @@ class CacheValues: self.data = None self.creation_time = None self.version = None + self.settings_state = None def data_copy(self): if not self.data: @@ -458,6 +459,9 @@ class CacheValues: self.creation_time = datetime.datetime.now() self.version = version + def update_settings_state(self, settings_state): + self.settings_state = settings_state + def update_from_document(self, document, version): data = {} if document: From 2b62f28e903e524e66d9520a86ea21ae3df81283 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 15:27:13 +0200 Subject: [PATCH 203/282] fix 'get_representations_parents' function to be able handle hero versions --- openpype/client/entities.py | 88 ++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/openpype/client/entities.py b/openpype/client/entities.py index 67ddb09ddb..f1f1d30214 100644 --- a/openpype/client/entities.py +++ b/openpype/client/entities.py @@ -1259,58 +1259,64 @@ def get_representations_parents(project_name, representations): dict[ObjectId, tuple]: Parents by representation id. """ - repres_by_version_id = collections.defaultdict(list) - versions_by_version_id = {} - versions_by_subset_id = collections.defaultdict(list) - subsets_by_subset_id = {} - subsets_by_asset_id = collections.defaultdict(list) + repre_docs_by_version_id = collections.defaultdict(list) + version_docs_by_version_id = {} + version_docs_by_subset_id = collections.defaultdict(list) + subset_docs_by_subset_id = {} + subset_docs_by_asset_id = collections.defaultdict(list) output = {} - for representation in representations: - repre_id = representation["_id"] + for repre_doc in representations: + repre_id = repre_doc["_id"] + version_id = repre_doc["parent"] output[repre_id] = (None, None, None, None) - version_id = representation["parent"] - repres_by_version_id[version_id].append(representation) + repre_docs_by_version_id[version_id].append(repre_doc) - versions = get_versions( - project_name, version_ids=repres_by_version_id.keys() + version_docs = get_versions( + project_name, + version_ids=repre_docs_by_version_id.keys(), + hero=True ) - for version in versions: - version_id = version["_id"] - subset_id = version["parent"] - versions_by_version_id[version_id] = version - versions_by_subset_id[subset_id].append(version) + for version_doc in version_docs: + version_id = version_doc["_id"] + subset_id = version_doc["parent"] + version_docs_by_version_id[version_id] = version_doc + version_docs_by_subset_id[subset_id].append(version_doc) - subsets = get_subsets( - project_name, subset_ids=versions_by_subset_id.keys() + subset_docs = get_subsets( + project_name, subset_ids=version_docs_by_subset_id.keys() ) - for subset in subsets: - subset_id = subset["_id"] - asset_id = subset["parent"] - subsets_by_subset_id[subset_id] = subset - subsets_by_asset_id[asset_id].append(subset) + for subset_doc in subset_docs: + subset_id = subset_doc["_id"] + asset_id = subset_doc["parent"] + subset_docs_by_subset_id[subset_id] = subset_doc + subset_docs_by_asset_id[asset_id].append(subset_doc) - assets = get_assets(project_name, asset_ids=subsets_by_asset_id.keys()) - assets_by_id = { - asset["_id"]: asset - for asset in assets + asset_docs = get_assets( + project_name, asset_ids=subset_docs_by_asset_id.keys() + ) + asset_docs_by_id = { + asset_doc["_id"]: asset_doc + for asset_doc in asset_docs } - project = get_project(project_name) + project_doc = get_project(project_name) - for version_id, representations in repres_by_version_id.items(): - asset = None - subset = None - version = versions_by_version_id.get(version_id) - if version: - subset_id = version["parent"] - subset = subsets_by_subset_id.get(subset_id) - if subset: - asset_id = subset["parent"] - asset = assets_by_id.get(asset_id) + for version_id, repre_docs in repre_docs_by_version_id.items(): + asset_doc = None + subset_doc = None + version_doc = version_docs_by_version_id.get(version_id) + if version_doc: + subset_id = version_doc["parent"] + subset_doc = subset_docs_by_subset_id.get(subset_id) + if subset_doc: + asset_id = subset_doc["parent"] + asset_doc = asset_docs_by_id.get(asset_id) - for representation in representations: - repre_id = representation["_id"] - output[repre_id] = (version, subset, asset, project) + for repre_doc in repre_docs: + repre_id = repre_doc["_id"] + output[repre_id] = ( + version_doc, subset_doc, asset_doc, project_doc + ) return output From ce746737154e5c7b12f9a0da5ef47b0edd911f64 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 15:28:10 +0200 Subject: [PATCH 204/282] Be explicit in error message what is missing --- openpype/pipeline/load/utils.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/openpype/pipeline/load/utils.py b/openpype/pipeline/load/utils.py index 9945e1fce4..99d6876d4b 100644 --- a/openpype/pipeline/load/utils.py +++ b/openpype/pipeline/load/utils.py @@ -222,13 +222,20 @@ def get_representation_context(representation): project_name, representation ) + if not representation: + raise AssertionError("Representation was not found in database") + version, subset, asset, project = get_representation_parents( project_name, representation ) - - assert all([representation, version, subset, asset, project]), ( - "This is a bug" - ) + if not version: + raise AssertionError("Version was not found in database") + if not subset: + raise AssertionError("Subset was not found in database") + if not asset: + raise AssertionError("Asset was not found in database") + if not project: + raise AssertionError("Project was not found in database") context = { "project": { From 9d54333e93afe14b3686cc429009632cf1f24f00 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 15:28:54 +0200 Subject: [PATCH 205/282] load error can handle invalid hero version --- openpype/tools/loader/widgets.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py index 2d8b4b048d..597c35e89b 100644 --- a/openpype/tools/loader/widgets.py +++ b/openpype/tools/loader/widgets.py @@ -1547,6 +1547,11 @@ def _load_representations_by_loader(loader, repre_contexts, return for repre_context in repre_contexts.values(): + version_doc = repre_context["version"] + if version_doc["type"] == "hero_version": + version_name = "Hero" + else: + version_name = version_doc.get("name") try: if data_by_repre_id: _id = repre_context["representation"]["_id"] @@ -1564,7 +1569,7 @@ def _load_representations_by_loader(loader, repre_contexts, None, repre_context["representation"]["name"], repre_context["subset"]["name"], - repre_context["version"]["name"] + version_name )) except Exception as exc: @@ -1577,7 +1582,7 @@ def _load_representations_by_loader(loader, repre_contexts, formatted_traceback, repre_context["representation"]["name"], repre_context["subset"]["name"], - repre_context["version"]["name"] + version_name )) return error_info From ac6de74b76dd741152c11d71c2262f605847acd7 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 15:33:09 +0200 Subject: [PATCH 206/282] handle hero version type in load clip --- openpype/hosts/nuke/plugins/load/load_clip.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index b2dc4a52d7..346773b5af 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -162,7 +162,15 @@ class LoadClip(plugin.NukeLoader): data_imprint = {} for k in add_keys: if k == 'version': - data_imprint[k] = context["version"]['name'] + version_doc = context["version"] + if version_doc["type"] == "hero_version": + version = "hero" + else: + version = version_doc.get("name") + + if version: + data_imprint[k] = version + elif k == 'colorspace': colorspace = repre["data"].get(k) colorspace = colorspace or version_data.get(k) From 0e6ff4a21d224ed188cdf076a4fd00a1a8f696ea Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 15:59:51 +0200 Subject: [PATCH 207/282] cache can be set to outdated --- openpype/settings/handlers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 0ee1f74692..f6e81a7d0a 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -485,6 +485,9 @@ class CacheValues: delta = (datetime.datetime.now() - self.creation_time).seconds return delta > self.cache_lifetime + def set_outdated(self): + self.create_time = None + class MongoSettingsHandler(SettingsHandler): """Settings handler that use mongo for storing and loading of settings.""" From 4a322f1ceda11843c13627ee5c1f1d9070c82f12 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 16:00:23 +0200 Subject: [PATCH 208/282] removed 'SettingsState' and kept only 'SettingsStateInfo' --- openpype/settings/handlers.py | 152 +++++++++++++++------------------- 1 file changed, 66 insertions(+), 86 deletions(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index f6e81a7d0a..e4b4bc3dc4 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -23,11 +23,11 @@ from .constants import ( class SettingsStateInfo: - """Helper state information for Settings state. + """Helper state information about some settings state. - Is used to hold information about last save and last opened UI. Keep + Is used to hold information about last saved and last opened UI. Keep information about the time when that happened and on which machine under - which user. + which user and on which openpype version. To create currrent machine and time information use 'create_new' method. """ @@ -35,12 +35,28 @@ class SettingsStateInfo: timestamp_format = "%Y-%m-%d %H:%M:%S.%f" def __init__( - self, timestamp, hostname, hostip, username, system_name, local_id + self, + openpype_version, + settings_type, + project_name, + timestamp, + hostname, + hostip, + username, + system_name, + local_id ): + self.openpype_version = openpype_version + self.settings_type = settings_type + self.project_name = project_name + + timestamp_obj = None + if timestamp: + timestamp_obj = datetime.datetime.strptime( + timestamp, self.timestamp_format + ) self.timestamp = timestamp - self._timestamp_obj = datetime.datetime.strptime( - timestamp, self.timestamp_format - ) + self.timestamp_obj = timestamp_obj self.hostname = hostname self.hostip = hostip self.username = username @@ -50,12 +66,8 @@ class SettingsStateInfo: def copy(self): return self.from_data(self.to_data()) - @property - def timestamp_obj(self): - return self._timestamp_obj - @classmethod - def create_new(cls): + def create_new(cls, openpype_version, settings_type, project_name): """Create information about this machine for current time.""" from openpype.lib.pype_info import get_workstation_info @@ -64,6 +76,9 @@ class SettingsStateInfo: workstation_info = get_workstation_info() return cls( + openpype_version, + settings_type, + project_name, now.strftime(cls.timestamp_format), workstation_info["hostname"], workstation_info["hostip"], @@ -77,6 +92,9 @@ class SettingsStateInfo: """Create object from data.""" return cls( + data["openpype_version"], + data["settings_type"], + data["project_name"], data["timestamp"], data["hostname"], data["hostip"], @@ -86,6 +104,40 @@ class SettingsStateInfo: ) def to_data(self): + data = self.to_document_data() + data.update({ + "openpype_version": self.openpype_version, + "settings_type": self.settings_type, + "project_name": self.project_name + }) + return data + + @classmethod + def from_document(cls, openpype_version, settings_type, document): + document = document or {} + project_name = document.get("project_name") + last_saved_info = document.get("last_saved_info") + if last_saved_info: + copy_last_saved_info = copy.deepcopy(last_saved_info) + copy_last_saved_info.update({ + "openpype_version": openpype_version, + "settings_type": settings_type, + "project_name": project_name, + }) + return cls.from_data(copy_last_saved_info) + return cls( + openpype_version, + settings_type, + project_name, + None, + None, + None, + None, + None, + None + ) + + def to_document_data(self): return { "timestamp": self.timestamp, "hostname": self.hostname, @@ -103,7 +155,8 @@ class SettingsStateInfo: return False return ( - self.hostname == other.hostname + self.openpype_version == other.openpype_version + and self.hostname == other.hostname and self.hostip == other.hostip and self.username == other.username and self.system_name == other.system_name @@ -111,79 +164,6 @@ class SettingsStateInfo: ) -class SettingsState: - """State of settings with last saved and last opened. - - Args: - openpype_version (str): OpenPype version string. - settings_type (str): Type of settings. System or project settings. - last_saved_info (Union[None, SettingsStateInfo]): Information about - machine and time when were settings saved last time. - last_opened_info (Union[None, SettingsStateInfo]): This is settings UI - specific information similar to last saved describes who had opened - settings as last. - project_name (Union[None, str]): Identifier for project settings. - """ - - def __init__( - self, - openpype_version, - settings_type, - last_saved_info, - last_opened_info, - project_name=None - ): - self.openpype_version = openpype_version - self.settings_type = settings_type - self.last_saved_info = last_saved_info - self.last_opened_info = last_opened_info - self.project_name = project_name - - def __eq__(self, other): - if not isinstance(other, SettingsState): - return False - - return ( - self.openpype_version == other.openpype_version - and self.settings_type == other.settings_type - and self.last_saved_info == other.last_saved_info - and self.last_opened_info == other.last_opened_info - and self.project_name == other.project_name - ) - - def copy(self): - return self.__class__( - self.openpype_version, - self.settings_type, - self.last_saved_info.copy(), - self.last_opened_info.copy(), - self.project_name - ) - - def on_save(self, openpype_version): - self.openpype_version = openpype_version - self.last_saved_info = SettingsStateInfo.create_new() - - @classmethod - def from_document(cls, openpype_version, settings_type, document): - document = document or {} - last_saved_info = document.get("last_saved_info") - if last_saved_info: - last_saved_info = SettingsStateInfo.from_data(last_saved_info) - - last_opened_info = document.get("last_opened_info") - if last_opened_info: - last_opened_info = SettingsStateInfo.from_data(last_opened_info) - - return cls( - openpype_version, - settings_type, - last_saved_info, - last_opened_info, - document.get("project_name") - ) - - @six.add_metaclass(ABCMeta) class SettingsHandler: @abstractmethod From 20509b4610250c6d6725c50659b0ce3a065b0e92 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 16:02:46 +0200 Subject: [PATCH 209/282] changed 'settings_state' to 'last_saved_info' in cache --- openpype/settings/handlers.py | 44 ++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index e4b4bc3dc4..e34a4c3540 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -368,7 +368,7 @@ class SettingsHandler: """OpenPype versions that have any studio project anatomy overrides. Returns: - list: OpenPype versions strings. + List[str]: OpenPype versions strings. """ pass @@ -379,7 +379,7 @@ class SettingsHandler: """OpenPype versions that have any studio project settings overrides. Returns: - list: OpenPype versions strings. + List[str]: OpenPype versions strings. """ pass @@ -393,8 +393,39 @@ class SettingsHandler: project_name(str): Name of project. Returns: - list: OpenPype versions strings. + List[str]: OpenPype versions strings. """ + + pass + + @abstractmethod + def get_system_last_saved_info(self): + """State of last system settings overrides at the moment when called. + + This method must provide most recent data so using cached data is not + the way. + + Returns: + SettingsStateInfo: Information about system settings overrides. + """ + + pass + + @abstractmethod + def get_project_last_saved_info(self, project_name): + """State of last project settings overrides at the moment when called. + + This method must provide most recent data so using cached data is not + the way. + + Args: + project_name (Union[None, str]): Project name for which state + should be returned. + + Returns: + SettingsStateInfo: Information about project settings overrides. + """ + pass @@ -427,7 +458,7 @@ class CacheValues: self.data = None self.creation_time = None self.version = None - self.settings_state = None + self.last_saved_info = None def data_copy(self): if not self.data: @@ -439,8 +470,8 @@ class CacheValues: self.creation_time = datetime.datetime.now() self.version = version - def update_settings_state(self, settings_state): - self.settings_state = settings_state + def update_last_saved_info(self, last_saved_info): + self.last_saved_info = last_saved_info def update_from_document(self, document, version): data = {} @@ -1288,6 +1319,7 @@ class MongoSettingsHandler(SettingsHandler): self.project_anatomy_cache[project_name].update_from_document( document, version ) + else: project_doc = get_project(project_name) self.project_anatomy_cache[project_name].update_data( From ba434d5f713de2eb478bd1cea533163d482d4033 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 16:03:49 +0200 Subject: [PATCH 210/282] changed how update of settings happens --- openpype/settings/handlers.py | 49 +++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index e34a4c3540..43b1d37c34 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -696,20 +696,28 @@ class MongoSettingsHandler(SettingsHandler): system_settings_data ) - # Store system settings - self.collection.replace_one( + system_settings_doc = self.collection.find_one( { "type": self._system_settings_key, "version": self._current_version }, - { - "type": self._system_settings_key, - "data": system_settings_data, - "version": self._current_version - }, - upsert=True + {"_id": True} ) + # Store system settings + new_system_settings_doc = { + "type": self._system_settings_key, + "version": self._current_version, + "data": system_settings_data, + } + if not system_settings_doc: + self.collections.insert_one(new_system_settings_doc) + else: + self.collections.update_one( + {"_id": system_settings_doc["_id"]}, + {"$set": new_system_settings_doc} + ) + # Store global settings self.collection.replace_one( { @@ -844,26 +852,33 @@ class MongoSettingsHandler(SettingsHandler): def _save_project_data(self, project_name, doc_type, data_cache): is_default = bool(project_name is None) - replace_filter = { + query_filter = { "type": doc_type, "is_default": is_default, "version": self._current_version } - replace_data = { + last_saved_info = data_cache.last_saved_info + new_project_settings_doc = { "type": doc_type, "data": data_cache.data, "is_default": is_default, - "version": self._current_version + "version": self._current_version, } if not is_default: - replace_filter["project_name"] = project_name - replace_data["project_name"] = project_name + query_filter["project_name"] = project_name + new_project_settings_doc["project_name"] = project_name - self.collection.replace_one( - replace_filter, - replace_data, - upsert=True + project_settings_doc = self.collection.find_one( + query_filter, + {"_id": True} ) + if project_settings_doc: + self.collection.update_one( + {"_id": project_settings_doc["_id"]}, + new_project_settings_doc + ) + else: + self.collection.insert_one(new_project_settings_doc) def _get_versions_order_doc(self, projection=None): # TODO cache From 6c9d6b3865cfdce385aba868d61b9cb09985ab88 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 16:05:15 +0200 Subject: [PATCH 211/282] added helper methods for query of override documents --- openpype/settings/handlers.py | 57 +++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 43b1d37c34..6080b5e77f 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -1205,18 +1205,7 @@ class MongoSettingsHandler(SettingsHandler): globals_document = self.collection.find_one({ "type": GLOBAL_SETTINGS_KEY }) - document = ( - self._get_studio_system_settings_overrides_for_version() - ) - if document is None: - document = self._find_closest_system_settings() - - version = None - if document: - if document["type"] == self._system_settings_key: - version = document["version"] - else: - version = LEGACY_SETTINGS_VERSION + document, version = self._get_system_settings_overrides_doc() merged_document = self._apply_global_settings( document, globals_document @@ -1232,21 +1221,27 @@ class MongoSettingsHandler(SettingsHandler): return data, cache.version return data + def _get_system_settings_overrides_doc(self): + document = ( + self._get_studio_system_settings_overrides_for_version() + ) + if document is None: + document = self._find_closest_system_settings() + + version = None + if document: + if document["type"] == self._system_settings_key: + version = document["version"] + else: + version = LEGACY_SETTINGS_VERSION + + return document, version + def _get_project_settings_overrides(self, project_name, return_version): if self.project_settings_cache[project_name].is_outdated: - document = self._get_project_settings_overrides_for_version( + document, version = self._get_project_settings_overrides_doc( project_name ) - if document is None: - document = self._find_closest_project_settings(project_name) - - version = None - if document: - if document["type"] == self._project_settings_key: - version = document["version"] - else: - version = LEGACY_SETTINGS_VERSION - self.project_settings_cache[project_name].update_from_document( document, version ) @@ -1257,6 +1252,22 @@ class MongoSettingsHandler(SettingsHandler): return data, cache.version return data + def _get_project_settings_overrides_doc(self, project_name): + document = self._get_project_settings_overrides_for_version( + project_name + ) + if document is None: + document = self._find_closest_project_settings(project_name) + + version = None + if document: + if document["type"] == self._project_settings_key: + version = document["version"] + else: + version = LEGACY_SETTINGS_VERSION + + return document, version + def get_studio_project_settings_overrides(self, return_version): """Studio overrides of default project settings.""" return self._get_project_settings_overrides(None, return_version) From 8f121275bdbb08eb686ce482f529b97c96dfe1cb Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 16:06:11 +0200 Subject: [PATCH 212/282] implemented methods to get last saved information --- openpype/settings/handlers.py | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 6080b5e77f..af2bf104de 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -688,6 +688,15 @@ class MongoSettingsHandler(SettingsHandler): # Update cache self.system_settings_cache.update_data(data, self._current_version) + last_saved_info = SettingsStateInfo.create_new( + self._current_version, + SYSTEM_SETTINGS_KEY, + None + ) + self.system_settings_cache.update_last_saved_info( + last_saved_info + ) + # Get copy of just updated cache system_settings_data = self.system_settings_cache.data_copy() @@ -709,6 +718,7 @@ class MongoSettingsHandler(SettingsHandler): "type": self._system_settings_key, "version": self._current_version, "data": system_settings_data, + "last_saved_info": last_saved_info.to_document_data() } if not system_settings_doc: self.collections.insert_one(new_system_settings_doc) @@ -749,6 +759,14 @@ class MongoSettingsHandler(SettingsHandler): data_cache = self.project_settings_cache[project_name] data_cache.update_data(overrides, self._current_version) + last_saved_info = SettingsStateInfo.create_new( + self._current_version, + PROJECT_SETTINGS_KEY, + project_name + ) + + data_cache.update_last_saved_info(last_saved_info) + self._save_project_data( project_name, self._project_settings_key, data_cache ) @@ -863,6 +881,7 @@ class MongoSettingsHandler(SettingsHandler): "data": data_cache.data, "is_default": is_default, "version": self._current_version, + "last_saved_info": last_saved_info.to_data() } if not is_default: query_filter["project_name"] = project_name @@ -1207,6 +1226,9 @@ class MongoSettingsHandler(SettingsHandler): }) document, version = self._get_system_settings_overrides_doc() + last_saved_info = SettingsStateInfo.from_document( + version, SYSTEM_SETTINGS_KEY, document + ) merged_document = self._apply_global_settings( document, globals_document ) @@ -1214,6 +1236,9 @@ class MongoSettingsHandler(SettingsHandler): self.system_settings_cache.update_from_document( merged_document, version ) + self.system_settings_cache.update_last_saved_info( + last_saved_info + ) cache = self.system_settings_cache data = cache.data_copy() @@ -1237,6 +1262,13 @@ class MongoSettingsHandler(SettingsHandler): return document, version + def get_system_last_saved_info(self): + # Make sure settings are recaches + self.system_settings_cache.set_outdated() + self.get_studio_system_settings_overrides(False) + + return self.system_settings_cache.last_saved_info.copy() + def _get_project_settings_overrides(self, project_name, return_version): if self.project_settings_cache[project_name].is_outdated: document, version = self._get_project_settings_overrides_doc( @@ -1245,6 +1277,12 @@ class MongoSettingsHandler(SettingsHandler): self.project_settings_cache[project_name].update_from_document( document, version ) + last_saved_info = SettingsStateInfo.from_document( + version, PROJECT_SETTINGS_KEY, document + ) + self.project_settings_cache[project_name].update_last_saved_info( + last_saved_info + ) cache = self.project_settings_cache[project_name] data = cache.data_copy() @@ -1268,6 +1306,13 @@ class MongoSettingsHandler(SettingsHandler): return document, version + def get_project_last_saved_info(self, project_name): + # Make sure settings are recaches + self.project_settings_cache[project_name].set_outdated() + self._get_project_settings_overrides(project_name, False) + + return self.project_settings_cache[project_name].last_saved_info.copy() + def get_studio_project_settings_overrides(self, return_version): """Studio overrides of default project settings.""" return self._get_project_settings_overrides(None, return_version) From 9ea46a2a3690df28c2781cdd0919ed44e0d275fc Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 16:45:37 +0200 Subject: [PATCH 213/282] make available api functions in settings to have access to lock information and last saved information --- openpype/settings/handlers.py | 127 +++++++++++++++++++++++++++++++++- openpype/settings/lib.py | 25 +++++++ 2 files changed, 149 insertions(+), 3 deletions(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index af2bf104de..3dc33503ea 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -67,7 +67,9 @@ class SettingsStateInfo: return self.from_data(self.to_data()) @classmethod - def create_new(cls, openpype_version, settings_type, project_name): + def create_new( + cls, openpype_version, settings_type=None, project_name=None + ): """Create information about this machine for current time.""" from openpype.lib.pype_info import get_workstation_info @@ -112,6 +114,20 @@ class SettingsStateInfo: }) return data + @classmethod + def create_new_empty(cls, openpype_version, settings_type=None): + return cls( + openpype_version, + settings_type, + None, + None, + None, + None, + None, + None, + None + ) + @classmethod def from_document(cls, openpype_version, settings_type, document): document = document or {} @@ -428,6 +444,54 @@ class SettingsHandler: pass + # UI related calls + @abstractmethod + def get_last_opened_info(self): + """Get information about last opened UI. + + Last opened UI is empty if there is noone who would have opened UI at + the moment when called. + + Returns: + Union[None, SettingsStateInfo]: Information about machine who had + opened Settings UI. + """ + + pass + + @abstractmethod + def opened_ui(self): + """Callback called when settings UI is opened. + + Information about this machine must be available when + 'get_last_opened_info' is called from anywhere until 'closed_ui' is + called again. + + Returns: + SettingsStateInfo: Object representing information about this + machine. Must be passed to 'closed_ui' when finished. + """ + + pass + + @abstractmethod + def closed_ui(self, info_obj): + """Callback called when settings UI is closed. + + From the moment this method is called the information about this + machine is removed and no more available when 'get_last_opened_info' + is called. + + Callback should validate if this machine is still stored as opened ui + before changing any value. + + Args: + info_obj (SettingsStateInfo): Object created when 'opened_ui' was + called. + """ + + pass + @six.add_metaclass(ABCMeta) class LocalSettingsHandler: @@ -690,8 +754,7 @@ class MongoSettingsHandler(SettingsHandler): last_saved_info = SettingsStateInfo.create_new( self._current_version, - SYSTEM_SETTINGS_KEY, - None + SYSTEM_SETTINGS_KEY ) self.system_settings_cache.update_last_saved_info( last_saved_info @@ -1610,6 +1673,64 @@ class MongoSettingsHandler(SettingsHandler): return output return self._sort_versions(output) + def get_last_opened_info(self): + doc = self.collection.find_one({ + "type": "last_opened_settings_ui", + "version": self._current_version + }) or {} + info_data = doc.get("info") + if not info_data: + return SettingsStateInfo.create_new_empty(self._current_version) + + # Fill not available information + info_data["openpype_version"] = self._current_version + info_data["settings_type"] = None + info_data["project_name"] = None + return SettingsStateInfo.from_data(info_data) + + def opened_ui(self): + doc_filter = { + "type": "last_opened_settings_ui", + "version": self._current_version + } + + opened_info = SettingsStateInfo.create_new(self._current_version) + new_doc_data = copy.deepcopy(doc_filter) + new_doc_data["info"] = opened_info.to_document_data() + + doc = self.collection.find_one( + doc_filter, + {"_id": True} + ) + if doc: + self.collection.update_one( + {"_id": doc["_id"]}, + {"$set": new_doc_data} + ) + else: + self.collection.insert_one(new_doc_data) + return opened_info + + def closed_ui(self, info_obj): + doc_filter = { + "type": "last_opened_settings_ui", + "version": self._current_version + } + doc = self.collection.find_one(doc_filter) or {} + info_data = doc.get("info") + if not info_data: + return + + info_data["openpype_version"] = self._current_version + info_data["settings_type"] = None + info_data["project_name"] = None + current_info = SettingsStateInfo.from_data(info_data) + if current_info == info_obj: + self.collection.update_one( + {"_id": doc["_id"]}, + {"$set": {"info": None}} + ) + class MongoLocalSettingsHandler(LocalSettingsHandler): """Settings handler that use mongo for store and load local settings. diff --git a/openpype/settings/lib.py b/openpype/settings/lib.py index 6df41112c8..58cfd3862c 100644 --- a/openpype/settings/lib.py +++ b/openpype/settings/lib.py @@ -91,6 +91,31 @@ def calculate_changes(old_value, new_value): return changes +@require_handler +def get_system_last_saved_info(): + return _SETTINGS_HANDLER.get_system_last_saved_info() + + +@require_handler +def get_project_last_saved_info(project_name): + return _SETTINGS_HANDLER.get_project_last_saved_info(project_name) + + +@require_handler +def get_last_opened_info(): + return _SETTINGS_HANDLER.get_last_opened_info() + + +@require_handler +def opened_ui(): + return _SETTINGS_HANDLER.opened_ui() + + +@require_handler +def closed_ui(info_obj): + return _SETTINGS_HANDLER.closed_ui(info_obj) + + @require_handler def save_studio_settings(data): """Save studio overrides of system settings. From 2b6d705c441fb147945a53d435895e919dc0111b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 18 Aug 2022 17:16:51 +0200 Subject: [PATCH 214/282] Added better logging when DL fails In some specific cases DL sends broken json payload even if response.ok. Handle parsing of broken json better. --- openpype/modules/deadline/abstract_submit_deadline.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index 3f54273a56..5cf8222b1c 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -4,6 +4,7 @@ It provides Deadline JobInfo data class. """ +import json.decoder import os from abc import abstractmethod import platform @@ -627,7 +628,12 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin): self.log.debug(payload) raise RuntimeError(response.text) - result = response.json() + try: + result = response.json() + except json.decoder.JSONDecodeError: + self.log.warning("Broken response {}".format(response)) + raise RuntimeError("Broken response from DL") + # for submit publish job self._instance.data["deadlineSubmissionJob"] = result From beedfd2ecee833854db505e0566de377a8243649 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 18 Aug 2022 17:22:28 +0200 Subject: [PATCH 215/282] Added better logging when DL fails In some specific cases DL sends broken json payload even if response.ok. Handle parsing of broken json better. --- openpype/modules/deadline/abstract_submit_deadline.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index 5cf8222b1c..c38f16149e 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -631,7 +631,9 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin): try: result = response.json() except json.decoder.JSONDecodeError: - self.log.warning("Broken response {}".format(response)) + msg = "Broken response {}. ".format(response) + msg += "Try restarting DL webservice" + self.log.warning() raise RuntimeError("Broken response from DL") # for submit publish job From 9251a0fd4294725a5fb1dfbef68788c409554230 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 18:09:55 +0200 Subject: [PATCH 216/282] changed function names --- openpype/settings/handlers.py | 20 ++++++++++---------- openpype/settings/lib.py | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 3dc33503ea..1b59531943 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -460,22 +460,22 @@ class SettingsHandler: pass @abstractmethod - def opened_ui(self): + def opened_settings_ui(self): """Callback called when settings UI is opened. Information about this machine must be available when - 'get_last_opened_info' is called from anywhere until 'closed_ui' is - called again. + 'get_last_opened_info' is called from anywhere until + 'closed_settings_ui' is called again. Returns: SettingsStateInfo: Object representing information about this - machine. Must be passed to 'closed_ui' when finished. + machine. Must be passed to 'closed_settings_ui' when finished. """ pass @abstractmethod - def closed_ui(self, info_obj): + def closed_settings_ui(self, info_obj): """Callback called when settings UI is closed. From the moment this method is called the information about this @@ -486,8 +486,8 @@ class SettingsHandler: before changing any value. Args: - info_obj (SettingsStateInfo): Object created when 'opened_ui' was - called. + info_obj (SettingsStateInfo): Object created when + 'opened_settings_ui' was called. """ pass @@ -1680,7 +1680,7 @@ class MongoSettingsHandler(SettingsHandler): }) or {} info_data = doc.get("info") if not info_data: - return SettingsStateInfo.create_new_empty(self._current_version) + return None # Fill not available information info_data["openpype_version"] = self._current_version @@ -1688,7 +1688,7 @@ class MongoSettingsHandler(SettingsHandler): info_data["project_name"] = None return SettingsStateInfo.from_data(info_data) - def opened_ui(self): + def opened_settings_ui(self): doc_filter = { "type": "last_opened_settings_ui", "version": self._current_version @@ -1711,7 +1711,7 @@ class MongoSettingsHandler(SettingsHandler): self.collection.insert_one(new_doc_data) return opened_info - def closed_ui(self, info_obj): + def closed_settings_ui(self, info_obj): doc_filter = { "type": "last_opened_settings_ui", "version": self._current_version diff --git a/openpype/settings/lib.py b/openpype/settings/lib.py index 58cfd3862c..5eaddf6e6e 100644 --- a/openpype/settings/lib.py +++ b/openpype/settings/lib.py @@ -107,13 +107,13 @@ def get_last_opened_info(): @require_handler -def opened_ui(): - return _SETTINGS_HANDLER.opened_ui() +def opened_settings_ui(): + return _SETTINGS_HANDLER.opened_settings_ui() @require_handler -def closed_ui(info_obj): - return _SETTINGS_HANDLER.closed_ui(info_obj) +def closed_settings_ui(info_obj): + return _SETTINGS_HANDLER.closed_settings_ui(info_obj) @require_handler From baa2505fbfa2055aded2e2c439805d44a3a82347 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 18:10:32 +0200 Subject: [PATCH 217/282] show a dialog if someone else has opened settings UI --- openpype/tools/settings/settings/window.py | 136 ++++++++++++++++++++- 1 file changed, 131 insertions(+), 5 deletions(-) diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index 22778e4a5b..96f11f3932 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -1,4 +1,16 @@ from Qt import QtWidgets, QtGui, QtCore + +from openpype import style + +from openpype.lib import is_admin_password_required +from openpype.widgets import PasswordDialog + +from openpype.settings.lib import ( + get_last_opened_info, + opened_settings_ui, + closed_settings_ui, +) + from .categories import ( CategoryState, SystemWidget, @@ -10,10 +22,6 @@ from .widgets import ( SettingsTabWidget ) from .search_dialog import SearchEntitiesDialog -from openpype import style - -from openpype.lib import is_admin_password_required -from openpype.widgets import PasswordDialog class MainWidget(QtWidgets.QWidget): @@ -25,6 +33,10 @@ class MainWidget(QtWidgets.QWidget): def __init__(self, user_role, parent=None, reset_on_show=True): super(MainWidget, self).__init__(parent) + # Object referencing to this machine and time when UI was opened + # - is used on close event + self._last_opened_info = None + self._user_passed = False self._reset_on_show = reset_on_show @@ -74,7 +86,7 @@ class MainWidget(QtWidgets.QWidget): self._on_restart_required ) tab_widget.reset_started.connect(self._on_reset_started) - tab_widget.reset_started.connect(self._on_reset_finished) + tab_widget.reset_finished.connect(self._on_reset_finished) tab_widget.full_path_requested.connect(self._on_full_path_request) header_tab_widget.context_menu_requested.connect( @@ -131,11 +143,38 @@ class MainWidget(QtWidgets.QWidget): def showEvent(self, event): super(MainWidget, self).showEvent(event) + if self._reset_on_show: self._reset_on_show = False # Trigger reset with 100ms delay QtCore.QTimer.singleShot(100, self.reset) + elif not self._last_opened_info: + self._check_on_ui_open() + + def _check_on_ui_open(self): + last_opened_info = get_last_opened_info() + if last_opened_info is not None: + if self._last_opened_info != last_opened_info: + self._last_opened_info = None + else: + self._last_opened_info = opened_settings_ui() + + if self._last_opened_info is not None: + return + + dialog = SettingsUIOpenedElsewhere(last_opened_info, self) + dialog.exec_() + if dialog.result() == 1: + self._last_opened_info = opened_settings_ui() + return + + def closeEvent(self, event): + if self._last_opened_info: + closed_settings_ui(self._last_opened_info) + self._last_opened_info = None + super(MainWidget, self).closeEvent(event) + def _show_password_dialog(self): if self._password_dialog: self._password_dialog.open() @@ -221,6 +260,8 @@ class MainWidget(QtWidgets.QWidget): if current_widget is widget: self._update_search_dialog() + self._check_on_ui_open() + def keyPressEvent(self, event): if event.matches(QtGui.QKeySequence.Find): # todo: search in all widgets (or in active)? @@ -231,3 +272,88 @@ class MainWidget(QtWidgets.QWidget): return return super(MainWidget, self).keyPressEvent(event) + + +class SettingsUIOpenedElsewhere(QtWidgets.QDialog): + def __init__(self, info_obj, parent=None): + super(SettingsUIOpenedElsewhere, self).__init__(parent) + + self._result = 0 + + self.setWindowTitle("Someone else has opened Settings UI") + + message_label = QtWidgets.QLabel(( + "Someone else has opened Settings UI. That may cause data loss." + " Please contact the person on the other side." + "

    You can open the UI in view-only mode or take" + " the control which will cause the other settings won't be able" + " to save changes.
    " + ), self) + message_label.setWordWrap(True) + + separator_widget_1 = QtWidgets.QFrame(self) + separator_widget_2 = QtWidgets.QFrame(self) + for separator_widget in ( + separator_widget_1, + separator_widget_2 + ): + separator_widget.setObjectName("Separator") + separator_widget.setMinimumHeight(1) + separator_widget.setMaximumHeight(1) + + other_information = QtWidgets.QWidget(self) + other_information_layout = QtWidgets.QFormLayout(other_information) + other_information_layout.setContentsMargins(0, 0, 0, 0) + for label, value in ( + ("Username", info_obj.username), + ("Host name", info_obj.hostname), + ("Host IP", info_obj.hostip), + ("System name", info_obj.system_name), + ("Local ID", info_obj.local_id), + ("Time Stamp", info_obj.timestamp), + ): + other_information_layout.addRow( + label, + QtWidgets.QLabel(value, other_information) + ) + + footer_widget = QtWidgets.QWidget(self) + buttons_widget = QtWidgets.QWidget(footer_widget) + + take_control_btn = QtWidgets.QPushButton( + "Take control", buttons_widget + ) + view_mode_btn = QtWidgets.QPushButton( + "View only", buttons_widget + ) + + buttons_layout = QtWidgets.QHBoxLayout(buttons_widget) + buttons_layout.setContentsMargins(0, 0, 0, 0) + buttons_layout.addWidget(take_control_btn, 1) + buttons_layout.addWidget(view_mode_btn, 1) + + footer_layout = QtWidgets.QHBoxLayout(footer_widget) + footer_layout.setContentsMargins(0, 0, 0, 0) + footer_layout.addStretch(1) + footer_layout.addWidget(buttons_widget, 0) + + layout = QtWidgets.QVBoxLayout(self) + layout.addWidget(message_label, 0) + layout.addWidget(separator_widget_1, 0) + layout.addWidget(other_information, 1, QtCore.Qt.AlignHCenter) + layout.addWidget(separator_widget_2, 0) + layout.addWidget(footer_widget, 0) + + take_control_btn.clicked.connect(self._on_take_control) + view_mode_btn.clicked.connect(self._on_view_mode) + + def result(self): + return self._result + + def _on_take_control(self): + self._result = 1 + self.close() + + def _on_view_mode(self): + self._result = 0 + self.close() From 936363a6608aed3bf4bc4b2a2b6977b9f6d03142 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Thu, 18 Aug 2022 18:45:54 +0200 Subject: [PATCH 218/282] settings can take go to view mode or take control --- .../tools/settings/settings/categories.py | 19 ++++++++++ openpype/tools/settings/settings/window.py | 38 +++++++++++++++---- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index f42027d9e2..0410fa1810 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -121,6 +121,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget): self.user_role = user_role self.entity = None + self._edit_mode = None self._state = CategoryState.Idle @@ -191,6 +192,21 @@ class SettingsCategoryWidget(QtWidgets.QWidget): ) raise TypeError("Unknown type: {}".format(label)) + def set_edit_mode(self, enabled): + if enabled is self._edit_mode: + return + + self.save_btn.setEnabled(enabled) + if enabled: + tooltip = ( + "Someone else has opened settings UI." + "\nTry hit refresh to check if settings are already available." + ) + else: + tooltip = "Save settings" + + self.save_btn.setToolTip(tooltip) + @property def state(self): return self._state @@ -434,6 +450,9 @@ class SettingsCategoryWidget(QtWidgets.QWidget): self.set_state(CategoryState.Idle) def save(self): + if not self._edit_mode: + return + if not self.items_are_valid(): return diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index 96f11f3932..013a273e98 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -36,6 +36,8 @@ class MainWidget(QtWidgets.QWidget): # Object referencing to this machine and time when UI was opened # - is used on close event self._last_opened_info = None + self._edit_mode = None + self._main_reset = False self._user_passed = False self._reset_on_show = reset_on_show @@ -152,6 +154,12 @@ class MainWidget(QtWidgets.QWidget): elif not self._last_opened_info: self._check_on_ui_open() + def closeEvent(self, event): + if self._last_opened_info: + closed_settings_ui(self._last_opened_info) + self._last_opened_info = None + super(MainWidget, self).closeEvent(event) + def _check_on_ui_open(self): last_opened_info = get_last_opened_info() if last_opened_info is not None: @@ -161,19 +169,27 @@ class MainWidget(QtWidgets.QWidget): self._last_opened_info = opened_settings_ui() if self._last_opened_info is not None: + if self._edit_mode is not True: + self._set_edit_mode(True) + return + + if self._edit_mode is False: return dialog = SettingsUIOpenedElsewhere(last_opened_info, self) dialog.exec_() - if dialog.result() == 1: + edit_enabled = dialog.result() == 1 + if edit_enabled: self._last_opened_info = opened_settings_ui() + self._set_edit_mode(edit_enabled) + + def _set_edit_mode(self, mode): + if self._edit_mode is mode: return - def closeEvent(self, event): - if self._last_opened_info: - closed_settings_ui(self._last_opened_info) - self._last_opened_info = None - super(MainWidget, self).closeEvent(event) + self._edit_mode = mode + for tab_widget in self.tab_widgets: + tab_widget.set_edit_mode(mode) def _show_password_dialog(self): if self._password_dialog: @@ -215,8 +231,11 @@ class MainWidget(QtWidgets.QWidget): if self._reset_on_show: self._reset_on_show = False + self._main_reset = True for tab_widget in self.tab_widgets: tab_widget.reset() + self._main_reset = False + self._check_on_ui_open() def _update_search_dialog(self, clear=False): if self._search_dialog.isVisible(): @@ -260,7 +279,8 @@ class MainWidget(QtWidgets.QWidget): if current_widget is widget: self._update_search_dialog() - self._check_on_ui_open() + if not self._main_reset: + self._check_on_ui_open() def keyPressEvent(self, event): if event.matches(QtGui.QKeySequence.Find): @@ -340,7 +360,9 @@ class SettingsUIOpenedElsewhere(QtWidgets.QDialog): layout = QtWidgets.QVBoxLayout(self) layout.addWidget(message_label, 0) layout.addWidget(separator_widget_1, 0) - layout.addWidget(other_information, 1, QtCore.Qt.AlignHCenter) + layout.addStretch(1) + layout.addWidget(other_information, 0, QtCore.Qt.AlignHCenter) + layout.addStretch(1) layout.addWidget(separator_widget_2, 0) layout.addWidget(footer_widget, 0) From 70cfa733f3e7e985580ec8fff8520c31ec5184c8 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Thu, 18 Aug 2022 18:34:34 +0000 Subject: [PATCH 219/282] [Automated] Bump version --- CHANGELOG.md | 27 +++++++++++++++++++-------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80673e9f8a..b192d26250 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,25 @@ # Changelog -## [3.13.1-nightly.3](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.14.0-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.13.0...HEAD) +**🆕 New features** + +- Maya: Build workfile by template [\#3578](https://github.com/pypeclub/OpenPype/pull/3578) + +**🚀 Enhancements** + +- Ftrack: Addiotional component metadata [\#3685](https://github.com/pypeclub/OpenPype/pull/3685) +- Ftrack: Set task status on farm publishing [\#3680](https://github.com/pypeclub/OpenPype/pull/3680) +- Ftrack: Set task status on task creation in integrate hierarchy [\#3675](https://github.com/pypeclub/OpenPype/pull/3675) +- Maya: Disable rendering of all lights for render instances submitted through Deadline. [\#3661](https://github.com/pypeclub/OpenPype/pull/3661) +- General: Optimized OCIO configs [\#3650](https://github.com/pypeclub/OpenPype/pull/3650) + **🐛 Bug fixes** +- General: Switch from hero version to versioned works [\#3691](https://github.com/pypeclub/OpenPype/pull/3691) +- General: Fix finding of last version [\#3656](https://github.com/pypeclub/OpenPype/pull/3656) - General: Extract Review can scale with pixel aspect ratio [\#3644](https://github.com/pypeclub/OpenPype/pull/3644) - Maya: Refactor moved usage of CreateRender settings [\#3643](https://github.com/pypeclub/OpenPype/pull/3643) - General: Hero version representations have full context [\#3638](https://github.com/pypeclub/OpenPype/pull/3638) @@ -14,8 +28,12 @@ **🔀 Refactored code** +- General: Use client projects getter [\#3673](https://github.com/pypeclub/OpenPype/pull/3673) +- Resolve: Match folder structure to other hosts [\#3653](https://github.com/pypeclub/OpenPype/pull/3653) +- Maya: Hosts as modules [\#3647](https://github.com/pypeclub/OpenPype/pull/3647) - TimersManager: Plugins are in timers manager module [\#3639](https://github.com/pypeclub/OpenPype/pull/3639) - General: Move workfiles functions into pipeline [\#3637](https://github.com/pypeclub/OpenPype/pull/3637) +- General: Workfiles builder using query functions [\#3598](https://github.com/pypeclub/OpenPype/pull/3598) **Merged pull requests:** @@ -89,7 +107,6 @@ **🚀 Enhancements** - General: Global thumbnail extractor is ready for more cases [\#3561](https://github.com/pypeclub/OpenPype/pull/3561) -- Maya: add additional validators to Settings [\#3540](https://github.com/pypeclub/OpenPype/pull/3540) **🐛 Bug fixes** @@ -100,16 +117,10 @@ - General: Remove hosts filter on integrator plugins [\#3556](https://github.com/pypeclub/OpenPype/pull/3556) - Settings: Clean default values of environments [\#3550](https://github.com/pypeclub/OpenPype/pull/3550) - Module interfaces: Fix import error [\#3547](https://github.com/pypeclub/OpenPype/pull/3547) -- Workfiles tool: Show of tool and it's flags [\#3539](https://github.com/pypeclub/OpenPype/pull/3539) -- General: Create workfile documents works again [\#3538](https://github.com/pypeclub/OpenPype/pull/3538) **🔀 Refactored code** - General: Use query functions in integrator [\#3563](https://github.com/pypeclub/OpenPype/pull/3563) -- General: Mongo core connection moved to client [\#3531](https://github.com/pypeclub/OpenPype/pull/3531) -- Refactor Integrate Asset [\#3530](https://github.com/pypeclub/OpenPype/pull/3530) -- General: Client docstrings cleanup [\#3529](https://github.com/pypeclub/OpenPype/pull/3529) -- General: Move load related functions into pipeline [\#3527](https://github.com/pypeclub/OpenPype/pull/3527) **Merged pull requests:** diff --git a/openpype/version.py b/openpype/version.py index 9ae52e8370..38723ed123 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.13.1-nightly.3" +__version__ = "3.14.0-nightly.1" diff --git a/pyproject.toml b/pyproject.toml index 287a3c78f0..4d4aff01a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.13.1-nightly.3" # OpenPype +version = "3.14.0-nightly.1" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 9f879bb22a2a01fe17adc1b7e9e61df8603e6537 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Thu, 18 Aug 2022 18:47:09 +0000 Subject: [PATCH 220/282] [Automated] Release --- CHANGELOG.md | 6 +++--- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b192d26250..e19993ad75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [3.14.0-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.14.0](https://github.com/pypeclub/OpenPype/tree/3.14.0) (2022-08-18) -[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.13.0...HEAD) +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.13.0...3.14.0) **🆕 New features** @@ -25,6 +25,7 @@ - General: Hero version representations have full context [\#3638](https://github.com/pypeclub/OpenPype/pull/3638) - Nuke: color settings for render write node is working now [\#3632](https://github.com/pypeclub/OpenPype/pull/3632) - Maya: FBX support for update in reference loader [\#3631](https://github.com/pypeclub/OpenPype/pull/3631) +- Integrator: Don't force to have dot before frame [\#3611](https://github.com/pypeclub/OpenPype/pull/3611) **🔀 Refactored code** @@ -69,7 +70,6 @@ - Ftrack: Sync hierarchical attributes can handle new created entities [\#3621](https://github.com/pypeclub/OpenPype/pull/3621) - General: Extract review aspect ratio scale is calculated by ffmpeg [\#3620](https://github.com/pypeclub/OpenPype/pull/3620) - Maya: Fix types of default settings [\#3617](https://github.com/pypeclub/OpenPype/pull/3617) -- Integrator: Don't force to have dot before frame [\#3611](https://github.com/pypeclub/OpenPype/pull/3611) - AfterEffects: refactored integrate doesnt work formulti frame publishes [\#3610](https://github.com/pypeclub/OpenPype/pull/3610) - Maya look data contents fails with custom attribute on group [\#3607](https://github.com/pypeclub/OpenPype/pull/3607) - TrayPublisher: Fix wrong conflict merge [\#3600](https://github.com/pypeclub/OpenPype/pull/3600) diff --git a/openpype/version.py b/openpype/version.py index 38723ed123..c28b480940 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.0-nightly.1" +__version__ = "3.14.0" diff --git a/pyproject.toml b/pyproject.toml index 4d4aff01a2..e670d0a2ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.14.0-nightly.1" # OpenPype +version = "3.14.0" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 407b6b518e0da63e8efd021952c01b6311cf0640 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 19 Aug 2022 12:05:38 +0200 Subject: [PATCH 221/282] use controlled to handle last opened info --- .../tools/settings/settings/categories.py | 23 ++- openpype/tools/settings/settings/window.py | 136 ++++++++++++------ 2 files changed, 114 insertions(+), 45 deletions(-) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index 0410fa1810..2e3c6d9dda 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -115,13 +115,19 @@ class SettingsCategoryWidget(QtWidgets.QWidget): "settings to update them to you current running OpenPype version." ) - def __init__(self, user_role, parent=None): + def __init__(self, controller, parent=None): super(SettingsCategoryWidget, self).__init__(parent) - self.user_role = user_role + self._controller = controller + controller.event_system.add_callback( + "edit.mode.changed", + self._edit_mode_changed + ) self.entity = None self._edit_mode = None + self._last_saved_info = None + self._reset_crashed = False self._state = CategoryState.Idle @@ -192,11 +198,16 @@ class SettingsCategoryWidget(QtWidgets.QWidget): ) raise TypeError("Unknown type: {}".format(label)) + def _edit_mode_changed(self, event): + self.set_edit_mode(event["edit_mode"]) + def set_edit_mode(self, enabled): if enabled is self._edit_mode: return - self.save_btn.setEnabled(enabled) + self._edit_mode = enabled + + self.save_btn.setEnabled(enabled and not self._reset_crashed) if enabled: tooltip = ( "Someone else has opened settings UI." @@ -302,7 +313,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget): footer_layout = QtWidgets.QHBoxLayout(footer_widget) footer_layout.setContentsMargins(5, 5, 5, 5) - if self.user_role == "developer": + if self._controller.user_role == "developer": self._add_developer_ui(footer_layout, footer_widget) footer_layout.addWidget(empty_label, 1) @@ -683,14 +694,16 @@ class SettingsCategoryWidget(QtWidgets.QWidget): ) def _on_reset_crash(self): + self._reset_crashed = True self.save_btn.setEnabled(False) if self.breadcrumbs_model is not None: self.breadcrumbs_model.set_entity(None) def _on_reset_success(self): + self._reset_crashed = True if not self.save_btn.isEnabled(): - self.save_btn.setEnabled(True) + self.save_btn.setEnabled(self._edit_mode) if self.breadcrumbs_model is not None: path = self.breadcrumbs_bar.path() diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index 013a273e98..612975e30a 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -3,6 +3,7 @@ from Qt import QtWidgets, QtGui, QtCore from openpype import style from openpype.lib import is_admin_password_required +from openpype.lib.events import EventSystem from openpype.widgets import PasswordDialog from openpype.settings.lib import ( @@ -24,6 +25,81 @@ from .widgets import ( from .search_dialog import SearchEntitiesDialog +class SettingsController: + """Controller for settings tools. + + Added when tool was finished for checks of last opened in settings + categories and being able communicated with main widget logic. + """ + + def __init__(self, user_role): + self._user_role = user_role + self._event_system = EventSystem() + + self._opened_info = None + self._last_opened_info = None + self._edit_mode = None + + @property + def user_role(self): + return self._user_role + + @property + def event_system(self): + return self._event_system + + @property + def opened_info(self): + return self._opened_info + + @property + def last_opened_info(self): + return self._last_opened_info + + @property + def edit_mode(self): + return self._edit_mode + + def ui_closed(self): + if self._opened_info is not None: + closed_settings_ui(self._opened_info) + + self._opened_info = None + self._edit_mode = None + + def set_edit_mode(self, enabled): + if self._edit_mode is enabled: + return + + opened_info = None + if enabled: + opened_info = opened_settings_ui() + self._last_opened_info = opened_info + + self._opened_info = opened_info + self._edit_mode = enabled + + self.event_system.emit( + "edit.mode.changed", + {"edit_mode": enabled}, + "controller" + ) + + def update_last_opened_info(self): + print("update_last_opened_info") + last_opened_info = get_last_opened_info() + enabled = False + if ( + last_opened_info is None + or self._opened_info == last_opened_info + ): + enabled = True + + self._last_opened_info = last_opened_info + + self.set_edit_mode(enabled) + + class MainWidget(QtWidgets.QWidget): trigger_restart = QtCore.Signal() @@ -33,11 +109,12 @@ class MainWidget(QtWidgets.QWidget): def __init__(self, user_role, parent=None, reset_on_show=True): super(MainWidget, self).__init__(parent) + controller = SettingsController(user_role) + # Object referencing to this machine and time when UI was opened # - is used on close event - self._last_opened_info = None - self._edit_mode = None self._main_reset = False + self._controller = controller self._user_passed = False self._reset_on_show = reset_on_show @@ -55,8 +132,8 @@ class MainWidget(QtWidgets.QWidget): header_tab_widget = SettingsTabWidget(parent=self) - studio_widget = SystemWidget(user_role, header_tab_widget) - project_widget = ProjectWidget(user_role, header_tab_widget) + studio_widget = SystemWidget(controller, header_tab_widget) + project_widget = ProjectWidget(controller, header_tab_widget) tab_widgets = [ studio_widget, @@ -151,45 +228,24 @@ class MainWidget(QtWidgets.QWidget): # Trigger reset with 100ms delay QtCore.QTimer.singleShot(100, self.reset) - elif not self._last_opened_info: - self._check_on_ui_open() - def closeEvent(self, event): - if self._last_opened_info: - closed_settings_ui(self._last_opened_info) - self._last_opened_info = None + self._controller.ui_closed() + super(MainWidget, self).closeEvent(event) - def _check_on_ui_open(self): - last_opened_info = get_last_opened_info() - if last_opened_info is not None: - if self._last_opened_info != last_opened_info: - self._last_opened_info = None - else: - self._last_opened_info = opened_settings_ui() - - if self._last_opened_info is not None: - if self._edit_mode is not True: - self._set_edit_mode(True) + def _check_on_reset(self): + self._controller.update_last_opened_info() + if self._controller.edit_mode: return - if self._edit_mode is False: - return + # if self._edit_mode is False: + # return - dialog = SettingsUIOpenedElsewhere(last_opened_info, self) + dialog = SettingsUIOpenedElsewhere( + self._controller.last_opened_info, self + ) dialog.exec_() - edit_enabled = dialog.result() == 1 - if edit_enabled: - self._last_opened_info = opened_settings_ui() - self._set_edit_mode(edit_enabled) - - def _set_edit_mode(self, mode): - if self._edit_mode is mode: - return - - self._edit_mode = mode - for tab_widget in self.tab_widgets: - tab_widget.set_edit_mode(mode) + self._controller.set_edit_mode(dialog.result() == 1) def _show_password_dialog(self): if self._password_dialog: @@ -235,7 +291,7 @@ class MainWidget(QtWidgets.QWidget): for tab_widget in self.tab_widgets: tab_widget.reset() self._main_reset = False - self._check_on_ui_open() + self._check_on_reset() def _update_search_dialog(self, clear=False): if self._search_dialog.isVisible(): @@ -280,7 +336,7 @@ class MainWidget(QtWidgets.QWidget): self._update_search_dialog() if not self._main_reset: - self._check_on_ui_open() + self._check_on_reset() def keyPressEvent(self, event): if event.matches(QtGui.QKeySequence.Find): @@ -306,8 +362,8 @@ class SettingsUIOpenedElsewhere(QtWidgets.QDialog): "Someone else has opened Settings UI. That may cause data loss." " Please contact the person on the other side." "

    You can open the UI in view-only mode or take" - " the control which will cause the other settings won't be able" - " to save changes.
    " + " the control which will cause settings on the other side" + " won't be able to save changes.
    " ), self) message_label.setWordWrap(True) From 496728e9abc54dbce957127e8e8134f629ed3ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Fri, 19 Aug 2022 12:09:52 +0200 Subject: [PATCH 222/282] :recycle: handle host name that is not set --- openpype/plugins/publish/extract_review.py | 2 ++ openpype/plugins/publish/integrate_subset_group.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_review.py b/openpype/plugins/publish/extract_review.py index e16f324e0a..27117510b2 100644 --- a/openpype/plugins/publish/extract_review.py +++ b/openpype/plugins/publish/extract_review.py @@ -1459,6 +1459,8 @@ class ExtractReview(pyblish.api.InstancePlugin): output = -1 regexes = self.compile_list_of_regexes(in_list) for regex in regexes: + if not value: + continue if re.match(regex, value): output = 1 break diff --git a/openpype/plugins/publish/integrate_subset_group.py b/openpype/plugins/publish/integrate_subset_group.py index 910cb060a6..79dd10fb8f 100644 --- a/openpype/plugins/publish/integrate_subset_group.py +++ b/openpype/plugins/publish/integrate_subset_group.py @@ -93,6 +93,6 @@ class IntegrateSubsetGroup(pyblish.api.InstancePlugin): return { "families": anatomy_data["family"], "tasks": task.get("name"), - "hosts": anatomy_data["app"], + "hosts": anatomy_data.get("app"), "task_types": task.get("type") } From 6d056c774d7011b8810a66bd63073df02596b50c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 19 Aug 2022 12:24:18 +0200 Subject: [PATCH 223/282] Small grammar fixes Just ran through google spellcheck. --- website/docs/dev_settings.md | 77 ++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/website/docs/dev_settings.md b/website/docs/dev_settings.md index 492d25930d..94590345e8 100644 --- a/website/docs/dev_settings.md +++ b/website/docs/dev_settings.md @@ -4,26 +4,26 @@ title: Settings sidebar_label: Settings --- -Settings gives ability to change how OpenPype behaves in certain situations. Settings are split into 3 categories **system settings**, **project anatomy** and **project settings**. Project anatomy and project settings are in grouped into single category but there is a technical difference (explained later). Only difference in system and project settings is that system settings can't be technically handled on a project level or their values must be available no matter in which project are values received. Settings have headless entities or settings UI. +Settings give the ability to change how OpenPype behaves in certain situations. Settings are split into 3 categories **system settings**, **project anatomy** and **project settings**. Project anatomy and project settings are grouped into a single category but there is a technical difference (explained later). Only difference in system and project settings is that system settings can't be technically handled on a project level or their values must be available no matter in which project the values are received. Settings have headless entities or settings UI. There is one more category **local settings** but they don't have ability to be changed or defined easily. Local settings can change how settings work per machine, can affect both system and project settings but they're hardcoded for predefined values at this moment. ## Settings schemas -System and project settings are defined by settings schemas. Schema define structure of output value, what value types output will contain, how settings are stored and how it's UI input will look. +System and project settings are defined by settings schemas. Schema defines the structure of output value, what value types output will contain, how settings are stored and how its UI input will look. ## Settings values -Output of settings is a json serializable value. There are 3 possible types of value **default values**, **studio overrides** and **project overrides**. Default values must be always available for all settings schemas, their values are stored to code. Default values is what everyone who just installed OpenPype will use as default values. It is good practice to set example values but they should be relevant. +Output of settings is a json serializable value. There are 3 possible types of value **default values**, **studio overrides** and **project overrides**. Default values must be always available for all settings schemas, their values are stored to code. Default values are what everyone who just installed OpenPype will use as default values. It is good practice to set example values but they should be actually relevant. -Setting overrides is what makes settings powerful tool. Overrides contain only a part of settings with additional metadata which describe which parts of settings values that should be replaced from overrides values. Using overrides gives ability to save only specific values and use default values for rest. It is super useful in project settings which have up to 2 levels of overrides. In project settings are used **default values** as base on which are applied **studio overrides** and then **project overrides**. In practice it is possible to save only studio overrides which affect all projects. Changes in studio overrides are then propagated to all projects without project overrides. But values can be locked on project level so studio overrides are not used. +Setting overrides is what makes settings a powerful tool. Overrides contain only a part of settings with additional metadata that describe which parts of settings values should be replaced from overrides values. Using overrides gives the ability to save only specific values and use default values for rest. It is super useful in project settings which have up to 2 levels of overrides. In project settings are used **default values** as base on which are applied **studio overrides** and then **project overrides**. In practice it is possible to save only studio overrides which affect all projects. Changes in studio overrides are then propagated to all projects without project overrides. But values can be locked on project level so studio overrides are not used. ## Settings storage -As was mentined default values are stored into repository files. Overrides are stored to Mongo database. The value in mongo contain only overrides with metadata so their content on it's own is useless and must be used with combination of default values. System settings and project settings are stored into special collection. Single document represents one set of overrides with OpenPype version for which is stored. Settings are versioned and are loaded in specific order - current OpenPype version overrides or first lower available. If there are any overrides with same or lower version then first higher version is used. If there are any overrides then no overrides are applied. +As was mentioned default values are stored into repository files. Overrides are stored in the Mongo database. The value in mongo contain only overrides with metadata so their content on it's own is useless and must be used with combination of default values. System settings and project settings are stored into special collection. Single document represents one set of overrides with OpenPype version for which is stored. Settings are versioned and are loaded in specific order - current OpenPype version overrides or first lower available. If there are any overrides with the same or lower version then the first higher version is used. If there are any overrides then no overrides are applied. -Project anatomy is stored into project document thus is not versioned and it's values are always overriden. Any changes in anatomy schema may have drastic effect on production and OpenPype updates. +Project anatomy is stored into a project document thus is not versioned and its values are always overridden. Any changes in anatomy schema may have a drastic effect on production and OpenPype updates. ## Settings schema items As was mentioned schema items define output type of values, how they are stored and how they look in UI. -- schemas are (by default) defined by a json files +- schemas are (by default) defined by json files - OpenPype core system settings schemas are stored in `~/openpype/settings/entities/schemas/system_schema/` and project settings in `~/openpype/settings/entities/schemas/projects_schema/` - both contain `schema_main.json` which are entry points - OpenPype modules/addons can define their settings schemas using `BaseModuleSettingsDef` in that case some functionality may be slightly modified @@ -31,20 +31,21 @@ As was mentioned schema items define output type of values, how they are stored - **type** is only common key which is required for all schema items - each item may have "input modifiers" (other keys in dictionary) and they may be required or optional based on the type - there are special keys across all items - - `"is_file"` - this key is used when defaults values are stored which define that this key is a filename where it's values are stored - - key is validated must be once in hierarchy else it won't be possible to store default values - - make sense to fill it only if it's value if `true` - - `"is_group"` - define that all values under a key in settings hierarchy will be overridden if any value is modified - - this key is not allowed for all inputs as they may not have technical ability to handle it - - key is validated can be only once in hierarchy and is automatically filled on last possible item if is not defined in schemas - - make sense to fill it only if it's value if `true` + - `"is_file"` - this key is used when defaults values are stored in the file. Its value matches the filename where values are stored + - key is validated, must be unique in hierarchy otherwise it won't be possible to store default values + - make sense to fill it only if it's value if `true` + + - `"is_group"` - define that all values under a key in settings hierarchy will be overridden if any value is modified + - this key is not allowed for all inputs as they may not have technical ability to handle it + - key is validated, must be unique in hierarchy and is automatically filled on last possible item if is not defined in schemas + - make sense to fill it only if it's value if `true` - all entities can have set `"tooltip"` key with description which will be shown in UI on hover ### Inner schema -Settings schemas are big json files which would became unmanageable if would be in single file. To be able to split them into multiple files to help organize them special types `schema` and `template` were added. Both types are relating to a different file by filename. If json file contains dictionary it is considered as `schema` if contains list it is considered as `template`. +Settings schemas are big json files which would become unmanageable if they were in a single file. To be able to split them into multiple files to help organize them special types `schema` and `template` were added. Both types are related to a different file by filename. If a json file contains a dictionary it is considered as `schema` if it contains a list it is considered as a `template`. #### schema -Schema item is replaced by content of entered schema name. It is recommended that schema file is used only once in settings hierarchy. Templates are meant for reusing. +Schema item is replaced by content of entered schema name. It is recommended that the schema file is used only once in settings hierarchy. Templates are meant for reusing. - schema must have `"name"` key which is name of schema that should be used ```javascript @@ -156,7 +157,7 @@ Templates are almost the same as schema items but can contain one or more items } ``` -Template data can be used only to fill templates in values but not in keys. It is also possible to define default values for unfilled fields to do so one of items in list must be dictionary with key `"__default_values__"` and value as dictionary with default key: values (as in example above). +Template data can be used only to fill templates in values but not in keys. It is also possible to define default values for unfilled fields to do so one of the items in the list must be a dictionary with key "__default_values__"` and value as dictionary with default key: values (as in example above). ```javascript { ... @@ -169,7 +170,7 @@ Template data can be used only to fill templates in values but not in keys. It i } ``` -Because formatting value can be only string it is possible to use formatting values which are replaced with different type. +Because formatting values can be only string it is possible to use formatting values which are replaced with different types. ```javascript // Template data { @@ -201,7 +202,7 @@ Dynamic schema item marks a place in settings schema where schemas defined by `B "name": "project_settings/global" } ``` -- `BaseModuleSettingsDef` with implemented `get_settings_schemas` can return a dictionary where key define a dynamic schema name and value schemas that will be put there +- `BaseModuleSettingsDef` with implemented `get_settings_schemas` can return a dictionary where key defines a dynamic schema name and value schemas that will be put there - dynamic schemas work almost the same way as templates - one item can be replaced by multiple items (or by 0 items) - goal is to dynamically load settings of OpenPype modules without having their schemas or default values in core repository @@ -215,12 +216,12 @@ These inputs wraps another inputs into {key: value} relation #### dict - this is dictionary type wrapping more inputs with keys defined in schema - may be used as dynamic children (e.g. in [list](#list) or [dict-modifiable](#dict-modifiable)) - - in that case the only key modifier is `children` which is list of it's keys - - USAGE: e.g. List of dictionaries where each dictionary have same structure. + - in that case the only key modifier is `children` which is a list of its keys + - USAGE: e.g. List of dictionaries where each dictionary has the same structure. - if is not used as dynamic children then must have defined `"key"` under which are it's values stored - may be with or without `"label"` (only for GUI) - - `"label"` must be set to be able mark item as group with `"is_group"` key set to True -- item with label can visually wrap it's children + - `"label"` must be set to be able to mark item as group with `"is_group"` key set to True +- item with label can visually wrap its children - this option is enabled by default to turn off set `"use_label_wrap"` to `False` - label wrap is by default collapsible - that can be set with key `"collapsible"` to `True`/`False` @@ -314,16 +315,16 @@ These inputs wraps another inputs into {key: value} relation - entity must have defined `"label"` if is not used as widget - is set as group if any parent is not group (can't have children as group) - may be with or without `"label"` (only for GUI) - - `"label"` must be set to be able mark item as group with `"is_group"` key set to True -- item with label can visually wrap it's children - - this option is enabled by default to turn off set `"use_label_wrap"` to `False` - - label wrap is by default collapsible - - that can be set with key `"collapsible"` to `True`/`False` - - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) - - it is possible to add lighter background with `"highlight_content"` (Default: `False`) - - lighter background has limits of maximum applies after 3-4 nested highlighted items there is not much difference in the color -- for UI porposes was added `enum_is_horizontal` which will make combobox appear next to children inputs instead of on top of them (Default: `False`) - - this has extended ability of `enum_on_right` which will move combobox to right side next to children widgets (Default: `False`) + - `"label"` must be set to be able to mark item as group with `"is_group"` key set to True +- item with label can visually wrap its children + - this option is enabled by default to turn off set `"use_label_wrap"` to `False` + - label wrap is by default collapsible + - that can be set with key `"collapsible"` to `True`/`False` + - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) + - it is possible to add lighter background with `"highlight_content"` (Default: `False`) + - lighter background has limits of maximum applies after 3-4 nested highlighted items there is not much difference in the color +- for UI purposes was added `enum_is_horizontal` which will make combobox appear next to children inputs instead of on top of them (Default: `False`) + - this has extended ability of `enum_on_right` which will move combobox to right side next to children widgets (Default: `False`) - output is dictionary `{the "key": children values}` - using this type as template item for list type can be used to create infinite hierarchies @@ -795,7 +796,7 @@ How output of the schema could look like on save: ``` #### color -- preimplemented entity to store and load color values +- pre implemented entity to store and load color values - entity store and expect list of 4 integers in range 0-255 - integers represents rgba [Red, Green, Blue, Alpha] - has modifier `"use_alpha"` which can be `True`/`False` @@ -842,9 +843,9 @@ Items used only for UI purposes. ``` ### Proxy wrappers -- should wraps multiple inputs only visually -- these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled -- can't be used as widget (first item in e.g. `list`, `dict-modifiable`, etc.) +- should wrap multiple inputs only visually +- these do not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled +- can't be used as a widget (first item in e.g. `list`, `dict-modifiable`, etc.) #### form - wraps inputs into form look layout @@ -893,6 +894,6 @@ Items used only for UI purposes. ## How to add new settings -Always start with modifying or adding new schema and don't worry about values. When you think schema is ready to use launch OpenPype settings in development mode using `poetry run python ./start.py settings --dev` or prepared script in `~/openpype/tools/run_settings(.sh|.ps1)`. Settings opened in development mode have checkbox `Modify defaults` available in bottom left corner. When checked default values are modified and saved on `Save`. This is recommended approach how default settings should be created instead of direct modification of files. +Always start with modifying or adding a new schema and don't worry about values. When you think schema is ready to use launch OpenPype settings in development mode using `poetry run python ./start.py settings --dev` or prepared script in `~/openpype/tools/run_settings(.sh|.ps1)`. Settings opened in development mode have the checkbox `Modify defaults` available in the bottom left corner. When checked default values are modified and saved on `Save`. This is a recommended approach on how default settings should be created instead of direct modification of files. ![Modify default settings](assets/settings_dev.png) From 4f03f2dd09f1eed5a0f23d2d9c9a428ae7656560 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 19 Aug 2022 12:33:32 +0200 Subject: [PATCH 224/282] modified dialog --- openpype/tools/settings/settings/window.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index 612975e30a..fcbcd129d0 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -359,11 +359,12 @@ class SettingsUIOpenedElsewhere(QtWidgets.QDialog): self.setWindowTitle("Someone else has opened Settings UI") message_label = QtWidgets.QLabel(( - "Someone else has opened Settings UI. That may cause data loss." + "Someone else has opened Settings UI which could cause data loss." " Please contact the person on the other side." - "

    You can open the UI in view-only mode or take" - " the control which will cause settings on the other side" - " won't be able to save changes.
    " + "

    You can open the UI in view-only mode." + " All changes in view mode will be lost." + "

    You can take the control which will cause that" + " all changes of settings on the other side will be lost.
    " ), self) message_label.setWordWrap(True) @@ -435,3 +436,7 @@ class SettingsUIOpenedElsewhere(QtWidgets.QDialog): def _on_view_mode(self): self._result = 0 self.close() + + def showEvent(self, event): + super(SettingsUIOpenedElsewhere, self).showEvent(event) + self.resize(600, 400) From fc4db8802d260d62a6cd93ea914bb5558151ba0c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 19 Aug 2022 13:01:46 +0200 Subject: [PATCH 225/282] Fixed issues after code review Warning should print exception. JSONDecoder is not in Pype2 --- .../deadline/abstract_submit_deadline.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index c38f16149e..9d952586d2 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -16,7 +16,12 @@ import attr import requests import pyblish.api -from openpype.pipeline.publish import AbstractMetaInstancePlugin +from openpype.pipeline.publish import ( + AbstractMetaInstancePlugin, + KnownPublishError +) + +JSONDecodeError = getattr(json.decoder, "JSONDecodeError", ValueError) def requests_post(*args, **kwargs): @@ -616,7 +621,7 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin): str: resulting Deadline job id. Throws: - RuntimeError: if submission fails. + KnownPublishError: if submission fails. """ url = "{}/api/jobs".format(self._deadline_url) @@ -626,15 +631,15 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin): self.log.error(response.status_code) self.log.error(response.content) self.log.debug(payload) - raise RuntimeError(response.text) + raise KnownPublishError(response.text) try: result = response.json() except json.decoder.JSONDecodeError: msg = "Broken response {}. ".format(response) - msg += "Try restarting DL webservice" - self.log.warning() - raise RuntimeError("Broken response from DL") + msg += "Try restarting the Deadline Webservice." + self.log.warning(msg, exc_info=True) + raise KnownPublishError("Broken response from DL") # for submit publish job self._instance.data["deadlineSubmissionJob"] = result From 8cd15708b65213092924263b0386f8bec28dc7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Fri, 19 Aug 2022 13:07:52 +0200 Subject: [PATCH 226/282] :bug: use the right key Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/plugins/publish/integrate_subset_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/integrate_subset_group.py b/openpype/plugins/publish/integrate_subset_group.py index 79dd10fb8f..a24ebba3a5 100644 --- a/openpype/plugins/publish/integrate_subset_group.py +++ b/openpype/plugins/publish/integrate_subset_group.py @@ -93,6 +93,6 @@ class IntegrateSubsetGroup(pyblish.api.InstancePlugin): return { "families": anatomy_data["family"], "tasks": task.get("name"), - "hosts": anatomy_data.get("app"), + "hosts": instance.context.data["hostName"], "task_types": task.get("type") } From 04397ccd2f8791a54917d505d1453a7a7e7e74cf Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 19 Aug 2022 13:10:31 +0200 Subject: [PATCH 227/282] OP-3723 - changed source files to 8K 16K was causing memory issues on some machines. --- openpype/hosts/photoshop/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_review.py b/openpype/hosts/photoshop/plugins/publish/extract_review.py index 64decbb957..60ae575b0a 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_review.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_review.py @@ -144,7 +144,7 @@ class ExtractReview(openpype.api.Extractor): used as a source for thumbnail or review mov. """ # 16384x16384 actually didn't work because int overflow - max_ffmpeg_size = 16000 + max_ffmpeg_size = 8192 Image.MAX_IMAGE_PIXELS = None first_url = os.path.join(staging_dir, processed_img_names[0]) with Image.open(first_url) as im: From d4bfbe3b9e1510d358f162628170cd29c145a198 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 19 Aug 2022 14:03:06 +0200 Subject: [PATCH 228/282] Updated missed occurence Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/modules/deadline/abstract_submit_deadline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/deadline/abstract_submit_deadline.py b/openpype/modules/deadline/abstract_submit_deadline.py index 9d952586d2..0bad981fdf 100644 --- a/openpype/modules/deadline/abstract_submit_deadline.py +++ b/openpype/modules/deadline/abstract_submit_deadline.py @@ -635,7 +635,7 @@ class AbstractSubmitDeadline(pyblish.api.InstancePlugin): try: result = response.json() - except json.decoder.JSONDecodeError: + except JSONDecodeError: msg = "Broken response {}. ".format(response) msg += "Try restarting the Deadline Webservice." self.log.warning(msg, exc_info=True) From ba45c7b1694a27005c7f78a47f2e90179bdd11b5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 19 Aug 2022 16:14:41 +0200 Subject: [PATCH 229/282] improving code readability --- openpype/plugins/publish/collect_otio_subset_resources.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/plugins/publish/collect_otio_subset_resources.py b/openpype/plugins/publish/collect_otio_subset_resources.py index 9c19f8a78e..3387cd1176 100644 --- a/openpype/plugins/publish/collect_otio_subset_resources.py +++ b/openpype/plugins/publish/collect_otio_subset_resources.py @@ -121,10 +121,8 @@ class CollectOtioSubsetResources(pyblish.api.InstancePlugin): otio.schema.ImageSequenceReference ): is_sequence = True - else: - # for OpenTimelineIO 0.12 and older - if metadata.get("padding"): - is_sequence = True + elif metadata.get("padding"): + is_sequence = True self.log.info( "frame_start-frame_end: {}-{}".format(frame_start, frame_end)) From 102965ea69f3ae738dd92af2c39ec9bc8ae577d4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 19 Aug 2022 16:15:16 +0200 Subject: [PATCH 230/282] editorial fixing handles to int and adding speed attribute --- openpype/pipeline/editorial.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openpype/pipeline/editorial.py b/openpype/pipeline/editorial.py index f62a1842e0..564d78ea6f 100644 --- a/openpype/pipeline/editorial.py +++ b/openpype/pipeline/editorial.py @@ -263,16 +263,17 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end): "retime": True, "speed": time_scalar, "timewarps": time_warp_nodes, - "handleStart": round(handle_start), - "handleEnd": round(handle_end) + "handleStart": int(round(handle_start)), + "handleEnd": int(round(handle_end)) } } returning_dict = { "mediaIn": media_in_trimmed, "mediaOut": media_out_trimmed, - "handleStart": round(handle_start), - "handleEnd": round(handle_end) + "handleStart": int(round(handle_start)), + "handleEnd": int(round(handle_end)), + "speed": time_scalar } # add version data only if retime From 869c9255ff266e90ec2f95abae67c234263beefb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 19 Aug 2022 16:15:43 +0200 Subject: [PATCH 231/282] flame: improving extractor of subsets --- .../publish/extract_subset_resources.py | 124 ++++++++++++++++-- 1 file changed, 113 insertions(+), 11 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index d34f5d5854..432bc3b500 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -8,6 +8,9 @@ import pyblish.api import openpype.api from openpype.hosts.flame import api as opfapi from openpype.hosts.flame.api import MediaInfoFile +from openpype.pipeline.editorial import ( + get_media_range_with_retimes +) import flame @@ -65,20 +68,50 @@ class ExtractSubsetResources(openpype.api.Extractor): # get configured workfile frame start/end (handles excluded) frame_start = instance.data["frameStart"] # get media source first frame - source_first_frame = instance.data["sourceFirstFrame"] + source_first_frame = instance.data["sourceFirstFrame"] # 1001 # get timeline in/out of segment clip_in = instance.data["clipIn"] clip_out = instance.data["clipOut"] + # get retimed attributres + retimed_data = self._get_retimed_attributes(instance) + self.log.debug("_ retimed_data: {}".format( + pformat(retimed_data) + )) + # get individual keys + r_handle_start = retimed_data["handle_start"] + r_handle_end = retimed_data["handle_end"] + r_source_dur = retimed_data["source_duration"] + r_speed = retimed_data["speed"] + r_handles = max(r_handle_start, r_handle_end) + # get handles value - take only the max from both handle_start = instance.data["handleStart"] - handle_end = instance.data["handleStart"] + handle_end = instance.data["handleEnd"] handles = max(handle_start, handle_end) + include_handles = instance.data.get("includeHandles") + self.log.debug("_ include_handles: {}".format(include_handles)) # get media source range with handles source_start_handles = instance.data["sourceStartH"] source_end_handles = instance.data["sourceEndH"] + # retime if needed + if r_speed != 1.0: + source_start_handles = ( + instance.data["sourceStart"] - r_handle_start) + source_end_handles = ( + source_start_handles + # TODO: duration exclude 1 - might be problem + + (r_source_dur - 1) + + r_handle_start + + r_handle_end + ) + + self.log.debug("_ source_start_handles: {}".format( + source_start_handles)) + self.log.debug("_ source_end_handles: {}".format( + source_end_handles)) # create staging dir path staging_dir = self.staging_dir(instance) @@ -93,6 +126,19 @@ class ExtractSubsetResources(openpype.api.Extractor): } export_presets.update(self.export_presets_mapping) + # set versiondata if any retime + version_data = retimed_data.get("version_data") + + if version_data: + instance.data["versionData"].update(version_data) + + if instance.data.get("versionData"): + if r_speed != 1.0: + instance.data["versionData"].update({ + "frameStart": source_start_handles + r_handle_start, + "frameEnd": source_end_handles - r_handle_end, + }) + # loop all preset names and for unique_name, preset_config in export_presets.items(): modify_xml_data = {} @@ -117,14 +163,22 @@ class ExtractSubsetResources(openpype.api.Extractor): # get frame range with handles for representation range frame_start_handle = frame_start - handle_start + if include_handles: + if r_speed == 1.0: + frame_start_handle = frame_start + else: + frame_start_handle = ( + frame_start - handle_start) + r_handle_start + + self.log.debug("_ frame_start_handle: {}".format( + frame_start_handle)) # calculate duration with handles source_duration_handles = ( - source_end_handles - source_start_handles) + source_end_handles - source_start_handles) + 1 - # define in/out marks - in_mark = (source_start_handles - source_first_frame) + 1 - out_mark = in_mark + source_duration_handles + self.log.debug("_ source_duration_handles: {}".format( + source_duration_handles)) exporting_clip = None name_patern_xml = "_{}.".format( @@ -142,19 +196,28 @@ class ExtractSubsetResources(openpype.api.Extractor): "__{}.").format( unique_name) - # change in/out marks to timeline in/out + # only for h264 with baked retime in_mark = clip_in - out_mark = clip_out + out_mark = clip_out + 1 + + modify_xml_data["nbHandles"] = handles else: + in_mark = (source_start_handles - source_first_frame) + 1 + out_mark = in_mark + source_duration_handles exporting_clip = self.import_clip(clip_path) exporting_clip.name.set_value("{}_{}".format( asset_name, segment_name)) + modify_xml_data["nbHandles"] = ( + handles if r_speed == 1.0 else r_handles) # add xml tags modifications modify_xml_data.update({ + # TODO: handles only to Sequence preset + # TODO: enable Start frame attribute "exportHandles": True, - "nbHandles": handles, - "startFrame": frame_start, + "startFrame": frame_start_handle, + # enum position low start from 0 + "frameIndex": 0, "namePattern": name_patern_xml }) @@ -162,6 +225,12 @@ class ExtractSubsetResources(openpype.api.Extractor): # add any xml overrides collected form segment.comment modify_xml_data.update(instance.data["xml_overrides"]) + self.log.debug(pformat(modify_xml_data)) + self.log.debug("_ sequence publish {}".format( + export_type == "Sequence Publish")) + self.log.debug("_ in_mark: {}".format(in_mark)) + self.log.debug("_ out_mark: {}".format(out_mark)) + export_kwargs = {} # validate xml preset file is filled if preset_file == "": @@ -283,7 +352,7 @@ class ExtractSubsetResources(openpype.api.Extractor): representation_data.update({ "frameStart": frame_start_handle, "frameEnd": ( - frame_start_handle + source_duration_handles), + frame_start_handle + source_duration_handles) - 1, "fps": instance.data["fps"] }) @@ -303,6 +372,39 @@ class ExtractSubsetResources(openpype.api.Extractor): self.log.debug("All representations: {}".format( pformat(instance.data["representations"]))) + def _get_retimed_attributes(self, instance): + handle_start = instance.data["handleStart"] + handle_end = instance.data["handleEnd"] + include_handles = instance.data.get("includeHandles") + self.log.debug("_ include_handles: {}".format(include_handles)) + + # get basic variables + otio_clip = instance.data["otioClip"] + otio_avalable_range = otio_clip.available_range() + available_duration = otio_avalable_range.duration.value + self.log.debug( + ">> available_duration: {}".format(available_duration)) + + # get available range trimmed with processed retimes + retimed_attributes = get_media_range_with_retimes( + otio_clip, handle_start, handle_end) + self.log.debug( + ">> retimed_attributes: {}".format(retimed_attributes)) + + r_media_in = int(retimed_attributes["mediaIn"]) + r_media_out = int(retimed_attributes["mediaOut"]) + version_data = retimed_attributes.get("versionData") + + return { + "version_data": version_data, + "handle_start": int(retimed_attributes["handleStart"]), + "handle_end": int(retimed_attributes["handleEnd"]), + "source_duration": ( + (r_media_out - r_media_in) + 1 + ), + "speed": float(retimed_attributes["speed"]) + } + def _should_skip(self, preset_config, clip_path, unique_name): # get activating attributes activated_preset = preset_config["active"] From faec36f1d65292121af9be129b2857d7d100a60f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 19 Aug 2022 16:34:37 +0200 Subject: [PATCH 232/282] code cleanup --- .../plugins/publish/extract_subset_resources.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 432bc3b500..2f4f90fe55 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -84,7 +84,6 @@ class ExtractSubsetResources(openpype.api.Extractor): r_handle_end = retimed_data["handle_end"] r_source_dur = retimed_data["source_duration"] r_speed = retimed_data["speed"] - r_handles = max(r_handle_start, r_handle_end) # get handles value - take only the max from both handle_start = instance.data["handleStart"] @@ -183,6 +182,7 @@ class ExtractSubsetResources(openpype.api.Extractor): exporting_clip = None name_patern_xml = "_{}.".format( unique_name) + if export_type == "Sequence Publish": # change export clip to sequence exporting_clip = flame.duplicate(sequence_clip) @@ -199,25 +199,22 @@ class ExtractSubsetResources(openpype.api.Extractor): # only for h264 with baked retime in_mark = clip_in out_mark = clip_out + 1 - - modify_xml_data["nbHandles"] = handles + modify_xml_data.update({ + "exportHandles": True, + "nbHandles": handles + }) else: in_mark = (source_start_handles - source_first_frame) + 1 out_mark = in_mark + source_duration_handles exporting_clip = self.import_clip(clip_path) exporting_clip.name.set_value("{}_{}".format( asset_name, segment_name)) - modify_xml_data["nbHandles"] = ( - handles if r_speed == 1.0 else r_handles) # add xml tags modifications modify_xml_data.update({ - # TODO: handles only to Sequence preset - # TODO: enable Start frame attribute - "exportHandles": True, - "startFrame": frame_start_handle, # enum position low start from 0 "frameIndex": 0, + "startFrame": frame_start_handle, "namePattern": name_patern_xml }) From 8d08d5966a5eb213d4a8de57bf497cda83ccb631 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 19 Aug 2022 17:39:59 +0200 Subject: [PATCH 233/282] cleaning code --- .../publish/extract_subset_resources.py | 48 ++++--------------- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 2f4f90fe55..ddf126c445 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -50,7 +50,6 @@ class ExtractSubsetResources(openpype.api.Extractor): export_presets_mapping = {} def process(self, instance): - if not self.keep_original_representation: # remove previeous representation if not needed instance.data["representations"] = [] @@ -68,7 +67,7 @@ class ExtractSubsetResources(openpype.api.Extractor): # get configured workfile frame start/end (handles excluded) frame_start = instance.data["frameStart"] # get media source first frame - source_first_frame = instance.data["sourceFirstFrame"] # 1001 + source_first_frame = instance.data["sourceFirstFrame"] # get timeline in/out of segment clip_in = instance.data["clipIn"] @@ -76,9 +75,7 @@ class ExtractSubsetResources(openpype.api.Extractor): # get retimed attributres retimed_data = self._get_retimed_attributes(instance) - self.log.debug("_ retimed_data: {}".format( - pformat(retimed_data) - )) + # get individual keys r_handle_start = retimed_data["handle_start"] r_handle_end = retimed_data["handle_end"] @@ -90,7 +87,6 @@ class ExtractSubsetResources(openpype.api.Extractor): handle_end = instance.data["handleEnd"] handles = max(handle_start, handle_end) include_handles = instance.data.get("includeHandles") - self.log.debug("_ include_handles: {}".format(include_handles)) # get media source range with handles source_start_handles = instance.data["sourceStartH"] @@ -101,17 +97,11 @@ class ExtractSubsetResources(openpype.api.Extractor): instance.data["sourceStart"] - r_handle_start) source_end_handles = ( source_start_handles - # TODO: duration exclude 1 - might be problem + (r_source_dur - 1) + r_handle_start + r_handle_end ) - self.log.debug("_ source_start_handles: {}".format( - source_start_handles)) - self.log.debug("_ source_end_handles: {}".format( - source_end_handles)) - # create staging dir path staging_dir = self.staging_dir(instance) @@ -125,18 +115,20 @@ class ExtractSubsetResources(openpype.api.Extractor): } export_presets.update(self.export_presets_mapping) + if not instance.data.get("versionData"): + instance.data["versionData"] = {} + # set versiondata if any retime version_data = retimed_data.get("version_data") if version_data: instance.data["versionData"].update(version_data) - if instance.data.get("versionData"): - if r_speed != 1.0: - instance.data["versionData"].update({ - "frameStart": source_start_handles + r_handle_start, - "frameEnd": source_end_handles - r_handle_end, - }) + if r_speed != 1.0: + instance.data["versionData"].update({ + "frameStart": source_start_handles + r_handle_start, + "frameEnd": source_end_handles - r_handle_end, + }) # loop all preset names and for unique_name, preset_config in export_presets.items(): @@ -176,9 +168,6 @@ class ExtractSubsetResources(openpype.api.Extractor): source_duration_handles = ( source_end_handles - source_start_handles) + 1 - self.log.debug("_ source_duration_handles: {}".format( - source_duration_handles)) - exporting_clip = None name_patern_xml = "_{}.".format( unique_name) @@ -222,9 +211,6 @@ class ExtractSubsetResources(openpype.api.Extractor): # add any xml overrides collected form segment.comment modify_xml_data.update(instance.data["xml_overrides"]) - self.log.debug(pformat(modify_xml_data)) - self.log.debug("_ sequence publish {}".format( - export_type == "Sequence Publish")) self.log.debug("_ in_mark: {}".format(in_mark)) self.log.debug("_ out_mark: {}".format(out_mark)) @@ -264,7 +250,6 @@ class ExtractSubsetResources(openpype.api.Extractor): thumb_frame_number = int(in_mark + ( source_duration_handles / 2)) - self.log.debug("__ in_mark: {}".format(in_mark)) self.log.debug("__ thumb_frame_number: {}".format( thumb_frame_number )) @@ -276,9 +261,6 @@ class ExtractSubsetResources(openpype.api.Extractor): "out_mark": out_mark }) - self.log.debug("__ modify_xml_data: {}".format( - pformat(modify_xml_data) - )) preset_path = opfapi.modify_preset_file( preset_orig_xml_path, staging_dir, modify_xml_data) @@ -366,21 +348,13 @@ class ExtractSubsetResources(openpype.api.Extractor): # at the end remove the duplicated clip flame.delete(exporting_clip) - self.log.debug("All representations: {}".format( - pformat(instance.data["representations"]))) def _get_retimed_attributes(self, instance): handle_start = instance.data["handleStart"] handle_end = instance.data["handleEnd"] - include_handles = instance.data.get("includeHandles") - self.log.debug("_ include_handles: {}".format(include_handles)) # get basic variables otio_clip = instance.data["otioClip"] - otio_avalable_range = otio_clip.available_range() - available_duration = otio_avalable_range.duration.value - self.log.debug( - ">> available_duration: {}".format(available_duration)) # get available range trimmed with processed retimes retimed_attributes = get_media_range_with_retimes( @@ -412,8 +386,6 @@ class ExtractSubsetResources(openpype.api.Extractor): unique_name, activated_preset, filter_path_regex ) ) - self.log.debug( - "__ clip_path: `{}`".format(clip_path)) # skip if not activated presete if not activated_preset: From b15471501a44a09e5e205460aea6b6fc0c365e91 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 19 Aug 2022 17:41:11 +0200 Subject: [PATCH 234/282] hound suggestions --- openpype/hosts/flame/api/lib.py | 1 - openpype/hosts/flame/plugins/publish/extract_subset_resources.py | 1 - 2 files changed, 2 deletions(-) diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index a5ae3c4468..94c46fe937 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -1,7 +1,6 @@ import sys import os import re -import sys import json import pickle import clique diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index ddf126c445..8a03ba119c 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -348,7 +348,6 @@ class ExtractSubsetResources(openpype.api.Extractor): # at the end remove the duplicated clip flame.delete(exporting_clip) - def _get_retimed_attributes(self, instance): handle_start = instance.data["handleStart"] handle_end = instance.data["handleEnd"] From 5d14fdd1cef6eb2d40925efeadfbcab3af219ca5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 19 Aug 2022 19:02:10 +0200 Subject: [PATCH 235/282] fix _reset_crashed --- openpype/tools/settings/settings/categories.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index 2e3c6d9dda..fd95b4ca71 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -701,7 +701,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget): self.breadcrumbs_model.set_entity(None) def _on_reset_success(self): - self._reset_crashed = True + self._reset_crashed = False if not self.save_btn.isEnabled(): self.save_btn.setEnabled(self._edit_mode) From 890d1becaa8a4fcc597977d6b0cbe25e21bf34d3 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 19 Aug 2022 19:11:00 +0200 Subject: [PATCH 236/282] moved dialog to separated file --- openpype/tools/settings/settings/dialogs.py | 115 ++++++++++++++++++++ openpype/tools/settings/settings/window.py | 93 +--------------- 2 files changed, 116 insertions(+), 92 deletions(-) create mode 100644 openpype/tools/settings/settings/dialogs.py diff --git a/openpype/tools/settings/settings/dialogs.py b/openpype/tools/settings/settings/dialogs.py new file mode 100644 index 0000000000..dea056b89d --- /dev/null +++ b/openpype/tools/settings/settings/dialogs.py @@ -0,0 +1,115 @@ +from Qt import QtWidgets, QtCore + + +class BaseInfoDialog(QtWidgets.QDialog): + width = 600 + height = 400 + + def __init__(self, message, title, info_obj, parent=None): + super(BaseInfoDialog, self).__init__(parent) + self._result = 0 + self._info_obj = info_obj + + self.setWindowTitle(title) + + message_label = QtWidgets.QLabel(message, self) + message_label.setWordWrap(True) + + separator_widget_1 = QtWidgets.QFrame(self) + separator_widget_2 = QtWidgets.QFrame(self) + for separator_widget in ( + separator_widget_1, + separator_widget_2 + ): + separator_widget.setObjectName("Separator") + separator_widget.setMinimumHeight(1) + separator_widget.setMaximumHeight(1) + + other_information = QtWidgets.QWidget(self) + other_information_layout = QtWidgets.QFormLayout(other_information) + other_information_layout.setContentsMargins(0, 0, 0, 0) + for label, value in ( + ("Username", info_obj.username), + ("Host name", info_obj.hostname), + ("Host IP", info_obj.hostip), + ("System name", info_obj.system_name), + ("Local ID", info_obj.local_id), + ("Time Stamp", info_obj.timestamp), + ): + other_information_layout.addRow( + label, + QtWidgets.QLabel(value, other_information) + ) + + footer_widget = QtWidgets.QWidget(self) + buttons_widget = QtWidgets.QWidget(footer_widget) + + buttons_layout = QtWidgets.QHBoxLayout(buttons_widget) + buttons_layout.setContentsMargins(0, 0, 0, 0) + buttons = self.get_buttons(buttons_widget) + for button in buttons: + buttons_layout.addWidget(button, 1) + + footer_layout = QtWidgets.QHBoxLayout(footer_widget) + footer_layout.setContentsMargins(0, 0, 0, 0) + footer_layout.addStretch(1) + footer_layout.addWidget(buttons_widget, 0) + + layout = QtWidgets.QVBoxLayout(self) + layout.addWidget(message_label, 0) + layout.addWidget(separator_widget_1, 0) + layout.addStretch(1) + layout.addWidget(other_information, 0, QtCore.Qt.AlignHCenter) + layout.addStretch(1) + layout.addWidget(separator_widget_2, 0) + layout.addWidget(footer_widget, 0) + + def showEvent(self, event): + super(BaseInfoDialog, self).showEvent(event) + self.resize(self.width, self.height) + + def result(self): + return self._result + + def get_buttons(self, parent): + return [] + + +class SettingsUIOpenedElsewhere(BaseInfoDialog): + def __init__(self, info_obj, parent=None): + title = "Someone else has opened Settings UI" + message = ( + "Someone else has opened Settings UI which could cause data loss." + " Please contact the person on the other side." + "

    You can continue in view-only mode." + " All changes in view mode will be lost." + "

    You can take control which will cause that" + " all changes of settings on the other side will be lost.
    " + ) + super(SettingsUIOpenedElsewhere, self).__init__( + message, title, info_obj, parent + ) + + def _on_take_control(self): + self._result = 1 + self.close() + + def _on_view_mode(self): + self._result = 0 + self.close() + + def get_buttons(self, parent): + take_control_btn = QtWidgets.QPushButton( + "Take control", parent + ) + view_mode_btn = QtWidgets.QPushButton( + "View only", parent + ) + + take_control_btn.clicked.connect(self._on_take_control) + view_mode_btn.clicked.connect(self._on_view_mode) + + return [ + take_control_btn, + view_mode_btn + ] diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index fcbcd129d0..2750785535 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -12,6 +12,7 @@ from openpype.settings.lib import ( closed_settings_ui, ) +from .dialogs import SettingsUIOpenedElsewhere from .categories import ( CategoryState, SystemWidget, @@ -348,95 +349,3 @@ class MainWidget(QtWidgets.QWidget): return return super(MainWidget, self).keyPressEvent(event) - - -class SettingsUIOpenedElsewhere(QtWidgets.QDialog): - def __init__(self, info_obj, parent=None): - super(SettingsUIOpenedElsewhere, self).__init__(parent) - - self._result = 0 - - self.setWindowTitle("Someone else has opened Settings UI") - - message_label = QtWidgets.QLabel(( - "Someone else has opened Settings UI which could cause data loss." - " Please contact the person on the other side." - "

    You can open the UI in view-only mode." - " All changes in view mode will be lost." - "

    You can take the control which will cause that" - " all changes of settings on the other side will be lost.
    " - ), self) - message_label.setWordWrap(True) - - separator_widget_1 = QtWidgets.QFrame(self) - separator_widget_2 = QtWidgets.QFrame(self) - for separator_widget in ( - separator_widget_1, - separator_widget_2 - ): - separator_widget.setObjectName("Separator") - separator_widget.setMinimumHeight(1) - separator_widget.setMaximumHeight(1) - - other_information = QtWidgets.QWidget(self) - other_information_layout = QtWidgets.QFormLayout(other_information) - other_information_layout.setContentsMargins(0, 0, 0, 0) - for label, value in ( - ("Username", info_obj.username), - ("Host name", info_obj.hostname), - ("Host IP", info_obj.hostip), - ("System name", info_obj.system_name), - ("Local ID", info_obj.local_id), - ("Time Stamp", info_obj.timestamp), - ): - other_information_layout.addRow( - label, - QtWidgets.QLabel(value, other_information) - ) - - footer_widget = QtWidgets.QWidget(self) - buttons_widget = QtWidgets.QWidget(footer_widget) - - take_control_btn = QtWidgets.QPushButton( - "Take control", buttons_widget - ) - view_mode_btn = QtWidgets.QPushButton( - "View only", buttons_widget - ) - - buttons_layout = QtWidgets.QHBoxLayout(buttons_widget) - buttons_layout.setContentsMargins(0, 0, 0, 0) - buttons_layout.addWidget(take_control_btn, 1) - buttons_layout.addWidget(view_mode_btn, 1) - - footer_layout = QtWidgets.QHBoxLayout(footer_widget) - footer_layout.setContentsMargins(0, 0, 0, 0) - footer_layout.addStretch(1) - footer_layout.addWidget(buttons_widget, 0) - - layout = QtWidgets.QVBoxLayout(self) - layout.addWidget(message_label, 0) - layout.addWidget(separator_widget_1, 0) - layout.addStretch(1) - layout.addWidget(other_information, 0, QtCore.Qt.AlignHCenter) - layout.addStretch(1) - layout.addWidget(separator_widget_2, 0) - layout.addWidget(footer_widget, 0) - - take_control_btn.clicked.connect(self._on_take_control) - view_mode_btn.clicked.connect(self._on_view_mode) - - def result(self): - return self._result - - def _on_take_control(self): - self._result = 1 - self.close() - - def _on_view_mode(self): - self._result = 0 - self.close() - - def showEvent(self, event): - super(SettingsUIOpenedElsewhere, self).showEvent(event) - self.resize(600, 400) From 2ea277992ea217ff9d4b65cd3b36dd5ad2218f8e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 19 Aug 2022 21:06:05 +0200 Subject: [PATCH 237/282] update ftrack cli commands --- website/docs/module_ftrack.md | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/website/docs/module_ftrack.md b/website/docs/module_ftrack.md index 667782754f..ad9cf75e8f 100644 --- a/website/docs/module_ftrack.md +++ b/website/docs/module_ftrack.md @@ -13,7 +13,7 @@ Ftrack is currently the main project management option for OpenPype. This docume ## Prepare Ftrack for OpenPype ### Server URL -If you want to connect Ftrack to OpenPype you might need to make few changes in Ftrack settings. These changes would take a long time to do manually, so we prepared a few Ftrack actions to help you out. First, you'll need to launch OpenPype settings, enable [Ftrack module](admin_settings_system.md#Ftrack), and enter the address to your Ftrack server. +If you want to connect Ftrack to OpenPype you might need to make few changes in Ftrack settings. These changes would take a long time to do manually, so we prepared a few Ftrack actions to help you out. First, you'll need to launch OpenPype settings, enable [Ftrack module](admin_settings_system.md#Ftrack), and enter the address to your Ftrack server. ### Login Once your server is configured, restart OpenPype and you should be prompted to enter your [Ftrack credentials](artist_ftrack.md#How-to-use-Ftrack-in-OpenPype) to be able to run our Ftrack actions. If you are already logged in to Ftrack in your browser, it is enough to press `Ftrack login` and it will connect automatically. @@ -26,7 +26,7 @@ You can only use our Ftrack Actions and publish to Ftrack if each artist is logg ### Custom Attributes After successfully connecting OpenPype with you Ftrack, you can right click on any project in Ftrack and you should see a bunch of actions available. The most important one is called `OpenPype Admin` and contains multiple options inside. -To prepare Ftrack for working with OpenPype you'll need to run [OpenPype Admin - Create/Update Custom Attributes](manager_ftrack_actions.md#create-update-avalon-attributes), which creates and sets the Custom Attributes necessary for OpenPype to function. +To prepare Ftrack for working with OpenPype you'll need to run [OpenPype Admin - Create/Update Custom Attributes](manager_ftrack_actions.md#create-update-avalon-attributes), which creates and sets the Custom Attributes necessary for OpenPype to function. @@ -34,7 +34,7 @@ To prepare Ftrack for working with OpenPype you'll need to run [OpenPype Admin - Ftrack Event Server is the key to automation of many tasks like _status change_, _thumbnail update_, _automatic synchronization to Avalon database_ and many more. Event server should run at all times to perform the required processing as it is not possible to catch some of them retrospectively with enough certainty. ### Running event server -There are specific launch arguments for event server. With `openpype_console eventserver` you can launch event server but without prior preparation it will terminate immediately. The reason is that event server requires 3 pieces of information: _Ftrack server url_, _paths to events_ and _credentials (Username and API key)_. Ftrack server URL and Event path are set from OpenPype's environments by default, but the credentials must be done separatelly for security reasons. +There are specific launch arguments for event server. With `openpype_console module ftrack eventserver` you can launch event server but without prior preparation it will terminate immediately. The reason is that event server requires 3 pieces of information: _Ftrack server url_, _paths to events_ and _credentials (Username and API key)_. Ftrack server URL and Event path are set from OpenPype's environments by default, but the credentials must be done separatelly for security reasons. @@ -53,7 +53,7 @@ There are specific launch arguments for event server. With `openpype_console eve - **`--ftrack-api-key "00000aaa-11bb-22cc-33dd-444444eeeee"`** : User's API key - `--ftrack-url "https://yourdomain.ftrackapp.com/"` : Ftrack server URL _(it is not needed to enter if you have set `FTRACK_SERVER` in OpenPype' environments)_ -So if you want to use OpenPype's environments then you can launch event server for first time with these arguments `openpype_console.exe eventserver --ftrack-user "my.username" --ftrack-api-key "00000aaa-11bb-22cc-33dd-444444eeeee" --store-credentials`. Since that time, if everything was entered correctly, you can launch event server with `openpype_console.exe eventserver`. +So if you want to use OpenPype's environments then you can launch event server for first time with these arguments `openpype_console.exe module ftrack eventserver --ftrack-user "my.username" --ftrack-api-key "00000aaa-11bb-22cc-33dd-444444eeeee" --store-credentials`. Since that time, if everything was entered correctly, you can launch event server with `openpype_console.exe module ftrack eventserver`. @@ -72,7 +72,7 @@ We do not recommend setting your Ftrack user and api key environments in a persi ### Where to run event server -We recommend you to run event server on stable server machine with ability to connect to Avalon database and Ftrack web server. Best practice we recommend is to run event server as service. It can be Windows or Linux. +We recommend you to run event server on stable server machine with ability to connect to Avalon database and Ftrack web server. Best practice we recommend is to run event server as service. It can be Windows or Linux. :::important Event server should **not** run more than once! It may cause major issues. @@ -99,11 +99,10 @@ Event server should **not** run more than once! It may cause major issues. - add content to the file: ```sh #!/usr/bin/env bash -export OPENPYPE_DEBUG=1 export OPENPYPE_MONGO= pushd /mnt/path/to/openpype -./openpype_console eventserver --ftrack-user --ftrack-api-key +./openpype_console module ftrack eventserver --ftrack-user --ftrack-api-key --debug ``` - change file permission: `sudo chmod 0755 /opt/openpype/run_event_server.sh` @@ -140,14 +139,13 @@ WantedBy=multi-user.target - create service file: `openpype-ftrack-eventserver.bat` -- add content to the service file: +- add content to the service file: ```sh @echo off -set OPENPYPE_DEBUG=1 set OPENPYPE_MONGO= pushd \\path\to\openpype -openpype_console.exe eventserver --ftrack-user --ftrack-api-key +openpype_console.exe module ftrack eventserver --ftrack-user --ftrack-api-key --debug ``` - download and install `nssm.cc` - create Windows service according to nssm.cc manual @@ -174,7 +172,7 @@ This event updates entities on their changes Ftrack. When new entity is created Deleting an entity by Ftrack's default is not processed for security reasons _(to delete entity use [Delete Asset/Subset action](manager_ftrack_actions.md#delete-asset-subset))_. ::: -### Synchronize Hierarchical and Entity Attributes +### Synchronize Hierarchical and Entity Attributes Auto-synchronization of hierarchical attributes from Ftrack entities. @@ -190,7 +188,7 @@ Change status of next task from `Not started` to `Ready` when previous task is a Multiple detailed rules for next task update can be configured in the settings. -### Delete Avalon ID from new entity +### Delete Avalon ID from new entity Is used to remove value from `Avalon/Mongo Id` Custom Attribute when entity is created. @@ -215,7 +213,7 @@ This event handler allows setting of different status to a first created Asset V This is useful for example if first version publish doesn't contain any actual reviewable work, but is only used for roundtrip conform check, in which case this version could receive status `pending conform` instead of standard `pending review` ### Update status on next task -Change status on next task by task types order when task status state changed to "Done". All tasks with the same Task mapping of next task status changes From → To. Some status can be ignored. +Change status on next task by task types order when task status state changed to "Done". All tasks with the same Task mapping of next task status changes From → To. Some status can be ignored. ## Publish plugins @@ -238,7 +236,7 @@ Add Ftrack Family: enabled #### Advanced adding if additional families present -In special cases adding 'ftrack' based on main family ('Families' set higher) is not enough. +In special cases adding 'ftrack' based on main family ('Families' set higher) is not enough. (For example upload to Ftrack for 'plate' main family should only happen if 'review' is contained in instance 'families', not added in other cases. ) -![Collect Ftrack Family](assets/ftrack/ftrack-collect-advanced.png) \ No newline at end of file +![Collect Ftrack Family](assets/ftrack/ftrack-collect-advanced.png) From 752f1cde1c307398fa56ada929f8299ee97face5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 19 Aug 2022 21:10:28 +0200 Subject: [PATCH 238/282] removed outdated repositories information --- website/docs/system_introduction.md | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/website/docs/system_introduction.md b/website/docs/system_introduction.md index 71c5d64aa8..db297b527a 100644 --- a/website/docs/system_introduction.md +++ b/website/docs/system_introduction.md @@ -48,24 +48,3 @@ to the table - Some DCCs do not support using Environment variables in file paths. This will make it very hard to maintain full multiplatform compatibility as well variable storage roots. - Relying on VPN connection and using it to work directly of network storage will be painfully slow. - - -## Repositories - -### [OpenPype](https://github.com/pypeclub/pype) - -This is where vast majority of the code that works with your data lives. It acts -as Avalon-Config, if we're speaking in avalon terms. - -Avalon gives us the ability to work with a certain host, say Maya, in a standardized manner, but OpenPype defines **how** we work with all the data, allows most of the behavior to be configured on a very granular level and provides a comprehensive build and installation tools for it. - -Thanks to that, we are able to maintain one codebase for vast majority of the features across all our clients deployments while keeping the option to tailor the pipeline to each individual studio. - -### [Avalon-core](https://github.com/pypeclub/avalon-core) - -Avalon-core is the heart of OpenPype. It provides the base functionality including key GUIs (albeit expanded and modified by us), database connection, standards for data structures, working with entities and some universal tools. - -Avalon is being actively developed and maintained by a community of studios and TDs from around the world, with Pype Club team being an active contributor as well. - -Due to the extensive work we've done on OpenPype and the need to react quickly to production needs, we -maintain our own fork of avalon-core, which is kept up to date with upstream changes as much as possible. From 40efddb9b40a3d74d136dd9a06647fd2b73ded91 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 19 Aug 2022 21:21:28 +0200 Subject: [PATCH 239/282] removed eventserver from global cli commands --- website/docs/admin_openpype_commands.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/website/docs/admin_openpype_commands.md b/website/docs/admin_openpype_commands.md index 53fc12410f..cf45138fa9 100644 --- a/website/docs/admin_openpype_commands.md +++ b/website/docs/admin_openpype_commands.md @@ -40,7 +40,6 @@ For more information [see here](admin_use.md#run-openpype). | module | Run command line arguments for modules. | | | repack-version | Tool to re-create version zip. | [📑](#repack-version-arguments) | | tray | Launch OpenPype Tray. | [📑](#tray-arguments) -| eventserver | This should be ideally used by system service (such as systemd or upstart on linux and window service). | [📑](#eventserver-arguments) | | launch | Launch application in Pype environment. | [📑](#launch-arguments) | | publish | Pype takes JSON from provided path and use it to publish data in it. | [📑](#publish-arguments) | | extractenvironments | Extract environment variables for entered context to a json file. | [📑](#extractenvironments-arguments) | @@ -57,25 +56,7 @@ For more information [see here](admin_use.md#run-openpype). openpype_console tray ``` --- -### `launch` arguments {#eventserver-arguments} -You have to set either proper environment variables to provide URL and credentials or use -option to specify them. -| Argument | Description | -| --- | --- | -| `--ftrack-url` | URL to ftrack server (can be set with `FTRACK_SERVER`) | -| `--ftrack-user` |user name to log in to ftrack (can be set with `FTRACK_API_USER`) | -| `--ftrack-api-key` | ftrack api key (can be set with `FTRACK_API_KEY`) | -| `--legacy` | run event server without mongo storing | -| `--clockify-api-key` | Clockify API key (can be set with `CLOCKIFY_API_KEY`) | -| `--clockify-workspace` | Clockify workspace (can be set with `CLOCKIFY_WORKSPACE`) | - -To run ftrack event server: -```shell -openpype_console eventserver --ftrack-url= --ftrack-user= --ftrack-api-key= -``` - ---- ### `launch` arguments {#launch-arguments} | Argument | Description | From ce4c00d20a677c08bcd046ec24a0a3ba6c9e4792 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 19 Aug 2022 21:46:21 +0200 Subject: [PATCH 240/282] add information about naming limitations to key concepts --- website/docs/artist_concepts.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/website/docs/artist_concepts.md b/website/docs/artist_concepts.md index 9005cffe87..f67ab89b9c 100644 --- a/website/docs/artist_concepts.md +++ b/website/docs/artist_concepts.md @@ -10,6 +10,8 @@ sidebar_label: Key Concepts In our pipeline all the main entities the project is made from are internally considered *'Assets'*. Episode, sequence, shot, character, prop, etc. All of these behave identically in the pipeline. Asset names need to be absolutely unique within the project because they are their key identifier. +OpenPype has limitation regarging duplicated names. Name of assets must be unique across whole project. + ### Subset Usually, an asset needs to be created in multiple *'flavours'*. A character might have multiple different looks, model needs to be published in different resolutions, a standard animation rig might not be usable in a crowd system and so on. 'Subsets' are here to accommodate all this variety that might be needed within a single asset. A model might have subset: *'main'*, *'proxy'*, *'sculpt'*, while data of *'look'* family could have subsets *'main'*, *'dirty'*, *'damaged'*. Subsets have some recommendations for their names, but ultimately it's up to the artist to use them for separation of publishes when needed. @@ -24,6 +26,11 @@ A numbered iteration of a given subset. Each version contains at least one [repr Each published variant can come out of the software in multiple representations. All of them hold exactly the same data, but in different formats. A model, for example, might be saved as `.OBJ`, Alembic, Maya geometry or as all of them, to be ready for pickup in any other applications supporting these formats. + +#### Naming convention + +At this moment names of assets, tasks, subsets or representations can contain only letters, numbers and underscore. + ### Family Each published [subset][3b89d8e0] can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joints when it is published. From 2591c1fad5355b824198389dae7c918061e67125 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 19 Aug 2022 21:46:36 +0200 Subject: [PATCH 241/282] add link to key concepts into system introduction --- website/docs/system_introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/system_introduction.md b/website/docs/system_introduction.md index db297b527a..b8a2cea487 100644 --- a/website/docs/system_introduction.md +++ b/website/docs/system_introduction.md @@ -17,7 +17,7 @@ various usage scenarios. You can find detailed breakdown of technical requirements [here](dev_requirements), but in general OpenPype should be able to operate in most studios fairly quickly. The main obstacles are usually related to workflows and habits, that -might now be fully compatible with what OpenPype is expecting or enforcing. +might now be fully compatible with what OpenPype is expecting or enforcing. It is recommended to go through artists [key concepts](artist_concepts) to get idea about basics. Keep in mind that if you run into any workflows that are not supported, it's usually just because we haven't hit that particular case and it can most likely be added upon request. From 2b4e3ef9fad40d9573b3dd37b73d68dba0ad1d3e Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 20 Aug 2022 03:56:03 +0000 Subject: [PATCH 242/282] [Automated] Bump version --- CHANGELOG.md | 16 ++++++++++++++-- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e19993ad75..65a3cb27e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,20 @@ # Changelog +## [3.14.1-nightly.1](https://github.com/pypeclub/OpenPype/tree/HEAD) + +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.14.0...HEAD) + +**🚀 Enhancements** + +- Ftrack: More logs related to auto sync value change [\#3671](https://github.com/pypeclub/OpenPype/pull/3671) + +**🐛 Bug fixes** + +- RoyalRender: handle host name that is not set [\#3695](https://github.com/pypeclub/OpenPype/pull/3695) + ## [3.14.0](https://github.com/pypeclub/OpenPype/tree/3.14.0) (2022-08-18) -[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.13.0...3.14.0) +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.14.0-nightly.1...3.14.0) **🆕 New features** @@ -25,7 +37,6 @@ - General: Hero version representations have full context [\#3638](https://github.com/pypeclub/OpenPype/pull/3638) - Nuke: color settings for render write node is working now [\#3632](https://github.com/pypeclub/OpenPype/pull/3632) - Maya: FBX support for update in reference loader [\#3631](https://github.com/pypeclub/OpenPype/pull/3631) -- Integrator: Don't force to have dot before frame [\#3611](https://github.com/pypeclub/OpenPype/pull/3611) **🔀 Refactored code** @@ -70,6 +81,7 @@ - Ftrack: Sync hierarchical attributes can handle new created entities [\#3621](https://github.com/pypeclub/OpenPype/pull/3621) - General: Extract review aspect ratio scale is calculated by ffmpeg [\#3620](https://github.com/pypeclub/OpenPype/pull/3620) - Maya: Fix types of default settings [\#3617](https://github.com/pypeclub/OpenPype/pull/3617) +- Integrator: Don't force to have dot before frame [\#3611](https://github.com/pypeclub/OpenPype/pull/3611) - AfterEffects: refactored integrate doesnt work formulti frame publishes [\#3610](https://github.com/pypeclub/OpenPype/pull/3610) - Maya look data contents fails with custom attribute on group [\#3607](https://github.com/pypeclub/OpenPype/pull/3607) - TrayPublisher: Fix wrong conflict merge [\#3600](https://github.com/pypeclub/OpenPype/pull/3600) diff --git a/openpype/version.py b/openpype/version.py index c28b480940..174aca1e6c 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.0" +__version__ = "3.14.1-nightly.1" diff --git a/pyproject.toml b/pyproject.toml index e670d0a2ff..e01cc71201 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.14.0" # OpenPype +version = "3.14.1-nightly.1" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From 3beca31c61317c068e9d667c8b0817265c3e26f3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 22 Aug 2022 10:57:54 +0200 Subject: [PATCH 243/282] OP-3723 - introduced max_downscale_size value to Settings Studios might want to set maximum size to resize for ffmpeg to work based on OS or resources. --- .../hosts/photoshop/plugins/publish/extract_review.py | 8 ++++---- .../settings/defaults/project_settings/photoshop.json | 1 + .../projects_schema/schema_project_photoshop.json | 9 +++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_review.py b/openpype/hosts/photoshop/plugins/publish/extract_review.py index 60ae575b0a..5d37c86ed8 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_review.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_review.py @@ -30,6 +30,7 @@ class ExtractReview(openpype.api.Extractor): jpg_options = None mov_options = None make_image_sequence = None + max_downscale_size = 8192 def process(self, instance): staging_dir = self.staging_dir(instance) @@ -143,14 +144,12 @@ class ExtractReview(openpype.api.Extractor): Ffmpeg has max size 16384x16384. Saved image(s) must be resized to be used as a source for thumbnail or review mov. """ - # 16384x16384 actually didn't work because int overflow - max_ffmpeg_size = 8192 Image.MAX_IMAGE_PIXELS = None first_url = os.path.join(staging_dir, processed_img_names[0]) with Image.open(first_url) as im: width, height = im.size - if width > max_ffmpeg_size or height > max_ffmpeg_size: + if width > self.max_downscale_size or height > self.max_downscale_size: resized_dir = os.path.join(staging_dir, "resized") os.mkdir(resized_dir) source_files_pattern = os.path.join(resized_dir, @@ -159,7 +158,8 @@ class ExtractReview(openpype.api.Extractor): source_url = os.path.join(staging_dir, file_name) with Image.open(source_url) as res_img: # 'thumbnail' automatically keeps aspect ratio - res_img.thumbnail((max_ffmpeg_size, max_ffmpeg_size), + res_img.thumbnail((self.max_downscale_size, + self.max_downscale_size), Image.ANTIALIAS) res_img.save(os.path.join(resized_dir, file_name)) diff --git a/openpype/settings/defaults/project_settings/photoshop.json b/openpype/settings/defaults/project_settings/photoshop.json index d9b7a8083f..758ac64a35 100644 --- a/openpype/settings/defaults/project_settings/photoshop.json +++ b/openpype/settings/defaults/project_settings/photoshop.json @@ -32,6 +32,7 @@ }, "ExtractReview": { "make_image_sequence": false, + "max_downscale_size": 8192, "jpg_options": { "tags": [] }, diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_photoshop.json b/openpype/settings/entities/schemas/projects_schema/schema_project_photoshop.json index badf94229b..49860301b6 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_photoshop.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_photoshop.json @@ -186,6 +186,15 @@ "key": "make_image_sequence", "label": "Makes an image sequence instead of a flatten image" }, + { + "type": "number", + "key": "max_downscale_size", + "label": "Maximum size of sources for review", + "tooltip": "FFMpeg can only handle limited resolution for creation of review and/or thumbnail", + "minimum": 300, + "maximum": 16384, + "decimal": 0 + }, { "type": "dict", "collapsible": false, From f4106714aeabd13eec6d8085cb3f3be39feb4f00 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 11:27:19 +0200 Subject: [PATCH 244/282] added dialogs for 2 other cases --- openpype/tools/settings/settings/dialogs.py | 64 +++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/openpype/tools/settings/settings/dialogs.py b/openpype/tools/settings/settings/dialogs.py index dea056b89d..a3eed68ae3 100644 --- a/openpype/tools/settings/settings/dialogs.py +++ b/openpype/tools/settings/settings/dialogs.py @@ -113,3 +113,67 @@ class SettingsUIOpenedElsewhere(BaseInfoDialog): take_control_btn, view_mode_btn ] + + +class SettingsLastSavedChanged(BaseInfoDialog): + width = 500 + height = 300 + + def __init__(self, info_obj, parent=None): + title = "Settings has changed" + message = ( + "Settings has changed while you had opened this settings session." + "

    It is recommended to refresh settings" + " and re-apply changes in the new session." + ) + super(SettingsLastSavedChanged, self).__init__( + message, title, info_obj, parent + ) + + def _on_save(self): + self._result = 1 + self.close() + + def _on_close(self): + self._result = 0 + self.close() + + def get_buttons(self, parent): + close_btn = QtWidgets.QPushButton( + "Close", parent + ) + save_btn = QtWidgets.QPushButton( + "Save anyway", parent + ) + + close_btn.clicked.connect(self._on_close) + save_btn.clicked.connect(self._on_save) + + return [ + close_btn, + save_btn + ] + + +class SettingsControlTaken(BaseInfoDialog): + width = 500 + height = 300 + + def __init__(self, info_obj, parent=None): + title = "Settings control taken" + message = ( + "Someone took control over your settings." + "

    It is not possible to save changes of currently" + " opened session. Copy changes you want to keep and hit refresh." + ) + super(SettingsControlTaken, self).__init__( + message, title, info_obj, parent + ) + + def _on_confirm(self): + self.close() + + def get_buttons(self, parent): + confirm_btn = QtWidgets.QPushButton("Understand", parent) + confirm_btn.clicked.connect(self._on_confirm) + return [confirm_btn] From 537bfaa8d683213f03a78b962d1767698947c390 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 11:27:45 +0200 Subject: [PATCH 245/282] removed print --- openpype/tools/settings/settings/window.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index 2750785535..a907a034d1 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -87,7 +87,6 @@ class SettingsController: ) def update_last_opened_info(self): - print("update_last_opened_info") last_opened_info = get_last_opened_info() enabled = False if ( From 80b5c0c064c47d4bab6e870759a2fc4caf54cfd9 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 11:28:00 +0200 Subject: [PATCH 246/282] categories have checks related to last saved settings --- .../tools/settings/settings/categories.py | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index fd95b4ca71..f4b2c13a12 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -36,6 +36,11 @@ from openpype.settings.entities.op_version_entity import ( ) from openpype.settings import SaveWarningExc +from openpype.settings.lib import ( + get_system_last_saved_info, + get_project_last_saved_info, +) +from .dialogs import SettingsLastSavedChanged, SettingsControlTaken from .widgets import ( ProjectListWidget, VersionAction @@ -205,6 +210,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget): if enabled is self._edit_mode: return + was_false = self._edit_mode is False self._edit_mode = enabled self.save_btn.setEnabled(enabled and not self._reset_crashed) @@ -218,6 +224,10 @@ class SettingsCategoryWidget(QtWidgets.QWidget): self.save_btn.setToolTip(tooltip) + # Reset when last saved information has changed + if was_false and not self._check_last_saved_info(): + self.reset() + @property def state(self): return self._state @@ -748,7 +758,24 @@ class SettingsCategoryWidget(QtWidgets.QWidget): """Callback on any tab widget save.""" return + def _check_last_saved_info(self): + raise NotImplementedError(( + "{} does not have implemented '_check_last_saved_info'" + ).format(self.__class__.__name__)) + def _save(self): + self._controller.update_last_opened_info() + if not self._controller.opened_info: + dialog = SettingsControlTaken(self._last_saved_info, self) + dialog.exec_() + return + + if not self._check_last_saved_info(): + dialog = SettingsLastSavedChanged(self._last_saved_info, self) + dialog.exec_() + if dialog.result() == 0: + return + # Don't trigger restart if defaults are modified if self.is_modifying_defaults: require_restart = False @@ -807,6 +834,13 @@ class SystemWidget(SettingsCategoryWidget): self._actions = [] super(SystemWidget, self).__init__(*args, **kwargs) + def _check_last_saved_info(self): + if self.is_modifying_defaults: + return True + + last_saved_info = get_system_last_saved_info() + return self._last_saved_info == last_saved_info + def contain_category_key(self, category): if category == "system_settings": return True @@ -821,6 +855,10 @@ class SystemWidget(SettingsCategoryWidget): ) entity.on_change_callbacks.append(self._on_entity_change) self.entity = entity + last_saved_info = None + if not self.is_modifying_defaults: + last_saved_info = get_system_last_saved_info() + self._last_saved_info = last_saved_info try: if self.is_modifying_defaults: entity.set_defaults_state() @@ -854,6 +892,13 @@ class ProjectWidget(SettingsCategoryWidget): def __init__(self, *args, **kwargs): super(ProjectWidget, self).__init__(*args, **kwargs) + def _check_last_saved_info(self): + if self.is_modifying_defaults: + return True + + last_saved_info = get_project_last_saved_info(self.project_name) + return self._last_saved_info == last_saved_info + def contain_category_key(self, category): if category in ("project_settings", "project_anatomy"): return True @@ -933,6 +978,11 @@ class ProjectWidget(SettingsCategoryWidget): entity.on_change_callbacks.append(self._on_entity_change) self.project_list_widget.set_entity(entity) self.entity = entity + + last_saved_info = None + if not self.is_modifying_defaults: + last_saved_info = get_project_last_saved_info(self.project_name) + self._last_saved_info = last_saved_info try: if self.is_modifying_defaults: self.entity.set_defaults_state() From 7cd6a423ead42bae21a2fa2e491bf32870402fe8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 11:55:04 +0200 Subject: [PATCH 247/282] fix attribute name --- openpype/settings/handlers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 1b59531943..09f36aa16e 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -784,9 +784,9 @@ class MongoSettingsHandler(SettingsHandler): "last_saved_info": last_saved_info.to_document_data() } if not system_settings_doc: - self.collections.insert_one(new_system_settings_doc) + self.collection.insert_one(new_system_settings_doc) else: - self.collections.update_one( + self.collection.update_one( {"_id": system_settings_doc["_id"]}, {"$set": new_system_settings_doc} ) From c3fe68c58a40fcca6f998b1d17e67aa690404349 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 12:02:21 +0200 Subject: [PATCH 248/282] converted unreal to openpype module --- openpype/hosts/unreal/__init__.py | 26 ++++----------------- openpype/hosts/unreal/module.py | 39 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 openpype/hosts/unreal/module.py diff --git a/openpype/hosts/unreal/__init__.py b/openpype/hosts/unreal/__init__.py index 10e9c5100e..41222f4f94 100644 --- a/openpype/hosts/unreal/__init__.py +++ b/openpype/hosts/unreal/__init__.py @@ -1,24 +1,6 @@ -import os -import openpype.hosts -from openpype.lib.applications import Application +from .module import UnrealModule -def add_implementation_envs(env: dict, _app: Application) -> None: - """Modify environments to contain all required for implementation.""" - # Set OPENPYPE_UNREAL_PLUGIN required for Unreal implementation - - ue_plugin = "UE_5.0" if _app.name[:1] == "5" else "UE_4.7" - unreal_plugin_path = os.path.join( - os.path.dirname(os.path.abspath(openpype.hosts.__file__)), - "unreal", "integration", ue_plugin - ) - if not env.get("OPENPYPE_UNREAL_PLUGIN"): - env["OPENPYPE_UNREAL_PLUGIN"] = unreal_plugin_path - - # Set default environments if are not set via settings - defaults = { - "OPENPYPE_LOG_NO_COLORS": "True" - } - for key, value in defaults.items(): - if not env.get(key): - env[key] = value +__all__ = ( + "UnrealModule", +) diff --git a/openpype/hosts/unreal/module.py b/openpype/hosts/unreal/module.py new file mode 100644 index 0000000000..a30c9e9e36 --- /dev/null +++ b/openpype/hosts/unreal/module.py @@ -0,0 +1,39 @@ +import os +from openpype.modules import OpenPypeModule +from openpype.modules.interfaces import IHostModule + +UNREAL_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class UnrealModule(OpenPypeModule, IHostModule): + name = "unreal" + host_name = "unreal" + + def initialize(self, module_settings): + self.enabled = True + + def add_implementation_envs(self, env, app) -> None: + """Modify environments to contain all required for implementation.""" + # Set OPENPYPE_UNREAL_PLUGIN required for Unreal implementation + + ue_plugin = "UE_5.0" if app.name[:1] == "5" else "UE_4.7" + unreal_plugin_path = os.path.join( + UNREAL_ROOT_DIR, "integration", ue_plugin + ) + if not env.get("OPENPYPE_UNREAL_PLUGIN"): + env["OPENPYPE_UNREAL_PLUGIN"] = unreal_plugin_path + + # Set default environments if are not set via settings + defaults = { + "OPENPYPE_LOG_NO_COLORS": "True" + } + for key, value in defaults.items(): + if not env.get(key): + env[key] = value + + def get_launch_hook_paths(self, app): + if app.host_name != self.host_name: + return [] + return [ + os.path.join(UNREAL_ROOT_DIR, "hooks") + ] From 44b9146e4fa43188a3065090797a05b319d58e59 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 12:16:50 +0200 Subject: [PATCH 249/282] use Unreal host as class instead of module --- openpype/hosts/unreal/api/__init__.py | 4 ++- openpype/hosts/unreal/api/pipeline.py | 27 +++++++++++++++++++ .../UE_4.7/Content/Python/init_unreal.py | 4 ++- .../UE_5.0/Content/Python/init_unreal.py | 4 ++- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/unreal/api/__init__.py b/openpype/hosts/unreal/api/__init__.py index ede71aa218..870982f5f9 100644 --- a/openpype/hosts/unreal/api/__init__.py +++ b/openpype/hosts/unreal/api/__init__.py @@ -19,6 +19,7 @@ from .pipeline import ( show_tools_dialog, show_tools_popup, instantiate, + UnrealHost, ) __all__ = [ @@ -36,5 +37,6 @@ __all__ = [ "show_experimental_tools", "show_tools_dialog", "show_tools_popup", - "instantiate" + "instantiate", + "UnrealHost", ] diff --git a/openpype/hosts/unreal/api/pipeline.py b/openpype/hosts/unreal/api/pipeline.py index bbca7916d3..ee4282e357 100644 --- a/openpype/hosts/unreal/api/pipeline.py +++ b/openpype/hosts/unreal/api/pipeline.py @@ -14,6 +14,7 @@ from openpype.pipeline import ( ) from openpype.tools.utils import host_tools import openpype.hosts.unreal +from openpypr.host import HostBase, ILoadHost import unreal # noqa @@ -29,6 +30,32 @@ CREATE_PATH = os.path.join(PLUGINS_DIR, "create") INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory") +class UnrealHost(HostBase, ILoadHost): + """Unreal host implementation. + + For some time this class will re-use functions from module based + implementation for backwards compatibility of older unreal projects. + """ + + name = "unreal" + + def install(self): + install() + + def get_containers(self): + return ls() + + def show_tools_popup(self): + """Show tools popup with actions leading to show other tools.""" + + show_tools_popup() + + def show_tools_dialog(self): + """Show tools dialog with actions leading to show other tools.""" + + show_tools_dialog() + + def install(): """Install Unreal configuration for OpenPype.""" print("-=" * 40) diff --git a/openpype/hosts/unreal/integration/UE_4.7/Content/Python/init_unreal.py b/openpype/hosts/unreal/integration/UE_4.7/Content/Python/init_unreal.py index 4bb03b07ed..b85f970699 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Content/Python/init_unreal.py +++ b/openpype/hosts/unreal/integration/UE_4.7/Content/Python/init_unreal.py @@ -3,7 +3,9 @@ import unreal openpype_detected = True try: from openpype.pipeline import install_host - from openpype.hosts.unreal import api as openpype_host + from openpype.hosts.unreal.api import UnrealHost + + openpype_host = UnrealHost() except ImportError as exc: openpype_host = None openpype_detected = False diff --git a/openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py b/openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py index 4bb03b07ed..b85f970699 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py +++ b/openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py @@ -3,7 +3,9 @@ import unreal openpype_detected = True try: from openpype.pipeline import install_host - from openpype.hosts.unreal import api as openpype_host + from openpype.hosts.unreal.api import UnrealHost + + openpype_host = UnrealHost() except ImportError as exc: openpype_host = None openpype_detected = False From d98bc3509057f2c59a278656ba6360a10825b57d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 13:22:38 +0200 Subject: [PATCH 250/282] implemented 'get_workfile_extensions' in unreal module --- openpype/hosts/unreal/module.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/hosts/unreal/module.py b/openpype/hosts/unreal/module.py index a30c9e9e36..aa08c8c130 100644 --- a/openpype/hosts/unreal/module.py +++ b/openpype/hosts/unreal/module.py @@ -37,3 +37,6 @@ class UnrealModule(OpenPypeModule, IHostModule): return [ os.path.join(UNREAL_ROOT_DIR, "hooks") ] + + def get_workfile_extensions(self): + return [".uproject"] From 9b60b9faa89c8551c88977c42ad9f404869c7680 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 15:19:26 +0200 Subject: [PATCH 251/282] change title if in view mode --- openpype/tools/settings/settings/window.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index a907a034d1..77a2f64dac 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -105,6 +105,7 @@ class MainWidget(QtWidgets.QWidget): widget_width = 1000 widget_height = 600 + window_title = "OpenPype Settings" def __init__(self, user_role, parent=None, reset_on_show=True): super(MainWidget, self).__init__(parent) @@ -122,7 +123,7 @@ class MainWidget(QtWidgets.QWidget): self._password_dialog = None self.setObjectName("SettingsMainWidget") - self.setWindowTitle("OpenPype Settings") + self.setWindowTitle(self.window_title) self.resize(self.widget_width, self.widget_height) @@ -155,6 +156,11 @@ class MainWidget(QtWidgets.QWidget): self._shadow_widget = ShadowWidget("Working...", self) self._shadow_widget.setVisible(False) + controller.event_system.add_callback( + "edit.mode.changed", + self._edit_mode_changed + ) + header_tab_widget.currentChanged.connect(self._on_tab_changed) search_dialog.path_clicked.connect(self._on_search_path_clicked) @@ -301,6 +307,12 @@ class MainWidget(QtWidgets.QWidget): entity = widget.entity self._search_dialog.set_root_entity(entity) + def _edit_mode_changed(self, event): + title = self.window_title + if not event["edit_mode"]: + title += " [View only]" + self.setWindowTitle(title) + def _on_tab_changed(self): self._update_search_dialog() From 1b64160644a1af0a8fd4349814a1c5e3fe496b85 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 15:21:48 +0200 Subject: [PATCH 252/282] use pretty time instead of timestamp --- openpype/tools/settings/settings/dialogs.py | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/dialogs.py b/openpype/tools/settings/settings/dialogs.py index a3eed68ae3..f25374a48c 100644 --- a/openpype/tools/settings/settings/dialogs.py +++ b/openpype/tools/settings/settings/dialogs.py @@ -1,5 +1,7 @@ from Qt import QtWidgets, QtCore +from openpype.tools.utils.delegates import pretty_date + class BaseInfoDialog(QtWidgets.QDialog): width = 600 @@ -34,13 +36,17 @@ class BaseInfoDialog(QtWidgets.QDialog): ("Host IP", info_obj.hostip), ("System name", info_obj.system_name), ("Local ID", info_obj.local_id), - ("Time Stamp", info_obj.timestamp), ): other_information_layout.addRow( label, QtWidgets.QLabel(value, other_information) ) + timestamp_label = QtWidgets.QLabel( + pretty_date(info_obj.timestamp_obj), other_information + ) + other_information_layout.addRow("Time", timestamp_label) + footer_widget = QtWidgets.QWidget(self) buttons_widget = QtWidgets.QWidget(footer_widget) @@ -64,10 +70,27 @@ class BaseInfoDialog(QtWidgets.QDialog): layout.addWidget(separator_widget_2, 0) layout.addWidget(footer_widget, 0) + timestamp_timer = QtCore.QTimer() + timestamp_timer.setInterval(1000) + timestamp_timer.timeout.connect(self._on_timestamp_timer) + + self._timestamp_label = timestamp_label + self._timestamp_timer = timestamp_timer + def showEvent(self, event): super(BaseInfoDialog, self).showEvent(event) + self._timestamp_timer.start() self.resize(self.width, self.height) + def closeEvent(self, event): + self._timestamp_timer.stop() + super(BaseInfoDialog, self).closeEvent(event) + + def _on_timestamp_timer(self): + self._timestamp_label.setText( + pretty_date(self._info_obj.timestamp_obj) + ) + def result(self): return self._result From 5df9c1b41f99fd2d587355c54b5c15eef53ce588 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 22 Aug 2022 16:48:32 +0200 Subject: [PATCH 253/282] Added default variant to workfile collectors for PS|AE Will only propagate in workfile subset (and final published name of workfile) if {variant} is used in subset name template. (By default it isn't.) --- .../hosts/aftereffects/plugins/publish/collect_workfile.py | 4 +++- openpype/hosts/photoshop/plugins/publish/collect_workfile.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py index 9cb6900b0a..fef5448a4c 100644 --- a/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py +++ b/openpype/hosts/aftereffects/plugins/publish/collect_workfile.py @@ -11,6 +11,8 @@ class CollectWorkfile(pyblish.api.ContextPlugin): label = "Collect After Effects Workfile Instance" order = pyblish.api.CollectorOrder + 0.1 + default_variant = "Main" + def process(self, context): existing_instance = None for instance in context: @@ -71,7 +73,7 @@ class CollectWorkfile(pyblish.api.ContextPlugin): family = "workfile" subset = get_subset_name_with_asset_doc( family, - "", + self.default_variant, context.data["anatomyData"]["task"]["name"], context.data["assetEntity"], context.data["anatomyData"]["project"]["name"], diff --git a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py index e4f0a07b34..6599f5c96e 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py @@ -11,6 +11,8 @@ class CollectWorkfile(pyblish.api.ContextPlugin): label = "Collect Workfile" hosts = ["photoshop"] + default_variant = "Main" + def process(self, context): existing_instance = None for instance in context: @@ -22,7 +24,7 @@ class CollectWorkfile(pyblish.api.ContextPlugin): family = "workfile" subset = get_subset_name_with_asset_doc( family, - "", + self.default_variant, context.data["anatomyData"]["task"]["name"], context.data["assetEntity"], context.data["anatomyData"]["project"]["name"], From 9434cb43c1d480ea523093907ad0fbe2a4a24744 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 17:07:46 +0200 Subject: [PATCH 254/282] fix published workfile filtering --- openpype/tools/workfiles/model.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openpype/tools/workfiles/model.py b/openpype/tools/workfiles/model.py index d5b7cef339..9a7fd659a9 100644 --- a/openpype/tools/workfiles/model.py +++ b/openpype/tools/workfiles/model.py @@ -299,7 +299,6 @@ class PublishFilesModel(QtGui.QStandardItemModel): self.project_name, asset_ids=[self._asset_id], fields=["_id", "name"] - ) subset_ids = [subset_doc["_id"] for subset_doc in subset_docs] @@ -329,7 +328,9 @@ class PublishFilesModel(QtGui.QStandardItemModel): # extension extensions = [ext.replace(".", "") for ext in self._file_extensions] repre_docs = get_representations( - self.project_name, version_ids, extensions + self.project_name, + version_ids=version_ids, + context_filters={"ext": extensions} ) # Filter queried representations by task name if task is set From 45da6cf5d0fbdb31a91eef2115e04299860f5f48 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 22 Aug 2022 17:50:06 +0200 Subject: [PATCH 255/282] Added possibility to propagate collected variant context.data["variant"] might be filled only by collect_batch_data, which should take precedence --- openpype/hosts/photoshop/plugins/publish/collect_workfile.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py index 6599f5c96e..9cf6d5227e 100644 --- a/openpype/hosts/photoshop/plugins/publish/collect_workfile.py +++ b/openpype/hosts/photoshop/plugins/publish/collect_workfile.py @@ -22,9 +22,11 @@ class CollectWorkfile(pyblish.api.ContextPlugin): break family = "workfile" + # context.data["variant"] might come only from collect_batch_data + variant = context.data.get("variant") or self.default_variant subset = get_subset_name_with_asset_doc( family, - self.default_variant, + variant, context.data["anatomyData"]["task"]["name"], context.data["assetEntity"], context.data["anatomyData"]["project"]["name"], From 20d08049672cd328f4a4ac093b01864ce61d270f Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 22 Aug 2022 17:50:59 +0200 Subject: [PATCH 256/282] Fix typo Co-authored-by: Simone Barbieri --- openpype/hosts/unreal/api/pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/unreal/api/pipeline.py b/openpype/hosts/unreal/api/pipeline.py index ee4282e357..d396b64072 100644 --- a/openpype/hosts/unreal/api/pipeline.py +++ b/openpype/hosts/unreal/api/pipeline.py @@ -14,7 +14,7 @@ from openpype.pipeline import ( ) from openpype.tools.utils import host_tools import openpype.hosts.unreal -from openpypr.host import HostBase, ILoadHost +from openpype.host import HostBase, ILoadHost import unreal # noqa From 4a4712b02047ff61ea23a90b5348768458b4aa34 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 22 Aug 2022 17:55:57 +0200 Subject: [PATCH 257/282] Added default variant to new creator --- .../photoshop/plugins/create/workfile_creator.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/create/workfile_creator.py b/openpype/hosts/photoshop/plugins/create/workfile_creator.py index 43302329f1..ce0245d5c6 100644 --- a/openpype/hosts/photoshop/plugins/create/workfile_creator.py +++ b/openpype/hosts/photoshop/plugins/create/workfile_creator.py @@ -11,6 +11,8 @@ class PSWorkfileCreator(AutoCreator): identifier = "workfile" family = "workfile" + default_variant = "Main" + def get_instance_attr_defs(self): return [] @@ -35,7 +37,6 @@ class PSWorkfileCreator(AutoCreator): existing_instance = instance break - variant = '' project_name = legacy_io.Session["AVALON_PROJECT"] asset_name = legacy_io.Session["AVALON_ASSET"] task_name = legacy_io.Session["AVALON_TASK"] @@ -43,15 +44,17 @@ class PSWorkfileCreator(AutoCreator): if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( - variant, task_name, asset_doc, project_name, host_name + self.default_variant, task_name, asset_doc, + project_name, host_name ) data = { "asset": asset_name, "task": task_name, - "variant": variant + "variant": self.default_variant } data.update(self.get_dynamic_data( - variant, task_name, asset_doc, project_name, host_name + self.default_variant, task_name, asset_doc, + project_name, host_name )) new_instance = CreatedInstance( @@ -67,7 +70,8 @@ class PSWorkfileCreator(AutoCreator): ): asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( - variant, task_name, asset_doc, project_name, host_name + self.default_variant, task_name, asset_doc, + project_name, host_name ) existing_instance["asset"] = asset_name existing_instance["task"] = task_name From c0457a88ea7e67f55818fd4b19db9eec7f887ec4 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 22 Aug 2022 17:56:25 +0200 Subject: [PATCH 258/282] Added overwrite old subset name for different context --- openpype/hosts/photoshop/plugins/create/workfile_creator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/photoshop/plugins/create/workfile_creator.py b/openpype/hosts/photoshop/plugins/create/workfile_creator.py index ce0245d5c6..e79d16d154 100644 --- a/openpype/hosts/photoshop/plugins/create/workfile_creator.py +++ b/openpype/hosts/photoshop/plugins/create/workfile_creator.py @@ -75,3 +75,4 @@ class PSWorkfileCreator(AutoCreator): ) existing_instance["asset"] = asset_name existing_instance["task"] = task_name + existing_instance["subset"] = subset_name From be568a0e4140312712ddfe3c8b2b4df573ffd279 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 22 Aug 2022 18:03:17 +0200 Subject: [PATCH 259/282] Added default variant for workfile creator for AE --- .../plugins/create/workfile_creator.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/aftereffects/plugins/create/workfile_creator.py b/openpype/hosts/aftereffects/plugins/create/workfile_creator.py index badb3675fd..3b6dee3b83 100644 --- a/openpype/hosts/aftereffects/plugins/create/workfile_creator.py +++ b/openpype/hosts/aftereffects/plugins/create/workfile_creator.py @@ -11,6 +11,8 @@ class AEWorkfileCreator(AutoCreator): identifier = "workfile" family = "workfile" + default_variant = "Main" + def get_instance_attr_defs(self): return [] @@ -35,7 +37,6 @@ class AEWorkfileCreator(AutoCreator): existing_instance = instance break - variant = '' project_name = legacy_io.Session["AVALON_PROJECT"] asset_name = legacy_io.Session["AVALON_ASSET"] task_name = legacy_io.Session["AVALON_TASK"] @@ -44,15 +45,17 @@ class AEWorkfileCreator(AutoCreator): if existing_instance is None: asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( - variant, task_name, asset_doc, project_name, host_name + self.default_variant, task_name, asset_doc, + project_name, host_name ) data = { "asset": asset_name, "task": task_name, - "variant": variant + "variant": self.default_variant } data.update(self.get_dynamic_data( - variant, task_name, asset_doc, project_name, host_name + self.default_variant, task_name, asset_doc, + project_name, host_name )) new_instance = CreatedInstance( @@ -69,7 +72,8 @@ class AEWorkfileCreator(AutoCreator): ): asset_doc = get_asset_by_name(project_name, asset_name) subset_name = self.get_subset_name( - variant, task_name, asset_doc, project_name, host_name + self.default_variant, task_name, asset_doc, + project_name, host_name ) existing_instance["asset"] = asset_name existing_instance["task"] = task_name From 0e7c183c1d74380c5cc3b0ac843b5e5d82bf60d8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 22 Aug 2022 18:03:57 +0200 Subject: [PATCH 260/282] Added overwrite subset for different context in AE --- openpype/hosts/aftereffects/plugins/create/workfile_creator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/aftereffects/plugins/create/workfile_creator.py b/openpype/hosts/aftereffects/plugins/create/workfile_creator.py index 3b6dee3b83..f82d15b3c9 100644 --- a/openpype/hosts/aftereffects/plugins/create/workfile_creator.py +++ b/openpype/hosts/aftereffects/plugins/create/workfile_creator.py @@ -77,3 +77,4 @@ class AEWorkfileCreator(AutoCreator): ) existing_instance["asset"] = asset_name existing_instance["task"] = task_name + existing_instance["subset"] = subset_name From d91274bb98e470d501837bcd8f3feacc823a25ec Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:07:38 +0200 Subject: [PATCH 261/282] moved traypublish action into traypublisher host --- openpype/hosts/traypublisher/__init__.py | 6 +++++ .../traypublisher/module.py} | 25 ++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 openpype/hosts/traypublisher/__init__.py rename openpype/{modules/traypublish_action.py => hosts/traypublisher/module.py} (70%) diff --git a/openpype/hosts/traypublisher/__init__.py b/openpype/hosts/traypublisher/__init__.py new file mode 100644 index 0000000000..4eb7bf3eef --- /dev/null +++ b/openpype/hosts/traypublisher/__init__.py @@ -0,0 +1,6 @@ +from .module import TrayPublishModule + + +__all__ = ( + "TrayPublishModule", +) diff --git a/openpype/modules/traypublish_action.py b/openpype/hosts/traypublisher/module.py similarity index 70% rename from openpype/modules/traypublish_action.py rename to openpype/hosts/traypublisher/module.py index 39163b8eb8..25012900bc 100644 --- a/openpype/modules/traypublish_action.py +++ b/openpype/hosts/traypublisher/module.py @@ -1,25 +1,24 @@ import os + +import click + from openpype.lib import get_openpype_execute_args from openpype.lib.execute import run_detached_process from openpype.modules import OpenPypeModule -from openpype_interfaces import ITrayAction +from openpype.modules.interfaces import ITrayAction, IHostModule + +TRAYPUBLISH_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class TrayPublishAction(OpenPypeModule, ITrayAction): +class TrayPublishModule(OpenPypeModule, IHostModule, ITrayAction): label = "New Publish (beta)" name = "traypublish_tool" + host_name = "traypublish" def initialize(self, modules_settings): - import openpype self.enabled = True self.publish_paths = [ - os.path.join( - openpype.PACKAGE_DIR, - "hosts", - "traypublisher", - "plugins", - "publish" - ) + os.path.join(TRAYPUBLISH_ROOT_DIR, "plugins", "publish") ] self._experimental_tools = None @@ -29,7 +28,7 @@ class TrayPublishAction(OpenPypeModule, ITrayAction): self._experimental_tools = ExperimentalTools() def tray_menu(self, *args, **kwargs): - super(TrayPublishAction, self).tray_menu(*args, **kwargs) + super(TrayPublishModule, self).tray_menu(*args, **kwargs) traypublisher = self._experimental_tools.get("traypublisher") visible = False if traypublisher and traypublisher.enabled: @@ -45,5 +44,7 @@ class TrayPublishAction(OpenPypeModule, ITrayAction): self.publish_paths.extend(publish_paths) def run_traypublisher(self): - args = get_openpype_execute_args("traypublisher") + args = get_openpype_execute_args( + "module", "traypublish_tool", "launch" + ) run_detached_process(args) From 2a54de9b538ba4a29faaf3a82da043e276535877 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:07:52 +0200 Subject: [PATCH 262/282] added cli commands to traypublisher module --- openpype/hosts/traypublisher/module.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openpype/hosts/traypublisher/module.py b/openpype/hosts/traypublisher/module.py index 25012900bc..6a088af635 100644 --- a/openpype/hosts/traypublisher/module.py +++ b/openpype/hosts/traypublisher/module.py @@ -48,3 +48,20 @@ class TrayPublishModule(OpenPypeModule, IHostModule, ITrayAction): "module", "traypublish_tool", "launch" ) run_detached_process(args) + + def cli(self, click_group): + click_group.add_command(cli_main) + + +@click.group(TrayPublishModule.name, help="TrayPublisher related commands.") +def cli_main(): + pass + + +@cli_main.command() +def launch(): + """Launch TrayPublish tool UI.""" + + from openpype.tools import traypublisher + + traypublisher.main() From e7000f0108d3a49934b1e7e3e5c20d2d63ffa7f2 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:08:03 +0200 Subject: [PATCH 263/282] removed global traypublisher cli command --- openpype/cli.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openpype/cli.py b/openpype/cli.py index ffe288040e..4b653ac43c 100644 --- a/openpype/cli.py +++ b/openpype/cli.py @@ -46,12 +46,6 @@ def standalonepublisher(): PypeCommands().launch_standalone_publisher() -@main.command() -def traypublisher(): - """Show new OpenPype Standalone publisher UI.""" - PypeCommands().launch_traypublisher() - - @main.command() def tray(): """Launch pype tray. From f9c49fcaefd04dbb5661f22193224456cf97da88 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:12:06 +0200 Subject: [PATCH 264/282] better fill of module name --- openpype/hosts/traypublisher/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/traypublisher/module.py b/openpype/hosts/traypublisher/module.py index 6a088af635..92a2312fec 100644 --- a/openpype/hosts/traypublisher/module.py +++ b/openpype/hosts/traypublisher/module.py @@ -45,7 +45,7 @@ class TrayPublishModule(OpenPypeModule, IHostModule, ITrayAction): def run_traypublisher(self): args = get_openpype_execute_args( - "module", "traypublish_tool", "launch" + "module", self.name, "launch" ) run_detached_process(args) From ffaa0b7adf6816e12500506f5d77ff4ab1ade3f8 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:22:24 +0200 Subject: [PATCH 265/282] moved standalonepublish action into standalone publish host --- openpype/hosts/standalonepublisher/__init__.py | 6 ++++++ .../standalonepublisher/standalonepublish_module.py} | 0 2 files changed, 6 insertions(+) rename openpype/{modules/standalonepublish_action.py => hosts/standalonepublisher/standalonepublish_module.py} (100%) diff --git a/openpype/hosts/standalonepublisher/__init__.py b/openpype/hosts/standalonepublisher/__init__.py index e69de29bb2..64c6d995f7 100644 --- a/openpype/hosts/standalonepublisher/__init__.py +++ b/openpype/hosts/standalonepublisher/__init__.py @@ -0,0 +1,6 @@ +from standalonepublish_module import StandAlonePublishModule + + +__all__ = ( + "StandAlonePublishModule", +) diff --git a/openpype/modules/standalonepublish_action.py b/openpype/hosts/standalonepublisher/standalonepublish_module.py similarity index 100% rename from openpype/modules/standalonepublish_action.py rename to openpype/hosts/standalonepublisher/standalonepublish_module.py From 8c849670872d1d0be4ad5611e7c21c4d77fff8e1 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:23:20 +0200 Subject: [PATCH 266/282] modified standalone publish action to work also as host module --- .../standalonepublish_module.py | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/openpype/hosts/standalonepublisher/standalonepublish_module.py b/openpype/hosts/standalonepublisher/standalonepublish_module.py index ba53ce9b9e..2cd46ce342 100644 --- a/openpype/hosts/standalonepublisher/standalonepublish_module.py +++ b/openpype/hosts/standalonepublisher/standalonepublish_module.py @@ -1,26 +1,26 @@ import os import platform import subprocess + +import click + from openpype.lib import get_openpype_execute_args +from openpype.lib.execute import run_detached_process from openpype.modules import OpenPypeModule -from openpype_interfaces import ITrayAction +from openpype.modules.interfaces import ITrayAction, IHostModule + +STANDALONEPUBLISH_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -class StandAlonePublishAction(OpenPypeModule, ITrayAction): +class StandAlonePublishModule(OpenPypeModule, ITrayAction, IHostModule): label = "Publish" name = "standalonepublish_tool" + host_name = "standalonepublisher" def initialize(self, modules_settings): - import openpype self.enabled = modules_settings[self.name]["enabled"] self.publish_paths = [ - os.path.join( - openpype.PACKAGE_DIR, - "hosts", - "standalonepublisher", - "plugins", - "publish" - ) + os.path.join(STANDALONEPUBLISH_ROOT_DIR, "plugins", "publish") ] def tray_init(self): @@ -31,19 +31,10 @@ class StandAlonePublishAction(OpenPypeModule, ITrayAction): def connect_with_modules(self, enabled_modules): """Collect publish paths from other modules.""" + publish_paths = self.manager.collect_plugin_paths()["publish"] self.publish_paths.extend(publish_paths) def run_standalone_publisher(self): - args = get_openpype_execute_args("standalonepublisher") - kwargs = {} - if platform.system().lower() == "darwin": - new_args = ["open", "-na", args.pop(0), "--args"] - new_args.extend(args) - args = new_args - - detached_process = getattr(subprocess, "DETACHED_PROCESS", None) - if detached_process is not None: - kwargs["creationflags"] = detached_process - - subprocess.Popen(args, **kwargs) + args = get_openpype_execute_args("module", self.name, "launch") + run_detached_process(args) From 9db2eb3cc0d85d706e5637ae19bfc4ae6f49f028 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:23:32 +0200 Subject: [PATCH 267/282] added cli commands for standalone publisher --- .../standalonepublish_module.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/openpype/hosts/standalonepublisher/standalonepublish_module.py b/openpype/hosts/standalonepublisher/standalonepublish_module.py index 2cd46ce342..2d0114dee1 100644 --- a/openpype/hosts/standalonepublisher/standalonepublish_module.py +++ b/openpype/hosts/standalonepublisher/standalonepublish_module.py @@ -38,3 +38,22 @@ class StandAlonePublishModule(OpenPypeModule, ITrayAction, IHostModule): def run_standalone_publisher(self): args = get_openpype_execute_args("module", self.name, "launch") run_detached_process(args) + + def cli(self, click_group): + click_group.add_command(cli_main) + + +@click.group( + StandAlonePublishModule.name, + help="StandalonePublisher related commands.") +def cli_main(): + pass + + +@cli_main.command() +def launch(): + """Launch StandalonePublisher tool UI.""" + + from openpype.tools import standalonepublish + + standalonepublish.main() From 6a271aae101d86e33eaffe6571b736d8b0ab8c88 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:25:10 +0200 Subject: [PATCH 268/282] removed standalonepublisher from global cli commands --- openpype/cli.py | 6 ------ openpype/pype_commands.py | 5 ----- website/docs/admin_openpype_commands.md | 7 ------- 3 files changed, 18 deletions(-) diff --git a/openpype/cli.py b/openpype/cli.py index 4b653ac43c..398d1a94c0 100644 --- a/openpype/cli.py +++ b/openpype/cli.py @@ -40,12 +40,6 @@ def settings(dev): PypeCommands().launch_settings_gui(dev) -@main.command() -def standalonepublisher(): - """Show Pype Standalone publisher UI.""" - PypeCommands().launch_standalone_publisher() - - @main.command() def tray(): """Launch pype tray. diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index a447aa916b..66bf5e9bb4 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -76,11 +76,6 @@ class PypeCommands: import (run_webserver) return run_webserver(*args, **kwargs) - @staticmethod - def launch_standalone_publisher(): - from openpype.tools import standalonepublish - standalonepublish.main() - @staticmethod def launch_traypublisher(): from openpype.tools import traypublisher diff --git a/website/docs/admin_openpype_commands.md b/website/docs/admin_openpype_commands.md index 53fc12410f..8345398e1d 100644 --- a/website/docs/admin_openpype_commands.md +++ b/website/docs/admin_openpype_commands.md @@ -48,7 +48,6 @@ For more information [see here](admin_use.md#run-openpype). | interactive | Start python like interactive console session. | | | projectmanager | Launch Project Manager UI | [📑](#projectmanager-arguments) | | settings | Open Settings UI | [📑](#settings-arguments) | -| standalonepublisher | Open Standalone Publisher UI | [📑](#standalonepublisher-arguments) | --- ### `tray` arguments {#tray-arguments} @@ -159,12 +158,6 @@ openpypeconsole settings ``` --- -### `standalonepublisher` arguments {#standalonepublisher-arguments} -`standalonepublisher` has no command-line arguments. -```shell -openpype_console standalonepublisher -``` - ### `repack-version` arguments {#repack-version-arguments} Takes path to unzipped and possibly modified OpenPype version. Files will be zipped, checksums recalculated and version will be determined by folder name From 986e4325c2379001bf33ca3729e8e9608ce9fe87 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:26:01 +0200 Subject: [PATCH 269/282] fix import --- openpype/hosts/standalonepublisher/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/standalonepublisher/__init__.py b/openpype/hosts/standalonepublisher/__init__.py index 64c6d995f7..394d5be397 100644 --- a/openpype/hosts/standalonepublisher/__init__.py +++ b/openpype/hosts/standalonepublisher/__init__.py @@ -1,4 +1,4 @@ -from standalonepublish_module import StandAlonePublishModule +from .standalonepublish_module import StandAlonePublishModule __all__ = ( From ab1e6c4e3dddacb0726c4eddea078af8fca42ebd Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:30:27 +0200 Subject: [PATCH 270/282] removed unused imports --- openpype/hosts/standalonepublisher/standalonepublish_module.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/standalonepublisher/standalonepublish_module.py b/openpype/hosts/standalonepublisher/standalonepublish_module.py index 2d0114dee1..bf8e1d2c23 100644 --- a/openpype/hosts/standalonepublisher/standalonepublish_module.py +++ b/openpype/hosts/standalonepublisher/standalonepublish_module.py @@ -1,6 +1,4 @@ import os -import platform -import subprocess import click From 227a21c057412ee764facce5ba0ebec6bf19630c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:33:52 +0200 Subject: [PATCH 271/282] removed uninstall function --- openpype/hosts/tvpaint/api/__init__.py | 2 -- openpype/hosts/tvpaint/api/pipeline.py | 13 ------------- 2 files changed, 15 deletions(-) diff --git a/openpype/hosts/tvpaint/api/__init__.py b/openpype/hosts/tvpaint/api/__init__.py index c461b33f4b..43d411d8f9 100644 --- a/openpype/hosts/tvpaint/api/__init__.py +++ b/openpype/hosts/tvpaint/api/__init__.py @@ -6,7 +6,6 @@ from . import pipeline from . import plugin from .pipeline import ( install, - uninstall, maintained_selection, remove_instance, list_instances, @@ -33,7 +32,6 @@ __all__ = ( "plugin", "install", - "uninstall", "maintained_selection", "remove_instance", "list_instances", diff --git a/openpype/hosts/tvpaint/api/pipeline.py b/openpype/hosts/tvpaint/api/pipeline.py index 0118c0104b..73e2c2335c 100644 --- a/openpype/hosts/tvpaint/api/pipeline.py +++ b/openpype/hosts/tvpaint/api/pipeline.py @@ -91,19 +91,6 @@ def install(): register_event_callback("application.exit", application_exit) -def uninstall(): - """Uninstall TVPaint-specific functionality. - - This function is called automatically on calling `uninstall_host()`. - """ - - log.info("OpenPype - Uninstalling TVPaint integration") - pyblish.api.deregister_host("tvpaint") - pyblish.api.deregister_plugin_path(PUBLISH_PATH) - deregister_loader_plugin_path(LOAD_PATH) - deregister_creator_plugin_path(CREATE_PATH) - - def containerise( name, namespace, members, context, loader, current_containers=None ): From b9c175d9691bc07f3bc5db9f31604363edf7f969 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:39:01 +0200 Subject: [PATCH 272/282] converted tvpaint into module --- openpype/hosts/tvpaint/__init__.py | 26 +++++---------- openpype/hosts/tvpaint/tvpaint_module.py | 42 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 openpype/hosts/tvpaint/tvpaint_module.py diff --git a/openpype/hosts/tvpaint/__init__.py b/openpype/hosts/tvpaint/__init__.py index 09b7c52cd1..068631a010 100644 --- a/openpype/hosts/tvpaint/__init__.py +++ b/openpype/hosts/tvpaint/__init__.py @@ -1,20 +1,10 @@ -import os +from .tvpaint_module import ( + get_launch_script_path, + TVPaintModule, +) -def add_implementation_envs(env, _app): - """Modify environments to contain all required for implementation.""" - defaults = { - "OPENPYPE_LOG_NO_COLORS": "True" - } - for key, value in defaults.items(): - if not env.get(key): - env[key] = value - - -def get_launch_script_path(): - current_dir = os.path.dirname(os.path.abspath(__file__)) - return os.path.join( - current_dir, - "api", - "launch_script.py" - ) +__all__ = ( + "get_launch_script_path", + "TVPaintModule", +) diff --git a/openpype/hosts/tvpaint/tvpaint_module.py b/openpype/hosts/tvpaint/tvpaint_module.py new file mode 100644 index 0000000000..a2471553a6 --- /dev/null +++ b/openpype/hosts/tvpaint/tvpaint_module.py @@ -0,0 +1,42 @@ +import os +from openpype.modules import OpenPypeModule +from openpype.modules.interfaces import IHostModule + +TVPAINT_ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) + + +def get_launch_script_path(): + return os.path.join( + TVPAINT_ROOT_DIR, + "api", + "launch_script.py" + ) + + + +class TVPaintModule(OpenPypeModule, IHostModule): + name = "tvpaint" + host_name = "tvpaint" + + def initialize(self, module_settings): + self.enabled = True + + def add_implementation_envs(env, _app): + """Modify environments to contain all required for implementation.""" + + defaults = { + "OPENPYPE_LOG_NO_COLORS": "True" + } + for key, value in defaults.items(): + if not env.get(key): + env[key] = value + + def get_launch_hook_paths(self, app): + if app.host_name != self.host_name: + return [] + return [ + os.path.join(TVPAINT_ROOT_DIR, "hooks") + ] + + def get_workfile_extensions(self): + return [".tvpp"] From c6f8b4559d249655f2b003982b8cf07f71fc70cb Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Mon, 22 Aug 2022 18:45:05 +0200 Subject: [PATCH 273/282] import TVPAINT_ROOT_DIR in init --- openpype/hosts/tvpaint/__init__.py | 2 ++ openpype/hosts/tvpaint/tvpaint_module.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/tvpaint/__init__.py b/openpype/hosts/tvpaint/__init__.py index 068631a010..0a84b575dc 100644 --- a/openpype/hosts/tvpaint/__init__.py +++ b/openpype/hosts/tvpaint/__init__.py @@ -1,10 +1,12 @@ from .tvpaint_module import ( get_launch_script_path, TVPaintModule, + TVPAINT_ROOT_DIR, ) __all__ = ( "get_launch_script_path", "TVPaintModule", + "TVPAINT_ROOT_DIR", ) diff --git a/openpype/hosts/tvpaint/tvpaint_module.py b/openpype/hosts/tvpaint/tvpaint_module.py index a2471553a6..c29602babc 100644 --- a/openpype/hosts/tvpaint/tvpaint_module.py +++ b/openpype/hosts/tvpaint/tvpaint_module.py @@ -13,7 +13,6 @@ def get_launch_script_path(): ) - class TVPaintModule(OpenPypeModule, IHostModule): name = "tvpaint" host_name = "tvpaint" From d65607eedbc2a80121820cc8b6efc66cbc759006 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 23 Aug 2022 10:27:26 +0200 Subject: [PATCH 274/282] removed unused imports --- openpype/hosts/tvpaint/api/pipeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/tvpaint/api/pipeline.py b/openpype/hosts/tvpaint/api/pipeline.py index 73e2c2335c..427c927264 100644 --- a/openpype/hosts/tvpaint/api/pipeline.py +++ b/openpype/hosts/tvpaint/api/pipeline.py @@ -16,8 +16,6 @@ from openpype.pipeline import ( legacy_io, register_loader_plugin_path, register_creator_plugin_path, - deregister_loader_plugin_path, - deregister_creator_plugin_path, AVALON_CONTAINER_ID, ) From 5bf34ebed7c4c848681c484c50ec70bd4ebb728d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 23 Aug 2022 10:29:27 +0200 Subject: [PATCH 275/282] fix project overrides save to mongo --- openpype/settings/handlers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/handlers.py b/openpype/settings/handlers.py index 09f36aa16e..79ec6248ac 100644 --- a/openpype/settings/handlers.py +++ b/openpype/settings/handlers.py @@ -957,7 +957,7 @@ class MongoSettingsHandler(SettingsHandler): if project_settings_doc: self.collection.update_one( {"_id": project_settings_doc["_id"]}, - new_project_settings_doc + {"$set": new_project_settings_doc} ) else: self.collection.insert_one(new_project_settings_doc) From 3176a0130d6b3ab110c0fd3c3616c6c56172df5d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 23 Aug 2022 10:40:27 +0200 Subject: [PATCH 276/282] replaced changelog and upgrade notes with releases information --- website/docs/admin_releases.md | 9 + website/docs/changelog.md | 1138 -------------------------------- website/docs/upgrade_notes.md | 165 ----- website/sidebars.js | 6 +- 4 files changed, 10 insertions(+), 1308 deletions(-) create mode 100644 website/docs/admin_releases.md delete mode 100644 website/docs/changelog.md delete mode 100644 website/docs/upgrade_notes.md diff --git a/website/docs/admin_releases.md b/website/docs/admin_releases.md new file mode 100644 index 0000000000..bba5a22110 --- /dev/null +++ b/website/docs/admin_releases.md @@ -0,0 +1,9 @@ +--- +id: admin_releases +title: Releases +sidebar_label: Releases +--- + +Information about releases can be found on GitHub [Releases page](https://github.com/pypeclub/OpenPype/releases). + +You can find features and bugfixes in the codebase or full changelog for advanced users. diff --git a/website/docs/changelog.md b/website/docs/changelog.md deleted file mode 100644 index 448592b930..0000000000 --- a/website/docs/changelog.md +++ /dev/null @@ -1,1138 +0,0 @@ ---- -id: changelog -title: Changelog -sidebar_label: Changelog ---- - -## [2.18.0](https://github.com/pypeclub/openpype/tree/2.18.0) -_**release date:** (2021-05-18)_ - -[Full Changelog](https://github.com/pypeclub/openpype/compare/2.17.3...2.18.0) - -**Enhancements:** - -- Use SubsetLoader and multiple contexts for delete_old_versions [\#1484](ttps://github.com/pypeclub/OpenPype/pull/1484)) -- TVPaint: Increment workfile version on successful publish. [\#1489](https://github.com/pypeclub/OpenPype/pull/1489) -- Maya: Use of multiple deadline servers [\#1483](https://github.com/pypeclub/OpenPype/pull/1483) - -**Fixed bugs:** - -- Use instance frame start instead of timeline. [\#1486](https://github.com/pypeclub/OpenPype/pull/1486) -- Maya: Redshift - set proper start frame on proxy [\#1480](https://github.com/pypeclub/OpenPype/pull/1480) -- Maya: wrong collection of playblasted frames [\#1517](https://github.com/pypeclub/OpenPype/pull/1517) -- Existing subsets hints in creator [\#1502](https://github.com/pypeclub/OpenPype/pull/1502) - - -### [2.17.3](https://github.com/pypeclub/openpype/tree/2.17.3) -_**release date:** (2021-05-06)_ - -[Full Changelog](https://github.com/pypeclub/openpype/compare/CI/3.0.0-rc.3...2.17.3) - -**Fixed bugs:** - -- Nuke: workfile version synced to db version always [\#1479](https://github.com/pypeclub/OpenPype/pull/1479) - -### [2.17.2](https://github.com/pypeclub/openpype/tree/2.17.2) -_**release date:** (2021-05-04)_ - -[Full Changelog](https://github.com/pypeclub/openpype/compare/CI/3.0.0-rc.1...2.17.2) - -**Enhancements:** - -- Forward/Backward compatible apps and tools with OpenPype 3 [\#1463](https://github.com/pypeclub/OpenPype/pull/1463) - -### [2.17.1](https://github.com/pypeclub/openpype/tree/2.17.1) -_**release date:** (2021-04-30)_ - -[Full Changelog](https://github.com/pypeclub/openpype/compare/2.17.0...2.17.1) - -**Enhancements:** - -- Faster settings UI loading [\#1442](https://github.com/pypeclub/OpenPype/pull/1442) -- Nuke: deadline submission with gpu [\#1414](https://github.com/pypeclub/OpenPype/pull/1414) -- TVPaint frame range definition [\#1424](https://github.com/pypeclub/OpenPype/pull/1424) -- PS - group all published instances [\#1415](https://github.com/pypeclub/OpenPype/pull/1415) -- Add task name to context pop up. [\#1383](https://github.com/pypeclub/OpenPype/pull/1383) -- Enhance review letterbox feature. [\#1371](https://github.com/pypeclub/OpenPype/pull/1371) -- AE add duration validation [\#1363](https://github.com/pypeclub/OpenPype/pull/1363) - -**Fixed bugs:** - -- Houdini menu filename [\#1417](https://github.com/pypeclub/OpenPype/pull/1417) -- Nuke: fixing undo for loaded mov and sequence [\#1433](https://github.com/pypeclub/OpenPype/pull/1433) -- AE - validation for duration was 1 frame shorter [\#1426](https://github.com/pypeclub/OpenPype/pull/1426) - -**Merged pull requests:** - -- Maya: Vray - problem getting all file nodes for look publishing [\#1399](https://github.com/pypeclub/OpenPype/pull/1399) -- Maya: Support for Redshift proxies [\#1360](https://github.com/pypeclub/OpenPype/pull/1360) - -## [2.17.0](https://github.com/pypeclub/openpype/tree/2.17.0) -_**release date:** (2021-04-20)_ - -[Full Changelog](https://github.com/pypeclub/openpype/compare/CI/3.0.0-beta.2...2.17.0) - -**Enhancements:** - -- Forward compatible ftrack group [\#1243](https://github.com/pypeclub/OpenPype/pull/1243) -- Maya: Make tx option configurable with presets [\#1328](https://github.com/pypeclub/OpenPype/pull/1328) -- TVPaint asset name validation [\#1302](https://github.com/pypeclub/OpenPype/pull/1302) -- TV Paint: Set initial project settings. [\#1299](https://github.com/pypeclub/OpenPype/pull/1299) -- TV Paint: Validate mark in and out. [\#1298](https://github.com/pypeclub/OpenPype/pull/1298) -- Validate project settings [\#1297](https://github.com/pypeclub/OpenPype/pull/1297) -- After Effects: added SubsetManager [\#1234](https://github.com/pypeclub/OpenPype/pull/1234) -- Show error message in pyblish UI [\#1206](https://github.com/pypeclub/OpenPype/pull/1206) - -**Fixed bugs:** - -- Hiero: fixing source frame from correct object [\#1362](https://github.com/pypeclub/OpenPype/pull/1362) -- Nuke: fix colourspace, prerenders and nuke panes opening [\#1308](https://github.com/pypeclub/OpenPype/pull/1308) -- AE remove orphaned instance from workfile - fix self.stub [\#1282](https://github.com/pypeclub/OpenPype/pull/1282) -- Nuke: deadline submission with search replaced env values from preset [\#1194](https://github.com/pypeclub/OpenPype/pull/1194) -- Ftrack custom attributes in bulks [\#1312](https://github.com/pypeclub/OpenPype/pull/1312) -- Ftrack optional pypclub role [\#1303](https://github.com/pypeclub/OpenPype/pull/1303) -- After Effects: remove orphaned instances [\#1275](https://github.com/pypeclub/OpenPype/pull/1275) -- Avalon schema names [\#1242](https://github.com/pypeclub/OpenPype/pull/1242) -- Handle duplication of Task name [\#1226](https://github.com/pypeclub/OpenPype/pull/1226) -- Modified path of plugin loads for Harmony and TVPaint [\#1217](https://github.com/pypeclub/OpenPype/pull/1217) -- Regex checks in profiles filtering [\#1214](https://github.com/pypeclub/OpenPype/pull/1214) -- Update custom ftrack session attributes [\#1202](https://github.com/pypeclub/OpenPype/pull/1202) -- Nuke: write node colorspace ignore `default\(\)` label [\#1199](https://github.com/pypeclub/OpenPype/pull/1199) - -## [2.16.0](https://github.com/pypeclub/pype/tree/2.16.0) - - _**release date:** 2021-03-22_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.15.3...2.16.0) - -**Enhancements:** - -- Nuke: deadline submit limit group filter [\#1167](https://github.com/pypeclub/pype/pull/1167) -- Maya: support for Deadline Group and Limit Groups - backport 2.x [\#1156](https://github.com/pypeclub/pype/pull/1156) -- Maya: fixes for Redshift support [\#1152](https://github.com/pypeclub/pype/pull/1152) -- Nuke: adding preset for a Read node name to all img and mov Loaders [\#1146](https://github.com/pypeclub/pype/pull/1146) -- nuke deadline submit with environ var from presets overrides [\#1142](https://github.com/pypeclub/pype/pull/1142) -- Change timers after task change [\#1138](https://github.com/pypeclub/pype/pull/1138) -- Nuke: shortcuts for Pype menu [\#1127](https://github.com/pypeclub/pype/pull/1127) -- Nuke: workfile template [\#1124](https://github.com/pypeclub/pype/pull/1124) -- Sites local settings by site name [\#1117](https://github.com/pypeclub/pype/pull/1117) -- Reset loader's asset selection on context change [\#1106](https://github.com/pypeclub/pype/pull/1106) -- Bulk mov render publishing [\#1101](https://github.com/pypeclub/pype/pull/1101) -- Photoshop: mark publishable instances [\#1093](https://github.com/pypeclub/pype/pull/1093) -- Added ability to define BG color for extract review [\#1088](https://github.com/pypeclub/pype/pull/1088) -- TVPaint extractor enhancement [\#1080](https://github.com/pypeclub/pype/pull/1080) -- Photoshop: added support for .psb in workfiles [\#1078](https://github.com/pypeclub/pype/pull/1078) -- Optionally add task to subset name [\#1072](https://github.com/pypeclub/pype/pull/1072) -- Only extend clip range when collecting. [\#1008](https://github.com/pypeclub/pype/pull/1008) -- Collect audio for farm reviews. [\#1073](https://github.com/pypeclub/pype/pull/1073) - - -**Fixed bugs:** - -- Fix path spaces in jpeg extractor [\#1174](https://github.com/pypeclub/pype/pull/1174) -- Maya: Bugfix: superclass for CreateCameraRig [\#1166](https://github.com/pypeclub/pype/pull/1166) -- Maya: Submit to Deadline - fix typo in condition [\#1163](https://github.com/pypeclub/pype/pull/1163) -- Avoid dot in repre extension [\#1125](https://github.com/pypeclub/pype/pull/1125) -- Fix versions variable usage in standalone publisher [\#1090](https://github.com/pypeclub/pype/pull/1090) -- Collect instance data fix subset query [\#1082](https://github.com/pypeclub/pype/pull/1082) -- Fix getting the camera name. [\#1067](https://github.com/pypeclub/pype/pull/1067) -- Nuke: Ensure "NUKE\_TEMP\_DIR" is not part of the Deadline job environment. [\#1064](https://github.com/pypeclub/pype/pull/1064) - -### [2.15.3](https://github.com/pypeclub/pype/tree/2.15.3) - - _**release date:** 2021-02-26_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.15.2...2.15.3) - -**Enhancements:** - -- Maya: speedup renderable camera collection [\#1053](https://github.com/pypeclub/pype/pull/1053) -- Harmony - add regex search to filter allowed task names for collectin… [\#1047](https://github.com/pypeclub/pype/pull/1047) - -**Fixed bugs:** - -- Ftrack integrate hierarchy fix [\#1085](https://github.com/pypeclub/pype/pull/1085) -- Explicit subset filter in anatomy instance data [\#1059](https://github.com/pypeclub/pype/pull/1059) -- TVPaint frame offset [\#1057](https://github.com/pypeclub/pype/pull/1057) -- Auto fix unicode strings [\#1046](https://github.com/pypeclub/pype/pull/1046) - -### [2.15.2](https://github.com/pypeclub/pype/tree/2.15.2) - - _**release date:** 2021-02-19_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.15.1...2.15.2) - -**Enhancements:** - -- Maya: Vray scene publishing [\#1013](https://github.com/pypeclub/pype/pull/1013) - -**Fixed bugs:** - -- Fix entity move under project [\#1040](https://github.com/pypeclub/pype/pull/1040) -- smaller nuke fixes from production [\#1036](https://github.com/pypeclub/pype/pull/1036) -- TVPaint thumbnail extract fix [\#1031](https://github.com/pypeclub/pype/pull/1031) - -### [2.15.1](https://github.com/pypeclub/pype/tree/2.15.1) - - _**release date:** 2021-02-12_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.15.0...2.15.1) - -**Enhancements:** - -- Delete version as loader action [\#1011](https://github.com/pypeclub/pype/pull/1011) -- Delete old versions [\#445](https://github.com/pypeclub/pype/pull/445) - -**Fixed bugs:** - -- PS - remove obsolete functions from pywin32 [\#1006](https://github.com/pypeclub/pype/pull/1006) -- Clone description of review session objects. [\#922](https://github.com/pypeclub/pype/pull/922) - -## [2.15.0](https://github.com/pypeclub/pype/tree/2.15.0) - - _**release date:** 2021-02-09_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.14.6...2.15.0) - -**Enhancements:** - -- Resolve - loading and updating clips [\#932](https://github.com/pypeclub/pype/pull/932) -- Release/2.15.0 [\#926](https://github.com/pypeclub/pype/pull/926) -- Photoshop: add option for template.psd and prelaunch hook [\#894](https://github.com/pypeclub/pype/pull/894) -- Nuke: deadline presets [\#993](https://github.com/pypeclub/pype/pull/993) -- Maya: Alembic only set attributes that exists. [\#986](https://github.com/pypeclub/pype/pull/986) -- Harmony: render local and handle fixes [\#981](https://github.com/pypeclub/pype/pull/981) -- PSD Bulk export of ANIM group [\#965](https://github.com/pypeclub/pype/pull/965) -- AE - added prelaunch hook for opening last or workfile from template [\#944](https://github.com/pypeclub/pype/pull/944) -- PS - safer handling of loading of workfile [\#941](https://github.com/pypeclub/pype/pull/941) -- Maya: Handling Arnold referenced AOVs [\#938](https://github.com/pypeclub/pype/pull/938) -- TVPaint: switch layer IDs for layer names during identification [\#903](https://github.com/pypeclub/pype/pull/903) -- TVPaint audio/sound loader [\#893](https://github.com/pypeclub/pype/pull/893) -- Clone review session with children. [\#891](https://github.com/pypeclub/pype/pull/891) -- Simple compositing data packager for freelancers [\#884](https://github.com/pypeclub/pype/pull/884) -- Harmony deadline submission [\#881](https://github.com/pypeclub/pype/pull/881) -- Maya: Optionally hide image planes from reviews. [\#840](https://github.com/pypeclub/pype/pull/840) -- Maya: handle referenced AOVs for Vray [\#824](https://github.com/pypeclub/pype/pull/824) -- DWAA/DWAB support on windows [\#795](https://github.com/pypeclub/pype/pull/795) -- Unreal: animation, layout and setdress updates [\#695](https://github.com/pypeclub/pype/pull/695) - -**Fixed bugs:** - -- Maya: Looks - disable hardlinks [\#995](https://github.com/pypeclub/pype/pull/995) -- Fix Ftrack custom attribute update [\#982](https://github.com/pypeclub/pype/pull/982) -- Prores ks in burnin script [\#960](https://github.com/pypeclub/pype/pull/960) -- terminal.py crash on import [\#839](https://github.com/pypeclub/pype/pull/839) -- Extract review handle bizarre pixel aspect ratio [\#990](https://github.com/pypeclub/pype/pull/990) -- Nuke: add nuke related env var to sumbission [\#988](https://github.com/pypeclub/pype/pull/988) -- Nuke: missing preset's variable [\#984](https://github.com/pypeclub/pype/pull/984) -- Get creator by name fix [\#979](https://github.com/pypeclub/pype/pull/979) -- Fix update of project's tasks on Ftrack sync [\#972](https://github.com/pypeclub/pype/pull/972) -- nuke: wrong frame offset in mov loader [\#971](https://github.com/pypeclub/pype/pull/971) -- Create project structure action fix multiroot [\#967](https://github.com/pypeclub/pype/pull/967) -- PS: remove pywin installation from hook [\#964](https://github.com/pypeclub/pype/pull/964) -- Prores ks in burnin script [\#959](https://github.com/pypeclub/pype/pull/959) -- Subset family is now stored in subset document [\#956](https://github.com/pypeclub/pype/pull/956) -- DJV new version arguments [\#954](https://github.com/pypeclub/pype/pull/954) -- TV Paint: Fix single frame Sequence [\#953](https://github.com/pypeclub/pype/pull/953) -- nuke: missing `file` knob update [\#933](https://github.com/pypeclub/pype/pull/933) -- Photoshop: Create from single layer was failing [\#920](https://github.com/pypeclub/pype/pull/920) -- Nuke: baking mov with correct colorspace inherited from write [\#909](https://github.com/pypeclub/pype/pull/909) -- Launcher fix actions discover [\#896](https://github.com/pypeclub/pype/pull/896) -- Get the correct file path for the updated mov. [\#889](https://github.com/pypeclub/pype/pull/889) -- Maya: Deadline submitter - shared data access violation [\#831](https://github.com/pypeclub/pype/pull/831) -- Maya: Take into account vray master AOV switch [\#822](https://github.com/pypeclub/pype/pull/822) - -**Merged pull requests:** - -- Refactor blender to 3.0 format [\#934](https://github.com/pypeclub/pype/pull/934) - -### [2.14.6](https://github.com/pypeclub/pype/tree/2.14.6) - - _**release date:** 2021-01-15_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.14.5...2.14.6) - -**Fixed bugs:** - -- Nuke: improving of hashing path [\#885](https://github.com/pypeclub/pype/pull/885) - -**Merged pull requests:** - -- Hiero: cut videos with correct secons [\#892](https://github.com/pypeclub/pype/pull/892) -- Faster sync to avalon preparation [\#869](https://github.com/pypeclub/pype/pull/869) - -### [2.14.5](https://github.com/pypeclub/pype/tree/2.14.5) - - _**release date:** 2021-01-06_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.14.4...2.14.5) - -**Merged pull requests:** - -- Pype logger refactor [\#866](https://github.com/pypeclub/pype/pull/866) - -### [2.14.4](https://github.com/pypeclub/pype/tree/2.14.4) - - _**release date:** 2020-12-18_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.14.3...2.14.4) - -**Merged pull requests:** - -- Fix - AE - added explicit cast to int [\#837](https://github.com/pypeclub/pype/pull/837) - -### [2.14.3](https://github.com/pypeclub/pype/tree/2.14.3) - - _**release date:** 2020-12-16_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.14.2...2.14.3) - -**Fixed bugs:** - -- TVPaint repair invalid metadata [\#809](https://github.com/pypeclub/pype/pull/809) -- Feature/push hier value to nonhier action [\#807](https://github.com/pypeclub/pype/pull/807) -- Harmony: fix palette and image sequence loader [\#806](https://github.com/pypeclub/pype/pull/806) - -**Merged pull requests:** - -- respecting space in path [\#823](https://github.com/pypeclub/pype/pull/823) - -### [2.14.2](https://github.com/pypeclub/pype/tree/2.14.2) - - _**release date:** 2020-12-04_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.14.1...2.14.2) - -**Enhancements:** - -- Collapsible wrapper in settings [\#767](https://github.com/pypeclub/pype/pull/767) - -**Fixed bugs:** - -- Harmony: template extraction and palettes thumbnails on mac [\#768](https://github.com/pypeclub/pype/pull/768) -- TVPaint store context to workfile metadata \(764\) [\#766](https://github.com/pypeclub/pype/pull/766) -- Extract review audio cut fix [\#763](https://github.com/pypeclub/pype/pull/763) - -**Merged pull requests:** - -- AE: fix publish after background load [\#781](https://github.com/pypeclub/pype/pull/781) -- TVPaint store members key [\#769](https://github.com/pypeclub/pype/pull/769) - -### [2.14.1](https://github.com/pypeclub/pype/tree/2.14.1) - - _**release date:** 2020-11-27_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.14.0...2.14.1) - -**Enhancements:** - -- Settings required keys in modifiable dict [\#770](https://github.com/pypeclub/pype/pull/770) -- Extract review may not add audio to output [\#761](https://github.com/pypeclub/pype/pull/761) - -**Fixed bugs:** - -- After Effects: frame range, file format and render source scene fixes [\#760](https://github.com/pypeclub/pype/pull/760) -- Hiero: trimming review with clip event number [\#754](https://github.com/pypeclub/pype/pull/754) -- TVPaint: fix updating of loaded subsets [\#752](https://github.com/pypeclub/pype/pull/752) -- Maya: Vray handling of default aov [\#748](https://github.com/pypeclub/pype/pull/748) -- Maya: multiple renderable cameras in layer didn't work [\#744](https://github.com/pypeclub/pype/pull/744) -- Ftrack integrate custom attributes fix [\#742](https://github.com/pypeclub/pype/pull/742) - -
    - -## [2.14.0](https://github.com/pypeclub/pype/tree/2.14.0) - - _**release date:** 2020-11-24_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.7...2.14.0) - -**Enhancements:** - -- Ftrack: Event for syncing shot or asset status with tasks.[\#736](https://github.com/pypeclub/pype/pull/736) -- Maya: add camera rig publishing option [\#721](https://github.com/pypeclub/pype/pull/721) -- Maya: Ask user to select non-default camera from scene or create a new. [\#678](https://github.com/pypeclub/pype/pull/678) -- Maya: Camera name can be added to burnins. [\#674](https://github.com/pypeclub/pype/pull/674) -- Sort instances by label in pyblish gui [\#719](https://github.com/pypeclub/pype/pull/719) -- Synchronize ftrack hierarchical and shot attributes [\#716](https://github.com/pypeclub/pype/pull/716) -- Standalone Publisher: Publish editorial from separate image sequences [\#699](https://github.com/pypeclub/pype/pull/699) -- Render publish plugins abstraction [\#687](https://github.com/pypeclub/pype/pull/687) -- TV Paint: image loader with options [\#675](https://github.com/pypeclub/pype/pull/675) -- **TV Paint (Beta):** initial implementation of creators and local rendering [\#693](https://github.com/pypeclub/pype/pull/693) -- **After Effects (Beta):** base integration with loaders [\#667](https://github.com/pypeclub/pype/pull/667) -- Harmony: Javascript refactoring and overall stability improvements [\#666](https://github.com/pypeclub/pype/pull/666) - -**Fixed bugs:** - -- TVPaint: extract review fix [\#740](https://github.com/pypeclub/pype/pull/740) -- After Effects: Review were not being sent to ftrack [\#738](https://github.com/pypeclub/pype/pull/738) -- Maya: vray proxy was not loading [\#722](https://github.com/pypeclub/pype/pull/722) -- Maya: Vray expected file fixes [\#682](https://github.com/pypeclub/pype/pull/682) - -**Deprecated:** - -- Removed artist view from pyblish gui [\#717](https://github.com/pypeclub/pype/pull/717) -- Maya: disable legacy override check for cameras [\#715](https://github.com/pypeclub/pype/pull/715) - - - - -### [2.13.7](https://github.com/pypeclub/pype/tree/2.13.7) - - _**release date:** 2020-11-19_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.6...2.13.7) - -**Merged pull requests:** - -- fix\(SP\): getting fps from context instead of nonexistent entity [\#729](https://github.com/pypeclub/pype/pull/729) - - - - -### [2.13.6](https://github.com/pypeclub/pype/tree/2.13.6) - - _**release date:** 2020-11-15_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.5...2.13.6) - -**Fixed bugs:** - -- Maya workfile version wasn't syncing with renders properly [\#711](https://github.com/pypeclub/pype/pull/711) -- Maya: Fix for publishing multiple cameras with review from the same scene [\#710](https://github.com/pypeclub/pype/pull/710) - - - - -### [2.13.5](https://github.com/pypeclub/pype/tree/2.13.5) - - _**release date:** 2020-11-12_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.4...2.13.5) - - -**Fixed bugs:** - -- Wrong thumbnail file was picked when publishing sequence in standalone publisher [\#703](https://github.com/pypeclub/pype/pull/703) -- Fix: Burnin data pass and FFmpeg tool check [\#701](https://github.com/pypeclub/pype/pull/701) - - - - -### [2.13.4](https://github.com/pypeclub/pype/tree/2.13.4) - - _**release date:** 2020-11-09_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.3...2.13.4) - - -**Fixed bugs:** - -- Photoshop unhiding hidden layers [\#688](https://github.com/pypeclub/pype/issues/688) -- Nuke: Favorite directories "shot dir" "project dir" - not working \#684 [\#685](https://github.com/pypeclub/pype/pull/685) - - - - - -### [2.13.3](https://github.com/pypeclub/pype/tree/2.13.3) - - _**release date:** _2020-11-03_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.2...2.13.3) - -**Fixed bugs:** - -- Fix ffmpeg executable path with spaces [\#680](https://github.com/pypeclub/pype/pull/680) -- Hotfix: Added default version number [\#679](https://github.com/pypeclub/pype/pull/679) - - - - -### [2.13.2](https://github.com/pypeclub/pype/tree/2.13.2) - - _**release date:** 2020-10-28_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.1...2.13.2) - -**Fixed bugs:** - -- Nuke: wrong conditions when fixing legacy write nodes [\#665](https://github.com/pypeclub/pype/pull/665) - - - - -### [2.13.1](https://github.com/pypeclub/pype/tree/2.13.1) - - _**release date:** 2020-10-23_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.13.0...2.13.1) - -**Fixed bugs:** - -- Photoshop: Layer name is not propagating to metadata [\#654](https://github.com/pypeclub/pype/issues/654) -- Photoshop: Loader in fails with "can't set attribute" [\#650](https://github.com/pypeclub/pype/issues/650) -- Hiero: Review video file adding one frame to the end [\#659](https://github.com/pypeclub/pype/issues/659) - - - -## [2.13.0](https://github.com/pypeclub/pype/tree/2.13.0) - - _**release date:** 2020-10-16_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.5...2.13.0) - -**Enhancements:** - -- Deadline Output Folder [\#636](https://github.com/pypeclub/pype/issues/636) -- Nuke Camera Loader [\#565](https://github.com/pypeclub/pype/issues/565) -- Deadline publish job shows publishing output folder [\#649](https://github.com/pypeclub/pype/pull/649) -- Get latest version in lib [\#642](https://github.com/pypeclub/pype/pull/642) -- Improved publishing of multiple representation from SP [\#638](https://github.com/pypeclub/pype/pull/638) -- TvPaint: launch shot work file from within Ftrack [\#631](https://github.com/pypeclub/pype/pull/631) -- Add mp4 support for RV action. [\#628](https://github.com/pypeclub/pype/pull/628) -- Maya: allow renders to have version synced with workfile [\#618](https://github.com/pypeclub/pype/pull/618) -- Renaming nukestudio host folder to hiero [\#617](https://github.com/pypeclub/pype/pull/617) -- Harmony: More efficient publishing [\#615](https://github.com/pypeclub/pype/pull/615) -- Ftrack server action improvement [\#608](https://github.com/pypeclub/pype/pull/608) -- Deadline user defaults to pype username if present [\#607](https://github.com/pypeclub/pype/pull/607) -- Standalone publisher now has icon [\#606](https://github.com/pypeclub/pype/pull/606) -- Nuke render write targeting knob improvement [\#603](https://github.com/pypeclub/pype/pull/603) -- Animated pyblish gui [\#602](https://github.com/pypeclub/pype/pull/602) -- Maya: Deadline - make use of asset dependencies optional [\#591](https://github.com/pypeclub/pype/pull/591) -- Nuke: Publishing, loading and updating alembic cameras [\#575](https://github.com/pypeclub/pype/pull/575) -- Maya: add look assigner to pype menu even if scriptsmenu is not available [\#573](https://github.com/pypeclub/pype/pull/573) -- Store task types in the database [\#572](https://github.com/pypeclub/pype/pull/572) -- Maya: Tiled EXRs to scanline EXRs render option [\#512](https://github.com/pypeclub/pype/pull/512) -- Fusion: basic integration refresh [\#452](https://github.com/pypeclub/pype/pull/452) - -**Fixed bugs:** - -- Burnin script did not propagate ffmpeg output [\#640](https://github.com/pypeclub/pype/issues/640) -- Pyblish-pype spacer in terminal wasn't transparent [\#646](https://github.com/pypeclub/pype/pull/646) -- Lib subprocess without logger [\#645](https://github.com/pypeclub/pype/pull/645) -- Nuke: prevent crash if we only have single frame in sequence [\#644](https://github.com/pypeclub/pype/pull/644) -- Burnin script logs better output [\#641](https://github.com/pypeclub/pype/pull/641) -- Missing audio on farm submission. [\#639](https://github.com/pypeclub/pype/pull/639) -- review from imagesequence error [\#633](https://github.com/pypeclub/pype/pull/633) -- Hiero: wrong order of fps clip instance data collecting [\#627](https://github.com/pypeclub/pype/pull/627) -- Add source for review instances. [\#625](https://github.com/pypeclub/pype/pull/625) -- Task processing in event sync [\#623](https://github.com/pypeclub/pype/pull/623) -- sync to avalon doesn t remove renamed task [\#619](https://github.com/pypeclub/pype/pull/619) -- Intent publish setting wasn't working with default value [\#562](https://github.com/pypeclub/pype/pull/562) -- Maya: Updating a look where the shader name changed, leaves the geo without a shader [\#514](https://github.com/pypeclub/pype/pull/514) - - -### [2.12.5](https://github.com/pypeclub/pype/tree/2.12.5) - -_**release date:** 2020-10-14_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.4...2.12.5) - -**Fixed Bugs:** - -- Harmony: Disable application launch logic [\#637](https://github.com/pypeclub/pype/pull/637) - -### [2.12.4](https://github.com/pypeclub/pype/tree/2.12.4) - -_**release date:** 2020-10-08_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.3...2.12.4) - -**Fixed bugs:** - -- Sync to avalon doesn't remove renamed task [\#605](https://github.com/pypeclub/pype/issues/605) - - -**Merged pull requests:** - -- NukeStudio: small fixes [\#622](https://github.com/pypeclub/pype/pull/622) -- NukeStudio: broken order of plugins [\#620](https://github.com/pypeclub/pype/pull/620) - -### [2.12.3](https://github.com/pypeclub/pype/tree/2.12.3) - -_**release date:** 2020-10-06_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.2...2.12.3) - -**Fixed bugs:** - -- Harmony: empty scene contamination [\#583](https://github.com/pypeclub/pype/issues/583) -- Edit publishing in SP doesn't respect shot selection for publishing [\#542](https://github.com/pypeclub/pype/issues/542) -- Pathlib breaks compatibility with python2 hosts [\#281](https://github.com/pypeclub/pype/issues/281) -- Maya: fix maya scene type preset exception [\#569](https://github.com/pypeclub/pype/pull/569) -- Standalone publisher editorial plugins interfering [\#580](https://github.com/pypeclub/pype/pull/580) - -### [2.12.2](https://github.com/pypeclub/pype/tree/2.12.2) - -_**release date:** 2020-09-25_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.1...2.12.2) - -**Fixed bugs:** - -- Harmony: Saving heavy scenes will crash [\#507](https://github.com/pypeclub/pype/issues/507) -- Extract review a representation name with `\*\_burnin` [\#388](https://github.com/pypeclub/pype/issues/388) -- Hierarchy data was not considering active instances [\#551](https://github.com/pypeclub/pype/pull/551) - -### [2.12.1](https://github.com/pypeclub/pype/tree/2.12.1) - -_**release date:** 2020-09-15_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.12.0...2.12.1) - -**Fixed bugs:** - -- dependency security alert ! [\#484](https://github.com/pypeclub/pype/issues/484) -- Maya: RenderSetup is missing update [\#106](https://github.com/pypeclub/pype/issues/106) -- \ extract effects creates new instance [\#78](https://github.com/pypeclub/pype/issues/78) - - - - -## [2.12.0](https://github.com/pypeclub/pype/tree/2.12.0) ## - -_**release date:** 09 Sept 2020_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.8...2.12.0) - -**Enhancements:** - -- Pype now uses less mongo connections [\#509](https://github.com/pypeclub/pype/pull/509) -- Nuke: adding image loader [\#499](https://github.com/pypeclub/pype/pull/499) -- Completely new application launcher [\#443](https://github.com/pypeclub/pype/pull/443) -- Maya: Optional skip review on renders. [\#441](https://github.com/pypeclub/pype/pull/441) -- Ftrack: Option to push status from task to latest version [\#440](https://github.com/pypeclub/pype/pull/440) -- Maya: Properly containerize image plane loads. [\#434](https://github.com/pypeclub/pype/pull/434) -- Option to keep the review files. [\#426](https://github.com/pypeclub/pype/pull/426) -- Maya: Isolate models during preview publishing [\#425](https://github.com/pypeclub/pype/pull/425) -- Ftrack attribute group is backwards compatible [\#418](https://github.com/pypeclub/pype/pull/418) -- Maya: Publishing of tile renderings on Deadline [\#398](https://github.com/pypeclub/pype/pull/398) -- Slightly better logging gui [\#383](https://github.com/pypeclub/pype/pull/383) -- Standalonepublisher: editorial family features expansion [\#411](https://github.com/pypeclub/pype/pull/411) - -**Fixed bugs:** - -- Maya: Fix tile order for Draft Tile Assembler [\#511](https://github.com/pypeclub/pype/pull/511) -- Remove extra dash [\#501](https://github.com/pypeclub/pype/pull/501) -- Fix: strip dot from repre names in single frame renders [\#498](https://github.com/pypeclub/pype/pull/498) -- Better handling of destination during integrating [\#485](https://github.com/pypeclub/pype/pull/485) -- Fix: allow thumbnail creation for single frame renders [\#460](https://github.com/pypeclub/pype/pull/460) -- added missing argument to launch\_application in ftrack app handler [\#453](https://github.com/pypeclub/pype/pull/453) -- Burnins: Copy bit rate of input video to match quality. [\#448](https://github.com/pypeclub/pype/pull/448) -- Standalone publisher is now independent from tray [\#442](https://github.com/pypeclub/pype/pull/442) -- Bugfix/empty enumerator attributes [\#436](https://github.com/pypeclub/pype/pull/436) -- Fixed wrong order of "other" category collapssing in publisher [\#435](https://github.com/pypeclub/pype/pull/435) -- Multiple reviews where being overwritten to one. [\#424](https://github.com/pypeclub/pype/pull/424) -- Cleanup plugin fail on instances without staging dir [\#420](https://github.com/pypeclub/pype/pull/420) -- deprecated -intra parameter in ffmpeg to new `-g` [\#417](https://github.com/pypeclub/pype/pull/417) -- Delivery action can now work with entered path [\#397](https://github.com/pypeclub/pype/pull/397) - - - - - -### [2.11.8](https://github.com/pypeclub/pype/tree/2.11.8) ## - -_**release date:** 27 Aug 2020_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.7...2.11.8) - -**Fixed bugs:** - -- pyblish pype - other group is collapsed before plugins are done [\#431](https://github.com/pypeclub/pype/issues/431) -- Alpha white edges in harmony on PNGs [\#412](https://github.com/pypeclub/pype/issues/412) -- harmony image loader picks wrong representations [\#404](https://github.com/pypeclub/pype/issues/404) -- Clockify crash when response contain symbol not allowed by UTF-8 [\#81](https://github.com/pypeclub/pype/issues/81) - - - - -### [2.11.7](https://github.com/pypeclub/pype/tree/2.11.7) ## - -_**release date:** 21 Aug 2020_ - - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.6...2.11.7) - -**Fixed bugs:** - -- Clean Up Baked Movie [\#369](https://github.com/pypeclub/pype/issues/369) -- celaction last workfile wasn't picked up correctly [\#459](https://github.com/pypeclub/pype/pull/459) - - - -### [2.11.5](https://github.com/pypeclub/pype/tree/2.11.5) ## - -_**release date:** 13 Aug 2020_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.4...2.11.5) - -**Enhancements:** - -- Standalone publisher now only groups sequence if the extension is known [\#439](https://github.com/pypeclub/pype/pull/439) - -**Fixed bugs:** - -- Logs have been disable for editorial by default to speed up publishing [\#433](https://github.com/pypeclub/pype/pull/433) -- Various fixes for celaction [\#430](https://github.com/pypeclub/pype/pull/430) -- Harmony: invalid variable scope in validate scene settings [\#428](https://github.com/pypeclub/pype/pull/428) -- Harmomny: new representation name for audio was not accepted [\#427](https://github.com/pypeclub/pype/pull/427) - - - - -### [2.11.3](https://github.com/pypeclub/pype/tree/2.11.3) ## - -_**release date:** 4 Aug 2020_ - -[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.2...2.11.3) - -**Fixed bugs:** - -- Harmony: publishing performance issues [\#408](https://github.com/pypeclub/pype/pull/408) - - - - -## 2.11.0 ## - -_**release date:** 27 July 2020_ - -**new:** -- _(blender)_ namespace support [\#341](https://github.com/pypeclub/pype/pull/341) -- _(blender)_ start end frames [\#330](https://github.com/pypeclub/pype/pull/330) -- _(blender)_ camera asset [\#322](https://github.com/pypeclub/pype/pull/322) -- _(pype)_ toggle instances per family in pyblish GUI [\#320](https://github.com/pypeclub/pype/pull/320) -- _(pype)_ current release version is now shown in the tray menu [#379](https://github.com/pypeclub/pype/pull/379) - - -**improved:** -- _(resolve)_ tagging for publish [\#239](https://github.com/pypeclub/pype/issues/239) -- _(pype)_ Support publishing a subset of shots with standalone editorial [\#336](https://github.com/pypeclub/pype/pull/336) -- _(harmony)_ Basic support for palettes [\#324](https://github.com/pypeclub/pype/pull/324) -- _(photoshop)_ Flag outdated containers on startup and publish. [\#309](https://github.com/pypeclub/pype/pull/309) -- _(harmony)_ Flag Outdated containers [\#302](https://github.com/pypeclub/pype/pull/302) -- _(photoshop)_ Publish review [\#298](https://github.com/pypeclub/pype/pull/298) -- _(pype)_ Optional Last workfile launch [\#365](https://github.com/pypeclub/pype/pull/365) - - -**fixed:** -- _(premiere)_ workflow fixes [\#346](https://github.com/pypeclub/pype/pull/346) -- _(pype)_ pype-setup does not work with space in path [\#327](https://github.com/pypeclub/pype/issues/327) -- _(ftrack)_ Ftrack delete action cause circular error [\#206](https://github.com/pypeclub/pype/issues/206) -- _(nuke)_ Priority was forced to 50 [\#345](https://github.com/pypeclub/pype/pull/345) -- _(nuke)_ Fix ValidateNukeWriteKnobs [\#340](https://github.com/pypeclub/pype/pull/340) -- _(maya)_ If camera attributes are connected, we can ignore them. [\#339](https://github.com/pypeclub/pype/pull/339) -- _(pype)_ stop appending of tools environment to existing env [\#337](https://github.com/pypeclub/pype/pull/337) -- _(ftrack)_ Ftrack timeout needs to look at AVALON\_TIMEOUT [\#325](https://github.com/pypeclub/pype/pull/325) -- _(harmony)_ Only zip files are supported. [\#310](https://github.com/pypeclub/pype/pull/310) -- _(pype)_ hotfix/Fix event server mongo uri [\#305](https://github.com/pypeclub/pype/pull/305) -- _(photoshop)_ Subset was not named or validated correctly. [\#304](https://github.com/pypeclub/pype/pull/304) - - - - - -## 2.10.0 ## - -_**release date:** 17 June 2020_ - -**new:** -- _(harmony)_ **Toon Boom Harmony** has been greatly extended to support rigging, scene build, animation and rendering workflows. [#270](https://github.com/pypeclub/pype/issues/270) [#271](https://github.com/pypeclub/pype/issues/271) [#190](https://github.com/pypeclub/pype/issues/190) [#191](https://github.com/pypeclub/pype/issues/191) [#172](https://github.com/pypeclub/pype/issues/172) [#168](https://github.com/pypeclub/pype/issues/168) -- _(pype)_ Added support for rudimentary **edl publishing** into individual shots. [#265](https://github.com/pypeclub/pype/issues/265) -- _(celaction)_ Simple **Celaction** integration has been added with support for workfiles and rendering. [#255](https://github.com/pypeclub/pype/issues/255) -- _(maya)_ Support for multiple job types when submitting to the farm. We can now render Maya or Standalone render jobs for Vray and Arnold (limited support for arnold) [#204](https://github.com/pypeclub/pype/issues/204) -- _(photoshop)_ Added initial support for Photoshop [#232](https://github.com/pypeclub/pype/issues/232) - -**improved:** -- _(blender)_ Updated support for rigs and added support Layout family [#233](https://github.com/pypeclub/pype/issues/233) [#226](https://github.com/pypeclub/pype/issues/226) -- _(premiere)_ It is now possible to choose different storage root for workfiles of different task types. [#255](https://github.com/pypeclub/pype/issues/255) -- _(maya)_ Support for unmerged AOVs in Redshift multipart EXRs [#197](https://github.com/pypeclub/pype/issues/197) -- _(pype)_ Pype repository has been refactored in preparation for 3.0 release [#169](https://github.com/pypeclub/pype/issues/169) -- _(deadline)_ All file dependencies are now passed to deadline from maya to prevent premature start of rendering if caches or textures haven't been coppied over yet. [#195](https://github.com/pypeclub/pype/issues/195) -- _(nuke)_ Script validation can now be made optional. [#194](https://github.com/pypeclub/pype/issues/194) -- _(pype)_ Publishing can now be stopped at any time. [#194](https://github.com/pypeclub/pype/issues/194) - -**fix:** -- _(pype)_ Pyblish-lite has been integrated into pype repository, plus various publishing GUI fixes. [#274](https://github.com/pypeclub/pype/issues/274) [#275](https://github.com/pypeclub/pype/issues/275) [#268](https://github.com/pypeclub/pype/issues/268) [#227](https://github.com/pypeclub/pype/issues/227) [#238](https://github.com/pypeclub/pype/issues/238) -- _(maya)_ Alembic extractor was getting wrong frame range type in certain scenarios [#254](https://github.com/pypeclub/pype/issues/254) -- _(maya)_ Attaching a render to subset in maya was not passing validation in certain scenarios [#256](https://github.com/pypeclub/pype/issues/256) -- _(ftrack)_ Various small fixes to ftrack sync [#263](https://github.com/pypeclub/pype/issues/263) [#259](https://github.com/pypeclub/pype/issues/259) -- _(maya)_ Look extraction is now able to skp invalid connections in shaders [#207](https://github.com/pypeclub/pype/issues/207) - - - - - -## 2.9.0 ## - -_**release date:** 25 May 2020_ - -**new:** -- _(pype)_ Support for **Multiroot projects**. You can now store project data on multiple physical or virtual storages and target individual publishes to these locations. For instance render can be stored on a faster storage than the rest of the project. [#145](https://github.com/pypeclub/pype/issues/145), [#38](https://github.com/pypeclub/pype/issues/38) -- _(harmony)_ Basic implementation of **Toon Boom Harmony** has been added. [#142](https://github.com/pypeclub/pype/issues/142) -- _(pype)_ OSX support is in public beta now. There are issues to be expected, but the main implementation should be functional. [#141](https://github.com/pypeclub/pype/issues/141) - - -**improved:** - -- _(pype)_ **Review extractor** has been completely rebuilt. It now supports granular filtering so you can create **multiple outputs** for different tasks, families or hosts. [#103](https://github.com/pypeclub/pype/issues/103), [#166](https://github.com/pypeclub/pype/issues/166), [#165](https://github.com/pypeclub/pype/issues/165) -- _(pype)_ **Burnin** generation had been extended to **support same multi-output filtering** as review extractor [#103](https://github.com/pypeclub/pype/issues/103) -- _(pype)_ Publishing file templates can now be specified in config for each individual family [#114](https://github.com/pypeclub/pype/issues/114) -- _(pype)_ Studio specific plugins can now be appended to pype standard publishing plugins. [#112](https://github.com/pypeclub/pype/issues/112) -- _(nukestudio)_ Reviewable clips no longer need to be previously cut, exported and re-imported to timeline. **Pype can now dynamically cut reviewable quicktimes** from continuous offline footage during publishing. [#23](https://github.com/pypeclub/pype/issues/23) -- _(deadline)_ Deadline can now correctly differentiate between staging and production pype. [#154](https://github.com/pypeclub/pype/issues/154) -- _(deadline)_ `PYPE_PYTHON_EXE` env variable can now be used to direct publishing to explicit python installation. [#120](https://github.com/pypeclub/pype/issues/120) -- _(nuke)_ Nuke now check for new version of loaded data on file open. [#140](https://github.com/pypeclub/pype/issues/140) -- _(nuke)_ frame range and limit checkboxes are now exposed on write node. [#119](https://github.com/pypeclub/pype/issues/119) - - - -**fix:** - -- _(nukestudio)_ Project Location was using backslashes which was breaking nukestudio native exporting in certains configurations [#82](https://github.com/pypeclub/pype/issues/82) -- _(nukestudio)_ Duplicity in hierarchy tags was prone to throwing publishing error [#130](https://github.com/pypeclub/pype/issues/130), [#144](https://github.com/pypeclub/pype/issues/144) -- _(ftrack)_ multiple stability improvements [#157](https://github.com/pypeclub/pype/issues/157), [#159](https://github.com/pypeclub/pype/issues/159), [#128](https://github.com/pypeclub/pype/issues/128), [#118](https://github.com/pypeclub/pype/issues/118), [#127](https://github.com/pypeclub/pype/issues/127) -- _(deadline)_ multipart EXRs were stopping review publishing on the farm. They are still not supported for automatic review generation, but the publish will go through correctly without the quicktime. [#155](https://github.com/pypeclub/pype/issues/155) -- _(deadline)_ If deadline is non-responsive it will no longer freeze host when publishing [#149](https://github.com/pypeclub/pype/issues/149) -- _(deadline)_ Sometimes deadline was trying to launch render before all the source data was coppied over. [#137](https://github.com/pypeclub/pype/issues/137) _(harmony)_ Basic implementation of **Toon Boom Harmony** has been added. [#142](https://github.com/pypeclub/pype/issues/142) -- _(nuke)_ Filepath knob wasn't updated properly. [#131](https://github.com/pypeclub/pype/issues/131) -- _(maya)_ When extracting animation, the "Write Color Set" options on the instance were not respected. [#108](https://github.com/pypeclub/pype/issues/108) -- _(maya)_ Attribute overrides for AOV only worked for the legacy render layers. Now it works for new render setup as well [#132](https://github.com/pypeclub/pype/issues/132) -- _(maya)_ Stability and usability improvements in yeti workflow [#104](https://github.com/pypeclub/pype/issues/104) - - - - - -## 2.8.0 ## - -_**release date:** 20 April 2020_ - -**new:** - -- _(pype)_ Option to generate slates from json templates. [PYPE-628] [#26](https://github.com/pypeclub/pype/issues/26) -- _(pype)_ It is now possible to automate loading of published subsets into any scene. Documentation will follow :). [PYPE-611] [#24](https://github.com/pypeclub/pype/issues/24) - -**fix:** - -- _(maya)_ Some Redshift render tokens could break publishing. [PYPE-778] [#33](https://github.com/pypeclub/pype/issues/33) -- _(maya)_ Publish was not preserving maya file extension. [#39](https://github.com/pypeclub/pype/issues/39) -- _(maya)_ Rig output validator was failing on nodes without shapes. [#40](https://github.com/pypeclub/pype/issues/40) -- _(maya)_ Yeti caches can now be properly versioned up in the scene inventory. [#40](https://github.com/pypeclub/pype/issues/40) -- _(nuke)_ Build first workfiles was not accepting jpeg sequences. [#34](https://github.com/pypeclub/pype/issues/34) -- _(deadline)_ Trying to generate ffmpeg review from multipart EXRs no longer crashes publishing. [PYPE-781] -- _(deadline)_ Render publishing is more stable in multiplatform environments. [PYPE-775] - - - - - -## 2.7.0 ## - -_**release date:** 30 March 2020_ - -**new:** - -- _(maya)_ Artist can now choose to load multiple references of the same subset at once [PYPE-646, PYPS-81] -- _(nuke)_ Option to use named OCIO colorspaces for review colour baking. [PYPS-82] -- _(pype)_ Pype can now work with `master` versions for publishing and loading. These are non-versioned publishes that are overwritten with the latest version during publish. These are now supported in all the GUIs, but their publishing is deactivated by default. [PYPE-653] -- _(blender)_ Added support for basic blender workflow. We currently support `rig`, `model` and `animation` families. [PYPE-768] -- _(pype)_ Source timecode can now be used in burn-ins. [PYPE-777] -- _(pype)_ Review outputs profiles can now specify delivery resolution different than project setting [PYPE-759] -- _(nuke)_ Bookmark to current context is now added automatically to all nuke browser windows. [PYPE-712] - -**change:** - -- _(maya)_ It is now possible to publish camera without. baking. Keep in mind that unbaked cameras can't be guaranteed to work in other hosts. [PYPE-595] -- _(maya)_ All the renders from maya are now grouped in the loader by their Layer name. [PYPE-482] -- _(nuke/hiero)_ Any publishes from nuke and hiero can now be versioned independently of the workfile. [PYPE-728] - - -**fix:** - -- _(nuke)_ Mixed slashes caused issues in ocio config path. -- _(pype)_ Intent field in pyblish GUI was passing label instead of value to ftrack. [PYPE-733] -- _(nuke)_ Publishing of pre-renders was inconsistent. [PYPE-766] -- _(maya)_ Handles and frame ranges were inconsistent in various places during publishing. -- _(nuke)_ Nuke was crashing if it ran into certain missing knobs. For example DPX output missing `autocrop` [PYPE-774] -- _(deadline)_ Project overrides were not working properly with farm render publishing. -- _(hiero)_ Problems with single frame plates publishing. -- _(maya)_ Redshift RenderPass token were breaking render publishing. [PYPE-778] -- _(nuke)_ Build first workfile was not accepting jpeg sequences. -- _(maya)_ Multipart (Multilayer) EXRs were breaking review publishing due to FFMPEG incompatiblity [PYPE-781] - - - - -## 2.6.0 ## - -_**release date:** 9 March 2020_ - -**change:** -- _(maya)_ render publishing has been simplified and made more robust. Render setup layers are now automatically added to publishing subsets and `render globals` family has been replaced with simple `render` [PYPE-570] -- _(avalon)_ change context and workfiles apps, have been merged into one, that allows both actions to be performed at the same time. [PYPE-747] -- _(pype)_ thumbnails are now automatically propagate to asset from the last published subset in the loader -- _(ftrack)_ publishing comment and intent are now being published to ftrack note as well as describtion. [PYPE-727] -- _(pype)_ when overriding existing version new old representations are now overriden, instead of the new ones just being appended. (to allow this behaviour, the version validator need to be disabled. [PYPE-690]) -- _(pype)_ burnin preset has been significantly simplified. It now doesn't require passing function to each field, but only need the actual text template. to use this, all the current burnin PRESETS MUST BE UPDATED for all the projects. -- _(ftrack)_ credentials are now stored on a per server basis, so it's possible to switch between ftrack servers without having to log in and out. [PYPE-723] - - -**new:** -- _(pype)_ production and development deployments now have different colour of the tray icon. Orange for Dev and Green for production [PYPE-718] -- _(maya)_ renders can now be attached to a publishable subset rather than creating their own subset. For example it is possible to create a reviewable `look` or `model` render and have it correctly attached as a representation of the subsets [PYPE-451] -- _(maya)_ after saving current scene into a new context (as a new shot for instance), all the scene publishing subsets data gets re-generated automatically to match the new context [PYPE-532] -- _(pype)_ we now support project specific publish, load and create plugins [PYPE-740] -- _(ftrack)_ new action that allow archiving/deleting old published versions. User can keep how many of the latest version to keep when the action is ran. [PYPE-748, PYPE-715] -- _(ftrack)_ it is now possible to monitor and restart ftrack event server using ftrack action. [PYPE-658] -- _(pype)_ validator that prevent accidental overwrites of previously published versions. [PYPE-680] -- _(avalon)_ avalon core updated to version 5.6.0 -- _(maya)_ added validator to make sure that relative paths are used when publishing arnold standins. -- _(nukestudio)_ it is now possible to extract and publish audio family from clip in nuke studio [PYPE-682] - -**fix**: -- _(maya)_ maya set framerange button was ignoring handles [PYPE-719] -- _(ftrack)_ sync to avalon was sometime crashing when ran on empty project -- _(nukestudio)_ publishing same shots after they've been previously archived/deleted would result in a crash. [PYPE-737] -- _(nuke)_ slate workflow was breaking in certain scenarios. [PYPE-730] -- _(pype)_ rendering publish workflow has been significantly improved to prevent error resulting from implicit render collection. [PYPE-665, PYPE-746] -- _(pype)_ launching application on a non-synced project resulted in obscure [PYPE-528] -- _(pype)_ missing keys in burnins no longer result in an error. [PYPE-706] -- _(ftrack)_ create folder structure action was sometimes failing for project managers due to wrong permissions. -- _(Nukestudio)_ using `source` in the start frame tag could result in wrong frame range calculation -- _(ftrack)_ sync to avalon action and event have been improved by catching more edge cases and provessing them properly. - - - - -## 2.5.0 ## - -_**release date:** 11 Feb 2020_ - -**change:** -- _(pype)_ added many logs for easier debugging -- _(pype)_ review presets can now be separated between 2d and 3d renders [PYPE-693] -- _(pype)_ anatomy module has been greatly improved to allow for more dynamic pulblishing and faster debugging [PYPE-685] -- _(pype)_ avalon schemas have been moved from `pype-config` to `pype` repository, for simplification. [PYPE-670] -- _(ftrack)_ updated to latest ftrack API -- _(ftrack)_ publishing comments now appear in ftrack also as a note on version with customisable category [PYPE-645] -- _(ftrack)_ delete asset/subset action had been improved. It is now able to remove multiple entities and descendants of the selected entities [PYPE-361, PYPS-72] -- _(workfiles)_ added date field to workfiles app [PYPE-603] -- _(maya)_ old deprecated loader have been removed in favour of a single unified reference loader (old scenes will upgrade automatically to the new loader upon opening) [PYPE-633, PYPE-697] -- _(avalon)_ core updated to 5.5.15 [PYPE-671] -- _(nuke)_ library loader is now available in nuke [PYPE-698] - - -**new:** -- _(pype)_ added pype render wrapper to allow rendering on mixed platform farms. [PYPE-634] -- _(pype)_ added `pype launch` command. It let's admin run applications with dynamically built environment based on the given context. [PYPE-634] -- _(pype)_ added support for extracting review sequences with burnins [PYPE-657] -- _(publish)_ users can now set intent next to a comment when publishing. This will then be reflected on an attribute in ftrack. [PYPE-632] -- _(burnin)_ timecode can now be added to burnin -- _(burnin)_ datetime keys can now be added to burnin and anatomy [PYPE-651] -- _(burnin)_ anatomy templates can now be used in burnins. [PYPE=626] -- _(nuke)_ new validator for render resolution -- _(nuke)_ support for attach slate to nuke renders [PYPE-630] -- _(nuke)_ png sequences were added to loaders -- _(maya)_ added maya 2020 compatibility [PYPE-677] -- _(maya)_ ability to publish and load .ASS standin sequences [PYPS-54] -- _(pype)_ thumbnails can now be published and are visible in the loader. `AVALON_THUMBNAIL_ROOT` environment variable needs to be set for this to work [PYPE-573, PYPE-132] -- _(blender)_ base implementation of blender was added with publishing and loading of .blend files [PYPE-612] -- _(ftrack)_ new action for preparing deliveries [PYPE-639] - - -**fix**: -- _(burnin)_ more robust way of finding ffmpeg for burnins. -- _(pype)_ improved UNC paths remapping when sending to farm. -- _(pype)_ float frames sometimes made their way to representation context in database, breaking loaders [PYPE-668] -- _(pype)_ `pype install --force` was failing sometimes [PYPE-600] -- _(pype)_ padding in published files got calculated wrongly sometimes. It is now instead being always read from project anatomy. [PYPE-667] -- _(publish)_ comment publishing was failing in certain situations -- _(ftrack)_ multiple edge case scenario fixes in auto sync and sync-to-avalon action -- _(ftrack)_ sync to avalon now works on empty projects -- _(ftrack)_ thumbnail update event was failing when deleting entities [PYPE-561] -- _(nuke)_ loader applies proper colorspaces from Presets -- _(nuke)_ publishing handles didn't always work correctly [PYPE-686] -- _(maya)_ assembly publishing and loading wasn't working correctly - - - - - - -## 2.4.0 ## - -_**release date:** 9 Dec 2019_ - -**change:** -- _(ftrack)_ version to status ftrack event can now be configured from Presets - - based on preset `presets/ftracc/ftrack_config.json["status_version_to_task"]` -- _(ftrack)_ sync to avalon event has been completely re-written. It now supports most of the project management situations on ftrack including moving, renaming and deleting entities, updating attributes and working with tasks. -- _(ftrack)_ sync to avalon action has been also re-writen. It is now much faster (up to 100 times depending on a project structure), has much better logging and reporting on encountered problems, and is able to handle much more complex situations. -- _(ftrack)_ sync to avalon trigger by checking `auto-sync` toggle on ftrack [PYPE-504] -- _(pype)_ various new features in the REST api -- _(pype)_ new visual identity used across pype -- _(pype)_ started moving all requirements to pip installation rather than vendorising them in pype repository. Due to a few yet unreleased packages, this means that pype can temporarily be only installed in the offline mode. - -**new:** -- _(nuke)_ support for publishing gizmos and loading them as viewer processes -- _(nuke)_ support for publishing nuke nodes from backdrops and loading them back -- _(pype)_ burnins can now work with start and end frames as keys - - use keys `{frame_start}`, `{frame_end}` and `{current_frame}` in burnin preset to use them. [PYPS-44,PYPS-73, PYPE-602] -- _(pype)_ option to filter logs by user and level in loggin GUI -- _(pype)_ image family added to standalone publisher [PYPE-574] -- _(pype)_ matchmove family added to standalone publisher [PYPE-574] -- _(nuke)_ validator for comparing arbitrary knobs with values from presets -- _(maya)_ option to force maya to copy textures in the new look publish rather than hardlinking them -- _(pype)_ comments from pyblish GUI are now being added to ftrack version -- _(maya)_ validator for checking outdated containers in the scene -- _(maya)_ option to publish and load arnold standin sequence [PYPE-579, PYPS-54] - -**fix**: -- _(pype)_ burnins were not respecting codec of the input video -- _(nuke)_ lot's of various nuke and nuke studio fixes across the board [PYPS-45] -- _(pype)_ workfiles app is not launching with the start of the app by default [PYPE-569] -- _(ftrack)_ ftrack integration during publishing was failing under certain situations [PYPS-66] -- _(pype)_ minor fixes in REST api -- _(ftrack)_ status change event was crashing when the target status was missing [PYPS-68] -- _(ftrack)_ actions will try to reconnect if they fail for some reason -- _(maya)_ problems with fps mapping when using float FPS values -- _(deadline)_ overall improvements to deadline publishing -- _(setup)_ environment variables are now remapped on the fly based on the platform pype is running on. This fixes many issues in mixed platform environments. - - - - -## 2.3.6 # - -_**release date:** 27 Nov 2019_ - -**hotfix**: -- _(ftrack)_ was hiding important debug logo -- _(nuke)_ crashes during workfile publishing -- _(ftrack)_ event server crashes because of signal problems -- _(muster)_ problems with muster render submissions -- _(ftrack)_ thumbnail update event syntax errors - - - - -## 2.3.0 ## - -_release date: 6 Oct 2019_ - -**new**: -- _(maya)_ support for yeti rigs and yeti caches -- _(maya)_ validator for comparing arbitrary attributes against ftrack -- _(pype)_ burnins can now show current date and time -- _(muster)_ pools can now be set in render globals in maya -- _(pype)_ Rest API has been implemented in beta stage -- _(nuke)_ LUT loader has been added -- _(pype)_ rudimentary user module has been added as preparation for user management -- _(pype)_ a simple logging GUI has been added to pype tray -- _(nuke)_ nuke can now bake input process into mov -- _(maya)_ imported models now have selection handle displayed by defaulting -- _(avalon)_ it's is now possible to load multiple assets at once using loader -- _(maya)_ added ability to automatically connect yeti rig to a mesh upon loading - -**changed**: -- _(ftrack)_ event server now runs two parallel processes and is able to keep queue of events to process. -- _(nuke)_ task name is now added to all rendered subsets -- _(pype)_ adding more families to standalone publisher -- _(pype)_ standalone publisher now uses pyblish-lite -- _(pype)_ standalone publisher can now create review quicktimes -- _(ftrack)_ queries to ftrack were sped up -- _(ftrack)_ multiple ftrack action have been deprecated -- _(avalon)_ avalon upstream has been updated to 5.5.0 -- _(nukestudio)_ published transforms can now be animated -- - -**fix**: -- _(maya)_ fps popup button didn't work in some cases -- _(maya)_ geometry instances and references in maya were losing shader assignments -- _(muster)_ muster rendering templates were not working correctly -- _(maya)_ arnold tx texture conversion wasn't respecting colorspace set by the artist -- _(pype)_ problems with avalon db sync -- _(maya)_ ftrack was rounding FPS making it inconsistent -- _(pype)_ wrong icon names in Creator -- _(maya)_ scene inventory wasn't showing anything if representation was removed from database after it's been loaded to the scene -- _(nukestudio)_ multiple bugs squashed -- _(loader)_ loader was taking long time to show all the loading action when first launcher in maya - -## 2.2.0 ## -_**release date:** 8 Sept 2019_ - -**new**: -- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts -- _(nuke)_ option to choose deadline chunk size on write nodes -- _(nukestudio)_ added option to publish soft effects (subTrackItems) from NukeStudio as subsets including LUT files. these can then be loaded in nuke or NukeStudio -- _(nuke)_ option to build nuke script from previously published latest versions of plate and render subsets. -- _(nuke)_ nuke writes now have deadline tab. -- _(ftrack)_ Prepare Project action can now be used for creating the base folder structure on disk and in ftrack, setting up all the initial project attributes and it automatically prepares `pype_project_config` folder for the given project. -- _(clockify)_ Added support for time tracking in clockify. This currently in addition to ftrack time logs, but does not completely replace them. -- _(pype)_ any attributes in Creator and Loader plugins can now be customised using pype preset system - -**changed**: -- nukestudio now uses workio API for workfiles -- _(maya)_ "FIX FPS" prompt in maya now appears in the middle of the screen -- _(muster)_ can now be configured with custom templates -- _(pype)_ global publishing plugins can now be configured using presets as well as host specific ones - - -**fix**: -- wrong version retrieval from path in certain scenarios -- nuke reset resolution wasn't working in certain scenarios - -## 2.1.0 ## -_release date: 6 Aug 2019_ - -A large cleanup release. Most of the change are under the hood. - -**new**: -- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts -- _(pype)_ Added configurable option to add burnins to any generated quicktimes -- _(ftrack)_ Action that identifies what machines pype is running on. -- _(system)_ unify subprocess calls -- _(maya)_ add audio to review quicktimes -- _(nuke)_ add crop before write node to prevent overscan problems in ffmpeg -- **Nuke Studio** publishing and workfiles support -- **Muster** render manager support -- _(nuke)_ Framerange, FPS and Resolution are set automatically at startup -- _(maya)_ Ability to load published sequences as image planes -- _(system)_ Ftrack event that sets asset folder permissions based on task assignees in ftrack. -- _(maya)_ Pyblish plugin that allow validation of maya attributes -- _(system)_ added better startup logging to tray debug, including basic connection information -- _(avalon)_ option to group published subsets to groups in the loader -- _(avalon)_ loader family filters are working now - -**changed**: -- change multiple key attributes to unify their behaviour across the pipeline - - `frameRate` to `fps` - - `startFrame` to `frameStart` - - `endFrame` to `frameEnd` - - `fstart` to `frameStart` - - `fend` to `frameEnd` - - `handle_start` to `handleStart` - - `handle_end` to `handleEnd` - - `resolution_width` to `resolutionWidth` - - `resolution_height` to `resolutionHeight` - - `pixel_aspect` to `pixelAspect` - -- _(nuke)_ write nodes are now created inside group with only some attributes editable by the artist -- rendered frames are now deleted from temporary location after their publishing is finished. -- _(ftrack)_ RV action can now be launched from any entity -- after publishing only refresh button is now available in pyblish UI -- added context instance pyblish-lite so that artist knows if context plugin fails -- _(avalon)_ allow opening selected files using enter key -- _(avalon)_ core updated to v5.2.9 with our forked changes on top - -**fix**: -- faster hierarchy retrieval from db -- _(nuke)_ A lot of stability enhancements -- _(nuke studio)_ A lot of stability enhancements -- _(nuke)_ now only renders a single write node on farm -- _(ftrack)_ pype would crash when launcher project level task -- work directory was sometimes not being created correctly -- major pype.lib cleanup. Removing of unused functions, merging those that were doing the same and general house cleaning. -- _(avalon)_ subsets in maya 2019 weren't behaving correctly in the outliner diff --git a/website/docs/upgrade_notes.md b/website/docs/upgrade_notes.md deleted file mode 100644 index 8231cf997d..0000000000 --- a/website/docs/upgrade_notes.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -id: update_notes -title: Update Notes -sidebar_label: Update Notes ---- - - - -## **Updating to 2.13.0** ## - -### MongoDB - -**Must** - -Due to changes in how tasks are stored in the database (we added task types and possibility of more arbitrary data.), we must take a few precautions when updating. -1. Make sure that ftrack event server with sync to avalon is NOT running during the update. -2. Any project that is to be worked on with 2.13 must be synced from ftrack to avalon with the updated sync to avalon action, or using and updated event server sync to avalon event. - -If 2.12 event servers runs when trying to update the project sync with 2.13, it will override any changes. - -### Nuke Studio / hiero - -Make sure to re-generate pype tags and replace any `task` tags on your shots with the new ones. This will allow you to make multiple tasks of the same type, but with different task name at the same time. - -### Nuke - -Due to a minor update to nuke write node, artists will be prompted to update their write nodes before being able to publish any old shots. There is a "repair" action for this in the publisher, so it doesn't have to be done manually. - - - - -## **Updating to 2.12.0** ## - -### Apps and tools - -**Must** - -run Create/Update Custom attributes action (to update custom attributes group) -check if studio has set custom intent values and move values to ~/config/presets/global/intent.json - -**Optional** - -Set true/false on application and tools by studio usage (eliminate app list in Ftrack and time for registering Ftrack ations) - - - - -## **Updating to 2.11.0** ## - -### Maya in deadline - -We added or own maya deadline plugin to make render management easier. It operates the same as standard mayaBatch in deadline, but allow us to separate Pype sumitted jobs from standard submitter. You'll need to follow this guide to update this [install pype deadline](https://pype.club/docs/admin_hosts#pype-dealine-supplement-code) - - - - -## **Updating to 2.9.0** ## - -### Review and Burnin PRESETS - -This release introduces a major update to working with review and burnin presets. They can now be much more granular and can target extremely specific usecases. The change is backwards compatible with previous format of review and burnin presets, however we highly recommend updating all the presets to the new format. Documentation on what this looks like can be found on pype main [documentation page](https://pype.club/docs/admin_presets_plugins#publishjson). - -### Multiroot and storages - -With the support of multiroot projects, we removed the old `storage.json` from configuration and replaced it with simpler `config/anatomy/roots.json`. This is a required change, but only needs to be done once per studio during the update to 2.9.0. [Read More](https://pype.club/docs/next/admin_config#roots) - - - - -## **Updating to 2.7.0** ## - -### Master Versions -To activate `master` version workflow you need to activate `integrateMasterVersion` plugin in the `config/presets/plugins/global/publish.json` - -``` -"IntegrateMasterVersion": {"enabled": true}, -``` - -### Ftrack - -Make sure that `intent` attributes in ftrack is set correctly. It should follow this setup unless you have your custom values -``` -{ - "label": "Intent", - "key": "intent", - "type": "enumerator", - "entity_type": "assetversion", - "group": "avalon", - "config": { - "multiselect": false, - "data": [ - {"test": "Test"}, - {"wip": "WIP"}, - {"final": "Final"} - ] - } -``` - - - - -## **Updating to 2.6.0** ## - -### Dev vs Prod - -If you want to differentiate between dev and prod deployments of pype, you need to add `config.ini` file to `pype-setup/pypeapp` folder with content. - -``` -[Default] -dev=true -``` - -### Ftrack - -You will have to log in to ftrack in pype after the update. You should be automatically prompted with the ftrack login window when you launch 2.6 release for the first time. - -Event server has to be restarted after the update to enable the ability to control it via action. - -### Presets - -There is a major change in the way how burnin presets are being stored. We simplified the preset format, however that means the currently running production configs need to be tweaked to match the new format. - -:::note Example of converting burnin preset from 2.5 to 2.6 - -2.5 burnin preset - -``` -"burnins":{ - "TOP_LEFT": { - "function": "text", - "text": "{dd}/{mm}/{yyyy}" - }, - "TOP_CENTERED": { - "function": "text", - "text": "" - }, - "TOP_RIGHT": { - "function": "text", - "text": "v{version:0>3}" - }, - "BOTTOM_LEFT": { - "function": "text", - "text": "{frame_start}-{current_frame}-{frame_end}" - }, - "BOTTOM_CENTERED": { - "function": "text", - "text": "{asset}" - }, - "BOTTOM_RIGHT": { - "function": "frame_numbers", - "text": "{username}" - } -``` - -2.6 burnin preset -``` -"burnins":{ - "TOP_LEFT": "{dd}/{mm}/{yyyy}", - "TOP_CENTER": "", - "TOP_RIGHT": "v{version:0>3}" - "BOTTOM_LEFT": "{frame_start}-{current_frame}-{frame_end}", - "BOTTOM_CENTERED": "{asset}", - "BOTTOM_RIGHT": "{username}" -} -``` diff --git a/website/sidebars.js b/website/sidebars.js index 9d60a5811c..c4d07e728f 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -109,11 +109,7 @@ module.exports = { "admin_hosts_tvpaint" ], }, - { - type: "category", - label: "Releases", - items: ["changelog", "update_notes"], - }, + "admin_releases", { type: "category", collapsed: false, From 7466063001d7efce8ef63302e22ac50607be20bf Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 23 Aug 2022 10:41:02 +0200 Subject: [PATCH 277/282] Fix typo Co-authored-by: Milan Kolar --- website/docs/system_introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/system_introduction.md b/website/docs/system_introduction.md index b8a2cea487..05627b5359 100644 --- a/website/docs/system_introduction.md +++ b/website/docs/system_introduction.md @@ -17,7 +17,7 @@ various usage scenarios. You can find detailed breakdown of technical requirements [here](dev_requirements), but in general OpenPype should be able to operate in most studios fairly quickly. The main obstacles are usually related to workflows and habits, that -might now be fully compatible with what OpenPype is expecting or enforcing. It is recommended to go through artists [key concepts](artist_concepts) to get idea about basics. +might not be fully compatible with what OpenPype is expecting or enforcing. It is recommended to go through artists [key concepts](artist_concepts) to get idea about basics. Keep in mind that if you run into any workflows that are not supported, it's usually just because we haven't hit that particular case and it can most likely be added upon request. From bf5584d77f9766dc5da23890c76dba1841c6bfdb Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 23 Aug 2022 11:46:47 +0200 Subject: [PATCH 278/282] Change avalon to openpype Co-authored-by: Roy Nieterau --- website/docs/module_ftrack.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/module_ftrack.md b/website/docs/module_ftrack.md index ad9cf75e8f..6d5529b512 100644 --- a/website/docs/module_ftrack.md +++ b/website/docs/module_ftrack.md @@ -72,7 +72,7 @@ We do not recommend setting your Ftrack user and api key environments in a persi ### Where to run event server -We recommend you to run event server on stable server machine with ability to connect to Avalon database and Ftrack web server. Best practice we recommend is to run event server as service. It can be Windows or Linux. +We recommend you to run event server on stable server machine with ability to connect to OpenPype database and Ftrack web server. Best practice we recommend is to run event server as service. It can be Windows or Linux. :::important Event server should **not** run more than once! It may cause major issues. From 4943b7889eecb207304683b01dca778d376dc9ee Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Tue, 23 Aug 2022 11:47:07 +0200 Subject: [PATCH 279/282] grammar fix Co-authored-by: Roy Nieterau --- website/docs/artist_concepts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/artist_concepts.md b/website/docs/artist_concepts.md index f67ab89b9c..7582540811 100644 --- a/website/docs/artist_concepts.md +++ b/website/docs/artist_concepts.md @@ -10,7 +10,7 @@ sidebar_label: Key Concepts In our pipeline all the main entities the project is made from are internally considered *'Assets'*. Episode, sequence, shot, character, prop, etc. All of these behave identically in the pipeline. Asset names need to be absolutely unique within the project because they are their key identifier. -OpenPype has limitation regarging duplicated names. Name of assets must be unique across whole project. +OpenPype has a limitation regarding duplicated names. Name of assets must be unique across whole project. ### Subset From 6a42f07d8e5977193236f9b3665a5a655188ae1c Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Tue, 23 Aug 2022 15:05:55 +0200 Subject: [PATCH 280/282] fix missing argument --- openpype/hosts/tvpaint/tvpaint_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/tvpaint/tvpaint_module.py b/openpype/hosts/tvpaint/tvpaint_module.py index c29602babc..a004359231 100644 --- a/openpype/hosts/tvpaint/tvpaint_module.py +++ b/openpype/hosts/tvpaint/tvpaint_module.py @@ -20,7 +20,7 @@ class TVPaintModule(OpenPypeModule, IHostModule): def initialize(self, module_settings): self.enabled = True - def add_implementation_envs(env, _app): + def add_implementation_envs(self, env, _app): """Modify environments to contain all required for implementation.""" defaults = { From ffa3b0829f800f3ee43d7b8e0cf80801dffda591 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 23 Aug 2022 15:12:31 +0200 Subject: [PATCH 281/282] flame: fixing frame ranges after client tests --- .../publish/extract_subset_resources.py | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 8a03ba119c..3e1e8db986 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -69,6 +69,9 @@ class ExtractSubsetResources(openpype.api.Extractor): # get media source first frame source_first_frame = instance.data["sourceFirstFrame"] + self.log.debug("_ frame_start: {}".format(frame_start)) + self.log.debug("_ source_first_frame: {}".format(source_first_frame)) + # get timeline in/out of segment clip_in = instance.data["clipIn"] clip_out = instance.data["clipOut"] @@ -102,6 +105,25 @@ class ExtractSubsetResources(openpype.api.Extractor): + r_handle_end ) + # get frame range with handles for representation range + frame_start_handle = frame_start - handle_start + repre_frame_start = frame_start_handle + if include_handles: + if r_speed == 1.0: + frame_start_handle = frame_start + else: + frame_start_handle = ( + frame_start - handle_start) + r_handle_start + + self.log.debug("_ frame_start_handle: {}".format( + frame_start_handle)) + self.log.debug("_ repre_frame_start: {}".format( + repre_frame_start)) + + # calculate duration with handles + source_duration_handles = ( + source_end_handles - source_start_handles) + 1 + # create staging dir path staging_dir = self.staging_dir(instance) @@ -120,15 +142,22 @@ class ExtractSubsetResources(openpype.api.Extractor): # set versiondata if any retime version_data = retimed_data.get("version_data") + self.log.debug("_ version_data: {}".format(version_data)) if version_data: instance.data["versionData"].update(version_data) if r_speed != 1.0: instance.data["versionData"].update({ - "frameStart": source_start_handles + r_handle_start, - "frameEnd": source_end_handles - r_handle_end, + "frameStart": frame_start_handle, + "frameEnd": ( + (frame_start_handle + source_duration_handles - 1) + - (r_handle_start + r_handle_end) + ) }) + self.log.debug("_ i_version_data: {}".format( + instance.data["versionData"] + )) # loop all preset names and for unique_name, preset_config in export_presets.items(): @@ -152,22 +181,6 @@ class ExtractSubsetResources(openpype.api.Extractor): ) ) - # get frame range with handles for representation range - frame_start_handle = frame_start - handle_start - if include_handles: - if r_speed == 1.0: - frame_start_handle = frame_start - else: - frame_start_handle = ( - frame_start - handle_start) + r_handle_start - - self.log.debug("_ frame_start_handle: {}".format( - frame_start_handle)) - - # calculate duration with handles - source_duration_handles = ( - source_end_handles - source_start_handles) + 1 - exporting_clip = None name_patern_xml = "_{}.".format( unique_name) @@ -203,7 +216,7 @@ class ExtractSubsetResources(openpype.api.Extractor): modify_xml_data.update({ # enum position low start from 0 "frameIndex": 0, - "startFrame": frame_start_handle, + "startFrame": repre_frame_start, "namePattern": name_patern_xml }) @@ -248,7 +261,7 @@ class ExtractSubsetResources(openpype.api.Extractor): "namePattern": "__thumbnail" }) thumb_frame_number = int(in_mark + ( - source_duration_handles / 2)) + (out_mark - in_mark + 1) / 2)) self.log.debug("__ thumb_frame_number: {}".format( thumb_frame_number @@ -329,9 +342,9 @@ class ExtractSubsetResources(openpype.api.Extractor): # add frame range if preset_config["representation_add_range"]: representation_data.update({ - "frameStart": frame_start_handle, + "frameStart": repre_frame_start, "frameEnd": ( - frame_start_handle + source_duration_handles) - 1, + repre_frame_start + source_duration_handles) - 1, "fps": instance.data["fps"] }) From b96cff6ea9f85f80d5ee801fc8bd17020e484580 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 23 Aug 2022 15:24:58 +0200 Subject: [PATCH 282/282] Removed submodule vendor/configs/OpenColorIO-Configs --- vendor/configs/OpenColorIO-Configs | 1 - 1 file changed, 1 deletion(-) delete mode 160000 vendor/configs/OpenColorIO-Configs diff --git a/vendor/configs/OpenColorIO-Configs b/vendor/configs/OpenColorIO-Configs deleted file mode 160000 index 0bb079c08b..0000000000 --- a/vendor/configs/OpenColorIO-Configs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0bb079c08be410030669cbf5f19ff869b88af953

(Zfh%a(0ju?YwE!YFunz8QgZg!+ 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 TAO39h=#iqV>f2Ij<1haQx}=q) literal 0 HcmV?d00001 diff --git a/website/docs/assets/unreal_openpype_tools_load.png b/website/docs/assets/unreal_openpype_tools_load.png new file mode 100644 index 0000000000000000000000000000000000000000..4909feac3b26adad018829cf4a26d07d9ab324aa GIT binary patch literal 27465 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 literal 0 HcmV?d00001 diff --git a/website/docs/assets/unreal_level_streaming_method_no_sequences.png b/website/docs/assets/unreal_level_streaming_method_no_sequences.png new file mode 100644 index 0000000000000000000000000000000000000000..77a2754ded51a563ad3426d13f65edff7c2ce83f GIT binary patch literal 82416 zcmX`SWmKD8*R>rSiWgek-6`%~v{-S6;>9gEgyIgxT|#jy4#i!AySuylo9lkQ@%_lo zIP)iCBzvzl=Um4QS5cBd|3LTw005xN$x3|(0AP^;02l#eMCd0jg{9iiHyD@iG7^AF z2=O8G0p3zvQ5*pH8;km4f&hI+ag^0@0RS+1{(Hd;I24-!0Pla~q{P)d3{SFuL!x#vU4B!`e}+McKtcFsqsvLZ#dyS6={d$9X`^3T`2&MKBI4~UyxeaW$Zt!5 z*YWer(kk!tY!eC0(T#sb9aW|Ft1WJ2YxCzTAI{sX%c|O+tPYF8F#<>bErc?@+$aD4 z)6pa~C-U@gUBIDvnt2M7@9Xrg#7$)1q?WW>RG;NO4e@qH==&GEv@eU7twZMCPKTKZ zCp&K6Hd0WYh+|UHlzlH&A;VxK85wy35=~nvr(k(r!|vy+b0!xfoq>^GM`aw_w&~?7 zQogk#qvDzZ14o%;zVQTvnL1}}`)3>iT=dT^C>1dR>3A)di~f`Mb=0&IYn*SYz#PBq z8aLtjF9IC-3jFh>(%^QH`;w+NoLho=;*$3EL;0>#P6w&?B43E4yp|xl_c}u4!4Db+ITe(6+R&$W+FFq zU}gFK(k~W^+$dn&Ts=}drf+vGPTwJAn^o`=UtXT{*JO8UfSt=CHLVAmN{nR{gyXRNz)Kl??O ze*TsaxX(l9jV|QH047`k<@txnc)(trwG&$5<`-G3C9ckpCTApgbyyygHh_eHG=McX z7UnkwF|sc};s%xk@C9TCfb$4unpvI~RS5~PNQMcf0@b@JCfN1#1b*y_nVFrBeZk*E z1wgDZjcr+tnk|}?oU9VC>x`Jic<<0KAiptYONa$2wZU=p3<*t^b2!u}|Z5`vQ3QC8_3{OeI6kaL-|2 zg)qgmW7!pnwad|jjQy-S$`clGNLr!I!Ll7|9zKU9TH-GaLU-PAJ)$8Zi6@p(U~6;5 z1sX|v|F?xd2i;{l*)N(t@jrzUs>tK{!|@o?gV;U70LWj%IBP6b7Up?- zoI#A_g6JS1vN5uShS`jfn;C;+0tg@#iVGw43j69e0$`qrF1|rWHr|w*;3RDJ4KyHa4?QptJnSYpG z@}X_Xs=7dOlOZ0GrJkKUAW|7u7kk6 z#TWw!5^SzGf!FFPzps)|g%4{0E6iC61kM!eMtg%=Xsa6wfI*m3;kNSSW%)z{kdKA5;-xae-dHaH1<&`T2% zDtuzX&Evl0zV16Ro%42cRg=*&{qo4mgY&B*?-*5PHBD1nD|4 zS`8twFR*)=&l%%;1}cLvWr=5t{j98tS3I`scb9A`YtY@-JY~|jT{LI^fQKzTK}(FP zIk&;{Ag+?(JP#HzR=%8*#NfzQQy&d^LohvlRZi3L2=XfYLj#9KV`TKKq#`X%&nA