Merge branch 'develop' into 1175-add-ffmpeg-and-othe-binaries-to-build

This commit is contained in:
Milan Kolar 2021-04-12 19:50:31 +02:00
commit 3a46ce9277
446 changed files with 22752 additions and 1233 deletions

63
.github/workflows/documentation.yml vendored Normal file
View file

@ -0,0 +1,63 @@
name: documentation
on:
pull_request:
branches: [develop]
types: [review_requested, ready_for_review]
paths:
- 'website/**'
push:
branches: [main]
paths:
- 'website/**'
jobs:
check-build:
if: github.event_name != 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Test Build
run: |
cd website
if [ -e yarn.lock ]; then
yarn install --frozen-lockfile
elif [ -e package-lock.json ]; then
npm ci
else
npm i
fi
npm run build
deploy-website:
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: 🔨 Build
run: |
cd website
if [ -e yarn.lock ]; then
yarn install --frozen-lockfile
elif [ -e package-lock.json ]; then
npm ci
else
npm i
fi
npm run build
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@4.0.0
with:
server: ftp.openpype.io
username: ${{ secrets.ftp_user }}
password: ${{ secrets.ftp_password }}
local-dir: ./website/build/

88
.github/workflows/test_build.yml vendored Normal file
View file

@ -0,0 +1,88 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
name: Test Build
on:
pull_request:
branches: [develop]
types: [review_requested, ready_for_review]
paths-ignore:
- 'docs/**'
- 'website/**'
- 'vendor/**'
jobs:
Windows-latest:
runs-on: windows-latest
strategy:
matrix:
python-version: [3.7]
steps:
- name: 🚛 Checkout Code
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: 🧵 Install Requirements
shell: pwsh
run: |
./tools/create_env.ps1
- name: 🔨 Build
shell: pwsh
run: |
./tools/build.ps1
Ubuntu-latest:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7]
steps:
- name: 🚛 Checkout Code
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: 🧵 Install Requirements
run: |
./tools/create_env.sh
- name: 🔨 Build
run: |
./tools/build.sh
# MacOS-latest:
# runs-on: macos-latest
# strategy:
# matrix:
# python-version: [3.7]
# steps:
# - name: 🚛 Checkout Code
# uses: actions/checkout@v2
# - name: Set up Python
# uses: actions/setup-python@v2
# with:
# python-version: ${{ matrix.python-version }}
# - name: 🧵 Install Requirements
# run: |
# ./tools/create_env.sh
# - name: 🔨 Build
# run: |
# ./tools/build.sh

15
.gitignore vendored
View file

@ -67,7 +67,7 @@ coverage.xml
# Node JS packages
##################
node_modules/
node_modules
package-lock.json
openpype/premiere/ppro/js/debug.log
@ -81,4 +81,15 @@ openpype/premiere/ppro/js/debug.log
.vscode/
.env
dump.sql
test_localsystem.txt
test_localsystem.txt
# website
##########
website/translated_docs
website/build/
website/node_modules
website/i18n/*
website/debug.log
website/.docusaurus

6
.gitmodules vendored
View file

@ -1,13 +1,13 @@
[submodule "repos/avalon-core"]
path = repos/avalon-core
url = git@github.com:pypeclub/avalon-core.git
url = https://github.com/pypeclub/avalon-core.git
branch = develop
[submodule "repos/avalon-unreal-integration"]
path = repos/avalon-unreal-integration
url = git@github.com:pypeclub/avalon-unreal-integration.git
url = https://github.com/pypeclub/avalon-unreal-integration.git
[submodule "openpype/modules/ftrack/python2_vendor/ftrack-python-api"]
path = openpype/modules/ftrack/python2_vendor/ftrack-python-api
url = https://bitbucket.org/ftrack/ftrack-python-api.git
[submodule "openpype/modules/ftrack/python2_vendor/arrow"]
path = openpype/modules/ftrack/python2_vendor/arrow
url = git@github.com:arrow-py/arrow.git
url = https://github.com/arrow-py/arrow.git

View file

@ -167,14 +167,23 @@ sudo yum install qt5-qtbase-devel
<details>
<summary>Use pyenv to install Python version for OpenPype build</summary>
You will need **bzip2**, **readline** and **sqlite3** libraries.
You will need **bzip2**, **readline**, **sqlite3** and other libraries.
**Ubuntu:**
For more details about Python build environments see:
https://github.com/pyenv/pyenv/wiki#suggested-build-environment
**For Ubuntu:**
```sh
sudo apt install libbz2-dev libreadline-dev libsqlite3-dev
sudo apt-get update; sudo apt-get install --no-install-recommends make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
```
1) install **pyenv**
**For Centos:**
```sh
yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel
```
**install pyenv**
```sh
curl https://pyenv.run | bash

View file

@ -1,15 +1,11 @@
# -*- coding: utf-8 -*-
"""Open install dialog."""
import os
import sys
import os
os.chdir(os.path.dirname(__file__)) # for override sys.path in Deadline
from Qt import QtWidgets # noqa
from Qt.QtCore import Signal # noqa
from .install_dialog import InstallDialog
from .bootstrap_repos import BootstrapRepos
from .version import __version__ as version
@ -25,16 +21,21 @@ def get_result(res: int):
def open_dialog():
"""Show Igniter dialog."""
from Qt import QtWidgets
from .install_dialog import InstallDialog
app = QtWidgets.QApplication(sys.argv)
d = InstallDialog()
d.finished.connect(get_result)
d.open()
app.exec()
return RESULT
__all__ = [
"InstallDialog",
"BootstrapRepos",
"open_dialog",
"version"

View file

@ -14,7 +14,10 @@ from zipfile import ZipFile, BadZipFile
from appdirs import user_data_dir
from speedcopy import copyfile
from .user_settings import OpenPypeSettingsRegistry
from .user_settings import (
OpenPypeSecureRegistry,
OpenPypeSettingsRegistry
)
from .tools import get_openpype_path_from_db
@ -239,6 +242,7 @@ class BootstrapRepos:
self._app = "openpype"
self._log = log.getLogger(str(__class__))
self.data_dir = Path(user_data_dir(self._app, self._vendor))
self.secure_registry = OpenPypeSecureRegistry("mongodb")
self.registry = OpenPypeSettingsRegistry()
self.zip_filter = [".pyc", "__pycache__"]
self.openpype_filter = [

View file

@ -13,7 +13,7 @@ from .tools import (
validate_mongo_connection,
get_openpype_path_from_db
)
from .user_settings import OpenPypeSettingsRegistry
from .user_settings import OpenPypeSecureRegistry
from .version import __version__
@ -42,13 +42,13 @@ class InstallDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(InstallDialog, self).__init__(parent)
self.registry = OpenPypeSettingsRegistry()
self.secure_registry = OpenPypeSecureRegistry("mongodb")
self.mongo_url = ""
try:
self.mongo_url = (
os.getenv("OPENPYPE_MONGO", "")
or self.registry.get_secure_item("openPypeMongo")
or self.secure_registry.get_item("openPypeMongo")
)
except ValueError:
pass

View file

@ -71,7 +71,7 @@ class InstallThread(QThread):
if not os.getenv("OPENPYPE_MONGO"):
# try to get it from settings registry
try:
self._mongo = bs.registry.get_secure_item(
self._mongo = bs.secure_registry.get_item(
"openPypeMongo")
except ValueError:
self.message.emit(
@ -82,7 +82,7 @@ class InstallThread(QThread):
self._mongo = os.getenv("OPENPYPE_MONGO")
else:
self.message.emit("Saving mongo connection string ...", False)
bs.registry.set_secure_item("openPypeMongo", self._mongo)
bs.secure_registry.set_item("openPypeMongo", self._mongo)
os.environ["OPENPYPE_MONGO"] = self._mongo
@ -169,7 +169,7 @@ class InstallThread(QThread):
f"!!! invalid mongo url {self._mongo}", True)
self.finished.emit(InstallResult(-1))
return
bs.registry.set_secure_item("openPypeMongo", self._mongo)
bs.secure_registry.set_item("openPypeMongo", self._mongo)
os.environ["OPENPYPE_MONGO"] = self._mongo
self.message.emit(f"processing {self._path}", True)

View file

@ -25,8 +25,112 @@ except ImportError:
import platform
import appdirs
import six
import appdirs
_PLACEHOLDER = object()
class OpenPypeSecureRegistry:
"""Store information using keyring.
Registry should be used for private data that should be available only for
user.
All passed registry names will have added prefix `OpenPype/` to easier
identify which data were created by OpenPype.
Args:
name(str): Name of registry used as identifier for data.
"""
def __init__(self, name):
try:
import keyring
except Exception:
raise NotImplementedError(
"Python module `keyring` is not available."
)
# hack for cx_freeze and Windows keyring backend
if platform.system().lower() == "windows":
from keyring.backends import Windows
keyring.set_keyring(Windows.WinVaultKeyring())
# Force "OpenPype" prefix
self._name = "/".join(("OpenPype", name))
def set_item(self, name, value):
# type: (str, str) -> None
"""Set sensitive item into system's keyring.
This uses `Keyring module`_ to save sensitive stuff into system's
keyring.
Args:
name (str): Name of the item.
value (str): Value of the item.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
import keyring
keyring.set_password(self._name, name, value)
@lru_cache(maxsize=32)
def get_item(self, name, default=_PLACEHOLDER):
"""Get value of sensitive item from system's keyring.
See also `Keyring module`_
Args:
name (str): Name of the item.
default (Any): Default value if item is not available.
Returns:
value (str): Value of the item.
Raises:
ValueError: If item doesn't exist and default is not defined.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
import keyring
value = keyring.get_password(self._name, name)
if value:
return value
if default is not _PLACEHOLDER:
return default
# NOTE Should raise `KeyError`
raise ValueError(
"Item {}:{} does not exist in keyring.".format(self._name, name)
)
def delete_item(self, name):
# type: (str) -> None
"""Delete value stored in system's keyring.
See also `Keyring module`_
Args:
name (str): Name of the item to be deleted.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
import keyring
self.get_item.cache_clear()
keyring.delete_password(self._name, name)
@six.add_metaclass(ABCMeta)
@ -46,13 +150,6 @@ class ASettingRegistry():
# type: (str) -> ASettingRegistry
super(ASettingRegistry, self).__init__()
if six.PY3:
import keyring
# hack for cx_freeze and Windows keyring backend
if platform.system() == "Windows":
from keyring.backends import Windows
keyring.set_keyring(Windows.WinVaultKeyring())
self._name = name
self._items = {}
@ -127,78 +224,6 @@ class ASettingRegistry():
del self._items[name]
self._delete_item(name)
def set_secure_item(self, name, value):
# type: (str, str) -> None
"""Set sensitive item into system's keyring.
This uses `Keyring module`_ to save sensitive stuff into system's
keyring.
Args:
name (str): Name of the item.
value (str): Value of the item.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
if six.PY2:
raise NotImplementedError(
"Keyring not available on Python 2 hosts")
import keyring
keyring.set_password(self._name, name, value)
@lru_cache(maxsize=32)
def get_secure_item(self, name):
# type: (str) -> str
"""Get value of sensitive item from system's keyring.
See also `Keyring module`_
Args:
name (str): Name of the item.
Returns:
value (str): Value of the item.
Raises:
ValueError: If item doesn't exist.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
if six.PY2:
raise NotImplementedError(
"Keyring not available on Python 2 hosts")
import keyring
value = keyring.get_password(self._name, name)
if not value:
raise ValueError(
"Item {}:{} does not exist in keyring.".format(
self._name, name))
return value
def delete_secure_item(self, name):
# type: (str) -> None
"""Delete value stored in system's keyring.
See also `Keyring module`_
Args:
name (str): Name of the item to be deleted.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
if six.PY2:
raise NotImplementedError(
"Keyring not available on Python 2 hosts")
import keyring
self.get_secure_item.cache_clear()
keyring.delete_password(self._name, name)
class IniSettingRegistry(ASettingRegistry):
"""Class using :mod:`configparser`.
@ -459,9 +484,10 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry):
"""
def __init__(self):
def __init__(self, name=None):
self.vendor = "pypeclub"
self.product = "openpype"
if not name:
name = "openpype_settings"
path = appdirs.user_data_dir(self.product, self.vendor)
super(OpenPypeSettingsRegistry, self).__init__(
"openpype_settings", path)
super(OpenPypeSettingsRegistry, self).__init__(name, path)

View file

@ -6,7 +6,7 @@ class PrePython2Vendor(PreLaunchHook):
"""Prepend python 2 dependencies for py2 hosts."""
# WARNING This hook will probably be deprecated in OpenPype 3 - kept for test
order = 10
app_groups = ["hiero", "nuke", "nukex"]
app_groups = ["hiero", "nuke", "nukex", "unreal"]
def execute(self):
# Prepare vendor dir path

View file

@ -1,4 +1,5 @@
import os
import subprocess
from openpype.lib import PreLaunchHook
@ -10,15 +11,32 @@ class LaunchWithWindowsShell(PreLaunchHook):
instead.
"""
order = 10
app_groups = ["resolve", "nuke", "nukex", "hiero", "nukestudio"]
# Should be as last hook becuase must change launch arguments to string
order = 1000
app_groups = ["nuke", "nukex", "hiero", "nukestudio"]
platforms = ["windows"]
def execute(self):
# Get comspec which is cmd.exe in most cases.
comspec = os.environ.get("COMSPEC", "cmd.exe")
# Add comspec to arguments list and add "/k"
new_args = [comspec, "/c"]
new_args.extend(self.launch_context.launch_args)
new_args = [
# Get comspec which is cmd.exe in most cases.
os.environ.get("COMSPEC", "cmd.exe"),
# NOTE change to "/k" if want to keep console opened
"/c",
# Convert arguments to command line arguments (as string)
"\"{}\"".format(
subprocess.list2cmdline(self.launch_context.launch_args)
)
]
# Convert list to string
# WARNING this only works if is used as string
args_string = " ".join(new_args)
self.log.info((
"Modified launch arguments to be launched with shell \"{}\"."
).format(args_string))
# Replace launch args with new one
self.launch_context.launch_args = new_args
self.launch_context.launch_args = args_string
# Change `creationflags` to CREATE_NEW_CONSOLE
self.launch_context.kwargs["creationflags"] = (
subprocess.CREATE_NEW_CONSOLE
)

View file

@ -10,7 +10,7 @@ import pyblish.api as pyblish
import openpype.hosts.aftereffects
log = logging.getLogger("pype.hosts.aftereffects")
log = logging.getLogger("openpype.hosts.aftereffects")
HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.aftereffects.__file__))

View file

@ -46,6 +46,12 @@ class CollectAERender(abstract_collect_render.AbstractCollectRender):
"Please recreate instance.")
item_id = inst["members"][0]
work_area_info = self.stub.get_work_area(int(item_id))
if not work_area_info:
self.log.warning("Orphaned instance, deleting metadata")
self.stub.remove_instance(int(item_id))
continue
frameStart = work_area_info.workAreaStart
frameEnd = round(work_area_info.workAreaStart +

View file

@ -21,3 +21,4 @@ class RemovePublishHighlight(openpype.api.Extractor):
item = instance.data
comp_name = item["comp_name"].replace(stub.PUBLISH_ICON, '')
stub.rename_item(item["comp_id"], comp_name)
instance.data["comp_name"] = comp_name

View file

@ -51,9 +51,18 @@ def set_start_end_frames():
"name": asset_name
})
bpy.context.scene.frame_start = asset_doc["data"]["frameStart"]
bpy.context.scene.frame_end = asset_doc["data"]["frameEnd"]
# Default frame start/end
frameStart = 0
frameEnd = 100
# 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"]
bpy.context.scene.frame_start = frameStart
bpy.context.scene.frame_end = frameEnd
def on_new(arg1, arg2):
set_start_end_frames()

View file

@ -292,6 +292,9 @@ class UnrealLayoutLoader(plugin.AssetLoader):
icon = "code-fork"
color = "orange"
animation_creator_name = "CreateAnimation"
setdress_creator_name = "CreateSetDress"
def _remove_objects(self, objects):
for obj in list(objects):
if obj.type == 'ARMATURE':
@ -368,7 +371,7 @@ class UnrealLayoutLoader(plugin.AssetLoader):
location.get('z')
)
obj.rotation_euler = (
rotation.get('x'),
rotation.get('x') + math.pi / 2,
-rotation.get('y'),
-rotation.get('z')
)

View file

@ -57,27 +57,12 @@ def _prepare_publish_environments():
project_name = os.getenv("AVALON_PROJECT")
asset_name = os.getenv("AVALON_ASSET")
io.install()
project_doc = io.find_one({
"type": "project"
})
av_asset = io.find_one({
"type": "asset",
"name": asset_name
})
parents = av_asset["data"]["parents"]
hierarchy = ""
if parents:
hierarchy = "/".join(parents)
env["AVALON_PROJECT"] = project_name
env["AVALON_ASSET"] = asset_name
env["AVALON_TASK"] = os.getenv("AVALON_TASK")
env["AVALON_WORKDIR"] = os.getenv("AVALON_WORKDIR")
env["AVALON_HIERARCHY"] = hierarchy
env["AVALON_PROJECTCODE"] = project_doc["data"].get("code", "")
env["AVALON_APP"] = f"hosts.{publish_host}"
env["AVALON_APP_NAME"] = "celaction_local"
env["AVALON_APP_NAME"] = "celaction/local"
env["PYBLISH_HOSTS"] = publish_host

View file

@ -39,7 +39,7 @@ def install():
avalon.data["familiesStateDefault"] = False
avalon.data["familiesStateToggled"] = family_states
log.info("pype.hosts.fusion installed")
log.info("openpype.hosts.fusion installed")
pyblish.register_host("fusion")
pyblish.register_plugin_path(PUBLISH_PATH)

View file

@ -13,7 +13,7 @@ class CollectFusionRenderMode(pyblish.api.InstancePlugin):
available tool does not visualize which render mode is set for the
current comp, please run the following line in the console (Py2)
comp.GetData("pype.rendermode")
comp.GetData("openpype.rendermode")
This will return the name of the current render mode as seen above under
Options.
@ -34,7 +34,7 @@ class CollectFusionRenderMode(pyblish.api.InstancePlugin):
raise RuntimeError("No comp previously collected, unable to "
"retrieve Fusion version.")
rendermode = comp.GetData("pype.rendermode") or "local"
rendermode = comp.GetData("openpype.rendermode") or "local"
assert rendermode in options, "Must be supported render mode"
self.log.info("Render mode: {0}".format(rendermode))

View file

@ -96,11 +96,11 @@ class SetRenderMode(QtWidgets.QWidget):
return self._comp.GetAttrs("COMPS_Name")
def _get_comp_rendermode(self):
return self._comp.GetData("pype.rendermode") or "local"
return self._comp.GetData("openpype.rendermode") or "local"
def _set_comp_rendermode(self):
rendermode = self.mode_options.currentText()
self._comp.SetData("pype.rendermode", rendermode)
self._comp.SetData("openpype.rendermode", rendermode)
self._comp.Print("Updated render mode to '%s'\n" % rendermode)
self.hide()

View file

@ -6,7 +6,7 @@ import openpype.hosts.hiero.api as phiero
avalon.api.install(phiero)
try:
__import__("pype.hosts.hiero.api")
__import__("openpype.hosts.hiero.api")
__import__("pyblish")
except ImportError as e:

View file

@ -1,18 +1,12 @@
import os
import sys
import nuke
from avalon import api as avalon
from openpype.tools import workfiles
from pyblish import api as pyblish
from openpype.api import Logger
import openpype.hosts.nuke
import avalon.api
import pyblish.api
import openpype
from . import lib, menu
self = sys.modules[__name__]
self.workfiles_launched = False
log = Logger().get_logger(__name__)
log = openpype.api.Logger().get_logger(__name__)
AVALON_CONFIG = os.getenv("AVALON_CONFIG", "pype")
HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.nuke.__file__))
@ -25,7 +19,7 @@ INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
# registering pyblish gui regarding settings in presets
if os.getenv("PYBLISH_GUI", None):
pyblish.register_gui(os.getenv("PYBLISH_GUI", None))
pyblish.api.register_gui(os.getenv("PYBLISH_GUI", None))
def reload_config():
@ -61,15 +55,16 @@ def install():
'''
log.info("Registering Nuke plug-ins..")
pyblish.register_plugin_path(PUBLISH_PATH)
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH)
pyblish.api.register_plugin_path(PUBLISH_PATH)
avalon.api.register_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.register_plugin_path(avalon.api.Creator, CREATE_PATH)
avalon.api.register_plugin_path(avalon.api.InventoryAction, INVENTORY_PATH)
# Register Avalon event for workfiles loading.
avalon.on("workio.open_file", lib.check_inventory_versions)
avalon.api.on("workio.open_file", lib.check_inventory_versions)
pyblish.register_callback("instanceToggled", on_pyblish_instance_toggled)
pyblish.api.register_callback(
"instanceToggled", on_pyblish_instance_toggled)
workfile_settings = lib.WorkfileSettings()
# Disable all families except for the ones we explicitly want to see
family_states = [
@ -79,39 +74,27 @@ def install():
"gizmo"
]
avalon.data["familiesStateDefault"] = False
avalon.data["familiesStateToggled"] = family_states
# Workfiles.
launch_workfiles = os.environ.get("WORKFILES_STARTUP")
if launch_workfiles:
nuke.addOnCreate(launch_workfiles_app, nodeClass="Root")
avalon.api.data["familiesStateDefault"] = False
avalon.api.data["familiesStateToggled"] = family_states
# Set context settings.
nuke.addOnCreate(workfile_settings.set_context_settings, nodeClass="Root")
# nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root")
nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root")
nuke.addOnCreate(lib.open_last_workfile, nodeClass="Root")
nuke.addOnCreate(lib.launch_workfiles_app, nodeClass="Root")
menu.install()
def launch_workfiles_app():
'''Function letting start workfiles after start of host
'''
if not self.workfiles_launched:
self.workfiles_launched = True
workfiles.show(os.environ["AVALON_WORKDIR"])
def uninstall():
'''Uninstalling host's integration
'''
log.info("Deregistering Nuke plug-ins..")
pyblish.deregister_plugin_path(PUBLISH_PATH)
avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
pyblish.api.deregister_plugin_path(PUBLISH_PATH)
avalon.api.deregister_plugin_path(avalon.api.Loader, LOAD_PATH)
avalon.api.deregister_plugin_path(avalon.api.Creator, CREATE_PATH)
pyblish.deregister_callback("instanceToggled", on_pyblish_instance_toggled)
pyblish.api.deregister_callback(
"instanceToggled", on_pyblish_instance_toggled)
reload_config()
menu.uninstall()
@ -123,7 +106,7 @@ def on_pyblish_instance_toggled(instance, old_value, new_value):
log.info("instance toggle: {}, old_value: {}, new_value:{} ".format(
instance, old_value, new_value))
from avalon.nuke import (
from avalon.api.nuke import (
viewer_update_and_undo_stop,
add_publish_knob
)

View file

@ -3,9 +3,14 @@ import re
import sys
from collections import OrderedDict
from avalon import api, io, lib
from avalon.tools import workfiles
import avalon.nuke
from avalon.nuke import lib as anlib
from avalon.nuke import (
save_file, open_file
)
from openpype.api import (
Logger,
Anatomy,
@ -13,6 +18,7 @@ from openpype.api import (
get_anatomy_settings,
get_hierarchy,
get_asset,
get_current_project_settings,
config,
ApplicationManager
)
@ -25,8 +31,10 @@ log = Logger().get_logger(__name__)
self = sys.modules[__name__]
self._project = None
self.workfiles_launched = False
self._node_tab_name = "{}".format(os.getenv("AVALON_LABEL") or "Avalon")
def get_node_imageio_setting(**kwarg):
''' Get preset data for dataflow (fileType, compression, bitDepth)
'''
@ -1616,3 +1624,41 @@ def find_free_space_to_paste_nodes(
xpos = min(group_xpos)
ypos = max(group_ypos) + abs(offset)
return xpos, ypos
def launch_workfiles_app():
'''Function letting start workfiles after start of host
'''
# get state from settings
open_at_start = get_current_project_settings()["nuke"].get(
"general", {}).get("open_workfile_at_start")
# return if none is defined
if not open_at_start:
return
if not self.workfiles_launched:
self.workfiles_launched = True
workfiles.show(os.environ["AVALON_WORKDIR"])
def open_last_workfile():
# get state from settings
open_last_version = get_current_project_settings()["nuke"].get(
"general", {}).get("create_initial_workfile")
log.info("Opening last workfile...")
last_workfile_path = os.environ.get("AVALON_LAST_WORKFILE")
if not os.path.exists(last_workfile_path):
# return if none is defined
if not open_last_version:
return
save_file(last_workfile_path)
else:
# to avoid looping of the callback, remove it!
nuke.removeOnCreate(open_last_workfile, nodeClass="Root")
# open workfile
open_file(last_workfile_path)

View file

@ -9,7 +9,7 @@ from openpype import lib
from pyblish import api as pyblish
import openpype.hosts.photoshop
log = logging.getLogger("pype.hosts.photoshop")
log = logging.getLogger("openpype.hosts.photoshop")
HOST_DIR = os.path.dirname(os.path.abspath(openpype.hosts.photoshop.__file__))
PLUGINS_DIR = os.path.join(HOST_DIR, "plugins")

View file

@ -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",

View file

@ -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()

View file

@ -47,7 +47,7 @@ def install():
avalon.data["familiesStateDefault"] = False
avalon.data["familiesStateToggled"] = family_states
log.info("pype.hosts.resolve installed")
log.info("openpype.hosts.resolve installed")
pyblish.register_host("resolve")
pyblish.register_plugin_path(PUBLISH_PATH)
@ -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

View file

@ -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

View file

@ -44,7 +44,7 @@ class ResolvePrelaunch(PreLaunchHook):
self.launch_context.env["PRE_PYTHON_SCRIPT"] = pre_py_sc
self.log.debug(f"-- pre_py_sc: `{pre_py_sc}`...")
try:
__import__("pype.hosts.resolve")
__import__("openpype.hosts.resolve")
__import__("pyblish")
except ImportError:

View file

@ -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}

View file

@ -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:

View file

@ -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

View file

@ -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")

View file

View file

@ -23,8 +23,8 @@ class UnrealPrelaunchHook(PreLaunchHook):
def execute(self):
asset_name = self.data["asset_name"]
task_name = self.data["task_name"]
workdir = self.env["AVALON_WORKDIR"]
engine_version = self.app_name.split("_")[-1]
workdir = self.launch_context.env["AVALON_WORKDIR"]
engine_version = self.app_name.split("_")[-1].replace("-", ".")
unreal_project_name = f"{asset_name}_{task_name}"
# Unreal is sensitive about project names longer then 20 chars
@ -81,8 +81,8 @@ class UnrealPrelaunchHook(PreLaunchHook):
# Set "AVALON_UNREAL_PLUGIN" to current process environment for
# execution of `create_unreal_project`
env_key = "AVALON_UNREAL_PLUGIN"
if self.env.get(env_key):
os.environ[env_key] = self.env[env_key]
if self.launch_context.env.get(env_key):
os.environ[env_key] = self.launch_context.env[env_key]
unreal_lib.create_unreal_project(
unreal_project_name,

View file

@ -104,7 +104,8 @@ from .plugin_tools import (
from .local_settings import (
IniSettingRegistry,
JSONSettingRegistry,
PypeSettingsRegistry,
OpenPypeSecureRegistry,
OpenPypeSettingsRegistry,
get_local_site_id,
change_openpype_mongo_url
)
@ -217,7 +218,8 @@ __all__ = [
"IniSettingRegistry",
"JSONSettingRegistry",
"PypeSettingsRegistry",
"OpenPypeSecureRegistry",
"OpenPypeSettingsRegistry",
"get_local_site_id",
"change_openpype_mongo_url",

View file

@ -216,7 +216,7 @@ class Anatomy:
"""Returns value of root key from template."""
root_templates = []
for group in re.findall(self.root_key_regex, template):
root_templates.append(group)
root_templates.append("{" + group + "}")
if not root_templates:
return None

View file

@ -17,6 +17,10 @@ from openpype.settings import (
get_project_settings,
get_environments
)
from openpype.settings.constants import (
METADATA_KEYS,
M_DYNAMIC_KEY_LABEL
)
from . import (
PypeLogger,
Anatomy
@ -72,7 +76,7 @@ class ApplictionExecutableNotFound(Exception):
for executable in application.executables:
details += "\n- " + executable.executable_path
self.msg = msg.format(application.full_label, application.name)
self.msg = msg.format(application.full_label, application.full_name)
self.details = details
exc_mgs = str(self.msg)
@ -123,7 +127,16 @@ class ApplicationGroup:
self.host_name = host_name
variants = data.get("variants") or {}
key_label_mapping = variants.pop(M_DYNAMIC_KEY_LABEL, {})
for variant_name, variant_data in variants.items():
if variant_name in METADATA_KEYS:
continue
if "variant_label" not in variant_data:
variant_label = key_label_mapping.get(variant_name)
if variant_label:
variant_data["variant_label"] = variant_label
variants[variant_name] = Application(
variant_name, variant_data, self
)
@ -165,7 +178,7 @@ class Application:
enabled = False
if group.enabled:
enabled = data.get("enabled", True)
self.enabled = enabled
self.enabled = enabled
self.label = data.get("variant_label") or name
self.full_name = "/".join((group.name, name))
@ -244,7 +257,7 @@ class Application:
Returns:
subprocess.Popen: Return executed process as Popen object.
"""
return self.manager.launch(self.name, *args, **kwargs)
return self.manager.launch(self.full_name, *args, **kwargs)
class ApplicationManager:
@ -265,22 +278,31 @@ class ApplicationManager:
self.tool_groups.clear()
self.tools.clear()
settings = get_system_settings()
settings = get_system_settings(
clear_metadata=False, exclude_locals=False
)
app_defs = settings["applications"]
for group_name, variant_defs in app_defs.items():
if group_name in METADATA_KEYS:
continue
group = ApplicationGroup(group_name, variant_defs, self)
self.app_groups[group_name] = group
for app in group:
# TODO This should be replaced with `full_name` in future
self.applications[app.name] = app
self.applications[app.full_name] = app
tools_definitions = settings["tools"]["tool_groups"]
tool_label_mapping = tools_definitions.pop(M_DYNAMIC_KEY_LABEL, {})
for tool_group_name, tool_group_data in tools_definitions.items():
if not tool_group_name:
if not tool_group_name or tool_group_name in METADATA_KEYS:
continue
tool_group_label = (
tool_label_mapping.get(tool_group_name) or tool_group_name
)
group = EnvironmentToolGroup(
tool_group_name, tool_group_data, self
tool_group_name, tool_group_label, tool_group_data, self
)
self.tool_groups[tool_group_name] = group
for tool in group:
@ -336,16 +358,24 @@ class EnvironmentToolGroup:
manager (ApplicationManager): Manager that creates the group.
"""
def __init__(self, name, data, manager):
def __init__(self, name, label, data, manager):
self.name = name
self.label = label
self._data = data
self.manager = manager
self._environment = data["environment"]
variants = data.get("variants") or {}
label_by_key = variants.pop(M_DYNAMIC_KEY_LABEL, {})
variants_by_name = {}
for variant_name, variant_env in variants.items():
tool = EnvironmentTool(variant_name, variant_env, self)
if variant_name in METADATA_KEYS:
continue
variant_label = label_by_key.get(variant_name) or variant_name
tool = EnvironmentTool(
variant_name, variant_label, variant_env, self
)
variants_by_name[variant_name] = tool
self.variants = variants_by_name
@ -372,8 +402,10 @@ class EnvironmentTool:
group (str): Name of group which wraps tool.
"""
def __init__(self, name, environment, group):
def __init__(self, name, label, environment, group):
self.name = name
self.variant_label = label
self.label = " ".join((group.label, label))
self.group = group
self._environment = environment
self.full_name = "/".join((group.name, name))
@ -502,7 +534,7 @@ class LaunchHook:
@property
def app_name(self):
return getattr(self.application, "name", None)
return getattr(self.application, "full_name", None)
def validate(self):
"""Optional validation of launch hook on initialization.
@ -804,10 +836,15 @@ class ApplicationLaunchContext:
self.log.debug("All prelaunch hook executed. Starting new process.")
# Prepare subprocess args
args = self.clear_launch_args(self.launch_args)
self.log.debug(
"Launching \"{}\" with args ({}): {}".format(
self.app_name, len(args), args
args_len_str = ""
if isinstance(self.launch_args, str):
args = self.launch_args
else:
args = self.clear_launch_args(self.launch_args)
args_len_str = " ({})".format(len(args))
self.log.info(
"Launching \"{}\" with args{}: {}".format(
self.app_name, args_len_str, args
)
)
# Run process
@ -853,7 +890,10 @@ class ApplicationLaunchContext:
Return:
list: Unpacked arguments.
"""
while True:
if isinstance(args, str):
return args
all_cleared = False
while not all_cleared:
all_cleared = True
new_args = []
for arg in args:
@ -865,8 +905,6 @@ class ApplicationLaunchContext:
new_args.append(arg)
args = new_args
if all_cleared:
break
return args
@ -939,7 +977,7 @@ def get_app_environments_for_context(
"project_name": project_name,
"asset_name": asset_name,
"task_name": task_name,
"app_name": app_name,
"app": app,
"dbcon": dbcon,
@ -1117,8 +1155,7 @@ def prepare_context_environments(data):
"AVALON_ASSET": asset_doc["name"],
"AVALON_TASK": task_name,
"AVALON_APP": app.host_name,
# TODO this hould be `app.full_name` in future PRs
"AVALON_APP_NAME": app.name,
"AVALON_APP_NAME": app.full_name,
"AVALON_WORKDIR": workdir
}
log.debug(

View file

@ -1123,6 +1123,7 @@ class BuildWorkfile:
return output
@with_avalon
def get_creator_by_name(creator_name, case_sensitive=False):
"""Find creator plugin by name.

View file

@ -5,6 +5,7 @@ from datetime import datetime
from abc import ABCMeta, abstractmethod
import json
# TODO Use pype igniter logic instead of using duplicated code
# disable lru cache in Python 2
try:
from functools import lru_cache
@ -25,11 +26,115 @@ except ImportError:
import platform
import appdirs
import six
import appdirs
from .import validate_mongo_connection
_PLACEHOLDER = object()
class OpenPypeSecureRegistry:
"""Store information using keyring.
Registry should be used for private data that should be available only for
user.
All passed registry names will have added prefix `OpenPype/` to easier
identify which data were created by OpenPype.
Args:
name(str): Name of registry used as identifier for data.
"""
def __init__(self, name):
try:
import keyring
except Exception:
raise NotImplementedError(
"Python module `keyring` is not available."
)
# hack for cx_freeze and Windows keyring backend
if platform.system().lower() == "windows":
from keyring.backends import Windows
keyring.set_keyring(Windows.WinVaultKeyring())
# Force "OpenPype" prefix
self._name = "/".join(("OpenPype", name))
def set_item(self, name, value):
# type: (str, str) -> None
"""Set sensitive item into system's keyring.
This uses `Keyring module`_ to save sensitive stuff into system's
keyring.
Args:
name (str): Name of the item.
value (str): Value of the item.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
import keyring
keyring.set_password(self._name, name, value)
@lru_cache(maxsize=32)
def get_item(self, name, default=_PLACEHOLDER):
"""Get value of sensitive item from system's keyring.
See also `Keyring module`_
Args:
name (str): Name of the item.
default (Any): Default value if item is not available.
Returns:
value (str): Value of the item.
Raises:
ValueError: If item doesn't exist and default is not defined.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
import keyring
value = keyring.get_password(self._name, name)
if value is not None:
return value
if default is not _PLACEHOLDER:
return default
# NOTE Should raise `KeyError`
raise ValueError(
"Item {}:{} does not exist in keyring.".format(self._name, name)
)
def delete_item(self, name):
# type: (str) -> None
"""Delete value stored in system's keyring.
See also `Keyring module`_
Args:
name (str): Name of the item to be deleted.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
import keyring
self.get_item.cache_clear()
keyring.delete_password(self._name, name)
@six.add_metaclass(ABCMeta)
class ASettingRegistry():
@ -48,13 +153,6 @@ class ASettingRegistry():
# type: (str) -> ASettingRegistry
super(ASettingRegistry, self).__init__()
if six.PY3:
import keyring
# hack for cx_freeze and Windows keyring backend
if platform.system() == "Windows":
from keyring.backends import Windows
keyring.set_keyring(Windows.WinVaultKeyring())
self._name = name
self._items = {}
@ -120,7 +218,7 @@ class ASettingRegistry():
"""Delete item from settings.
Note:
see :meth:`pype.lib.local_settings.ARegistrySettings.delete_item`
see :meth:`openpype.lib.user_settings.ARegistrySettings.delete_item`
"""
pass
@ -129,78 +227,6 @@ class ASettingRegistry():
del self._items[name]
self._delete_item(name)
def set_secure_item(self, name, value):
# type: (str, str) -> None
"""Set sensitive item into system's keyring.
This uses `Keyring module`_ to save sensitive stuff into system's
keyring.
Args:
name (str): Name of the item.
value (str): Value of the item.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
if six.PY2:
raise NotImplementedError(
"Keyring not available on Python 2 hosts")
import keyring
keyring.set_password(self._name, name, value)
@lru_cache(maxsize=32)
def get_secure_item(self, name):
# type: (str) -> str
"""Get value of sensitive item from system's keyring.
See also `Keyring module`_
Args:
name (str): Name of the item.
Returns:
value (str): Value of the item.
Raises:
ValueError: If item doesn't exist.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
if six.PY2:
raise NotImplementedError(
"Keyring not available on Python 2 hosts")
import keyring
value = keyring.get_password(self._name, name)
if not value:
raise ValueError(
"Item {}:{} does not exist in keyring.".format(
self._name, name))
return value
def delete_secure_item(self, name):
# type: (str) -> None
"""Delete value stored in system's keyring.
See also `Keyring module`_
Args:
name (str): Name of the item to be deleted.
.. _Keyring module:
https://github.com/jaraco/keyring
"""
if six.PY2:
raise NotImplementedError(
"Keyring not available on Python 2 hosts")
import keyring
self.get_secure_item.cache_clear()
keyring.delete_password(self._name, name)
class IniSettingRegistry(ASettingRegistry):
"""Class using :mod:`configparser`.
@ -218,7 +244,7 @@ class IniSettingRegistry(ASettingRegistry):
if not os.path.exists(self._registry_file):
with open(self._registry_file, mode="w") as cfg:
print("# Settings registry", cfg)
print("# Generated by Pype {}".format(version), cfg)
print("# Generated by OpenPype {}".format(version), cfg)
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
print("# {}".format(now), cfg)
@ -352,7 +378,7 @@ class IniSettingRegistry(ASettingRegistry):
"""Delete item from default section.
Note:
See :meth:`~pype.lib.IniSettingsRegistry.delete_item_from_section`
See :meth:`~openpype.lib.IniSettingsRegistry.delete_item_from_section`
"""
self.delete_item_from_section("MAIN", name)
@ -369,7 +395,7 @@ class JSONSettingRegistry(ASettingRegistry):
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
header = {
"__metadata__": {
"pype-version": os.getenv("OPENPYPE_VERSION", "N/A"),
"openpype-version": os.getenv("OPENPYPE_VERSION", "N/A"),
"generated": now
},
"registry": {}
@ -387,7 +413,7 @@ class JSONSettingRegistry(ASettingRegistry):
"""Get item value from registry json.
Note:
See :meth:`pype.lib.JSONSettingRegistry.get_item`
See :meth:`openpype.lib.JSONSettingRegistry.get_item`
"""
with open(self._registry_file, mode="r") as cfg:
@ -420,7 +446,7 @@ class JSONSettingRegistry(ASettingRegistry):
"""Set item value to registry json.
Note:
See :meth:`pype.lib.JSONSettingRegistry.set_item`
See :meth:`openpype.lib.JSONSettingRegistry.set_item`
"""
with open(self._registry_file, "r+") as cfg:
@ -452,8 +478,8 @@ class JSONSettingRegistry(ASettingRegistry):
json.dump(data, cfg, indent=4)
class PypeSettingsRegistry(JSONSettingRegistry):
"""Class handling Pype general settings registry.
class OpenPypeSettingsRegistry(JSONSettingRegistry):
"""Class handling OpenPype general settings registry.
Attributes:
vendor (str): Name used for path construction.
@ -461,21 +487,23 @@ class PypeSettingsRegistry(JSONSettingRegistry):
"""
def __init__(self):
def __init__(self, name=None):
self.vendor = "pypeclub"
self.product = "pype"
self.product = "openpype"
if not name:
name = "openpype_settings"
path = appdirs.user_data_dir(self.product, self.vendor)
super(PypeSettingsRegistry, self).__init__("pype_settings", path)
super(OpenPypeSettingsRegistry, self).__init__(name, path)
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 = PypeSettingsRegistry()
registry = OpenPypeSettingsRegistry()
new_id = str(uuid4())
new_id = generate_slug(3)
print("Created local site id \"{}\"".format(new_id))
@ -489,7 +517,7 @@ def get_local_site_id():
Identifier is created if does not exists yet.
"""
registry = PypeSettingsRegistry()
registry = OpenPypeSettingsRegistry()
try:
return registry.get_item("localId")
except ValueError:
@ -504,5 +532,9 @@ def change_openpype_mongo_url(new_mongo_url):
"""
validate_mongo_connection(new_mongo_url)
registry = PypeSettingsRegistry()
registry.set_secure_item("pypeMongo", new_mongo_url)
key = "openPypeMongo"
registry = OpenPypeSecureRegistry("mongodb")
existing_value = registry.get_item(key, None)
if existing_value is not None:
registry.delete_item(key)
registry.set_item(key, new_mongo_url)

View file

@ -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/'

View file

@ -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/"

View file

@ -252,7 +252,7 @@ class HarmonySubmitDeadline(
def get_job_info(self):
job_info = DeadlineJobInfo("Harmony")
job_info.Name = self._instance.data["name"]
job_info.Plugin = "HarmonyPype"
job_info.Plugin = "HarmonyOpenPype"
job_info.Frames = "{}-{}".format(
self._instance.data["frameStartHandle"],
self._instance.data["frameEndHandle"]

View file

@ -400,9 +400,9 @@ class CustomAttributes(BaseAction):
def tools_attribute(self, event):
tools_data = []
for tool_name in self.app_manager.tools.keys():
for tool_name, tool in self.app_manager.tools.items():
tools_data.append({
tool_name: tool_name
tool_name: tool.label
})
# Make sure there is at least one item

View file

@ -42,7 +42,7 @@ class FtrackModule(
ftrack_settings = settings[self.name]
self.enabled = ftrack_settings["enabled"]
self.ftrack_url = ftrack_settings["ftrack_server"]
self.ftrack_url = ftrack_settings["ftrack_server"].strip("/ ")
current_dir = os.path.dirname(os.path.abspath(__file__))
server_event_handlers_paths = [
@ -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 ""

View file

@ -1,4 +1,5 @@
import os
import time
import types
import logging
import traceback
@ -10,7 +11,6 @@ from openpype.lib import (
modules_from_path
)
log = PypeLogger.get_logger(__name__)
"""
@ -120,6 +120,18 @@ class FtrackServer:
if not session:
session = ftrack_api.Session(auto_connect_event_hub=True)
# Wait until session has connected event hub
if session._auto_connect_event_hub_thread:
# Use timeout from session (since ftrack-api 2.1.0)
timeout = getattr(session, "request_timeout", 60)
started = time.time()
while not session.event_hub.connected:
if (time.time() - started) > timeout:
raise RuntimeError((
"Connection to Ftrack was not created in {} seconds"
).format(timeout))
time.sleep(0.1)
self.session = session
if load_files:
if not self.handler_paths:

View file

@ -3,11 +3,11 @@ import sys
import logging
import getpass
import atexit
import tempfile
import threading
import datetime
import time
import queue
import appdirs
import pymongo
import requests
@ -165,7 +165,6 @@ class ProcessEventHub(SocketBaseEventHub):
def wait(self, duration=None):
"""Overriden wait
Event are loaded from Mongo DB when queue is empty. Handled event is
set as processed in Mongo DB.
"""
@ -252,7 +251,7 @@ class CustomEventHubSession(ftrack_api.session.Session):
self, server_url=None, api_key=None, api_user=None, auto_populate=True,
plugin_paths=None, cache=None, cache_key_maker=None,
auto_connect_event_hub=False, schema_cache_path=None,
plugin_arguments=None, **kwargs
plugin_arguments=None, timeout=60, **kwargs
):
self.kwargs = kwargs
@ -331,6 +330,7 @@ class CustomEventHubSession(ftrack_api.session.Session):
self._request.auth = ftrack_api.session.SessionAuthentication(
self._api_key, self._api_user
)
self.request_timeout = timeout
self.auto_populate = auto_populate
@ -368,8 +368,9 @@ class CustomEventHubSession(ftrack_api.session.Session):
# rebuilding types)?
if schema_cache_path is not False:
if schema_cache_path is None:
schema_cache_path = appdirs.user_cache_dir()
schema_cache_path = os.environ.get(
'FTRACK_API_SCHEMA_CACHE_PATH', tempfile.gettempdir()
'FTRACK_API_SCHEMA_CACHE_PATH', schema_cache_path
)
schema_cache_path = os.path.join(

View file

@ -9,7 +9,7 @@ class PrePython2Support(PreLaunchHook):
Path to vendor modules is added to the beggining of PYTHONPATH.
"""
# There will be needed more granular filtering in future
app_groups = ["maya", "nuke", "nukex", "hiero", "nukestudio"]
app_groups = ["maya", "nuke", "nukex", "hiero", "nukestudio", "unreal"]
def execute(self):
# Prepare vendor dir path

View file

@ -1256,19 +1256,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,

View file

@ -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

View file

@ -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

View file

@ -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):

View file

@ -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

View file

@ -40,8 +40,7 @@ class IdleManager(PypeModule, ITrayService):
name = "idle_manager"
def initialize(self, module_settings):
idle_man_settings = module_settings[self.name]
self.enabled = idle_man_settings["enabled"]
self.enabled = True
self.time_callbacks = collections.defaultdict(list)
self.idle_thread = None
@ -50,7 +49,8 @@ class IdleManager(PypeModule, ITrayService):
return
def tray_start(self):
self.start_thread()
if self.time_callbacks:
self.start_thread()
def tray_exit(self):
self.stop_thread()

View file

@ -45,11 +45,13 @@ class TimersManager(PypeModule, ITrayService, IIdleManager, IWebServerRoutes):
timers_settings = modules_settings[self.name]
self.enabled = timers_settings["enabled"]
auto_stop = timers_settings["auto_stop"]
# When timer will stop if idle manager is running (minutes)
full_time = int(timers_settings["full_time"] * 60)
# How many minutes before the timer is stopped will popup the message
message_time = int(timers_settings["message_time"] * 60)
self.auto_stop = auto_stop
self.time_show_message = full_time - message_time
self.time_stop_timer = full_time
@ -160,6 +162,9 @@ class TimersManager(PypeModule, ITrayService, IIdleManager, IWebServerRoutes):
def callbacks_by_idle_time(self):
"""Implementation of IIdleManager interface."""
# Time when message is shown
if not self.auto_stop:
return {}
callbacks = collections.defaultdict(list)
callbacks[self.time_show_message].append(lambda: self.time_callback(0))

View file

@ -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'] = {

View file

@ -54,11 +54,11 @@ def __main__():
print("Got Pype location from environment: {}".format(
os.environ.get('OPENPYPE_SETUP_PATH')))
pype_command = "pype.ps1"
pype_command = "openpype.ps1"
if platform.system().lower() == "linux":
pype_command = "pype"
elif platform.system().lower() == "windows":
pype_command = "pype.bat"
pype_command = "openpype.bat"
if kwargs.pype:
pype_root = kwargs.pype

View file

@ -14,7 +14,7 @@
"priority": 50,
"primary_pool": "",
"secondary_pool": "",
"chunk_size": 0
"chunk_size": 1000000
}
}
}

View file

@ -6,7 +6,9 @@
"load": "ctrl+alt+l",
"manage": "ctrl+alt+m",
"build_workfile": "ctrl+alt+b"
}
},
"open_workfile_at_start": false,
"create_initial_workfile": true
},
"create": {
"CreateWriteRender": {

View file

@ -19,9 +19,7 @@
"OPENPYPE_LOG_NO_COLORS": "Yes"
},
"variants": {
"maya_2020": {
"enabled": true,
"variant_label": "2020",
"2020": {
"executables": {
"windows": [
"C:\\Program Files\\Autodesk\\Maya2020\\bin\\maya.exe"
@ -40,9 +38,7 @@
"MAYA_VERSION": "2020"
}
},
"maya_2019": {
"enabled": true,
"variant_label": "2019",
"2019": {
"executables": {
"windows": [
"C:\\Program Files\\Autodesk\\Maya2019\\bin\\maya.exe"
@ -61,9 +57,7 @@
"MAYA_VERSION": "2019"
}
},
"maya_2018": {
"enabled": true,
"variant_label": "2018",
"2018": {
"executables": {
"windows": [
"C:\\Program Files\\Autodesk\\Maya2018\\bin\\maya.exe"
@ -84,86 +78,6 @@
}
}
},
"mayabatch": {
"enabled": true,
"label": "MayaBatch",
"icon": "{}/app_icons/maya.png",
"host_name": "maya",
"environment": {
"PYTHONPATH": [
"{OPENPYPE_ROOT}/avalon-core/setup/maya",
"{OPENPYPE_ROOT}/maya-look-assigner",
"{PYTHON_ENV}/python2/Lib/site-packages",
"{PYTHONPATH}"
],
"MAYA_DISABLE_CLIC_IPM": "Yes",
"MAYA_DISABLE_CIP": "Yes",
"MAYA_DISABLE_CER": "Yes",
"PYMEL_SKIP_MEL_INIT": "Yes",
"LC_ALL": "C",
"OPENPYPE_LOG_NO_COLORS": "Yes",
"MAYA_TEST": "{MAYA_VERSION}"
},
"variants": {
"mayabatch_2020": {
"enabled": true,
"variant_label": "2020",
"executables": {
"windows": [
"C:\\Program Files\\Autodesk\\Maya2020\\bin\\mayabatch.exe"
],
"darwin": [],
"linux": []
},
"arguments": {
"windows": [],
"darwin": [],
"linux": []
},
"environment": {
"MAYA_VERSION": "2020"
}
},
"mayabatch_2019": {
"enabled": true,
"variant_label": "2019",
"executables": {
"windows": [
"C:\\Program Files\\Autodesk\\Maya2019\\bin\\mayabatch.exe"
],
"darwin": [],
"linux": []
},
"arguments": {
"windows": [],
"darwin": [],
"linux": []
},
"environment": {
"MAYA_VERSION": "2019"
}
},
"mayabatch_2018": {
"enabled": true,
"variant_label": "2018",
"executables": {
"windows": [
"C:\\Program Files\\Autodesk\\Maya2018\\bin\\mayabatch.exe"
],
"darwin": [],
"linux": []
},
"arguments": {
"windows": [],
"darwin": [],
"linux": []
},
"environment": {
"MAYA_VERSION": "2018"
}
}
}
},
"nuke": {
"enabled": true,
"label": "Nuke",
@ -181,9 +95,7 @@
"LOGLEVEL": "DEBUG"
},
"variants": {
"nuke_12-2": {
"enabled": true,
"variant_label": "12.2",
"12-2": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe"
@ -200,9 +112,7 @@
},
"environment": {}
},
"nuke_12-0": {
"enabled": true,
"variant_label": "12.0",
"12-0": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe"
@ -219,9 +129,7 @@
},
"environment": {}
},
"nuke_11-3": {
"enabled": true,
"variant_label": "11.3",
"11-3": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe"
@ -238,9 +146,7 @@
},
"environment": {}
},
"nuke_11-2": {
"enabled": true,
"variant_label": "11.2",
"11-2": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe"
@ -254,6 +160,11 @@
"linux": []
},
"environment": {}
},
"__dynamic_keys_labels__": {
"12-2": "12.2",
"12-0": "12.0",
"11-3": "11.3"
}
}
},
@ -274,9 +185,7 @@
"LOGLEVEL": "DEBUG"
},
"variants": {
"nukex_12-2": {
"enabled": true,
"variant_label": "12.2",
"12-2": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe"
@ -299,9 +208,7 @@
},
"environment": {}
},
"nukex_12-0": {
"enabled": true,
"variant_label": "12.0",
"12-0": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe"
@ -324,9 +231,7 @@
},
"environment": {}
},
"nukex_11-3": {
"enabled": true,
"variant_label": "11.3",
"11-3": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe"
@ -349,9 +254,7 @@
},
"environment": {}
},
"nukex_11-2": {
"enabled": true,
"variant_label": "11.2",
"11-2": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe"
@ -371,6 +274,12 @@
]
},
"environment": {}
},
"__dynamic_keys_labels__": {
"12-2": "12.2",
"12-0": "12.0",
"11-3": "11.3",
"11-2": "11.2"
}
}
},
@ -391,9 +300,7 @@
"LOGLEVEL": "DEBUG"
},
"variants": {
"nukestudio_12-2": {
"enabled": true,
"variant_label": "12.2",
"12-2": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe"
@ -416,9 +323,7 @@
},
"environment": {}
},
"nukestudio_12-0": {
"enabled": true,
"variant_label": "12.0",
"12-0": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe"
@ -441,9 +346,7 @@
},
"environment": {}
},
"nukestudio_11-3": {
"enabled": true,
"variant_label": "11.3",
"11-3": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe"
@ -466,9 +369,7 @@
},
"environment": {}
},
"nukestudio_11-2": {
"enabled": true,
"variant_label": "11.2",
"11-2": {
"executables": {
"windows": [],
"darwin": [],
@ -486,6 +387,12 @@
]
},
"environment": {}
},
"__dynamic_keys_labels__": {
"12-2": "12.2",
"12-0": "12.0",
"11-3": "11.3",
"11-2": "11.2"
}
}
},
@ -506,9 +413,7 @@
"LOGLEVEL": "DEBUG"
},
"variants": {
"hiero_12-2": {
"enabled": true,
"variant_label": "12.2",
"12-2": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke12.2v3\\Nuke12.2.exe"
@ -531,9 +436,7 @@
},
"environment": {}
},
"hiero_12-0": {
"enabled": true,
"variant_label": "12.0",
"12-0": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke12.0v1\\Nuke12.0.exe"
@ -556,9 +459,7 @@
},
"environment": {}
},
"hiero_11-3": {
"enabled": true,
"variant_label": "11.3",
"11-3": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke11.3v1\\Nuke11.3.exe"
@ -581,9 +482,7 @@
},
"environment": {}
},
"hiero_11-2": {
"enabled": true,
"variant_label": "11.2",
"11-2": {
"executables": {
"windows": [
"C:\\Program Files\\Nuke11.2v2\\Nuke11.2.exe"
@ -603,6 +502,12 @@
]
},
"environment": {}
},
"__dynamic_keys_labels__": {
"12-2": "12.2",
"12-0": "12.0",
"11-3": "11.3",
"11-2": "11.2"
}
}
},
@ -636,7 +541,7 @@
"OPENPYPE_LOG_NO_COLORS": "Yes"
},
"variants": {
"fusion_16": {
"16": {
"enabled": true,
"variant_label": "16",
"executables": {
@ -651,7 +556,7 @@
},
"environment": {}
},
"fusion_9": {
"9": {
"enabled": true,
"variant_label": "9",
"executables": {
@ -714,7 +619,7 @@
"RESOLVE_DEV": "True"
},
"variants": {
"resolve_16": {
"16": {
"enabled": true,
"variant_label": "16",
"executables": {
@ -751,9 +656,7 @@
}
},
"variants": {
"houdini_18-5": {
"enabled": true,
"variant_label": "18.5",
"18-5": {
"executables": {
"windows": [
"C:\\Program Files\\Side Effects Software\\Houdini 18.5.499\\bin\\houdini.exe"
@ -768,9 +671,7 @@
},
"environment": {}
},
"houdini_18": {
"enabled": true,
"variant_label": "18",
"18": {
"executables": {
"windows": [],
"darwin": [],
@ -783,9 +684,7 @@
},
"environment": {}
},
"houdini_17": {
"enabled": true,
"variant_label": "17",
"17": {
"executables": {
"windows": [],
"darwin": [],
@ -797,6 +696,11 @@
"linux": []
},
"environment": {}
},
"__dynamic_keys_labels__": {
"18-5": "18.5",
"18": "18",
"17": "17"
}
}
},
@ -814,9 +718,7 @@
"CREATE_NEW_CONSOLE": "yes"
},
"variants": {
"blender_2-83": {
"enabled": true,
"variant_label": "2.83",
"2-83": {
"executables": {
"windows": [
"C:\\Program Files\\Blender Foundation\\Blender 2.83\\blender.exe"
@ -837,9 +739,7 @@
},
"environment": {}
},
"blender_2-90": {
"enabled": true,
"variant_label": "2.90",
"2-90": {
"executables": {
"windows": [
"C:\\Program Files\\Blender Foundation\\Blender 2.90\\blender.exe"
@ -859,6 +759,10 @@
]
},
"environment": {}
},
"__dynamic_keys_labels__": {
"2-83": "2.83",
"2-90": "2.90"
}
}
},
@ -872,7 +776,7 @@
"LIB_OPENHARMONY_PATH": "{OPENPYPE_ROOT}/pype/vendor/OpenHarmony"
},
"variants": {
"harmony_20": {
"20": {
"enabled": true,
"variant_label": "20",
"executables": {
@ -887,7 +791,7 @@
},
"environment": {}
},
"harmony_17": {
"17": {
"enabled": true,
"variant_label": "17",
"executables": {
@ -915,9 +819,7 @@
"OPENPYPE_LOG_NO_COLORS": "True"
},
"variants": {
"tvpaint_animation_11-64bits": {
"enabled": true,
"variant_label": "11 (64bits)",
"animation_11-64bits": {
"executables": {
"windows": [
"C:\\Program Files\\TVPaint Developpement\\TVPaint Animation 11 (64bits)\\TVPaint Animation 11 (64bits).exe"
@ -932,9 +834,7 @@
},
"environment": {}
},
"tvpaint_animation_11-32bits": {
"enabled": true,
"variant_label": "11 (32bits)",
"animation_11-32bits": {
"executables": {
"windows": [
"C:\\Program Files (x86)\\TVPaint Developpement\\TVPaint Animation 11 (32bits)\\TVPaint Animation 11 (32bits).exe"
@ -948,6 +848,10 @@
"linux": []
},
"environment": {}
},
"__dynamic_keys_labels__": {
"animation_11-64bits": "11 (64bits)",
"animation_11-32bits": "11 (32bits)"
}
}
},
@ -963,7 +867,7 @@
"WORKFILES_SAVE_AS": "Yes"
},
"variants": {
"photoshop_2020": {
"2020": {
"enabled": true,
"variant_label": "2020",
"executables": {
@ -980,7 +884,7 @@
},
"environment": {}
},
"photoshop_2021": {
"2021": {
"enabled": true,
"variant_label": "2021",
"executables": {
@ -1011,7 +915,7 @@
"WORKFILES_SAVE_AS": "Yes"
},
"variants": {
"aftereffects_2020": {
"2020": {
"enabled": true,
"variant_label": "2020",
"executables": {
@ -1028,7 +932,7 @@
},
"environment": {}
},
"aftereffects_2021": {
"2021": {
"enabled": true,
"variant_label": "2021",
"executables": {
@ -1056,10 +960,14 @@
"CELACTION_TEMPLATE": "{OPENPYPE_ROOT}/openpype/hosts/celaction/celaction_template_scene.scn"
},
"variants": {
"celation_Local": {
"local": {
"enabled": true,
"variant_label": "Local",
"executables": "",
"executables": {
"windows": [],
"darwin": [],
"linux": []
},
"arguments": {
"windows": [],
"darwin": [],
@ -1080,9 +988,7 @@
"QT_PREFERRED_BINDING": "PySide"
},
"variants": {
"unreal_4-24": {
"enabled": true,
"variant_label": "4.24",
"4-24": {
"executables": {
"windows": [],
"darwin": [],
@ -1101,9 +1007,7 @@
"enabled": true,
"environment": {},
"variants": {
"python_python_3-7": {
"enabled": true,
"variant_label": "3.7",
"python_3-7": {
"executables": {
"windows": [],
"darwin": [],
@ -1116,9 +1020,7 @@
},
"environment": {}
},
"python_python_2-7": {
"enabled": true,
"variant_label": "2.7",
"python_2-7": {
"executables": {
"windows": [],
"darwin": [],
@ -1131,9 +1033,7 @@
},
"environment": {}
},
"terminal_terminal": {
"enabled": true,
"variant_label": "",
"terminal": {
"executables": {
"windows": [],
"darwin": [],
@ -1145,6 +1045,10 @@
"linux": []
},
"environment": {}
},
"__dynamic_keys_labels__": {
"python_3-7": "Python 3.7",
"python_2-7": "Python 2.7"
}
}
},
@ -1155,9 +1059,7 @@
"host_name": "",
"environment": {},
"variants": {
"djvview_1-1": {
"enabled": true,
"variant_label": "1.1",
"1-1": {
"executables": {
"windows": [],
"darwin": [],
@ -1169,6 +1071,9 @@
"linux": []
},
"environment": {}
},
"__dynamic_keys_labels__": {
"1-1": "1.1"
}
}
}

View file

@ -126,6 +126,7 @@
},
"timers_manager": {
"enabled": true,
"auto_stop": true,
"full_time": 15.0,
"message_time": 0.5
},
@ -165,8 +166,5 @@
},
"standalonepublish_tool": {
"enabled": true
},
"idle_manager": {
"enabled": true
}
}

View file

@ -226,7 +226,16 @@ class DictMutableKeysEntity(EndpointEntity):
self.is_group = True
def schema_validations(self):
# Allow to have not set label if keys are collapsible
# - this it to bypass label validation
used_temp_label = False
if self.is_group and not self.label and self.collapsible_key:
used_temp_label = True
self.label = "LABEL"
super(DictMutableKeysEntity, self).schema_validations()
if used_temp_label:
self.label = None
if not self.schema_data.get("object_type"):
reason = (

View file

@ -117,7 +117,8 @@ class AppsEnumEntity(BaseEnumEntity):
valid_keys = set()
enum_items = []
for app_group in system_settings_entity["applications"].values():
applications_entity = system_settings_entity["applications"]
for group_name, app_group in applications_entity.items():
enabled_entity = app_group.get("enabled")
if enabled_entity and not enabled_entity.value:
continue
@ -127,17 +128,29 @@ class AppsEnumEntity(BaseEnumEntity):
continue
group_label = app_group["label"].value
for variant_name, variant_entity in app_group["variants"].items():
variants_entity = app_group["variants"]
for variant_name, variant_entity in variants_entity.items():
enabled_entity = variant_entity.get("enabled")
if enabled_entity and not enabled_entity.value:
continue
variant_label = variant_entity["variant_label"].value
variant_label = None
if "variant_label" in variant_entity:
variant_label = variant_entity["variant_label"].value
elif hasattr(variants_entity, "get_key_label"):
variant_label = variants_entity.get_key_label(variant_name)
full_label = "{} {}".format(group_label, variant_label)
enum_items.append({variant_name: full_label})
valid_keys.add(variant_name)
if not variant_label:
variant_label = variant_name
if group_label:
full_label = "{} {}".format(group_label, variant_label)
else:
full_label = variant_label
full_name = "/".join((group_name, variant_name))
enum_items.append({full_name: full_label})
valid_keys.add(full_name)
return enum_items, valid_keys
def set_override_state(self, *args, **kwargs):

View file

@ -43,6 +43,16 @@
"label": "Build Workfile"
}
]
},
{
"type": "boolean",
"key": "open_workfile_at_start",
"label": "Open Workfile window at start of a Nuke session"
},
{
"type": "boolean",
"key": "create_initial_workfile",
"label": "Create initial workfile version if none available"
}
]
},
@ -87,7 +97,7 @@
"name": "schema_nuke_publish",
"template_data": []
},
{
{
"type": "schema",
"name": "schema_nuke_load",
"template_data": []
@ -101,4 +111,4 @@
"name": "schema_publish_gui_filter"
}
]
}
}

View file

@ -29,13 +29,11 @@
"template_data": [
{
"app_variant_label": "2020",
"app_variant": "2020",
"app_name": "aftereffects"
"app_variant": "2020"
},
{
"app_variant_label": "2021",
"app_variant": "2021",
"app_name": "aftereffects"
"app_variant": "2021"
}
]
}

View file

@ -20,26 +20,22 @@
"type": "raw-json"
},
{
"type": "dict",
"type": "dict-modifiable",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": [
{
"app_variant_label": "2.83",
"app_variant": "2-83",
"app_name": "blender"
},
{
"app_variant_label": "2.90",
"app_variant": "2-90",
"app_name": "blender"
}
]
}
]
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "schema_template",
"name": "template_host_variant_items"
}
]
}
}
]
}

View file

@ -29,10 +29,7 @@
"template_data": [
{
"app_variant_label": "Local",
"app_variant": "Local",
"app_name": "celation",
"multiplatform": false,
"multipath_executables": false
"app_variant": "local"
}
]
}

View file

@ -20,19 +20,22 @@
"type": "raw-json"
},
{
"type": "dict",
"type": "dict-modifiable",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": {
"app_variant_label": "1.1",
"app_variant": "1-1",
"app_name": "djvview"
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "schema_template",
"name": "template_host_variant_items"
}
}
]
]
}
}
]
}

View file

@ -29,13 +29,11 @@
"template_data": [
{
"app_variant_label": "16",
"app_variant": "16",
"app_name": "fusion"
"app_variant": "16"
},
{
"app_variant_label": "9",
"app_variant": "9",
"app_name": "fusion"
"app_variant": "9"
}
]
}

View file

@ -29,13 +29,11 @@
"template_data": [
{
"app_variant_label": "20",
"app_variant": "20",
"app_name": "harmony"
"app_variant": "20"
},
{
"app_variant_label": "17",
"app_variant": "17",
"app_name": "harmony"
"app_variant": "17"
}
]
}

View file

@ -20,31 +20,22 @@
"type": "raw-json"
},
{
"type": "dict",
"type": "dict-modifiable",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": [
{
"app_variant_label": "18.5",
"app_variant": "18-5",
"app_name": "houdini"
},
{
"app_variant_label": "18",
"app_variant": "18",
"app_name": "houdini"
},
{
"app_variant_label": "17",
"app_variant": "17",
"app_name": "houdini"
}
]
}
]
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "schema_template",
"name": "template_host_variant_items"
}
]
}
}
]
}

View file

@ -20,31 +20,22 @@
"type": "raw-json"
},
{
"type": "dict",
"type": "dict-modifiable",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": [
{
"app_variant_label": "2020",
"app_variant": "2020",
"app_name": "maya"
},
{
"app_variant_label": "2019",
"app_variant": "2019",
"app_name": "maya"
},
{
"app_variant_label": "2018",
"app_variant": "2018",
"app_name": "maya"
}
]
}
]
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "schema_template",
"name": "template_host_variant_items"
}
]
}
}
]
}

View file

@ -1,50 +0,0 @@
{
"type": "dict",
"key": "mayabatch",
"label": "Autodesk Maya Batch",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "schema_template",
"name": "template_host_unchangables"
},
{
"key": "environment",
"label": "Environment",
"type": "raw-json"
},
{
"type": "dict",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": [
{
"app_variant_label": "2020",
"app_variant": "2020",
"app_name": "mayabatch"
},
{
"app_variant_label": "2019",
"app_variant": "2019",
"app_name": "mayabatch"
},
{
"app_variant_label": "2018",
"app_variant": "2018",
"app_name": "mayabatch"
}
]
}
]
}
]
}

View file

@ -29,13 +29,11 @@
"template_data": [
{
"app_variant_label": "2020",
"app_variant": "2020",
"app_name": "photoshop"
"app_variant": "2020"
},
{
"app_variant_label": "2021",
"app_variant": "2021",
"app_name": "photoshop"
"app_variant": "2021"
}
]
}

View file

@ -29,8 +29,7 @@
"template_data": [
{
"app_variant_label": "16",
"app_variant": "16",
"app_name": "resolve"
"app_variant": "16"
}
]
}

View file

@ -16,31 +16,22 @@
"type": "raw-json"
},
{
"type": "dict",
"type": "dict-modifiable",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": [
{
"app_variant": "python_3-7",
"app_variant_label": "Python 3.7",
"app_name": "python"
},
{
"app_variant": "python_2-7",
"app_variant_label": "Python 2.7",
"app_name": "python"
},
{
"app_variant": "terminal",
"app_variant_label": "Terminal",
"app_name": "terminal"
}
]
}
]
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "schema_template",
"name": "template_host_variant_items"
}
]
}
}
]
}

View file

@ -20,26 +20,22 @@
"type": "raw-json"
},
{
"type": "dict",
"type": "dict-modifiable",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": [
{
"app_variant_label": "Animation 11 (64bits)",
"app_variant": "animation_11-64bits",
"app_name": "tvpaint"
},
{
"app_variant_label": "Animation 11 (32bits)",
"app_variant": "animation_11-32bits",
"app_name": "tvpaint"
}
]
}
]
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "schema_template",
"name": "template_host_variant_items"
}
]
}
}
]
}

View file

@ -20,21 +20,22 @@
"type": "raw-json"
},
{
"type": "dict",
"type": "dict-modifiable",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": [
{
"app_variant": "4-24",
"app_variant_label": "4.24",
"app_name": "unreal"
}
]
}
]
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "schema_template",
"name": "template_host_variant_items"
}
]
}
}
]
}

View file

@ -1,13 +1,7 @@
[
{
"__default_values__": {
"multipath_executables": true,
"multiplatform": true
}
},
{
"type": "dict",
"key": "{app_name}_{app_variant}",
"key": "{app_variant}",
"label": "{app_variant_label}",
"collapsible": true,
"checkbox_key": "enabled",
@ -21,49 +15,11 @@
"type": "text",
"key": "variant_label",
"label": "Variant label",
"placeholder": "Only \"Label\" is used if not filled.",
"roles": ["developer"]
"placeholder": "< {app_variant} >"
},
{
"type": "path",
"key": "executables",
"label": "Executables",
"multiplatform": "{multiplatform}",
"multipath": "{multipath_executables}"
},
{
"type":"separator"
},
{
"type": "dict",
"key": "arguments",
"label": "Arguments",
"use_label_wrap": false,
"children": [
{
"key": "windows",
"label": "Windows",
"type": "list",
"object_type": "text"
},
{
"key": "darwin",
"label": "MacOS",
"type": "list",
"object_type": "text"
},
{
"key": "linux",
"label": "Linux",
"type": "list",
"object_type": "text"
}
]
},
{
"key": "environment",
"label": "Environment",
"type": "raw-json"
"type": "schema_template",
"name": "template_host_variant_items"
}
]
}

View file

@ -0,0 +1,43 @@
[
{
"type": "path",
"key": "executables",
"label": "Executables",
"multiplatform": true,
"multipath": true
},
{
"type":"separator"
},
{
"type": "dict",
"key": "arguments",
"label": "Arguments",
"use_label_wrap": false,
"children": [
{
"key": "windows",
"label": "Windows",
"type": "list",
"object_type": "text"
},
{
"key": "darwin",
"label": "MacOS",
"type": "list",
"object_type": "text"
},
{
"key": "linux",
"label": "Linux",
"type": "list",
"object_type": "text"
}
]
},
{
"key": "environment",
"label": "Environment",
"type": "raw-json"
}
]

View file

@ -21,36 +21,22 @@
"type": "raw-json"
},
{
"type": "dict",
"type": "dict-modifiable",
"key": "variants",
"children": [
{
"type": "schema_template",
"name": "template_host_variant",
"template_data": [
{
"app_variant": "12-2",
"app_variant_label": "12.2",
"app_name": "{nuke_type}"
},
{
"app_variant": "12-0",
"app_variant_label": "12.0",
"app_name": "{nuke_type}"
},
{
"app_variant": "11-3",
"app_variant_label": "11.3",
"app_name": "{nuke_type}"
},
{
"app_variant": "11-2",
"app_variant_label": "11.2",
"app_name": "{nuke_type}"
}
]
}
]
"collapsible_key": true,
"dynamic_label": false,
"use_label_wrap": false,
"object_type": {
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "schema_template",
"name": "template_host_variant_items"
}
]
}
}
]
}

View file

@ -9,10 +9,6 @@
"type": "schema",
"name": "schema_maya"
},
{
"type": "schema",
"name": "schema_mayabatch"
},
{
"type": "schema_template",
"name": "template_nuke",

View file

@ -42,6 +42,11 @@
"key": "enabled",
"label": "Enabled"
},
{
"type": "boolean",
"key": "auto_stop",
"label": "Auto stop timer"
},
{
"type": "number",
"decimal": 2,
@ -176,20 +181,6 @@
"label": "Enabled"
}
]
},
{
"type": "dict",
"key": "idle_manager",
"label": "Idle Manager",
"collapsible": true,
"checkbox_key": "enabled",
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
}
]
}
]
}

View file

@ -489,7 +489,7 @@ def apply_local_settings_on_system_settings(system_settings, local_settings):
# TODO This is temporary fix until launch arguments will be stored
# per platform and not per executable.
# - local settings store only executable
new_executables = [[executable, ""]]
new_executables = [executable]
new_executables.extend(platform_executables)
variants[app_name]["executables"] = new_executables
@ -645,13 +645,22 @@ def apply_local_settings_on_project_settings(
sync_server_config["remote_site"] = remote_site
def get_system_settings(clear_metadata=True):
def get_system_settings(clear_metadata=True, exclude_locals=None):
"""System settings with applied studio overrides."""
default_values = get_default_settings()[SYSTEM_SETTINGS_KEY]
studio_values = get_studio_system_settings_overrides()
result = apply_overrides(default_values, studio_values)
# Clear overrides metadata from settings
if clear_metadata:
clear_metadata_from_settings(result)
# Apply local settings
# Default behavior is based on `clear_metadata` value
if exclude_locals is None:
exclude_locals = not clear_metadata
if not exclude_locals:
# TODO local settings may be required to apply for environments
local_settings = get_local_settings()
apply_local_settings_on_system_settings(result, local_settings)
@ -659,40 +668,52 @@ def get_system_settings(clear_metadata=True):
return result
def get_default_project_settings(clear_metadata=True, exclude_locals=False):
def get_default_project_settings(clear_metadata=True, exclude_locals=None):
"""Project settings with applied studio's default project overrides."""
default_values = get_default_settings()[PROJECT_SETTINGS_KEY]
studio_values = get_studio_project_settings_overrides()
result = apply_overrides(default_values, studio_values)
# Clear overrides metadata from settings
if clear_metadata:
clear_metadata_from_settings(result)
if not exclude_locals:
local_settings = get_local_settings()
apply_local_settings_on_project_settings(
result, local_settings, None
)
# Apply local settings
if exclude_locals is None:
exclude_locals = not clear_metadata
if not exclude_locals:
local_settings = get_local_settings()
apply_local_settings_on_project_settings(
result, local_settings, None
)
return result
def get_default_anatomy_settings(clear_metadata=True, exclude_locals=False):
def get_default_anatomy_settings(clear_metadata=True, exclude_locals=None):
"""Project anatomy data with applied studio's default project overrides."""
default_values = get_default_settings()[PROJECT_ANATOMY_KEY]
studio_values = get_studio_project_anatomy_overrides()
# TODO uncomment and remove hotfix result when overrides of anatomy
# are stored correctly.
result = apply_overrides(default_values, studio_values)
# Clear overrides metadata from settings
if clear_metadata:
clear_metadata_from_settings(result)
if not exclude_locals:
local_settings = get_local_settings()
apply_local_settings_on_anatomy_settings(
result, local_settings, None
)
# Apply local settings
if exclude_locals is None:
exclude_locals = not clear_metadata
if not exclude_locals:
local_settings = get_local_settings()
apply_local_settings_on_anatomy_settings(
result, local_settings, None
)
return result
def get_anatomy_settings(project_name, site_name=None, exclude_locals=False):
def get_anatomy_settings(
project_name, site_name=None, clear_metadata=True, exclude_locals=None
):
"""Project anatomy data with applied studio and project overrides."""
if not project_name:
raise ValueError(
@ -709,7 +730,13 @@ def get_anatomy_settings(project_name, site_name=None, exclude_locals=False):
for key, value in project_overrides.items():
result[key] = value
clear_metadata_from_settings(result)
# Clear overrides metadata from settings
if clear_metadata:
clear_metadata_from_settings(result)
# Apply local settings
if exclude_locals is None:
exclude_locals = not clear_metadata
if not exclude_locals:
local_settings = get_local_settings()
@ -719,7 +746,9 @@ def get_anatomy_settings(project_name, site_name=None, exclude_locals=False):
return result
def get_project_settings(project_name, exclude_locals=False):
def get_project_settings(
project_name, clear_metadata=True, exclude_locals=None
):
"""Project settings with applied studio and project overrides."""
if not project_name:
raise ValueError(
@ -733,7 +762,14 @@ def get_project_settings(project_name, exclude_locals=False):
)
result = apply_overrides(studio_overrides, project_overrides)
clear_metadata_from_settings(result)
# Clear overrides metadata from settings
if clear_metadata:
clear_metadata_from_settings(result)
# Apply local settings
if exclude_locals is None:
exclude_locals = not clear_metadata
if not exclude_locals:
local_settings = get_local_settings()

View file

@ -11,6 +11,7 @@ from avalon.tools import lib as tools_lib
from avalon.tools.widgets import AssetWidget
from avalon.vendor import qtawesome
from .models import ProjectModel
from .lib import get_action_label
from .widgets import (
ProjectBar,
ActionBar,
@ -407,7 +408,7 @@ class LauncherWindow(QtWidgets.QDialog):
self.discover_actions()
def on_action_clicked(self, action):
self.echo("Running action: {}".format(action.name))
self.echo("Running action: {}".format(get_action_label(action)))
self.run_action(action)
def on_history_action(self, history_data):

View file

@ -10,12 +10,20 @@ from .constants import CHILD_OFFSET
class AppVariantWidget(QtWidgets.QWidget):
exec_placeholder = "< Specific path for this machine >"
def __init__(self, group_label, variant_entity, parent):
def __init__(self, group_label, variant_name, variant_entity, parent):
super(AppVariantWidget, self).__init__(parent)
self.executable_input_widget = None
variant_label = variant_entity.label
if variant_label is None:
parent_entity = variant_entity.parent
if hasattr(parent_entity, "get_key_label"):
variant_label = parent_entity.get_key_label(variant_name)
label = " ".join([group_label, variant_entity.label])
if not variant_label:
variant_label = variant_name
label = " ".join([group_label, variant_label])
expading_widget = ExpandingWidget(label, self)
content_widget = QtWidgets.QWidget(expading_widget)
@ -102,7 +110,7 @@ class AppGroupWidget(QtWidgets.QWidget):
valid_variants = {}
for key, entity in group_entity["variants"].items():
if entity["enabled"].value:
if "enabled" not in entity or entity["enabled"].value:
valid_variants[key] = entity
group_label = group_entity.label
@ -114,7 +122,7 @@ class AppGroupWidget(QtWidgets.QWidget):
widgets_by_variant_name = {}
for variant_name, variant_entity in valid_variants.items():
variant_widget = AppVariantWidget(
group_label, variant_entity, content_widget
group_label, variant_name, variant_entity, content_widget
)
widgets_by_variant_name[variant_name] = variant_widget
content_layout.addWidget(variant_widget)
@ -173,7 +181,10 @@ class LocalApplicationsWidgets(QtWidgets.QWidget):
# Check if has enabled any variant
enabled_variant = False
for variant_entity in entity["variants"].values():
if variant_entity["enabled"].value:
if (
"enabled" not in variant_entity
or variant_entity["enabled"].value
):
enabled_variant = True
break

View file

@ -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

View file

@ -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:

View file

@ -103,7 +103,10 @@ class ModifiableDictEmptyItem(QtWidgets.QWidget):
self.key_is_valid = KEY_REGEX.match(key)
self.is_duplicated = self.entity_widget.is_key_duplicated(key)
key_input_state = ""
if self.is_duplicated or not self.key_is_valid:
# Collapsible key and empty key are not invalid
if self.collapsible_key and self.key_input.text() == "":
pass
elif self.is_duplicated or not self.key_is_valid:
key_input_state = "invalid"
elif key != "":
key_input_state = "modified"
@ -550,7 +553,9 @@ class DictMutableKeysWidget(BaseWidget):
label = self.entity.label
body_widget = None
content_left_margin = 0
if label:
content_left_margin = CHILD_OFFSET
body_widget = ExpandingWidget(label, self)
main_layout.addWidget(body_widget)
label = None
@ -565,7 +570,9 @@ class DictMutableKeysWidget(BaseWidget):
content_widget.setObjectName("ContentWidget")
content_widget.setProperty("content_state", content_state)
content_layout = QtWidgets.QVBoxLayout(content_widget)
content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, bottom_margin)
content_layout.setContentsMargins(
content_left_margin, 5, 0, bottom_margin
)
if body_widget is None:
main_layout.addWidget(content_widget)

View file

@ -160,32 +160,11 @@ def set_context(project, asset, task):
os.environ["AVALON_TASK"] = task
io.Session["AVALON_TASK"] = task
io.install()
av_project = io.find_one({'type': 'project'})
av_asset = io.find_one({
"type": 'asset',
"name": asset
})
parents = av_asset['data']['parents']
hierarchy = ''
if parents and len(parents) > 0:
hierarchy = os.path.sep.join(parents)
os.environ["AVALON_HIERARCHY"] = hierarchy
io.Session["AVALON_HIERARCHY"] = hierarchy
os.environ["AVALON_PROJECTCODE"] = av_project['data'].get('code', '')
io.Session["AVALON_PROJECTCODE"] = av_project['data'].get('code', '')
io.Session["current_dir"] = os.path.normpath(os.getcwd())
os.environ["AVALON_APP"] = HOST_NAME
io.Session["AVALON_APP"] = HOST_NAME
io.uninstall()
def cli_publish(data, publish_paths, gui=True):
PUBLISH_SCRIPT_PATH = os.path.join(

View file

@ -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"]

322
poetry.lock generated
View file

@ -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
@ -318,17 +326,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"
@ -358,7 +366,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
@ -396,7 +404,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
@ -441,7 +449,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
@ -468,7 +476,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
@ -480,7 +488,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"
@ -492,7 +500,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
@ -591,11 +599,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"
@ -665,7 +673,7 @@ pyparsing = ">=2.0.2"
[[package]]
name = "parso"
version = "0.8.1"
version = "0.8.2"
description = "A Python Parser"
category = "dev"
optional = false
@ -688,7 +696,7 @@ six = "*"
[[package]]
name = "pillow"
version = "8.1.2"
version = "8.2.0"
description = "Python Imaging Library (Fork)"
category = "main"
optional = false
@ -718,7 +726,7 @@ python-versions = "*"
[[package]]
name = "protobuf"
version = "3.15.6"
version = "3.15.7"
description = "Protocol Buffers"
category = "main"
optional = false
@ -772,7 +780,7 @@ python-versions = "*"
[[package]]
name = "pycodestyle"
version = "2.6.0"
version = "2.7.0"
description = "Python style guide checker"
category = "dev"
optional = false
@ -800,7 +808,7 @@ snowballstemmer = "*"
[[package]]
name = "pyflakes"
version = "2.2.0"
version = "2.3.1"
description = "passive checker of Python programs"
category = "dev"
optional = false
@ -816,14 +824,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"
@ -941,7 +949,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
@ -1132,7 +1140,7 @@ python-versions = "*"
[[package]]
name = "sphinx"
version = "3.5.2"
version = "3.5.3"
description = "Python documentation generator"
category = "dev"
optional = false
@ -1291,7 +1299,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
@ -1328,16 +1336,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"
@ -1368,7 +1376,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
@ -1411,7 +1419,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt
[metadata]
lock-version = "1.1"
python-versions = "3.7.*"
content-hash = "b356e327dbaa1aa38dbf1463901f64539f2c8d07be8d8a017e83b8a1554dbff9"
content-hash = "a8c9915ce3096b74b9328a632911a759780844d368fa1d6d0fbd7c5d7d4536cf"
[metadata.files]
acre = []
@ -1475,8 +1483,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"},
@ -1491,8 +1499,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"},
@ -1569,6 +1577,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"},
@ -1624,18 +1636,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"},
@ -1653,8 +1665,8 @@ 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"},
]
enlighten = [
{file = "enlighten-1.9.0-py2.py3-none-any.whl", hash = "sha256:5c59e41505702243c6b26437403e371d2a146ac72de5f706376f738ea8f32659"},
@ -1664,8 +1676,8 @@ 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"},
@ -1675,16 +1687,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"},
@ -1695,8 +1707,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"},
@ -1707,16 +1719,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"},
@ -1743,30 +1755,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"},
@ -1874,47 +1884,47 @@ 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"},
@ -1925,26 +1935,26 @@ prefixed = [
{file = "prefixed-0.3.2.tar.gz", hash = "sha256:ca48277ba5fa8346dd4b760847da930c7b84416387c39e93affef086add2c029"},
]
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"},
@ -1988,8 +1998,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"},
@ -2001,16 +2011,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"},
@ -2151,8 +2161,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"},
@ -2226,8 +2236,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"},
@ -2273,8 +2283,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"},
@ -2318,8 +2328,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"},
@ -2333,8 +2343,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"},

View file

@ -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"

View file

@ -6,7 +6,8 @@ exclude =
.git,
__pycache__,
docs,
*/vendor
*/vendor,
website
max-complexity = 30

View file

@ -296,7 +296,7 @@ def _determine_mongodb() -> str:
if not openpype_mongo:
# try system keyring
try:
openpype_mongo = bootstrap.registry.get_secure_item(
openpype_mongo = bootstrap.secure_registry.get_item(
"openPypeMongo")
except ValueError:
print("*** No DB connection string specified.")
@ -305,7 +305,7 @@ def _determine_mongodb() -> str:
igniter.open_dialog()
try:
openpype_mongo = bootstrap.registry.get_secure_item(
openpype_mongo = bootstrap.secure_registry.get_item(
"openPypeMongo")
except ValueError:
raise RuntimeError("missing mongodb url")
@ -326,6 +326,7 @@ def _initialize_environment(openpype_version: OpenPypeVersion) -> None:
# TODO move additional paths to `boot` part when OPENPYPE_ROOT will point
# to same hierarchy from code and from frozen OpenPype
additional_paths = [
os.environ["OPENPYPE_ROOT"],
# add OpenPype tools
os.path.join(os.environ["OPENPYPE_ROOT"], "openpype", "tools"),
# add common OpenPype vendor

View file

@ -11,7 +11,7 @@ import pytest
from igniter.bootstrap_repos import BootstrapRepos
from igniter.bootstrap_repos import PypeVersion
from pype.lib import PypeSettingsRegistry
from pype.lib import OpenPypeSettingsRegistry
@pytest.fixture
@ -348,7 +348,7 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer):
return d_path.as_posix()
monkeypatch.setattr(appdirs, "user_data_dir", mock_user_data_dir)
fix_bootstrap.registry = PypeSettingsRegistry()
fix_bootstrap.registry = OpenPypeSettingsRegistry()
fix_bootstrap.registry.set_item("pypePath", d_path.as_posix())
result = fix_bootstrap.find_pype(include_zips=True)

View file

@ -1,10 +1,20 @@
import pytest
from pype.lib import IniSettingRegistry
from pype.lib import JSONSettingRegistry
from pype.lib import (
IniSettingRegistry,
JSONSettingRegistry,
OpenPypeSecureRegistry
)
from uuid import uuid4
import configparser
@pytest.fixture
def secure_registry(tmpdir):
name = "pypetest_{}".format(str(uuid4()))
r = OpenPypeSecureRegistry(name, tmpdir)
yield r
@pytest.fixture
def json_registry(tmpdir):
name = "pypetest_{}".format(str(uuid4()))
@ -19,21 +29,21 @@ def ini_registry(tmpdir):
yield r
def test_keyring(json_registry):
json_registry.set_secure_item("item1", "foo")
json_registry.set_secure_item("item2", "bar")
result1 = json_registry.get_secure_item("item1")
result2 = json_registry.get_secure_item("item2")
def test_keyring(secure_registry):
secure_registry.set_item("item1", "foo")
secure_registry.set_item("item2", "bar")
result1 = secure_registry.get_item("item1")
result2 = secure_registry.get_item("item2")
assert result1 == "foo"
assert result2 == "bar"
json_registry.delete_secure_item("item1")
json_registry.delete_secure_item("item2")
secure_registry.delete_item("item1")
secure_registry.delete_item("item2")
with pytest.raises(ValueError):
json_registry.get_secure_item("item1")
json_registry.get_secure_item("item2")
secure_registry.get_item("item1")
secure_registry.get_item("item2")
def test_ini_registry(ini_registry):

View file

@ -157,11 +157,12 @@ Write-Host "Reading Poetry ... " -NoNewline
if (-not (Test-Path -PathType Container -Path "$($env:USERPROFILE)\.poetry\bin")) {
Write-Host "NOT FOUND" -ForegroundColor Yellow
Install-Poetry
Write-Host "INSTALLED" -ForegroundColor Cyan
} else {
Write-Host "OK" -ForegroundColor Green
}
$env:PATH = "$($env:PATH);$($env:USERPROFILE)\.poetry\bin"
Write-Host ">>> " -NoNewline -ForegroundColor green
Write-Host "Cleaning cache files ... " -NoNewline
@ -172,6 +173,7 @@ Write-Host "OK" -ForegroundColor green
Write-Host ">>> " -NoNewline -ForegroundColor green
Write-Host "Building OpenPype ..."
$out = & poetry run python setup.py build 2>&1
if ($LASTEXITCODE -ne 0)
{

View file

@ -172,6 +172,7 @@ main () {
poetry run python -m pip install --upgrade pip
poetry run pip install --force-reinstall setuptools
poetry run pip install --force-reinstall wheel
poetry run python -m pip install --force-reinstall pip
}
main -3

Some files were not shown because too many files have changed in this diff Show more