Merge pull request #4195 from ynput/feature/OP-2479_color-v3-Colorspace-management-and-distribution

This commit is contained in:
Jakub Ježek 2023-01-19 12:43:44 +01:00 committed by GitHub
commit 8ed932b6c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 2372 additions and 407 deletions

View file

@ -1,4 +1,3 @@
import enlighten
import os
import re
import urllib
@ -252,6 +251,11 @@ class RemoteFileHandler:
if key.startswith('download_warning'):
return value
# handle antivirus warning for big zips
found = re.search("(confirm=)([^&.+])", response.text)
if found:
return found.groups()[1]
return None
@staticmethod
@ -259,15 +263,9 @@ class RemoteFileHandler:
response_gen, destination,
):
with open(destination, "wb") as f:
pbar = enlighten.Counter(
total=None, desc="Save content", units="%", color="green")
progress = 0
for chunk in response_gen:
if chunk: # filter out keep-alive new chunks
f.write(chunk)
progress += len(chunk)
pbar.close()
@staticmethod
def _quota_exceeded(first_chunk):

View file

@ -31,7 +31,6 @@ from openpype.lib import (
from openpype.settings import (
get_project_settings,
get_anatomy_settings,
get_current_project_settings,
)
from openpype.modules import ModulesManager
@ -45,6 +44,9 @@ from openpype.pipeline.context_tools import (
get_current_project_asset,
get_custom_workfile_template_from_session
)
from openpype.pipeline.colorspace import (
get_imageio_config
)
from openpype.pipeline.workfile import BuildWorkfile
from . import gizmo_menu
@ -690,14 +692,6 @@ def get_node_path(path, padding=4):
def get_nuke_imageio_settings():
project_imageio = get_project_settings(
Context.project_name)["nuke"]["imageio"]
# backward compatibility for project started before 3.10
# those are still having `__legacy__` knob types.
if not project_imageio["enabled"]:
return get_anatomy_settings(Context.project_name)["imageio"]["nuke"]
return get_project_settings(Context.project_name)["nuke"]["imageio"]
@ -2002,59 +1996,55 @@ class WorkfileSettings(object):
"Attention! Viewer nodes {} were erased."
"It had wrong color profile".format(erased_viewers))
def set_root_colorspace(self, root_dict):
def set_root_colorspace(self, nuke_colorspace):
''' Adds correct colorspace to root
Arguments:
root_dict (dict): adjustmensts from presets
nuke_colorspace (dict): adjustmensts from presets
'''
if not isinstance(root_dict, dict):
msg = "set_root_colorspace(): argument should be dictionary"
log.error(msg)
nuke.message(msg)
workfile_settings = nuke_colorspace["workfile"]
log.debug(">> root_dict: {}".format(root_dict))
# resolve config data if they are enabled in host
config_data = None
if nuke_colorspace.get("ocio_config", {}).get("enabled"):
# switch ocio config to custom config
workfile_settings["OCIO_config"] = "custom"
workfile_settings["colorManagement"] = "OCIO"
# get resolved ocio config path
config_data = get_imageio_config(
legacy_io.active_project(), "nuke"
)
# first set OCIO
if self._root_node["colorManagement"].value() \
not in str(root_dict["colorManagement"]):
not in str(workfile_settings["colorManagement"]):
self._root_node["colorManagement"].setValue(
str(root_dict["colorManagement"]))
log.debug("nuke.root()['{0}'] changed to: {1}".format(
"colorManagement", root_dict["colorManagement"]))
root_dict.pop("colorManagement")
str(workfile_settings["colorManagement"]))
# we dont need the key anymore
workfile_settings.pop("colorManagement")
# second set ocio version
if self._root_node["OCIO_config"].value() \
not in str(root_dict["OCIO_config"]):
not in str(workfile_settings["OCIO_config"]):
self._root_node["OCIO_config"].setValue(
str(root_dict["OCIO_config"]))
log.debug("nuke.root()['{0}'] changed to: {1}".format(
"OCIO_config", root_dict["OCIO_config"]))
root_dict.pop("OCIO_config")
str(workfile_settings["OCIO_config"]))
# we dont need the key anymore
workfile_settings.pop("OCIO_config")
# third set ocio custom path
if root_dict.get("customOCIOConfigPath"):
unresolved_path = root_dict["customOCIOConfigPath"]
ocio_paths = unresolved_path[platform.system().lower()]
resolved_path = None
for ocio_p in ocio_paths:
resolved_path = str(ocio_p).format(**os.environ)
if not os.path.exists(resolved_path):
continue
if resolved_path:
self._root_node["customOCIOConfigPath"].setValue(
str(resolved_path).replace("\\", "/")
)
log.debug("nuke.root()['{}'] changed to: {}".format(
"customOCIOConfigPath", resolved_path))
root_dict.pop("customOCIOConfigPath")
if config_data:
self._root_node["customOCIOConfigPath"].setValue(
str(config_data["path"]).replace("\\", "/")
)
# backward compatibility, remove in case it exists
workfile_settings.pop("customOCIOConfigPath")
# then set the rest
for knob, value in root_dict.items():
for knob, value in workfile_settings.items():
# skip unfilled ocio config path
# it will be dict in value
if isinstance(value, dict):
@ -2184,7 +2174,7 @@ class WorkfileSettings(object):
log.info("Setting colorspace to workfile...")
try:
self.set_root_colorspace(nuke_colorspace["workfile"])
self.set_root_colorspace(nuke_colorspace)
except AttributeError:
msg = "set_colorspace(): missing `workfile` settings in template"
nuke.message(msg)

View file

@ -7,8 +7,7 @@ import nuke
from openpype.pipeline import publish
class NukeRenderLocal(publish.Extractor):
# TODO: rewrite docstring to nuke
class NukeRenderLocal(publish.ExtractorColormanaged):
"""Render the current Nuke composition locally.
Extract the result of savers by starting a comp render
@ -69,6 +68,7 @@ class NukeRenderLocal(publish.Extractor):
)
ext = node["file_type"].value()
colorspace = node["colorspace"].value()
if "representations" not in instance.data:
instance.data["representations"] = []
@ -92,6 +92,13 @@ class NukeRenderLocal(publish.Extractor):
'files': filenames,
"stagingDir": out_dir
}
# inject colorspace data
self.set_representation_colorspace(
repre, instance.context,
colorspace=colorspace
)
instance.data["representations"].append(repre)
self.log.info("Extracted instance '{0}' to: {1}".format(

View file

@ -0,0 +1,468 @@
from copy import deepcopy
import re
import os
import sys
import json
import platform
import contextlib
import tempfile
from openpype import PACKAGE_DIR
from openpype.settings import get_project_settings
from openpype.lib import (
StringTemplate,
run_openpype_process,
Logger
)
from openpype.pipeline import Anatomy
log = Logger.get_logger(__name__)
@contextlib.contextmanager
def _make_temp_json_file():
"""Wrapping function for json temp file
"""
try:
# Store dumped json to temporary file
temporary_json_file = tempfile.NamedTemporaryFile(
mode="w", suffix=".json", delete=False
)
temporary_json_file.close()
temporary_json_filepath = temporary_json_file.name.replace(
"\\", "/"
)
yield temporary_json_filepath
except IOError as _error:
raise IOError(
"Unable to create temp json file: {}".format(
_error
)
)
finally:
# Remove the temporary json
os.remove(temporary_json_filepath)
def get_ocio_config_script_path():
"""Get path to ocio wrapper script
Returns:
str: path string
"""
return os.path.normpath(
os.path.join(
PACKAGE_DIR,
"scripts",
"ocio_wrapper.py"
)
)
def get_imageio_colorspace_from_filepath(
path, host_name, project_name,
config_data=None, file_rules=None,
project_settings=None,
validate=True
):
"""Get colorspace name from filepath
ImageIO Settings file rules are tested for matching rule.
Args:
path (str): path string, file rule pattern is tested on it
host_name (str): host name
project_name (str): project name
config_data (dict, optional): config path and template in dict.
Defaults to None.
file_rules (dict, optional): file rule data from settings.
Defaults to None.
project_settings (dict, optional): project settings. Defaults to None.
validate (bool, optional): should resulting colorspace be validated
with config file? Defaults to True.
Returns:
str: name of colorspace
"""
if not any([config_data, file_rules]):
project_settings = project_settings or get_project_settings(
project_name
)
config_data = get_imageio_config(
project_name, host_name, project_settings)
file_rules = get_imageio_file_rules(
project_name, host_name, project_settings)
# match file rule from path
colorspace_name = None
for _frule_name, file_rule in file_rules.items():
pattern = file_rule["pattern"]
extension = file_rule["ext"]
ext_match = re.match(
r".*(?=.{})".format(extension), path
)
file_match = re.search(
pattern, path
)
if ext_match and file_match:
colorspace_name = file_rule["colorspace"]
if not colorspace_name:
log.info("No imageio file rule matched input path: '{}'".format(
path
))
return None
# validate matching colorspace with config
if validate and config_data:
validate_imageio_colorspace_in_config(
config_data["path"], colorspace_name)
return colorspace_name
def parse_colorspace_from_filepath(
path, host_name, project_name,
config_data=None,
project_settings=None
):
"""Parse colorspace name from filepath
An input path can have colorspace name used as part of name
or as folder name.
Args:
path (str): path string
host_name (str): host name
project_name (str): project name
config_data (dict, optional): config path and template in dict.
Defaults to None.
project_settings (dict, optional): project settings. Defaults to None.
Returns:
str: name of colorspace
"""
if not config_data:
project_settings = project_settings or get_project_settings(
project_name
)
config_data = get_imageio_config(
project_name, host_name, project_settings)
config_path = config_data["path"]
# match file rule from path
colorspace_name = None
colorspaces = get_ocio_config_colorspaces(config_path)
for colorspace_key in colorspaces:
# check underscored variant of colorspace name
# since we are reformating it in integrate.py
if colorspace_key.replace(" ", "_") in path:
colorspace_name = colorspace_key
break
if colorspace_key in path:
colorspace_name = colorspace_key
break
if not colorspace_name:
log.info("No matching colorspace in config '{}' for path: '{}'".format(
config_path, path
))
return None
return colorspace_name
def validate_imageio_colorspace_in_config(config_path, colorspace_name):
"""Validator making sure colorspace name is used in config.ocio
Args:
config_path (str): path leading to config.ocio file
colorspace_name (str): tested colorspace name
Raises:
KeyError: missing colorspace name
Returns:
bool: True if exists
"""
colorspaces = get_ocio_config_colorspaces(config_path)
if colorspace_name not in colorspaces:
raise KeyError(
"Missing colorspace '{}' in config file '{}'".format(
colorspace_name, config_path)
)
return True
def get_ocio_config_colorspaces(config_path):
"""Get all colorspace data
Wrapper function for aggregating all names and its families.
Families can be used for building menu and submenus in gui.
Args:
config_path (str): path leading to config.ocio file
Returns:
dict: colorspace and family in couple
"""
if sys.version_info[0] == 2:
return get_colorspace_data_subprocess(config_path)
from ..scripts.ocio_wrapper import _get_colorspace_data
return _get_colorspace_data(config_path)
def get_colorspace_data_subprocess(config_path):
"""Get colorspace data via subprocess
Wrapper for Python 2 hosts.
Args:
config_path (str): path leading to config.ocio file
Returns:
dict: colorspace and family in couple
"""
with _make_temp_json_file() as tmp_json_path:
# Prepare subprocess arguments
args = [
"run", get_ocio_config_script_path(),
"config", "get_colorspace",
"--in_path", config_path,
"--out_path", tmp_json_path
]
log.info("Executing: {}".format(" ".join(args)))
process_kwargs = {
"logger": log,
"env": {}
}
run_openpype_process(*args, **process_kwargs)
# return all colorspaces
return_json_data = open(tmp_json_path).read()
return json.loads(return_json_data)
def get_ocio_config_views(config_path):
"""Get all viewer data
Wrapper function for aggregating all display and related viewers.
Key can be used for building gui menu with submenus.
Args:
config_path (str): path leading to config.ocio file
Returns:
dict: `display/viewer` and viewer data
"""
if sys.version_info[0] == 2:
return get_views_data_subprocess(config_path)
from ..scripts.ocio_wrapper import _get_views_data
return _get_views_data(config_path)
def get_views_data_subprocess(config_path):
"""Get viewers data via subprocess
Wrapper for Python 2 hosts.
Args:
config_path (str): path leading to config.ocio file
Returns:
dict: `display/viewer` and viewer data
"""
with _make_temp_json_file() as tmp_json_path:
# Prepare subprocess arguments
args = [
"run", get_ocio_config_script_path(),
"config", "get_views",
"--in_path", config_path,
"--out_path", tmp_json_path
]
log.info("Executing: {}".format(" ".join(args)))
process_kwargs = {
"logger": log,
"env": {}
}
run_openpype_process(*args, **process_kwargs)
# return all colorspaces
return_json_data = open(tmp_json_path).read()
return json.loads(return_json_data)
def get_imageio_config(
project_name, host_name,
project_settings=None,
anatomy_data=None,
anatomy=None
):
"""Returns config data from settings
Config path is formatted in `path` key
and original settings input is saved into `template` key.
Args:
project_name (str): project name
host_name (str): host name
project_settings (dict, optional): project settings.
Defaults to None.
anatomy_data (dict, optional): anatomy formatting data.
Defaults to None.
anatomy (lib.Anatomy, optional): Anatomy object.
Defaults to None.
Returns:
dict or bool: config path data or None
"""
project_settings = project_settings or get_project_settings(project_name)
anatomy = anatomy or Anatomy(project_name)
if not anatomy_data:
from openpype.pipeline.context_tools import (
get_template_data_from_session)
anatomy_data = get_template_data_from_session()
# add project roots to anatomy data
anatomy_data["root"] = anatomy.roots
anatomy_data["platform"] = platform.system().lower()
# get colorspace settings
imageio_global, imageio_host = _get_imageio_settings(
project_settings, host_name)
config_host = imageio_host["ocio_config"]
if config_host["enabled"]:
config_data = _get_config_data(
config_host["filepath"], anatomy_data
)
else:
config_data = None
if not config_data:
# get config path from either global or host_name
config_global = imageio_global["ocio_config"]
config_data = _get_config_data(
config_global["filepath"], anatomy_data
)
if not config_data:
raise FileExistsError(
"No OCIO config found in settings. It is "
"either missing or there is typo in path inputs"
)
return config_data
def _get_config_data(path_list, anatomy_data):
"""Return first existing path in path list.
If template is used in path inputs,
then it is formated by anatomy data
and environment variables
Args:
path_list (list[str]): list of abs paths
anatomy_data (dict): formating data
Returns:
dict: config data
"""
formatting_data = deepcopy(anatomy_data)
# format the path for potential env vars
formatting_data.update(dict(**os.environ))
# first try host config paths
for path_ in path_list:
formated_path = _format_path(path_, formatting_data)
if not os.path.exists(formated_path):
continue
return {
"path": os.path.normpath(formated_path),
"template": path_
}
def _format_path(tempate_path, formatting_data):
"""Single template path formating.
Args:
tempate_path (str): template string
formatting_data (dict): data to be used for
template formating
Returns:
str: absolute formated path
"""
# format path for anatomy keys
formatted_path = StringTemplate(tempate_path).format(
formatting_data)
return os.path.abspath(formatted_path)
def get_imageio_file_rules(project_name, host_name, project_settings=None):
"""Get ImageIO File rules from project settings
Args:
project_name (str): project name
host_name (str): host name
project_settings (dict, optional): project settings.
Defaults to None.
Returns:
dict: file rules data
"""
project_settings = project_settings or get_project_settings(project_name)
imageio_global, imageio_host = _get_imageio_settings(
project_settings, host_name)
# get file rules from global and host_name
frules_global = imageio_global["file_rules"]
frules_host = imageio_host["file_rules"]
# compile file rules dictionary
file_rules = {}
if frules_global["enabled"]:
file_rules.update(frules_global["rules"])
if frules_host["enabled"]:
file_rules.update(frules_host["rules"])
return file_rules
def _get_imageio_settings(project_settings, host_name):
"""Get ImageIO settings for global and host
Args:
project_settings (dict): project settings.
Defaults to None.
host_name (str): host name
Returns:
tuple[dict, dict]: image io settings for global and host
"""
# get image io from global and host_name
imageio_global = project_settings["global"]["imageio"]
imageio_host = project_settings[host_name]["imageio"]
return imageio_global, imageio_host

View file

@ -19,6 +19,7 @@ from .publish_plugins import (
RepairContextAction,
Extractor,
ExtractorColormanaged,
)
from .lib import (
@ -63,6 +64,7 @@ __all__ = (
"RepairContextAction",
"Extractor",
"ExtractorColormanaged",
"get_publish_template_name",

View file

@ -1,6 +1,6 @@
import inspect
from abc import ABCMeta
from pprint import pformat
import pyblish.api
from pyblish.plugin import MetaPlugin, ExplicitMetaPlugin
@ -13,6 +13,12 @@ from .lib import (
get_instance_staging_dir,
)
from openpype.pipeline.colorspace import (
get_imageio_colorspace_from_filepath,
get_imageio_config,
get_imageio_file_rules
)
class AbstractMetaInstancePlugin(ABCMeta, MetaPlugin):
pass
@ -250,12 +256,12 @@ class RepairContextAction(pyblish.api.Action):
if not hasattr(plugin, "repair"):
raise RuntimeError("Plug-in does not have repair method.")
# Get the errored instances
# Get the failed instances
self.log.info("Finding failed instances..")
errored_plugins = get_errored_plugins_from_context(context)
failed_plugins = get_errored_plugins_from_context(context)
# Apply pyblish.logic to get the instances for the plug-in
if plugin in errored_plugins:
if plugin in failed_plugins:
self.log.info("Attempting fix ...")
plugin.repair(context)
@ -280,3 +286,143 @@ class Extractor(pyblish.api.InstancePlugin):
"""
return get_instance_staging_dir(instance)
class ExtractorColormanaged(Extractor):
"""Extractor base for color managed image data.
Each Extractor intended to export pixel data representation
should inherit from this class to allow color managed data.
Class implements "get_colorspace_settings" and
"set_representation_colorspace" functions used
for injecting colorspace data to representation data for farther
integration into db document.
"""
allowed_ext = [
"cin", "dpx", "avi", "dv", "gif", "flv", "mkv", "mov", "mpg", "mpeg",
"mp4", "m4v", "mxf", "iff", "z", "ifl", "jpeg", "jpg", "jfif", "lut",
"1dl", "exr", "pic", "png", "ppm", "pnm", "pgm", "pbm", "rla", "rpf",
"sgi", "rgba", "rgb", "bw", "tga", "tiff", "tif", "img"
]
@staticmethod
def get_colorspace_settings(context):
"""Retuns solved settings for the host context.
Args:
context (publish.Context): publishing context
Returns:
tuple | bool: config, file rules or None
"""
if "imageioSettings" in context.data:
return context.data["imageioSettings"]
project_name = context.data["projectName"]
host_name = context.data["hostName"]
anatomy_data = context.data["anatomyData"]
project_settings_ = context.data["project_settings"]
config_data = get_imageio_config(
project_name, host_name,
project_settings=project_settings_,
anatomy_data=anatomy_data
)
file_rules = get_imageio_file_rules(
project_name, host_name,
project_settings=project_settings_
)
# caching settings for future instance processing
context.data["imageioSettings"] = (config_data, file_rules)
return config_data, file_rules
def set_representation_colorspace(
self, representation, context,
colorspace=None,
colorspace_settings=None
):
"""Sets colorspace data to representation.
Args:
representation (dict): publishing representation
context (publish.Context): publishing context
config_data (dict): host resolved config data
file_rules (dict): host resolved file rules data
colorspace (str, optional): colorspace name. Defaults to None.
colorspace_settings (tuple[dict, dict], optional):
Settings for config_data and file_rules.
Defaults to None.
Example:
```
{
# for other publish plugins and loaders
"colorspace": "linear",
"config": {
# for future references in case need
"path": "/abs/path/to/config.ocio",
# for other plugins within remote publish cases
"template": "{project[root]}/path/to/config.ocio"
}
}
```
"""
if colorspace_settings is None:
colorspace_settings = self.get_colorspace_settings(context)
# unpack colorspace settings
config_data, file_rules = colorspace_settings
if not config_data:
# warn in case no colorspace path was defined
self.log.warning("No colorspace management was defined")
return
self.log.info("Config data is : `{}`".format(
config_data))
ext = representation["ext"]
# check extension
self.log.debug("__ ext: `{}`".format(ext))
if ext.lower() not in self.allowed_ext:
return
project_name = context.data["projectName"]
host_name = context.data["hostName"]
project_settings = context.data["project_settings"]
# get one filename
filename = representation["files"]
if isinstance(filename, list):
filename = filename[0]
self.log.debug("__ filename: `{}`".format(
filename))
# get matching colorspace from rules
colorspace = colorspace or get_imageio_colorspace_from_filepath(
filename, host_name, project_name,
config_data=config_data,
file_rules=file_rules,
project_settings=project_settings
)
self.log.debug("__ colorspace: `{}`".format(
colorspace))
# infuse data to representation
if colorspace:
colorspace_data = {
"colorspace": colorspace,
"config": config_data
}
# update data key
representation["colorspaceData"] = colorspace_data
self.log.debug("__ colorspace_data: `{}`".format(
pformat(colorspace_data)))

View file

@ -0,0 +1,47 @@
import pyblish.api
from openpype.pipeline import publish
class ExtractColorspaceData(publish.ExtractorColormanaged):
""" Inject Colorspace data to available representations.
Input data:
- context.data[colorspace_config_path]:
for anatomy formatting of possible template tokens in config path
- context.data[colorspace_config_path]:
for resolving project and host related config.ocio
- context.data[colorspace_file_rules]:
for resolving matched file rule from representation file name
and adding it to representation
Output data:
representation[colorspaceData] = {
"colorspace": "linear",
"config": {
"path": "/abs/path/to/config.ocio",
"template": "{project[root]}/path/to/config.ocio"
}
}
"""
label = "Extract Colorspace data"
order = pyblish.api.ExtractorOrder + 0.49
def process(self, instance):
representations = instance.data.get("representations")
if not representations:
self.log.info("No representations at instance : `{}`".format(
instance))
return
# get colorspace settings
context = instance.context
# loop representations
for representation in representations:
# skip if colorspaceData is already at representation
if representation.get("colorspaceData"):
continue
self.set_representation_colorspace(
representation, context
)

View file

@ -534,6 +534,15 @@ class IntegrateAsset(pyblish.api.InstancePlugin):
template_data["representation"] = repre["name"]
template_data["ext"] = repre["ext"]
# add template data for colorspaceData
if repre.get("colorspaceData"):
colorspace = repre["colorspaceData"]["colorspace"]
# replace spaces with underscores
# pipeline.colorspace.parse_colorspace_from_filepath
# is checking it with underscores too
colorspace = colorspace.replace(" ", "_")
template_data["colorspace"] = colorspace
stagingdir = repre.get("stagingDir")
if not stagingdir:
# Fall back to instance staging dir if not explicitly
@ -750,6 +759,11 @@ class IntegrateAsset(pyblish.api.InstancePlugin):
# and the actual representation entity for the database
data = repre.get("data", {})
data.update({"path": published_path, "template": template})
# add colorspace data if any exists on representation
if repre.get("colorspaceData"):
data["colorspaceData"] = repre["colorspaceData"]
repre_doc = new_representation_doc(
repre["name"], version["_id"], repre_context, data, repre_id
)

View file

@ -0,0 +1,168 @@
"""OpenColorIO Wrapper.
Only to be interpreted by Python 3. It is run in subprocess in case
Python 2 hosts needs to use it. Or it is used as module for Python 3
processing.
Providing functionality:
- get_colorspace - console command - python 2
- returning all available color spaces
found in input config path.
- _get_colorspace_data - python 3 - module function
- returning all available colorspaces
found in input config path.
- get_views - console command - python 2
- returning all available viewers
found in input config path.
- _get_views_data - python 3 - module function
- returning all available viewers
found in input config path.
"""
import click
import json
from pathlib2 import Path
import PyOpenColorIO as ocio
@click.group()
def main():
pass
@main.group()
def config():
"""Config related commands group
Example of use:
> pyton.exe ./ocio_wrapper.py config <command> *args
"""
pass
@config.command(
name="get_colorspace",
help=(
"return all colorspaces from config file "
"--path input arg is required"
)
)
@click.option("--in_path", required=True,
help="path where to read ocio config file",
type=click.Path(exists=True))
@click.option("--out_path", required=True,
help="path where to write output json file",
type=click.Path())
def get_colorspace(in_path, out_path):
"""Aggregate all colorspace to file.
Python 2 wrapped console command
Args:
in_path (str): config file path string
out_path (str): temp json file path string
Example of use:
> pyton.exe ./ocio_wrapper.py config get_colorspace
--in_path=<path> --out_path=<path>
"""
json_path = Path(out_path)
out_data = _get_colorspace_data(in_path)
with open(json_path, "w") as f:
json.dump(out_data, f)
print(f"Colorspace data are saved to '{json_path}'")
def _get_colorspace_data(config_path):
"""Return all found colorspace data.
Args:
config_path (str): path string leading to config.ocio
Raises:
IOError: Input config does not exist.
Returns:
dict: aggregated available colorspaces
"""
config_path = Path(config_path)
if not config_path.is_file():
raise IOError(
f"Input path `{config_path}` should be `config.ocio` file")
config = ocio.Config().CreateFromFile(str(config_path))
return {
c.getName(): c.getFamily()
for c in config.getColorSpaces()
}
@config.command(
name="get_views",
help=(
"return all viewers from config file "
"--path input arg is required"
)
)
@click.option("--in_path", required=True,
help="path where to read ocio config file",
type=click.Path(exists=True))
@click.option("--out_path", required=True,
help="path where to write output json file",
type=click.Path())
def get_views(in_path, out_path):
"""Aggregate all viewers to file.
Python 2 wrapped console command
Args:
in_path (str): config file path string
out_path (str): temp json file path string
Example of use:
> pyton.exe ./ocio_wrapper.py config get_views \
--in_path=<path> --out_path=<path>
"""
json_path = Path(out_path)
out_data = _get_views_data(in_path)
with open(json_path, "w") as f:
json.dump(out_data, f)
print(f"Viewer data are saved to '{json_path}'")
def _get_views_data(config_path):
"""Return all found viewer data.
Args:
config_path (str): path string leading to config.ocio
Raises:
IOError: Input config does not exist.
Returns:
dict: aggregated available viewers
"""
config_path = Path(config_path)
if not config_path.is_file():
raise IOError("Input path should be `config.ocio` file")
config = ocio.Config().CreateFromFile(str(config_path))
return {
f"{d}/{v}": {"display": d, "view": v}
for d in config.getDisplays()
for v in config.getViews(d)
}
if __name__ == '__main__':
main()

View file

@ -19,8 +19,7 @@
"blender/2-91",
"harmony/20",
"photoshop/2021",
"aftereffects/2021",
"unreal/4-26"
"aftereffects/2021"
],
"tools_env": [],
"active": true

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"create": {
"RenderCreator": {
"defaults": [

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"workfile_builder": {
"create_first_version": false,
"custom_templates": []

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"publish": {
"CollectRenderPath": {
"output_extension": "png",

View file

@ -1,5 +1,13 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
},
"project": {
"colourPolicy": "ACES 1.1",
"frameDepth": "16-bit fp",

View file

@ -1,5 +1,13 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
},
"ocio": {
"enabled": false,
"configFilePath": {

View file

@ -1,4 +1,22 @@
{
"imageio": {
"ocio_config": {
"filepath": [
"{OPENPYPE_ROOT}/vendor/bin/ocioconfig/OpenColorIOConfigs/aces_1.2/config.ocio",
"{OPENPYPE_ROOT}/vendor/bin/ocioconfig/OpenColorIOConfigs/nuke-default/config.ocio"
]
},
"file_rules": {
"enabled": false,
"rules": {
"example": {
"pattern": ".*(beauty).*",
"colorspace": "ACES - ACEScg",
"ext": "exr"
}
}
}
},
"publish": {
"CollectAnatomyInstanceData": {
"follow_workfile_version": false
@ -422,7 +440,9 @@
"template": "{family}{Task}"
},
{
"families": ["render"],
"families": [
"render"
],
"hosts": [
"aftereffects"
],

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"load": {
"ImageSequenceLoader": {
"family": [

View file

@ -1,5 +1,13 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
},
"workfile": {
"ocioConfigName": "nuke-default",
"ocioconfigpath": {

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"shelves": [],
"create": {
"CreateArnoldAss": {

View file

@ -1,5 +1,13 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
},
"colorManagementPreference_v2": {
"enabled": true,
"configFilePath": {
@ -158,24 +166,6 @@
"Main"
]
},
"CreateMultiverseUsd": {
"enabled": true,
"defaults": [
"Main"
]
},
"CreateMultiverseUsdComp": {
"enabled": true,
"defaults": [
"Main"
]
},
"CreateMultiverseUsdOver": {
"enabled": true,
"defaults": [
"Main"
]
},
"CreateAss": {
"enabled": true,
"defaults": [
@ -196,6 +186,24 @@
"maskColor_manager": false,
"maskOperator": false
},
"CreateMultiverseUsd": {
"enabled": true,
"defaults": [
"Main"
]
},
"CreateMultiverseUsdComp": {
"enabled": true,
"defaults": [
"Main"
]
},
"CreateMultiverseUsdOver": {
"enabled": true,
"defaults": [
"Main"
]
},
"CreateAssembly": {
"enabled": true,
"defaults": [
@ -1040,4 +1048,4 @@
"ValidateNoAnimation": false
}
}
}
}

View file

@ -9,7 +9,14 @@
}
},
"imageio": {
"enabled": false,
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
},
"viewer": {
"viewerProcess": "sRGB"
},

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"create": {
"CreateImage": {
"defaults": [

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"create": {
"CreateShotClip": {
"hierarchy": "{folder}/{sequence}",

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"simple_creators": [
{
"family": "workfile",

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"stop_timer_on_application_exit": false,
"publish": {
"CollectRenderScene": {

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"level_sequences_for_layouts": false,
"delete_unmatched_assets": false,
"project_setup": {

View file

@ -1,4 +1,14 @@
{
"imageio": {
"ocio_config": {
"enabled": false,
"filepath": []
},
"file_rules": {
"enabled": false,
"rules": {}
}
},
"timeout_profiles": [
{
"hosts": [

View file

@ -5,6 +5,23 @@
"label": "AfterEffects",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -5,6 +5,23 @@
"label": "Blender",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "schema_template",
"name": "template_workfile_options",

View file

@ -5,6 +5,23 @@
"label": "CelAction",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -11,6 +11,14 @@
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
},
{
"key": "project",
"type": "dict",

View file

@ -11,6 +11,14 @@
"label": "Color Management (ImageIO)",
"collapsible": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
},
{
"key": "ocio",
"type": "dict",
@ -23,6 +31,10 @@
"key": "enabled",
"label": "Set OCIO variable for Fusion"
},
{
"type": "label",
"label": "<b style='color:red'>'configFilePath'</b> will be deprecated. <br>Please move values to : <i>project_settings/{app}/imageio/ocio_config/filepath</i>."
},
{
"type": "path",
"key": "configFilePath",

View file

@ -5,6 +5,34 @@
"label": "Global",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"key": "ocio_config",
"type": "dict",
"label": "OCIO config",
"collapsible": true,
"children": [
{
"type": "path",
"key": "filepath",
"label": "Config path",
"multiplatform": false,
"multipath": true
}
]
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "schema",
"name": "schema_global_publish"

View file

@ -5,6 +5,23 @@
"label": "Harmony",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -5,116 +5,128 @@
"label": "Hiero",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"collapsible": true,
"children": [
{
"key": "workfile",
"type": "dict",
"label": "Workfile",
"collapsible": false,
"children": [
{
"type": "form",
"children": [
{
"type": "enum",
"key": "ocioConfigName",
"label": "OpenColorIO Config",
"enum_items": [
{
"nuke-default": "nuke-default"
},
{
"aces_1.0.3": "aces_1.0.3"
},
{
"aces_1.1": "aces_1.1"
},
{
"custom": "custom"
}
]
},
{
"type": "path",
"key": "ocioconfigpath",
"label": "Custom OCIO path",
"multiplatform": true,
"multipath": true
},
{
"type": "text",
"key": "workingSpace",
"label": "Working Space"
},
{
"type": "text",
"key": "sixteenBitLut",
"label": "16 Bit Files"
},
{
"type": "text",
"key": "eightBitLut",
"label": "8 Bit Files"
},
{
"type": "text",
"key": "floatLut",
"label": "Floating Point Files"
},
{
"type": "text",
"key": "logLut",
"label": "Log Files"
},
{
"type": "text",
"key": "viewerLut",
"label": "Viewer"
},
{
"type": "text",
"key": "thumbnailLut",
"label": "Thumbnails"
}
]
}
]
},
{
"key": "regexInputs",
"type": "dict",
"label": "Colorspace on Inputs by regex detection",
"collapsible": true,
"children": [
{
"type": "list",
"key": "inputs",
"object_type": {
"type": "dict",
"children": [
{
"type": "text",
"key": "regex",
"label": "Regex"
},
{
"type": "text",
"key": "colorspace",
"label": "Colorspace"
}
]
}
}
]
}
]
},
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"collapsible": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
},
{
"key": "workfile",
"type": "dict",
"label": "Workfile",
"collapsible": false,
"children": [
{
"type": "label",
"label": "<b style='color:red'>'ocioconfigpath'</b> will be deprecated. <br>Please move values to : <i>project_settings/{app}/imageio/ocio_config/filepath</i>."
},
{
"type": "form",
"children": [
{
"type": "enum",
"key": "ocioConfigName",
"label": "OpenColorIO Config",
"enum_items": [
{
"nuke-default": "nuke-default"
},
{
"aces_1.0.3": "aces_1.0.3"
},
{
"aces_1.1": "aces_1.1"
},
{
"custom": "custom"
}
]
},
{
"type": "path",
"key": "ocioconfigpath",
"label": "Custom OCIO path",
"multiplatform": true,
"multipath": true
},
{
"type": "text",
"key": "workingSpace",
"label": "Working Space"
},
{
"type": "text",
"key": "sixteenBitLut",
"label": "16 Bit Files"
},
{
"type": "text",
"key": "eightBitLut",
"label": "8 Bit Files"
},
{
"type": "text",
"key": "floatLut",
"label": "Floating Point Files"
},
{
"type": "text",
"key": "logLut",
"label": "Log Files"
},
{
"type": "text",
"key": "viewerLut",
"label": "Viewer"
},
{
"type": "text",
"key": "thumbnailLut",
"label": "Thumbnails"
}
]
}
]
},
{
"key": "regexInputs",
"type": "dict",
"label": "Colorspace on Inputs by regex detection",
"collapsible": true,
"children": [
{
"type": "list",
"key": "inputs",
"object_type": {
"type": "dict",
"children": [
{
"type": "text",
"key": "regex",
"label": "Regex"
},
{
"type": "text",
"key": "colorspace",
"label": "Colorspace"
}
]
}
}
]
}
]
},
{
"type": "dict",
"collapsible": true,
@ -129,102 +141,102 @@
"is_group": true,
"children": [
{
"type": "collapsible-wrap",
"label": "Shot Hierarchy And Rename Settings",
"collapsible": false,
"children": [
{
"type": "text",
"key": "hierarchy",
"label": "Shot parent hierarchy"
},
{
"type": "boolean",
"key": "clipRename",
"label": "Rename clips"
},
{
"type": "text",
"key": "clipName",
"label": "Clip name template"
},
{
"type": "number",
"key": "countFrom",
"label": "Count sequence from"
},
{
"type": "number",
"key": "countSteps",
"label": "Stepping number"
}
]
"type": "collapsible-wrap",
"label": "Shot Hierarchy And Rename Settings",
"collapsible": false,
"children": [
{
"type": "text",
"key": "hierarchy",
"label": "Shot parent hierarchy"
},
{
"type": "boolean",
"key": "clipRename",
"label": "Rename clips"
},
{
"type": "text",
"key": "clipName",
"label": "Clip name template"
},
{
"type": "number",
"key": "countFrom",
"label": "Count sequence from"
},
{
"type": "number",
"key": "countSteps",
"label": "Stepping number"
}
]
},
{
"type": "collapsible-wrap",
"label": "Shot Template Keywords",
"collapsible": false,
"children": [
{
"type": "text",
"key": "folder",
"label": "{folder}"
},
{
"type": "text",
"key": "episode",
"label": "{episode}"
},
{
"type": "text",
"key": "sequence",
"label": "{sequence}"
},
{
"type": "text",
"key": "track",
"label": "{track}"
},
{
"type": "text",
"key": "shot",
"label": "{shot}"
}
]
"type": "collapsible-wrap",
"label": "Shot Template Keywords",
"collapsible": false,
"children": [
{
"type": "text",
"key": "folder",
"label": "{folder}"
},
{
"type": "text",
"key": "episode",
"label": "{episode}"
},
{
"type": "text",
"key": "sequence",
"label": "{sequence}"
},
{
"type": "text",
"key": "track",
"label": "{track}"
},
{
"type": "text",
"key": "shot",
"label": "{shot}"
}
]
},
{
"type": "collapsible-wrap",
"label": "Vertical Synchronization Of Attributes",
"collapsible": false,
"children": [
{
"type": "boolean",
"key": "vSyncOn",
"label": "Enable Vertical Sync"
}
]
"type": "collapsible-wrap",
"label": "Vertical Synchronization Of Attributes",
"collapsible": false,
"children": [
{
"type": "boolean",
"key": "vSyncOn",
"label": "Enable Vertical Sync"
}
]
},
{
"type": "collapsible-wrap",
"label": "Shot Attributes",
"collapsible": false,
"children": [
{
"type": "number",
"key": "workfileFrameStart",
"label": "Workfiles Start Frame"
},
{
"type": "number",
"key": "handleStart",
"label": "Handle start (head)"
},
{
"type": "number",
"key": "handleEnd",
"label": "Handle end (tail)"
}
]
"type": "collapsible-wrap",
"label": "Shot Attributes",
"collapsible": false,
"children": [
{
"type": "number",
"key": "workfileFrameStart",
"label": "Workfiles Start Frame"
},
{
"type": "number",
"key": "handleStart",
"label": "Handle start (head)"
},
{
"type": "number",
"key": "handleEnd",
"label": "Handle end (tail)"
}
]
}
]
}
@ -322,4 +334,4 @@
"name": "schema_scriptsmenu"
}
]
}
}

View file

@ -5,6 +5,23 @@
"label": "Houdini",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "schema",
"name": "schema_houdini_scriptshelf"

View file

@ -12,6 +12,14 @@
"collapsible": true,
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
},
{
"key": "colorManagementPreference_v2",
"type": "dict",
@ -24,6 +32,10 @@
"key": "enabled",
"label": "Use Color Management Preference v2"
},
{
"type": "label",
"label": "<b style='color:red'>'configFilePath'</b> will be deprecated. <br>Please move values to : <i>project_settings/{app}/imageio/ocio_config/filepath</i>."
},
{
"type": "path",
"key": "configFilePath",
@ -54,6 +66,10 @@
"label": "Color Management Preference (legacy)",
"collapsible": true,
"children": [
{
"type": "label",
"label": "<b style='color:red'>'configFilePath'</b> will be deprecated. <br>Please move values to : <i>project_settings/{app}/imageio/ocio_config/filepath</i>."
},
{
"type": "path",
"key": "configFilePath",

View file

@ -5,6 +5,23 @@
"label": "Photoshop",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -5,6 +5,23 @@
"label": "DaVinci Resolve",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -5,6 +5,23 @@
"label": "Tray Publisher",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "list",
"collapsible": true,

View file

@ -5,6 +5,23 @@
"label": "TVPaint",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "boolean",
"key": "stop_timer_on_application_exit",

View file

@ -5,6 +5,23 @@
"label": "Unreal Engine",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "boolean",
"key": "level_sequences_for_layouts",

View file

@ -5,6 +5,23 @@
"label": "Web Publisher",
"is_file": true,
"children": [
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
},
{
"type": "list",
"collapsible": true,

View file

@ -0,0 +1,21 @@
{
"key": "ocio_config",
"type": "dict",
"label": "OCIO config",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "path",
"key": "filepath",
"label": "Config path",
"multiplatform": false,
"multipath": true
}
]
}

View file

@ -0,0 +1,41 @@
{
"key": "file_rules",
"type": "dict",
"label": "File Rules",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"key": "rules",
"label": "Rules",
"type": "dict-modifiable",
"highlight_content": true,
"collapsible": false,
"object_type": {
"type": "dict",
"children": [
{
"key": "pattern",
"label": "Regex pattern",
"type": "text"
},
{
"key": "colorspace",
"label": "Colorspace name",
"type": "text"
},
{
"key": "ext",
"label": "File extension",
"type": "text"
}
]
}
}
]
}

View file

@ -2,14 +2,20 @@
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"checkbox_key": "enabled",
"collapsible": true,
"is_group": true,
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
"type": "label",
"label": "<b style='color:red'>'Custom OCIO config path'</b> has deprecated. <br> If you need to set custom config, just enable and add path into 'OCIO config'. <br>Anatomy keys are supported.</i>."
},
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
},
{
"key": "viewer",

235
poetry.lock generated
View file

@ -3,10 +3,10 @@
[[package]]
name = "acre"
version = "1.0.0"
description = ""
description = "Lightweight cross-platform environment management Python package that makes it trivial to launch applications in their own configurable working environment."
category = "main"
optional = false
python-versions = "*"
python-versions = ">=2.7"
files = []
develop = false
@ -174,14 +174,14 @@ frozenlist = ">=1.1.0"
[[package]]
name = "alabaster"
version = "0.7.12"
version = "0.7.13"
description = "A configurable sidebar-enabled Sphinx theme"
category = "dev"
optional = false
python-versions = "*"
python-versions = ">=3.6"
files = [
{file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
{file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
{file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"},
{file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"},
]
[[package]]
@ -567,63 +567,63 @@ files = [
[[package]]
name = "coverage"
version = "7.0.4"
version = "7.0.5"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "coverage-7.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:daf91db39324e9939a9db919ee4fb42a1a23634a056616dae891a030e89f87ba"},
{file = "coverage-7.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:55121fe140d7e42cb970999b93cf1c2b24484ce028b32bbd00238bb25c13e34a"},
{file = "coverage-7.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c027fbb83a8c78a6e06a0302ea1799fdb70e5cda9845a5e000545b8e2b47ea39"},
{file = "coverage-7.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf82db5b7f16b51ec32fe0bd2da0805b177c807aa8bfb478c7e6f893418c284"},
{file = "coverage-7.0.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ba5cc54baf3c322c4388de2a43cc95f7809366f0600e743e5aae8ea9d1038b2"},
{file = "coverage-7.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:260854160083f8275a9d9d49a05ab0ffc7a1f08f2ccccbfaec94a18aae9f407c"},
{file = "coverage-7.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ea45f0dba5a993e93b158f1a9dcfff2770e3bcabf2b80dbe7aa15dce0bcb3bf3"},
{file = "coverage-7.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6abc91f6f8b3cc0ae1034e2c03f38769fba1952ab70d0b26953aa01691265c39"},
{file = "coverage-7.0.4-cp310-cp310-win32.whl", hash = "sha256:053cdc47cae08257051d7e934a0de4d095b60eb8a3024fa9f1b2322fa1547137"},
{file = "coverage-7.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:1e9e94f2612ee549a4b3ee79cbc61bceed77e69cf38cfa05858bae939a886d16"},
{file = "coverage-7.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5caa9dd91dcc5f054350dc57a02e053d79633907b9ccffff999568d13dcd19f8"},
{file = "coverage-7.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:efc200fa75d9634525b40babc7a16342bd21c101db1a58ef84dc14f4bf6ac0fd"},
{file = "coverage-7.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1791e5f74c5b52f76e83fe9f4bb9571cf76d40ee0c51952ee1e4ee935b7e98b9"},
{file = "coverage-7.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d9201cfa5a98652b9cef36ab202f17fe3ea83f497b4ba2a8ed39399dfb8fcd4"},
{file = "coverage-7.0.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22d8ef6865cb6834cab2b72fff20747a55c714b57b675f7e11c9624fe4f7cb45"},
{file = "coverage-7.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b84076e3de192fba0f95e279ac017b64c7c6ecd4f09f36f13420f5bed898a9c7"},
{file = "coverage-7.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:dcfbf8ffc046f20d75fd775a92c378f6fc7b9bded6c6f2ab88b6b9cb5805a184"},
{file = "coverage-7.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4665a714af31f160403c2e448fb2fef330719d2e04e836b08d60d612707c1041"},
{file = "coverage-7.0.4-cp311-cp311-win32.whl", hash = "sha256:2e59aef3fba5758059208c9eff10ae7ded3629e797972746ec33b56844f69411"},
{file = "coverage-7.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:2b854f7985b48122b6fe346631e86d67b63293f8255cb59a93d79e3d9f1574e3"},
{file = "coverage-7.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e44b60b0b49aa85d548d392a2dca2c6a581cd4084e72e9e16bd58bd86ec20816"},
{file = "coverage-7.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2904d7a0388911c61e7e3beefe48c29dfccaba938fc1158f63190101a21e04c2"},
{file = "coverage-7.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc74b64bfa89e2f862ea45dd6ac1def371d7cc883b76680d20bdd61a6f3daa20"},
{file = "coverage-7.0.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c06046f54e719da21c79f98ecc0962581d1aee0b3798dc6b12b1217da8bf93f4"},
{file = "coverage-7.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:bc9c77004970a364a1e5454cf7cb884e4277592b959c287689b2a0fd027ef552"},
{file = "coverage-7.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:0815a09b32384e8ff00a5939ec9cd10efce8742347e019c2daca1a32f5ac2aae"},
{file = "coverage-7.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a78a80d131c067d67d8a6f9bd3d3f7ea7eac82c1c7259f97d7ab73f723da9d55"},
{file = "coverage-7.0.4-cp37-cp37m-win32.whl", hash = "sha256:2b5936b624fbe711ed02dfd86edd678822e5ee68da02b6d231e5c01090b64590"},
{file = "coverage-7.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:a63922765ee49d5b4c32afb2cd5516812c8665f3b78e64a0dd005bdfabf991b1"},
{file = "coverage-7.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d68f2f7bddb3acdd3b36ef7f334b9d14f30b93e094f808fbbd8d288b8f9e2f9b"},
{file = "coverage-7.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9dafdba3b2b9010abab08cb8c0dc6549bfca6e1630fe14d47b01dca00d39e694"},
{file = "coverage-7.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0322354757b47640535daabd2d56384ff3cad2896248fc84d328c5fad4922d5c"},
{file = "coverage-7.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e8267466662aff93d66fa72b9591d02122dfc8a729b0a43dd70e0fb07ed9b37"},
{file = "coverage-7.0.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f684d88eb4924ed0630cf488fd5606e334c6835594bb5fe36b50a509b10383ed"},
{file = "coverage-7.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:70c294bb15ba576fb96b580db35895bf03749d683df044212b74e938a7f6821f"},
{file = "coverage-7.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:34c0457e1ba450ae8b22dc8ea2fd36ada1010af61291e4c96963cd9d9633366f"},
{file = "coverage-7.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b75aff2c35ceaa299691e772f7bf7c8aeab25f46acea2be3dd04cccb914a9860"},
{file = "coverage-7.0.4-cp38-cp38-win32.whl", hash = "sha256:6c5554d55668381e131577f20e8f620d4882b04ad558f7e7f3f1f55b3124c379"},
{file = "coverage-7.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c82f34fafaf5bc05d222fcf84423d6e156432ca35ca78672d4affd0c09c6ef6c"},
{file = "coverage-7.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8dfb5fed540f77e814bf4ec79619c241af6b4578fa1093c5e3389bbb7beab3f"},
{file = "coverage-7.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee32a080bab779b71c4d09a3eb5254bfca43ee88828a683dab27dfe8f582516e"},
{file = "coverage-7.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dfbee0bf0d633be3a2ab068f5a5731a70adf147d0ba17d9f9932b46c7c5782b"},
{file = "coverage-7.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32dc010713455ac0fe2fddb0e48aa43875cc7eb7b09768df10bad8ce45f9c430"},
{file = "coverage-7.0.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cb88a3019ad042eaa69fc7639ef077793fedbf313e89207aa82fefe92c97ebd"},
{file = "coverage-7.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:73bc6114aab7753ca784f87bcd3b7613bc797aa255b5bca45e5654070ae9acfb"},
{file = "coverage-7.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:92f135d370fcd7a6fb9659fa2eb716dd2ca364719cbb1756f74d90a221bca1a7"},
{file = "coverage-7.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f3d485e6ec6e09857bf2115ece572d666b7c498377d4c70e66bb06c63ed177c2"},
{file = "coverage-7.0.4-cp39-cp39-win32.whl", hash = "sha256:c58921fcd9914b56444292e7546fe183d079db99528142c809549ddeaeacd8e9"},
{file = "coverage-7.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:f092d9f2ddaa30235d33335fbdb61eb8f3657af519ef5f9dd6bdae65272def11"},
{file = "coverage-7.0.4-pp37.pp38.pp39-none-any.whl", hash = "sha256:cb8cfa3bf3a9f18211279458917fef5edeb5e1fdebe2ea8b11969ec2ebe48884"},
{file = "coverage-7.0.4.tar.gz", hash = "sha256:f6c4ad409a0caf7e2e12e203348b1a9b19c514e7d078520973147bf2d3dcbc6f"},
{file = "coverage-7.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a7f23bbaeb2a87f90f607730b45564076d870f1fb07b9318d0c21f36871932b"},
{file = "coverage-7.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c18d47f314b950dbf24a41787ced1474e01ca816011925976d90a88b27c22b89"},
{file = "coverage-7.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef14d75d86f104f03dea66c13188487151760ef25dd6b2dbd541885185f05f40"},
{file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66e50680e888840c0995f2ad766e726ce71ca682e3c5f4eee82272c7671d38a2"},
{file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9fed35ca8c6e946e877893bbac022e8563b94404a605af1d1e6accc7eb73289"},
{file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d8d04e755934195bdc1db45ba9e040b8d20d046d04d6d77e71b3b34a8cc002d0"},
{file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e109f1c9a3ece676597831874126555997c48f62bddbcace6ed17be3e372de8"},
{file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0a1890fca2962c4f1ad16551d660b46ea77291fba2cc21c024cd527b9d9c8809"},
{file = "coverage-7.0.5-cp310-cp310-win32.whl", hash = "sha256:be9fcf32c010da0ba40bf4ee01889d6c737658f4ddff160bd7eb9cac8f094b21"},
{file = "coverage-7.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:cbfcba14a3225b055a28b3199c3d81cd0ab37d2353ffd7f6fd64844cebab31ad"},
{file = "coverage-7.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:30b5fec1d34cc932c1bc04017b538ce16bf84e239378b8f75220478645d11fca"},
{file = "coverage-7.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1caed2367b32cc80a2b7f58a9f46658218a19c6cfe5bc234021966dc3daa01f0"},
{file = "coverage-7.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d254666d29540a72d17cc0175746cfb03d5123db33e67d1020e42dae611dc196"},
{file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19245c249aa711d954623d94f23cc94c0fd65865661f20b7781210cb97c471c0"},
{file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b05ed4b35bf6ee790832f68932baf1f00caa32283d66cc4d455c9e9d115aafc"},
{file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:29de916ba1099ba2aab76aca101580006adfac5646de9b7c010a0f13867cba45"},
{file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e057e74e53db78122a3979f908973e171909a58ac20df05c33998d52e6d35757"},
{file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:411d4ff9d041be08fdfc02adf62e89c735b9468f6d8f6427f8a14b6bb0a85095"},
{file = "coverage-7.0.5-cp311-cp311-win32.whl", hash = "sha256:52ab14b9e09ce052237dfe12d6892dd39b0401690856bcfe75d5baba4bfe2831"},
{file = "coverage-7.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:1f66862d3a41674ebd8d1a7b6f5387fe5ce353f8719040a986551a545d7d83ea"},
{file = "coverage-7.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b69522b168a6b64edf0c33ba53eac491c0a8f5cc94fa4337f9c6f4c8f2f5296c"},
{file = "coverage-7.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436e103950d05b7d7f55e39beeb4d5be298ca3e119e0589c0227e6d0b01ee8c7"},
{file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c56bec53d6e3154eaff6ea941226e7bd7cc0d99f9b3756c2520fc7a94e6d96"},
{file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a38362528a9115a4e276e65eeabf67dcfaf57698e17ae388599568a78dcb029"},
{file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f67472c09a0c7486e27f3275f617c964d25e35727af952869dd496b9b5b7f6a3"},
{file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:220e3fa77d14c8a507b2d951e463b57a1f7810a6443a26f9b7591ef39047b1b2"},
{file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ecb0f73954892f98611e183f50acdc9e21a4653f294dfbe079da73c6378a6f47"},
{file = "coverage-7.0.5-cp37-cp37m-win32.whl", hash = "sha256:d8f3e2e0a1d6777e58e834fd5a04657f66affa615dae61dd67c35d1568c38882"},
{file = "coverage-7.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9e662e6fc4f513b79da5d10a23edd2b87685815b337b1a30cd11307a6679148d"},
{file = "coverage-7.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:790e4433962c9f454e213b21b0fd4b42310ade9c077e8edcb5113db0818450cb"},
{file = "coverage-7.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49640bda9bda35b057b0e65b7c43ba706fa2335c9a9896652aebe0fa399e80e6"},
{file = "coverage-7.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d66187792bfe56f8c18ba986a0e4ae44856b1c645336bd2c776e3386da91e1dd"},
{file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:276f4cd0001cd83b00817c8db76730938b1ee40f4993b6a905f40a7278103b3a"},
{file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95304068686545aa368b35dfda1cdfbbdbe2f6fe43de4a2e9baa8ebd71be46e2"},
{file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:17e01dd8666c445025c29684d4aabf5a90dc6ef1ab25328aa52bedaa95b65ad7"},
{file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea76dbcad0b7b0deb265d8c36e0801abcddf6cc1395940a24e3595288b405ca0"},
{file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:50a6adc2be8edd7ee67d1abc3cd20678987c7b9d79cd265de55941e3d0d56499"},
{file = "coverage-7.0.5-cp38-cp38-win32.whl", hash = "sha256:e4ce984133b888cc3a46867c8b4372c7dee9cee300335e2925e197bcd45b9e16"},
{file = "coverage-7.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:4a950f83fd3f9bca23b77442f3a2b2ea4ac900944d8af9993743774c4fdc57af"},
{file = "coverage-7.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c2155943896ac78b9b0fd910fb381186d0c345911f5333ee46ac44c8f0e43ab"},
{file = "coverage-7.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54f7e9705e14b2c9f6abdeb127c390f679f6dbe64ba732788d3015f7f76ef637"},
{file = "coverage-7.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee30375b409d9a7ea0f30c50645d436b6f5dfee254edffd27e45a980ad2c7f4"},
{file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b78729038abea6a5df0d2708dce21e82073463b2d79d10884d7d591e0f385ded"},
{file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13250b1f0bd023e0c9f11838bdeb60214dd5b6aaf8e8d2f110c7e232a1bff83b"},
{file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c407b1950b2d2ffa091f4e225ca19a66a9bd81222f27c56bd12658fc5ca1209"},
{file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c76a3075e96b9c9ff00df8b5f7f560f5634dffd1658bafb79eb2682867e94f78"},
{file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f26648e1b3b03b6022b48a9b910d0ae209e2d51f50441db5dce5b530fad6d9b1"},
{file = "coverage-7.0.5-cp39-cp39-win32.whl", hash = "sha256:ba3027deb7abf02859aca49c865ece538aee56dcb4871b4cced23ba4d5088904"},
{file = "coverage-7.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:949844af60ee96a376aac1ded2a27e134b8c8d35cc006a52903fc06c24a3296f"},
{file = "coverage-7.0.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:b9727ac4f5cf2cbf87880a63870b5b9730a8ae3a4a360241a0fdaa2f71240ff0"},
{file = "coverage-7.0.5.tar.gz", hash = "sha256:051afcbd6d2ac39298d62d340f94dbb6a1f31de06dfaf6fcef7b759dd3860c45"},
]
[package.dependencies]
@ -812,22 +812,23 @@ files = [
[[package]]
name = "dnspython"
version = "2.2.1"
version = "2.3.0"
description = "DNS toolkit"
category = "main"
optional = false
python-versions = ">=3.6,<4.0"
python-versions = ">=3.7,<4.0"
files = [
{file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"},
{file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"},
{file = "dnspython-2.3.0-py3-none-any.whl", hash = "sha256:89141536394f909066cabd112e3e1a37e4e654db00a25308b0f130bc3152eb46"},
{file = "dnspython-2.3.0.tar.gz", hash = "sha256:224e32b03eb46be70e12ef6d64e0be123a64e621ab4c0822ff6d450d52a540b9"},
]
[package.extras]
curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"]
dnssec = ["cryptography (>=2.6,<37.0)"]
doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"]
dnssec = ["cryptography (>=2.6,<40.0)"]
doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.11.0)"]
doq = ["aioquic (>=0.9.20)"]
idna = ["idna (>=2.1,<4.0)"]
trio = ["trio (>=0.14,<0.20)"]
trio = ["trio (>=0.14,<0.23)"]
wmi = ["wmi (>=1.5.1,<2.0.0)"]
[[package]]
@ -1029,13 +1030,13 @@ websocket-client = ">=0.40.0,<1"
[[package]]
name = "future"
version = "0.18.2"
version = "0.18.3"
description = "Clean single-source support for Python 3 and 2"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
{file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"},
]
[[package]]
@ -1208,14 +1209,14 @@ pyparsing = {version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0
[[package]]
name = "identify"
version = "2.5.12"
version = "2.5.13"
description = "File identification library for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "identify-2.5.12-py2.py3-none-any.whl", hash = "sha256:e8a400c3062d980243d27ce10455a52832205649bbcaf27ffddb3dfaaf477bad"},
{file = "identify-2.5.12.tar.gz", hash = "sha256:0bc96b09c838310b6fcfcc61f78a981ea07f94836ef6ef553da5bb5d4745d662"},
{file = "identify-2.5.13-py2.py3-none-any.whl", hash = "sha256:8aa48ce56e38c28b6faa9f261075dea0a942dfbb42b341b4e711896cbb40f3f7"},
{file = "identify-2.5.13.tar.gz", hash = "sha256:abb546bca6f470228785338a01b539de8a85bbf46491250ae03363956d8ebb10"},
]
[package.extras]
@ -1690,6 +1691,41 @@ files = [
[package.dependencies]
setuptools = "*"
[[package]]
name = "opencolorio"
version = "2.2.1"
description = "OpenColorIO (OCIO) is a complete color management solution geared towards motion picture production with an emphasis on visual effects and computer animation."
category = "main"
optional = false
python-versions = "*"
files = [
{file = "opencolorio-2.2.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a9feec76e450325f12203264194d905a938d5e7944772b806886f9531e406d42"},
{file = "opencolorio-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7eeae01328b359408940a1f29d53b15b034755413d95d08781b76084ee14cbb1"},
{file = "opencolorio-2.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85b63a9162e99f0f29ef4074017d1b6e8caf59096043fb91cbacfc5bc01fa0b9"},
{file = "opencolorio-2.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67d19ea54daff2b209b91981da415aa41ea8e3a60fecd5dd843ae13272d38dcf"},
{file = "opencolorio-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:da0043a1007d269b5da3c8ca1de8c63926b38bf5e08cfade6cb8f2f5f6b663b9"},
{file = "opencolorio-2.2.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:62180cec075cae8dff56eeb977132eb9755d7fe312d8d34236cba838cb9314b3"},
{file = "opencolorio-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:24b7bfc4b77c04845de847373e58232c48838042d5e45e027b8bf64bada988e3"},
{file = "opencolorio-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41cadab13b18dbedd992df2056c787cf38bf89a5b0903b90f701d5228ac496f9"},
{file = "opencolorio-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa278dd4414791a5605e685b562b6ad1c729a4a44c1c906151f5bca10c0ff10e"},
{file = "opencolorio-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:7b44858c26b662ec42b089f8f85ea3aa63aa04e0e58e902a4cbf8cae0fbd4c6c"},
{file = "opencolorio-2.2.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:07fce0d36a6041b524b2122b9f55fbd03e029def5a22e93822041b652b60590a"},
{file = "opencolorio-2.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae043bc588d9ee98f54fe9524481eba5634d6dd70d0c70e1bd242b60a3a81731"},
{file = "opencolorio-2.2.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a4ad1a4ed5742a7dda41f0548274e8328b2774ce04dfc31fd5dfbacabc4c166"},
{file = "opencolorio-2.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bd885e34898c204db19a9e6926c551a74bda6d8e7d3ef27596630e3422b99b1"},
{file = "opencolorio-2.2.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:86ed205bec96fd84e882d431c181560df0cf6f0f73150976303b6f3ff1d9d5ed"},
{file = "opencolorio-2.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c1bf1c19baa86203e2329194ea837161520dae5c94e4f04b7659e9bfe4f1a6a9"},
{file = "opencolorio-2.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639f7052da7086d999c0d84e424453fb44abc8f2d22ec8601d20d8ee9d90384b"},
{file = "opencolorio-2.2.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7e3208c5c1ac63a6e921398db661fdd9309b17253b285f227818713f3faec92"},
{file = "opencolorio-2.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:68814600c0d8c07b552e1f1e4e32d45bffba4cb49b41481e5d4dd0bc56a206ea"},
{file = "opencolorio-2.2.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:cb5337ac2804dbb90c856b423d2799d3dc35f9c948da25d8e6506d1dd8200df7"},
{file = "opencolorio-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:425593a96de7927aa7cda065dc3729e881de1d0b72c43e704e02962adb63b4ad"},
{file = "opencolorio-2.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8be9f6af01e4c710de4cc03c9b6de04ef0844bf611e9100abf045ec62a4c685a"},
{file = "opencolorio-2.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84788002aa28151409f2367a040e9d39ffea0a9129777451bd0c55ac87d9d47"},
{file = "opencolorio-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:d92802922bc4e2ff3e9a06d44b6055efd1863abb1aaf0243849d35b077b72253"},
{file = "opencolorio-2.2.1.tar.gz", hash = "sha256:283abb8db5bc18ab9686e08255a9245deaba3d7837be5363b7a69b0902b73a78"},
]
[[package]]
name = "opentimelineio"
version = "0.14.1"
@ -1734,7 +1770,7 @@ view = ["PySide2 (>=5.11,<6.0)"]
name = "packaging"
version = "23.0"
description = "Core utilities for Python packages"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
@ -1784,18 +1820,18 @@ testing = ["docopt", "pytest (<6.0.0)"]
[[package]]
name = "patchelf"
version = "0.17.0.0"
version = "0.17.2.0"
description = "A small utility to modify the dynamic linker and RPATH of ELF executables."
category = "dev"
optional = false
python-versions = "*"
files = [
{file = "patchelf-0.17.0.0-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:bb675f65ad3d999763e7332a53ec98d5ae186fb057e15f781de0d108e2258f5d"},
{file = "patchelf-0.17.0.0-py2.py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:634e7b0c389251f2f8ae3f30a0cfb15873048113fcd22ae18ca354a96dc94368"},
{file = "patchelf-0.17.0.0-py2.py3-none-manylinux_2_17_s390x.manylinux2014_s390x.musllinux_1_1_s390x.whl", hash = "sha256:80008417d50f66a82747a1a851f100c0f2de5f0df7aec9eaca0b479ad10a3caa"},
{file = "patchelf-0.17.0.0-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.musllinux_1_1_i686.whl", hash = "sha256:f01e680cdfbbcdfd70dc95b23fe19f6c05b76a92961d04bf812ee188b8bd013a"},
{file = "patchelf-0.17.0.0-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:858447ad58f84818afce32ad870c559fa27c3fe102302e9906d376461055e599"},
{file = "patchelf-0.17.0.0.tar.gz", hash = "sha256:a90c0244593ad353513b098a3c46a5fd60a71c160b7acf86ed16f1b5cb98878b"},
{file = "patchelf-0.17.2.0-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:b8d86f32e1414d6964d5d166ddd2cf829d156fba0d28d32a3bd0192f987f4529"},
{file = "patchelf-0.17.2.0-py2.py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:9233a0f2fc73820c5bd468f27507bdf0c9ac543f07c7f9888bb7cf910b1be22f"},
{file = "patchelf-0.17.2.0-py2.py3-none-manylinux_2_17_s390x.manylinux2014_s390x.musllinux_1_1_s390x.whl", hash = "sha256:6601d7d831508bcdd3d8ebfa6435c2379bf11e41af2409ae7b88de572926841c"},
{file = "patchelf-0.17.2.0-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.musllinux_1_1_i686.whl", hash = "sha256:c62a34f0c25e6c2d6ae44389f819a00ccdf3f292ad1b814fbe1cc23cb27023ce"},
{file = "patchelf-0.17.2.0-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:1b9fd14f300341dc020ae05c49274dd1fa6727eabb4e61dd7fb6fb3600acd26e"},
{file = "patchelf-0.17.2.0.tar.gz", hash = "sha256:dedf987a83d7f6d6f5512269e57f5feeec36719bd59567173b6d9beabe019efe"},
]
[package.extras]
@ -1831,6 +1867,13 @@ files = [
{file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"},
{file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"},
{file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"},
{file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"},
{file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"},
{file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"},
{file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"},
{file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"},
{file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"},
{file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"},
{file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"},
{file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"},
{file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"},
@ -1965,14 +2008,14 @@ virtualenv = ">=20.10.0"
[[package]]
name = "prefixed"
version = "0.5.0"
version = "0.6.0"
description = "Prefixed alternative numeric library"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "prefixed-0.5.0-py2.py3-none-any.whl", hash = "sha256:debab03014863087eb013750a2e71daa5f6a295cee46b44ba1b90d7262c1b92d"},
{file = "prefixed-0.5.0.tar.gz", hash = "sha256:b134d734136250b17b68eede65a3370fab0134412cb66bc8be3568ff05bdf8e4"},
{file = "prefixed-0.6.0-py2.py3-none-any.whl", hash = "sha256:5ab094773dc71df68cc78151c81510b9521dcc6b58a4acb78442b127d4e400fa"},
{file = "prefixed-0.6.0.tar.gz", hash = "sha256:b39fbfac72618fa1eeb5b3fd9ed1341f10dd90df75499cb4c38a6c3ef47cdd94"},
]
[[package]]
@ -2309,7 +2352,7 @@ files = [
cffi = ">=1.4.1"
[package.extras]
docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
docs = ["sphinx (>=1.6.5)", "sphinx_rtd_theme"]
tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
[[package]]
@ -2583,14 +2626,14 @@ files = [
[[package]]
name = "pytz"
version = "2022.7"
version = "2022.7.1"
description = "World timezone definitions, modern and historical"
category = "dev"
optional = false
python-versions = "*"
files = [
{file = "pytz-2022.7-py2.py3-none-any.whl", hash = "sha256:93007def75ae22f7cd991c84e02d434876818661f8df9ad5df9e950ff4e52cfd"},
{file = "pytz-2022.7.tar.gz", hash = "sha256:7ccfae7b4b2c067464a6733c6261673fdb8fd1be905460396b97a073e9fa683a"},
{file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"},
{file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"},
]
[[package]]
@ -2805,18 +2848,18 @@ files = [
[[package]]
name = "setuptools"
version = "65.6.3"
version = "65.7.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"},
{file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"},
{file = "setuptools-65.7.0-py3-none-any.whl", hash = "sha256:8ab4f1dbf2b4a65f7eec5ad0c620e84c34111a68d3349833494b9088212214dd"},
{file = "setuptools-65.7.0.tar.gz", hash = "sha256:4d3c92fac8f1118bb77a22181355e29c239cabfe2b9effdaa665c66b711136d7"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
@ -3139,14 +3182,14 @@ files = [
[[package]]
name = "urllib3"
version = "1.26.13"
version = "1.26.14"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
files = [
{file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"},
{file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"},
{file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"},
{file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"},
]
[package.extras]
@ -3177,14 +3220,14 @@ testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7
[[package]]
name = "wcwidth"
version = "0.2.5"
version = "0.2.6"
description = "Measures the displayed width of unicode strings in a terminal"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
{file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
{file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
]
[[package]]
@ -3419,4 +3462,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
[metadata]
lock-version = "2.0"
python-versions = ">=3.9.1,<3.10"
content-hash = "03a7c6c3f5aebd2e3ca4c23f66c8ae1c119cef7e041460f9ec916726df6a569e"
content-hash = "02daca205796a0f29a0d9f50707544e6804f32027eba493cd2aa7f175a00dcea"

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "OpenPype"
version = "3.14.2" # OpenPype
version = "3.14.10" # OpenPype
description = "Open VFX and Animation pipeline with support."
authors = ["OpenPype Team <info@openpype.io>"]
license = "MIT License"
@ -70,6 +70,7 @@ requests = "^2.25.1"
pysftp = "^0.2.9"
dropbox = "^11.20.0"
aiohttp-middlewares = "^2.0.0"
opencolorio = "^2.2.0"
[tool.poetry.dev-dependencies]
flake8 = "^6.0"

View file

@ -14,6 +14,7 @@ import re
from tests.lib.db_handler import DBHandler
from common.openpype_common.distribution.file_handler import RemoteFileHandler
from openpype.modules import ModulesManager
from openpype.settings import get_project_settings
class BaseTest:
@ -28,6 +29,7 @@ class ModuleUnitTest(BaseTest):
Implemented fixtures:
monkeypatch_session - fixture for env vars with session scope
project_settings - fixture for project settings with session scope
download_test_data - tmp folder with extracted data from GDrive
env_var - sets env vars from input file
db_setup - prepares avalon AND openpype DBs for testing from
@ -59,6 +61,12 @@ class ModuleUnitTest(BaseTest):
yield m
m.undo()
@pytest.fixture(scope='module')
def project_settings(self):
yield get_project_settings(
self.PROJECT
)
@pytest.fixture(scope="module")
def download_test_data(self, test_data_folder, persist, request):
test_data_folder = test_data_folder or self.TEST_DATA_FOLDER
@ -67,6 +75,7 @@ class ModuleUnitTest(BaseTest):
yield test_data_folder
else:
tmpdir = tempfile.mkdtemp()
print("Temporary folder created:: {}".format(tmpdir))
for test_file in self.TEST_FILES:
file_id, file_name, md5 = test_file
@ -78,7 +87,6 @@ class ModuleUnitTest(BaseTest):
if ext.lstrip('.') in RemoteFileHandler.IMPLEMENTED_ZIP_FORMATS: # noqa: E501
RemoteFileHandler.unzip(os.path.join(tmpdir, file_name))
print("Temporary folder created:: {}".format(tmpdir))
yield tmpdir
persist = (persist or self.PERSIST or
@ -87,6 +95,15 @@ class ModuleUnitTest(BaseTest):
print("Removing {}".format(tmpdir))
shutil.rmtree(tmpdir)
@pytest.fixture(scope="module")
def output_folder_url(self, download_test_data):
"""Returns location of published data, cleans it first if exists."""
path = os.path.join(download_test_data, "output")
if os.path.exists(path):
print("Purging {}".format(path))
shutil.rmtree(path)
yield path
@pytest.fixture(scope="module")
def env_var(self, monkeypatch_session, download_test_data):
"""Sets temporary env vars from json file."""
@ -152,14 +169,27 @@ class ModuleUnitTest(BaseTest):
db_handler.teardown(self.TEST_OPENPYPE_NAME)
@pytest.fixture(scope="module")
def dbcon(self, db_setup):
def dbcon(self, db_setup, output_folder_url):
"""Provide test database connection.
Database prepared from dumps with 'db_setup' fixture.
"""
from openpype.pipeline import AvalonMongoDB
dbcon = AvalonMongoDB()
dbcon.Session["AVALON_PROJECT"] = self.TEST_PROJECT_NAME
dbcon.Session["AVALON_PROJECT"] = self.PROJECT
dbcon.Session["AVALON_ASSET"] = self.ASSET
dbcon.Session["AVALON_TASK"] = self.TASK
# set project root to temp folder
platform_str = platform.system().lower()
root_key = "config.roots.work.{}".format(platform_str)
dbcon.update_one(
{"type": "project"},
{"$set":
{
root_key: output_folder_url
}}
)
yield dbcon
@pytest.fixture(scope="module")
@ -228,15 +258,6 @@ class PublishTest(ModuleUnitTest):
yield "{}/{}".format(self.APP_GROUP, app_variant)
@pytest.fixture(scope="module")
def output_folder_url(self, download_test_data):
"""Returns location of published data, cleans it first if exists."""
path = os.path.join(download_test_data, "output")
if os.path.exists(path):
print("Purging {}".format(path))
shutil.rmtree(path)
yield path
@pytest.fixture(scope="module")
def app_args(self, download_test_data):
"""Returns additional application arguments from a test file.
@ -267,17 +288,6 @@ class PublishTest(ModuleUnitTest):
def launched_app(self, dbcon, download_test_data, last_workfile_path,
startup_scripts, app_args, app_name, output_folder_url):
"""Launch host app"""
# set publishing folders
platform_str = platform.system().lower()
root_key = "config.roots.work.{}".format(platform_str)
dbcon.update_one(
{"type": "project"},
{"$set":
{
root_key: output_folder_url
}}
)
# set schema - for integrate_new
from openpype import PACKAGE_DIR
# Path to OpenPype's schema

View file

@ -0,0 +1,13 @@
import pytest
from tests.lib.testing_classes import ModuleUnitTest
from openpype.pipeline import legacy_io
class TestPipeline(ModuleUnitTest):
""" Testing Pipeline base class
"""
@pytest.fixture(scope="module")
def legacy_io(self, dbcon):
legacy_io.Session = dbcon.Session
yield legacy_io.Session

View file

@ -0,0 +1,216 @@
"""Test Publish_plugins pipeline publish modul, tests API methods
File:
creates temporary directory and downloads .zip file from GDrive
unzips .zip file
uses content of .zip file (MongoDB's dumps) to import to new databases
with use of 'monkeypatch_session' modifies required env vars
temporarily
runs battery of tests checking that site operation for Sync Server
module are working
removes temporary folder
removes temporary databases (?)
"""
import os
import pytest
import shutil
import logging
from tests.unit.openpype.pipeline.lib import TestPipeline
from openpype.pipeline.publish import publish_plugins
from openpype.pipeline import colorspace
log = logging.getLogger(__name__)
class TestPipelinePublishPlugins(TestPipeline):
""" Testing Pipeline pubish_plugins.py
Example:
cd to OpenPype repo root dir
poetry run python ./start.py runtests \
../tests/unit/openpype/pipeline/publish
"""
# files are the same as those used in `test_pipeline_colorspace`
TEST_FILES = [
(
"1d7t9_cVKeZRVF0ppCHiE5MJTTtTlJgBe",
"test_pipeline_colorspace.zip",
""
)
]
PROJECT = "test_project"
ASSET = "sh0010"
HIERARCHY = "shots/sq010"
TASK = "comp"
@pytest.fixture(scope="module")
def context(self, legacy_io, project_settings):
class CTX:
data = {
"projectName": legacy_io["AVALON_PROJECT"],
"asset": legacy_io["AVALON_ASSET"],
"hostName": "nuke",
"anatomyData": {},
"project_settings": project_settings
}
yield CTX
@pytest.fixture(scope="module")
def config_path_project(
self,
download_test_data,
output_folder_url
):
src_path = os.path.join(
download_test_data,
"input",
"data",
"configs",
"aces_1.3",
"ayon_aces_config_project.ocio"
)
dest_dir = os.path.join(
output_folder_url,
self.PROJECT,
"config"
)
dest_path = os.path.join(
dest_dir,
"aces.ocio"
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
shutil.copyfile(src_path, dest_path)
yield dest_path
@pytest.fixture(scope="module")
def config_path_asset(
self,
download_test_data,
output_folder_url
):
src_path = os.path.join(
download_test_data,
"input",
"data",
"configs",
"aces_1.3",
"ayon_aces_config_asset.ocio"
)
dest_dir = os.path.join(
output_folder_url,
self.PROJECT,
self.HIERARCHY,
self.ASSET,
"config"
)
dest_path = os.path.join(
dest_dir,
"aces.ocio"
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
shutil.copyfile(src_path, dest_path)
yield dest_path
def test_get_colorspace_settings(self, context, config_path_asset):
expected_config_template = (
"{root[work]}/{project[name]}"
"/{hierarchy}/{asset}/config/aces.ocio"
)
expected_file_rules = {
"comp_review": {
"pattern": "renderCompMain.baking_h264",
"colorspace": "Camera Rec.709",
"ext": "mp4"
}
}
# load plugin function for testing
plugin = publish_plugins.ExtractorColormanaged()
plugin.log = log
config_data, file_rules = plugin.get_colorspace_settings(context)
assert config_data["template"] == expected_config_template, (
"Returned config tempate is not "
f"matching {expected_config_template}"
)
assert file_rules == expected_file_rules, (
"Returned file rules are not "
f"matching {expected_file_rules}"
)
def test_set_representation_colorspace(
self, context, project_settings,
config_path_project, config_path_asset
):
expected_colorspace_hiero = "sRGB - Texture"
expected_colorspace_nuke = "Camera Rec.709"
config_data_nuke = colorspace.get_imageio_config(
"test_project", "nuke", project_settings)
file_rules_nuke = colorspace.get_imageio_file_rules(
"test_project", "nuke", project_settings)
config_data_hiero = colorspace.get_imageio_config(
"test_project", "hiero", project_settings)
file_rules_hiero = colorspace.get_imageio_file_rules(
"test_project", "hiero", project_settings)
representation_nuke = {
"ext": "mp4",
"files": "this_file_renderCompMain.baking_h264.mp4"
}
representation_hiero = {
"ext": "mp4",
"files": "this_file_renderCompMain_h264burninburnin.mp4"
}
# load plugin function for testing
plugin = publish_plugins.ExtractorColormanaged()
plugin.log = log
plugin.set_representation_colorspace(
representation_nuke, context,
colorspace_settings=(config_data_nuke, file_rules_nuke)
)
# load plugin function for testing
plugin = publish_plugins.ExtractorColormanaged()
plugin.log = log
plugin.set_representation_colorspace(
representation_hiero, context,
colorspace_settings=(config_data_hiero, file_rules_hiero)
)
colorspace_data_nuke = representation_nuke.get("colorspaceData")
colorspace_data_hiero = representation_hiero.get("colorspaceData")
assert colorspace_data_nuke, (
"Colorspace data were not created in prepresentation"
f"matching {representation_nuke}"
)
assert colorspace_data_hiero, (
"Colorspace data were not created in prepresentation"
f"matching {representation_hiero}"
)
ret_colorspace_nuke = colorspace_data_nuke["colorspace"]
assert ret_colorspace_nuke == expected_colorspace_nuke, (
"Returned colorspace is not "
f"matching {expected_colorspace_nuke}"
)
ret_colorspace_hiero = colorspace_data_hiero["colorspace"]
assert ret_colorspace_hiero == expected_colorspace_hiero, (
"Returned colorspace is not "
f"matching {expected_colorspace_hiero}"
)
test_case = TestPipelinePublishPlugins()

View file

@ -0,0 +1,189 @@
"""Test Colorspace pipeline modul, tests API methods
File:
creates temporary directory and downloads .zip file from GDrive
unzips .zip file
uses content of .zip file (MongoDB's dumps) to import to new databases
with use of 'monkeypatch_session' modifies required env vars
temporarily
runs battery of tests checking that site operation for Sync Server
module are working
removes temporary folder
removes temporary databases (?)
"""
import pytest
import shutil
import os
from tests.unit.openpype.pipeline.lib import TestPipeline
from openpype.pipeline import colorspace
class TestPipelineColorspace(TestPipeline):
""" Testing Colorspace
Example:
cd to OpenPype repo root dir
poetry run python ./start.py runtests ../tests/unit/openpype/pipeline
"""
TEST_FILES = [
(
"1d7t9_cVKeZRVF0ppCHiE5MJTTtTlJgBe",
"test_pipeline_colorspace.zip",
""
)
]
PROJECT = "test_project"
ASSET = "test_asset"
TASK = "test_task"
@pytest.fixture(scope="module")
def config_path_project(
self,
download_test_data,
output_folder_url
):
src_path = os.path.join(
download_test_data,
"input",
"data",
"configs",
"aces_1.3",
"ayon_aces_config_project.ocio"
)
dest_dir = os.path.join(
output_folder_url,
self.PROJECT,
"config"
)
dest_path = os.path.join(
dest_dir,
"aces.ocio"
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
shutil.copyfile(src_path, dest_path)
yield dest_path
@pytest.fixture(scope="module")
def config_path_asset(
self,
download_test_data,
output_folder_url
):
src_path = os.path.join(
download_test_data,
"input",
"data",
"configs",
"aces_1.3",
"ayon_aces_config_asset.ocio"
)
dest_dir = os.path.join(
output_folder_url,
self.PROJECT,
self.ASSET,
"config"
)
dest_path = os.path.join(
dest_dir,
"aces.ocio"
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
shutil.copyfile(src_path, dest_path)
yield dest_path
def test_config_file_project(
self,
legacy_io,
config_path_project,
project_settings
):
expected_template = "{root[work]}/{project[name]}/config/aces.ocio"
# get config_data from hiero
# where project level config is defined
config_data = colorspace.get_imageio_config(
"test_project", "hiero", project_settings)
assert os.path.exists(config_data["path"]), (
f"Config file \'{config_data['path']}\' doesn't exist"
)
assert config_data["template"] == expected_template, (
f"Config template \'{config_data['template']}\' doesn't match "
f"expected tempalte \'{expected_template}\'"
)
def test_parse_colorspace_from_filepath(
self,
legacy_io,
config_path_asset,
project_settings
):
path_1 = "renderCompMain_ACES2065-1.####.exr"
expected_1 = "ACES2065-1"
ret_1 = colorspace.parse_colorspace_from_filepath(
path_1, "nuke", "test_project", project_settings=project_settings
)
assert ret_1 == expected_1, f"Not matching colorspace {expected_1}"
path_2 = "renderCompMain_BMDFilm_WideGamut_Gen5.mov"
expected_2 = "BMDFilm WideGamut Gen5"
ret_2 = colorspace.parse_colorspace_from_filepath(
path_2, "nuke", "test_project", project_settings=project_settings
)
assert ret_2 == expected_2, f"Not matching colorspace {expected_2}"
def test_get_ocio_config_views_asset(self, config_path_asset):
expected_num_keys = 12
ret = colorspace.get_ocio_config_views(config_path_asset)
assert len(ret) == expected_num_keys, (
f"Not matching num viewer keys {expected_num_keys}")
def test_get_ocio_config_views_project(self, config_path_project):
expected_num_keys = 3
ret = colorspace.get_ocio_config_views(config_path_project)
assert len(ret) == expected_num_keys, (
f"Not matching num viewer keys {expected_num_keys}")
def test_file_rules(self, project_settings):
expected_nuke = {
"comp_review": {
"pattern": "renderCompMain.baking_h264",
"colorspace": "Camera Rec.709",
"ext": "mp4"
}
}
expected_hiero = {
"comp_review": {
"pattern": "renderCompMain_h264burninburnin",
"colorspace": "sRGB - Texture",
"ext": "mp4"
}
}
nuke_file_rules = colorspace.get_imageio_file_rules(
"test_project", "nuke", project_settings=project_settings)
assert expected_nuke == nuke_file_rules, (
f"Not matching file rules {expected_nuke}")
hiero_file_rules = colorspace.get_imageio_file_rules(
"test_project", "hiero", project_settings=project_settings)
assert expected_hiero == hiero_file_rules, (
f"Not matching file rules {expected_hiero}")
test_case = TestPipelineColorspace()

View file

@ -0,0 +1,120 @@
---
id: dev_colorspace
title: Colorspace Management and Distribution
sidebar_label: Colorspace
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Introduction
Defines the distribution of colors and OCIO config during publishing. Once colorspace data are captured and integrated into representation loaders could use them for loading image and video data with correct colorspace.
:::warning Color Management (ImageIO)
Adding the `imagio` settings schema is required for any host or module which is processing pixel data.
:::
## Data model
Published representations that are extracted with color managed data store a **colorspaceData** entry in its data: `representation_doc["data"]["colorspaceData"]`.
It's up to the Host implementation to pre-configure the application or workfile to have the correct OCIO config applied.
It's up to the Extractors to set these values for the representation during publishing.
It's up to the Loaders to read these values and apply the correct expected color space.
### Keys
- **colorspace** - string value used in other publish plugins and loaders
- **config** - storing two versions of path.
- **path** - is formated and with baked platform root. It is used for posible need to find out where we were sourcing color config during publishing.
- **template** - unformated tempate resolved from settings. It is used for other plugins targeted to remote publish which could be processed at different platform.
### Example
{
"colorspace": "linear",
"config": {
"path": "/abs/path/to/config.ocio",
"template": "{project[root]}/path/to/config.ocio"
}
}
## How to integrate it into a host
1. The settings for a host should add the `imagio` schema. Ideally near the top of all categories in its `/settings/entities/schemas/system_scheams/host_settings/schema_{host}.json` so it matches the settings layout other hosts.
```json
{
"key": "imageio",
"type": "dict",
"label": "Color Management (ImageIO)",
"is_group": true,
"children": [
{
"type": "schema",
"name": "schema_imageio_config"
},
{
"type": "schema",
"name": "schema_imageio_file_rules"
}
]
}
```
2. Set the OCIO config path for the host to the path returned from `openpype.pipeline.colorspace.get_imageio_config`, for example:
- set the `OCIO` environment variable before launching the host via a prelaunch hook
- or (if the host allows) to set the workfile OCIO config path using the host's API
3. Each Extractor exporting pixel data (e.g. image or video) has to use parent class `openpype.pipeline.publish.publish_plugins.ExtractorColormanaged` and use `self.set_representation_colorspace` on the representations to be integrated.
The **set_representation_colorspace** method adds `colorspaceData` to the representation. If the `colorspace` passed is not `None` then it is added directly to the representation with resolved config path otherwise a color space is assumed using the configured file rules. If no file rule matches the `colorspaceData` is **not** added to the representation.
An example implementation can be found here: `openpype\hosts\nuke\plugins\publish\extract_render_local.py`
4. The Loader plug-ins should take into account the `colorspaceData` in the published representation's data to allow the DCC to read in the expected color space.
```python
from openpype.pipeline.colorspace import (
get_imageio_colorspace_from_filepath,
get_imageio_config,
get_imageio_file_rules
)
class YourLoader(api.Loader):
def load(self, context, name=None, namespace=None, options=None):
path = self.fname
colorspace_data = context["representation"]["data"].get("colorspaceData", {})
colorspace = (
colorspace_data.get("colorspace")
# try to match colorspace from file rules
or self.get_colorspace_from_file_rules(path, context)
)
# pseudocode
load_file(path, colorspace=colorspace)
def get_colorspace_from_file_rules(self, path, context)
project_name = context.data["projectName"]
host_name = context.data["hostName"]
anatomy_data = context.data["anatomyData"]
project_settings_ = context.data["project_settings"]
config_data = get_imageio_config(
project_name, host_name,
project_settings=project_settings_,
anatomy_data=anatomy_data
)
file_rules = get_imageio_file_rules(
project_name, host_name,
project_settings=project_settings_
)
# get matching colorspace from rules
colorspace = get_imageio_colorspace_from_filepath(
path, host_name, project_name,
config_data=config_data,
file_rules=file_rules,
project_settings=project_settings
)
```
:::warning Loading
A custom OCIO config can be set per asset/shot and thus it can happen the current session you are loading into uses a different config than the original context's **colorspaceData** was published with. It's up the loader's implementation to take that into account and decide what to do if the colorspace differs and or might not exist.
:::

View file

@ -13,6 +13,39 @@ Project settings can have project specific values. Each new project is using stu
Projects always use default project values unless they have [project override](../admin_settings#project-overrides) (orage colour). Any changes in default project may affect all existing projects.
:::
## Color Management (ImageIO)
:::info Default OCIO config
OpenPype distributes its own OCIO configs. Those can be found in `{openpype install dir}/{version}/vendor/bin/ocioconfig/OpenColorIOConfigs`. Windows example: `C:\Program Files (x86)\OpenPype\3.14.0\vendor\bin\ocioconfig\OpenColorIOConfigs`
:::
### Using OCIO config
Global config path is set by default to OpenPype distributed configs. At the moment there are only two - **aces_1.2** and **nuke-default**. Since this path input is not platform specific it is required to use at least an environment variable do platform specific config root directory. Order of paths matter so first path found and existing first served.
Each OCIO config path input supports formatting using environment variables and [anatomy template keys](../admin_settings_project_anatomy#available-template-keys). The default global OCIO config path is `{OPENPYPE_ROOT}/vendor/bin/ocioconfig/OpenColorIOConfigs/aces_1.2/config.ocio`.
If the project settings for a particular host has its own OCIO config **enabled** and set to at least one path and the path exists, it overrides the global OCIO config for that host.
**For example**
Project nuke-specific OCIO config: `project_settings/nuke/imageio/ocio_config`
If config path is defined to particular shot target with following path inputs:
1. `{root[work]}/{project[name]}/{hierarchy}/{asset}/config/aces.ocio`
2. `{root[work]}/{project[name]}/{hierarchy}/config/aces.ocio`
Procedure of resolving path (from above example) will look first into path 1st and if the path is not existing then it will try 2nd and if even that is not existing then it will fall back to global default.
### Using File rules
File rules are inspired by [OCIO v2 configuration]((https://opencolorio.readthedocs.io/en/latest/guides/authoring/rules.html)). Each rule has a unique name which can be overridden by host-specific _File rules_ (example: `project_settings/nuke/imageio/file_rules/rules`).
The _input pattern_ matching uses REGEX expression syntax (try [regexr.com](https://regexr.com/)). Matching rules procedure's intention is to be used during publishing or loading of representation. Since the publishing procedure is run before integrator formate publish template path, make sure the pattern is working or any work render path.
:::warning Colorspace name input
The **colorspace name** value is a raw string input and no validation is run after saving project settings. We recommend to open the specified `config.ocio` file and copy pasting the exact colorspace names.
:::
## Profile filters
Many of the settings are using a concept of **Profile filters**

View file

@ -158,6 +158,7 @@ module.exports = {
"dev_publishing"
]
},
"dev_deadline"
"dev_deadline",
"dev_colorspace"
]
};