diff --git a/openpype/hosts/blender/api/__init__.py b/openpype/hosts/blender/api/__init__.py
index c5b0a44072..66102a2ae1 100644
--- a/openpype/hosts/blender/api/__init__.py
+++ b/openpype/hosts/blender/api/__init__.py
@@ -51,18 +51,38 @@ def set_start_end_frames():
"name": asset_name
})
- # Default frame start/end
- frameStart = 0
- frameEnd = 100
+ scene = bpy.context.scene
- # Check if frameStart/frameEnd are set
- if asset_doc["data"]["frameStart"]:
- frameStart = asset_doc["data"]["frameStart"]
- if asset_doc["data"]["frameEnd"]:
- frameEnd = asset_doc["data"]["frameEnd"]
+ # Default scene settings
+ frameStart = scene.frame_start
+ frameEnd = scene.frame_end
+ fps = scene.render.fps
+ resolution_x = scene.render.resolution_x
+ resolution_y = scene.render.resolution_y
+
+ # Check if settings are set
+ data = asset_doc.get("data")
+
+ if not data:
+ return
+
+ if data.get("frameStart"):
+ frameStart = data.get("frameStart")
+ if data.get("frameEnd"):
+ frameEnd = data.get("frameEnd")
+ if data.get("fps"):
+ fps = data.get("fps")
+ if data.get("resolutionWidth"):
+ resolution_x = data.get("resolutionWidth")
+ if data.get("resolutionHeight"):
+ resolution_y = data.get("resolutionHeight")
+
+ scene.frame_start = frameStart
+ scene.frame_end = frameEnd
+ scene.render.fps = fps
+ scene.render.resolution_x = resolution_x
+ scene.render.resolution_y = resolution_y
- bpy.context.scene.frame_start = frameStart
- bpy.context.scene.frame_end = frameEnd
def on_new(arg1, arg2):
set_start_end_frames()
diff --git a/openpype/hosts/blender/plugins/publish/validate_object_mode.py b/openpype/hosts/blender/plugins/publish/validate_object_mode.py
new file mode 100644
index 0000000000..1c82628c1c
--- /dev/null
+++ b/openpype/hosts/blender/plugins/publish/validate_object_mode.py
@@ -0,0 +1,35 @@
+from typing import List
+
+import pyblish.api
+import openpype.hosts.blender.api.action
+
+
+class ValidateObjectIsInObjectMode(pyblish.api.InstancePlugin):
+ """Validate that the current object is in Object Mode."""
+
+ order = pyblish.api.ValidatorOrder - 0.01
+ hosts = ["blender"]
+ families = ["model", "rig"]
+ category = "geometry"
+ label = "Object is in Object Mode"
+ actions = [openpype.hosts.blender.api.action.SelectInvalidAction]
+ optional = True
+
+ @classmethod
+ def get_invalid(cls, instance) -> List:
+ invalid = []
+ for obj in [obj for obj in instance]:
+ try:
+ if obj.type == 'MESH' or obj.type == 'ARMATURE':
+ # Check if the object is in object mode.
+ if not obj.mode == 'OBJECT':
+ invalid.append(obj)
+ except Exception:
+ continue
+ return invalid
+
+ def process(self, instance):
+ invalid = self.get_invalid(instance)
+ if invalid:
+ raise RuntimeError(
+ f"Object found in instance is not in Object Mode: {invalid}")
diff --git a/openpype/hosts/nuke/plugins/publish/precollect_instances.py b/openpype/hosts/nuke/plugins/publish/precollect_instances.py
index 2d25b29826..92f96ea48d 100644
--- a/openpype/hosts/nuke/plugins/publish/precollect_instances.py
+++ b/openpype/hosts/nuke/plugins/publish/precollect_instances.py
@@ -80,25 +80,31 @@ class PreCollectNukeInstances(pyblish.api.ContextPlugin):
# Add all nodes in group instances.
if node.Class() == "Group":
- # check if it is write node in family
- if "write" in families:
+ # only alter families for render family
+ if "write" in families_ak:
target = node["render"].value()
if target == "Use existing frames":
# Local rendering
self.log.info("flagged for no render")
- families.append("render")
+ families.append(family)
elif target == "Local":
# Local rendering
self.log.info("flagged for local render")
- families.append("{}.local".format("render"))
+ families.append("{}.local".format(family))
elif target == "On farm":
# Farm rendering
self.log.info("flagged for farm render")
instance.data["transfer"] = False
- families.append("{}.farm".format("render"))
+ families.append("{}.farm".format(family))
+
+ # suffle family to `write` as it is main family
+ # this will be changed later on in process
if "render" in families:
families.remove("render")
family = "write"
+ elif "prerender" in families:
+ families.remove("prerender")
+ family = "write"
node.begin()
for i in nuke.allNodes():
diff --git a/openpype/hosts/nuke/plugins/publish/precollect_writes.py b/openpype/hosts/nuke/plugins/publish/precollect_writes.py
index a519609f52..57303bd42e 100644
--- a/openpype/hosts/nuke/plugins/publish/precollect_writes.py
+++ b/openpype/hosts/nuke/plugins/publish/precollect_writes.py
@@ -108,6 +108,8 @@ class CollectNukeWrites(pyblish.api.InstancePlugin):
# Add version data to instance
version_data = {
+ "families": [f.replace(".local", "").replace(".farm", "")
+ for f in families if "write" not in f],
"colorspace": node["colorspace"].value(),
}
diff --git a/openpype/hosts/resolve/__init__.py b/openpype/hosts/resolve/__init__.py
index 734e0bc5df..3e49ce3b9b 100644
--- a/openpype/hosts/resolve/__init__.py
+++ b/openpype/hosts/resolve/__init__.py
@@ -11,7 +11,9 @@ from .api.pipeline import (
update_container,
publish,
launch_workfiles_app,
- maintained_selection
+ maintained_selection,
+ remove_instance,
+ list_instances
)
from .api.lib import (
@@ -73,6 +75,8 @@ __all__ = [
"publish",
"launch_workfiles_app",
"maintained_selection",
+ "remove_instance",
+ "list_instances",
# utils
"setup",
diff --git a/openpype/hosts/resolve/api/menu.py b/openpype/hosts/resolve/api/menu.py
index 5ed7aeab34..e7be3fc963 100644
--- a/openpype/hosts/resolve/api/menu.py
+++ b/openpype/hosts/resolve/api/menu.py
@@ -12,7 +12,8 @@ from avalon.tools import (
creator,
loader,
sceneinventory,
- libraryloader
+ libraryloader,
+ subsetmanager
)
@@ -64,8 +65,9 @@ class OpenPypeMenu(QtWidgets.QWidget):
publish_btn = QtWidgets.QPushButton("Publish ...", self)
load_btn = QtWidgets.QPushButton("Load ...", self)
inventory_btn = QtWidgets.QPushButton("Inventory ...", self)
+ subsetm_btn = QtWidgets.QPushButton("Subset Manager ...", self)
libload_btn = QtWidgets.QPushButton("Library ...", self)
- # rename_btn = QtWidgets.QPushButton("Rename ...", self)
+ # rename_btn = QtWidgets.QPushButton("Rename", self)
# set_colorspace_btn = QtWidgets.QPushButton(
# "Set colorspace from presets", self
# )
@@ -81,6 +83,7 @@ class OpenPypeMenu(QtWidgets.QWidget):
layout.addWidget(publish_btn)
layout.addWidget(load_btn)
layout.addWidget(inventory_btn)
+ layout.addWidget(subsetm_btn)
layout.addWidget(Spacer(15, self))
@@ -102,6 +105,7 @@ class OpenPypeMenu(QtWidgets.QWidget):
publish_btn.clicked.connect(self.on_publish_clicked)
load_btn.clicked.connect(self.on_load_clicked)
inventory_btn.clicked.connect(self.on_inventory_clicked)
+ subsetm_btn.clicked.connect(self.on_subsetm_clicked)
libload_btn.clicked.connect(self.on_libload_clicked)
# rename_btn.clicked.connect(self.on_rename_clicked)
# set_colorspace_btn.clicked.connect(self.on_set_colorspace_clicked)
@@ -127,6 +131,10 @@ class OpenPypeMenu(QtWidgets.QWidget):
print("Clicked Inventory")
sceneinventory.show()
+ def on_subsetm_clicked(self):
+ print("Clicked Subset Manager")
+ subsetmanager.show()
+
def on_libload_clicked(self):
print("Clicked Library")
libraryloader.show()
diff --git a/openpype/hosts/resolve/api/pipeline.py b/openpype/hosts/resolve/api/pipeline.py
index e3a832459b..a659ac7e51 100644
--- a/openpype/hosts/resolve/api/pipeline.py
+++ b/openpype/hosts/resolve/api/pipeline.py
@@ -258,3 +258,51 @@ def on_pyblish_instance_toggled(instance, old_value, new_value):
# Whether instances should be passthrough based on new value
timeline_item = instance.data["item"]
set_publish_attribute(timeline_item, new_value)
+
+
+def remove_instance(instance):
+ """Remove instance marker from track item."""
+ instance_id = instance.get("uuid")
+
+ selected_timeline_items = lib.get_current_timeline_items(
+ filter=True, selecting_color=lib.publish_clip_color)
+
+ found_ti = None
+ for timeline_item_data in selected_timeline_items:
+ timeline_item = timeline_item_data["clip"]["item"]
+
+ # get openpype tag data
+ tag_data = lib.get_timeline_item_pype_tag(timeline_item)
+ _ti_id = tag_data.get("uuid")
+ if _ti_id == instance_id:
+ found_ti = timeline_item
+ break
+
+ if found_ti is None:
+ return
+
+ # removing instance by marker color
+ print(f"Removing instance: {found_ti.GetName()}")
+ found_ti.DeleteMarkersByColor(lib.pype_marker_color)
+
+
+def list_instances():
+ """List all created instances from current workfile."""
+ listed_instances = []
+ selected_timeline_items = lib.get_current_timeline_items(
+ filter=True, selecting_color=lib.publish_clip_color)
+
+ for timeline_item_data in selected_timeline_items:
+ timeline_item = timeline_item_data["clip"]["item"]
+ ti_name = timeline_item.GetName().split(".")[0]
+
+ # get openpype tag data
+ tag_data = lib.get_timeline_item_pype_tag(timeline_item)
+
+ if tag_data:
+ asset = tag_data.get("asset")
+ subset = tag_data.get("subset")
+ tag_data["label"] = f"{ti_name} [{asset}-{subset}]"
+ listed_instances.append(tag_data)
+
+ return listed_instances
diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py
index 3833795b96..4712d0a8b9 100644
--- a/openpype/hosts/resolve/api/plugin.py
+++ b/openpype/hosts/resolve/api/plugin.py
@@ -1,4 +1,5 @@
import re
+import uuid
from avalon import api
import openpype.api as pype
from openpype.hosts import resolve
@@ -697,13 +698,13 @@ class PublishClip:
Populating the tag data into internal variable self.tag_data
"""
# define vertical sync attributes
- master_layer = True
+ hero_track = True
self.review_layer = ""
if self.vertical_sync:
# check if track name is not in driving layer
if self.track_name not in self.driving_layer:
# if it is not then define vertical sync as None
- master_layer = False
+ hero_track = False
# increasing steps by index of rename iteration
self.count_steps *= self.rename_index
@@ -717,7 +718,7 @@ class PublishClip:
self.tag_data[_k] = _v["value"]
# driving layer is set as positive match
- if master_layer or self.vertical_sync:
+ if hero_track or self.vertical_sync:
# mark review layer
if self.review_track and (
self.review_track not in self.review_track_default):
@@ -751,35 +752,39 @@ class PublishClip:
hierarchy_formating_data
)
- tag_hierarchy_data.update({"masterLayer": True})
- if master_layer and self.vertical_sync:
- # tag_hierarchy_data.update({"masterLayer": True})
+ tag_hierarchy_data.update({"heroTrack": True})
+ if hero_track and self.vertical_sync:
self.vertical_clip_match.update({
(self.clip_in, self.clip_out): tag_hierarchy_data
})
- if not master_layer and self.vertical_sync:
+ if not hero_track and self.vertical_sync:
# driving layer is set as negative match
- for (_in, _out), master_data in self.vertical_clip_match.items():
- master_data.update({"masterLayer": False})
+ for (_in, _out), hero_data in self.vertical_clip_match.items():
+ hero_data.update({"heroTrack": False})
if _in == self.clip_in and _out == self.clip_out:
- data_subset = master_data["subset"]
- # add track index in case duplicity of names in master data
+ data_subset = hero_data["subset"]
+ # add track index in case duplicity of names in hero data
if self.subset in data_subset:
- master_data["subset"] = self.subset + str(
+ hero_data["subset"] = self.subset + str(
self.track_index)
# in case track name and subset name is the same then add
if self.subset_name == self.track_name:
- master_data["subset"] = self.subset
+ hero_data["subset"] = self.subset
# assing data to return hierarchy data to tag
- tag_hierarchy_data = master_data
+ tag_hierarchy_data = hero_data
# add data to return data dict
self.tag_data.update(tag_hierarchy_data)
- if master_layer and self.review_layer:
+ # add uuid to tag data
+ self.tag_data["uuid"] = str(uuid.uuid4())
+
+ # add review track only to hero track
+ if hero_track and self.review_layer:
self.tag_data.update({"reviewTrack": self.review_layer})
+
def _solve_tag_hierarchy_data(self, hierarchy_formating_data):
""" Solve tag data from hierarchy data and templates. """
# fill up clip name and hierarchy keys
diff --git a/openpype/hosts/resolve/plugins/create/create_shot_clip.py b/openpype/hosts/resolve/plugins/create/create_shot_clip.py
index 2916a52298..41fdbf5c61 100644
--- a/openpype/hosts/resolve/plugins/create/create_shot_clip.py
+++ b/openpype/hosts/resolve/plugins/create/create_shot_clip.py
@@ -117,7 +117,7 @@ class CreateShotClip(resolve.Creator):
"vSyncTrack": {
"value": gui_tracks, # noqa
"type": "QComboBox",
- "label": "Master track",
+ "label": "Hero track",
"target": "ui",
"toolTip": "Select driving track name which should be mastering all others", # noqa
"order": 1}
diff --git a/openpype/hosts/resolve/plugins/publish/collect_instances.py b/openpype/hosts/resolve/plugins/publish/precollect_instances.py
similarity index 95%
rename from openpype/hosts/resolve/plugins/publish/collect_instances.py
rename to openpype/hosts/resolve/plugins/publish/precollect_instances.py
index f4eeb39754..c38cbc4f73 100644
--- a/openpype/hosts/resolve/plugins/publish/collect_instances.py
+++ b/openpype/hosts/resolve/plugins/publish/precollect_instances.py
@@ -5,11 +5,11 @@ from openpype.hosts import resolve
from pprint import pformat
-class CollectInstances(pyblish.api.ContextPlugin):
+class PrecollectInstances(pyblish.api.ContextPlugin):
"""Collect all Track items selection."""
order = pyblish.api.CollectorOrder - 0.59
- label = "Collect Instances"
+ label = "Precollect Instances"
hosts = ["resolve"]
def process(self, context):
@@ -26,7 +26,7 @@ class CollectInstances(pyblish.api.ContextPlugin):
data = dict()
timeline_item = timeline_item_data["clip"]["item"]
- # get openpype tag data
+ # get pype tag data
tag_data = resolve.get_timeline_item_pype_tag(timeline_item)
self.log.debug(f"__ tag_data: {pformat(tag_data)}")
@@ -102,10 +102,10 @@ class CollectInstances(pyblish.api.ContextPlugin):
})
def create_shot_instance(self, context, timeline_item, **data):
- master_layer = data.get("masterLayer")
+ hero_track = data.get("heroTrack")
hierarchy_data = data.get("hierarchyData")
- if not master_layer:
+ if not hero_track:
return
if not hierarchy_data:
diff --git a/openpype/hosts/resolve/plugins/publish/collect_workfile.py b/openpype/hosts/resolve/plugins/publish/precollect_workfile.py
similarity index 88%
rename from openpype/hosts/resolve/plugins/publish/collect_workfile.py
rename to openpype/hosts/resolve/plugins/publish/precollect_workfile.py
index a66284ed02..ee05fb6f13 100644
--- a/openpype/hosts/resolve/plugins/publish/collect_workfile.py
+++ b/openpype/hosts/resolve/plugins/publish/precollect_workfile.py
@@ -9,10 +9,10 @@ from openpype.hosts.resolve.otio import davinci_export
reload(davinci_export)
-class CollectWorkfile(pyblish.api.ContextPlugin):
- """Inject the current working file into context"""
+class PrecollectWorkfile(pyblish.api.ContextPlugin):
+ """Precollect the current working file into context"""
- label = "Collect Workfile"
+ label = "Precollect Workfile"
order = pyblish.api.CollectorOrder - 0.6
def process(self, context):
@@ -21,8 +21,6 @@ class CollectWorkfile(pyblish.api.ContextPlugin):
subset = "workfile"
project = resolve.get_current_project()
fps = project.GetSetting("timelineFrameRate")
-
- active_timeline = resolve.get_current_timeline()
video_tracks = resolve.get_video_track_names()
# adding otio timeline to context
diff --git a/openpype/hosts/resolve/utility_scripts/OTIO_export.py b/openpype/hosts/resolve/utility_scripts/OTIO_export.py
index 91bc2c5700..0431eb7daa 100644
--- a/openpype/hosts/resolve/utility_scripts/OTIO_export.py
+++ b/openpype/hosts/resolve/utility_scripts/OTIO_export.py
@@ -58,9 +58,8 @@ def _close_window(event):
def _export_button(event):
pm = resolve.GetProjectManager()
project = pm.GetCurrentProject()
- fps = project.GetSetting("timelineFrameRate")
timeline = project.GetCurrentTimeline()
- otio_timeline = otio_export.create_otio_timeline(timeline, fps)
+ otio_timeline = otio_export.create_otio_timeline(project)
otio_path = os.path.join(
itm["exportfilebttn"].Text,
timeline.GetName() + ".otio")
diff --git a/openpype/hosts/tvpaint/plugins/publish/collect_instances.py b/openpype/hosts/tvpaint/plugins/publish/collect_instances.py
index 57602d9610..68c142c005 100644
--- a/openpype/hosts/tvpaint/plugins/publish/collect_instances.py
+++ b/openpype/hosts/tvpaint/plugins/publish/collect_instances.py
@@ -18,7 +18,7 @@ class CollectInstances(pyblish.api.ContextPlugin):
))
for instance_data in workfile_instances:
- instance_data["fps"] = context.data["fps"]
+ instance_data["fps"] = context.data["sceneFps"]
# Store workfile instance data to instance data
instance_data["originData"] = copy.deepcopy(instance_data)
@@ -32,6 +32,11 @@ class CollectInstances(pyblish.api.ContextPlugin):
subset_name = instance_data["subset"]
name = instance_data.get("name", subset_name)
instance_data["name"] = name
+ instance_data["label"] = "{} [{}-{}]".format(
+ name,
+ context.data["sceneFrameStart"],
+ context.data["sceneFrameEnd"]
+ )
active = instance_data.get("active", True)
instance_data["active"] = active
@@ -73,8 +78,8 @@ class CollectInstances(pyblish.api.ContextPlugin):
if instance is None:
continue
- instance.data["frameStart"] = context.data["frameStart"]
- instance.data["frameEnd"] = context.data["frameEnd"]
+ instance.data["frameStart"] = context.data["sceneFrameStart"]
+ instance.data["frameEnd"] = context.data["sceneFrameEnd"]
self.log.debug("Created instance: {}\n{}".format(
instance, json.dumps(instance.data, indent=4)
diff --git a/openpype/hosts/tvpaint/plugins/publish/collect_workfile_data.py b/openpype/hosts/tvpaint/plugins/publish/collect_workfile_data.py
index 7965112136..e683c66ea9 100644
--- a/openpype/hosts/tvpaint/plugins/publish/collect_workfile_data.py
+++ b/openpype/hosts/tvpaint/plugins/publish/collect_workfile_data.py
@@ -127,11 +127,11 @@ class CollectWorkfileData(pyblish.api.ContextPlugin):
"currentFile": workfile_path,
"sceneWidth": width,
"sceneHeight": height,
- "pixelAspect": pixel_apsect,
- "frameStart": frame_start,
- "frameEnd": frame_end,
- "fps": frame_rate,
- "fieldOrder": field_order
+ "scenePixelAspect": pixel_apsect,
+ "sceneFrameStart": frame_start,
+ "sceneFrameEnd": frame_end,
+ "sceneFps": frame_rate,
+ "sceneFieldOrder": field_order
}
self.log.debug(
"Scene data: {}".format(json.dumps(scene_data, indent=4))
diff --git a/openpype/hosts/tvpaint/plugins/publish/validate_project_settings.py b/openpype/hosts/tvpaint/plugins/publish/validate_project_settings.py
new file mode 100644
index 0000000000..fead3393ae
--- /dev/null
+++ b/openpype/hosts/tvpaint/plugins/publish/validate_project_settings.py
@@ -0,0 +1,36 @@
+import json
+
+import pyblish.api
+
+
+class ValidateProjectSettings(pyblish.api.ContextPlugin):
+ """Validate project settings against database.
+ """
+
+ label = "Validate Project Settings"
+ order = pyblish.api.ValidatorOrder
+ optional = True
+
+ def process(self, context):
+ scene_data = {
+ "frameStart": context.data.get("sceneFrameStart"),
+ "frameEnd": context.data.get("sceneFrameEnd"),
+ "fps": context.data.get("sceneFps"),
+ "resolutionWidth": context.data.get("sceneWidth"),
+ "resolutionHeight": context.data.get("sceneHeight"),
+ "pixelAspect": context.data.get("scenePixelAspect")
+ }
+ invalid = {}
+ for k in scene_data.keys():
+ expected_value = context.data["assetEntity"]["data"][k]
+ if scene_data[k] != expected_value:
+ invalid[k] = {
+ "current": scene_data[k], "expected": expected_value
+ }
+
+ if invalid:
+ raise AssertionError(
+ "Project settings does not match database:\n{}".format(
+ json.dumps(invalid, sort_keys=True, indent=4)
+ )
+ )
diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py
index 5d2955532a..56bdd047c9 100644
--- a/openpype/lib/local_settings.py
+++ b/openpype/lib/local_settings.py
@@ -498,12 +498,12 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry):
def _create_local_site_id(registry=None):
"""Create a local site identifier."""
- from uuid import uuid4
+ from coolname import generate_slug
if registry is None:
registry = OpenPypeSettingsRegistry()
- new_id = str(uuid4())
+ new_id = generate_slug(3)
print("Created local site id \"{}\"".format(new_id))
diff --git a/openpype/modules/clockify/clockify_api.py b/openpype/modules/clockify/clockify_api.py
index d88b2ef8df..29de5de0c9 100644
--- a/openpype/modules/clockify/clockify_api.py
+++ b/openpype/modules/clockify/clockify_api.py
@@ -1,13 +1,16 @@
import os
import re
import time
-import requests
import json
import datetime
+import requests
from .constants import (
- CLOCKIFY_ENDPOINT, ADMIN_PERMISSION_NAMES, CREDENTIALS_JSON_PATH
+ CLOCKIFY_ENDPOINT,
+ ADMIN_PERMISSION_NAMES
)
+from openpype.lib.local_settings import OpenPypeSecureRegistry
+
def time_check(obj):
if obj.request_counter < 10:
@@ -31,6 +34,8 @@ class ClockifyAPI:
self.request_counter = 0
self.request_time = time.time()
+ self.secure_registry = OpenPypeSecureRegistry("clockify")
+
@property
def headers(self):
return {"X-Api-Key": self.api_key}
@@ -129,22 +134,10 @@ class ClockifyAPI:
return False
def get_api_key(self):
- api_key = None
- try:
- file = open(CREDENTIALS_JSON_PATH, 'r')
- api_key = json.load(file).get('api_key', None)
- if api_key == '':
- api_key = None
- except Exception:
- file = open(CREDENTIALS_JSON_PATH, 'w')
- file.close()
- return api_key
+ return self.secure_registry.get_item("api_key", None)
def save_api_key(self, api_key):
- data = {'api_key': api_key}
- file = open(CREDENTIALS_JSON_PATH, 'w')
- file.write(json.dumps(data))
- file.close()
+ self.secure_registry.set_item("api_key", api_key)
def get_workspaces(self):
action_url = 'workspaces/'
diff --git a/openpype/modules/clockify/constants.py b/openpype/modules/clockify/constants.py
index 38ad4b64cf..66f6cb899a 100644
--- a/openpype/modules/clockify/constants.py
+++ b/openpype/modules/clockify/constants.py
@@ -1,17 +1,12 @@
import os
-import appdirs
CLOCKIFY_FTRACK_SERVER_PATH = os.path.join(
- os.path.dirname(__file__), "ftrack", "server"
+ os.path.dirname(os.path.abspath(__file__)), "ftrack", "server"
)
CLOCKIFY_FTRACK_USER_PATH = os.path.join(
- os.path.dirname(__file__), "ftrack", "user"
+ os.path.dirname(os.path.abspath(__file__)), "ftrack", "user"
)
-CREDENTIALS_JSON_PATH = os.path.normpath(os.path.join(
- appdirs.user_data_dir("pype-app", "pype"),
- "clockify.json"
-))
ADMIN_PERMISSION_NAMES = ["WORKSPACE_OWN", "WORKSPACE_ADMIN"]
CLOCKIFY_ENDPOINT = "https://api.clockify.me/api/"
diff --git a/openpype/modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/deadline/plugins/publish/submit_publish_job.py
index a2e21fb766..ea953441a2 100644
--- a/openpype/modules/deadline/plugins/publish/submit_publish_job.py
+++ b/openpype/modules/deadline/plugins/publish/submit_publish_job.py
@@ -102,7 +102,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
hosts = ["fusion", "maya", "nuke", "celaction", "aftereffects", "harmony"]
- families = ["render.farm", "prerender",
+ families = ["render.farm", "prerender.farm",
"renderlayer", "imagesequence", "vrayscene"]
aov_filter = {"maya": [r".+(?:\.|_)([Bb]eauty)(?:\.|_).*"],
diff --git a/openpype/modules/ftrack/event_handlers_server/action_prepare_project.py b/openpype/modules/ftrack/event_handlers_server/action_prepare_project.py
new file mode 100644
index 0000000000..8248bf532e
--- /dev/null
+++ b/openpype/modules/ftrack/event_handlers_server/action_prepare_project.py
@@ -0,0 +1,365 @@
+import json
+
+from openpype.api import ProjectSettings
+
+from openpype.modules.ftrack.lib import ServerAction
+from openpype.modules.ftrack.lib.avalon_sync import (
+ get_pype_attr,
+ CUST_ATTR_AUTO_SYNC
+)
+
+
+class PrepareProjectServer(ServerAction):
+ """Prepare project attributes in Anatomy."""
+
+ identifier = "prepare.project.server"
+ label = "OpenPype Admin"
+ variant = "- Prepare Project (Server)"
+ description = "Set basic attributes on the project"
+
+ settings_key = "prepare_project"
+
+ role_list = ["Pypeclub", "Administrator", "Project Manager"]
+
+ # Key to store info about trigerring create folder structure
+ item_splitter = {"type": "label", "value": "---"}
+
+ def discover(self, session, entities, event):
+ """Show only on project."""
+ if (
+ len(entities) != 1
+ or entities[0].entity_type.lower() != "project"
+ ):
+ return False
+
+ return self.valid_roles(session, entities, event)
+
+ def interface(self, session, entities, event):
+ if event['data'].get('values', {}):
+ return
+
+ # Inform user that this may take a while
+ self.show_message(event, "Preparing data... Please wait", True)
+ self.log.debug("Preparing data which will be shown")
+
+ self.log.debug("Loading custom attributes")
+
+ project_entity = entities[0]
+ project_name = project_entity["full_name"]
+
+ try:
+ project_settings = ProjectSettings(project_name)
+ except ValueError:
+ return {
+ "message": "Project is not synchronized yet",
+ "success": False
+ }
+
+ project_anatom_settings = project_settings["project_anatomy"]
+ root_items = self.prepare_root_items(project_anatom_settings)
+
+ ca_items, multiselect_enumerators = (
+ self.prepare_custom_attribute_items(project_anatom_settings)
+ )
+
+ self.log.debug("Heavy items are ready. Preparing last items group.")
+
+ title = "Prepare Project"
+ items = []
+
+ # Add root items
+ items.extend(root_items)
+
+ items.append(self.item_splitter)
+ items.append({
+ "type": "label",
+ "value": "
Set basic Attributes:
"
+ })
+
+ items.extend(ca_items)
+
+ # This item will be last (before enumerators)
+ # - sets value of auto synchronization
+ auto_sync_name = "avalon_auto_sync"
+ auto_sync_value = project_entity["custom_attributes"].get(
+ CUST_ATTR_AUTO_SYNC, False
+ )
+ auto_sync_item = {
+ "name": auto_sync_name,
+ "type": "boolean",
+ "value": auto_sync_value,
+ "label": "AutoSync to Avalon"
+ }
+ # Add autosync attribute
+ items.append(auto_sync_item)
+
+ # Add enumerator items at the end
+ for item in multiselect_enumerators:
+ items.append(item)
+
+ return {
+ "items": items,
+ "title": title
+ }
+
+ def prepare_root_items(self, project_anatom_settings):
+ self.log.debug("Root items preparation begins.")
+
+ root_items = []
+ root_items.append({
+ "type": "label",
+ "value": "Check your Project root settings
"
+ })
+ root_items.append({
+ "type": "label",
+ "value": (
+ "NOTE: Roots are crutial for path filling"
+ " (and creating folder structure).
"
+ )
+ })
+ root_items.append({
+ "type": "label",
+ "value": (
+ "WARNING: Do not change roots on running project,"
+ " that will cause workflow issues.
"
+ )
+ })
+
+ empty_text = "Enter root path here..."
+
+ roots_entity = project_anatom_settings["roots"]
+ for root_name, root_entity in roots_entity.items():
+ root_items.append(self.item_splitter)
+ root_items.append({
+ "type": "label",
+ "value": "Root: \"{}\"".format(root_name)
+ })
+ for platform_name, value_entity in root_entity.items():
+ root_items.append({
+ "label": platform_name,
+ "name": "__root__{}__{}".format(root_name, platform_name),
+ "type": "text",
+ "value": value_entity.value,
+ "empty_text": empty_text
+ })
+
+ root_items.append({
+ "type": "hidden",
+ "name": "__rootnames__",
+ "value": json.dumps(list(roots_entity.keys()))
+ })
+
+ self.log.debug("Root items preparation ended.")
+ return root_items
+
+ def _attributes_to_set(self, project_anatom_settings):
+ attributes_to_set = {}
+
+ attribute_values_by_key = {}
+ for key, entity in project_anatom_settings["attributes"].items():
+ attribute_values_by_key[key] = entity.value
+
+ cust_attrs, hier_cust_attrs = get_pype_attr(self.session, True)
+
+ for attr in hier_cust_attrs:
+ key = attr["key"]
+ if key.startswith("avalon_"):
+ continue
+ attributes_to_set[key] = {
+ "label": attr["label"],
+ "object": attr,
+ "default": attribute_values_by_key.get(key)
+ }
+
+ for attr in cust_attrs:
+ if attr["entity_type"].lower() != "show":
+ continue
+ key = attr["key"]
+ if key.startswith("avalon_"):
+ continue
+ attributes_to_set[key] = {
+ "label": attr["label"],
+ "object": attr,
+ "default": attribute_values_by_key.get(key)
+ }
+
+ # Sort by label
+ attributes_to_set = dict(sorted(
+ attributes_to_set.items(),
+ key=lambda x: x[1]["label"]
+ ))
+ return attributes_to_set
+
+ def prepare_custom_attribute_items(self, project_anatom_settings):
+ items = []
+ multiselect_enumerators = []
+ attributes_to_set = self._attributes_to_set(project_anatom_settings)
+
+ self.log.debug("Preparing interface for keys: \"{}\"".format(
+ str([key for key in attributes_to_set])
+ ))
+
+ for key, in_data in attributes_to_set.items():
+ attr = in_data["object"]
+
+ # initial item definition
+ item = {
+ "name": key,
+ "label": in_data["label"]
+ }
+
+ # cust attr type - may have different visualization
+ type_name = attr["type"]["name"].lower()
+ easy_types = ["text", "boolean", "date", "number"]
+
+ easy_type = False
+ if type_name in easy_types:
+ easy_type = True
+
+ elif type_name == "enumerator":
+
+ attr_config = json.loads(attr["config"])
+ attr_config_data = json.loads(attr_config["data"])
+
+ if attr_config["multiSelect"] is True:
+ multiselect_enumerators.append(self.item_splitter)
+ multiselect_enumerators.append({
+ "type": "label",
+ "value": in_data["label"]
+ })
+
+ default = in_data["default"]
+ names = []
+ for option in sorted(
+ attr_config_data, key=lambda x: x["menu"]
+ ):
+ name = option["value"]
+ new_name = "__{}__{}".format(key, name)
+ names.append(new_name)
+ item = {
+ "name": new_name,
+ "type": "boolean",
+ "label": "- {}".format(option["menu"])
+ }
+ if default:
+ if isinstance(default, (list, tuple)):
+ if name in default:
+ item["value"] = True
+ else:
+ if name == default:
+ item["value"] = True
+
+ multiselect_enumerators.append(item)
+
+ multiselect_enumerators.append({
+ "type": "hidden",
+ "name": "__hidden__{}".format(key),
+ "value": json.dumps(names)
+ })
+ else:
+ easy_type = True
+ item["data"] = attr_config_data
+
+ else:
+ self.log.warning((
+ "Custom attribute \"{}\" has type \"{}\"."
+ " I don't know how to handle"
+ ).format(key, type_name))
+ items.append({
+ "type": "label",
+ "value": (
+ "!!! Can't handle Custom attritubte type \"{}\""
+ " (key: \"{}\")"
+ ).format(type_name, key)
+ })
+
+ if easy_type:
+ item["type"] = type_name
+
+ # default value in interface
+ default = in_data["default"]
+ if default is not None:
+ item["value"] = default
+
+ items.append(item)
+
+ return items, multiselect_enumerators
+
+ def launch(self, session, entities, event):
+ if not event['data'].get('values', {}):
+ return
+
+ in_data = event['data']['values']
+
+ root_values = {}
+ root_key = "__root__"
+ for key in tuple(in_data.keys()):
+ if key.startswith(root_key):
+ _key = key[len(root_key):]
+ root_values[_key] = in_data.pop(key)
+
+ root_names = in_data.pop("__rootnames__", None)
+ root_data = {}
+ for root_name in json.loads(root_names):
+ root_data[root_name] = {}
+ for key, value in tuple(root_values.items()):
+ prefix = "{}__".format(root_name)
+ if not key.startswith(prefix):
+ continue
+
+ _key = key[len(prefix):]
+ root_data[root_name][_key] = value
+
+ # Find hidden items for multiselect enumerators
+ keys_to_process = []
+ for key in in_data:
+ if key.startswith("__hidden__"):
+ keys_to_process.append(key)
+
+ self.log.debug("Preparing data for Multiselect Enumerators")
+ enumerators = {}
+ for key in keys_to_process:
+ new_key = key.replace("__hidden__", "")
+ enumerator_items = in_data.pop(key)
+ enumerators[new_key] = json.loads(enumerator_items)
+
+ # find values set for multiselect enumerator
+ for key, enumerator_items in enumerators.items():
+ in_data[key] = []
+
+ name = "__{}__".format(key)
+
+ for item in enumerator_items:
+ value = in_data.pop(item)
+ if value is True:
+ new_key = item.replace(name, "")
+ in_data[key].append(new_key)
+
+ self.log.debug("Setting Custom Attribute values")
+
+ project_name = entities[0]["full_name"]
+ project_settings = ProjectSettings(project_name)
+ project_anatomy_settings = project_settings["project_anatomy"]
+ project_anatomy_settings["roots"] = root_data
+
+ custom_attribute_values = {}
+ attributes_entity = project_anatomy_settings["attributes"]
+ for key, value in in_data.items():
+ if key not in attributes_entity:
+ custom_attribute_values[key] = value
+ else:
+ attributes_entity[key] = value
+
+ project_settings.save()
+
+ entity = entities[0]
+ for key, value in custom_attribute_values.items():
+ entity["custom_attributes"][key] = value
+ self.log.debug("- Key \"{}\" set to \"{}\"".format(key, value))
+
+ return True
+
+
+def register(session):
+ '''Register plugin. Called when used as an plugin.'''
+ PrepareProjectServer(session).register()
diff --git a/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py b/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py
index 7f674310fc..bd25f995fe 100644
--- a/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py
+++ b/openpype/modules/ftrack/event_handlers_user/action_prepare_project.py
@@ -1,31 +1,34 @@
-import os
import json
-from openpype.modules.ftrack.lib import BaseAction, statics_icon
-from openpype.api import config, Anatomy
-from openpype.modules.ftrack.lib.avalon_sync import get_pype_attr
+from openpype.api import ProjectSettings
+
+from openpype.modules.ftrack.lib import (
+ BaseAction,
+ statics_icon
+)
+from openpype.modules.ftrack.lib.avalon_sync import (
+ get_pype_attr,
+ CUST_ATTR_AUTO_SYNC
+)
-class PrepareProject(BaseAction):
- '''Edit meta data action.'''
+class PrepareProjectLocal(BaseAction):
+ """Prepare project attributes in Anatomy."""
- #: Action identifier.
- identifier = 'prepare.project'
- #: Action label.
- label = 'Prepare Project'
- #: Action description.
- description = 'Set basic attributes on the project'
- #: roles that are allowed to register this action
+ identifier = "prepare.project.local"
+ label = "Prepare Project"
+ description = "Set basic attributes on the project"
icon = statics_icon("ftrack", "action_icons", "PrepareProject.svg")
+ role_list = ["Pypeclub", "Administrator", "Project Manager"]
+
settings_key = "prepare_project"
# Key to store info about trigerring create folder structure
- create_project_structure_key = "create_folder_structure"
- item_splitter = {'type': 'label', 'value': '---'}
+ item_splitter = {"type": "label", "value": "---"}
def discover(self, session, entities, event):
- ''' Validation '''
+ """Show only on project."""
if (
len(entities) != 1
or entities[0].entity_type.lower() != "project"
@@ -44,27 +47,22 @@ class PrepareProject(BaseAction):
self.log.debug("Loading custom attributes")
- project_name = entities[0]["full_name"]
+ project_entity = entities[0]
+ project_name = project_entity["full_name"]
- project_defaults = (
- config.get_presets(project_name)
- .get("ftrack", {})
- .get("project_defaults", {})
- )
-
- anatomy = Anatomy(project_name)
- if not anatomy.roots:
+ try:
+ project_settings = ProjectSettings(project_name)
+ except ValueError:
return {
- "success": False,
- "message": (
- "Have issues with loading Roots for project \"{}\"."
- ).format(anatomy.project_name)
+ "message": "Project is not synchronized yet",
+ "success": False
}
- root_items = self.prepare_root_items(anatomy)
+ project_anatom_settings = project_settings["project_anatomy"]
+ root_items = self.prepare_root_items(project_anatom_settings)
ca_items, multiselect_enumerators = (
- self.prepare_custom_attribute_items(project_defaults)
+ self.prepare_custom_attribute_items(project_anatom_settings)
)
self.log.debug("Heavy items are ready. Preparing last items group.")
@@ -74,19 +72,6 @@ class PrepareProject(BaseAction):
# Add root items
items.extend(root_items)
- items.append(self.item_splitter)
-
- # Ask if want to trigger Action Create Folder Structure
- items.append({
- "type": "label",
- "value": "Want to create basic Folder Structure?
"
- })
- items.append({
- "name": self.create_project_structure_key,
- "type": "boolean",
- "value": False,
- "label": "Check if Yes"
- })
items.append(self.item_splitter)
items.append({
@@ -99,10 +84,13 @@ class PrepareProject(BaseAction):
# This item will be last (before enumerators)
# - sets value of auto synchronization
auto_sync_name = "avalon_auto_sync"
+ auto_sync_value = project_entity["custom_attributes"].get(
+ CUST_ATTR_AUTO_SYNC, False
+ )
auto_sync_item = {
"name": auto_sync_name,
"type": "boolean",
- "value": project_defaults.get(auto_sync_name, False),
+ "value": auto_sync_value,
"label": "AutoSync to Avalon"
}
# Add autosync attribute
@@ -117,13 +105,10 @@ class PrepareProject(BaseAction):
"title": title
}
- def prepare_root_items(self, anatomy):
- root_items = []
+ def prepare_root_items(self, project_anatom_settings):
self.log.debug("Root items preparation begins.")
- root_names = anatomy.root_names()
- roots = anatomy.roots
-
+ root_items = []
root_items.append({
"type": "label",
"value": "Check your Project root settings
"
@@ -143,85 +128,40 @@ class PrepareProject(BaseAction):
)
})
- default_roots = anatomy.roots
- while isinstance(default_roots, dict):
- key = tuple(default_roots.keys())[0]
- default_roots = default_roots[key]
-
empty_text = "Enter root path here..."
- # Root names is None when anatomy templates contain "{root}"
- all_platforms = ["windows", "linux", "darwin"]
- if root_names is None:
- root_items.append(self.item_splitter)
- # find first possible key
- for platform in all_platforms:
- value = default_roots.raw_data.get(platform) or ""
- root_items.append({
- "label": platform,
- "name": "__root__{}".format(platform),
- "type": "text",
- "value": value,
- "empty_text": empty_text
- })
- return root_items
-
- root_name_data = {}
- missing_roots = []
- for root_name in root_names:
- root_name_data[root_name] = {}
- if not isinstance(roots, dict):
- missing_roots.append(root_name)
- continue
-
- root_item = roots.get(root_name)
- if not root_item:
- missing_roots.append(root_name)
- continue
-
- for platform in all_platforms:
- root_name_data[root_name][platform] = (
- root_item.raw_data.get(platform) or ""
- )
-
- if missing_roots:
- default_values = {}
- for platform in all_platforms:
- default_values[platform] = (
- default_roots.raw_data.get(platform) or ""
- )
-
- for root_name in missing_roots:
- root_name_data[root_name] = default_values
-
- root_names = list(root_name_data.keys())
- root_items.append({
- "type": "hidden",
- "name": "__rootnames__",
- "value": json.dumps(root_names)
- })
-
- for root_name, values in root_name_data.items():
+ roots_entity = project_anatom_settings["roots"]
+ for root_name, root_entity in roots_entity.items():
root_items.append(self.item_splitter)
root_items.append({
"type": "label",
"value": "Root: \"{}\"".format(root_name)
})
- for platform, value in values.items():
+ for platform_name, value_entity in root_entity.items():
root_items.append({
- "label": platform,
- "name": "__root__{}{}".format(root_name, platform),
+ "label": platform_name,
+ "name": "__root__{}__{}".format(root_name, platform_name),
"type": "text",
- "value": value,
+ "value": value_entity.value,
"empty_text": empty_text
})
+ root_items.append({
+ "type": "hidden",
+ "name": "__rootnames__",
+ "value": json.dumps(list(roots_entity.keys()))
+ })
+
self.log.debug("Root items preparation ended.")
return root_items
- def _attributes_to_set(self, project_defaults):
+ def _attributes_to_set(self, project_anatom_settings):
attributes_to_set = {}
+ attribute_values_by_key = {}
+ for key, entity in project_anatom_settings["attributes"].items():
+ attribute_values_by_key[key] = entity.value
+
cust_attrs, hier_cust_attrs = get_pype_attr(self.session, True)
for attr in hier_cust_attrs:
@@ -231,7 +171,7 @@ class PrepareProject(BaseAction):
attributes_to_set[key] = {
"label": attr["label"],
"object": attr,
- "default": project_defaults.get(key)
+ "default": attribute_values_by_key.get(key)
}
for attr in cust_attrs:
@@ -243,7 +183,7 @@ class PrepareProject(BaseAction):
attributes_to_set[key] = {
"label": attr["label"],
"object": attr,
- "default": project_defaults.get(key)
+ "default": attribute_values_by_key.get(key)
}
# Sort by label
@@ -253,10 +193,10 @@ class PrepareProject(BaseAction):
))
return attributes_to_set
- def prepare_custom_attribute_items(self, project_defaults):
+ def prepare_custom_attribute_items(self, project_anatom_settings):
items = []
multiselect_enumerators = []
- attributes_to_set = self._attributes_to_set(project_defaults)
+ attributes_to_set = self._attributes_to_set(project_anatom_settings)
self.log.debug("Preparing interface for keys: \"{}\"".format(
str([key for key in attributes_to_set])
@@ -363,24 +303,15 @@ class PrepareProject(BaseAction):
root_names = in_data.pop("__rootnames__", None)
root_data = {}
- if root_names:
- for root_name in json.loads(root_names):
- root_data[root_name] = {}
- for key, value in tuple(root_values.items()):
- if key.startswith(root_name):
- _key = key[len(root_name):]
- root_data[root_name][_key] = value
+ for root_name in json.loads(root_names):
+ root_data[root_name] = {}
+ for key, value in tuple(root_values.items()):
+ prefix = "{}__".format(root_name)
+ if not key.startswith(prefix):
+ continue
- else:
- for key, value in root_values.items():
- root_data[key] = value
-
- # TODO implement creating of anatomy for new projects
- # project_name = entities[0]["full_name"]
- # anatomy = Anatomy(project_name)
-
- # pop out info about creating project structure
- create_proj_struct = in_data.pop(self.create_project_structure_key)
+ _key = key[len(prefix):]
+ root_data[root_name][_key] = value
# Find hidden items for multiselect enumerators
keys_to_process = []
@@ -407,54 +338,31 @@ class PrepareProject(BaseAction):
new_key = item.replace(name, "")
in_data[key].append(new_key)
- self.log.debug("Setting Custom Attribute values:")
- entity = entities[0]
+ self.log.debug("Setting Custom Attribute values")
+
+ project_name = entities[0]["full_name"]
+ project_settings = ProjectSettings(project_name)
+ project_anatomy_settings = project_settings["project_anatomy"]
+ project_anatomy_settings["roots"] = root_data
+
+ custom_attribute_values = {}
+ attributes_entity = project_anatomy_settings["attributes"]
for key, value in in_data.items():
+ if key not in attributes_entity:
+ custom_attribute_values[key] = value
+ else:
+ attributes_entity[key] = value
+
+ project_settings.save()
+
+ entity = entities[0]
+ for key, value in custom_attribute_values.items():
entity["custom_attributes"][key] = value
self.log.debug("- Key \"{}\" set to \"{}\"".format(key, value))
- session.commit()
-
- # Create project structure
- self.create_project_specific_config(entities[0]["full_name"], in_data)
-
- # Trigger Create Project Structure action
- if create_proj_struct is True:
- self.trigger_action("create.project.structure", event)
-
return True
- def create_project_specific_config(self, project_name, json_data):
- self.log.debug("*** Creating project specifig configs ***")
- project_specific_path = project_overrides_dir_path(project_name)
- if not os.path.exists(project_specific_path):
- os.makedirs(project_specific_path)
- self.log.debug((
- "Project specific config folder for project \"{}\" created."
- ).format(project_name))
-
- # Presets ####################################
- self.log.debug("--- Processing Presets Begins: ---")
-
- project_defaults_dir = os.path.normpath(os.path.join(
- project_specific_path, "presets", "ftrack"
- ))
- project_defaults_path = os.path.normpath(os.path.join(
- project_defaults_dir, "project_defaults.json"
- ))
- # Create folder if not exist
- if not os.path.exists(project_defaults_dir):
- self.log.debug("Creating Ftrack Presets folder: \"{}\"".format(
- project_defaults_dir
- ))
- os.makedirs(project_defaults_dir)
-
- with open(project_defaults_path, 'w') as file_stream:
- json.dump(json_data, file_stream, indent=4)
-
- self.log.debug("*** Creating project specifig configs Finished ***")
-
def register(session):
'''Register plugin. Called when used as an plugin.'''
- PrepareProject(session).register()
+ PrepareProjectLocal(session).register()
diff --git a/openpype/modules/ftrack/ftrack_module.py b/openpype/modules/ftrack/ftrack_module.py
index e1af9c15a7..cd383cbdc6 100644
--- a/openpype/modules/ftrack/ftrack_module.py
+++ b/openpype/modules/ftrack/ftrack_module.py
@@ -210,3 +210,7 @@ class FtrackModule(
def tray_exit(self):
return self.tray_module.stop_action_server()
+
+ def set_credentials_to_env(self, username, api_key):
+ os.environ["FTRACK_API_USER"] = username or ""
+ os.environ["FTRACK_API_KEY"] = api_key or ""
diff --git a/openpype/modules/ftrack/lib/avalon_sync.py b/openpype/modules/ftrack/lib/avalon_sync.py
index 7511c2627b..79e1366a0d 100644
--- a/openpype/modules/ftrack/lib/avalon_sync.py
+++ b/openpype/modules/ftrack/lib/avalon_sync.py
@@ -891,6 +891,33 @@ class SyncEntitiesFactory:
self.entities_dict[parent_id]["children"].remove(id)
+ def _query_custom_attributes(self, session, conf_ids, entity_ids):
+ output = []
+ # Prepare values to query
+ attributes_joined = join_query_keys(conf_ids)
+ attributes_len = len(conf_ids)
+ chunk_size = int(5000 / attributes_len)
+ for idx in range(0, len(entity_ids), chunk_size):
+ entity_ids_joined = join_query_keys(
+ entity_ids[idx:idx + chunk_size]
+ )
+
+ call_expr = [{
+ "action": "query",
+ "expression": (
+ "select value, entity_id from ContextCustomAttributeValue "
+ "where entity_id in ({}) and configuration_id in ({})"
+ ).format(entity_ids_joined, attributes_joined)
+ }]
+ if hasattr(session, "call"):
+ [result] = session.call(call_expr)
+ else:
+ [result] = session._call(call_expr)
+
+ for item in result["data"]:
+ output.append(item)
+ return output
+
def set_cutom_attributes(self):
self.log.debug("* Preparing custom attributes")
# Get custom attributes and values
@@ -1000,31 +1027,13 @@ class SyncEntitiesFactory:
copy.deepcopy(prepared_avalon_attr_ca_id)
)
- # TODO query custom attributes by entity_id
- entity_ids_joined = ", ".join([
- "\"{}\"".format(id) for id in sync_ids
- ])
- attributes_joined = ", ".join([
- "\"{}\"".format(attr_id) for attr_id in attribute_key_by_id.keys()
- ])
-
- cust_attr_query = (
- "select value, configuration_id, entity_id"
- " from ContextCustomAttributeValue"
- " where entity_id in ({}) and configuration_id in ({})"
+ items = self._query_custom_attributes(
+ self.session,
+ list(attribute_key_by_id.keys()),
+ sync_ids
)
- call_expr = [{
- "action": "query",
- "expression": cust_attr_query.format(
- entity_ids_joined, attributes_joined
- )
- }]
- if hasattr(self.session, "call"):
- [values] = self.session.call(call_expr)
- else:
- [values] = self.session._call(call_expr)
- for item in values["data"]:
+ for item in items:
entity_id = item["entity_id"]
attr_id = item["configuration_id"]
key = attribute_key_by_id[attr_id]
@@ -1106,28 +1115,14 @@ class SyncEntitiesFactory:
for key, val in prepare_dict_avalon.items():
entity_dict["avalon_attrs"][key] = val
- # Prepare values to query
- entity_ids_joined = ", ".join([
- "\"{}\"".format(id) for id in sync_ids
- ])
- attributes_joined = ", ".join([
- "\"{}\"".format(attr_id) for attr_id in attribute_key_by_id.keys()
- ])
- avalon_hier = []
- call_expr = [{
- "action": "query",
- "expression": (
- "select value, entity_id, configuration_id"
- " from ContextCustomAttributeValue"
- " where entity_id in ({}) and configuration_id in ({})"
- ).format(entity_ids_joined, attributes_joined)
- }]
- if hasattr(self.session, "call"):
- [values] = self.session.call(call_expr)
- else:
- [values] = self.session._call(call_expr)
+ items = self._query_custom_attributes(
+ self.session,
+ list(attribute_key_by_id.keys()),
+ sync_ids
+ )
- for item in values["data"]:
+ avalon_hier = []
+ for item in items:
value = item["value"]
# WARNING It is not possible to propage enumerate hierachical
# attributes with multiselection 100% right. Unseting all values
@@ -1256,19 +1251,21 @@ class SyncEntitiesFactory:
if not msg or not items:
continue
self.report_items["warning"][msg] = items
- tasks = {}
- for task_type in task_types:
- task_type_name = task_type["name"]
- # Set short name to empty string
- # QUESTION Maybe better would be to lower and remove spaces
- # from task type name.
- tasks[task_type_name] = {
- "short_name": ""
- }
current_project_anatomy_data = get_anatomy_settings(
project_name, exclude_locals=True
)
+ anatomy_tasks = current_project_anatomy_data["tasks"]
+ tasks = {}
+ default_type_data = {
+ "short_name": ""
+ }
+ for task_type in task_types:
+ task_type_name = task_type["name"]
+ tasks[task_type_name] = copy.deepcopy(
+ anatomy_tasks.get(task_type_name)
+ or default_type_data
+ )
project_config = {
"tasks": tasks,
diff --git a/openpype/modules/ftrack/lib/credentials.py b/openpype/modules/ftrack/lib/credentials.py
index 16b1fb25fb..2d719347e7 100644
--- a/openpype/modules/ftrack/lib/credentials.py
+++ b/openpype/modules/ftrack/lib/credentials.py
@@ -1,23 +1,16 @@
import os
-import json
import ftrack_api
-import appdirs
-import getpass
+
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
-CONFIG_PATH = os.path.normpath(appdirs.user_data_dir("pype-app", "pype"))
-CREDENTIALS_FILE_NAME = "ftrack_cred.json"
-CREDENTIALS_PATH = os.path.join(CONFIG_PATH, CREDENTIALS_FILE_NAME)
-CREDENTIALS_FOLDER = os.path.dirname(CREDENTIALS_PATH)
+from openpype.lib import OpenPypeSecureRegistry
-if not os.path.isdir(CREDENTIALS_FOLDER):
- os.makedirs(CREDENTIALS_FOLDER)
-
-USER_GETTER = None
+USERNAME_KEY = "username"
+API_KEY_KEY = "api_key"
def get_ftrack_hostname(ftrack_server=None):
@@ -30,112 +23,73 @@ def get_ftrack_hostname(ftrack_server=None):
return urlparse(ftrack_server).hostname
-def get_user():
- if USER_GETTER:
- return USER_GETTER()
- return getpass.getuser()
+def _get_ftrack_secure_key(hostname, key):
+ """Secure item key for entered hostname."""
+ return "/".join(("ftrack", hostname, key))
-def get_credentials(ftrack_server=None, user=None):
- credentials = {}
- if not os.path.exists(CREDENTIALS_PATH):
- with open(CREDENTIALS_PATH, "w") as file:
- file.write(json.dumps(credentials))
- file.close()
- return credentials
-
- with open(CREDENTIALS_PATH, "r") as file:
- content = file.read()
-
+def get_credentials(ftrack_server=None):
hostname = get_ftrack_hostname(ftrack_server)
- if not user:
- user = get_user()
+ username_name = _get_ftrack_secure_key(hostname, USERNAME_KEY)
+ api_key_name = _get_ftrack_secure_key(hostname, API_KEY_KEY)
- content_json = json.loads(content or "{}")
- credentials = content_json.get(hostname, {}).get(user) or {}
+ username_registry = OpenPypeSecureRegistry(username_name)
+ api_key_registry = OpenPypeSecureRegistry(api_key_name)
- return credentials
-
-
-def save_credentials(ft_user, ft_api_key, ftrack_server=None, user=None):
- hostname = get_ftrack_hostname(ftrack_server)
- if not user:
- user = get_user()
-
- with open(CREDENTIALS_PATH, "r") as file:
- content = file.read()
-
- content_json = json.loads(content or "{}")
- if hostname not in content_json:
- content_json[hostname] = {}
-
- content_json[hostname][user] = {
- "username": ft_user,
- "api_key": ft_api_key
+ return {
+ USERNAME_KEY: username_registry.get_item(USERNAME_KEY, None),
+ API_KEY_KEY: api_key_registry.get_item(API_KEY_KEY, None)
}
- # Deprecated keys
- if "username" in content_json:
- content_json.pop("username")
- if "apiKey" in content_json:
- content_json.pop("apiKey")
-
- with open(CREDENTIALS_PATH, "w") as file:
- file.write(json.dumps(content_json, indent=4))
-
-
-def clear_credentials(ft_user=None, ftrack_server=None, user=None):
- if not ft_user:
- ft_user = os.environ.get("FTRACK_API_USER")
-
- if not ft_user:
- return
+def save_credentials(username, api_key, ftrack_server=None):
hostname = get_ftrack_hostname(ftrack_server)
- if not user:
- user = get_user()
+ username_name = _get_ftrack_secure_key(hostname, USERNAME_KEY)
+ api_key_name = _get_ftrack_secure_key(hostname, API_KEY_KEY)
- with open(CREDENTIALS_PATH, "r") as file:
- content = file.read()
+ # Clear credentials
+ clear_credentials(ftrack_server)
- content_json = json.loads(content or "{}")
- if hostname not in content_json:
- content_json[hostname] = {}
+ username_registry = OpenPypeSecureRegistry(username_name)
+ api_key_registry = OpenPypeSecureRegistry(api_key_name)
- content_json[hostname].pop(user, None)
-
- with open(CREDENTIALS_PATH, "w") as file:
- file.write(json.dumps(content_json))
+ username_registry.set_item(USERNAME_KEY, username)
+ api_key_registry.set_item(API_KEY_KEY, api_key)
-def set_env(ft_user=None, ft_api_key=None):
- os.environ["FTRACK_API_USER"] = ft_user or ""
- os.environ["FTRACK_API_KEY"] = ft_api_key or ""
+def clear_credentials(ftrack_server=None):
+ hostname = get_ftrack_hostname(ftrack_server)
+ username_name = _get_ftrack_secure_key(hostname, USERNAME_KEY)
+ api_key_name = _get_ftrack_secure_key(hostname, API_KEY_KEY)
+
+ username_registry = OpenPypeSecureRegistry(username_name)
+ api_key_registry = OpenPypeSecureRegistry(api_key_name)
+
+ current_username = username_registry.get_item(USERNAME_KEY, None)
+ current_api_key = api_key_registry.get_item(API_KEY_KEY, None)
+
+ if current_username is not None:
+ username_registry.delete_item(USERNAME_KEY)
+
+ if current_api_key is not None:
+ api_key_registry.delete_item(API_KEY_KEY)
-def get_env_credentials():
- return (
- os.environ.get("FTRACK_API_USER"),
- os.environ.get("FTRACK_API_KEY")
- )
-
-
-def check_credentials(ft_user, ft_api_key, ftrack_server=None):
+def check_credentials(username, api_key, ftrack_server=None):
if not ftrack_server:
ftrack_server = os.environ["FTRACK_SERVER"]
- if not ft_user or not ft_api_key:
+ if not username or not api_key:
return False
try:
session = ftrack_api.Session(
server_url=ftrack_server,
- api_key=ft_api_key,
- api_user=ft_user
+ api_key=api_key,
+ api_user=username
)
session.close()
except Exception:
return False
-
return True
diff --git a/openpype/modules/ftrack/lib/settings.py b/openpype/modules/ftrack/lib/settings.py
index f6967411db..027356edc6 100644
--- a/openpype/modules/ftrack/lib/settings.py
+++ b/openpype/modules/ftrack/lib/settings.py
@@ -1,6 +1,7 @@
import os
from openpype.api import get_system_settings
+
def get_ftrack_settings():
return get_system_settings()["modules"]["ftrack"]
@@ -10,7 +11,6 @@ def get_ftrack_url_from_settings():
def get_ftrack_event_mongo_info():
- ftrack_settings = get_ftrack_settings()
database_name = os.environ["OPENPYPE_DATABASE_NAME"]
collection_name = "ftrack_events"
return database_name, collection_name
diff --git a/openpype/modules/ftrack/tray/ftrack_tray.py b/openpype/modules/ftrack/tray/ftrack_tray.py
index 9da5db835b..ee27d8b730 100644
--- a/openpype/modules/ftrack/tray/ftrack_tray.py
+++ b/openpype/modules/ftrack/tray/ftrack_tray.py
@@ -30,7 +30,7 @@ class FtrackTrayWrapper:
self.bool_action_thread_running = False
self.bool_timer_event = False
- self.widget_login = login_dialog.CredentialsDialog()
+ self.widget_login = login_dialog.CredentialsDialog(module)
self.widget_login.login_changed.connect(self.on_login_change)
self.widget_login.logout_signal.connect(self.on_logout)
@@ -56,7 +56,7 @@ class FtrackTrayWrapper:
validation = credentials.check_credentials(ft_user, ft_api_key)
if validation:
self.widget_login.set_credentials(ft_user, ft_api_key)
- credentials.set_env(ft_user, ft_api_key)
+ self.module.set_credentials_to_env(ft_user, ft_api_key)
log.info("Connected to Ftrack successfully")
self.on_login_change()
@@ -337,7 +337,7 @@ class FtrackTrayWrapper:
def changed_user(self):
self.stop_action_server()
- credentials.set_env()
+ self.module.set_credentials_to_env(None, None)
self.validate()
def start_timer_manager(self, data):
diff --git a/openpype/modules/ftrack/tray/login_dialog.py b/openpype/modules/ftrack/tray/login_dialog.py
index ca409ebcaa..ce91c6d012 100644
--- a/openpype/modules/ftrack/tray/login_dialog.py
+++ b/openpype/modules/ftrack/tray/login_dialog.py
@@ -14,11 +14,13 @@ class CredentialsDialog(QtWidgets.QDialog):
login_changed = QtCore.Signal()
logout_signal = QtCore.Signal()
- def __init__(self, parent=None):
+ def __init__(self, module, parent=None):
super(CredentialsDialog, self).__init__(parent)
self.setWindowTitle("OpenPype - Ftrack Login")
+ self._module = module
+
self._login_server_thread = None
self._is_logged = False
self._in_advance_mode = False
@@ -268,7 +270,7 @@ class CredentialsDialog(QtWidgets.QDialog):
verification = credentials.check_credentials(username, api_key)
if verification:
credentials.save_credentials(username, api_key, False)
- credentials.set_env(username, api_key)
+ self._module.set_credentials_to_env(username, api_key)
self.set_credentials(username, api_key)
self.login_changed.emit()
return verification
diff --git a/openpype/plugins/publish/collect_hierarchy.py b/openpype/plugins/publish/collect_hierarchy.py
index 5c5dbf018c..390ce443b6 100644
--- a/openpype/plugins/publish/collect_hierarchy.py
+++ b/openpype/plugins/publish/collect_hierarchy.py
@@ -40,7 +40,7 @@ class CollectHierarchy(pyblish.api.ContextPlugin):
continue
# exclude if not masterLayer True
- if not instance.data.get("masterLayer"):
+ if not instance.data.get("heroTrack"):
continue
# get asset build data if any available
@@ -50,7 +50,7 @@ class CollectHierarchy(pyblish.api.ContextPlugin):
# suppose that all instances are Shots
shot_data['entity_type'] = 'Shot'
- shot_data['tasks'] = instance.data.get("tasks") or []
+ shot_data['tasks'] = instance.data.get("tasks") or {}
shot_data["comments"] = instance.data.get("comments", [])
shot_data['custom_attributes'] = {
diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json
index 03ac8f309f..04f2842b93 100644
--- a/openpype/settings/defaults/project_settings/ftrack.json
+++ b/openpype/settings/defaults/project_settings/ftrack.json
@@ -7,6 +7,14 @@
"not ready"
]
},
+ "prepare_project": {
+ "enabled": true,
+ "role_list": [
+ "Pypeclub",
+ "Administrator",
+ "Project manager"
+ ]
+ },
"sync_hier_entity_attributes": {
"enabled": true,
"interest_entity_types": [
diff --git a/openpype/settings/defaults/project_settings/tvpaint.json b/openpype/settings/defaults/project_settings/tvpaint.json
new file mode 100644
index 0000000000..d4130c88be
--- /dev/null
+++ b/openpype/settings/defaults/project_settings/tvpaint.json
@@ -0,0 +1,10 @@
+{
+ "publish": {
+ "ValidateMissingLayers": {
+ "enabled": true,
+ "optional": true,
+ "active": true
+ }
+ },
+ "filters": {}
+}
\ No newline at end of file
diff --git a/openpype/settings/entities/schemas/projects_schema/schema_main.json b/openpype/settings/entities/schemas/projects_schema/schema_main.json
index 565500edd2..6bc158aa60 100644
--- a/openpype/settings/entities/schemas/projects_schema/schema_main.json
+++ b/openpype/settings/entities/schemas/projects_schema/schema_main.json
@@ -82,6 +82,10 @@
"type": "schema",
"name": "schema_project_harmony"
},
+ {
+ "type": "schema",
+ "name": "schema_project_tvpaint"
+ },
{
"type": "schema",
"name": "schema_project_celaction"
diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json
index eefc0e12b7..a801175031 100644
--- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json
+++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json
@@ -36,6 +36,25 @@
}
]
},
+ {
+ "type": "dict",
+ "key": "prepare_project",
+ "label": "Prepare Project",
+ "checkbox_key": "enabled",
+ "children": [
+ {
+ "type": "boolean",
+ "key": "enabled",
+ "label": "Enabled"
+ },
+ {
+ "type": "list",
+ "key": "role_list",
+ "label": "Roles",
+ "object_type": "text"
+ }
+ ]
+ },
{
"type": "dict",
"key": "sync_hier_entity_attributes",
diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_tvpaint.json b/openpype/settings/entities/schemas/projects_schema/schema_project_tvpaint.json
new file mode 100644
index 0000000000..b9fe26a57c
--- /dev/null
+++ b/openpype/settings/entities/schemas/projects_schema/schema_project_tvpaint.json
@@ -0,0 +1,32 @@
+{
+ "type": "dict",
+ "collapsible": true,
+ "key": "tvpaint",
+ "label": "TVPaint",
+ "is_file": true,
+ "children": [
+ {
+ "type": "dict",
+ "collapsible": true,
+ "key": "publish",
+ "label": "Publish plugins",
+ "is_file": true,
+ "children": [
+ {
+ "type": "schema_template",
+ "name": "template_publish_plugin",
+ "template_data": [
+ {
+ "key": "ValidateMissingLayers",
+ "label": "ValidateMissingLayers"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "schema",
+ "name": "schema_publish_gui_filter"
+ }
+ ]
+}
diff --git a/openpype/tools/settings/local_settings/general_widget.py b/openpype/tools/settings/local_settings/general_widget.py
index 7732157122..e820d8ab8b 100644
--- a/openpype/tools/settings/local_settings/general_widget.py
+++ b/openpype/tools/settings/local_settings/general_widget.py
@@ -5,28 +5,16 @@ class LocalGeneralWidgets(QtWidgets.QWidget):
def __init__(self, parent):
super(LocalGeneralWidgets, self).__init__(parent)
- local_site_name_input = QtWidgets.QLineEdit(self)
-
- layout = QtWidgets.QFormLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
-
- layout.addRow("Local site label", local_site_name_input)
-
- self.local_site_name_input = local_site_name_input
def update_local_settings(self, value):
- site_label = ""
- if value:
- site_label = value.get("site_label", site_label)
- self.local_site_name_input.setText(site_label)
+ return
+
+ # RETURNING EARLY TO HIDE WIDGET WITHOUT CONTENT
def settings_value(self):
# Add changed
# If these have changed then
output = {}
- local_site_name = self.local_site_name_input.text()
- if local_site_name:
- output["site_label"] = local_site_name
- # Do not return output yet since we don't have mechanism to save or
- # load these data through api calls
+ # TEMPORARILY EMPTY AS THERE IS NOTHING TO PUT HERE
+
return output
diff --git a/openpype/tools/settings/local_settings/window.py b/openpype/tools/settings/local_settings/window.py
index b6ca56d348..a12a2289b5 100644
--- a/openpype/tools/settings/local_settings/window.py
+++ b/openpype/tools/settings/local_settings/window.py
@@ -80,6 +80,7 @@ class LocalSettingsWidget(QtWidgets.QWidget):
general_widget = LocalGeneralWidgets(general_content)
general_layout.addWidget(general_widget)
+ general_expand_widget.hide()
self.main_layout.addWidget(general_expand_widget)
@@ -126,9 +127,9 @@ class LocalSettingsWidget(QtWidgets.QWidget):
self.system_settings.reset()
self.project_settings.reset()
- self.general_widget.update_local_settings(
- value.get(LOCAL_GENERAL_KEY)
- )
+ # self.general_widget.update_local_settings(
+ # value.get(LOCAL_GENERAL_KEY)
+ # )
self.app_widget.update_local_settings(
value.get(LOCAL_APPS_KEY)
)
@@ -138,9 +139,9 @@ class LocalSettingsWidget(QtWidgets.QWidget):
def settings_value(self):
output = {}
- general_value = self.general_widget.settings_value()
- if general_value:
- output[LOCAL_GENERAL_KEY] = general_value
+ # general_value = self.general_widget.settings_value()
+ # if general_value:
+ # output[LOCAL_GENERAL_KEY] = general_value
app_value = self.app_widget.settings_value()
if app_value:
diff --git a/openpype/tools/tray/pype_info_widget.py b/openpype/tools/tray/pype_info_widget.py
index dbff36eca7..a70a360378 100644
--- a/openpype/tools/tray/pype_info_widget.py
+++ b/openpype/tools/tray/pype_info_widget.py
@@ -363,7 +363,7 @@ class PypeInfoWidget(QtWidgets.QWidget):
"version_value": "OpenPype version:",
"executable": "OpenPype executable:",
"pype_root": "OpenPype location:",
- "mongo_url": "OpenPype Mongo URL:"
+ "mongo_url": "OpenPype Mongo URL:"
}
# Prepare keys order
keys_order = ["version_value", "executable", "pype_root", "mongo_url"]
diff --git a/poetry.lock b/poetry.lock
index 6695a7bcca..767aeee500 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -80,7 +80,7 @@ python-dateutil = ">=2.7.0"
[[package]]
name = "astroid"
-version = "2.5.1"
+version = "2.5.2"
description = "An abstract syntax tree for Python with inference support."
category = "dev"
optional = false
@@ -123,14 +123,14 @@ tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>
[[package]]
name = "autopep8"
-version = "1.5.5"
+version = "1.5.6"
description = "A tool that automatically formats Python code to conform to the PEP 8 style guide"
category = "dev"
optional = false
python-versions = "*"
[package.dependencies]
-pycodestyle = ">=2.6.0"
+pycodestyle = ">=2.7.0"
toml = "*"
[[package]]
@@ -232,6 +232,14 @@ python-versions = "*"
[package.extras]
test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
+[[package]]
+name = "coolname"
+version = "1.1.0"
+description = "Random name and slug generator"
+category = "main"
+optional = false
+python-versions = "*"
+
[[package]]
name = "coverage"
version = "5.5"
@@ -245,7 +253,7 @@ toml = ["toml"]
[[package]]
name = "cryptography"
-version = "3.4.6"
+version = "3.4.7"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
category = "main"
optional = false
@@ -290,7 +298,7 @@ trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"]
[[package]]
name = "docutils"
-version = "0.16"
+version = "0.17"
description = "Docutils -- Python Documentation Utilities"
category = "dev"
optional = false
@@ -306,17 +314,17 @@ python-versions = "*"
[[package]]
name = "flake8"
-version = "3.8.4"
+version = "3.9.0"
description = "the modular source code checker: pep8 pyflakes and co"
category = "dev"
optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[package.dependencies]
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
mccabe = ">=0.6.0,<0.7.0"
-pycodestyle = ">=2.6.0a1,<2.7.0"
-pyflakes = ">=2.2.0,<2.3.0"
+pycodestyle = ">=2.7.0,<2.8.0"
+pyflakes = ">=2.3.0,<2.4.0"
[[package]]
name = "ftrack-python-api"
@@ -346,7 +354,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "google-api-core"
-version = "1.26.1"
+version = "1.26.3"
description = "Google API client core library"
category = "main"
optional = false
@@ -384,7 +392,7 @@ uritemplate = ">=3.0.0,<4dev"
[[package]]
name = "google-auth"
-version = "1.27.1"
+version = "1.28.0"
description = "Google Authentication Library"
category = "main"
optional = false
@@ -429,7 +437,7 @@ grpc = ["grpcio (>=1.0.0)"]
[[package]]
name = "httplib2"
-version = "0.19.0"
+version = "0.19.1"
description = "A comprehensive HTTP client library."
category = "main"
optional = false
@@ -456,7 +464,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "importlib-metadata"
-version = "3.7.2"
+version = "3.10.0"
description = "Read metadata from Python packages"
category = "main"
optional = false
@@ -468,7 +476,7 @@ zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
[[package]]
name = "iniconfig"
@@ -480,7 +488,7 @@ python-versions = "*"
[[package]]
name = "isort"
-version = "5.7.0"
+version = "5.8.0"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
@@ -579,11 +587,11 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt
[[package]]
name = "lazy-object-proxy"
-version = "1.5.2"
+version = "1.6.0"
description = "A fast and thorough lazy object proxy."
category = "dev"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[[package]]
name = "log4mongo"
@@ -653,7 +661,7 @@ pyparsing = ">=2.0.2"
[[package]]
name = "parso"
-version = "0.8.1"
+version = "0.8.2"
description = "A Python Parser"
category = "dev"
optional = false
@@ -676,7 +684,7 @@ six = "*"
[[package]]
name = "pillow"
-version = "8.1.2"
+version = "8.2.0"
description = "Python Imaging Library (Fork)"
category = "main"
optional = false
@@ -698,7 +706,7 @@ dev = ["pre-commit", "tox"]
[[package]]
name = "protobuf"
-version = "3.15.6"
+version = "3.15.7"
description = "Protocol Buffers"
category = "main"
optional = false
@@ -752,7 +760,7 @@ python-versions = "*"
[[package]]
name = "pycodestyle"
-version = "2.6.0"
+version = "2.7.0"
description = "Python style guide checker"
category = "dev"
optional = false
@@ -780,7 +788,7 @@ snowballstemmer = "*"
[[package]]
name = "pyflakes"
-version = "2.2.0"
+version = "2.3.1"
description = "passive checker of Python programs"
category = "dev"
optional = false
@@ -796,14 +804,14 @@ python-versions = ">=3.5"
[[package]]
name = "pylint"
-version = "2.7.2"
+version = "2.7.4"
description = "python code static checker"
category = "dev"
optional = false
python-versions = "~=3.6"
[package.dependencies]
-astroid = ">=2.5.1,<2.6"
+astroid = ">=2.5.2,<2.7"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
isort = ">=4.2.5,<6"
mccabe = ">=0.6,<0.7"
@@ -921,7 +929,7 @@ python-versions = ">=3.5"
[[package]]
name = "pytest"
-version = "6.2.2"
+version = "6.2.3"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
@@ -1112,7 +1120,7 @@ python-versions = "*"
[[package]]
name = "sphinx"
-version = "3.5.2"
+version = "3.5.3"
description = "Python documentation generator"
category = "dev"
optional = false
@@ -1271,7 +1279,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "tqdm"
-version = "4.59.0"
+version = "4.60.0"
description = "Fast, Extensible Progress Meter"
category = "dev"
optional = false
@@ -1308,16 +1316,16 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "urllib3"
-version = "1.26.3"
+version = "1.26.4"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
[package.extras]
-brotli = ["brotlipy (>=0.6.0)"]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+brotli = ["brotlipy (>=0.6.0)"]
[[package]]
name = "wcwidth"
@@ -1348,7 +1356,7 @@ python-versions = "*"
[[package]]
name = "wsrpc-aiohttp"
-version = "3.1.1"
+version = "3.1.2"
description = "WSRPC is the RPC over WebSocket for aiohttp"
category = "main"
optional = false
@@ -1391,7 +1399,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt
[metadata]
lock-version = "1.1"
python-versions = "3.7.*"
-content-hash = "4905515073ad2bf2a8517d513d68e48669b6a829f24e540b2dd60bc70cbea26b"
+content-hash = "a8c9915ce3096b74b9328a632911a759780844d368fa1d6d0fbd7c5d7d4536cf"
[metadata.files]
acre = []
@@ -1455,8 +1463,8 @@ arrow = [
{file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"},
]
astroid = [
- {file = "astroid-2.5.1-py3-none-any.whl", hash = "sha256:21d735aab248253531bb0f1e1e6d068f0ee23533e18ae8a6171ff892b98297cf"},
- {file = "astroid-2.5.1.tar.gz", hash = "sha256:cfc35498ee64017be059ceffab0a25bedf7548ab76f2bea691c5565896e7128d"},
+ {file = "astroid-2.5.2-py3-none-any.whl", hash = "sha256:cd80bf957c49765dce6d92c43163ff9d2abc43132ce64d4b1b47717c6d2522df"},
+ {file = "astroid-2.5.2.tar.gz", hash = "sha256:6b0ed1af831570e500e2437625979eaa3b36011f66ddfc4ce930128610258ca9"},
]
async-timeout = [
{file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"},
@@ -1471,8 +1479,8 @@ attrs = [
{file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"},
]
autopep8 = [
- {file = "autopep8-1.5.5-py2.py3-none-any.whl", hash = "sha256:9e136c472c475f4ee4978b51a88a494bfcd4e3ed17950a44a988d9e434837bea"},
- {file = "autopep8-1.5.5.tar.gz", hash = "sha256:cae4bc0fb616408191af41d062d7ec7ef8679c7f27b068875ca3a9e2878d5443"},
+ {file = "autopep8-1.5.6-py2.py3-none-any.whl", hash = "sha256:f01b06a6808bc31698db907761e5890eb2295e287af53f6693b39ce55454034a"},
+ {file = "autopep8-1.5.6.tar.gz", hash = "sha256:5454e6e9a3d02aae38f866eec0d9a7de4ab9f93c10a273fb0340f3d6d09f7514"},
]
babel = [
{file = "Babel-2.9.0-py2.py3-none-any.whl", hash = "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5"},
@@ -1549,6 +1557,10 @@ commonmark = [
{file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
{file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
]
+coolname = [
+ {file = "coolname-1.1.0-py2.py3-none-any.whl", hash = "sha256:e6a83a0ac88640f4f3d2070438dbe112fe80cfebc119c93bd402976ec84c0978"},
+ {file = "coolname-1.1.0.tar.gz", hash = "sha256:410fe6ea9999bf96f2856ef0c726d5f38782bbefb7bb1aca0e91e0dc98ed09e3"},
+]
coverage = [
{file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"},
{file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"},
@@ -1604,18 +1616,18 @@ coverage = [
{file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"},
]
cryptography = [
- {file = "cryptography-3.4.6-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799"},
- {file = "cryptography-3.4.6-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7"},
- {file = "cryptography-3.4.6-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3"},
- {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b"},
- {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"},
- {file = "cryptography-3.4.6-cp36-abi3-win32.whl", hash = "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2"},
- {file = "cryptography-3.4.6-cp36-abi3-win_amd64.whl", hash = "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0"},
- {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b"},
- {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df"},
- {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336"},
- {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724"},
- {file = "cryptography-3.4.6.tar.gz", hash = "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87"},
+ {file = "cryptography-3.4.7-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1"},
+ {file = "cryptography-3.4.7-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250"},
+ {file = "cryptography-3.4.7-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2"},
+ {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6"},
+ {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959"},
+ {file = "cryptography-3.4.7-cp36-abi3-win32.whl", hash = "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d"},
+ {file = "cryptography-3.4.7-cp36-abi3-win_amd64.whl", hash = "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca"},
+ {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873"},
+ {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d"},
+ {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177"},
+ {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"},
+ {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"},
]
cx-freeze = [
{file = "cx_Freeze-6.5.3-cp36-cp36m-win32.whl", hash = "sha256:0a1babae574546b622303da53e1a9829aa3a7e53e62b41eb260250220f83164b"},
@@ -1633,15 +1645,15 @@ dnspython = [
{file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"},
]
docutils = [
- {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"},
- {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"},
+ {file = "docutils-0.17-py2.py3-none-any.whl", hash = "sha256:a71042bb7207c03d5647f280427f14bfbd1a65c9eb84f4b341d85fafb6bb4bdf"},
+ {file = "docutils-0.17.tar.gz", hash = "sha256:e2ffeea817964356ba4470efba7c2f42b6b0de0b04e66378507e3e2504bbff4c"},
]
evdev = [
{file = "evdev-1.4.0.tar.gz", hash = "sha256:8782740eb1a86b187334c07feb5127d3faa0b236e113206dfe3ae8f77fb1aaf1"},
]
flake8 = [
- {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"},
- {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"},
+ {file = "flake8-3.9.0-py2.py3-none-any.whl", hash = "sha256:12d05ab02614b6aee8df7c36b97d1a3b2372761222b19b58621355e82acddcff"},
+ {file = "flake8-3.9.0.tar.gz", hash = "sha256:78873e372b12b093da7b5e5ed302e8ad9e988b38b063b61ad937f26ca58fc5f0"},
]
ftrack-python-api = [
{file = "ftrack-python-api-2.0.0.tar.gz", hash = "sha256:dd6f02c31daf5a10078196dc9eac4671e4297c762fbbf4df98de668ac12281d9"},
@@ -1651,16 +1663,16 @@ future = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
]
google-api-core = [
- {file = "google-api-core-1.26.1.tar.gz", hash = "sha256:23b0df512c4cc8729793f8992edb350e3211f5fd0ec007afb1599864b421beef"},
- {file = "google_api_core-1.26.1-py2.py3-none-any.whl", hash = "sha256:c383206f0f87545d3e658c4f8dc3b18a8457610fdbd791a15757c5b42d1e0e7f"},
+ {file = "google-api-core-1.26.3.tar.gz", hash = "sha256:b914345c7ea23861162693a27703bab804a55504f7e6e9abcaff174d80df32ac"},
+ {file = "google_api_core-1.26.3-py2.py3-none-any.whl", hash = "sha256:099762d4b4018cd536bcf85136bf337957da438807572db52f21dc61251be089"},
]
google-api-python-client = [
{file = "google-api-python-client-1.12.8.tar.gz", hash = "sha256:f3b9684442eec2cfe9f9bb48e796ef919456b82142c7528c5fd527e5224f08bb"},
{file = "google_api_python_client-1.12.8-py2.py3-none-any.whl", hash = "sha256:3c4c4ca46b5c21196bec7ee93453443e477d82cbfa79234d1ce0645f81170eaf"},
]
google-auth = [
- {file = "google-auth-1.27.1.tar.gz", hash = "sha256:d8958af6968e4ecd599f82357ebcfeb126f826ed0656126ad68416f810f7531e"},
- {file = "google_auth-1.27.1-py2.py3-none-any.whl", hash = "sha256:63a5636d7eacfe6ef5b7e36e112b3149fa1c5b5ad77dd6df54910459bcd6b89f"},
+ {file = "google-auth-1.28.0.tar.gz", hash = "sha256:9bd436d19ab047001a1340720d2b629eb96dd503258c524921ec2af3ee88a80e"},
+ {file = "google_auth-1.28.0-py2.py3-none-any.whl", hash = "sha256:dcaba3aa9d4e0e96fd945bf25a86b6f878fcb05770b67adbeb50a63ca4d28a5e"},
]
google-auth-httplib2 = [
{file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"},
@@ -1671,8 +1683,8 @@ googleapis-common-protos = [
{file = "googleapis_common_protos-1.53.0-py2.py3-none-any.whl", hash = "sha256:f6d561ab8fb16b30020b940e2dd01cd80082f4762fa9f3ee670f4419b4b8dbd0"},
]
httplib2 = [
- {file = "httplib2-0.19.0-py3-none-any.whl", hash = "sha256:749c32603f9bf16c1277f59531d502e8f1c2ca19901ae653b49c4ed698f0820e"},
- {file = "httplib2-0.19.0.tar.gz", hash = "sha256:e0d428dad43c72dbce7d163b7753ffc7a39c097e6788ef10f4198db69b92f08e"},
+ {file = "httplib2-0.19.1-py3-none-any.whl", hash = "sha256:2ad195faf9faf079723f6714926e9a9061f694d07724b846658ce08d40f522b4"},
+ {file = "httplib2-0.19.1.tar.gz", hash = "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d"},
]
idna = [
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
@@ -1683,16 +1695,16 @@ imagesize = [
{file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"},
]
importlib-metadata = [
- {file = "importlib_metadata-3.7.2-py3-none-any.whl", hash = "sha256:407d13f55dc6f2a844e62325d18ad7019a436c4bfcaee34cda35f2be6e7c3e34"},
- {file = "importlib_metadata-3.7.2.tar.gz", hash = "sha256:18d5ff601069f98d5d605b6a4b50c18a34811d655c55548adc833e687289acde"},
+ {file = "importlib_metadata-3.10.0-py3-none-any.whl", hash = "sha256:d2d46ef77ffc85cbf7dac7e81dd663fde71c45326131bea8033b9bad42268ebe"},
+ {file = "importlib_metadata-3.10.0.tar.gz", hash = "sha256:c9db46394197244adf2f0b08ec5bc3cf16757e9590b02af1fca085c16c0d600a"},
]
iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
isort = [
- {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"},
- {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"},
+ {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"},
+ {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"},
]
jedi = [
{file = "jedi-0.13.3-py2.py3-none-any.whl", hash = "sha256:2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c"},
@@ -1719,30 +1731,28 @@ keyring = [
{file = "keyring-22.4.0.tar.gz", hash = "sha256:d981e02d134cc3d636a716fbc3ca967bc9609bae5dc21b0063e4409355993ddf"},
]
lazy-object-proxy = [
- {file = "lazy-object-proxy-1.5.2.tar.gz", hash = "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4"},
- {file = "lazy_object_proxy-1.5.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315"},
- {file = "lazy_object_proxy-1.5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871"},
- {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9"},
- {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128"},
- {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win32.whl", hash = "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847"},
- {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108"},
- {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068"},
- {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7"},
- {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win32.whl", hash = "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb"},
- {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a"},
- {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39"},
- {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0"},
- {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win32.whl", hash = "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef"},
- {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302"},
- {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163"},
- {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f"},
- {file = "lazy_object_proxy-1.5.2-cp38-cp38-win32.whl", hash = "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694"},
- {file = "lazy_object_proxy-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-win32.whl", hash = "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84"},
+ {file = "lazy-object-proxy-1.6.0.tar.gz", hash = "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726"},
+ {file = "lazy_object_proxy-1.6.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b"},
+ {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win32.whl", hash = "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e"},
+ {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93"},
+ {file = "lazy_object_proxy-1.6.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741"},
+ {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587"},
+ {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4"},
+ {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f"},
+ {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3"},
+ {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981"},
+ {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2"},
+ {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd"},
+ {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837"},
+ {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653"},
+ {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3"},
+ {file = "lazy_object_proxy-1.6.0-cp38-cp38-win32.whl", hash = "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8"},
+ {file = "lazy_object_proxy-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"},
]
log4mongo = [
{file = "log4mongo-1.7.0.tar.gz", hash = "sha256:dc374617206162a0b14167fbb5feac01dbef587539a235dadba6200362984a68"},
@@ -1850,73 +1860,73 @@ packaging = [
{file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"},
]
parso = [
- {file = "parso-0.8.1-py2.py3-none-any.whl", hash = "sha256:15b00182f472319383252c18d5913b69269590616c947747bc50bf4ac768f410"},
- {file = "parso-0.8.1.tar.gz", hash = "sha256:8519430ad07087d4c997fda3a7918f7cfa27cb58972a8c89c2a0295a1c940e9e"},
+ {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"},
+ {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"},
]
pathlib2 = [
{file = "pathlib2-2.3.5-py2.py3-none-any.whl", hash = "sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db"},
{file = "pathlib2-2.3.5.tar.gz", hash = "sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868"},
]
pillow = [
- {file = "Pillow-8.1.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:5cf03b9534aca63b192856aa601c68d0764810857786ea5da652581f3a44c2b0"},
- {file = "Pillow-8.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:f91b50ad88048d795c0ad004abbe1390aa1882073b1dca10bfd55d0b8cf18ec5"},
- {file = "Pillow-8.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5762ebb4436f46b566fc6351d67a9b5386b5e5de4e58fdaa18a1c83e0e20f1a8"},
- {file = "Pillow-8.1.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e2cd8ac157c1e5ae88b6dd790648ee5d2777e76f1e5c7d184eaddb2938594f34"},
- {file = "Pillow-8.1.2-cp36-cp36m-win32.whl", hash = "sha256:72027ebf682abc9bafd93b43edc44279f641e8996fb2945104471419113cfc71"},
- {file = "Pillow-8.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d1d6bca39bb6dd94fba23cdb3eeaea5e30c7717c5343004d900e2a63b132c341"},
- {file = "Pillow-8.1.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:90882c6f084ef68b71bba190209a734bf90abb82ab5e8f64444c71d5974008c6"},
- {file = "Pillow-8.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:89e4c757a91b8c55d97c91fa09c69b3677c227b942fa749e9a66eef602f59c28"},
- {file = "Pillow-8.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8c4e32218c764bc27fe49b7328195579581aa419920edcc321c4cb877c65258d"},
- {file = "Pillow-8.1.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a01da2c266d9868c4f91a9c6faf47a251f23b9a862dce81d2ff583135206f5be"},
- {file = "Pillow-8.1.2-cp37-cp37m-win32.whl", hash = "sha256:30d33a1a6400132e6f521640dd3f64578ac9bfb79a619416d7e8802b4ce1dd55"},
- {file = "Pillow-8.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:71b01ee69e7df527439d7752a2ce8fb89e19a32df484a308eca3e81f673d3a03"},
- {file = "Pillow-8.1.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:5a2d957eb4aba9d48170b8fe6538ec1fbc2119ffe6373782c03d8acad3323f2e"},
- {file = "Pillow-8.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:87f42c976f91ca2fc21a3293e25bd3cd895918597db1b95b93cbd949f7d019ce"},
- {file = "Pillow-8.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:15306d71a1e96d7e271fd2a0737038b5a92ca2978d2e38b6ced7966583e3d5af"},
- {file = "Pillow-8.1.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:71f31ee4df3d5e0b366dd362007740106d3210fb6a56ec4b581a5324ba254f06"},
- {file = "Pillow-8.1.2-cp38-cp38-win32.whl", hash = "sha256:98afcac3205d31ab6a10c5006b0cf040d0026a68ec051edd3517b776c1d78b09"},
- {file = "Pillow-8.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:328240f7dddf77783e72d5ed79899a6b48bc6681f8d1f6001f55933cb4905060"},
- {file = "Pillow-8.1.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:bead24c0ae3f1f6afcb915a057943ccf65fc755d11a1410a909c1fefb6c06ad1"},
- {file = "Pillow-8.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81b3716cc9744ffdf76b39afb6247eae754186838cedad0b0ac63b2571253fe6"},
- {file = "Pillow-8.1.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:63cd413ac52ee3f67057223d363f4f82ce966e64906aea046daf46695e3c8238"},
- {file = "Pillow-8.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:8565355a29655b28fdc2c666fd9a3890fe5edc6639d128814fafecfae2d70910"},
- {file = "Pillow-8.1.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:1940fc4d361f9cc7e558d6f56ff38d7351b53052fd7911f4b60cd7bc091ea3b1"},
- {file = "Pillow-8.1.2-cp39-cp39-win32.whl", hash = "sha256:46c2bcf8e1e75d154e78417b3e3c64e96def738c2a25435e74909e127a8cba5e"},
- {file = "Pillow-8.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:aeab4cd016e11e7aa5cfc49dcff8e51561fa64818a0be86efa82c7038e9369d0"},
- {file = "Pillow-8.1.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:74cd9aa648ed6dd25e572453eb09b08817a1e3d9f8d1bd4d8403d99e42ea790b"},
- {file = "Pillow-8.1.2-pp36-pypy36_pp73-manylinux2010_i686.whl", hash = "sha256:e5739ae63636a52b706a0facec77b2b58e485637e1638202556156e424a02dc2"},
- {file = "Pillow-8.1.2-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:903293320efe2466c1ab3509a33d6b866dc850cfd0c5d9cc92632014cec185fb"},
- {file = "Pillow-8.1.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:5daba2b40782c1c5157a788ec4454067c6616f5a0c1b70e26ac326a880c2d328"},
- {file = "Pillow-8.1.2-pp37-pypy37_pp73-manylinux2010_i686.whl", hash = "sha256:1f93f2fe211f1ef75e6f589327f4d4f8545d5c8e826231b042b483d8383e8a7c"},
- {file = "Pillow-8.1.2-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:6efac40344d8f668b6c4533ae02a48d52fd852ef0654cc6f19f6ac146399c733"},
- {file = "Pillow-8.1.2-pp37-pypy37_pp73-win32.whl", hash = "sha256:f36c3ff63d6fc509ce599a2f5b0d0732189eed653420e7294c039d342c6e204a"},
- {file = "Pillow-8.1.2.tar.gz", hash = "sha256:b07c660e014852d98a00a91adfbe25033898a9d90a8f39beb2437d22a203fc44"},
+ {file = "Pillow-8.2.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:dc38f57d8f20f06dd7c3161c59ca2c86893632623f33a42d592f097b00f720a9"},
+ {file = "Pillow-8.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a013cbe25d20c2e0c4e85a9daf438f85121a4d0344ddc76e33fd7e3965d9af4b"},
+ {file = "Pillow-8.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8bb1e155a74e1bfbacd84555ea62fa21c58e0b4e7e6b20e4447b8d07990ac78b"},
+ {file = "Pillow-8.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c5236606e8570542ed424849f7852a0ff0bce2c4c8d0ba05cc202a5a9c97dee9"},
+ {file = "Pillow-8.2.0-cp36-cp36m-win32.whl", hash = "sha256:12e5e7471f9b637762453da74e390e56cc43e486a88289995c1f4c1dc0bfe727"},
+ {file = "Pillow-8.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5afe6b237a0b81bd54b53f835a153770802f164c5570bab5e005aad693dab87f"},
+ {file = "Pillow-8.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:cb7a09e173903541fa888ba010c345893cd9fc1b5891aaf060f6ca77b6a3722d"},
+ {file = "Pillow-8.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0d19d70ee7c2ba97631bae1e7d4725cdb2ecf238178096e8c82ee481e189168a"},
+ {file = "Pillow-8.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:083781abd261bdabf090ad07bb69f8f5599943ddb539d64497ed021b2a67e5a9"},
+ {file = "Pillow-8.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:c6b39294464b03457f9064e98c124e09008b35a62e3189d3513e5148611c9388"},
+ {file = "Pillow-8.2.0-cp37-cp37m-win32.whl", hash = "sha256:01425106e4e8cee195a411f729cff2a7d61813b0b11737c12bd5991f5f14bcd5"},
+ {file = "Pillow-8.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3b570f84a6161cf8865c4e08adf629441f56e32f180f7aa4ccbd2e0a5a02cba2"},
+ {file = "Pillow-8.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:031a6c88c77d08aab84fecc05c3cde8414cd6f8406f4d2b16fed1e97634cc8a4"},
+ {file = "Pillow-8.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:66cc56579fd91f517290ab02c51e3a80f581aba45fd924fcdee01fa06e635812"},
+ {file = "Pillow-8.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c32cc3145928c4305d142ebec682419a6c0a8ce9e33db900027ddca1ec39178"},
+ {file = "Pillow-8.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:624b977355cde8b065f6d51b98497d6cd5fbdd4f36405f7a8790e3376125e2bb"},
+ {file = "Pillow-8.2.0-cp38-cp38-win32.whl", hash = "sha256:5cbf3e3b1014dddc45496e8cf38b9f099c95a326275885199f427825c6522232"},
+ {file = "Pillow-8.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:463822e2f0d81459e113372a168f2ff59723e78528f91f0bd25680ac185cf797"},
+ {file = "Pillow-8.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:95d5ef984eff897850f3a83883363da64aae1000e79cb3c321915468e8c6add5"},
+ {file = "Pillow-8.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b91c36492a4bbb1ee855b7d16fe51379e5f96b85692dc8210831fbb24c43e484"},
+ {file = "Pillow-8.2.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d68cb92c408261f806b15923834203f024110a2e2872ecb0bd2a110f89d3c602"},
+ {file = "Pillow-8.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f217c3954ce5fd88303fc0c317af55d5e0204106d86dea17eb8205700d47dec2"},
+ {file = "Pillow-8.2.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5b70110acb39f3aff6b74cf09bb4169b167e2660dabc304c1e25b6555fa781ef"},
+ {file = "Pillow-8.2.0-cp39-cp39-win32.whl", hash = "sha256:a7d5e9fad90eff8f6f6106d3b98b553a88b6f976e51fce287192a5d2d5363713"},
+ {file = "Pillow-8.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:238c197fc275b475e87c1453b05b467d2d02c2915fdfdd4af126145ff2e4610c"},
+ {file = "Pillow-8.2.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0e04d61f0064b545b989126197930807c86bcbd4534d39168f4aa5fda39bb8f9"},
+ {file = "Pillow-8.2.0-pp36-pypy36_pp73-manylinux2010_i686.whl", hash = "sha256:63728564c1410d99e6d1ae8e3b810fe012bc440952168af0a2877e8ff5ab96b9"},
+ {file = "Pillow-8.2.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:c03c07ed32c5324939b19e36ae5f75c660c81461e312a41aea30acdd46f93a7c"},
+ {file = "Pillow-8.2.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:4d98abdd6b1e3bf1a1cbb14c3895226816e666749ac040c4e2554231068c639b"},
+ {file = "Pillow-8.2.0-pp37-pypy37_pp73-manylinux2010_i686.whl", hash = "sha256:aac00e4bc94d1b7813fe882c28990c1bc2f9d0e1aa765a5f2b516e8a6a16a9e4"},
+ {file = "Pillow-8.2.0-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:22fd0f42ad15dfdde6c581347eaa4adb9a6fc4b865f90b23378aa7914895e120"},
+ {file = "Pillow-8.2.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:e98eca29a05913e82177b3ba3d198b1728e164869c613d76d0de4bde6768a50e"},
+ {file = "Pillow-8.2.0.tar.gz", hash = "sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1"},
]
pluggy = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
]
protobuf = [
- {file = "protobuf-3.15.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1771ef20e88759c4d81db213e89b7a1fc53937968e12af6603c658ee4bcbfa38"},
- {file = "protobuf-3.15.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1a66261a402d05c8ad8c1fde8631837307bf8d7e7740a4f3941fc3277c2e1528"},
- {file = "protobuf-3.15.6-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:eac23a3e56175b710f3da9a9e8e2aa571891fbec60e0c5a06db1c7b1613b5cfd"},
- {file = "protobuf-3.15.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ec220d90eda8bb7a7a1434a8aed4fe26d7e648c1a051c2885f3f5725b6aa71a"},
- {file = "protobuf-3.15.6-cp35-cp35m-win32.whl", hash = "sha256:88d8f21d1ac205eedb6dea943f8204ed08201b081dba2a966ab5612788b9bb1e"},
- {file = "protobuf-3.15.6-cp35-cp35m-win_amd64.whl", hash = "sha256:eaada29bbf087dea7d8bce4d1d604fc768749e8809e9c295922accd7c8fce4d5"},
- {file = "protobuf-3.15.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:256c0b2e338c1f3228d3280707606fe5531fde85ab9d704cde6fdeb55112531f"},
- {file = "protobuf-3.15.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b9069e45b6e78412fba4a314ea38b4a478686060acf470d2b131b3a2c50484ec"},
- {file = "protobuf-3.15.6-cp36-cp36m-win32.whl", hash = "sha256:24f4697f57b8520c897a401b7f9a5ae45c369e22c572e305dfaf8053ecb49687"},
- {file = "protobuf-3.15.6-cp36-cp36m-win_amd64.whl", hash = "sha256:d9ed0955b794f1e5f367e27f8a8ff25501eabe34573f003f06639c366ca75f73"},
- {file = "protobuf-3.15.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:822ac7f87fc2fb9b24edd2db390538b60ef50256e421ca30d65250fad5a3d477"},
- {file = "protobuf-3.15.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:74ac159989e2b02d761188a2b6f4601ff5e494d9b9d863f5ad6e98e5e0c54328"},
- {file = "protobuf-3.15.6-cp37-cp37m-win32.whl", hash = "sha256:30fe4249a364576f9594180589c3f9c4771952014b5f77f0372923fc7bafbbe2"},
- {file = "protobuf-3.15.6-cp37-cp37m-win_amd64.whl", hash = "sha256:45a91fc6f9aa86d3effdeda6751882b02de628519ba06d7160daffde0c889ff8"},
- {file = "protobuf-3.15.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83c7c7534f050cb25383bb817159416601d1cc46c40bc5e851ec8bbddfc34a2f"},
- {file = "protobuf-3.15.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9ec20a6ded7d0888e767ad029dbb126e604e18db744ac0a428cf746e040ccecd"},
- {file = "protobuf-3.15.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0f2da2fcc4102b6c3b57f03c9d8d5e37c63f8bc74deaa6cb54e0cc4524a77247"},
- {file = "protobuf-3.15.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:70054ae1ce5dea7dec7357db931fcf487f40ea45b02cb719ee6af07eb1e906fb"},
- {file = "protobuf-3.15.6-py2.py3-none-any.whl", hash = "sha256:1655fc0ba7402560d749de13edbfca1ac45d1753d8f4e5292989f18f5a00c215"},
- {file = "protobuf-3.15.6.tar.gz", hash = "sha256:2b974519a2ae83aa1e31cff9018c70bbe0e303a46a598f982943c49ae1d4fcd3"},
+ {file = "protobuf-3.15.7-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a14141d5c967362d2eedff8825d2b69cc36a5b3ed6b1f618557a04e58a3cf787"},
+ {file = "protobuf-3.15.7-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d54d78f621852ec4fdd1484d1263ca04d4bf5ffdf7abffdbb939e444b6ff3385"},
+ {file = "protobuf-3.15.7-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:462085acdb410b06335315fe7e63cb281a1902856e0f4657f341c283cedc1d56"},
+ {file = "protobuf-3.15.7-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:849c92ce112e1ef648705c29ce044248e350f71d9d54a2026830623198f0bd38"},
+ {file = "protobuf-3.15.7-cp35-cp35m-win32.whl", hash = "sha256:1f6083382f7714700deadf3014e921711e2f807de7f27e40c32b744701ae5b99"},
+ {file = "protobuf-3.15.7-cp35-cp35m-win_amd64.whl", hash = "sha256:e17f60f00081adcb32068ee0bb51e418f6474acf83424244ff3512ffd2166385"},
+ {file = "protobuf-3.15.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c75e563c6fb2ca5b8f21dd75c15659aa2c4a0025b9da3a7711ae661cd6a488d"},
+ {file = "protobuf-3.15.7-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d939f41b4108350841c4790ebbadb61729e1363522fdb8434eb4e6f2065d0db1"},
+ {file = "protobuf-3.15.7-cp36-cp36m-win32.whl", hash = "sha256:24f14c09d4c0a3641f1b0e9b552d026361de65b01686fdd3e5fdf8f9512cd79b"},
+ {file = "protobuf-3.15.7-cp36-cp36m-win_amd64.whl", hash = "sha256:1247170191bcb2a8d978d11a58afe391004ec6c2184e4d961baf8102d43ff500"},
+ {file = "protobuf-3.15.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:364cadaeec0756afdc099cbd88cb5659bd1bb7d547168d063abcb0272ccbb2f6"},
+ {file = "protobuf-3.15.7-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0c3a6941b1e6e6e22d812a8e5c46bfe83082ea60d262a46f2cfb22d9b9fb17db"},
+ {file = "protobuf-3.15.7-cp37-cp37m-win32.whl", hash = "sha256:eb5668f3f6a83b6603ca2e09be5b20de89521ea5914aabe032cce981e4129cc8"},
+ {file = "protobuf-3.15.7-cp37-cp37m-win_amd64.whl", hash = "sha256:1001e671cf8476edce7fb72778358d026390649cc35a79d47b2a291684ccfbb2"},
+ {file = "protobuf-3.15.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a5ba7dd6f97964655aa7b234c95d80886425a31b7010764f042cdeb985314d18"},
+ {file = "protobuf-3.15.7-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:46674bd6fcf8c63b4b9869ba579685db67cf51ae966443dd6bd9a8fa00fcef62"},
+ {file = "protobuf-3.15.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4c4399156fb27e3768313b7a59352c861a893252bda6fb9f3643beb3ebb7047e"},
+ {file = "protobuf-3.15.7-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:85cd29faf056036167d87445d5a5059034c298881c044e71a73d3b61a4be1c23"},
+ {file = "protobuf-3.15.7-py2.py3-none-any.whl", hash = "sha256:22054432b923c0086f9cf1e1c0c52d39bf3c6e31014ea42eec2dabc22ee26d78"},
+ {file = "protobuf-3.15.7.tar.gz", hash = "sha256:2d03fc2591543cd2456d0b72230b50c4519546a8d379ac6fd3ecd84c6df61e5d"},
]
py = [
{file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
@@ -1960,8 +1970,8 @@ pyblish-base = [
{file = "pyblish_base-1.8.8-py2.py3-none-any.whl", hash = "sha256:67ea253a05d007ab4a175e44e778928ea7bdb0e9707573e1100417bbf0451a53"},
]
pycodestyle = [
- {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"},
- {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"},
+ {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"},
+ {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
]
pycparser = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
@@ -1973,16 +1983,16 @@ pydocstyle = [
{file = "pydocstyle-3.0.0.tar.gz", hash = "sha256:5741c85e408f9e0ddf873611085e819b809fca90b619f5fd7f34bd4959da3dd4"},
]
pyflakes = [
- {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
- {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"},
+ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
+ {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
]
pygments = [
{file = "Pygments-2.8.1-py3-none-any.whl", hash = "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"},
{file = "Pygments-2.8.1.tar.gz", hash = "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94"},
]
pylint = [
- {file = "pylint-2.7.2-py3-none-any.whl", hash = "sha256:d09b0b07ba06bcdff463958f53f23df25e740ecd81895f7d2699ec04bbd8dc3b"},
- {file = "pylint-2.7.2.tar.gz", hash = "sha256:0e21d3b80b96740909d77206d741aa3ce0b06b41be375d92e1f3244a274c1f8a"},
+ {file = "pylint-2.7.4-py3-none-any.whl", hash = "sha256:209d712ec870a0182df034ae19f347e725c1e615b2269519ab58a35b3fcbbe7a"},
+ {file = "pylint-2.7.4.tar.gz", hash = "sha256:bd38914c7731cdc518634a8d3c5585951302b6e2b6de60fbb3f7a0220e21eeee"},
]
pymongo = [
{file = "pymongo-3.11.3-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:4d959e929cec805c2bf391418b1121590b4e7d5cb00af7b1ba521443d45a0918"},
@@ -2123,8 +2133,8 @@ pyrsistent = [
{file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"},
]
pytest = [
- {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"},
- {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"},
+ {file = "pytest-6.2.3-py3-none-any.whl", hash = "sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"},
+ {file = "pytest-6.2.3.tar.gz", hash = "sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634"},
]
pytest-cov = [
{file = "pytest-cov-2.11.1.tar.gz", hash = "sha256:359952d9d39b9f822d9d29324483e7ba04a3a17dd7d05aa6beb7ea01e359e5f7"},
@@ -2198,8 +2208,8 @@ speedcopy = [
{file = "speedcopy-2.1.0.tar.gz", hash = "sha256:8bb1a6c735900b83901a7be84ba2175ed3887c13c6786f97dea48f2ea7d504c2"},
]
sphinx = [
- {file = "Sphinx-3.5.2-py3-none-any.whl", hash = "sha256:ef64a814576f46ec7de06adf11b433a0d6049be007fefe7fd0d183d28b581fac"},
- {file = "Sphinx-3.5.2.tar.gz", hash = "sha256:672cfcc24b6b69235c97c750cb190a44ecd72696b4452acaf75c2d9cc78ca5ff"},
+ {file = "Sphinx-3.5.3-py3-none-any.whl", hash = "sha256:3f01732296465648da43dec8fb40dc451ba79eb3e2cc5c6d79005fd98197107d"},
+ {file = "Sphinx-3.5.3.tar.gz", hash = "sha256:ce9c228456131bab09a3d7d10ae58474de562a6f79abb3dc811ae401cf8c1abc"},
]
sphinx-qt-documentation = [
{file = "sphinx_qt_documentation-0.3-py3-none-any.whl", hash = "sha256:bee247cb9e4fc03fc496d07adfdb943100e1103320c3e5e820e0cfa7c790d9b6"},
@@ -2245,8 +2255,8 @@ toml = [
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
tqdm = [
- {file = "tqdm-4.59.0-py2.py3-none-any.whl", hash = "sha256:9fdf349068d047d4cfbe24862c425883af1db29bcddf4b0eeb2524f6fbdb23c7"},
- {file = "tqdm-4.59.0.tar.gz", hash = "sha256:d666ae29164da3e517fcf125e41d4fe96e5bb375cd87ff9763f6b38b5592fe33"},
+ {file = "tqdm-4.60.0-py2.py3-none-any.whl", hash = "sha256:daec693491c52e9498632dfbe9ccfc4882a557f5fa08982db1b4d3adbe0887c3"},
+ {file = "tqdm-4.60.0.tar.gz", hash = "sha256:ebdebdb95e3477ceea267decfc0784859aa3df3e27e22d23b83e9b272bf157ae"},
]
typed-ast = [
{file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"},
@@ -2290,8 +2300,8 @@ uritemplate = [
{file = "uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"},
]
urllib3 = [
- {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"},
- {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"},
+ {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"},
+ {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"},
]
wcwidth = [
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
@@ -2305,8 +2315,8 @@ wrapt = [
{file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"},
]
wsrpc-aiohttp = [
- {file = "wsrpc-aiohttp-3.1.1.tar.gz", hash = "sha256:a17e1d91624a437e759d4f276b73de1db2071b1681e992cade025e91d31b2a9f"},
- {file = "wsrpc_aiohttp-3.1.1-py3-none-any.whl", hash = "sha256:f3f1ee31aed5145a7fafe8d6c778b914b7e6ec131500395c9c85b0d8676f7302"},
+ {file = "wsrpc-aiohttp-3.1.2.tar.gz", hash = "sha256:891164dfe06a8d8d846b485d04b1e56b2c397ff1b46ef0348e6f62bd8efb1693"},
+ {file = "wsrpc_aiohttp-3.1.2-py3-none-any.whl", hash = "sha256:4ba64e02b12dcbc09d02544f35bceba49bd04cbc496db47aa8559ae4609ada8e"},
]
yarl = [
{file = "yarl-1.6.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434"},
diff --git a/pyproject.toml b/pyproject.toml
index ec2d9c7e3b..6df6db5a18 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -18,6 +18,7 @@ acre = { git = "https://github.com/pypeclub/acre.git" }
opentimelineio = { version = "0.14.0.dev1", source = "openpype" }
appdirs = "^1.4.3"
blessed = "^1.17" # openpype terminal formatting
+coolname = "*"
clique = "1.5.*"
Click = "^7"
dnspython = "^2.1.0"