From c30b917e6ca5c4e754bc60450de9495482051ebd Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 22 Jun 2021 17:53:09 +0200 Subject: [PATCH 001/150] remove PyQt5 and add PySide2 --- openpype/lib/import_utils.py | 15 +++++++ poetry.lock | 75 ++++++--------------------------- pyproject.toml | 1 - tools/fetch_thirdparty_libs.ps1 | 3 ++ 4 files changed, 31 insertions(+), 63 deletions(-) diff --git a/openpype/lib/import_utils.py b/openpype/lib/import_utils.py index 4e72618803..9f459bbb51 100644 --- a/openpype/lib/import_utils.py +++ b/openpype/lib/import_utils.py @@ -2,6 +2,7 @@ import os import sys import importlib from .log import PypeLogger as Logger +from pathlib import Path log = Logger().get_logger(__name__) @@ -23,3 +24,17 @@ def discover_host_vendor_module(module_name): sys.path.insert(1, module_path) return importlib.import_module(module_name) + + +def get_pyside2_location(): + """Get location of PySide2 and its dependencies. + + Returned path can be used with `site.addsitedir()` + + Returns: + str: path to PySide2 + + """ + path = Path(os.getenv("OPENPYPE_ROOT")) + path = path / "vendor/python/PySide2" + return str(path) diff --git a/poetry.lock b/poetry.lock index 48e6f95469..869e953060 100644 --- a/poetry.lock +++ b/poetry.lock @@ -941,34 +941,6 @@ category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -[[package]] -name = "pyqt5" -version = "5.15.4" -description = "Python bindings for the Qt cross platform application toolkit" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -PyQt5-Qt5 = ">=5.15" -PyQt5-sip = ">=12.8,<13" - -[[package]] -name = "pyqt5-qt5" -version = "5.15.2" -description = "The subset of a Qt installation needed by PyQt5." -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "pyqt5-sip" -version = "12.9.0" -description = "The sip module support for PyQt5" -category = "main" -optional = false -python-versions = ">=3.5" - [[package]] name = "pyrsistent" version = "0.17.3" @@ -1466,7 +1438,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "8875d530ae66f9763b5b0cb84d9d35edc184ef5c141b63d38bf1ff5a1226e556" +content-hash = "70c5951f20ded8f10757ea030f7a99a49c1ea6773ad944f922533b692a3c5166" [metadata.files] acre = [] @@ -1582,24 +1554,36 @@ cffi = [ {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24ec4ff2c5c0c8f9c6b87d5bb53555bf267e1e6f70e52e5a9740d32861d36b6f"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c3f39fa737542161d8b0d680df2ec249334cd70a8f420f71c9304bd83c3cbed"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:681d07b0d1e3c462dd15585ef5e33cb021321588bebd910124ef4f4fb71aef55"}, {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06d7cd1abac2ffd92e65c0609661866709b4b2d82dd15f611e602b9b188b0b69"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f861a89e0043afec2a51fd177a567005847973be86f709bbb044d7f42fc4e05"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc5a8e069b9ebfa22e26d0e6b97d6f9781302fe7f4f2b8776c3e1daea35f1adc"}, {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04c468b622ed31d408fea2346bec5bbffba2cc44226302a0de1ade9f5ea3d373"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06db6321b7a68b2bd6df96d08a5adadc1fa0e8f419226e25b2a5fbf6ccc7350f"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:293e7ea41280cb28c6fcaaa0b1aa1f533b8ce060b9e701d78511e1e6c4a1de76"}, {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bf1ac1984eaa7675ca8d5745a8cb87ef7abecb5592178406e55858d411eadc0"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:df5052c5d867c1ea0b311fb7c3cd28b19df469c056f7fdcfe88c7473aa63e333"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24a570cd11895b60829e941f2613a4f79df1a27344cbbb82164ef2e0116f09c7"}, {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, @@ -1976,7 +1960,6 @@ pillow = [ {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-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8b56553c0345ad6dcb2e9b433ae47d67f95fc23fe28a0bde15a120f25257e291"}, {file = "Pillow-8.2.0.tar.gz", hash = "sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1"}, ] pluggy = [ @@ -2177,38 +2160,6 @@ pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] -pyqt5 = [ - {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:8c0848ba790a895801d5bfd171da31cad3e551dbcc4e59677a3b622de2ceca98"}, - {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:883a549382fc22d29a0568f3ef20b38c8e7ab633a59498ac4eb63a3bf36d3fd3"}, - {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:a88526a271e846e44779bb9ad7a738c6d3c4a9d01e15a128ecfc6dd4696393b7"}, - {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:213bebd51821ed89b4d5b35bb10dbe67564228b3568f463a351a08e8b1677025"}, - {file = "PyQt5-5.15.4.tar.gz", hash = "sha256:2a69597e0dd11caabe75fae133feca66387819fc9bc050f547e5551bce97e5be"}, -] -pyqt5-qt5 = [ - {file = "PyQt5_Qt5-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154"}, - {file = "PyQt5_Qt5-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a"}, - {file = "PyQt5_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327"}, - {file = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"}, -] -pyqt5-sip = [ - {file = "PyQt5_sip-12.9.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:d85002238b5180bce4b245c13d6face848faa1a7a9e5c6e292025004f2fd619a"}, - {file = "PyQt5_sip-12.9.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:83c3220b1ca36eb8623ba2eb3766637b19eb0ce9f42336ad8253656d32750c0a"}, - {file = "PyQt5_sip-12.9.0-cp36-cp36m-win32.whl", hash = "sha256:d8b2bdff7bbf45bc975c113a03b14fd669dc0c73e1327f02706666a7dd51a197"}, - {file = "PyQt5_sip-12.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:69a3ad4259172e2b1aa9060de211efac39ddd734a517b1924d9c6c0cc4f55f96"}, - {file = "PyQt5_sip-12.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42274a501ab4806d2c31659170db14c282b8313d2255458064666d9e70d96206"}, - {file = "PyQt5_sip-12.9.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6a8701892a01a5a2a4720872361197cc80fdd5f49c8482d488ddf38c9c84f055"}, - {file = "PyQt5_sip-12.9.0-cp37-cp37m-win32.whl", hash = "sha256:ac57d796c78117eb39edd1d1d1aea90354651efac9d3590aac67fa4983f99f1f"}, - {file = "PyQt5_sip-12.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4347bd81d30c8e3181e553b3734f91658cfbdd8f1a19f254777f906870974e6d"}, - {file = "PyQt5_sip-12.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c446971c360a0a1030282a69375a08c78e8a61d568bfd6dab3dcc5cf8817f644"}, - {file = "PyQt5_sip-12.9.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fc43f2d7c438517ee33e929e8ae77132749c15909afab6aeece5fcf4147ffdb5"}, - {file = "PyQt5_sip-12.9.0-cp38-cp38-win32.whl", hash = "sha256:055581c6fed44ba4302b70eeb82e979ff70400037358908f251cd85cbb3dbd93"}, - {file = "PyQt5_sip-12.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:c5216403d4d8d857ec4a61f631d3945e44fa248aa2415e9ee9369ab7c8a4d0c7"}, - {file = "PyQt5_sip-12.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a25b9843c7da6a1608f310879c38e6434331aab1dc2fe6cb65c14f1ecf33780e"}, - {file = "PyQt5_sip-12.9.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:dd05c768c2b55ffe56a9d49ce6cc77cdf3d53dbfad935258a9e347cbfd9a5850"}, - {file = "PyQt5_sip-12.9.0-cp39-cp39-win32.whl", hash = "sha256:4f8e05fe01d54275877c59018d8e82dcdd0bc5696053a8b830eecea3ce806121"}, - {file = "PyQt5_sip-12.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:b09f4cd36a4831229fb77c424d89635fa937d97765ec90685e2f257e56a2685a"}, - {file = "PyQt5_sip-12.9.0.tar.gz", hash = "sha256:d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32"}, -] pyrsistent = [ {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, ] diff --git a/pyproject.toml b/pyproject.toml index e376986606..c9580b1601 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,6 @@ Pillow = "^8.1" # only used for slates prototype pyblish-base = "^1.8.8" pynput = "^1.7.2" # idle manager in tray pymongo = "^3.11.2" -pyqt5 = "^5.12.2" # ideally should be replaced with PySide2 "Qt.py" = "^1.3.3" speedcopy = "^2.1" six = "^1.15" diff --git a/tools/fetch_thirdparty_libs.ps1 b/tools/fetch_thirdparty_libs.ps1 index 23f0b50c7a..7ece9ee10e 100644 --- a/tools/fetch_thirdparty_libs.ps1 +++ b/tools/fetch_thirdparty_libs.ps1 @@ -36,6 +36,9 @@ if (-not (Test-Path -PathType Container -Path "$openpype_root\.poetry\bin")) { } else { Write-Host "OK" -ForegroundColor Green } +Write-Host ">>> " -NoNewline -ForegroundColor Green +Write-Host "Installing PySide2 ... " +& "$($env:POETRY_HOME)\bin\poetry.bat" run python -m pip install PySide2 -t "$($openpype_root)\vendor\python\PySide2" & poetry run python "$($openpype_root)\tools\fetch_thirdparty_libs.py" Set-Location -Path $current_dir From fbc7ccab31613d8766d5ef5408a3b2f8718ca720 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 22 Jun 2021 18:08:05 +0200 Subject: [PATCH 002/150] linux version --- tools/fetch_thirdparty_libs.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/fetch_thirdparty_libs.sh b/tools/fetch_thirdparty_libs.sh index 31f109ba68..e5c79b81dc 100755 --- a/tools/fetch_thirdparty_libs.sh +++ b/tools/fetch_thirdparty_libs.sh @@ -99,6 +99,9 @@ main () { pushd "$openpype_root" > /dev/null || return > /dev/null + echo -e "${BIGreen}>>>${RST} Installing PySide2 ..." + "$POETRY_HOME/bin/poetry" run python -m pip install PySide2 -t "$openpype_root/vendor/python/PySide2" + echo -e "${BIGreen}>>>${RST} Running Pype tool ..." poetry run python "$openpype_root/tools/fetch_thirdparty_libs.py" } From 09486d7e66cd5d946164605f25442642dbdf5ac1 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 22 Jun 2021 18:09:57 +0200 Subject: [PATCH 003/150] add vendor/python to gitignore --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 07c1c151ce..c4d0d4a9d0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -142,5 +142,6 @@ cython_debug/ .poetry/ .github/ vendor/bin/ +vendor/python/ docs/ website/ From 6c06eefaefa86314b524724eeb2d1809477d23b8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 10:24:11 +0200 Subject: [PATCH 004/150] added python vendor to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 221a2f2241..fa3fae1ad2 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ Temporary Items /dist/ /vendor/bin/* +/vendor/python/* /.venv /venv/ From 25a18e1bc1b74da8c05521411e50d405bd9a7fc6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 10:24:35 +0200 Subject: [PATCH 005/150] do not install PySide2 into subfolder --- tools/fetch_thirdparty_libs.ps1 | 2 +- tools/fetch_thirdparty_libs.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/fetch_thirdparty_libs.ps1 b/tools/fetch_thirdparty_libs.ps1 index 7ece9ee10e..f87ce3e724 100644 --- a/tools/fetch_thirdparty_libs.ps1 +++ b/tools/fetch_thirdparty_libs.ps1 @@ -38,7 +38,7 @@ if (-not (Test-Path -PathType Container -Path "$openpype_root\.poetry\bin")) { } Write-Host ">>> " -NoNewline -ForegroundColor Green Write-Host "Installing PySide2 ... " -& "$($env:POETRY_HOME)\bin\poetry.bat" run python -m pip install PySide2 -t "$($openpype_root)\vendor\python\PySide2" +& "$($env:POETRY_HOME)\bin\poetry.bat" run python -m pip install PySide2 -t "$($openpype_root)\vendor\python" & poetry run python "$($openpype_root)\tools\fetch_thirdparty_libs.py" Set-Location -Path $current_dir diff --git a/tools/fetch_thirdparty_libs.sh b/tools/fetch_thirdparty_libs.sh index e5c79b81dc..f619bc9f01 100755 --- a/tools/fetch_thirdparty_libs.sh +++ b/tools/fetch_thirdparty_libs.sh @@ -100,7 +100,7 @@ main () { pushd "$openpype_root" > /dev/null || return > /dev/null echo -e "${BIGreen}>>>${RST} Installing PySide2 ..." - "$POETRY_HOME/bin/poetry" run python -m pip install PySide2 -t "$openpype_root/vendor/python/PySide2" + "$POETRY_HOME/bin/poetry" run python -m pip install PySide2 -t "$openpype_root/vendor/python" echo -e "${BIGreen}>>>${RST} Running Pype tool ..." poetry run python "$openpype_root/tools/fetch_thirdparty_libs.py" From 64a1839c9d0f1632db45ccb5038816acc10046aa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 10:24:59 +0200 Subject: [PATCH 006/150] add vendor directory to sys.path in start.py --- start.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/start.py b/start.py index 8e7c195e95..905526480f 100644 --- a/start.py +++ b/start.py @@ -124,6 +124,10 @@ else: paths.append(frozen_libs) os.environ["PYTHONPATH"] = os.pathsep.join(paths) +# Vendored python modules that must not be in PYTHONPATH environment but +# are required for OpenPype processes +vendor_python_path = os.path.join(OPENPYPE_ROOT, "vendor", "python") +sys.path.insert(0, vendor_python_path) import blessed # noqa: E402 import certifi # noqa: E402 From 39bf35429b7403735c3ff02025e78a7fc46aed5a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 10:25:34 +0200 Subject: [PATCH 007/150] removed get_pyside2_location as is not needed inside openpype --- openpype/lib/import_utils.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/openpype/lib/import_utils.py b/openpype/lib/import_utils.py index 9f459bbb51..4e72618803 100644 --- a/openpype/lib/import_utils.py +++ b/openpype/lib/import_utils.py @@ -2,7 +2,6 @@ import os import sys import importlib from .log import PypeLogger as Logger -from pathlib import Path log = Logger().get_logger(__name__) @@ -24,17 +23,3 @@ def discover_host_vendor_module(module_name): sys.path.insert(1, module_path) return importlib.import_module(module_name) - - -def get_pyside2_location(): - """Get location of PySide2 and its dependencies. - - Returned path can be used with `site.addsitedir()` - - Returns: - str: path to PySide2 - - """ - path = Path(os.getenv("OPENPYPE_ROOT")) - path = path / "vendor/python/PySide2" - return str(path) From ea8a3e891d68806384a08857c9f55b1fb70c4c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Wed, 23 Jun 2021 10:50:47 +0200 Subject: [PATCH 008/150] changes in ignore files --- .dockerignore | 2 +- .gitignore | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index c4d0d4a9d0..9c506b9964 100644 --- a/.dockerignore +++ b/.dockerignore @@ -87,7 +87,7 @@ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: -# .python-version +.python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. diff --git a/.gitignore b/.gitignore index 221a2f2241..d2c682b1e5 100644 --- a/.gitignore +++ b/.gitignore @@ -99,3 +99,5 @@ website/.docusaurus .poetry/ .python-version + +vendor/python/PySide2 From 2e35e30ead8f06ee79dbe576d382b5a73a09678d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 11:04:17 +0200 Subject: [PATCH 009/150] removed duplicated ignore directory --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 63d311f033..fa3fae1ad2 100644 --- a/.gitignore +++ b/.gitignore @@ -100,5 +100,3 @@ website/.docusaurus .poetry/ .python-version - -vendor/python/PySide2 From 5937461cf6c53f29d48153a14527bb771031846f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 11:26:05 +0200 Subject: [PATCH 010/150] fix receivers discovery --- openpype/tools/settings/settings/window.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index a60a2a1d88..54f8ec0a11 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -141,7 +141,10 @@ class MainWidget(QtWidgets.QWidget): # Don't show dialog if there are not registered slots for # `trigger_restart` signal. # - For example when settings are runnin as standalone tool - if self.receivers(self.trigger_restart) < 1: + # - PySide2 and PyQt5 compatible way how to find out + method_index = self.metaObject().indexOfMethod("trigger_restart()") + method = self.metaObject().method(method_index) + if not self.isSignalConnected(method): return dialog = RestartDialog(self) From 60445b705cf2dd9591aa12ec9c7969e441a9de90 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 11:56:56 +0200 Subject: [PATCH 011/150] fix log viewer stylesheet of qtoolbutton --- openpype/modules/log_viewer/tray/app.py | 8 ++++---- openpype/modules/log_viewer/tray/widgets.py | 5 ++--- openpype/style/style.css | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/openpype/modules/log_viewer/tray/app.py b/openpype/modules/log_viewer/tray/app.py index 9aab37cd20..1e8d6483cd 100644 --- a/openpype/modules/log_viewer/tray/app.py +++ b/openpype/modules/log_viewer/tray/app.py @@ -7,12 +7,13 @@ class LogsWindow(QtWidgets.QWidget): def __init__(self, parent=None): super(LogsWindow, self).__init__(parent) - self.setStyleSheet(style.load_stylesheet()) + self.setWindowTitle("Logs viewer") + self.resize(1400, 800) log_detail = OutputWidget(parent=self) logs_widget = LogsWidget(log_detail, parent=self) - main_layout = QtWidgets.QHBoxLayout() + main_layout = QtWidgets.QHBoxLayout(self) log_splitter = QtWidgets.QSplitter(self) log_splitter.setOrientation(QtCore.Qt.Horizontal) @@ -24,5 +25,4 @@ class LogsWindow(QtWidgets.QWidget): self.logs_widget = logs_widget self.log_detail = log_detail - self.setLayout(main_layout) - self.setWindowTitle("Logs") + self.setStyleSheet(style.load_stylesheet()) diff --git a/openpype/modules/log_viewer/tray/widgets.py b/openpype/modules/log_viewer/tray/widgets.py index b9a8499a4c..d906a1b6ad 100644 --- a/openpype/modules/log_viewer/tray/widgets.py +++ b/openpype/modules/log_viewer/tray/widgets.py @@ -76,13 +76,12 @@ class CustomCombo(QtWidgets.QWidget): toolbutton.setMenu(toolmenu) toolbutton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup) + toolbutton.setProperty("popup_mode", "1") - layout = QtWidgets.QHBoxLayout() + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(toolbutton) - self.setLayout(layout) - toolmenu.selection_changed.connect(self.selection_changed) self.toolbutton = toolbutton diff --git a/openpype/style/style.css b/openpype/style/style.css index c57b9a8da6..8391fcd0ae 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -97,7 +97,7 @@ QToolButton:disabled { background: {color:bg-buttons-disabled}; } -QToolButton[popupMode="1"] { +QToolButton[popupMode="1"], QToolButton[popup_mode="1"] { /* make way for the popup button */ padding-right: 20px; border: 1px solid {color:bg-buttons}; From 7b45e69f99dba951c9f9a13ee3cea73061aa187e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 12:11:17 +0200 Subject: [PATCH 012/150] added comment --- openpype/modules/log_viewer/tray/widgets.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/modules/log_viewer/tray/widgets.py b/openpype/modules/log_viewer/tray/widgets.py index d906a1b6ad..669acf4b67 100644 --- a/openpype/modules/log_viewer/tray/widgets.py +++ b/openpype/modules/log_viewer/tray/widgets.py @@ -76,6 +76,9 @@ class CustomCombo(QtWidgets.QWidget): toolbutton.setMenu(toolmenu) toolbutton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup) + + # Fake popupMenu property as PySide2 does not store it's value as + # integer but as enum object toolbutton.setProperty("popup_mode", "1") layout = QtWidgets.QHBoxLayout(self) From 25cb349b7a0f1de801831c638e12933b0d71e672 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Jun 2021 12:38:50 +0200 Subject: [PATCH 013/150] fixed popupMode property --- openpype/modules/log_viewer/tray/widgets.py | 4 ---- openpype/style/style.css | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/openpype/modules/log_viewer/tray/widgets.py b/openpype/modules/log_viewer/tray/widgets.py index 669acf4b67..0f77a7f111 100644 --- a/openpype/modules/log_viewer/tray/widgets.py +++ b/openpype/modules/log_viewer/tray/widgets.py @@ -77,10 +77,6 @@ class CustomCombo(QtWidgets.QWidget): toolbutton.setMenu(toolmenu) toolbutton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup) - # Fake popupMenu property as PySide2 does not store it's value as - # integer but as enum object - toolbutton.setProperty("popup_mode", "1") - layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(toolbutton) diff --git a/openpype/style/style.css b/openpype/style/style.css index 8391fcd0ae..8dffd98e43 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -97,7 +97,7 @@ QToolButton:disabled { background: {color:bg-buttons-disabled}; } -QToolButton[popupMode="1"], QToolButton[popup_mode="1"] { +QToolButton[popupMode="1"], QToolButton[popupMode="MenuButtonPopup"] { /* make way for the popup button */ padding-right: 20px; border: 1px solid {color:bg-buttons}; From bc30890b88ee23cce7c3908d47fab215b5d128c6 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 23 Jun 2021 14:58:31 +0200 Subject: [PATCH 014/150] get PySide2 version from pyproject.toml --- pyproject.toml | 6 ++++++ tools/fetch_thirdparty_libs.ps1 | 3 --- tools/fetch_thirdparty_libs.py | 21 +++++++++++++++++++-- tools/fetch_thirdparty_libs.sh | 3 --- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c9580b1601..1e797130db 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,6 +101,12 @@ build-backend = "poetry.core.masonry.api" [openpype] +[openpype.pyside2] +# note: in here we can use pip version specifiers as this is installed with pip until +# Poetry will support custom location (-t flag for pip) +# https://pip.pypa.io/en/stable/cli/pip_install/#requirement-specifiers +version = "==5.15.2" + [openpype.thirdparty.ffmpeg.windows] url = "https://distribute.openpype.io/thirdparty/ffmpeg-4.4-windows.zip" hash = "dd51ba29d64ee238e7c4c3c7301b19754c3f0ee2e2a729c20a0e2789e72db925" diff --git a/tools/fetch_thirdparty_libs.ps1 b/tools/fetch_thirdparty_libs.ps1 index f87ce3e724..23f0b50c7a 100644 --- a/tools/fetch_thirdparty_libs.ps1 +++ b/tools/fetch_thirdparty_libs.ps1 @@ -36,9 +36,6 @@ if (-not (Test-Path -PathType Container -Path "$openpype_root\.poetry\bin")) { } else { Write-Host "OK" -ForegroundColor Green } -Write-Host ">>> " -NoNewline -ForegroundColor Green -Write-Host "Installing PySide2 ... " -& "$($env:POETRY_HOME)\bin\poetry.bat" run python -m pip install PySide2 -t "$($openpype_root)\vendor\python" & poetry run python "$($openpype_root)\tools\fetch_thirdparty_libs.py" Set-Location -Path $current_dir diff --git a/tools/fetch_thirdparty_libs.py b/tools/fetch_thirdparty_libs.py index 75ee052950..60392d782c 100644 --- a/tools/fetch_thirdparty_libs.py +++ b/tools/fetch_thirdparty_libs.py @@ -20,6 +20,7 @@ import hashlib import tarfile import zipfile import time +import subprocess term = blessed.Terminal() @@ -65,11 +66,27 @@ def _print(msg: str, message_type: int = 0) -> None: print("{}{}".format(header, msg)) - -_print("Processing third-party dependencies ...") start_time = time.time_ns() openpype_root = Path(os.path.dirname(__file__)).parent pyproject = toml.load(openpype_root / "pyproject.toml") +_print("Handling PySide2 Qt framework ...") +pyside2_version = None +try: + pyside2_version = pyproject["openpype"]["pyside2"]["version"] +except AttributeError: + _print("No PySide2 version was specified, using latest available.", 2) + +pyside2_arg = "PySide2" if pyside2_version else "PySide2{}".format(pyside2_version) # noqa: E501 +try: + subprocess.run( + [sys.executable, "-m", "pip", "install", "--upgrade", + pyside2_arg, "-t", str(openpype_root / "vendor/python")], check=True) +except subprocess.CalledProcessError as e: + _print("Error during PySide2 installation.", 1) + _print(str(e), 1) + sys.exit(1) + +_print("Processing third-party dependencies ...") platform_name = platform.system().lower() try: diff --git a/tools/fetch_thirdparty_libs.sh b/tools/fetch_thirdparty_libs.sh index f619bc9f01..31f109ba68 100755 --- a/tools/fetch_thirdparty_libs.sh +++ b/tools/fetch_thirdparty_libs.sh @@ -99,9 +99,6 @@ main () { pushd "$openpype_root" > /dev/null || return > /dev/null - echo -e "${BIGreen}>>>${RST} Installing PySide2 ..." - "$POETRY_HOME/bin/poetry" run python -m pip install PySide2 -t "$openpype_root/vendor/python" - echo -e "${BIGreen}>>>${RST} Running Pype tool ..." poetry run python "$openpype_root/tools/fetch_thirdparty_libs.py" } From 4362668b66f22fec09b26a65ec8ae767353eed79 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 25 Jun 2021 10:15:49 +0200 Subject: [PATCH 015/150] use parenting to skip style set --- .../tools/standalonepublish/widgets/widget_component_item.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/tools/standalonepublish/widgets/widget_component_item.py b/openpype/tools/standalonepublish/widgets/widget_component_item.py index 186c8024db..de3cde50cd 100644 --- a/openpype/tools/standalonepublish/widgets/widget_component_item.py +++ b/openpype/tools/standalonepublish/widgets/widget_component_item.py @@ -1,7 +1,6 @@ import os from Qt import QtCore, QtGui, QtWidgets from .resources import get_resource -from avalon import style class ComponentItem(QtWidgets.QFrame): @@ -61,7 +60,7 @@ class ComponentItem(QtWidgets.QFrame): name="menu", size=QtCore.QSize(22, 22) ) - self.action_menu = QtWidgets.QMenu() + self.action_menu = QtWidgets.QMenu(self.btn_action_menu) expanding_sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding @@ -229,7 +228,6 @@ class ComponentItem(QtWidgets.QFrame): if not self.btn_action_menu.isVisible(): self.btn_action_menu.setVisible(True) self.btn_action_menu.clicked.connect(self.show_actions) - self.action_menu.setStyleSheet(style.load_stylesheet()) def set_repre_name_valid(self, valid): self.has_valid_repre = valid From d28f8cd1d433b002bff2ded970b7950bd21fc120 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 30 Jun 2021 18:13:11 +0200 Subject: [PATCH 016/150] fix linux scripts, add patchelf --- Dockerfile | 46 ++++++++++++++++------------------ tools/build.sh | 5 ++-- tools/create_env.sh | 4 +-- tools/docker_build.sh | 2 +- tools/fetch_thirdparty_libs.py | 5 ++-- tools/fetch_thirdparty_libs.sh | 4 +-- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2d8ed27b15..99b9743de0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build Pype docker image -FROM centos:7 AS builder +FROM centos:7 AS system_builder ARG OPENPYPE_PYTHON_VERSION=3.7.10 LABEL org.opencontainers.image.name="pypeclub/openpype" @@ -22,6 +22,7 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n which \ git \ devtoolset-7-gcc* \ + gcc-c++ \ make \ cmake \ curl \ @@ -35,13 +36,19 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n openssl-devel \ tk-devel libffi-devel \ qt5-qtbase-devel \ - patchelf \ + autoconf \ + automake \ && yum clean all -RUN mkdir /opt/openpype -# RUN useradd -m pype -# RUN chown pype /opt/openpype -# USER pype +# we need to build our own patchelf +WORKDIR /temp-patchelf +RUN git clone https://github.com/NixOS/patchelf.git . \ + && source scl_source enable devtoolset-7 \ + && ./bootstrap.sh \ + && ./configure \ + && make \ + && make install + RUN curl https://pyenv.run | bash ENV PYTHON_CONFIGURE_OPTS --enable-shared @@ -49,27 +56,21 @@ ENV PYTHON_CONFIGURE_OPTS --enable-shared RUN echo 'export PATH="$HOME/.pyenv/bin:$PATH"'>> $HOME/.bashrc \ && echo 'eval "$(pyenv init -)"' >> $HOME/.bashrc \ && echo 'eval "$(pyenv virtualenv-init -)"' >> $HOME/.bashrc \ - && echo 'eval "$(pyenv init --path)"' >> $HOME/.bashrc -RUN source $HOME/.bashrc && pyenv install ${OPENPYPE_PYTHON_VERSION} - -COPY . /opt/openpype/ -RUN rm -rf /openpype/.poetry || echo "No Poetry installed yet." -# USER root -# RUN chown -R pype /opt/openpype -RUN chmod +x /opt/openpype/tools/create_env.sh && chmod +x /opt/openpype/tools/build.sh - -# USER pype + && echo 'eval "$(pyenv init --path)"' >> $HOME/.bashrc \ + && source $HOME/.bashrc \ + && pyenv install ${OPENPYPE_PYTHON_VERSION} WORKDIR /opt/openpype - -RUN cd /opt/openpype \ +COPY . /opt/openpype/ +RUN rm -rf /opt/openpype/.poetry || echo "No Poetry installed yet." \ + && chmod +x /opt/openpype/tools/create_env.sh \ + && chmod +x /opt/openpype/tools/build.sh \ && source $HOME/.bashrc \ && pyenv local ${OPENPYPE_PYTHON_VERSION} RUN source $HOME/.bashrc \ - && ./tools/create_env.sh - -RUN source $HOME/.bashrc \ + && ./tools/create_env.sh \ + && source $HOME/.bashrc \ && ./tools/fetch_thirdparty_libs.sh RUN source $HOME/.bashrc \ @@ -77,6 +78,3 @@ RUN source $HOME/.bashrc \ && cp /usr/lib64/libffi* ./build/exe.linux-x86_64-3.7/lib \ && cp /usr/lib64/libssl* ./build/exe.linux-x86_64-3.7/lib \ && cp /usr/lib64/libcrypto* ./build/exe.linux-x86_64-3.7/lib - -RUN cd /opt/openpype \ - rm -rf ./vendor/bin diff --git a/tools/build.sh b/tools/build.sh index aa8f0121ea..4343431c2b 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -58,7 +58,7 @@ BICyan='\033[1;96m' # Cyan BIWhite='\033[1;97m' # White args=$@ -disable_submodule_update = 0 +disable_submodule_update=0 while :; do case $1 in --no-submodule-update) @@ -122,7 +122,7 @@ clean_pyc () { local path path=$openpype_root echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" - find "$path" -path ./build -prune -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete + find "$path" -path ./build -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -228,3 +228,4 @@ if [ "$disable_submodule_update" == 1 ]; then } main +exit $? diff --git a/tools/create_env.sh b/tools/create_env.sh index 226a26e199..f93b8e32e6 100755 --- a/tools/create_env.sh +++ b/tools/create_env.sh @@ -126,7 +126,7 @@ clean_pyc () { local path path=$openpype_root echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" - find "$path" -path ./build -prune -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete + find "$path" -path ./build -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -177,7 +177,7 @@ main () { echo -e "${BIGreen}>>>${RST} Installing dependencies ..." fi - poetry install --no-root $poetry_verbosity || { echo -e "${BIRed}!!!${RST} Poetry environment installation failed"; return; } + poetry install --no-root --ansi $poetry_verbosity || { echo -e "${BIRed}!!!${RST} Poetry environment installation failed"; return; } echo -e "${BIGreen}>>>${RST} Cleaning cache files ..." clean_pyc diff --git a/tools/docker_build.sh b/tools/docker_build.sh index 7600fe044b..a6df2a099e 100755 --- a/tools/docker_build.sh +++ b/tools/docker_build.sh @@ -32,7 +32,7 @@ main () { openpype_version="$(python3 <<< ${version_command})" echo -e "${BIGreen}>>>${RST} Running docker build ..." - docker build --pull --no-cache -t pypeclub/openpype:$openpype_version . + docker build --pull -t pypeclub/openpype:$openpype_version . if [ $? -ne 0 ] ; then echo -e "${BIRed}!!!${RST} Docker build failed." return 1 diff --git a/tools/fetch_thirdparty_libs.py b/tools/fetch_thirdparty_libs.py index 60392d782c..1ded907576 100644 --- a/tools/fetch_thirdparty_libs.py +++ b/tools/fetch_thirdparty_libs.py @@ -73,14 +73,15 @@ _print("Handling PySide2 Qt framework ...") pyside2_version = None try: pyside2_version = pyproject["openpype"]["pyside2"]["version"] + _print("We'll install PySide2{}".format(pyside2_version)) except AttributeError: _print("No PySide2 version was specified, using latest available.", 2) -pyside2_arg = "PySide2" if pyside2_version else "PySide2{}".format(pyside2_version) # noqa: E501 +pyside2_arg = "PySide2" if not pyside2_version else "PySide2{}".format(pyside2_version) # noqa: E501 try: subprocess.run( [sys.executable, "-m", "pip", "install", "--upgrade", - pyside2_arg, "-t", str(openpype_root / "vendor/python")], check=True) + pyside2_arg, "-t", str(openpype_root / "vendor/python")], check=True, stdout=subprocess.DEVNULL) except subprocess.CalledProcessError as e: _print("Error during PySide2 installation.", 1) _print(str(e), 1) diff --git a/tools/fetch_thirdparty_libs.sh b/tools/fetch_thirdparty_libs.sh index 31f109ba68..12116d9e9e 100755 --- a/tools/fetch_thirdparty_libs.sh +++ b/tools/fetch_thirdparty_libs.sh @@ -99,8 +99,8 @@ main () { pushd "$openpype_root" > /dev/null || return > /dev/null - echo -e "${BIGreen}>>>${RST} Running Pype tool ..." + echo -e "${BIGreen}>>>${RST} Fetching third party dependencies ..." poetry run python "$openpype_root/tools/fetch_thirdparty_libs.py" } -main \ No newline at end of file +main From f460fad23f992d3ed34a5135c0eb286ef24ca2c5 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 30 Jun 2021 18:15:43 +0200 Subject: [PATCH 017/150] fix hound --- tools/fetch_thirdparty_libs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/fetch_thirdparty_libs.py b/tools/fetch_thirdparty_libs.py index 1ded907576..803d092186 100644 --- a/tools/fetch_thirdparty_libs.py +++ b/tools/fetch_thirdparty_libs.py @@ -81,7 +81,8 @@ pyside2_arg = "PySide2" if not pyside2_version else "PySide2{}".format(pyside2_v try: subprocess.run( [sys.executable, "-m", "pip", "install", "--upgrade", - pyside2_arg, "-t", str(openpype_root / "vendor/python")], check=True, stdout=subprocess.DEVNULL) + pyside2_arg, "-t", str(openpype_root / "vendor/python")], + check=True, stdout=subprocess.DEVNULL) except subprocess.CalledProcessError as e: _print("Error during PySide2 installation.", 1) _print(str(e), 1) From fa78f9805b2135df3ea9bef8ab6adf282623156a Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 1 Jul 2021 10:41:23 +0200 Subject: [PATCH 018/150] add ncurses --- Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 99b9743de0..74ab06a114 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,7 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n which \ git \ devtoolset-7-gcc* \ - gcc-c++ \ + gcc-c++ \ make \ cmake \ curl \ @@ -36,8 +36,9 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n openssl-devel \ tk-devel libffi-devel \ qt5-qtbase-devel \ - autoconf \ - automake \ + autoconf \ + automake \ + ncurses-libs \ && yum clean all # we need to build our own patchelf From 7c302631014f85efa05cf809679f55260a0d9593 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 7 Jul 2021 18:50:53 +0200 Subject: [PATCH 019/150] #1784 - location of existing unittests refactored for futuru use --- .../igniter/test_bootstrap_repos.py | 0 tests/{ => unit}/igniter/test_tools.py | 0 .../openpype/lib/test_user_settings.py | 0 .../sync_server/fixture/openpype/logs.bson | Bin 0 -> 2824 bytes .../fixture/openpype/logs.metadata.json | 1 + .../fixture/openpype/settings.bson | Bin 0 -> 623 bytes .../fixture/openpype/settings.metadata.json | 1 + .../fixture/test_db/test_project.bson | Bin 0 -> 13295 bytes .../test_db/test_project.metadata.json | 1 + .../sync_server/test_site_operations.py | 164 ++++++++++++++++++ 10 files changed, 167 insertions(+) rename tests/{ => unit}/igniter/test_bootstrap_repos.py (100%) rename tests/{ => unit}/igniter/test_tools.py (100%) rename tests/{ => unit}/openpype/lib/test_user_settings.py (100%) create mode 100644 tests/unit/openpype/modules/sync_server/fixture/openpype/logs.bson create mode 100644 tests/unit/openpype/modules/sync_server/fixture/openpype/logs.metadata.json create mode 100644 tests/unit/openpype/modules/sync_server/fixture/openpype/settings.bson create mode 100644 tests/unit/openpype/modules/sync_server/fixture/openpype/settings.metadata.json create mode 100644 tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.bson create mode 100644 tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.metadata.json create mode 100644 tests/unit/openpype/modules/sync_server/test_site_operations.py diff --git a/tests/igniter/test_bootstrap_repos.py b/tests/unit/igniter/test_bootstrap_repos.py similarity index 100% rename from tests/igniter/test_bootstrap_repos.py rename to tests/unit/igniter/test_bootstrap_repos.py diff --git a/tests/igniter/test_tools.py b/tests/unit/igniter/test_tools.py similarity index 100% rename from tests/igniter/test_tools.py rename to tests/unit/igniter/test_tools.py diff --git a/tests/openpype/lib/test_user_settings.py b/tests/unit/openpype/lib/test_user_settings.py similarity index 100% rename from tests/openpype/lib/test_user_settings.py rename to tests/unit/openpype/lib/test_user_settings.py diff --git a/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.bson b/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.bson new file mode 100644 index 0000000000000000000000000000000000000000..37efb8a4a8dd94738bd7800df8e7a6d0f4c010c6 GIT binary patch literal 2824 zcmdUw&ui2`6vxM)*7^gAJtf+z9Nn@3+}vNbEQ71~3DWoPofFEjJz^WMwHLxha@EF|~7 zz5P7?bL&O>*~`kPW-%yDGe0;#+Nv}}9ze$b*au1j$r0Q&2}FC_p`a5 z&MQfuIM#=p#67H=kzS=XU4nieav4{FdqDRC+0v>Up#-gb^%J zj*z8wa9dQlm_1TMIE40ek#~;oUDWr*m*G+T*q+5R4>mJZo^YCAd2I*rVH9MC57E7f zwi42PS3tL#qkCZwx=-|9>0(L~o;g zUqpM*u-kcd$b%fg#Rq4}s4(jpl`TGBo|ombo3b%gOE+UxR=` literal 0 HcmV?d00001 diff --git a/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.metadata.json b/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.metadata.json new file mode 100644 index 0000000000..8c7a16261d --- /dev/null +++ b/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.metadata.json @@ -0,0 +1 @@ +{"options":{"capped":true,"size":{"$numberDouble":"1.073741824E+09"},"max":{"$numberInt":"5000"}},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"f982c4d7baf54d03b88aaa540c9ced8e","collectionName":"logs"} \ No newline at end of file diff --git a/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.bson b/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.bson new file mode 100644 index 0000000000000000000000000000000000000000..dbfe2e88c6e63f08fccd8a06a280b29dd9bf5bbc GIT binary patch literal 623 zcmbV~Jx&8L5QS&6AXcIY5+#SAqo4%|3JN6p!MmPKO#HL*%p&bg=(!1J0nWidfUr@D zkir^Sp7;6LZ=MT)19TSd-(GHRpW6A!-NoxfhK^tg06efzKqe6vXAGq^Vj!rf49WJM z81Qq`N;b^`&QwxSG_@xSu!oo)DQ9OX;(`W7gk$ZPoI<7Lw+~8jfihz-(ab3CjNu_R z>NV@7V@9#P6-&l?7ikRm$6HuTw8p1MU0-|0bCi_)t~mXtb6x8Zy{{sg`BWRf9?`yv z0IvT?<1*dL!=>~{kGh;5sF97@$}w7MP45K?xY_`kt~~sJG(SmU_#Trl4`a>;Ny@BQ literal 0 HcmV?d00001 diff --git a/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.metadata.json b/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.metadata.json new file mode 100644 index 0000000000..dafcd98d52 --- /dev/null +++ b/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.metadata.json @@ -0,0 +1 @@ +{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"8329d557adfe48018cd533dc648e3b7f","collectionName":"settings"} \ No newline at end of file diff --git a/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.bson b/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.bson new file mode 100644 index 0000000000000000000000000000000000000000..c81a0bd315f5c02f4ef86523e34f8b4098ae31cf GIT binary patch literal 13295 zcmeHOO^h5z6)yJ-pyYzYfdg;=E{Fp^;s^*3NPqwdMT&?J7nCChBJsVduAb^i?`9`) z#Ij_iFx^$Js@|*j-uHgmyz)`TZfiPi_N7;?AOH06g`d>E_OnYyydH3NJ7X*e{p-9H zGsCm{oP8K0F^}S=8ZNZ$*k-R`*l79f9D>_jXF0UP^>hWBXt_>s#$)@iNIah(#NuUN zCx|dce{&}$Iw1~x%4@TK6hJ55F2;5k%lDq`wOuhy;q!C5w&`}Z?pUG<_Fvh za6dR7FOEZ|RjZ9;a*XCilQkt_cT^~K$4*R~h4w*1HJ92i=^J72i`GFF7jvY+Tz6Vcs zC*~pVbfBh)Xy^pXWS>llK7^-%7joMzS4))|-U?3N?sCUxFGEiSAv*gWUG)t=Tju?ca!`&Wmk3#6a@mI^JMS z83P^Vc-@PE-Qo;vFwAm0WJcty#hiPmocJt^noK9U@boEW2y=VOXvg(!L8x!x`dwN} zL-W|x_n5Kj@EbhL?ilw5{bkQ~+{`d5guKhw&UnEfj@VU_$&t_J@C<7_jUPkM2u)o5 zV#zK&f3kGNEX`dz9JqGOFYwNhsmBf_J*8pBF>F#UrT$ae10%-y|}@(KEIO zE9i4i-tsxx&^SMT=6o~pL$d6w!drtV_WML5?PBp=sr~GwrHtm`1WxRaD9Q2S*^GV+ zj99hoP>#a$3Erb@2yOCNzGKbw|P}T%yNSSFH%~KKqG`A+;tfU*?OXNZ;%{J87g5fw& zZL(}A08X*kpLDezq&-X#hBUPBFRSs9OihYZy@Qy-1TLTfom&@V(4&U+Wn}&%n2CjrjmRPrI7}))HI>e3KIl z;k+WSLL!kdorCQV!S@k+;2{#Y*=5>QMOJe4`J?3|bArhyLG~jUFF%Xytk0ve2*`$v zxF4g5z89CHo*nYxLhK&f(MrVrMh5*f_ju^EWa5B?BaE8@AIM_5GzXfK$Q?y8rp=Q# zQ%=bW&j1W@VmFth-*!Q=#Mk0M$a5)Tz6Of3zQ5Aut1?B>jv?i`m;=cLrwe?}KPE)} z$O=!joj7*~P7^r9UiXn8mazu<2FHQ?rq2!+=hodic;a+qioD#r_*0x9|!A( zCJI6g>j+sXgWgIKw@aKZ+6Z^KTm)i<73P8Ze&mRKM8d0`M3+WU0Y8P9_eF9NvA;uQ zg(QiK*bA7PKpsM2qZ!z3B(hybEE>rmJAjwfjpXg9d2Hjv2>Iq_QeC9$$tVm_a0uQv z#G_a$o)jGxCKmpEvA}mJv_6UF4RV3239u+>|~GlDOVH_Jp? z-XMG4#L1MyK0({4l~h?>+iWJ(O-a~HCE0wUxq*wKWN7o))CQ~+y9gh;hjuy95uD+) z6SOsPodkBIMdqpk!56Bp5le*v(^4 zOo4GK26rf2!W4T5z+gz(*Co42tzbj*9$xvV zm%g1*XGKFn8bkb~_5`=9FkjV|c`fP7JUh%bg?Iu!ASyL$DAXnINw0#k%(Pb_revo= zv}_D)UkngZJp^l!eB8O}L<8Gh6k{s7K8igM_@a0T;Kc67+psmHf-c%Ena)jKLq+Sd zXuX&GHjTKLxAc03&7G0f5Vez33rX)SjrMSoCK0ui#NTaF`b^)89ZGNg_0=~%|4OH~ zf5}*pB4-jIZShb!1mH67AlmfSgae3l8EMo}8LI7hLCmE_pUhIfiNmC6zP|R` zUwozDUf+lxP~1|&mRg)+JFpuUR%!V>ehgP*IxqrGOb}W}KL$3}>QoL*E?at08ku4FQYQU&|tdME%&s}O-8#+L`5-630H?Pfb>Kl+rv0WWi=Svdq*gm1^~-Wg&&CjSDOP)M4d2;Aj-1A6Bq3X8I~K7wVQ$^bny$<|QT$ z8Rmos@s@N}Lr&BTomGOsP8=fVC5DF8NLo;^mveM}NOAh^lGukwli0^_)))-$<(yXk z*9N$iq(4Z7BfT+pC?_sGs?>5TGu}hPjF((XTGo?bLi+s;@G?%uD^0H@k@MGPTLNHD{W0wRae0p8J)Syq0r7;>ddl z5_gj1>K}!?4;9+y66rjf&0AOt-}iq96~CZ*rf;o^}TxR`to;R468zQ4L#fPz@ri>2)z$|lpD3Frsp> z-zDE&$_gXKEL`bpg!-PON`V9n9>LVG5~MN{rRyCUJsxw*)xM@r#h<14duQdU+NL~O zu2L!XHcam25|y#K7BJK;Rn%qQiXv2PY7L7}`YI`l(0N?H^i=$NlCg?VWpoYopsa8E zLUfc``%JnAOVN9Ay}PIs%{agM+>(nR`Q@nin!UsCEcD@fo6vEbZpLI(m5xGTRT|`% zVUYS4x3?`vm1&8O*O5samF}hZZRV$nnZuNsf6I9L3uIYesK@=I%0y3mb+I cYjUn))vGhJH|x{W^_jVGW61H}Xl3bt05iqOQ~&?~ literal 0 HcmV?d00001 diff --git a/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.metadata.json b/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.metadata.json new file mode 100644 index 0000000000..b43f27f459 --- /dev/null +++ b/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.metadata.json @@ -0,0 +1 @@ +{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"bfe11cd230d041438b288f7d6ad8e70f","collectionName":"test_project"} \ No newline at end of file diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py new file mode 100644 index 0000000000..7e1c994456 --- /dev/null +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -0,0 +1,164 @@ +"""Test file for Sync Server, tests site operations add_site, remove_site""" +import os +import pytest +from bson.objectid import ObjectId + +from tests.lib.DBHandler import DBHandler + +TEST_DB_NAME = "test_db" +TEST_PROJECT_NAME = "test_project" +TEST_OPENPYPE_NAME = "test_openpype" +REPRESENTATION_ID = "60e578d0c987036c6a7b741d" + + +@pytest.fixture(scope='session') +def monkeypatch_session(): + """Monkeypatch couldn't be used with module or session fixtures.""" + from _pytest.monkeypatch import MonkeyPatch + m = MonkeyPatch() + yield m + m.undo() + + +@pytest.fixture(scope="module") +def db_init(monkeypatch_session): + backup_dir = os.path.abspath( + os.path.join( + os.path.dirname(__file__), + 'fixture' + ) + ) + + uri = os.environ.get("OPENPYPE_MONGO") or "mongodb://localhost:27017" + db = DBHandler(uri) + db.setup_from_dump(TEST_DB_NAME, backup_dir, True, + db_name_out=TEST_DB_NAME) + + db.setup_from_dump("openpype", backup_dir, True, + db_name_out=TEST_OPENPYPE_NAME) + + # set needed env vars temporarily for tests + monkeypatch_session.setenv("OPENPYPE_MONGO", uri) + monkeypatch_session.setenv("AVALON_MONGO", uri) + monkeypatch_session.setenv("OPENPYPE_DATABASE_NAME", TEST_OPENPYPE_NAME) + monkeypatch_session.setenv("AVALON_TIMEOUT", '3000') + monkeypatch_session.setenv("AVALON_DB", TEST_DB_NAME) + monkeypatch_session.setenv("AVALON_PROJECT", TEST_PROJECT_NAME) + monkeypatch_session.setenv("PYPE_DEBUG", "3") + + +@pytest.fixture(scope="module") +def setup_avalon_db(db_init): + """Connect to Avalon, only after 'db_init' sets env vars.""" + from avalon.api import AvalonMongoDB + db = AvalonMongoDB() + yield db + + +@pytest.fixture(scope="module") +def setup_sync_server_module(db_init): + """Get sync_server_module from ModulesManager""" + from openpype.modules import ModulesManager + + manager = ModulesManager() + sync_server = manager.modules_by_name["sync_server"] + yield sync_server + + +@pytest.mark.usefixtures("setup_avalon_db") +def test_project_created(setup_avalon_db): + assert ['test_project'] == setup_avalon_db.database.collection_names(False) + + +@pytest.mark.usefixtures("setup_avalon_db") +def test_objects_imported(setup_avalon_db): + count_obj = len(list(setup_avalon_db.database[TEST_PROJECT_NAME].find({}))) + assert 15 == count_obj + + +@pytest.mark.usefixtures("setup_sync_server_module") +def test_add_site(setup_avalon_db, setup_sync_server_module): + """Adds 'test_site', checks that added, checks that doesn't duplicate.""" + query = { + "_id": ObjectId(REPRESENTATION_ID) + } + + ret = setup_avalon_db.database[TEST_PROJECT_NAME].find(query) + + assert 1 == len(list(ret)), \ + "Single {} must be in DB".format(REPRESENTATION_ID) + + setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, + site_name='test_site') + + ret = list(setup_avalon_db.database[TEST_PROJECT_NAME].find(query)) + + assert 1 == len(ret), \ + "Single {} must be in DB".format(REPRESENTATION_ID) + + ret = ret.pop() + site_names = [site["name"] for site in ret["files"][0]["sites"]] + assert 'test_site' in site_names, "Site name wasn't added" + + +@pytest.mark.usefixtures("setup_sync_server_module") +def test_add_site_again(setup_avalon_db, setup_sync_server_module): + """Depends on test_add_site, must throw exception.""" + with pytest.raises(ValueError): + setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, + site_name='test_site') + + +@pytest.mark.usefixtures("setup_sync_server_module") +def test_add_site_again_force(setup_avalon_db, setup_sync_server_module): + """Depends on test_add_site, must not throw exception.""" + setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, + site_name='test_site', force=True) + + query = { + "_id": ObjectId(REPRESENTATION_ID) + } + + ret = list(setup_avalon_db.database[TEST_PROJECT_NAME].find(query)) + + assert 1 == len(ret), \ + "Single {} must be in DB".format(REPRESENTATION_ID) + + +@pytest.mark.usefixtures("setup_sync_server_module") +def test_remove_site(setup_avalon_db, setup_sync_server_module): + """Depends on test_add_site, must remove 'test_site'.""" + setup_sync_server_module.remove_site(TEST_PROJECT_NAME, REPRESENTATION_ID, + site_name='test_site') + + query = { + "_id": ObjectId(REPRESENTATION_ID) + } + + ret = list(setup_avalon_db.database[TEST_PROJECT_NAME].find(query)) + + assert 1 == len(ret), \ + "Single {} must be in DB".format(REPRESENTATION_ID) + + ret = ret.pop() + site_names = [site["name"] for site in ret["files"][0]["sites"]] + + assert 'test_site' not in site_names, "Site name wasn't removed" + + +@pytest.mark.usefixtures("setup_sync_server_module") +def test_remove_site_again(setup_avalon_db, setup_sync_server_module): + """Depends on test_add_site, must trow exception""" + with pytest.raises(ValueError): + setup_sync_server_module.remove_site(TEST_PROJECT_NAME, + REPRESENTATION_ID, + site_name='test_site') + + query = { + "_id": ObjectId(REPRESENTATION_ID) + } + + ret = list(setup_avalon_db.database[TEST_PROJECT_NAME].find(query)) + + assert 1 == len(ret), \ + "Single {} must be in DB".format(REPRESENTATION_ID) From d8b7fca9657fda4e95337cb8ce0eaaa46c9f119e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 7 Jul 2021 18:51:55 +0200 Subject: [PATCH 020/150] #1784 - added base implementation for helper DB class Added example of usage of helper class to test SyncServerModule (WIP) --- tests/README.md | 12 +++ tests/__init__.py | 0 tests/integration/README.md | 6 ++ tests/lib/DBHandler.py | 144 ++++++++++++++++++++++++++++++++++++ tests/lib/README.md | 1 + tests/lib/__init__.py | 0 6 files changed, 163 insertions(+) create mode 100644 tests/__init__.py create mode 100644 tests/integration/README.md create mode 100644 tests/lib/DBHandler.py create mode 100644 tests/lib/README.md create mode 100644 tests/lib/__init__.py diff --git a/tests/README.md b/tests/README.md index e69de29bb2..727b89a86e 100644 --- a/tests/README.md +++ b/tests/README.md @@ -0,0 +1,12 @@ +Automatic tests for OpenPype +============================ +Structure: +- integration - end to end tests, slow + - openpype/modules/MODULE_NAME - structure follow directory structure in code base + - fixture - sample data `(MongoDB dumps, test files etc.)` + - `tests.py` - single or more pytest files for MODULE_NAME +- unit - quick unit test + - MODULE_NAME + - fixture + - `tests.py` + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/integration/README.md b/tests/integration/README.md new file mode 100644 index 0000000000..00d8a4c10d --- /dev/null +++ b/tests/integration/README.md @@ -0,0 +1,6 @@ +Integration test for OpenPype +============================= +Contains end-to-end tests for automatic testing of OP. + +Should run headless publish on all hosts to check basic publish use cases automatically +to limit regression issues. diff --git a/tests/lib/DBHandler.py b/tests/lib/DBHandler.py new file mode 100644 index 0000000000..258ff67df7 --- /dev/null +++ b/tests/lib/DBHandler.py @@ -0,0 +1,144 @@ +""" + Helper class for automatic testing, provides dump and restore via command + line utilities. + + Expect mongodump and mongorestore present at MONGODB_UTILS_DIR +""" +import os +import pymongo +import subprocess + + +class DBHandler(): + + # vendorize ?? + MONGODB_UTILS_DIR = "c:\\Program Files\\MongoDB\\Server\\4.4\\bin" + + def __init__(self, uri=None, host=None, port=None, + user=None, password=None): + """'uri' or rest of separate credentials""" + if uri: + self.uri = uri + if host: + if all([user, password]): + host = "{}:{}@{}".format(user, password, host) + uri = 'mongodb://{}:{}'.format(host, port or 27017) + + assert uri, "Must have uri to MongoDB" + self.client = pymongo.MongoClient(uri) + self.db = None + + def setup_empty(self, name): + # not much sense + self.db = self.client[name] + + def setup_from_dump(self, db_name, dump_dir, overwrite=False, + collection=None, db_name_out=None): + """ + Restores 'db_name' from 'dump_dir'. + + Works with BSON folders exported by mongodump + + Args: + db_name (str): source DB name + dump_dir (str): folder with dumped subfolders + overwrite (bool): True if overwrite target + collection (str): name of source project + db_name_out (str): name of target DB, if empty restores to + source 'db_name' + """ + db_name_out = db_name_out or db_name + if self._db_exists(db_name) and not overwrite: + raise RuntimeError("DB {} already exists".format(db_name_out) + + "Run with overwrite=True") + + dir_path = os.path.join(dump_dir, db_name) + if not os.path.exists(dir_path): + raise RuntimeError( + "Backup folder {} doesn't exist".format(dir_path)) + + query = self._restore_query(self.uri, dump_dir, + db_name=db_name, db_name_out=db_name_out, + collection=collection) + print("mongorestore query:: {}".format(query)) + subprocess.run(query) + + def teardown(self, db_name): + """Drops 'db_name' if exists.""" + if not self._db_exists(db_name): + print("{} doesn't exist".format(db_name)) + return + + self.client.drop_database(db_name) + + def backup_to_dump(self, db_name, dump_dir, overwrite=False): + """ + Helper class for running mongodump for specific 'db_name' + """ + if not self._db_exists(db_name) and not overwrite: + raise RuntimeError("DB {} doesn't exists".format(db_name)) + + dir_path = os.path.join(dump_dir, db_name) + if os.path.exists(dir_path) and not overwrite: + raise RuntimeError("Backup already exists, " + "run with overwrite=True") + + query = self._dump_query(self.uri, dump_dir, db_name=db_name) + print("Mongodump query:: {}".format(query)) + subprocess.run(query) + + def _db_exists(self, db_name): + return db_name in self.client.list_database_names() + + def _dump_query(self, uri, + output_path, + db_name=None, collection=None): + + utility_path = os.path.join(self.MONGODB_UTILS_DIR, "mongodump") + + db_part = coll_part = "" + if db_name: + db_part = "--db={}".format(db_name) + if collection: + if not db_name: + raise ValueError("db_name must be present") + coll_part = "--nsInclude={}.{}".format(db_name, collection) + query = "\"{}\" --uri=\"{}\" --out={} {} {}".format( + utility_path, uri, output_path, db_part, coll_part + ) + + return query + + def _restore_query(self, uri, dump_dir, + db_name=None, db_name_out=None, + collection=None, drop=True): + + utility_path = os.path.join(self.MONGODB_UTILS_DIR, "mongorestore") + + db_part = coll_part = drop_part = "" + if db_name: + db_part = "--nsInclude={}.* --nsFrom={}.*".format(db_name, db_name) + if collection: + assert db_name, "Must provide db name too" + db_part = "--nsInclude={}.{} --nsFrom={}.{}".format(db_name, + collection, + db_name, + collection) + if drop: + drop_part = "--drop" + + if db_name_out: + db_part += " --nsTo={}.*".format(db_name_out) + + query = "\"{}\" --uri=\"{}\" --dir=\"{}\" {} {} {}".format( + utility_path, uri, dump_dir, db_part, coll_part, drop_part + ) + + return query + +# handler = DBHandler(uri="mongodb://localhost:27017") +# +# backup_dir = "c:\\projects\\dumps" +# +# handler.backup_to_dump("openpype", backup_dir, True) +# handler.setup_from_dump("test_db", backup_dir, True) diff --git a/tests/lib/README.md b/tests/lib/README.md new file mode 100644 index 0000000000..043dd3b8e9 --- /dev/null +++ b/tests/lib/README.md @@ -0,0 +1 @@ +Folder for libs and tooling for automatic testing. \ No newline at end of file diff --git a/tests/lib/__init__.py b/tests/lib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 42774d337360e53075da3c9131d74e3cd634a17e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 8 Jul 2021 16:34:17 +0200 Subject: [PATCH 021/150] #1784 - added base implementation for helper class to download files from remote url, mostly GDrive --- tests/lib/FileHandler.py | 272 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 tests/lib/FileHandler.py diff --git a/tests/lib/FileHandler.py b/tests/lib/FileHandler.py new file mode 100644 index 0000000000..e90eac34c1 --- /dev/null +++ b/tests/lib/FileHandler.py @@ -0,0 +1,272 @@ +import requests +import hashlib +import enlighten +import os +import re +import urllib +from urllib.parse import urlparse +import urllib.request +import urllib.error +import itertools +import hashlib +import tarfile +import zipfile + + +USER_AGENT = "openpype" + + +class RemoteFileHandler: + """Download file from url, might be GDrive shareable link""" + + IMPLEMENTED_ZIP_FORMATS = ['zip', 'tar', 'tgz', + 'tar.gz', 'tar.xz', 'tar.bz2'] + + @staticmethod + def calculate_md5(fpath, chunk_size): + md5 = hashlib.md5() + with open(fpath, 'rb') as f: + for chunk in iter(lambda: f.read(chunk_size), b''): + md5.update(chunk) + return md5.hexdigest() + + @staticmethod + def check_md5(fpath, md5, **kwargs): + return md5 == RemoteFileHandler.calculate_md5(fpath, **kwargs) + + @staticmethod + def check_integrity(fpath, md5=None): + if not os.path.isfile(fpath): + return False + if md5 is None: + return True + return RemoteFileHandler.check_md5(fpath, md5) + + @staticmethod + def download_url( + url, root, filename=None, + md5=None, max_redirect_hops=3 + ): + """Download a file from a url and place it in root. + Args: + url (str): URL to download file from + root (str): Directory to place downloaded file in + filename (str, optional): Name to save the file under. + If None, use the basename of the URL + md5 (str, optional): MD5 checksum of the download. + If None, do not check + max_redirect_hops (int, optional): Maximum number of redirect + hops allowed + """ + root = os.path.expanduser(root) + if not filename: + filename = os.path.basename(url) + fpath = os.path.join(root, filename) + + os.makedirs(root, exist_ok=True) + + # check if file is already present locally + if RemoteFileHandler.check_integrity(fpath, md5): + print('Using downloaded and verified file: ' + fpath) + return + + # expand redirect chain if needed + url = RemoteFileHandler._get_redirect_url(url, + max_hops=max_redirect_hops) + + # check if file is located on Google Drive + file_id = RemoteFileHandler._get_google_drive_file_id(url) + if file_id is not None: + return RemoteFileHandler.download_file_from_google_drive( + file_id, root, filename, md5) + + # download the file + try: + print('Downloading ' + url + ' to ' + fpath) + RemoteFileHandler._urlretrieve(url, fpath) + except (urllib.error.URLError, IOError) as e: # type: ignore[attr-defined] + if url[:5] == 'https': + url = url.replace('https:', 'http:') + print('Failed download. Trying https -> http instead.' + ' Downloading ' + url + ' to ' + fpath) + RemoteFileHandler._urlretrieve(url, fpath) + else: + raise e + + # check integrity of downloaded file + if not RemoteFileHandler.check_integrity(fpath, md5): + raise RuntimeError("File not found or corrupted.") + + @staticmethod + def download_file_from_google_drive(file_id, root, + filename=None, + md5=None): + """Download a Google Drive file from and place it in root. + Args: + file_id (str): id of file to be downloaded + root (str): Directory to place downloaded file in + filename (str, optional): Name to save the file under. + If None, use the id of the file. + md5 (str, optional): MD5 checksum of the download. + If None, do not check + """ + # Based on https://stackoverflow.com/questions/38511444/python-download-files-from-google-drive-using-url + import requests + url = "https://docs.google.com/uc?export=download" + + root = os.path.expanduser(root) + if not filename: + filename = file_id + fpath = os.path.join(root, filename) + + os.makedirs(root, exist_ok=True) + + if os.path.isfile(fpath) and RemoteFileHandler.check_integrity(fpath, + md5): + print('Using downloaded and verified file: ' + fpath) + else: + session = requests.Session() + + response = session.get(url, params={'id': file_id}, stream=True) + token = RemoteFileHandler._get_confirm_token(response) + + if token: + params = {'id': file_id, 'confirm': token} + response = session.get(url, params=params, stream=True) + + response_content_generator = response.iter_content(32768) + first_chunk = None + while not first_chunk: # filter out keep-alive new chunks + first_chunk = next(response_content_generator) + + if RemoteFileHandler._quota_exceeded(first_chunk): + msg = ( + f"The daily quota of the file {filename} is exceeded and " + f"it can't be downloaded. This is a limitation of " + f"Google Drive and can only be overcome by trying " + f"again later." + ) + raise RuntimeError(msg) + + RemoteFileHandler._save_response_content( + itertools.chain((first_chunk, ), + response_content_generator), + fpath) + response.close() + + @staticmethod + def unzip(path, destination_path=None): + if not destination_path: + destination_path = os.path.dirname(path) + + _, archive_type = os.path.splitext(path) + archive_type = archive_type.lstrip('.') + + if archive_type in ['zip']: + print("Unzipping {}->{}".format(path, destination_path)) + zip_file = zipfile.ZipFile(path) + zip_file.extractall(destination_path) + zip_file.close() + + elif archive_type in [ + 'tar', 'tgz', 'tar.gz', 'tar.xz', 'tar.bz2' + ]: + print("Unzipping {}->{}".format(path, destination_path)) + if archive_type == 'tar': + tar_type = 'r:' + elif archive_type.endswith('xz'): + tar_type = 'r:xz' + elif archive_type.endswith('gz'): + tar_type = 'r:gz' + elif archive_type.endswith('bz2'): + tar_type = 'r:bz2' + else: + tar_type = 'r:*' + try: + tar_file = tarfile.open(path, tar_type) + except tarfile.ReadError: + raise SystemExit("corrupted archive") + tar_file.extractall(destination_path) + tar_file.close() + + @staticmethod + def _urlretrieve(url, filename, chunk_size): + with open(filename, "wb") as fh: + with urllib.request.urlopen( + urllib.request.Request(url, + headers={"User-Agent": USER_AGENT})) \ + as response: + for chunk in iter(lambda: response.read(chunk_size), + ""): + if not chunk: + break + fh.write(chunk) + + @staticmethod + def _get_redirect_url(url, max_hops): + initial_url = url + headers = {"Method": "HEAD", "User-Agent": USER_AGENT} + + for _ in range(max_hops + 1): + with urllib.request.urlopen( + urllib.request.Request(url, headers=headers)) as response: + if response.url == url or response.url is None: + return url + + url = response.url + else: + raise RecursionError( + f"Request to {initial_url} exceeded {max_hops} redirects. " + f"The last redirect points to {url}." + ) + + @staticmethod + def _get_confirm_token(response): # type: ignore[name-defined] + for key, value in response.cookies.items(): + if key.startswith('download_warning'): + return value + + return None + + @staticmethod + def _save_response_content( + response_gen, destination, # type: ignore[name-defined] + ): + with open(destination, "wb") as f: + pbar = enlighten.Counter( + total=None, desc="Save content", units="%", color="green") + progress = 0 + for chunk in response_gen: + if chunk: # filter out keep-alive new chunks + f.write(chunk) + progress += len(chunk) + + pbar.close() + + @staticmethod + def _quota_exceeded(first_chunk): # type: ignore[name-defined] + try: + return "Google Drive - Quota exceeded" in first_chunk.decode() + except UnicodeDecodeError: + return False + + @staticmethod + def _get_google_drive_file_id(url): + parts = urlparse(url) + + if re.match(r"(drive|docs)[.]google[.]com", parts.netloc) is None: + return None + + match = re.match(r"/file/d/(?P[^/]*)", parts.path) + if match is None: + return None + + return match.group("id") + + +url = "https://drive.google.com/file/d/1LOVnao6WLW7FpbQELKawzjd19GKx-HH_/view?usp=sharing" # readme +url = "https://drive.google.com/file/d/1SYTZGRVjJUwMUGgZjmOjhDljMzyGaWcv/view?usp=sharing" + + +RemoteFileHandler.download_url(url, root="c:/projects/", filename="temp.zip") +RemoteFileHandler.unzip("c:/projects/temp.zip") \ No newline at end of file From 046966dee18690766375144b03fcbb40aab77770 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 8 Jul 2021 19:07:02 +0200 Subject: [PATCH 022/150] #1784 - refactored names Removed unneeded test files, are being downloaded from GDrive Slight refactoring of fixtures --- tests/lib/{DBHandler.py => db_handler.py} | 1 + tests/lib/{FileHandler.py => file_handler.py} | 12 +-- .../sync_server/fixture/openpype/logs.bson | Bin 2824 -> 0 bytes .../fixture/openpype/logs.metadata.json | 1 - .../fixture/openpype/settings.bson | Bin 623 -> 0 bytes .../fixture/openpype/settings.metadata.json | 1 - .../fixture/test_db/test_project.bson | Bin 13295 -> 0 bytes .../test_db/test_project.metadata.json | 1 - .../sync_server/test_site_operations.py | 102 ++++++++++++------ 9 files changed, 74 insertions(+), 44 deletions(-) rename tests/lib/{DBHandler.py => db_handler.py} (98%) rename tests/lib/{FileHandler.py => file_handler.py} (96%) delete mode 100644 tests/unit/openpype/modules/sync_server/fixture/openpype/logs.bson delete mode 100644 tests/unit/openpype/modules/sync_server/fixture/openpype/logs.metadata.json delete mode 100644 tests/unit/openpype/modules/sync_server/fixture/openpype/settings.bson delete mode 100644 tests/unit/openpype/modules/sync_server/fixture/openpype/settings.metadata.json delete mode 100644 tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.bson delete mode 100644 tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.metadata.json diff --git a/tests/lib/DBHandler.py b/tests/lib/db_handler.py similarity index 98% rename from tests/lib/DBHandler.py rename to tests/lib/db_handler.py index 258ff67df7..4f134e4b66 100644 --- a/tests/lib/DBHandler.py +++ b/tests/lib/db_handler.py @@ -69,6 +69,7 @@ class DBHandler(): print("{} doesn't exist".format(db_name)) return + print("Dropping {} database".format(db_name)) self.client.drop_database(db_name) def backup_to_dump(self, db_name, dump_dir, overwrite=False): diff --git a/tests/lib/FileHandler.py b/tests/lib/file_handler.py similarity index 96% rename from tests/lib/FileHandler.py rename to tests/lib/file_handler.py index e90eac34c1..79f86b5cf9 100644 --- a/tests/lib/FileHandler.py +++ b/tests/lib/file_handler.py @@ -264,9 +264,9 @@ class RemoteFileHandler: return match.group("id") -url = "https://drive.google.com/file/d/1LOVnao6WLW7FpbQELKawzjd19GKx-HH_/view?usp=sharing" # readme -url = "https://drive.google.com/file/d/1SYTZGRVjJUwMUGgZjmOjhDljMzyGaWcv/view?usp=sharing" - - -RemoteFileHandler.download_url(url, root="c:/projects/", filename="temp.zip") -RemoteFileHandler.unzip("c:/projects/temp.zip") \ No newline at end of file +# url = "https://drive.google.com/file/d/1LOVnao6WLW7FpbQELKawzjd19GKx-HH_/view?usp=sharing" # readme +# url = "https://drive.google.com/file/d/1SYTZGRVjJUwMUGgZjmOjhDljMzyGaWcv/view?usp=sharing" +# +# +# RemoteFileHandler.download_url(url, root="c:/projects/", filename="temp.zip") +# RemoteFileHandler.unzip("c:/projects/temp.zip") \ No newline at end of file diff --git a/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.bson b/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.bson deleted file mode 100644 index 37efb8a4a8dd94738bd7800df8e7a6d0f4c010c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2824 zcmdUw&ui2`6vxM)*7^gAJtf+z9Nn@3+}vNbEQ71~3DWoPofFEjJz^WMwHLxha@EF|~7 zz5P7?bL&O>*~`kPW-%yDGe0;#+Nv}}9ze$b*au1j$r0Q&2}FC_p`a5 z&MQfuIM#=p#67H=kzS=XU4nieav4{FdqDRC+0v>Up#-gb^%J zj*z8wa9dQlm_1TMIE40ek#~;oUDWr*m*G+T*q+5R4>mJZo^YCAd2I*rVH9MC57E7f zwi42PS3tL#qkCZwx=-|9>0(L~o;g zUqpM*u-kcd$b%fg#Rq4}s4(jpl`TGBo|ombo3b%gOE+UxR=` diff --git a/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.metadata.json b/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.metadata.json deleted file mode 100644 index 8c7a16261d..0000000000 --- a/tests/unit/openpype/modules/sync_server/fixture/openpype/logs.metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"options":{"capped":true,"size":{"$numberDouble":"1.073741824E+09"},"max":{"$numberInt":"5000"}},"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"f982c4d7baf54d03b88aaa540c9ced8e","collectionName":"logs"} \ No newline at end of file diff --git a/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.bson b/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.bson deleted file mode 100644 index dbfe2e88c6e63f08fccd8a06a280b29dd9bf5bbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 623 zcmbV~Jx&8L5QS&6AXcIY5+#SAqo4%|3JN6p!MmPKO#HL*%p&bg=(!1J0nWidfUr@D zkir^Sp7;6LZ=MT)19TSd-(GHRpW6A!-NoxfhK^tg06efzKqe6vXAGq^Vj!rf49WJM z81Qq`N;b^`&QwxSG_@xSu!oo)DQ9OX;(`W7gk$ZPoI<7Lw+~8jfihz-(ab3CjNu_R z>NV@7V@9#P6-&l?7ikRm$6HuTw8p1MU0-|0bCi_)t~mXtb6x8Zy{{sg`BWRf9?`yv z0IvT?<1*dL!=>~{kGh;5sF97@$}w7MP45K?xY_`kt~~sJG(SmU_#Trl4`a>;Ny@BQ diff --git a/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.metadata.json b/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.metadata.json deleted file mode 100644 index dafcd98d52..0000000000 --- a/tests/unit/openpype/modules/sync_server/fixture/openpype/settings.metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"8329d557adfe48018cd533dc648e3b7f","collectionName":"settings"} \ No newline at end of file diff --git a/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.bson b/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.bson deleted file mode 100644 index c81a0bd315f5c02f4ef86523e34f8b4098ae31cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13295 zcmeHOO^h5z6)yJ-pyYzYfdg;=E{Fp^;s^*3NPqwdMT&?J7nCChBJsVduAb^i?`9`) z#Ij_iFx^$Js@|*j-uHgmyz)`TZfiPi_N7;?AOH06g`d>E_OnYyydH3NJ7X*e{p-9H zGsCm{oP8K0F^}S=8ZNZ$*k-R`*l79f9D>_jXF0UP^>hWBXt_>s#$)@iNIah(#NuUN zCx|dce{&}$Iw1~x%4@TK6hJ55F2;5k%lDq`wOuhy;q!C5w&`}Z?pUG<_Fvh za6dR7FOEZ|RjZ9;a*XCilQkt_cT^~K$4*R~h4w*1HJ92i=^J72i`GFF7jvY+Tz6Vcs zC*~pVbfBh)Xy^pXWS>llK7^-%7joMzS4))|-U?3N?sCUxFGEiSAv*gWUG)t=Tju?ca!`&Wmk3#6a@mI^JMS z83P^Vc-@PE-Qo;vFwAm0WJcty#hiPmocJt^noK9U@boEW2y=VOXvg(!L8x!x`dwN} zL-W|x_n5Kj@EbhL?ilw5{bkQ~+{`d5guKhw&UnEfj@VU_$&t_J@C<7_jUPkM2u)o5 zV#zK&f3kGNEX`dz9JqGOFYwNhsmBf_J*8pBF>F#UrT$ae10%-y|}@(KEIO zE9i4i-tsxx&^SMT=6o~pL$d6w!drtV_WML5?PBp=sr~GwrHtm`1WxRaD9Q2S*^GV+ zj99hoP>#a$3Erb@2yOCNzGKbw|P}T%yNSSFH%~KKqG`A+;tfU*?OXNZ;%{J87g5fw& zZL(}A08X*kpLDezq&-X#hBUPBFRSs9OihYZy@Qy-1TLTfom&@V(4&U+Wn}&%n2CjrjmRPrI7}))HI>e3KIl z;k+WSLL!kdorCQV!S@k+;2{#Y*=5>QMOJe4`J?3|bArhyLG~jUFF%Xytk0ve2*`$v zxF4g5z89CHo*nYxLhK&f(MrVrMh5*f_ju^EWa5B?BaE8@AIM_5GzXfK$Q?y8rp=Q# zQ%=bW&j1W@VmFth-*!Q=#Mk0M$a5)Tz6Of3zQ5Aut1?B>jv?i`m;=cLrwe?}KPE)} z$O=!joj7*~P7^r9UiXn8mazu<2FHQ?rq2!+=hodic;a+qioD#r_*0x9|!A( zCJI6g>j+sXgWgIKw@aKZ+6Z^KTm)i<73P8Ze&mRKM8d0`M3+WU0Y8P9_eF9NvA;uQ zg(QiK*bA7PKpsM2qZ!z3B(hybEE>rmJAjwfjpXg9d2Hjv2>Iq_QeC9$$tVm_a0uQv z#G_a$o)jGxCKmpEvA}mJv_6UF4RV3239u+>|~GlDOVH_Jp? z-XMG4#L1MyK0({4l~h?>+iWJ(O-a~HCE0wUxq*wKWN7o))CQ~+y9gh;hjuy95uD+) z6SOsPodkBIMdqpk!56Bp5le*v(^4 zOo4GK26rf2!W4T5z+gz(*Co42tzbj*9$xvV zm%g1*XGKFn8bkb~_5`=9FkjV|c`fP7JUh%bg?Iu!ASyL$DAXnINw0#k%(Pb_revo= zv}_D)UkngZJp^l!eB8O}L<8Gh6k{s7K8igM_@a0T;Kc67+psmHf-c%Ena)jKLq+Sd zXuX&GHjTKLxAc03&7G0f5Vez33rX)SjrMSoCK0ui#NTaF`b^)89ZGNg_0=~%|4OH~ zf5}*pB4-jIZShb!1mH67AlmfSgae3l8EMo}8LI7hLCmE_pUhIfiNmC6zP|R` zUwozDUf+lxP~1|&mRg)+JFpuUR%!V>ehgP*IxqrGOb}W}KL$3}>QoL*E?at08ku4FQYQU&|tdME%&s}O-8#+L`5-630H?Pfb>Kl+rv0WWi=Svdq*gm1^~-Wg&&CjSDOP)M4d2;Aj-1A6Bq3X8I~K7wVQ$^bny$<|QT$ z8Rmos@s@N}Lr&BTomGOsP8=fVC5DF8NLo;^mveM}NOAh^lGukwli0^_)))-$<(yXk z*9N$iq(4Z7BfT+pC?_sGs?>5TGu}hPjF((XTGo?bLi+s;@G?%uD^0H@k@MGPTLNHD{W0wRae0p8J)Syq0r7;>ddl z5_gj1>K}!?4;9+y66rjf&0AOt-}iq96~CZ*rf;o^}TxR`to;R468zQ4L#fPz@ri>2)z$|lpD3Frsp> z-zDE&$_gXKEL`bpg!-PON`V9n9>LVG5~MN{rRyCUJsxw*)xM@r#h<14duQdU+NL~O zu2L!XHcam25|y#K7BJK;Rn%qQiXv2PY7L7}`YI`l(0N?H^i=$NlCg?VWpoYopsa8E zLUfc``%JnAOVN9Ay}PIs%{agM+>(nR`Q@nin!UsCEcD@fo6vEbZpLI(m5xGTRT|`% zVUYS4x3?`vm1&8O*O5samF}hZZRV$nnZuNsf6I9L3uIYesK@=I%0y3mb+I cYjUn))vGhJH|x{W^_jVGW61H}Xl3bt05iqOQ~&?~ diff --git a/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.metadata.json b/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.metadata.json deleted file mode 100644 index b43f27f459..0000000000 --- a/tests/unit/openpype/modules/sync_server/fixture/test_db/test_project.metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"bfe11cd230d041438b288f7d6ad8e70f","collectionName":"test_project"} \ No newline at end of file diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py index 7e1c994456..cea201e0c8 100644 --- a/tests/unit/openpype/modules/sync_server/test_site_operations.py +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -1,15 +1,34 @@ -"""Test file for Sync Server, tests site operations add_site, remove_site""" +"""Test file for Sync Server, tests site operations add_site, remove_site. + + File: + creates temporary directory and downloads .zip file from GDrive + unzips .zip file + uses content of .zip file (MongoDB's dumps) to import to new databases + with use of 'monkeypatch_session' modifies required env vars + temporarily + runs battery of tests checking that site operation for Sync Server + module are working + removes temporary folder + removes temporary databases (?) +""" import os import pytest +import tempfile +import shutil from bson.objectid import ObjectId -from tests.lib.DBHandler import DBHandler +from tests.lib.db_handler import DBHandler +from tests.lib.file_handler import RemoteFileHandler TEST_DB_NAME = "test_db" TEST_PROJECT_NAME = "test_project" TEST_OPENPYPE_NAME = "test_openpype" REPRESENTATION_ID = "60e578d0c987036c6a7b741d" +TEST_FILES = [ + ("1eCwPljuJeOI8A3aisfOIBKKjcmIycTEt", "test_site_operations.zip", "") +] + @pytest.fixture(scope='session') def monkeypatch_session(): @@ -21,21 +40,36 @@ def monkeypatch_session(): @pytest.fixture(scope="module") -def db_init(monkeypatch_session): - backup_dir = os.path.abspath( - os.path.join( - os.path.dirname(__file__), - 'fixture' - ) - ) +def download_test_data(): + tmpdir = tempfile.mkdtemp() + for test_file in TEST_FILES: + file_id, file_name, md5 = test_file + + f_name, ext = os.path.splitext(file_name) + + RemoteFileHandler.download_file_from_google_drive(file_id, + str(tmpdir), + file_name) + + if ext.lstrip('.') in RemoteFileHandler.IMPLEMENTED_ZIP_FORMATS: + RemoteFileHandler.unzip(os.path.join(tmpdir, file_name)) + + + yield tmpdir + shutil.rmtree(tmpdir) + + +@pytest.fixture(scope="module") +def db(monkeypatch_session, download_test_data): + backup_dir = download_test_data uri = os.environ.get("OPENPYPE_MONGO") or "mongodb://localhost:27017" - db = DBHandler(uri) - db.setup_from_dump(TEST_DB_NAME, backup_dir, True, - db_name_out=TEST_DB_NAME) + db_handler = DBHandler(uri) + db_handler.setup_from_dump(TEST_DB_NAME, backup_dir, True, + db_name_out=TEST_DB_NAME) - db.setup_from_dump("openpype", backup_dir, True, - db_name_out=TEST_OPENPYPE_NAME) + db_handler.setup_from_dump("openpype", backup_dir, True, + db_name_out=TEST_OPENPYPE_NAME) # set needed env vars temporarily for tests monkeypatch_session.setenv("OPENPYPE_MONGO", uri) @@ -46,17 +80,15 @@ def db_init(monkeypatch_session): monkeypatch_session.setenv("AVALON_PROJECT", TEST_PROJECT_NAME) monkeypatch_session.setenv("PYPE_DEBUG", "3") - -@pytest.fixture(scope="module") -def setup_avalon_db(db_init): - """Connect to Avalon, only after 'db_init' sets env vars.""" from avalon.api import AvalonMongoDB db = AvalonMongoDB() yield db + db_handler.teardown(TEST_DB_NAME) + db_handler.teardown(TEST_OPENPYPE_NAME) @pytest.fixture(scope="module") -def setup_sync_server_module(db_init): +def setup_sync_server_module(db): """Get sync_server_module from ModulesManager""" from openpype.modules import ModulesManager @@ -65,25 +97,25 @@ def setup_sync_server_module(db_init): yield sync_server -@pytest.mark.usefixtures("setup_avalon_db") -def test_project_created(setup_avalon_db): - assert ['test_project'] == setup_avalon_db.database.collection_names(False) +@pytest.mark.usefixtures("db") +def test_project_created(db): + assert ['test_project'] == db.database.collection_names(False) -@pytest.mark.usefixtures("setup_avalon_db") -def test_objects_imported(setup_avalon_db): - count_obj = len(list(setup_avalon_db.database[TEST_PROJECT_NAME].find({}))) +@pytest.mark.usefixtures("db") +def test_objects_imported(db): + count_obj = len(list(db.database[TEST_PROJECT_NAME].find({}))) assert 15 == count_obj @pytest.mark.usefixtures("setup_sync_server_module") -def test_add_site(setup_avalon_db, setup_sync_server_module): +def test_add_site(db, setup_sync_server_module): """Adds 'test_site', checks that added, checks that doesn't duplicate.""" query = { "_id": ObjectId(REPRESENTATION_ID) } - ret = setup_avalon_db.database[TEST_PROJECT_NAME].find(query) + ret = db.database[TEST_PROJECT_NAME].find(query) assert 1 == len(list(ret)), \ "Single {} must be in DB".format(REPRESENTATION_ID) @@ -91,7 +123,7 @@ def test_add_site(setup_avalon_db, setup_sync_server_module): setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, site_name='test_site') - ret = list(setup_avalon_db.database[TEST_PROJECT_NAME].find(query)) + ret = list(db.database[TEST_PROJECT_NAME].find(query)) assert 1 == len(ret), \ "Single {} must be in DB".format(REPRESENTATION_ID) @@ -102,7 +134,7 @@ def test_add_site(setup_avalon_db, setup_sync_server_module): @pytest.mark.usefixtures("setup_sync_server_module") -def test_add_site_again(setup_avalon_db, setup_sync_server_module): +def test_add_site_again(db, setup_sync_server_module): """Depends on test_add_site, must throw exception.""" with pytest.raises(ValueError): setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, @@ -110,7 +142,7 @@ def test_add_site_again(setup_avalon_db, setup_sync_server_module): @pytest.mark.usefixtures("setup_sync_server_module") -def test_add_site_again_force(setup_avalon_db, setup_sync_server_module): +def test_add_site_again_force(db, setup_sync_server_module): """Depends on test_add_site, must not throw exception.""" setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, site_name='test_site', force=True) @@ -119,14 +151,14 @@ def test_add_site_again_force(setup_avalon_db, setup_sync_server_module): "_id": ObjectId(REPRESENTATION_ID) } - ret = list(setup_avalon_db.database[TEST_PROJECT_NAME].find(query)) + ret = list(db.database[TEST_PROJECT_NAME].find(query)) assert 1 == len(ret), \ "Single {} must be in DB".format(REPRESENTATION_ID) @pytest.mark.usefixtures("setup_sync_server_module") -def test_remove_site(setup_avalon_db, setup_sync_server_module): +def test_remove_site(db, setup_sync_server_module): """Depends on test_add_site, must remove 'test_site'.""" setup_sync_server_module.remove_site(TEST_PROJECT_NAME, REPRESENTATION_ID, site_name='test_site') @@ -135,7 +167,7 @@ def test_remove_site(setup_avalon_db, setup_sync_server_module): "_id": ObjectId(REPRESENTATION_ID) } - ret = list(setup_avalon_db.database[TEST_PROJECT_NAME].find(query)) + ret = list(db.database[TEST_PROJECT_NAME].find(query)) assert 1 == len(ret), \ "Single {} must be in DB".format(REPRESENTATION_ID) @@ -147,7 +179,7 @@ def test_remove_site(setup_avalon_db, setup_sync_server_module): @pytest.mark.usefixtures("setup_sync_server_module") -def test_remove_site_again(setup_avalon_db, setup_sync_server_module): +def test_remove_site_again(db, setup_sync_server_module): """Depends on test_add_site, must trow exception""" with pytest.raises(ValueError): setup_sync_server_module.remove_site(TEST_PROJECT_NAME, @@ -158,7 +190,7 @@ def test_remove_site_again(setup_avalon_db, setup_sync_server_module): "_id": ObjectId(REPRESENTATION_ID) } - ret = list(setup_avalon_db.database[TEST_PROJECT_NAME].find(query)) + ret = list(db.database[TEST_PROJECT_NAME].find(query)) assert 1 == len(ret), \ "Single {} must be in DB".format(REPRESENTATION_ID) From bafba8dae019e13dec3865a72b729c4d44b8d883 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 13 Jul 2021 15:33:51 +0200 Subject: [PATCH 023/150] #1784 - added json import option --- tests/lib/db_handler.py | 103 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/tests/lib/db_handler.py b/tests/lib/db_handler.py index 4f134e4b66..af3ff0742d 100644 --- a/tests/lib/db_handler.py +++ b/tests/lib/db_handler.py @@ -32,6 +32,73 @@ class DBHandler(): # not much sense self.db = self.client[name] + def setup_from_sql(self, db_name, sql_dir, collection=None, + drop=True, mode=None): + """ + Restores 'db_name' from 'sql_url'. + + Works with directory with .json files, + if 'collection' arg is empty, name + of .json file is used as name of target collection. + + Args: + db_name (str): source DB name + sql_dir (str): folder with json files + collection (str): if all sql files are meant for single coll. + drop (bool): True if drop whole collection + mode (str): "insert" - fails on duplicates + "upsert" - modifies existing + "merge" - updates existing + "delete" - removes in DB present if file + """ + if not os.path.exists(sql_dir): + raise RuntimeError( + "Backup folder {} doesn't exist".format(sql_dir)) + + for (dirpath, dirnames, filenames) in os.walk(sql_dir): + for file_name in filenames: + sql_url = os.path.join(dirpath, file_name) + query = self._import_query(self.uri, sql_url, + db_name=db_name, + collection=collection, + drop=drop, + mode=mode) + + print("mongoimport query:: {}".format(query)) + subprocess.run(query) + + def setup_from_sql_file(self, db_name, sql_url, + collection=None, drop=True, mode=None): + """ + Restores 'db_name' from 'sql_url'. + + Works with single .json file. + If 'collection' arg is empty, name + of .json file is used as name of target collection. + + Args: + db_name (str): source DB name + sql_file (str): folder with json files + collection (str): name of target collection + drop (bool): True if drop collection + mode (str): "insert" - fails on duplicates + "upsert" - modifies existing + "merge" - updates existing + "delete" - removes in DB present if file + """ + if not os.path.exists(sql_url): + raise RuntimeError( + "Sql file {} doesn't exist".format(sql_url)) + + query = self._import_query(self.uri, sql_url, + db_name=db_name, + collection=collection, + drop=drop, + mode=mode) + + print("mongoimport query:: {}".format(query)) + subprocess.run(query) + def setup_from_dump(self, db_name, dump_dir, overwrite=False, collection=None, db_name_out=None): """ @@ -137,9 +204,39 @@ class DBHandler(): return query + def _import_query(self, uri, sql_url, + db_name=None, + collection=None, drop=True, mode=None): + + utility_path = os.path.join(self.MONGODB_UTILS_DIR, "mongoimport") + + db_part = coll_part = drop_part = mode_part = "" + if db_name: + db_part = "--db {}".format(db_name) + if collection: + assert db_name, "Must provide db name too" + coll_part = "--collection {}".format(collection) + if drop: + drop_part = "--drop" + if mode: + mode_part = "--mode {}".format(mode) + + query = \ + "\"{}\" --legacy --uri=\"{}\" --file=\"{}\" {} {} {} {}".format( + utility_path, uri, sql_url, + db_part, coll_part, drop_part, mode_part) + + return query + # handler = DBHandler(uri="mongodb://localhost:27017") # # backup_dir = "c:\\projects\\dumps" -# -# handler.backup_to_dump("openpype", backup_dir, True) -# handler.setup_from_dump("test_db", backup_dir, True) +# # +# # handler.backup_to_dump("openpype", backup_dir, True) +# # handler.setup_from_dump("test_db", backup_dir, True) +# # handler.setup_from_sql_file("test_db", "c:\\projects\\sql\\item.sql", +# # collection="test_project", +# # drop=False, mode="upsert") +# handler.setup_from_sql("test_db", "c:\\projects\\sql", +# collection="test_project", +# drop=False, mode="upsert") From 7fd3abc91fe764d656a6b5d2f321baf84b47ae9f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 13 Jul 2021 17:13:03 +0200 Subject: [PATCH 024/150] #1784 - implemented fixture for setting environment variables from json file --- .../sync_server/test_site_operations.py | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py index cea201e0c8..280e4daafe 100644 --- a/tests/unit/openpype/modules/sync_server/test_site_operations.py +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -12,6 +12,9 @@ removes temporary databases (?) """ import os +import sys +import six +import json import pytest import tempfile import shutil @@ -20,6 +23,7 @@ from bson.objectid import ObjectId from tests.lib.db_handler import DBHandler from tests.lib.file_handler import RemoteFileHandler +TEST_OPENPYPE_MONGO = "mongodb://localhost:27017" TEST_DB_NAME = "test_db" TEST_PROJECT_NAME = "test_project" TEST_OPENPYPE_NAME = "test_openpype" @@ -54,14 +58,36 @@ def download_test_data(): if ext.lstrip('.') in RemoteFileHandler.IMPLEMENTED_ZIP_FORMATS: RemoteFileHandler.unzip(os.path.join(tmpdir, file_name)) - yield tmpdir shutil.rmtree(tmpdir) @pytest.fixture(scope="module") -def db(monkeypatch_session, download_test_data): - backup_dir = download_test_data +def env_var(monkeypatch_session, download_test_data): + """Sets temporary env vars from json file.""" + env_url = os.path.join(download_test_data, "input", + "env_vars", "env_var.json") + if not os.path.exists(env_url): + raise ValueError("Env variable file {} doesn't exist".format(env_url)) + + env_dict = {} + try: + with open(env_url) as json_file: + env_dict = json.load(json_file) + except ValueError: + print("{} doesn't contain valid JSON") + six.reraise(*sys.exc_info()) + + for key, value in env_dict.items(): + value = value.format(**globals()) + print("Setting {}:{}".format(key, value)) + monkeypatch_session.setenv(key, value) + + +@pytest.fixture(scope="module") +def db_setup(download_test_data, env_var, monkeypatch_session): + """Restore prepared MongoDB dumps into selected DB.""" + backup_dir = os.path.join(download_test_data, "input", "dumps") uri = os.environ.get("OPENPYPE_MONGO") or "mongodb://localhost:27017" db_handler = DBHandler(uri) @@ -71,21 +97,22 @@ def db(monkeypatch_session, download_test_data): db_handler.setup_from_dump("openpype", backup_dir, True, db_name_out=TEST_OPENPYPE_NAME) - # set needed env vars temporarily for tests - monkeypatch_session.setenv("OPENPYPE_MONGO", uri) - monkeypatch_session.setenv("AVALON_MONGO", uri) - monkeypatch_session.setenv("OPENPYPE_DATABASE_NAME", TEST_OPENPYPE_NAME) - monkeypatch_session.setenv("AVALON_TIMEOUT", '3000') - monkeypatch_session.setenv("AVALON_DB", TEST_DB_NAME) - monkeypatch_session.setenv("AVALON_PROJECT", TEST_PROJECT_NAME) - monkeypatch_session.setenv("PYPE_DEBUG", "3") + yield db_handler + db_handler.teardown(TEST_DB_NAME) + db_handler.teardown(TEST_OPENPYPE_NAME) + + +@pytest.fixture(scope="module") +def db(db_setup): + """Provide test database connection. + + Database prepared from dumps with 'db_setup' fixture. + """ from avalon.api import AvalonMongoDB db = AvalonMongoDB() yield db - db_handler.teardown(TEST_DB_NAME) - db_handler.teardown(TEST_OPENPYPE_NAME) @pytest.fixture(scope="module") def setup_sync_server_module(db): From f977cba564c96fb6a6ecf99c009d75643688dc27 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 14 Jul 2021 14:58:36 +0200 Subject: [PATCH 025/150] #1784 - added wrapper class Added documentation --- tests/lib/README.md | 43 ++- tests/lib/testing_wrapper.py | 105 ++++++ .../sync_server/test_site_operations.py | 310 ++++++------------ 3 files changed, 256 insertions(+), 202 deletions(-) create mode 100644 tests/lib/testing_wrapper.py diff --git a/tests/lib/README.md b/tests/lib/README.md index 043dd3b8e9..56ff9749a2 100644 --- a/tests/lib/README.md +++ b/tests/lib/README.md @@ -1 +1,42 @@ -Folder for libs and tooling for automatic testing. \ No newline at end of file +Automatic testing +----------------- +Folder for libs and tooling for automatic testing. + +- db_handler.py - class for preparation of test DB + - dumps DB(s) to BSON (mongodump) + - loads dump(s) to new DB (mongorestore) + - loads sql file(s) to DB (mongoimport) + - deletes test DB + +- file_handler.py - class to download test data from GDrive + - downloads data from (list) of files from GDrive + - checks md5 if file ok + - unzips if zip + +- testing_wrapper.py - base class to use for testing + - all env var necessary for running (OPENPYPE_MONGO ...) + - implements reusable fixtures to: + - load test data (uses `file_handler`) + - prepare DB (uses `db_handler`) + - modify temporarily env vars for testing + + Should be used as a skeleton to create new test cases. + + +Test data +--------- +Each class implementing `TestCase` can provide test file(s) by adding them to +TEST_FILES ('GDRIVE_FILE_ID', 'ACTUAL_FILE_NAME', 'MD5HASH') + +GDRIVE_FILE_ID can be pulled from shareable link from Google Drive app. + +Currently it is expected that test file will be zip file with structure: +- expected - expected files (not implemented yet) +- input + - data - test data (workfiles, images etc) + - dumps - folder for BSOn dumps from (`mongodump`) + - env_vars + env_vars.json - dictionary with environment variables {key:value} + + - sql - sql files to load with `mongoimport` (human readable) + \ No newline at end of file diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py new file mode 100644 index 0000000000..fd50abd18e --- /dev/null +++ b/tests/lib/testing_wrapper.py @@ -0,0 +1,105 @@ +import os +import sys +import six +import json +import pytest +import tempfile +import shutil +from bson.objectid import ObjectId + +from tests.lib.db_handler import DBHandler +from tests.lib.file_handler import RemoteFileHandler + + +class TestCase(): + + TEST_OPENPYPE_MONGO = "mongodb://localhost:27017" + TEST_DB_NAME = "test_db" + TEST_PROJECT_NAME = "test_project" + TEST_OPENPYPE_NAME = "test_openpype" + + REPRESENTATION_ID = "60e578d0c987036c6a7b741d" + + TEST_FILES = [ + ("1eCwPljuJeOI8A3aisfOIBKKjcmIycTEt", "test_site_operations.zip", "") + ] + + @pytest.fixture(scope='session') + def monkeypatch_session(self): + """Monkeypatch couldn't be used with module or session fixtures.""" + from _pytest.monkeypatch import MonkeyPatch + m = MonkeyPatch() + yield m + m.undo() + + + @pytest.fixture(scope="module") + def download_test_data(self): + tmpdir = tempfile.mkdtemp() + for test_file in self.TEST_FILES: + file_id, file_name, md5 = test_file + + f_name, ext = os.path.splitext(file_name) + + RemoteFileHandler.download_file_from_google_drive(file_id, + str(tmpdir), + file_name) + + if ext.lstrip('.') in RemoteFileHandler.IMPLEMENTED_ZIP_FORMATS: + RemoteFileHandler.unzip(os.path.join(tmpdir, file_name)) + + yield tmpdir + shutil.rmtree(tmpdir) + + + @pytest.fixture(scope="module") + def env_var(self, monkeypatch_session, download_test_data): + """Sets temporary env vars from json file.""" + env_url = os.path.join(download_test_data, "input", + "env_vars", "env_var.json") + if not os.path.exists(env_url): + raise ValueError("Env variable file {} doesn't exist".format(env_url)) + + env_dict = {} + try: + with open(env_url) as json_file: + env_dict = json.load(json_file) + except ValueError: + print("{} doesn't contain valid JSON") + six.reraise(*sys.exc_info()) + + for key, value in env_dict.items(): + all_vars = globals() + all_vars.update(vars(TestCase)) # TODO check + value = value.format(**all_vars) + print("Setting {}:{}".format(key, value)) + monkeypatch_session.setenv(key, value) + + @pytest.fixture(scope="module") + def db_setup(self, download_test_data, env_var, monkeypatch_session): + """Restore prepared MongoDB dumps into selected DB.""" + backup_dir = os.path.join(download_test_data, "input", "dumps") + + uri = os.environ.get("OPENPYPE_MONGO") or "mongodb://localhost:27017" + db_handler = DBHandler(uri) + db_handler.setup_from_dump(self.TEST_DB_NAME, backup_dir, True, + db_name_out=self.TEST_DB_NAME) + + db_handler.setup_from_dump("openpype", backup_dir, True, + db_name_out=self.TEST_OPENPYPE_NAME) + + yield db_handler + + db_handler.teardown(self.TEST_DB_NAME) + db_handler.teardown(self.TEST_OPENPYPE_NAME) + + + @pytest.fixture(scope="module") + def db(self, db_setup): + """Provide test database connection. + + Database prepared from dumps with 'db_setup' fixture. + """ + from avalon.api import AvalonMongoDB + db = AvalonMongoDB() + yield db diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py index 280e4daafe..9c27da21c0 100644 --- a/tests/unit/openpype/modules/sync_server/test_site_operations.py +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -11,213 +11,121 @@ removes temporary folder removes temporary databases (?) """ -import os -import sys -import six -import json import pytest -import tempfile -import shutil + +from tests.lib.testing_wrapper import TestCase from bson.objectid import ObjectId -from tests.lib.db_handler import DBHandler -from tests.lib.file_handler import RemoteFileHandler -TEST_OPENPYPE_MONGO = "mongodb://localhost:27017" -TEST_DB_NAME = "test_db" -TEST_PROJECT_NAME = "test_project" -TEST_OPENPYPE_NAME = "test_openpype" -REPRESENTATION_ID = "60e578d0c987036c6a7b741d" +class TestSiteOperation(TestCase): -TEST_FILES = [ - ("1eCwPljuJeOI8A3aisfOIBKKjcmIycTEt", "test_site_operations.zip", "") -] - - -@pytest.fixture(scope='session') -def monkeypatch_session(): - """Monkeypatch couldn't be used with module or session fixtures.""" - from _pytest.monkeypatch import MonkeyPatch - m = MonkeyPatch() - yield m - m.undo() - - -@pytest.fixture(scope="module") -def download_test_data(): - tmpdir = tempfile.mkdtemp() - for test_file in TEST_FILES: - file_id, file_name, md5 = test_file - - f_name, ext = os.path.splitext(file_name) - - RemoteFileHandler.download_file_from_google_drive(file_id, - str(tmpdir), - file_name) - - if ext.lstrip('.') in RemoteFileHandler.IMPLEMENTED_ZIP_FORMATS: - RemoteFileHandler.unzip(os.path.join(tmpdir, file_name)) - - yield tmpdir - shutil.rmtree(tmpdir) - - -@pytest.fixture(scope="module") -def env_var(monkeypatch_session, download_test_data): - """Sets temporary env vars from json file.""" - env_url = os.path.join(download_test_data, "input", - "env_vars", "env_var.json") - if not os.path.exists(env_url): - raise ValueError("Env variable file {} doesn't exist".format(env_url)) - - env_dict = {} - try: - with open(env_url) as json_file: - env_dict = json.load(json_file) - except ValueError: - print("{} doesn't contain valid JSON") - six.reraise(*sys.exc_info()) - - for key, value in env_dict.items(): - value = value.format(**globals()) - print("Setting {}:{}".format(key, value)) - monkeypatch_session.setenv(key, value) - - -@pytest.fixture(scope="module") -def db_setup(download_test_data, env_var, monkeypatch_session): - """Restore prepared MongoDB dumps into selected DB.""" - backup_dir = os.path.join(download_test_data, "input", "dumps") - - uri = os.environ.get("OPENPYPE_MONGO") or "mongodb://localhost:27017" - db_handler = DBHandler(uri) - db_handler.setup_from_dump(TEST_DB_NAME, backup_dir, True, - db_name_out=TEST_DB_NAME) - - db_handler.setup_from_dump("openpype", backup_dir, True, - db_name_out=TEST_OPENPYPE_NAME) - - yield db_handler - - db_handler.teardown(TEST_DB_NAME) - db_handler.teardown(TEST_OPENPYPE_NAME) - - -@pytest.fixture(scope="module") -def db(db_setup): - """Provide test database connection. - - Database prepared from dumps with 'db_setup' fixture. - """ - from avalon.api import AvalonMongoDB - db = AvalonMongoDB() - yield db - - -@pytest.fixture(scope="module") -def setup_sync_server_module(db): - """Get sync_server_module from ModulesManager""" - from openpype.modules import ModulesManager - - manager = ModulesManager() - sync_server = manager.modules_by_name["sync_server"] - yield sync_server - - -@pytest.mark.usefixtures("db") -def test_project_created(db): - assert ['test_project'] == db.database.collection_names(False) - - -@pytest.mark.usefixtures("db") -def test_objects_imported(db): - count_obj = len(list(db.database[TEST_PROJECT_NAME].find({}))) - assert 15 == count_obj - - -@pytest.mark.usefixtures("setup_sync_server_module") -def test_add_site(db, setup_sync_server_module): - """Adds 'test_site', checks that added, checks that doesn't duplicate.""" - query = { - "_id": ObjectId(REPRESENTATION_ID) - } - - ret = db.database[TEST_PROJECT_NAME].find(query) - - assert 1 == len(list(ret)), \ - "Single {} must be in DB".format(REPRESENTATION_ID) - - setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, - site_name='test_site') - - ret = list(db.database[TEST_PROJECT_NAME].find(query)) - - assert 1 == len(ret), \ - "Single {} must be in DB".format(REPRESENTATION_ID) - - ret = ret.pop() - site_names = [site["name"] for site in ret["files"][0]["sites"]] - assert 'test_site' in site_names, "Site name wasn't added" - - -@pytest.mark.usefixtures("setup_sync_server_module") -def test_add_site_again(db, setup_sync_server_module): - """Depends on test_add_site, must throw exception.""" - with pytest.raises(ValueError): - setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, + @pytest.fixture(scope="module") + def setup_sync_server_module(self, db): + """Get sync_server_module from ModulesManager""" + from openpype.modules import ModulesManager + + manager = ModulesManager() + sync_server = manager.modules_by_name["sync_server"] + yield sync_server + + + @pytest.mark.usefixtures("db") + def test_project_created(self, db): + assert ['test_project'] == db.database.collection_names(False) + + + @pytest.mark.usefixtures("db") + def test_objects_imported(self, db): + count_obj = len(list(db.database[self.TEST_PROJECT_NAME].find({}))) + assert 15 == count_obj + + + @pytest.mark.usefixtures("setup_sync_server_module") + def test_add_site(self, db, setup_sync_server_module): + """Adds 'test_site', checks that added, checks that doesn't duplicate.""" + query = { + "_id": ObjectId(self.REPRESENTATION_ID) + } + + ret = db.database[self.TEST_PROJECT_NAME].find(query) + + assert 1 == len(list(ret)), \ + "Single {} must be in DB".format(self.REPRESENTATION_ID) + + setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, site_name='test_site') - - -@pytest.mark.usefixtures("setup_sync_server_module") -def test_add_site_again_force(db, setup_sync_server_module): - """Depends on test_add_site, must not throw exception.""" - setup_sync_server_module.add_site(TEST_PROJECT_NAME, REPRESENTATION_ID, - site_name='test_site', force=True) - - query = { - "_id": ObjectId(REPRESENTATION_ID) - } - - ret = list(db.database[TEST_PROJECT_NAME].find(query)) - - assert 1 == len(ret), \ - "Single {} must be in DB".format(REPRESENTATION_ID) - - -@pytest.mark.usefixtures("setup_sync_server_module") -def test_remove_site(db, setup_sync_server_module): - """Depends on test_add_site, must remove 'test_site'.""" - setup_sync_server_module.remove_site(TEST_PROJECT_NAME, REPRESENTATION_ID, - site_name='test_site') - - query = { - "_id": ObjectId(REPRESENTATION_ID) - } - - ret = list(db.database[TEST_PROJECT_NAME].find(query)) - - assert 1 == len(ret), \ - "Single {} must be in DB".format(REPRESENTATION_ID) - - ret = ret.pop() - site_names = [site["name"] for site in ret["files"][0]["sites"]] - - assert 'test_site' not in site_names, "Site name wasn't removed" - - -@pytest.mark.usefixtures("setup_sync_server_module") -def test_remove_site_again(db, setup_sync_server_module): - """Depends on test_add_site, must trow exception""" - with pytest.raises(ValueError): - setup_sync_server_module.remove_site(TEST_PROJECT_NAME, - REPRESENTATION_ID, + + ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) + + assert 1 == len(ret), \ + "Single {} must be in DB".format(self.REPRESENTATION_ID) + + ret = ret.pop() + site_names = [site["name"] for site in ret["files"][0]["sites"]] + assert 'test_site' in site_names, "Site name wasn't added" + + + @pytest.mark.usefixtures("setup_sync_server_module") + def test_add_site_again(self, db, setup_sync_server_module): + """Depends on test_add_site, must throw exception.""" + with pytest.raises(ValueError): + setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, + site_name='test_site') + + + @pytest.mark.usefixtures("setup_sync_server_module") + def test_add_site_again_force(self, db, setup_sync_server_module): + """Depends on test_add_site, must not throw exception.""" + setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, + site_name='test_site', force=True) + + query = { + "_id": ObjectId(self.REPRESENTATION_ID) + } + + ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) + + assert 1 == len(ret), \ + "Single {} must be in DB".format(self.REPRESENTATION_ID) + + + @pytest.mark.usefixtures("setup_sync_server_module") + def test_remove_site(self, db, setup_sync_server_module): + """Depends on test_add_site, must remove 'test_site'.""" + setup_sync_server_module.remove_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, site_name='test_site') + + query = { + "_id": ObjectId(self.REPRESENTATION_ID) + } + + ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) + + assert 1 == len(ret), \ + "Single {} must be in DB".format(self.REPRESENTATION_ID) + + ret = ret.pop() + site_names = [site["name"] for site in ret["files"][0]["sites"]] + + assert 'test_site' not in site_names, "Site name wasn't removed" + + + @pytest.mark.usefixtures("setup_sync_server_module") + def test_remove_site_again(self, db, setup_sync_server_module): + """Depends on test_add_site, must trow exception""" + with pytest.raises(ValueError): + setup_sync_server_module.remove_site(self.TEST_PROJECT_NAME, + self.REPRESENTATION_ID, + site_name='test_site') + + query = { + "_id": ObjectId(self.REPRESENTATION_ID) + } + + ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) + + assert 1 == len(ret), \ + "Single {} must be in DB".format(self.REPRESENTATION_ID) - query = { - "_id": ObjectId(REPRESENTATION_ID) - } - ret = list(db.database[TEST_PROJECT_NAME].find(query)) - - assert 1 == len(ret), \ - "Single {} must be in DB".format(REPRESENTATION_ID) +test_case = TestSiteOperation() \ No newline at end of file From 1c99861702b82c75a97957ecfa2aa799be4db928 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 30 Jul 2021 12:20:54 +0100 Subject: [PATCH 026/150] Stop timer on application exit. --- openpype/hosts/tvpaint/api/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openpype/hosts/tvpaint/api/__init__.py b/openpype/hosts/tvpaint/api/__init__.py index 57a03d38b7..27ae5769c3 100644 --- a/openpype/hosts/tvpaint/api/__init__.py +++ b/openpype/hosts/tvpaint/api/__init__.py @@ -1,6 +1,8 @@ import os import logging +import requests + import avalon.api import pyblish.api from avalon.tvpaint import pipeline @@ -51,6 +53,13 @@ def initial_launch(): set_context_settings() +def application_exit(): + # Stop application timer. + webserver_url = os.environ.get("OPENPYPE_WEBSERVER_URL") + rest_api_url = "{}/timers_manager/stop_timer".format(webserver_url) + requests.post(rest_api_url) + + def install(): log.info("OpenPype - Installing TVPaint integration") localization_file = os.path.join(HOST_DIR, "resources", "avalon.loc") @@ -67,6 +76,7 @@ def install(): pyblish.api.register_callback("instanceToggled", on_instance_toggle) avalon.api.on("application.launched", initial_launch) + avalon.api.on("application.exit", application_exit) def uninstall(): From 0750a2545613adc3a8930ac4667d9d740af11fe9 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 4 Aug 2021 10:42:06 +0100 Subject: [PATCH 027/150] Get task time method --- openpype/modules/timers_manager/rest_api.py | 21 +++++++++++++++++++ .../modules/timers_manager/timers_manager.py | 9 ++++++++ 2 files changed, 30 insertions(+) diff --git a/openpype/modules/timers_manager/rest_api.py b/openpype/modules/timers_manager/rest_api.py index ac8d8b7b74..1699179fd6 100644 --- a/openpype/modules/timers_manager/rest_api.py +++ b/openpype/modules/timers_manager/rest_api.py @@ -1,3 +1,5 @@ +import json + from aiohttp.web_response import Response from openpype.api import Logger @@ -28,6 +30,11 @@ class TimersManagerModuleRestApi: self.prefix + "/stop_timer", self.stop_timer ) + self.server_manager.add_route( + "GET", + self.prefix + "/get_task_time", + self.get_task_time + ) async def start_timer(self, request): data = await request.json() @@ -48,3 +55,17 @@ class TimersManagerModuleRestApi: async def stop_timer(self, request): self.module.stop_timers() return Response(status=200) + + async def get_task_time(self, request): + data = await request.json() + try: + project_name = data['project_name'] + asset_name = data['asset_name'] + task_name = data['task_name'] + except KeyError: + log.error("Payload must contain fields 'project_name, " + + "'asset_name', 'task_name'") + return Response(status=400) + + time = self.module.get_task_time(project_name, asset_name, task_name) + return Response(text=json.dumps(time)) diff --git a/openpype/modules/timers_manager/timers_manager.py b/openpype/modules/timers_manager/timers_manager.py index 92edd5aeaa..dfe5e6fc4b 100644 --- a/openpype/modules/timers_manager/timers_manager.py +++ b/openpype/modules/timers_manager/timers_manager.py @@ -124,6 +124,15 @@ class TimersManager(PypeModule, ITrayService, IIdleManager, IWebServerRoutes): } self.timer_started(None, data) + def get_task_time(self, project_name, asset_name, task_name): + time = {} + for module in self.modules: + time[module.name] = module.get_task_time( + project_name, asset_name, task_name + ) + + return time + def timer_started(self, source_id, data): for module in self.modules: if module.id != source_id: From 8ae107f4a40b8b4b60e3f8c396df721a424a77c7 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 4 Aug 2021 10:42:26 +0100 Subject: [PATCH 028/150] Get Ftrack task time --- openpype/modules/ftrack/ftrack_module.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/openpype/modules/ftrack/ftrack_module.py b/openpype/modules/ftrack/ftrack_module.py index ee139a500e..ee58a175f5 100644 --- a/openpype/modules/ftrack/ftrack_module.py +++ b/openpype/modules/ftrack/ftrack_module.py @@ -3,7 +3,7 @@ import json import collections from abc import ABCMeta, abstractmethod import six -import openpype + from openpype.modules import ( PypeModule, ITrayModule, @@ -368,3 +368,14 @@ class FtrackModule( def set_credentials_to_env(self, username, api_key): os.environ["FTRACK_API_USER"] = username or "" os.environ["FTRACK_API_KEY"] = api_key or "" + + def get_task_time(self, project_name, asset_name, task_name): + session = self.create_ftrack_session() + query = ( + 'Task where name is "{}"' + ' and parent.name is "{}"' + ' and project.full_name is "{}"' + ).format(task_name, asset_name, project_name) + task_entity = session.query(query).one() + hours_logged = (task_entity["time_logged"] / 60) / 60 + return hours_logged From 86c2aaff37b336ed3f11498dc46db51dcef4ec24 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 4 Aug 2021 10:47:30 +0100 Subject: [PATCH 029/150] Get data from context with defined keys. --- openpype/plugins/publish/extract_burnin.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index ef52d51325..88ccbdda1c 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -156,6 +156,16 @@ class ExtractBurnin(openpype.api.Extractor): filled_anatomy = anatomy.format_all(burnin_data) burnin_data["anatomy"] = filled_anatomy.get_solved() + # Add context data burnin_data. + burnin_data["context"] = {} + for item in repre_burnin_defs: + for field, setting in repre_burnin_defs[item].items(): + if "context" in setting: + key = setting.split("[")[1].split("]")[0] + burnin_data["context"][key] = ( + setting.format(context=instance.context.data) + ) + # Add source camera name to burnin data camera_name = repre.get("camera_name") if camera_name: From 26174213bd443e5f92471ef634b71ab83c24b944 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 4 Aug 2021 10:52:06 +0100 Subject: [PATCH 030/150] Hound fix. --- openpype/plugins/publish/extract_burnin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index 88ccbdda1c..a30f713e8a 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -159,7 +159,7 @@ class ExtractBurnin(openpype.api.Extractor): # Add context data burnin_data. burnin_data["context"] = {} for item in repre_burnin_defs: - for field, setting in repre_burnin_defs[item].items(): + for _, setting in repre_burnin_defs[item].items(): if "context" in setting: key = setting.split("[")[1].split("]")[0] burnin_data["context"][key] = ( From ebcfe422ac612b84096a2599a7fdfecb8f187d7a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 4 Aug 2021 16:51:09 +0100 Subject: [PATCH 031/150] Simplify to predefined data variable. --- openpype/plugins/publish/extract_burnin.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index a30f713e8a..2fab67cdb9 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -1,6 +1,5 @@ import os import re -import subprocess import json import copy import tempfile @@ -157,14 +156,7 @@ class ExtractBurnin(openpype.api.Extractor): burnin_data["anatomy"] = filled_anatomy.get_solved() # Add context data burnin_data. - burnin_data["context"] = {} - for item in repre_burnin_defs: - for _, setting in repre_burnin_defs[item].items(): - if "context" in setting: - key = setting.split("[")[1].split("]")[0] - burnin_data["context"][key] = ( - setting.format(context=instance.context.data) - ) + burnin_data["context"] = instance.context.data["burnin_context"] # Add source camera name to burnin data camera_name = repre.get("camera_name") From 08ceabd441d5762aaa1788ba6e9212a37ea6f5ed Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 9 Aug 2021 12:01:41 +0200 Subject: [PATCH 032/150] #1784 - Mongo command line utilities are expected at PATH --- tests/lib/db_handler.py | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/tests/lib/db_handler.py b/tests/lib/db_handler.py index af3ff0742d..97e69d9bd0 100644 --- a/tests/lib/db_handler.py +++ b/tests/lib/db_handler.py @@ -2,19 +2,16 @@ Helper class for automatic testing, provides dump and restore via command line utilities. - Expect mongodump and mongorestore present at MONGODB_UTILS_DIR + Expect mongodump, mongoimport and mongorestore present at PATH """ import os import pymongo import subprocess -class DBHandler(): +class DBHandler: - # vendorize ?? - MONGODB_UTILS_DIR = "c:\\Program Files\\MongoDB\\Server\\4.4\\bin" - - def __init__(self, uri=None, host=None, port=None, + def __init__(self, uri=None, host=None, port=None, user=None, password=None): """'uri' or rest of separate credentials""" if uri: @@ -141,7 +138,7 @@ class DBHandler(): def backup_to_dump(self, db_name, dump_dir, overwrite=False): """ - Helper class for running mongodump for specific 'db_name' + Helper method for running mongodump for specific 'db_name' """ if not self._db_exists(db_name) and not overwrite: raise RuntimeError("DB {} doesn't exists".format(db_name)) @@ -158,12 +155,8 @@ class DBHandler(): def _db_exists(self, db_name): return db_name in self.client.list_database_names() - def _dump_query(self, uri, - output_path, - db_name=None, collection=None): - - utility_path = os.path.join(self.MONGODB_UTILS_DIR, "mongodump") - + def _dump_query(self, uri, output_path, db_name=None, collection=None): + """Prepares dump query based on 'db_name' or 'collection'.""" db_part = coll_part = "" if db_name: db_part = "--db={}".format(db_name) @@ -172,7 +165,7 @@ class DBHandler(): raise ValueError("db_name must be present") coll_part = "--nsInclude={}.{}".format(db_name, collection) query = "\"{}\" --uri=\"{}\" --out={} {} {}".format( - utility_path, uri, output_path, db_part, coll_part + "mongodump", uri, output_path, db_part, coll_part ) return query @@ -180,9 +173,7 @@ class DBHandler(): def _restore_query(self, uri, dump_dir, db_name=None, db_name_out=None, collection=None, drop=True): - - utility_path = os.path.join(self.MONGODB_UTILS_DIR, "mongorestore") - + """Prepares query for mongorestore base on arguments""" db_part = coll_part = drop_part = "" if db_name: db_part = "--nsInclude={}.* --nsFrom={}.*".format(db_name, db_name) @@ -199,7 +190,7 @@ class DBHandler(): db_part += " --nsTo={}.*".format(db_name_out) query = "\"{}\" --uri=\"{}\" --dir=\"{}\" {} {} {}".format( - utility_path, uri, dump_dir, db_part, coll_part, drop_part + "mongorestore", uri, dump_dir, db_part, coll_part, drop_part ) return query @@ -208,8 +199,6 @@ class DBHandler(): db_name=None, collection=None, drop=True, mode=None): - utility_path = os.path.join(self.MONGODB_UTILS_DIR, "mongoimport") - db_part = coll_part = drop_part = mode_part = "" if db_name: db_part = "--db {}".format(db_name) @@ -223,7 +212,7 @@ class DBHandler(): query = \ "\"{}\" --legacy --uri=\"{}\" --file=\"{}\" {} {} {} {}".format( - utility_path, uri, sql_url, + "mongoimport", uri, sql_url, db_part, coll_part, drop_part, mode_part) return query @@ -232,7 +221,7 @@ class DBHandler(): # # backup_dir = "c:\\projects\\dumps" # # -# # handler.backup_to_dump("openpype", backup_dir, True) +# handler.backup_to_dump("openpype", backup_dir, True) # # handler.setup_from_dump("test_db", backup_dir, True) # # handler.setup_from_sql_file("test_db", "c:\\projects\\sql\\item.sql", # # collection="test_project", From 7d2974f8e9126d176f8ffa61fb417010a51657d8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 9 Aug 2021 12:14:36 +0200 Subject: [PATCH 033/150] Hound --- tests/lib/file_handler.py | 13 +--- tests/lib/testing_wrapper.py | 8 +-- .../sync_server/test_site_operations.py | 60 +++++++++---------- 3 files changed, 34 insertions(+), 47 deletions(-) diff --git a/tests/lib/file_handler.py b/tests/lib/file_handler.py index 79f86b5cf9..5d7e64b9cd 100644 --- a/tests/lib/file_handler.py +++ b/tests/lib/file_handler.py @@ -1,5 +1,3 @@ -import requests -import hashlib import enlighten import os import re @@ -84,7 +82,7 @@ class RemoteFileHandler: try: print('Downloading ' + url + ' to ' + fpath) RemoteFileHandler._urlretrieve(url, fpath) - except (urllib.error.URLError, IOError) as e: # type: ignore[attr-defined] + except (urllib.error.URLError, IOError) as e: #noqa type: ignore[attr-defined] if url[:5] == 'https': url = url.replace('https:', 'http:') print('Failed download. Trying https -> http instead.' @@ -110,7 +108,7 @@ class RemoteFileHandler: md5 (str, optional): MD5 checksum of the download. If None, do not check """ - # Based on https://stackoverflow.com/questions/38511444/python-download-files-from-google-drive-using-url + # Based on https://stackoverflow.com/questions/38511444/python-download-files-from-google-drive-using-url # noqa import requests url = "https://docs.google.com/uc?export=download" @@ -263,10 +261,3 @@ class RemoteFileHandler: return match.group("id") - -# url = "https://drive.google.com/file/d/1LOVnao6WLW7FpbQELKawzjd19GKx-HH_/view?usp=sharing" # readme -# url = "https://drive.google.com/file/d/1SYTZGRVjJUwMUGgZjmOjhDljMzyGaWcv/view?usp=sharing" -# -# -# RemoteFileHandler.download_url(url, root="c:/projects/", filename="temp.zip") -# RemoteFileHandler.unzip("c:/projects/temp.zip") \ No newline at end of file diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py index fd50abd18e..75ac476dfc 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_wrapper.py @@ -5,13 +5,12 @@ import json import pytest import tempfile import shutil -from bson.objectid import ObjectId from tests.lib.db_handler import DBHandler from tests.lib.file_handler import RemoteFileHandler -class TestCase(): +class TestCase: TEST_OPENPYPE_MONGO = "mongodb://localhost:27017" TEST_DB_NAME = "test_db" @@ -51,14 +50,14 @@ class TestCase(): yield tmpdir shutil.rmtree(tmpdir) - @pytest.fixture(scope="module") def env_var(self, monkeypatch_session, download_test_data): """Sets temporary env vars from json file.""" env_url = os.path.join(download_test_data, "input", "env_vars", "env_var.json") if not os.path.exists(env_url): - raise ValueError("Env variable file {} doesn't exist".format(env_url)) + raise ValueError("Env variable file {} doesn't exist". + format(env_url)) env_dict = {} try: @@ -93,7 +92,6 @@ class TestCase(): db_handler.teardown(self.TEST_DB_NAME) db_handler.teardown(self.TEST_OPENPYPE_NAME) - @pytest.fixture(scope="module") def db(self, db_setup): """Provide test database connection. diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py index 9c27da21c0..7dba792965 100644 --- a/tests/unit/openpype/modules/sync_server/test_site_operations.py +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -23,93 +23,91 @@ class TestSiteOperation(TestCase): def setup_sync_server_module(self, db): """Get sync_server_module from ModulesManager""" from openpype.modules import ModulesManager - + manager = ModulesManager() sync_server = manager.modules_by_name["sync_server"] yield sync_server - - + @pytest.mark.usefixtures("db") def test_project_created(self, db): assert ['test_project'] == db.database.collection_names(False) - @pytest.mark.usefixtures("db") def test_objects_imported(self, db): count_obj = len(list(db.database[self.TEST_PROJECT_NAME].find({}))) assert 15 == count_obj - @pytest.mark.usefixtures("setup_sync_server_module") def test_add_site(self, db, setup_sync_server_module): - """Adds 'test_site', checks that added, checks that doesn't duplicate.""" + """Adds 'test_site', checks that added, + checks that doesn't duplicate.""" query = { "_id": ObjectId(self.REPRESENTATION_ID) } - + ret = db.database[self.TEST_PROJECT_NAME].find(query) - + assert 1 == len(list(ret)), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) - - setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, + + setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, + self.REPRESENTATION_ID, site_name='test_site') - + ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) - + assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) - + ret = ret.pop() site_names = [site["name"] for site in ret["files"][0]["sites"]] assert 'test_site' in site_names, "Site name wasn't added" - @pytest.mark.usefixtures("setup_sync_server_module") def test_add_site_again(self, db, setup_sync_server_module): """Depends on test_add_site, must throw exception.""" with pytest.raises(ValueError): - setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, + setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, + self.REPRESENTATION_ID, site_name='test_site') - @pytest.mark.usefixtures("setup_sync_server_module") def test_add_site_again_force(self, db, setup_sync_server_module): """Depends on test_add_site, must not throw exception.""" - setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, + setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, + self.REPRESENTATION_ID, site_name='test_site', force=True) - + query = { "_id": ObjectId(self.REPRESENTATION_ID) } - + ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) - + assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) - @pytest.mark.usefixtures("setup_sync_server_module") def test_remove_site(self, db, setup_sync_server_module): """Depends on test_add_site, must remove 'test_site'.""" - setup_sync_server_module.remove_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, + setup_sync_server_module.remove_site(self.TEST_PROJECT_NAME, + self.REPRESENTATION_ID, site_name='test_site') query = { "_id": ObjectId(self.REPRESENTATION_ID) } - + ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) - + assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) - + ret = ret.pop() site_names = [site["name"] for site in ret["files"][0]["sites"]] - + assert 'test_site' not in site_names, "Site name wasn't removed" - @pytest.mark.usefixtures("setup_sync_server_module") def test_remove_site_again(self, db, setup_sync_server_module): """Depends on test_add_site, must trow exception""" @@ -117,15 +115,15 @@ class TestSiteOperation(TestCase): setup_sync_server_module.remove_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, site_name='test_site') - + query = { "_id": ObjectId(self.REPRESENTATION_ID) } - + ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) - + assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) -test_case = TestSiteOperation() \ No newline at end of file +test_case = TestSiteOperation() From fa542e8f65428ad30f6c9384396b4cbc7e8ab068 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 9 Aug 2021 12:17:34 +0200 Subject: [PATCH 034/150] #1784 - added example link to readme --- tests/lib/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/lib/README.md b/tests/lib/README.md index 56ff9749a2..1c2b188d84 100644 --- a/tests/lib/README.md +++ b/tests/lib/README.md @@ -39,4 +39,8 @@ Currently it is expected that test file will be zip file with structure: env_vars.json - dictionary with environment variables {key:value} - sql - sql files to load with `mongoimport` (human readable) - \ No newline at end of file + + +Example +------- +See `tests\unit\openpype\modules\sync_server\test_site_operations.py` for example usage of implemented classes. \ No newline at end of file From c76889dd552e65f46d5f61cbca7f11dc4a6e4674 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 9 Aug 2021 12:25:19 +0200 Subject: [PATCH 035/150] Hound --- tests/lib/db_handler.py | 2 +- tests/lib/file_handler.py | 4 +--- tests/lib/testing_wrapper.py | 1 - .../modules/sync_server/test_site_operations.py | 12 ++++++------ 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/lib/db_handler.py b/tests/lib/db_handler.py index 97e69d9bd0..44f3e80f98 100644 --- a/tests/lib/db_handler.py +++ b/tests/lib/db_handler.py @@ -52,7 +52,7 @@ class DBHandler: raise RuntimeError( "Backup folder {} doesn't exist".format(sql_dir)) - for (dirpath, dirnames, filenames) in os.walk(sql_dir): + for (_dirpath, _dirnames, filenames) in os.walk(sql_dir): for file_name in filenames: sql_url = os.path.join(dirpath, file_name) query = self._import_query(self.uri, sql_url, diff --git a/tests/lib/file_handler.py b/tests/lib/file_handler.py index 5d7e64b9cd..4c769620a0 100644 --- a/tests/lib/file_handler.py +++ b/tests/lib/file_handler.py @@ -148,8 +148,7 @@ class RemoteFileHandler: RemoteFileHandler._save_response_content( itertools.chain((first_chunk, ), - response_content_generator), - fpath) + response_content_generator), fpath) response.close() @staticmethod @@ -260,4 +259,3 @@ class RemoteFileHandler: return None return match.group("id") - diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py index 75ac476dfc..373bd9af0b 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_wrapper.py @@ -31,7 +31,6 @@ class TestCase: yield m m.undo() - @pytest.fixture(scope="module") def download_test_data(self): tmpdir = tempfile.mkdtemp() diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py index 7dba792965..85e52bf5df 100644 --- a/tests/unit/openpype/modules/sync_server/test_site_operations.py +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -31,12 +31,12 @@ class TestSiteOperation(TestCase): @pytest.mark.usefixtures("db") def test_project_created(self, db): assert ['test_project'] == db.database.collection_names(False) - + @pytest.mark.usefixtures("db") def test_objects_imported(self, db): count_obj = len(list(db.database[self.TEST_PROJECT_NAME].find({}))) assert 15 == count_obj - + @pytest.mark.usefixtures("setup_sync_server_module") def test_add_site(self, db, setup_sync_server_module): """Adds 'test_site', checks that added, @@ -62,7 +62,7 @@ class TestSiteOperation(TestCase): ret = ret.pop() site_names = [site["name"] for site in ret["files"][0]["sites"]] assert 'test_site' in site_names, "Site name wasn't added" - + @pytest.mark.usefixtures("setup_sync_server_module") def test_add_site_again(self, db, setup_sync_server_module): """Depends on test_add_site, must throw exception.""" @@ -70,7 +70,7 @@ class TestSiteOperation(TestCase): setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, site_name='test_site') - + @pytest.mark.usefixtures("setup_sync_server_module") def test_add_site_again_force(self, db, setup_sync_server_module): """Depends on test_add_site, must not throw exception.""" @@ -86,14 +86,14 @@ class TestSiteOperation(TestCase): assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) - + @pytest.mark.usefixtures("setup_sync_server_module") def test_remove_site(self, db, setup_sync_server_module): """Depends on test_add_site, must remove 'test_site'.""" setup_sync_server_module.remove_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, site_name='test_site') - + query = { "_id": ObjectId(self.REPRESENTATION_ID) } From dde84172e4833e238aa70759c053126630967ddd Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 9 Aug 2021 12:26:59 +0200 Subject: [PATCH 036/150] Fix wrong hound modification --- tests/lib/db_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/db_handler.py b/tests/lib/db_handler.py index 44f3e80f98..c38f351b76 100644 --- a/tests/lib/db_handler.py +++ b/tests/lib/db_handler.py @@ -52,7 +52,7 @@ class DBHandler: raise RuntimeError( "Backup folder {} doesn't exist".format(sql_dir)) - for (_dirpath, _dirnames, filenames) in os.walk(sql_dir): + for (dirpath, _dirnames, filenames) in os.walk(sql_dir): for file_name in filenames: sql_url = os.path.join(dirpath, file_name) query = self._import_query(self.uri, sql_url, From 65b60d6b5dd6a32e296a7b81e3d2451ee409a5ff Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 9 Aug 2021 16:56:20 +0100 Subject: [PATCH 037/150] Stop timer on application exit setting. Making the feature optional. --- openpype/hosts/tvpaint/api/__init__.py | 7 +++++++ openpype/settings/defaults/project_settings/tvpaint.json | 1 + .../schemas/projects_schema/schema_project_tvpaint.json | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/openpype/hosts/tvpaint/api/__init__.py b/openpype/hosts/tvpaint/api/__init__.py index 27ae5769c3..1c50987d6d 100644 --- a/openpype/hosts/tvpaint/api/__init__.py +++ b/openpype/hosts/tvpaint/api/__init__.py @@ -10,6 +10,7 @@ from avalon.tvpaint.communication_server import register_localization_file from .lib import set_context_settings from openpype.hosts import tvpaint +from openpype.api import get_current_project_settings log = logging.getLogger(__name__) @@ -54,6 +55,12 @@ def initial_launch(): def application_exit(): + data = get_current_project_settings() + stop_timer = data["tvpaint"]["stop_timer_on_application_exit"] + + if not stop_timer: + return + # Stop application timer. webserver_url = os.environ.get("OPENPYPE_WEBSERVER_URL") rest_api_url = "{}/timers_manager/stop_timer".format(webserver_url) diff --git a/openpype/settings/defaults/project_settings/tvpaint.json b/openpype/settings/defaults/project_settings/tvpaint.json index 47f486aa98..528bf6de8e 100644 --- a/openpype/settings/defaults/project_settings/tvpaint.json +++ b/openpype/settings/defaults/project_settings/tvpaint.json @@ -1,4 +1,5 @@ { + "stop_timer_on_application_exit": false, "publish": { "ExtractSequence": { "review_bg": [ diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_tvpaint.json b/openpype/settings/entities/schemas/projects_schema/schema_project_tvpaint.json index 368141813f..8286ed1193 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_tvpaint.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_tvpaint.json @@ -5,6 +5,11 @@ "label": "TVPaint", "is_file": true, "children": [ + { + "type": "boolean", + "key": "stop_timer_on_application_exit", + "label": "Stop timer on application exit" + }, { "type": "dict", "collapsible": true, From 900e3aac7ae1e9a1bee97cf12fa4a8544df3208b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 25 Aug 2021 16:40:13 +0200 Subject: [PATCH 038/150] Hound --- tests/lib/file_handler.py | 2 +- tests/lib/testing_wrapper.py | 6 ++-- .../sync_server/test_site_operations.py | 34 +++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/lib/file_handler.py b/tests/lib/file_handler.py index 4c769620a0..98e14b0541 100644 --- a/tests/lib/file_handler.py +++ b/tests/lib/file_handler.py @@ -82,7 +82,7 @@ class RemoteFileHandler: try: print('Downloading ' + url + ' to ' + fpath) RemoteFileHandler._urlretrieve(url, fpath) - except (urllib.error.URLError, IOError) as e: #noqa type: ignore[attr-defined] + except (urllib.error.URLError, IOError) as e: if url[:5] == 'https': url = url.replace('https:', 'http:') print('Failed download. Trying https -> http instead.' diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py index 373bd9af0b..b72e4284d0 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_wrapper.py @@ -92,11 +92,11 @@ class TestCase: db_handler.teardown(self.TEST_OPENPYPE_NAME) @pytest.fixture(scope="module") - def db(self, db_setup): + def dbcon(self, db_setup): """Provide test database connection. Database prepared from dumps with 'db_setup' fixture. """ from avalon.api import AvalonMongoDB - db = AvalonMongoDB() - yield db + dbcon = AvalonMongoDB() + yield dbcon diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py index 85e52bf5df..029f9a9f05 100644 --- a/tests/unit/openpype/modules/sync_server/test_site_operations.py +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -20,7 +20,7 @@ from bson.objectid import ObjectId class TestSiteOperation(TestCase): @pytest.fixture(scope="module") - def setup_sync_server_module(self, db): + def setup_sync_server_module(self, dbcon): """Get sync_server_module from ModulesManager""" from openpype.modules import ModulesManager @@ -28,24 +28,24 @@ class TestSiteOperation(TestCase): sync_server = manager.modules_by_name["sync_server"] yield sync_server - @pytest.mark.usefixtures("db") - def test_project_created(self, db): - assert ['test_project'] == db.database.collection_names(False) + @pytest.mark.usefixtures("dbcon") + def test_project_created(self, dbcon): + assert ['test_project'] == dbcon.database.collection_names(False) - @pytest.mark.usefixtures("db") - def test_objects_imported(self, db): - count_obj = len(list(db.database[self.TEST_PROJECT_NAME].find({}))) + @pytest.mark.usefixtures("dbcon") + def test_objects_imported(self, dbcon): + count_obj = len(list(dbcon.database[self.TEST_PROJECT_NAME].find({}))) assert 15 == count_obj @pytest.mark.usefixtures("setup_sync_server_module") - def test_add_site(self, db, setup_sync_server_module): + def test_add_site(self, dbcon, setup_sync_server_module): """Adds 'test_site', checks that added, checks that doesn't duplicate.""" query = { "_id": ObjectId(self.REPRESENTATION_ID) } - ret = db.database[self.TEST_PROJECT_NAME].find(query) + ret = dbcon.database[self.TEST_PROJECT_NAME].find(query) assert 1 == len(list(ret)), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) @@ -54,7 +54,7 @@ class TestSiteOperation(TestCase): self.REPRESENTATION_ID, site_name='test_site') - ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) + ret = list(dbcon.database[self.TEST_PROJECT_NAME].find(query)) assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) @@ -64,7 +64,7 @@ class TestSiteOperation(TestCase): assert 'test_site' in site_names, "Site name wasn't added" @pytest.mark.usefixtures("setup_sync_server_module") - def test_add_site_again(self, db, setup_sync_server_module): + def test_add_site_again(self, dbcon, setup_sync_server_module): """Depends on test_add_site, must throw exception.""" with pytest.raises(ValueError): setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, @@ -72,7 +72,7 @@ class TestSiteOperation(TestCase): site_name='test_site') @pytest.mark.usefixtures("setup_sync_server_module") - def test_add_site_again_force(self, db, setup_sync_server_module): + def test_add_site_again_force(self, dbcon, setup_sync_server_module): """Depends on test_add_site, must not throw exception.""" setup_sync_server_module.add_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, @@ -82,13 +82,13 @@ class TestSiteOperation(TestCase): "_id": ObjectId(self.REPRESENTATION_ID) } - ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) + ret = list(dbcon.database[self.TEST_PROJECT_NAME].find(query)) assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) @pytest.mark.usefixtures("setup_sync_server_module") - def test_remove_site(self, db, setup_sync_server_module): + def test_remove_site(self, dbcon, setup_sync_server_module): """Depends on test_add_site, must remove 'test_site'.""" setup_sync_server_module.remove_site(self.TEST_PROJECT_NAME, self.REPRESENTATION_ID, @@ -98,7 +98,7 @@ class TestSiteOperation(TestCase): "_id": ObjectId(self.REPRESENTATION_ID) } - ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) + ret = list(dbcon.database[self.TEST_PROJECT_NAME].find(query)) assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) @@ -109,7 +109,7 @@ class TestSiteOperation(TestCase): assert 'test_site' not in site_names, "Site name wasn't removed" @pytest.mark.usefixtures("setup_sync_server_module") - def test_remove_site_again(self, db, setup_sync_server_module): + def test_remove_site_again(self, dbcon, setup_sync_server_module): """Depends on test_add_site, must trow exception""" with pytest.raises(ValueError): setup_sync_server_module.remove_site(self.TEST_PROJECT_NAME, @@ -120,7 +120,7 @@ class TestSiteOperation(TestCase): "_id": ObjectId(self.REPRESENTATION_ID) } - ret = list(db.database[self.TEST_PROJECT_NAME].find(query)) + ret = list(dbcon.database[self.TEST_PROJECT_NAME].find(query)) assert 1 == len(ret), \ "Single {} must be in DB".format(self.REPRESENTATION_ID) From 4bb1b5c4a0dfc7c50bd7e154adebabe7a6a4fc2f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 25 Aug 2021 16:44:53 +0200 Subject: [PATCH 039/150] Removed default value --- tests/lib/testing_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py index b72e4284d0..df406f0ab9 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_wrapper.py @@ -78,7 +78,7 @@ class TestCase: """Restore prepared MongoDB dumps into selected DB.""" backup_dir = os.path.join(download_test_data, "input", "dumps") - uri = os.environ.get("OPENPYPE_MONGO") or "mongodb://localhost:27017" + uri = os.environ.get("OPENPYPE_MONGO") db_handler = DBHandler(uri) db_handler.setup_from_dump(self.TEST_DB_NAME, backup_dir, True, db_name_out=self.TEST_DB_NAME) From 08b42c9427dae0afd513716362cd715960aeecf0 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 26 Aug 2021 11:45:55 +0200 Subject: [PATCH 040/150] Added setup of _ROOT env vars --- tests/lib/testing_wrapper.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py index df406f0ab9..1ff42158db 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_wrapper.py @@ -72,6 +72,12 @@ class TestCase: value = value.format(**all_vars) print("Setting {}:{}".format(key, value)) monkeypatch_session.setenv(key, value) + import openpype + + openpype_root = os.path.dirname(os.path.dirname(openpype.__file__)) + # ?? why 2 of those + monkeypatch_session.setenv("OPENPYPE_ROOT", openpype_root) + monkeypatch_session.setenv("OPENPYPE_REPOS_ROOT", openpype_root) @pytest.fixture(scope="module") def db_setup(self, download_test_data, env_var, monkeypatch_session): From c130b72f126a31142e71f6d749d5b5ee65e1a3b3 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 27 Aug 2021 11:02:05 +0100 Subject: [PATCH 041/150] Update openpype/plugins/publish/extract_burnin.py Co-authored-by: Milan Kolar --- openpype/plugins/publish/extract_burnin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index 2fab67cdb9..b35f514509 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -156,7 +156,7 @@ class ExtractBurnin(openpype.api.Extractor): burnin_data["anatomy"] = filled_anatomy.get_solved() # Add context data burnin_data. - burnin_data["context"] = instance.context.data["burnin_context"] + burnin_data["context"] = instance.context.data.get("burnin_context") or {} # Add source camera name to burnin data camera_name = repre.get("camera_name") From 1693be8778cac688de8c8606c7b19a495ed7e7b5 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 27 Aug 2021 11:04:49 +0100 Subject: [PATCH 042/150] Update openpype/plugins/publish/extract_burnin.py --- openpype/plugins/publish/extract_burnin.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index b35f514509..fae79d6334 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -156,7 +156,9 @@ class ExtractBurnin(openpype.api.Extractor): burnin_data["anatomy"] = filled_anatomy.get_solved() # Add context data burnin_data. - burnin_data["context"] = instance.context.data.get("burnin_context") or {} + burnin_data["context"] = ( + instance.context.data.get("burnin_context") or {} + ) # Add source camera name to burnin data camera_name = repre.get("camera_name") From d1e8032fcdfb5f1c27872e8c99e07084856e8e55 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 1 Sep 2021 09:06:04 +0200 Subject: [PATCH 043/150] Failsafe for not finding the task. Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/modules/default_modules/ftrack/ftrack_module.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/modules/default_modules/ftrack/ftrack_module.py b/openpype/modules/default_modules/ftrack/ftrack_module.py index 828a7f1cab..0258b0ea1e 100644 --- a/openpype/modules/default_modules/ftrack/ftrack_module.py +++ b/openpype/modules/default_modules/ftrack/ftrack_module.py @@ -364,6 +364,8 @@ class FtrackModule( ' and parent.name is "{}"' ' and project.full_name is "{}"' ).format(task_name, asset_name, project_name) - task_entity = session.query(query).one() + task_entity = session.query(query).first() + if not task_entity: + return 0 hours_logged = (task_entity["time_logged"] / 60) / 60 return hours_logged From 19c058eafd3f6dbda94cef6230612ddb3489cf7c Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 1 Sep 2021 09:06:51 +0200 Subject: [PATCH 044/150] Respond with error message Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/modules/default_modules/timers_manager/rest_api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/modules/default_modules/timers_manager/rest_api.py b/openpype/modules/default_modules/timers_manager/rest_api.py index 1699179fd6..942db60ebc 100644 --- a/openpype/modules/default_modules/timers_manager/rest_api.py +++ b/openpype/modules/default_modules/timers_manager/rest_api.py @@ -63,7 +63,9 @@ class TimersManagerModuleRestApi: asset_name = data['asset_name'] task_name = data['task_name'] except KeyError: - log.error("Payload must contain fields 'project_name, " + + message = "Payload must contain fields 'project_name, 'asset_name', 'task_name'" + log.warning(message) + return Response(text=message, status=404) "'asset_name', 'task_name'") return Response(status=400) From 348274de5050feb94b3e48821baf1720e373e5a6 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 1 Sep 2021 08:22:06 +0100 Subject: [PATCH 045/150] Hound fix --- .../modules/default_modules/timers_manager/rest_api.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/modules/default_modules/timers_manager/rest_api.py b/openpype/modules/default_modules/timers_manager/rest_api.py index 942db60ebc..19b72d688b 100644 --- a/openpype/modules/default_modules/timers_manager/rest_api.py +++ b/openpype/modules/default_modules/timers_manager/rest_api.py @@ -63,11 +63,12 @@ class TimersManagerModuleRestApi: asset_name = data['asset_name'] task_name = data['task_name'] except KeyError: - message = "Payload must contain fields 'project_name, 'asset_name', 'task_name'" + message = ( + "Payload must contain fields 'project_name, 'asset_name'," + " 'task_name'" + ) log.warning(message) return Response(text=message, status=404) - "'asset_name', 'task_name'") - return Response(status=400) time = self.module.get_task_time(project_name, asset_name, task_name) return Response(text=json.dumps(time)) From b6a4a071f1375b205a7792a3fd5e2cc46e115aad Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 1 Sep 2021 08:26:50 +0100 Subject: [PATCH 046/150] Reset submodule. --- repos/avalon-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repos/avalon-core b/repos/avalon-core index 91867aeb4b..f48fce09c0 160000 --- a/repos/avalon-core +++ b/repos/avalon-core @@ -1 +1 @@ -Subproject commit 91867aeb4bfde115c0595c683282cc0b8265e694 +Subproject commit f48fce09c0986c1fd7f6731de33907be46b436c5 From 9887e00859850cf0044452b0413db8406624f051 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Wed, 1 Sep 2021 09:36:20 +0200 Subject: [PATCH 047/150] Update openpype/plugins/publish/extract_burnin.py Co-authored-by: Milan Kolar --- openpype/plugins/publish/extract_burnin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index fae79d6334..a9076c3e3c 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -156,8 +156,8 @@ class ExtractBurnin(openpype.api.Extractor): burnin_data["anatomy"] = filled_anatomy.get_solved() # Add context data burnin_data. - burnin_data["context"] = ( - instance.context.data.get("burnin_context") or {} + burnin_data["custom"] = ( + instance.data.get("custom_burnin_data") or {} ) # Add source camera name to burnin data From 38d6e4805e0fc537427ed76e261bc5ffe8ede78b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 1 Sep 2021 11:25:26 +0200 Subject: [PATCH 048/150] Added possibility to inject 'last_workfile_path' through data --- openpype/lib/applications.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 71ab2eac61..a62bd99b8c 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1328,23 +1328,27 @@ def _prepare_last_workfile(data, workdir): # Last workfile path last_workfile_path = "" - extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get( - app.host_name - ) - if extensions: - anatomy = data["anatomy"] - # Find last workfile - file_template = anatomy.templates["work"]["file"] - workdir_data.update({ - "version": 1, - "user": get_openpype_username(), - "ext": extensions[0] - }) - - last_workfile_path = avalon.api.last_workfile( - workdir, file_template, workdir_data, extensions, True + if data.get("last_workfile_path"): # to inject explicitly + last_workfile_path = data.get("last_workfile_path") + else: + extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get( + app.host_name ) + if extensions: + anatomy = data["anatomy"] + # Find last workfile + file_template = anatomy.templates["work"]["file"] + workdir_data.update({ + "version": 1, + "user": get_openpype_username(), + "ext": extensions[0] + }) + + last_workfile_path = avalon.api.last_workfile( + workdir, file_template, workdir_data, extensions, True + ) + if os.path.exists(last_workfile_path): log.debug(( "Workfiles for launch context does not exists" From c9c21849b0b792b59c645ef6ffe6e102d874100d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 1 Sep 2021 11:54:01 +0200 Subject: [PATCH 049/150] Added possibility to inject 'last_workfile_path' through data --- openpype/hooks/pre_global_host_data.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hooks/pre_global_host_data.py b/openpype/hooks/pre_global_host_data.py index c669d91ad5..b32fb5e44a 100644 --- a/openpype/hooks/pre_global_host_data.py +++ b/openpype/hooks/pre_global_host_data.py @@ -43,6 +43,8 @@ class GlobalHostDataHook(PreLaunchHook): "env": self.launch_context.env, + "last_workfile_path": self.data.get("last_workfile_path"), + "log": self.log }) From d4150a6af2ae31de8db6a9e2372ec3e6c9e990ec Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 1 Sep 2021 16:49:04 +0200 Subject: [PATCH 050/150] Fix - order must be in range --- openpype/plugins/publish/collect_host_name.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/plugins/publish/collect_host_name.py b/openpype/plugins/publish/collect_host_name.py index 41d9cc3a5a..ffb8125cbb 100644 --- a/openpype/plugins/publish/collect_host_name.py +++ b/openpype/plugins/publish/collect_host_name.py @@ -14,7 +14,7 @@ class CollectHostName(pyblish.api.ContextPlugin): """Collect avalon host name to context.""" label = "Collect Host Name" - order = pyblish.api.CollectorOrder - 1 + order = pyblish.api.CollectorOrder - 0.49 def process(self, context): host_name = context.data.get("hostName") @@ -35,3 +35,4 @@ class CollectHostName(pyblish.api.ContextPlugin): host_name = app.host_name context.data["hostName"] = host_name + From 8be9838e011f187641ff4cc78c087c2fc1e513a6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 2 Sep 2021 18:47:03 +0200 Subject: [PATCH 051/150] #1794 - added fixtures for db connections --- tests/lib/testing_wrapper.py | 42 +++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py index 1ff42158db..a389741ce3 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_wrapper.py @@ -11,7 +11,21 @@ from tests.lib.file_handler import RemoteFileHandler class TestCase: + """Generic test class for testing + Implemented fixtures: + monkeypatch_session - fixture for env vars with session scope + download_test_data - tmp folder with extracted data from GDrive + env_var - sets env vars from input file + db_setup - prepares avalon AND openpype DBs for testing from + binary dumps from input data + dbcon - returns DBConnection to AvalonDB + dbcon_openpype - returns DBConnection for OpenpypeMongoDB + + Not implemented: + last_workfile_path - returns path to testing workfile + + """ TEST_OPENPYPE_MONGO = "mongodb://localhost:27017" TEST_DB_NAME = "test_db" TEST_PROJECT_NAME = "test_project" @@ -19,9 +33,11 @@ class TestCase: REPRESENTATION_ID = "60e578d0c987036c6a7b741d" - TEST_FILES = [ - ("1eCwPljuJeOI8A3aisfOIBKKjcmIycTEt", "test_site_operations.zip", "") - ] + TEST_FILES = [] + + PROJECT = "test_project" + ASSET = "test_asset" + TASK = "test_task" @pytest.fixture(scope='session') def monkeypatch_session(self): @@ -47,6 +63,7 @@ class TestCase: RemoteFileHandler.unzip(os.path.join(tmpdir, file_name)) yield tmpdir + print("Removing {}".format(tmpdir)) shutil.rmtree(tmpdir) @pytest.fixture(scope="module") @@ -105,4 +122,23 @@ class TestCase: """ from avalon.api import AvalonMongoDB dbcon = AvalonMongoDB() + dbcon.Session["AVALON_PROJECT"] = self.TEST_PROJECT_NAME yield dbcon + + @pytest.fixture(scope="module") + def dbcon_openpype(self, db_setup): + """Provide test database connection for OP settings. + + Database prepared from dumps with 'db_setup' fixture. + """ + from openpype.lib import OpenPypeMongoConnection + mongo_client = OpenPypeMongoConnection.get_mongo_client() + yield mongo_client[self.TEST_OPENPYPE_NAME]["settings"] + + @pytest.fixture(scope="module") + def last_workfile_path(self, download_test_data): + raise NotImplemented + + @pytest.fixture(scope="module") + def startup_scripts(self, monkeypatch_session, download_test_data): + raise NotImplemented From 216d2ab30e46a08b87bd0c33774cf058e1b4ab7e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 2 Sep 2021 18:48:00 +0200 Subject: [PATCH 052/150] #1794 - added basic test for publishing in Maya --- .../sync_server/test_publish_in_maya.py | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 tests/unit/openpype/modules/sync_server/test_publish_in_maya.py diff --git a/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py b/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py new file mode 100644 index 0000000000..2aca0314dc --- /dev/null +++ b/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py @@ -0,0 +1,206 @@ +import pytest +import sys +import os +import shutil + +from tests.lib.testing_wrapper import TestCase + + +class TestPublishInMaya(TestCase): + """Basic test case for publishing in Maya + + Uses generic TestCase to prepare fixtures for test data, testing DBs, + env vars. + + Opens Maya, run publish on prepared workile. + + Then checks content of DB (if subset, version, representations were + created. + Checks tmp folder if all expected files were published. + + """ + TEST_FILES = [ + ("1pOwjA_VVBc6ooTZyFxtAwLS2KZHaBlkY", "test_maya_publish.zip", "") + ] + + APP = "maya" + APP_VARIANT = "2019" + + APP_NAME = "{}/{}".format(APP, APP_VARIANT) + + @pytest.fixture(scope="module") + def last_workfile_path(self, download_test_data): + """Get last_workfile_path from source data. + + Maya expects workfile in proper folder, so copy is done first. + """ + src_path = os.path.join(download_test_data, + "input", + "data", + "test_project_test_asset_TestTask_v001.mb") + dest_folder = os.path.join(download_test_data, + self.PROJECT, + self.ASSET, + "work", + self.TASK) + os.makedirs(dest_folder) + dest_path = os.path.join(dest_folder, + "test_project_test_asset_TestTask_v001.mb") + shutil.copy(src_path, dest_path) + + yield dest_path + + @pytest.fixture(scope="module") + def startup_scripts(self, monkeypatch_session, download_test_data): + """Copy""" + startup_path = os.path.join(download_test_data, + "input", + "startup", + "userSetup.py") + from openpype.hosts import maya + maya_dir = os.path.dirname(os.path.abspath(maya.__file__)) + shutil.move(os.path.join(maya_dir, "startup", "userSetup.py"), + os.path.join(maya_dir, "startup", "userSetup.tmp") + ) + shutil.copy(startup_path, + os.path.join(maya_dir, "startup", "userSetup.py")) + yield os.path.join(maya_dir, "startup", "userSetup.py") + + shutil.move(os.path.join(maya_dir, "startup", "userSetup.tmp"), + os.path.join(maya_dir, "startup", "userSetup.py")) + + @pytest.fixture(scope="module") + def launched_app(self, dbcon, download_test_data, last_workfile_path, + startup_scripts): + """Get sync_server_module from ModulesManager""" + root_key = "config.roots.work.{}".format("windows") # TEMP + dbcon.update_one( + {"type": "project"}, + {"$set": + { + root_key: download_test_data + }} + ) + + from openpype import PACKAGE_DIR + + # Path to OpenPype's schema + schema_path = os.path.join( + os.path.dirname(PACKAGE_DIR), + "schema" + ) + os.environ["AVALON_SCHEMA"] = schema_path # TEMP + + import openpype + openpype.install() + os.environ["OPENPYPE_EXECUTABLE"] = sys.executable + from openpype.lib import ApplicationManager + + application_manager = ApplicationManager() + data = { + "last_workfile_path": last_workfile_path, + "start_last_workfile": True, + "project_name": self.PROJECT, + "asset_name": self.ASSET, + "task_name": self.TASK + } + + yield application_manager.launch(self.APP_NAME, **data) + + @pytest.fixture(scope="module") + def publish_finished(self, dbcon, launched_app): + """Dummy fixture waiting for publish to finish""" + import time + while launched_app.poll() is None: + time.sleep(0.5) + + # some clean exit test possible? + print("Publish finished") + + def test_db_asserts(self, dbcon, publish_finished): + print("test_db_asserts") + assert 5 == dbcon.find({"type": "version"}).count(), \ + "Not expected no of versions" + + assert 0 == \ + dbcon.find({"type": "version", "name": {"$ne": 1}}).count(), \ + "Only versions with 1 expected" + + assert 1 == \ + dbcon.find({"type": "subset", "name": "modelMain"}).count(), \ + "modelMain subset must be present" + + assert 1 == \ + dbcon.find( + {"type": "subset", "name": "workfileTest_task"}).count(), \ + "workfileTest_task subset must be present" + + assert 11 == dbcon.find({"type": "representation"}).count(), \ + "Not expected no of representations" + + assert 2 == dbcon.find({"type": "representation", + "context.subset": "modelMain", + "context.ext": "abc"}).count(), \ + "Not expected no of representations with ext 'abc'" + + assert 2 == dbcon.find({"type": "representation", + "context.subset": "modelMain", + "context.ext": "ma"}).count(), \ + "Not expected no of representations with ext 'abc'" + + def test_files(self, dbcon, publish_finished, download_test_data): + print("test_files") + # hero files + hero_folder = os.path.join(download_test_data, + self.PROJECT, + self.ASSET, + "publish", + "model", + "modelMain", + "hero") + + assert os.path.exists( + os.path.join(hero_folder, + "test_project_test_asset_modelMain_hero.ma") + ), "test_project_test_asset_modelMain_hero.ma doesn't exist" + + assert os.path.exists( + os.path.join(hero_folder, + "test_project_test_asset_modelMain_hero.abc") + ), "test_project_test_asset_modelMain_hero.abc doesn't exist" + + # version files + version_folder = os.path.join(download_test_data, + self.PROJECT, + self.ASSET, + "publish", + "model", + "modelMain", + "v001") + + assert os.path.exists( + os.path.join(version_folder, + "test_project_test_asset_modelMain_v001.ma") + ), "test_project_test_asset_modelMain_v001.ma doesn't exist" + + assert os.path.exists( + os.path.join(version_folder, + "test_project_test_asset_modelMain_v001.abc") + ), "test_project_test_asset_modelMain_v001.abc doesn't exist" + + # workfile files + workfile_folder = os.path.join(download_test_data, + self.PROJECT, + self.ASSET, + "publish", + "workfile", + "workfileTest_task", + "v001") + + assert os.path.exists( + os.path.join(workfile_folder, + "test_project_test_asset_workfileTest_task_v001.mb") + ), "test_project_test_asset_workfileTest_task_v001.mb doesn't exist" + +if __name__ == "__main__": + test_case = TestPublishInMaya() From 0b02e5348a8a53e6ac2326cc3bdc76acc73f36c3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 2 Sep 2021 19:01:03 +0200 Subject: [PATCH 053/150] #1794 - fixes from review --- tests/lib/README.md | 6 +++--- tests/lib/db_handler.py | 4 ++-- tests/lib/testing_wrapper.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/lib/README.md b/tests/lib/README.md index 1c2b188d84..0384cd2ff0 100644 --- a/tests/lib/README.md +++ b/tests/lib/README.md @@ -10,7 +10,7 @@ Folder for libs and tooling for automatic testing. - file_handler.py - class to download test data from GDrive - downloads data from (list) of files from GDrive - - checks md5 if file ok + - check file integrity with MD5 hash - unzips if zip - testing_wrapper.py - base class to use for testing @@ -34,11 +34,11 @@ Currently it is expected that test file will be zip file with structure: - expected - expected files (not implemented yet) - input - data - test data (workfiles, images etc) - - dumps - folder for BSOn dumps from (`mongodump`) + - dumps - folder for BSON dumps from (`mongodump`) - env_vars env_vars.json - dictionary with environment variables {key:value} - - sql - sql files to load with `mongoimport` (human readable) + - json - json files to load with `mongoimport` (human readable) Example diff --git a/tests/lib/db_handler.py b/tests/lib/db_handler.py index c38f351b76..9be70895da 100644 --- a/tests/lib/db_handler.py +++ b/tests/lib/db_handler.py @@ -19,9 +19,9 @@ class DBHandler: if host: if all([user, password]): host = "{}:{}@{}".format(user, password, host) - uri = 'mongodb://{}:{}'.format(host, port or 27017) + self.uri = 'mongodb://{}:{}'.format(host, port or 27017) - assert uri, "Must have uri to MongoDB" + assert self.uri, "Must have uri to MongoDB" self.client = pymongo.MongoClient(uri) self.db = None diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py index a389741ce3..b2a89edec7 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_wrapper.py @@ -88,7 +88,7 @@ class TestCase: all_vars.update(vars(TestCase)) # TODO check value = value.format(**all_vars) print("Setting {}:{}".format(key, value)) - monkeypatch_session.setenv(key, value) + monkeypatch_session.setenv(key, str(value)) import openpype openpype_root = os.path.dirname(os.path.dirname(openpype.__file__)) From 5701cfed2b6018141f8c4a89b0f9428c917c7686 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 2 Sep 2021 19:09:21 +0200 Subject: [PATCH 054/150] Hound --- openpype/plugins/publish/collect_host_name.py | 1 - tests/lib/testing_wrapper.py | 4 ++-- .../sync_server/test_publish_in_maya.py | 20 +++++++++---------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/openpype/plugins/publish/collect_host_name.py b/openpype/plugins/publish/collect_host_name.py index 17cb59b212..b731e3ed26 100644 --- a/openpype/plugins/publish/collect_host_name.py +++ b/openpype/plugins/publish/collect_host_name.py @@ -35,4 +35,3 @@ class CollectHostName(pyblish.api.ContextPlugin): host_name = app.host_name context.data["hostName"] = host_name - diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_wrapper.py index b2a89edec7..0a7c9a382f 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_wrapper.py @@ -137,8 +137,8 @@ class TestCase: @pytest.fixture(scope="module") def last_workfile_path(self, download_test_data): - raise NotImplemented + raise NotImplementedError @pytest.fixture(scope="module") def startup_scripts(self, monkeypatch_session, download_test_data): - raise NotImplemented + raise NotImplementedError diff --git a/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py b/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py index 2aca0314dc..612a657c12 100644 --- a/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py +++ b/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py @@ -122,18 +122,17 @@ class TestPublishInMaya(TestCase): assert 5 == dbcon.find({"type": "version"}).count(), \ "Not expected no of versions" - assert 0 == \ - dbcon.find({"type": "version", "name": {"$ne": 1}}).count(), \ - "Only versions with 1 expected" + assert 0 == dbcon.find({"type": "version", + "name": {"$ne": 1}}).count(), \ + "Only versions with 1 expected" - assert 1 == \ - dbcon.find({"type": "subset", "name": "modelMain"}).count(), \ - "modelMain subset must be present" + assert 1 == dbcon.find({"type": "subset", + "name": "modelMain"}).count(), \ + "modelMain subset must be present" - assert 1 == \ - dbcon.find( - {"type": "subset", "name": "workfileTest_task"}).count(), \ - "workfileTest_task subset must be present" + assert 1 == dbcon.find({"type": "subset", + "name": "workfileTest_task"}).count(), \ + "workfileTest_task subset must be present" assert 11 == dbcon.find({"type": "representation"}).count(), \ "Not expected no of representations" @@ -202,5 +201,6 @@ class TestPublishInMaya(TestCase): "test_project_test_asset_workfileTest_task_v001.mb") ), "test_project_test_asset_workfileTest_task_v001.mb doesn't exist" + if __name__ == "__main__": test_case = TestPublishInMaya() From 7e088d6b977f02560001cfef82650b8a47d16684 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 3 Sep 2021 17:45:32 +0200 Subject: [PATCH 055/150] #1794 - moved to better folder Implemented comparing published files with expected Changed approach to userSetup --- .../hosts/maya}/test_publish_in_maya.py | 101 +++++++----------- 1 file changed, 37 insertions(+), 64 deletions(-) rename tests/{unit/openpype/modules/sync_server => integration/hosts/maya}/test_publish_in_maya.py (61%) diff --git a/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py b/tests/integration/hosts/maya/test_publish_in_maya.py similarity index 61% rename from tests/unit/openpype/modules/sync_server/test_publish_in_maya.py rename to tests/integration/hosts/maya/test_publish_in_maya.py index 612a657c12..fd8882c349 100644 --- a/tests/unit/openpype/modules/sync_server/test_publish_in_maya.py +++ b/tests/integration/hosts/maya/test_publish_in_maya.py @@ -2,6 +2,7 @@ import pytest import sys import os import shutil +import glob from tests.lib.testing_wrapper import TestCase @@ -28,6 +29,8 @@ class TestPublishInMaya(TestCase): APP_NAME = "{}/{}".format(APP, APP_VARIANT) + TIMEOUT = 120 # publish timeout + @pytest.fixture(scope="module") def last_workfile_path(self, download_test_data): """Get last_workfile_path from source data. @@ -52,22 +55,14 @@ class TestPublishInMaya(TestCase): @pytest.fixture(scope="module") def startup_scripts(self, monkeypatch_session, download_test_data): - """Copy""" + """Points Maya to userSetup file from input data""" startup_path = os.path.join(download_test_data, "input", - "startup", - "userSetup.py") - from openpype.hosts import maya - maya_dir = os.path.dirname(os.path.abspath(maya.__file__)) - shutil.move(os.path.join(maya_dir, "startup", "userSetup.py"), - os.path.join(maya_dir, "startup", "userSetup.tmp") - ) - shutil.copy(startup_path, - os.path.join(maya_dir, "startup", "userSetup.py")) - yield os.path.join(maya_dir, "startup", "userSetup.py") - - shutil.move(os.path.join(maya_dir, "startup", "userSetup.tmp"), - os.path.join(maya_dir, "startup", "userSetup.py")) + "startup") + original_pythonpath = os.environ.get("PYTHONPATH") + monkeypatch_session.setenv("PYTHONPATH", + "{};{}".format(original_pythonpath, + startup_path)) @pytest.fixture(scope="module") def launched_app(self, dbcon, download_test_data, last_workfile_path, @@ -111,11 +106,15 @@ class TestPublishInMaya(TestCase): def publish_finished(self, dbcon, launched_app): """Dummy fixture waiting for publish to finish""" import time + time_start = time.time() while launched_app.poll() is None: time.sleep(0.5) + if time.time() - time_start > self.TIMEOUT: + raise ValueError("Timeout reached") # some clean exit test possible? print("Publish finished") + yield True def test_db_asserts(self, dbcon, publish_finished): print("test_db_asserts") @@ -147,59 +146,33 @@ class TestPublishInMaya(TestCase): "context.ext": "ma"}).count(), \ "Not expected no of representations with ext 'abc'" - def test_files(self, dbcon, publish_finished, download_test_data): - print("test_files") - # hero files - hero_folder = os.path.join(download_test_data, - self.PROJECT, - self.ASSET, - "publish", - "model", - "modelMain", - "hero") + def test_folder_structure_same(self, dbcon, publish_finished, + download_test_data): + """Check if expected and published subfolders contain same files. - assert os.path.exists( - os.path.join(hero_folder, - "test_project_test_asset_modelMain_hero.ma") - ), "test_project_test_asset_modelMain_hero.ma doesn't exist" + Compares only presence, not size nor content! + """ + published_dir_base = download_test_data + published_dir = os.path.join(published_dir_base, + self.PROJECT, + self.TASK, + "**") + expected_dir_base = os.path.join(published_dir_base, + "expected") + expected_dir = os.path.join(expected_dir_base, + self.PROJECT, + self.TASK, + "**") - assert os.path.exists( - os.path.join(hero_folder, - "test_project_test_asset_modelMain_hero.abc") - ), "test_project_test_asset_modelMain_hero.abc doesn't exist" + published = set(f.replace(published_dir_base, '') for f in + glob.glob(published_dir, recursive=True) if + f != published_dir_base and os.path.exists(f)) + expected = set(f.replace(expected_dir_base, '') for f in + glob.glob(expected_dir, recursive=True) if + f != expected_dir_base and os.path.exists(f)) - # version files - version_folder = os.path.join(download_test_data, - self.PROJECT, - self.ASSET, - "publish", - "model", - "modelMain", - "v001") - - assert os.path.exists( - os.path.join(version_folder, - "test_project_test_asset_modelMain_v001.ma") - ), "test_project_test_asset_modelMain_v001.ma doesn't exist" - - assert os.path.exists( - os.path.join(version_folder, - "test_project_test_asset_modelMain_v001.abc") - ), "test_project_test_asset_modelMain_v001.abc doesn't exist" - - # workfile files - workfile_folder = os.path.join(download_test_data, - self.PROJECT, - self.ASSET, - "publish", - "workfile", - "workfileTest_task", - "v001") - - assert os.path.exists( - os.path.join(workfile_folder, - "test_project_test_asset_workfileTest_task_v001.mb") - ), "test_project_test_asset_workfileTest_task_v001.mb doesn't exist" + not_matched = expected.difference(published) + assert not not_matched, "Missing {} files".format(not_matched) if __name__ == "__main__": From 124429c5eece382161231f98853a4398278af2f8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 3 Sep 2021 18:13:06 +0200 Subject: [PATCH 056/150] #1794 - created multiple test classes Refactor --- .../hosts/maya/test_publish_in_maya.py | 85 +----------- ...{testing_wrapper.py => testing_classes.py} | 127 ++++++++++++++++-- .../sync_server/test_site_operations.py | 6 +- 3 files changed, 126 insertions(+), 92 deletions(-) rename tests/lib/{testing_wrapper.py => testing_classes.py} (54%) diff --git a/tests/integration/hosts/maya/test_publish_in_maya.py b/tests/integration/hosts/maya/test_publish_in_maya.py index fd8882c349..86b26ba5e5 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya.py +++ b/tests/integration/hosts/maya/test_publish_in_maya.py @@ -4,10 +4,10 @@ import os import shutil import glob -from tests.lib.testing_wrapper import TestCase +from tests.lib.testing_classes import PublishTest -class TestPublishInMaya(TestCase): +class TestPublishInMaya(PublishTest): """Basic test case for publishing in Maya Uses generic TestCase to prepare fixtures for test data, testing DBs, @@ -64,59 +64,8 @@ class TestPublishInMaya(TestCase): "{};{}".format(original_pythonpath, startup_path)) - @pytest.fixture(scope="module") - def launched_app(self, dbcon, download_test_data, last_workfile_path, - startup_scripts): - """Get sync_server_module from ModulesManager""" - root_key = "config.roots.work.{}".format("windows") # TEMP - dbcon.update_one( - {"type": "project"}, - {"$set": - { - root_key: download_test_data - }} - ) - - from openpype import PACKAGE_DIR - - # Path to OpenPype's schema - schema_path = os.path.join( - os.path.dirname(PACKAGE_DIR), - "schema" - ) - os.environ["AVALON_SCHEMA"] = schema_path # TEMP - - import openpype - openpype.install() - os.environ["OPENPYPE_EXECUTABLE"] = sys.executable - from openpype.lib import ApplicationManager - - application_manager = ApplicationManager() - data = { - "last_workfile_path": last_workfile_path, - "start_last_workfile": True, - "project_name": self.PROJECT, - "asset_name": self.ASSET, - "task_name": self.TASK - } - - yield application_manager.launch(self.APP_NAME, **data) - - @pytest.fixture(scope="module") - def publish_finished(self, dbcon, launched_app): - """Dummy fixture waiting for publish to finish""" - import time - time_start = time.time() - while launched_app.poll() is None: - time.sleep(0.5) - if time.time() - time_start > self.TIMEOUT: - raise ValueError("Timeout reached") - - # some clean exit test possible? - print("Publish finished") - yield True - def test_db_asserts(self, dbcon, publish_finished): + """Host and input data dependent expected results in DB.""" print("test_db_asserts") assert 5 == dbcon.find({"type": "version"}).count(), \ "Not expected no of versions" @@ -146,34 +95,6 @@ class TestPublishInMaya(TestCase): "context.ext": "ma"}).count(), \ "Not expected no of representations with ext 'abc'" - def test_folder_structure_same(self, dbcon, publish_finished, - download_test_data): - """Check if expected and published subfolders contain same files. - - Compares only presence, not size nor content! - """ - published_dir_base = download_test_data - published_dir = os.path.join(published_dir_base, - self.PROJECT, - self.TASK, - "**") - expected_dir_base = os.path.join(published_dir_base, - "expected") - expected_dir = os.path.join(expected_dir_base, - self.PROJECT, - self.TASK, - "**") - - published = set(f.replace(published_dir_base, '') for f in - glob.glob(published_dir, recursive=True) if - f != published_dir_base and os.path.exists(f)) - expected = set(f.replace(expected_dir_base, '') for f in - glob.glob(expected_dir, recursive=True) if - f != expected_dir_base and os.path.exists(f)) - - not_matched = expected.difference(published) - assert not not_matched, "Missing {} files".format(not_matched) - if __name__ == "__main__": test_case = TestPublishInMaya() diff --git a/tests/lib/testing_wrapper.py b/tests/lib/testing_classes.py similarity index 54% rename from tests/lib/testing_wrapper.py rename to tests/lib/testing_classes.py index 0a7c9a382f..6c7bebd469 100644 --- a/tests/lib/testing_wrapper.py +++ b/tests/lib/testing_classes.py @@ -1,3 +1,4 @@ +"""Testing classes for module testing and publishing in hosts.""" import os import sys import six @@ -5,13 +6,18 @@ import json import pytest import tempfile import shutil +import glob from tests.lib.db_handler import DBHandler from tests.lib.file_handler import RemoteFileHandler -class TestCase: - """Generic test class for testing +class BaseTest: + """Empty base test class""" + + +class ModuleUnitTest(BaseTest): + """Generic test class for testing modules Implemented fixtures: monkeypatch_session - fixture for env vars with session scope @@ -22,17 +28,12 @@ class TestCase: dbcon - returns DBConnection to AvalonDB dbcon_openpype - returns DBConnection for OpenpypeMongoDB - Not implemented: - last_workfile_path - returns path to testing workfile - """ TEST_OPENPYPE_MONGO = "mongodb://localhost:27017" TEST_DB_NAME = "test_db" TEST_PROJECT_NAME = "test_project" TEST_OPENPYPE_NAME = "test_openpype" - REPRESENTATION_ID = "60e578d0c987036c6a7b741d" - TEST_FILES = [] PROJECT = "test_project" @@ -85,7 +86,7 @@ class TestCase: for key, value in env_dict.items(): all_vars = globals() - all_vars.update(vars(TestCase)) # TODO check + all_vars.update(vars(ModuleUnitTest)) # TODO check value = value.format(**all_vars) print("Setting {}:{}".format(key, value)) monkeypatch_session.setenv(key, str(value)) @@ -135,6 +136,35 @@ class TestCase: mongo_client = OpenPypeMongoConnection.get_mongo_client() yield mongo_client[self.TEST_OPENPYPE_NAME]["settings"] + +class PublishTest(ModuleUnitTest): + """Test class for publishing in hosts. + + Implemented fixtures: + launched_app - launches APP with last_workfile_path + publish_finished - waits until publish is finished, host must + kill its process when finished publishing. Includes timeout + which raises ValueError + + Not implemented: + last_workfile_path - returns path to testing workfile + startup_scripts - provide script for setup in host + + Implemented tests: + test_folder_structure_same - compares published and expected + subfolders if they contain same files. Compares only on file + presence + + TODO: implement test on file size, file content + """ + + APP = "" + APP_VARIANT = "" + + APP_NAME = "{}/{}".format(APP, APP_VARIANT) + + TIMEOUT = 120 # publish timeout + @pytest.fixture(scope="module") def last_workfile_path(self, download_test_data): raise NotImplementedError @@ -142,3 +172,84 @@ class TestCase: @pytest.fixture(scope="module") def startup_scripts(self, monkeypatch_session, download_test_data): raise NotImplementedError + + @pytest.fixture(scope="module") + def launched_app(self, dbcon, download_test_data, last_workfile_path, + startup_scripts): + """Launch host app""" + # set publishing folders + root_key = "config.roots.work.{}".format("windows") # TEMP + dbcon.update_one( + {"type": "project"}, + {"$set": + { + root_key: download_test_data + }} + ) + + # set schema - for integrate_new + from openpype import PACKAGE_DIR + # Path to OpenPype's schema + schema_path = os.path.join( + os.path.dirname(PACKAGE_DIR), + "schema" + ) + os.environ["AVALON_SCHEMA"] = schema_path + + import openpype + openpype.install() + os.environ["OPENPYPE_EXECUTABLE"] = sys.executable + from openpype.lib import ApplicationManager + + application_manager = ApplicationManager() + data = { + "last_workfile_path": last_workfile_path, + "start_last_workfile": True, + "project_name": self.PROJECT, + "asset_name": self.ASSET, + "task_name": self.TASK + } + + yield application_manager.launch(self.APP_NAME, **data) + + @pytest.fixture(scope="module") + def publish_finished(self, dbcon, launched_app): + """Dummy fixture waiting for publish to finish""" + import time + time_start = time.time() + while launched_app.poll() is None: + time.sleep(0.5) + if time.time() - time_start > self.TIMEOUT: + raise ValueError("Timeout reached") + + # some clean exit test possible? + print("Publish finished") + yield True + + def test_folder_structure_same(self, dbcon, publish_finished, + download_test_data): + """Check if expected and published subfolders contain same files. + + Compares only presence, not size nor content! + """ + published_dir_base = download_test_data + published_dir = os.path.join(published_dir_base, + self.PROJECT, + self.TASK, + "**") + expected_dir_base = os.path.join(published_dir_base, + "expected") + expected_dir = os.path.join(expected_dir_base, + self.PROJECT, + self.TASK, + "**") + + published = set(f.replace(published_dir_base, '') for f in + glob.glob(published_dir, recursive=True) if + f != published_dir_base and os.path.exists(f)) + expected = set(f.replace(expected_dir_base, '') for f in + glob.glob(expected_dir, recursive=True) if + f != expected_dir_base and os.path.exists(f)) + + not_matched = expected.difference(published) + assert not not_matched, "Missing {} files".format(not_matched) \ No newline at end of file diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py index 029f9a9f05..ab15025399 100644 --- a/tests/unit/openpype/modules/sync_server/test_site_operations.py +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -13,11 +13,13 @@ """ import pytest -from tests.lib.testing_wrapper import TestCase +from tests.lib.testing_classes import ModuleUnitTest from bson.objectid import ObjectId -class TestSiteOperation(TestCase): +class TestSiteOperation(ModuleUnitTest): + + REPRESENTATION_ID = "60e578d0c987036c6a7b741d" @pytest.fixture(scope="module") def setup_sync_server_module(self, dbcon): From 6d270bfeb5d951fe09ef580e5b7d625c3f2ec753 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 3 Sep 2021 19:44:10 +0200 Subject: [PATCH 057/150] script fixes --- Dockerfile | 9 ++++++--- pyproject.toml | 2 +- tools/build.sh | 15 +++++++++------ tools/create_env.sh | 22 ++++++++++++++-------- tools/docker_build.sh | 4 +++- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2d8ed27b15..78611860ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,6 +33,7 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n readline-devel \ sqlite sqlite-devel \ openssl-devel \ + openssl-libs \ tk-devel libffi-devel \ qt5-qtbase-devel \ patchelf \ @@ -73,10 +74,12 @@ RUN source $HOME/.bashrc \ && ./tools/fetch_thirdparty_libs.sh RUN source $HOME/.bashrc \ - && bash ./tools/build.sh \ - && cp /usr/lib64/libffi* ./build/exe.linux-x86_64-3.7/lib \ + && bash ./tools/build.sh + +RUN cp /usr/lib64/libffi* ./build/exe.linux-x86_64-3.7/lib \ && cp /usr/lib64/libssl* ./build/exe.linux-x86_64-3.7/lib \ - && cp /usr/lib64/libcrypto* ./build/exe.linux-x86_64-3.7/lib + && cp /usr/lib64/libcrypto* ./build/exe.linux-x86_64-3.7/lib \ + && cp /root/.pyenv/versions/${OPENPYPE_PYTHON_VERSION}/lib/libpython* ./build/exe.linux-x86_64-3.7/lib RUN cd /opt/openpype \ rm -rf ./vendor/bin diff --git a/pyproject.toml b/pyproject.toml index e376986606..a57ae19224 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,7 @@ slack-sdk = "^3.6.0" flake8 = "^3.7" autopep8 = "^1.4" coverage = "*" -cx_freeze = "^6.6" +cx_freeze = "*" GitPython = "^3.1.17" jedi = "^0.13" Jinja2 = "^2.11" diff --git a/tools/build.sh b/tools/build.sh index c44e7157af..bc79f03db7 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -58,7 +58,7 @@ BICyan='\033[1;96m' # Cyan BIWhite='\033[1;97m' # White args=$@ -disable_submodule_update = 0 +disable_submodule_update=0 while :; do case $1 in --no-submodule-update) @@ -90,6 +90,7 @@ done ############################################################################### detect_python () { echo -e "${BIGreen}>>>${RST} Using python \c" + command -v python >/dev/null 2>&1 || { echo -e "${BIRed}- NOT FOUND${RST} ${BIYellow}You need Python 3.7 installed to continue.${RST}"; return 1; } local version_command version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))" local python_version @@ -122,7 +123,7 @@ clean_pyc () { local path path=$openpype_root echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" - find "$path" -path ./build -prune -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete + find "$path" -path ./build -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -173,7 +174,7 @@ main () { else echo -e "${BIYellow}NOT FOUND${RST}" echo -e "${BIYellow}***${RST} We need to install Poetry and virtual env ..." - . "$openpype_root/tools/create_env.sh" || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return; } + . "$openpype_root/tools/create_env.sh" || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return 1; } fi if [ "$disable_submodule_update" == 1 ]; then @@ -184,9 +185,9 @@ if [ "$disable_submodule_update" == 1 ]; then fi echo -e "${BIGreen}>>>${RST} Building ..." if [[ "$OSTYPE" == "linux-gnu"* ]]; then - "$POETRY_HOME/bin/poetry" run python "$openpype_root/setup.py" build > "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; } + "$POETRY_HOME/bin/poetry" run python "$openpype_root/setup.py" build &> "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return 1; } elif [[ "$OSTYPE" == "darwin"* ]]; then - "$POETRY_HOME/bin/poetry" run python "$openpype_root/setup.py" bdist_mac > "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; } + "$POETRY_HOME/bin/poetry" run python "$openpype_root/setup.py" bdist_mac &> "$openpype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return 1; } fi "$POETRY_HOME/bin/poetry" run python "$openpype_root/tools/build_dependencies.py" @@ -210,4 +211,6 @@ if [ "$disable_submodule_update" == 1 ]; then echo -e "${BIWhite}$openpype_root/build${RST} directory." } -main +return_code=0 +main || return_code=$? +exit $return_code diff --git a/tools/create_env.sh b/tools/create_env.sh index cc9eddc317..4ed6412c43 100755 --- a/tools/create_env.sh +++ b/tools/create_env.sh @@ -88,6 +88,7 @@ done ############################################################################### detect_python () { echo -e "${BIGreen}>>>${RST} Using python \c" + command -v python >/dev/null 2>&1 || { echo -e "${BIRed}- NOT FOUND${RST} ${BIYellow}You need Python 3.7 installed to continue.${RST}"; return 1; } local version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))" local python_version="$(python <<< ${version_command})" oIFS="$IFS" @@ -125,7 +126,7 @@ clean_pyc () { local path path=$openpype_root echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" - find "$path" -path ./build -prune -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete + find "$path" -path ./build -o -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -166,7 +167,7 @@ main () { echo -e "${BIGreen}OK${RST}" else echo -e "${BIYellow}NOT FOUND${RST}" - install_poetry || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return; } + install_poetry || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return 1; } fi if [ -f "$openpype_root/poetry.lock" ]; then @@ -175,7 +176,11 @@ main () { echo -e "${BIGreen}>>>${RST} Installing dependencies ..." fi - "$POETRY_HOME/bin/poetry" install --no-root $poetry_verbosity || { echo -e "${BIRed}!!!${RST} Poetry environment installation failed"; return; } + "$POETRY_HOME/bin/poetry" install --no-root $poetry_verbosity || { echo -e "${BIRed}!!!${RST} Poetry environment installation failed"; return 1; } + if [ $? -ne 0 ] ; then + echo -e "${BIRed}!!!${RST} Virtual environment creation failed." + return 1 + fi echo -e "${BIGreen}>>>${RST} Cleaning cache files ..." clean_pyc @@ -184,10 +189,11 @@ main () { # cx_freeze will crash on missing __pychache__ on these but # reinstalling them solves the problem. echo -e "${BIGreen}>>>${RST} Fixing pycache bug ..." - "$POETRY_HOME/bin/poetry" run python -m pip install --force-reinstall pip - "$POETRY_HOME/bin/poetry" run pip install --force-reinstall setuptools - "$POETRY_HOME/bin/poetry" run pip install --force-reinstall wheel - "$POETRY_HOME/bin/poetry" run python -m pip install --force-reinstall pip + "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall setuptools + "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall wheel + "$POETRY_HOME/bin/poetry" run python -m pip install --disable-pip-version-check --force-reinstall pip } -main -3 +return_code=0 +main || return_code=$? +exit $return_code diff --git a/tools/docker_build.sh b/tools/docker_build.sh index 7600fe044b..dca217d534 100755 --- a/tools/docker_build.sh +++ b/tools/docker_build.sh @@ -32,7 +32,8 @@ main () { openpype_version="$(python3 <<< ${version_command})" echo -e "${BIGreen}>>>${RST} Running docker build ..." - docker build --pull --no-cache -t pypeclub/openpype:$openpype_version . + # docker build --pull --no-cache -t pypeclub/openpype:$openpype_version . + docker build --pull -t pypeclub/openpype:$openpype_version . if [ $? -ne 0 ] ; then echo -e "${BIRed}!!!${RST} Docker build failed." return 1 @@ -47,6 +48,7 @@ main () { fi echo -e "${BIYellow}---${RST} Copying ..." docker cp "$id:/opt/openpype/build/exe.linux-x86_64-3.7" "$openpype_root/build" + docker cp "$id:/opt/openpype/build/build.log" "$openpype_root/build" if [ $? -ne 0 ] ; then echo -e "${BIRed}!!!${RST} Copying failed." return 1 From d26095883921ac187dfccde229f38ceee5eea745 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Mon, 6 Sep 2021 10:43:50 +0200 Subject: [PATCH 058/150] try to get error log from failed build --- tools/docker_build.sh | 44 +++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/tools/docker_build.sh b/tools/docker_build.sh index dca217d534..c27041a1af 100755 --- a/tools/docker_build.sh +++ b/tools/docker_build.sh @@ -20,6 +20,28 @@ realpath () { echo $(cd $(dirname "$1"); pwd)/$(basename "$1") } +create_container () { + if [ ! -f "$openpype_root/build/docker-image.id" ]; then + echo -e "${BIRed}!!!${RST} Docker command failed, cannot find image id." + exit 1 + fi + local id=$(<"$openpype_root/build/docker-image.id") + echo -e "${BIYellow}---${RST} Creating container from $id ..." + local cid="$(docker create $id bash)" + if [ $? -ne 0 ] ; then + echo -e "${BIRed}!!!${RST} Cannot create container." + exit 1 + fi + return $cid +} + +retrieve_build_log () { + create_container + local cid=$? + echo -e "${BIYellow}***${RST} Copying build log to ${BIWhite}$openpype_root/build/build.log${RST}" + docker cp "$cid:/opt/openpype/build/build.log" "$openpype_root/build" +} + # Main main () { openpype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) @@ -28,34 +50,32 @@ main () { echo -e "${BIYellow}---${RST} Cleaning build directory ..." rm -rf "$openpype_root/build" && mkdir "$openpype_root/build" > /dev/null - version_command="import os;exec(open(os.path.join('$openpype_root', 'openpype', 'version.py')).read());print(__version__);" - openpype_version="$(python3 <<< ${version_command})" + local version_command="import os;exec(open(os.path.join('$openpype_root', 'openpype', 'version.py')).read());print(__version__);" + local openpype_version="$(python3 <<< ${version_command})" echo -e "${BIGreen}>>>${RST} Running docker build ..." # docker build --pull --no-cache -t pypeclub/openpype:$openpype_version . - docker build --pull -t pypeclub/openpype:$openpype_version . + docker build --pull --iidfile $openpype_root/build/docker-image.id -t pypeclub/openpype:$openpype_version . if [ $? -ne 0 ] ; then + echo $? echo -e "${BIRed}!!!${RST} Docker build failed." + retrieve_build_log return 1 fi echo -e "${BIGreen}>>>${RST} Copying build from container ..." - echo -e "${BIYellow}---${RST} Creating container from pypeclub/openpype:$openpype_version ..." - id="$(docker create -ti pypeclub/openpype:$openpype_version bash)" - if [ $? -ne 0 ] ; then - echo -e "${BIRed}!!!${RST} Cannot create just built container." - return 1 - fi + create_container + local cid=$? echo -e "${BIYellow}---${RST} Copying ..." - docker cp "$id:/opt/openpype/build/exe.linux-x86_64-3.7" "$openpype_root/build" - docker cp "$id:/opt/openpype/build/build.log" "$openpype_root/build" + docker cp "$cid:/opt/openpype/build/exe.linux-x86_64-3.7" "$openpype_root/build" + docker cp "$cid:/opt/openpype/build/build.log" "$openpype_root/build" if [ $? -ne 0 ] ; then echo -e "${BIRed}!!!${RST} Copying failed." return 1 fi echo -e "${BIGreen}>>>${RST} Fixing user ownership ..." - username="$(logname)" + local username="$(logname)" chown -R $username ./build echo -e "${BIGreen}>>>${RST} All done, you can delete container:" From d0a4293b9d12e59b59bac0c9845f45fc84839ff3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 6 Sep 2021 18:42:34 +0200 Subject: [PATCH 059/150] #1784 - added howto create new publishing test --- tests/integration/README.md | 31 ++++++++++++++++++ .../hosts/maya/test_publish_in_maya.py | 4 ++- tests/lib/testing_classes.py | 20 +++++++---- tests/resources/test_data.zip | Bin 0 -> 7350 bytes 4 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 tests/resources/test_data.zip diff --git a/tests/integration/README.md b/tests/integration/README.md index 00d8a4c10d..81c07ec50c 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -4,3 +4,34 @@ Contains end-to-end tests for automatic testing of OP. Should run headless publish on all hosts to check basic publish use cases automatically to limit regression issues. + +How to create test for publishing from host +------------------------------------------ +- Extend PublishTest +- Use `resources\test_data.zip` skeleton file as a template for testing input data +- Put workfile into `test_data.zip/input/workfile` +- If you require other than base DB dumps provide them to `test_data.zip/input/dumps` +-- (Check commented code in `db_handler.py` how to dump specific DB. Currently all collections will be dumped.) +- Implement `last_workfile_path` +- `startup_scripts` - must contain pointing host to startup script saved into `test_data.zip/input/startup` + -- Script must contain something like +``` +import openpype +from avalon import api, HOST + +api.install(HOST) +pyblish.util.publish() + +EXIT_APP (command to exit host) +``` +(Install and publish methods must be triggered only AFTER host app is fully initialized!) +- Zip `test_data.zip`, named it with descriptive name, upload it to Google Drive, right click - `Get link`, copy hash id +- Put this hash id and zip file name into TEST_FILES [(HASH_ID, FILE_NAME, MD5_OPTIONAL)]. If you want to check MD5 of downloaded +file, provide md5 value of zipped file. +- Implement any assert checks you need in extended class +- Run test class manually (via Pycharm or pytest runner (TODO)) +- If you want test to compare expected files to published one, set PERSIST to True, run test manually + -- Locate temporary `publish` subfolder of temporary folder (found in debugging console log) + -- Copy whole folder content into .zip file into `expected` subfolder + -- By default tests are comparing only structure of `expected` and published format (eg. if you want to save space, replace published files with empty files, but with expected names!) + -- Zip and upload again, change PERSIST to False \ No newline at end of file diff --git a/tests/integration/hosts/maya/test_publish_in_maya.py b/tests/integration/hosts/maya/test_publish_in_maya.py index 86b26ba5e5..b9c63651f1 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya.py +++ b/tests/integration/hosts/maya/test_publish_in_maya.py @@ -20,6 +20,8 @@ class TestPublishInMaya(PublishTest): Checks tmp folder if all expected files were published. """ + PERSIST = True + TEST_FILES = [ ("1pOwjA_VVBc6ooTZyFxtAwLS2KZHaBlkY", "test_maya_publish.zip", "") ] @@ -39,7 +41,7 @@ class TestPublishInMaya(PublishTest): """ src_path = os.path.join(download_test_data, "input", - "data", + "workfile", "test_project_test_asset_TestTask_v001.mb") dest_folder = os.path.join(download_test_data, self.PROJECT, diff --git a/tests/lib/testing_classes.py b/tests/lib/testing_classes.py index 6c7bebd469..6cd3c10d3e 100644 --- a/tests/lib/testing_classes.py +++ b/tests/lib/testing_classes.py @@ -19,6 +19,9 @@ class BaseTest: class ModuleUnitTest(BaseTest): """Generic test class for testing modules + Use PERSIST==True to keep temporary folder and DB prepared for + debugging or preparation of test files. + Implemented fixtures: monkeypatch_session - fixture for env vars with session scope download_test_data - tmp folder with extracted data from GDrive @@ -29,6 +32,8 @@ class ModuleUnitTest(BaseTest): dbcon_openpype - returns DBConnection for OpenpypeMongoDB """ + PERSIST = False # True to not purge temporary folder nor test DB + TEST_OPENPYPE_MONGO = "mongodb://localhost:27017" TEST_DB_NAME = "test_db" TEST_PROJECT_NAME = "test_project" @@ -62,10 +67,12 @@ class ModuleUnitTest(BaseTest): if ext.lstrip('.') in RemoteFileHandler.IMPLEMENTED_ZIP_FORMATS: RemoteFileHandler.unzip(os.path.join(tmpdir, file_name)) - + print("Temporary folder created:: {}".format(tmpdir)) yield tmpdir - print("Removing {}".format(tmpdir)) - shutil.rmtree(tmpdir) + + if not self.PERSIST: + print("Removing {}".format(tmpdir)) + shutil.rmtree(tmpdir) @pytest.fixture(scope="module") def env_var(self, monkeypatch_session, download_test_data): @@ -112,8 +119,9 @@ class ModuleUnitTest(BaseTest): yield db_handler - db_handler.teardown(self.TEST_DB_NAME) - db_handler.teardown(self.TEST_OPENPYPE_NAME) + if not self.PERSIST: + db_handler.teardown(self.TEST_DB_NAME) + db_handler.teardown(self.TEST_OPENPYPE_NAME) @pytest.fixture(scope="module") def dbcon(self, db_setup): @@ -213,7 +221,7 @@ class PublishTest(ModuleUnitTest): yield application_manager.launch(self.APP_NAME, **data) @pytest.fixture(scope="module") - def publish_finished(self, dbcon, launched_app): + def publish_finished(self, dbcon, launched_app, download_test_data): """Dummy fixture waiting for publish to finish""" import time time_start = time.time() diff --git a/tests/resources/test_data.zip b/tests/resources/test_data.zip new file mode 100644 index 0000000000000000000000000000000000000000..0faab86b37d5c7d1224e8a92cca766ed80536718 GIT binary patch literal 7350 zcmb7I1z1$u8XdZE=nm;_LAtv}N|27ByE`OAU}#VpL68msX(XiuK^hd0ZV(Uz^$nNj zMY-H}@7sKbGc(`6*4g{t|K98D1yY2A#|6Lw008_XI(6vn&xQ*9 z8Ao(24(GQxu%{!~)D>*@3xMhx0Qeig%HGk<^_OVuYti^OM4P$UIlBB048`AK92~*+ zj$V%7Kf%ZV~5Z-Q;;l_Z{v#(ni-;f;D+uA>_3_4;u= zI>y9!s)`ru+DgUns)GsnWtapLep49acxd0{2Wk0TWj4*{imJI2Uk69VWvnWFZM?j| ze%qMx8u;{#E>lYWvOov!cI4*YZd;S;@PlY*>`z9zUMyVrD>_u zk;FT^8hqleVs%_zQL(~>Hsp7;rFNAStI;$Q-g4g}F+&Z$Wt|dOA(V#f@d()?^JueI z2U)cFn;&KHmxB*NZdS^iDfzlzBFgn{(~=Rb+ClY_syq@ zw+DCa2k9DL|6G@sbzJI8MOF;0-xKJ?`7i6(4(w`tvBcS|p#=?&>BoG?0hIm$UQ{tb zO$2FgwnIdX(AP~lAbGT67z!sIx^qt}npX#!QxNn-tt?~<2x6Od?}-azkmC>@k(f4A zwcy+(%^;wIk0qB&dBOuG65f_auz@AZ`Y}+I@lXpWVT1wF4do6C+Jqf~BzK)5wNP1B zPwySh7<&=C2p(?rR%|^hkkGAEQqx5JfUgm!$MJ@rogpqsstbr6`<5_qzpKBzqwWlO z6Y2Mn3wYKS?n6iH0A0l_|2%RRu&b+;{eM?+Mx3%jrx;L%8K)~S4NK1(*@JDCX{|kU zzNO?jbBg;{dRI+EXPhq|I;#p+E8K?ToZ#i{Qgb$iMNTqN1L3L>cMP)}>?vltdgr?O zmAW&HF#%i=FJ+B2Nd$sMVzE!qlSES6Dgpj1rF7QGj>&NmaAVOJt>h+pP733Wt+X)@ zk-JY#+)*|CTXwTGHu+J!QQteImc()L@Y_7F6O8yFh@RlYyLSjwXp4;uI(z1>gV8{#P(K>s0e!7z(GEu z7O8qsi2wP_XUyMI=k**{#TS~gH0X8b|47~Mg)<-yEgamCg+?X4mq3NQV?_I=Ku-9t z(~yR;Gd4N@39nxds4$ z>*7KFx5K$qHj`g;K*MlVt$nVv_X$)3cDVrn_J73w!QtraU=3BgKjdKhfxa#2eY_UI zMjkuV_tg*uMbsVDhzxIG?#-hzzCKl);>U0*CfM}iyrUz zfzt#u3p-niNlru03{b6<2 ze|47I|I9RG%Z5L+ai3iuct==wY(TroCgcHI{)4@l!$y z?7%j};EwBS$(9Xc3 zugDm^S_!1PFaDxQBC~61!1HXOu(;I9S)P$mOkJIaSv&vb1E%CaEvg~u>TU$PJ2WbJ z;bg%L?s6;%sxqDQ^N$N_CBQ=y$x5i`qf17efjb+MLH62VC2w(G1nJ4g8OP_T-)FCvpK0!;0$R3atfiSKInhJW>?c1L4GigStKEX#py?w z3EQ8S%J?KQ54C9-QZ}9+ru+d`bU9^XsnK#n_f_L8msnT8C)-A=$*KX`RY~RHFzJj} z)vY0|(uh0UvT)_90Lg`9kGL=$g#}wLS8B9no91|Dm9W}4z|bIVOe!$*A}FuZ+bl3iO(Z4 zH+j0GKb>D}!Aid;>`aEhck0z8K-76bK&8WPj!!qY=4JBTVd zxu8?YW@7igM%t@QPHCUU)|Zg5W(oa?;leTPd>eyY@i&fkp+bm1q+4P&R@&<{D3QD$ zp2LjyyNvaGzMCY?yh#YdcW@nChc~P$mkzc_)r(R=?N4rA zit{0De1m-w!e&{~Nm*)X4jAB&yRVN3cJ7S$-dzG*?IZ*-=PHJYPQM$#hpV$*jOE)d zg99xSvCL1=$SEzQE<{Ba<{GG14P$;n|Mmvk$12EyPk#pG#WOI$Tp$;V2DZ_1E+UJ+ zggL3EmM$xTe<{9Xw<^7sgM@Wu!FrdQ`-~zw13h+Rw@SpkvS+!10@j&&&)cSv;Wmge zGHI}P8lF+|H`CctcE?(Bxdyj31l+k)i;uHonPe1eIvOk0=H4B3TB9|znjax$vX!xSMi@b_C_J~>WmEWUV6y%-V`pG{#)xe=lmcPcUy~>u5LKm z`0GU!bvy|jNHMYJO?K>?uAxulI5AzzPhzk5O==WuwYRp76(YPv~iCu zjVLUI>7d=%^ql7^ZDTaTK-*wo@#d}_2}D(TA*w2pnX`h$_OwiUJZF@GU z%*u1sPNHdxS9k?&_RxXK-!O=DmffOOF|?6yP2ba_OMlE)OhSUuHa8yykxPK&LfklT z@g+&R=_hV07~{EzahwIeSK^x7zN6?ur1!olgz6*&kX|y#h{{- zL3klV!X+3NyDFYZJQgnBmQ+-L5&gCFatLUtYxcuv+5O{$Pd&h9UQj)H&Adqr3{Iu- z#s?rt+cpZjs%WHiTYEwVUm2%iNxJ2f27r|B$Hy_pvu#RHq=6EYef9px)-zrx$^$x#(auVSGjhrUzcAC4bWD9}#R zP524BC4d5j_T$=t;;mP8iA8Gq8e`6O4ZaXLP?cnFMQXAHTn6sEY$V~%TdfH7DpeEm<2N@|@f(b$&Cp%iLu$%A}KGw9GD~eJ)_-Zse z!qyc@IRFl|sKg~o|HAmGlckX&G3V<@8&}NKcOi4HWc-~ z>E2nB#knaP-=d~0;wxBt=t2>gPqq3WM;eQT-Po%7OVM(j9Q*G(%+z9@yi~93`bwKc z6CeZoaNn671Bt zUO0D=u1}u_OUc(Nwu~Bj{CMIy$G>JCpCPV=Tg>J!Wt5*2m6VBB`g)0(6IV~dv$)Ha zCgwAbTI(>X7O3Yj)(E)BvZ^NaSu4{b)XfEXRfxl`@RLd-D8l<^lkj>)eNj9N+ex7K zzIflmVHJK{Z%{1x9hppW+S?sz{KRcIv(qdw{GB4!+i0d_fh=gGIxAeU%U$|mECr~t z$vz)@QOxS=^v#007JIn#S(Eyf1&dH=HNe{1rxv7IEgAP(TB-*Rl0KoiE57R zyutJbBhN~jTv_@QYr_Twu9*lmG#iT0gjED=_ z=g=eL{pN_b^qekuROR(uC5yBn^d4R!8=3?qa8A)UZl2bZd9v51CzUMJ7J;27m=EFo zySLpQi3UcHg+{>r@Bqc3mx~8-4#MO?%Yd@(+1rODaBAHsnF2*b zAoUfP(>!B!*@BStadXG7YZP%pLFo*_Y}h^Lf$;J5eefkCinlkUN}p@>k8*nysjH8z zPgn3Sb(Wj*FNt0qcP`%XjWOTP`9t6Bv!K`A|L-0D_Y+T)IA%K~F2e4?Vmv}Mgtj?| zgx!dEq@7+|mxGlMV_|2c&h^xsj=jT6(qWo&mdk*UOGTuV+m3*OGh5u)b9fclmmkGMsN!zmT!^fS*ro`a?QBb>S*Lx&RB>`r508eC3%T1E@oY)t%+l!XH7yC1C&n+W!UnFa8gUpm=3j z4FF5~191O!U=Luz(=b5PBY>6}A#VdXF(2!xvHyUUtiZdQLzW^y)I_tROP^GdG=nr) z|I;^8KmE!zI22QD?8WuX4GLmdHG5klqd>Op#So63E|f+r81e50Wp8gIhk{^u#(;bc z0-+7Ttde|PQy+&0aafWJV^i;gbYhD-`!&%3f1d!n8%A>BZTxxGgL-_|Oh&>RATF-P z&aQ5bzo00up>E2whl8_?xs~m&1|v@-mHLcuU2G0C%l%M$;&;PTO!a+H)5y9}-;i(2QZ6$( zyjpBe)!FHi4r3}lF{=b%j2}WqthNI0*0pYfRS_mb==kASfeM7p&jgXyZZ`(p2KVLT z3sR<8Xx0}WXT4%y#*FA1UD-VL;cwZgP3t0K(c0XY*#Jw3lpFMiG~0^^mAel`f-{$= zek4{N!n8@3-fMq1gDJr*6cH>l+?P(j)jN#?M^f$$zc4Eq|3G%vi%>X_3IwzFq$5l_ z?16Z#_`I@JM#Q<6Jz_zqmI}F+ z=D@|lub&GXyKS9JXrG&V4aQ`kk;Z5#9+C?A&iZi@_@>tv2->Ld-abltl>hNdJJQoY zSM#+6*$O)O;;_U!?YBm=&-J}*)V{QOG3k)Z4-q};HdqS}a8Pqe+EX{oOh7Ud*S$^O zT*&I)>0R{9(zIJ}3DQgBYsVA2hpXRk$ABMoR7=7pH+eqS_{WGLLMgbv&Z&!$KrQnd z97quc78mgMZaK7wpzXrmzG%OC=U2F!-1E!$3*7JC^Dkcd6~Rqz`W1oBZx8Jx@f5-aUc7L7zy5V?15BP(=0sbH9f3qL2Ghg@PE_g3HeuVJv zng6Eqf7Oc%kL;W@z+c4lDib%!=>^SYXLtV>&9CBmHU7U&)P=5Hwu_$C z Date: Wed, 8 Sep 2021 18:46:56 +0200 Subject: [PATCH 060/150] #1784 - init commit of pype command Pype command is better than run_tests.ps1 as OP is initialized by start.py. This is more similar to standard running of OP --- openpype/cli.py | 15 +++++++++++++++ openpype/pype_commands.py | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/openpype/cli.py b/openpype/cli.py index 18cc1c63cd..c69407e295 100644 --- a/openpype/cli.py +++ b/openpype/cli.py @@ -283,3 +283,18 @@ def run(script): args_string = " ".join(args[1:]) print(f"... running: {script} {args_string}") runpy.run_path(script, run_name="__main__", ) + + +@main.command() +@click.argument("folder", nargs=-1) +@click.option("-m", + "--mark", + help="Run tests marked by", + default=None) +@click.option("-p", + "--pyargs", + help="Run tests from package", + default=None) +def runtests(folder, mark, pyargs): + """Run all automatic tests after proper initialization via start.py""" + PypeCommands().run_tests(folder, mark, pyargs) diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index c18fe36667..c309ee8c09 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -257,3 +257,24 @@ class PypeCommands: def validate_jsons(self): pass + def run_tests(self, folder, mark, pyargs): + """ + Runs tests from 'folder' + + Args: + folder (str): relative path to folder with tests + mark (str): label to run tests marked by it (slow etc) + pyargs (str): package path to test + """ + print("run_tests") + import subprocess + folder = folder or "../tests" + mark_str = pyargs_str = '' + if mark: + mark_str = "- m {}".format(mark) + + if pyargs: + pyargs_str = "--pyargs {}".format(pyargs) + + subprocess.run("pytest {} {} {}".format(folder, mark_str, pyargs_str)) + From 46697d8d816c3a603a4ec8f0ed8cd8f1c2ef17e8 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 8 Sep 2021 18:53:37 +0200 Subject: [PATCH 061/150] fix docker build, switch to cx_freeze 6.7 --- poetry.lock | 684 +++++++++++++++++++++++++----------------- pyproject.toml | 2 +- tools/docker_build.sh | 7 +- 3 files changed, 416 insertions(+), 277 deletions(-) diff --git a/poetry.lock b/poetry.lock index e011b781c9..6dae442c9d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -80,7 +80,7 @@ python-dateutil = ">=2.7.0" [[package]] name = "astroid" -version = "2.5.6" +version = "2.7.3" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false @@ -89,6 +89,7 @@ python-versions = "~=3.6" [package.dependencies] lazy-object-proxy = ">=1.4.0" typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} +typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} wrapt = ">=1.11,<1.13" [[package]] @@ -146,11 +147,11 @@ pytz = ">=2015.7" [[package]] name = "blessed" -version = "1.18.0" +version = "1.18.1" description = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities." category = "main" optional = false -python-versions = "*" +python-versions = ">=2.7" [package.dependencies] jinxed = {version = ">=0.5.4", markers = "platform_system == \"Windows\""} @@ -175,7 +176,7 @@ python-versions = "*" [[package]] name = "cffi" -version = "1.14.5" +version = "1.14.6" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -192,6 +193,17 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "charset-normalizer" +version = "2.0.4" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + [[package]] name = "click" version = "7.1.2" @@ -253,7 +265,7 @@ toml = ["toml"] [[package]] name = "cryptography" -version = "3.4.7" +version = "3.4.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -272,15 +284,20 @@ test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pret [[package]] name = "cx-freeze" -version = "6.6" +version = "6.7" description = "Create standalone executables from Python scripts" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -cx-Logging = {version = ">=3.0", markers = "sys_platform == \"win32\""} -importlib-metadata = ">=3.1.1" +cx-logging = {version = ">=3.0", markers = "sys_platform == \"win32\""} +importlib-metadata = ">=4.3.1" + +[package.source] +type = "legacy" +url = "https://distribute.openpype.io/wheels" +reference = "openpype" [[package]] name = "cx-logging" @@ -386,19 +403,19 @@ smmap = ">=3.0.1,<5" [[package]] name = "gitpython" -version = "3.1.17" +version = "3.1.20" description = "Python Git Library" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] gitdb = ">=4.0.1,<5" -typing-extensions = {version = ">=3.7.4.0", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\""} [[package]] name = "google-api-core" -version = "1.30.0" +version = "1.31.2" description = "Google API client core library" category = "main" optional = false @@ -436,7 +453,7 @@ uritemplate = ">=3.0.0,<4dev" [[package]] name = "google-auth" -version = "1.31.0" +version = "1.35.0" description = "Google Authentication Library" category = "main" optional = false @@ -493,11 +510,11 @@ pyparsing = ">=2.4.2,<3" [[package]] name = "idna" -version = "2.10" +version = "3.2" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.5" [[package]] name = "imagesize" @@ -509,7 +526,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.5.0" +version = "4.8.1" description = "Read metadata from Python packages" category = "main" optional = false @@ -521,7 +538,8 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -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)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -533,16 +551,17 @@ python-versions = "*" [[package]] name = "isort" -version = "5.8.0" +version = "5.9.3" description = "A Python utility / library to sort Python imports." category = "dev" optional = false -python-versions = ">=3.6,<4.0" +python-versions = ">=3.6.1,<4.0" [package.extras] pipfile_deprecated_finder = ["pipreqs", "requirementslib"] requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] +plugins = ["setuptools"] [[package]] name = "jedi" @@ -560,14 +579,15 @@ testing = ["colorama", "docopt", "pytest (>=3.1.0)"] [[package]] name = "jeepney" -version = "0.6.0" +version = "0.7.1" description = "Low-level, pure Python DBus protocol wrapper." category = "main" optional = false python-versions = ">=3.6" [package.extras] -test = ["pytest", "pytest-trio", "pytest-asyncio", "testpath", "trio"] +test = ["pytest", "pytest-trio", "pytest-asyncio", "testpath", "trio", "async-timeout"] +trio = ["trio", "async-generator"] [[package]] name = "jinja2" @@ -695,11 +715,11 @@ reference = "openpype" [[package]] name = "packaging" -version = "20.9" +version = "21.0" description = "Core utilities for Python packages" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2" @@ -718,7 +738,7 @@ testing = ["docopt", "pytest (<6.0.0)"] [[package]] name = "pathlib2" -version = "2.3.5" +version = "2.3.6" description = "Object-oriented filesystem paths" category = "main" optional = false @@ -729,25 +749,38 @@ six = "*" [[package]] name = "pillow" -version = "8.2.0" +version = "8.3.2" description = "Python Imaging Library (Fork)" category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "platformdirs" +version = "2.3.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + [[package]] name = "pluggy" -version = "0.13.1" +version = "1.0.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.dependencies] importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] [[package]] name = "prefixed" @@ -849,7 +882,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.9.0" +version = "2.10.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false @@ -857,22 +890,23 @@ python-versions = ">=3.5" [[package]] name = "pylint" -version = "2.8.3" +version = "2.10.2" description = "python code static checker" category = "dev" optional = false python-versions = "~=3.6" [package.dependencies] -astroid = "2.5.6" +astroid = ">=2.7.2,<2.8" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" +platformdirs = ">=2.2.0" toml = ">=0.7.1" [[package]] name = "pymongo" -version = "3.11.4" +version = "3.12.0" description = "Python driver for MongoDB " category = "main" optional = false @@ -880,9 +914,9 @@ python-versions = "*" [package.extras] aws = ["pymongo-auth-aws (<2.0.0)"] -encryption = ["pymongocrypt (<2.0.0)"] +encryption = ["pymongocrypt (>=1.1.0,<2.0.0)"] gssapi = ["pykerberos"] -ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] +ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)", "certifi"] snappy = ["python-snappy"] srv = ["dnspython (>=1.16.0,<1.17.0)"] tls = ["ipaddress"] @@ -971,15 +1005,15 @@ python-versions = ">=3.5" [[package]] name = "pyrsistent" -version = "0.17.3" +version = "0.18.0" description = "Persistent/Functional/Immutable data structures" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [[package]] name = "pytest" -version = "6.2.4" +version = "6.2.5" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -992,7 +1026,7 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<1.0.0a1" +pluggy = ">=0.12,<2.0" py = ">=1.8.2" toml = "*" @@ -1017,21 +1051,21 @@ testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtuale [[package]] name = "pytest-print" -version = "0.2.1" +version = "0.3.0" description = "pytest-print adds the printer fixture you can use to print messages to the user (directly to the pytest runner, not stdout)" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6" [package.dependencies] -pytest = ">=3.0.0" +pytest = ">=6" [package.extras] -test = ["coverage (>=5)", "pytest (>=4)"] +test = ["coverage (>=5)"] [[package]] name = "python-dateutil" -version = "2.8.1" +version = "2.8.2" description = "Extensions to the standard Python datetime module" category = "main" optional = false @@ -1042,7 +1076,7 @@ six = ">=1.5" [[package]] name = "python-xlib" -version = "0.30" +version = "0.31" description = "Python X Library" category = "main" optional = false @@ -1085,7 +1119,7 @@ python-versions = "*" [[package]] name = "qt.py" -version = "1.3.3" +version = "1.3.6" description = "Python 2 & 3 compatibility wrapper around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5." category = "main" optional = false @@ -1106,21 +1140,21 @@ sphinx = ">=1.3.1" [[package]] name = "requests" -version = "2.25.1" +version = "2.26.0" description = "Python HTTP for Humans." category = "main" 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.dependencies] certifi = ">=2017.4.17" -chardet = ">=3.0.2,<5" -idna = ">=2.5,<3" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} urllib3 = ">=1.21.1,<1.27" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "rsa" @@ -1163,15 +1197,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "slack-sdk" -version = "3.6.0" +version = "3.10.1" description = "The Slack API Platform SDK for Python" category = "main" optional = false python-versions = ">=3.6.0" [package.extras] -optional = ["aiodns (>1.0)", "aiohttp (>=3.7.3,<4)", "boto3 (<=2)", "SQLAlchemy (>=1,<2)", "websockets (>=9.1,<10)", "websocket-client (>=0.57,<1)"] -testing = ["pytest (>=5.4,<6)", "pytest-asyncio (<1)", "Flask-Sockets (>=0.2,<1)", "pytest-cov (>=2,<3)", "codecov (>=2,<3)", "flake8 (>=3,<4)", "black (==21.5b1)", "psutil (>=5,<6)", "databases (>=0.3)"] +optional = ["aiodns (>1.0)", "aiohttp (>=3.7.3,<4)", "boto3 (<=2)", "SQLAlchemy (>=1,<2)", "websockets (>=9.1,<10)", "websocket-client (>=1,<2)"] +testing = ["pytest (>=5.4,<6)", "pytest-asyncio (<1)", "Flask-Sockets (>=0.2,<1)", "Flask (>=1,<2)", "Werkzeug (<2)", "pytest-cov (>=2,<3)", "codecov (>=2,<3)", "flake8 (>=3,<4)", "black (==21.7b0)", "psutil (>=5,<6)", "databases (>=0.3)", "boto3 (<=2)", "moto (<2)"] [[package]] name = "smmap" @@ -1199,7 +1233,7 @@ python-versions = "*" [[package]] name = "sphinx" -version = "4.0.2" +version = "4.1.2" description = "Python documentation generator" category = "dev" optional = false @@ -1218,14 +1252,14 @@ requests = ">=2.5.0" snowballstemmer = ">=1.1" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.800)", "docutils-stubs"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.900)", "docutils-stubs", "types-typed-ast", "types-pkg-resources", "types-requests"] test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] @@ -1367,7 +1401,7 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.10.0.0" +version = "3.10.0.2" description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false @@ -1383,7 +1417,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "urllib3" -version = "1.26.5" +version = "1.26.6" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -1453,7 +1487,7 @@ typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [[package]] name = "zipp" -version = "3.4.1" +version = "3.5.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false @@ -1461,12 +1495,12 @@ python-versions = ">=3.6" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "8875d530ae66f9763b5b0cb84d9d35edc184ef5c141b63d38bf1ff5a1226e556" +content-hash = "ca2a0258a784674ff489a07d0dc8dd2a22373ee39add02cb4676898b8a6993a1" [metadata.files] acre = [] @@ -1530,8 +1564,8 @@ arrow = [ {file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"}, ] astroid = [ - {file = "astroid-2.5.6-py3-none-any.whl", hash = "sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e"}, - {file = "astroid-2.5.6.tar.gz", hash = "sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"}, + {file = "astroid-2.7.3-py3-none-any.whl", hash = "sha256:dc1e8b28427d6bbef6b8842b18765ab58f558c42bb80540bd7648c98412af25e"}, + {file = "astroid-2.7.3.tar.gz", hash = "sha256:3b680ce0419b8a771aba6190139a3998d14b413852506d99aff8dc2bf65ee67c"}, ] async-timeout = [ {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, @@ -1554,8 +1588,8 @@ babel = [ {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, ] blessed = [ - {file = "blessed-1.18.0-py2.py3-none-any.whl", hash = "sha256:5b5e2f0563d5a668c282f3f5946f7b1abb70c85829461900e607e74d7725106e"}, - {file = "blessed-1.18.0.tar.gz", hash = "sha256:1312879f971330a1b7f2c6341f2ae7e2cbac244bfc9d0ecfbbecd4b0293bc755"}, + {file = "blessed-1.18.1-py2.py3-none-any.whl", hash = "sha256:dd7c0d33db9a2e7f597b446996484d0ed46e1586239db064fb5025008937dcae"}, + {file = "blessed-1.18.1.tar.gz", hash = "sha256:8b09936def6bc06583db99b65636b980075733e13550cb6af262ce724a55da23"}, ] cachetools = [ {file = "cachetools-4.2.2-py3-none-any.whl", hash = "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001"}, @@ -1566,48 +1600,60 @@ certifi = [ {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, ] cffi = [ - {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"}, - {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"}, - {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"}, - {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"}, - {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"}, - {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"}, - {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"}, - {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"}, - {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"}, - {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"}, - {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"}, - {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"}, - {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, - {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, - {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, - {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, - {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, - {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, - {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, - {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, - {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, - {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, - {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, - {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, - {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, + {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, + {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, + {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, + {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, + {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, + {file = "cffi-1.14.6-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a"}, + {file = "cffi-1.14.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5"}, + {file = "cffi-1.14.6-cp35-cp35m-win32.whl", hash = "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca"}, + {file = "cffi-1.14.6-cp35-cp35m-win_amd64.whl", hash = "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218"}, + {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, + {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, + {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, + {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, + {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, + {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, + {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, + {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, + {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, + {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, + {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, + {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, + {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, + {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, + {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, + {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, + {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, ] chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] +charset-normalizer = [ + {file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"}, + {file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"}, +] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, @@ -1683,30 +1729,25 @@ coverage = [ {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] cryptography = [ - {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.6-cp36-cp36m-win32.whl", hash = "sha256:b3d3a6bcd1a07c50b4e1c907f14842642156110e63a99cd5c73b8a24751e9b97"}, - {file = "cx_Freeze-6.6-cp36-cp36m-win_amd64.whl", hash = "sha256:1935266ec644ea4f7e584985f44cefc0622a449a09980d990833a1a2afcadac8"}, - {file = "cx_Freeze-6.6-cp37-cp37m-win32.whl", hash = "sha256:1eac2b0f254319cc641ce25bd83337effd7936092562fde701f3ffb40e0274ec"}, - {file = "cx_Freeze-6.6-cp37-cp37m-win_amd64.whl", hash = "sha256:2bc46ef6d510811b6002f34a3ae4cbfdea44e18644febd2a404d3ee8e48a9fc4"}, - {file = "cx_Freeze-6.6-cp38-cp38-win32.whl", hash = "sha256:46eb50ebc46f7ae236d16c6a52671ab0f7bb479bea668da19f4b6de3cc413e9e"}, - {file = "cx_Freeze-6.6-cp38-cp38-win_amd64.whl", hash = "sha256:8c3b00476ce385bb58595bffce55aed031e5a6e16ab6e14d8bee9d1d569e46c3"}, - {file = "cx_Freeze-6.6-cp39-cp39-win32.whl", hash = "sha256:6e9340cbcf52d4836980ecc83ddba4f7704ff6654dd41168c146b74f512977ce"}, - {file = "cx_Freeze-6.6-cp39-cp39-win_amd64.whl", hash = "sha256:2fcf1c8b77ae5c06f45be3a9aff79e1dd808c0d624e97561f840dec5ea9b214a"}, - {file = "cx_Freeze-6.6.tar.gz", hash = "sha256:c4af8ad3f7e7d71e291c1dec5d0fb26bbe92df834b098ed35434c901fbd6762f"}, + {file = "cryptography-3.4.8-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14"}, + {file = "cryptography-3.4.8-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb"}, + {file = "cryptography-3.4.8-cp36-abi3-win32.whl", hash = "sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7"}, + {file = "cryptography-3.4.8-cp36-abi3-win_amd64.whl", hash = "sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e"}, + {file = "cryptography-3.4.8.tar.gz", hash = "sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c"}, ] +cx-freeze = [] cx-logging = [ {file = "cx_Logging-3.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:9fcd297e5c51470521c47eff0f86ba844aeca6be97e13c3e2114ebdf03fa3c96"}, {file = "cx_Logging-3.0-cp36-cp36m-win32.whl", hash = "sha256:0df4be47c5022cc54316949e283403214568ef599817ced0c0972183d6d4fabb"}, @@ -1753,20 +1794,20 @@ gitdb = [ {file = "gitdb-4.0.7.tar.gz", hash = "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"}, ] gitpython = [ - {file = "GitPython-3.1.17-py3-none-any.whl", hash = "sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135"}, - {file = "GitPython-3.1.17.tar.gz", hash = "sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"}, + {file = "GitPython-3.1.20-py3-none-any.whl", hash = "sha256:b1e1c269deab1b08ce65403cf14e10d2ef1f6c89e33ea7c5e5bb0222ea593b8a"}, + {file = "GitPython-3.1.20.tar.gz", hash = "sha256:df0e072a200703a65387b0cfdf0466e3bab729c0458cf6b7349d0e9877636519"}, ] google-api-core = [ - {file = "google-api-core-1.30.0.tar.gz", hash = "sha256:0724d354d394b3d763bc10dfee05807813c5210f0bd9b8e2ddf6b6925603411c"}, - {file = "google_api_core-1.30.0-py2.py3-none-any.whl", hash = "sha256:92cd9e9f366e84bfcf2524e34d2dc244906c645e731962617ba620da1620a1e0"}, + {file = "google-api-core-1.31.2.tar.gz", hash = "sha256:8500aded318fdb235130bf183c726a05a9cb7c4b09c266bd5119b86cdb8a4d10"}, + {file = "google_api_core-1.31.2-py2.py3-none-any.whl", hash = "sha256:384459a0dc98c1c8cd90b28dc5800b8705e0275a673a7144a513ae80fc77950b"}, ] 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.31.0.tar.gz", hash = "sha256:154f7889c5d679a6f626f36adb12afbd4dbb0a9a04ec575d989d6ba79c4fd65e"}, - {file = "google_auth-1.31.0-py2.py3-none-any.whl", hash = "sha256:6d47c79b5d09fbc7e8355fd9594cc4cf65fdde5d401c63951eaac4baa1ba2ae1"}, + {file = "google-auth-1.35.0.tar.gz", hash = "sha256:b7033be9028c188ee30200b204ea00ed82ea1162e8ac1df4aa6ded19a191d88e"}, + {file = "google_auth-1.35.0-py2.py3-none-any.whl", hash = "sha256:997516b42ecb5b63e8d80f5632c1a61dddf41d2a4c2748057837e06e00014258"}, ] google-auth-httplib2 = [ {file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"}, @@ -1781,32 +1822,32 @@ httplib2 = [ {file = "httplib2-0.19.1.tar.gz", hash = "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d"}, ] idna = [ - {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, - {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, + {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, + {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, ] imagesize = [ {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, - {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, + {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, + {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, ] 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.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"}, - {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"}, + {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, + {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, ] jedi = [ {file = "jedi-0.13.3-py2.py3-none-any.whl", hash = "sha256:2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c"}, {file = "jedi-0.13.3.tar.gz", hash = "sha256:2bb0603e3506f708e792c7f4ad8fc2a7a9d9c2d292a358fbbd58da531695595b"}, ] jeepney = [ - {file = "jeepney-0.6.0-py3-none-any.whl", hash = "sha256:aec56c0eb1691a841795111e184e13cad504f7703b9a64f63020816afa79a8ae"}, - {file = "jeepney-0.6.0.tar.gz", hash = "sha256:7d59b6622675ca9e993a6bd38de845051d315f8b0c72cca3aef733a20b648657"}, + {file = "jeepney-0.7.1-py3-none-any.whl", hash = "sha256:1b5a0ea5c0e7b166b2f5895b91a08c14de8915afda4407fb5022a195224958ac"}, + {file = "jeepney-0.7.1.tar.gz", hash = "sha256:fa9e232dfa0c498bd0b8a3a73b8d8a31978304dcef0515adc859d4e096f96f4f"}, ] jinja2 = [ {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, @@ -1852,12 +1893,22 @@ log4mongo = [ {file = "log4mongo-1.7.0.tar.gz", hash = "sha256:dc374617206162a0b14167fbb5feac01dbef587539a235dadba6200362984a68"}, ] markupsafe = [ + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, @@ -1866,14 +1917,21 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, @@ -1883,6 +1941,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, @@ -1932,56 +1993,79 @@ multidict = [ ] opentimelineio = [] packaging = [ - {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, - {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, ] parso = [ {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"}, + {file = "pathlib2-2.3.6-py2.py3-none-any.whl", hash = "sha256:3a130b266b3a36134dcc79c17b3c7ac9634f083825ca6ea9d8f557ee6195c9c8"}, + {file = "pathlib2-2.3.6.tar.gz", hash = "sha256:7d8bcb5555003cdf4a8d2872c538faa3a0f5d20630cb360e518ca3b981795e5f"}, ] pillow = [ - {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-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8b56553c0345ad6dcb2e9b433ae47d67f95fc23fe28a0bde15a120f25257e291"}, - {file = "Pillow-8.2.0.tar.gz", hash = "sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a"}, + {file = "Pillow-8.3.2-cp310-cp310-win32.whl", hash = "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228"}, + {file = "Pillow-8.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875"}, + {file = "Pillow-8.3.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15ccb81a6ffc57ea0137f9f3ac2737ffa1d11f786244d719639df17476d399a7"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8f284dc1695caf71a74f24993b7c7473d77bc760be45f776a2c2f4e04c170550"}, + {file = "Pillow-8.3.2-cp36-cp36m-win32.whl", hash = "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073"}, + {file = "Pillow-8.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196"}, + {file = "Pillow-8.3.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1bd983c565f92779be456ece2479840ec39d386007cd4ae83382646293d681b"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4326ea1e2722f3dc00ed77c36d3b5354b8fb7399fb59230249ea6d59cbed90da"}, + {file = "Pillow-8.3.2-cp37-cp37m-win32.whl", hash = "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9"}, + {file = "Pillow-8.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bcb04ff12e79b28be6c9988f275e7ab69f01cc2ba319fb3114f87817bb7c74b6"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b9911ec70731711c3b6ebcde26caea620cbdd9dcb73c67b0730c8817f24711b"}, + {file = "Pillow-8.3.2-cp38-cp38-win32.whl", hash = "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341"}, + {file = "Pillow-8.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bff50ba9891be0a004ef48828e012babaaf7da204d81ab9be37480b9020a82b"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7dbfbc0020aa1d9bc1b0b8bcf255a7d73f4ad0336f8fd2533fcc54a4ccfb9441"}, + {file = "Pillow-8.3.2-cp39-cp39-win32.whl", hash = "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09"}, + {file = "Pillow-8.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:548794f99ff52a73a156771a0402f5e1c35285bd981046a502d7e4793e8facaa"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b68f565a4175e12e68ca900af8910e8fe48aaa48fd3ca853494f384e11c8bcd"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd4fd83aa912d7b89b4b4a1580d30e2a4242f3936882a3f433586e5ab97ed0d5"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0c8ebbfd439c37624db98f3877d9ed12c137cadd99dde2d2eae0dab0bbfc355"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96"}, + {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, +] +platformdirs = [ + {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, + {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, ] pluggy = [ - {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, - {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] prefixed = [ {file = "prefixed-0.3.2-py2.py3-none-any.whl", hash = "sha256:5e107306462d63f2f03c529dbf11b0026fdfec621a9a008ca639d71de22995c3"}, @@ -2006,9 +2090,13 @@ protobuf = [ {file = "protobuf-3.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ae692bb6d1992afb6b74348e7bb648a75bb0d3565a3f5eea5bec8f62bd06d87"}, {file = "protobuf-3.17.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:99938f2a2d7ca6563c0ade0c5ca8982264c484fdecf418bd68e880a7ab5730b1"}, {file = "protobuf-3.17.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6902a1e4b7a319ec611a7345ff81b6b004b36b0d2196ce7a748b3493da3d226d"}, + {file = "protobuf-3.17.3-cp38-cp38-win32.whl", hash = "sha256:59e5cf6b737c3a376932fbfb869043415f7c16a0cf176ab30a5bbc419cd709c1"}, + {file = "protobuf-3.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ebcb546f10069b56dc2e3da35e003a02076aaa377caf8530fe9789570984a8d2"}, {file = "protobuf-3.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ffbd23640bb7403574f7aff8368e2aeb2ec9a5c6306580be48ac59a6bac8bde"}, {file = "protobuf-3.17.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:26010f693b675ff5a1d0e1bdb17689b8b716a18709113288fead438703d45539"}, {file = "protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76d9686e088fece2450dbc7ee905f9be904e427341d289acbe9ad00b78ebd47"}, + {file = "protobuf-3.17.3-cp39-cp39-win32.whl", hash = "sha256:a38bac25f51c93e4be4092c88b2568b9f407c27217d3dd23c7a57fa522a17554"}, + {file = "protobuf-3.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:85d6303e4adade2827e43c2b54114d9a6ea547b671cb63fafd5011dc47d0e13d"}, {file = "protobuf-3.17.3-py2.py3-none-any.whl", hash = "sha256:2bfb815216a9cd9faec52b16fd2bfa68437a44b67c56bee59bc3926522ecb04e"}, {file = "protobuf-3.17.3.tar.gz", hash = "sha256:72804ea5eaa9c22a090d2803813e280fb273b62d5ae497aaf3553d141c4fdd7b"}, ] @@ -2071,78 +2159,112 @@ pyflakes = [ {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pygments = [ - {file = "Pygments-2.9.0-py3-none-any.whl", hash = "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"}, - {file = "Pygments-2.9.0.tar.gz", hash = "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f"}, + {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, + {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, ] pylint = [ - {file = "pylint-2.8.3-py3-none-any.whl", hash = "sha256:792b38ff30903884e4a9eab814ee3523731abd3c463f3ba48d7b627e87013484"}, - {file = "pylint-2.8.3.tar.gz", hash = "sha256:0a049c5d47b629d9070c3932d13bff482b12119b6a241a93bc460b0be16953c8"}, + {file = "pylint-2.10.2-py3-none-any.whl", hash = "sha256:e178e96b6ba171f8ef51fbce9ca30931e6acbea4a155074d80cc081596c9e852"}, + {file = "pylint-2.10.2.tar.gz", hash = "sha256:6758cce3ddbab60c52b57dcc07f0c5d779e5daf0cf50f6faacbef1d3ea62d2a1"}, ] pymongo = [ - {file = "pymongo-3.11.4-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:b7efc7e7049ef366777cfd35437c18a4166bb50a5606a1c840ee3b9624b54fc9"}, - {file = "pymongo-3.11.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:517ba47ca04a55b1f50ee8df9fd97f6c37df5537d118fb2718952b8623860466"}, - {file = "pymongo-3.11.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:225c61e08fe517aede7912937939e09adf086c8e6f7e40d4c85ad678c2c2aea3"}, - {file = "pymongo-3.11.4-cp27-cp27m-win32.whl", hash = "sha256:e4e9db78b71db2b1684ee4ecc3e32c4600f18cdf76e6b9ae03e338e52ee4b168"}, - {file = "pymongo-3.11.4-cp27-cp27m-win_amd64.whl", hash = "sha256:8e0004b0393d72d76de94b4792a006cb960c1c65c7659930fbf9a81ce4341982"}, - {file = "pymongo-3.11.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:fedf0dee7a412ca6d1d6d92c158fe9cbaa8ea0cae90d268f9ccc0744de7a97d0"}, - {file = "pymongo-3.11.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f947b359cc4769af8b49be7e37af01f05fcf15b401da2528021148e4a54426d1"}, - {file = "pymongo-3.11.4-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:3a3498a8326111221560e930f198b495ea6926937e249f475052ffc6893a6680"}, - {file = "pymongo-3.11.4-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:9a4f6e0b01df820ba9ed0b4e618ca83a1c089e48d4f268d0e00dcd49893d4549"}, - {file = "pymongo-3.11.4-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d65bac5f6724d9ea6f0b5a0f0e4952fbbf209adcf6b5583b54c54bd2fcd74dc0"}, - {file = "pymongo-3.11.4-cp34-cp34m-win32.whl", hash = "sha256:15b083d1b789b230e5ac284442d9ecb113c93f3785a6824f748befaab803b812"}, - {file = "pymongo-3.11.4-cp34-cp34m-win_amd64.whl", hash = "sha256:f08665d3cc5abc2f770f472a9b5f720a9b3ab0b8b3bb97c7c1487515e5653d39"}, - {file = "pymongo-3.11.4-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:977b1d4f868986b4ba5d03c317fde4d3b66e687d74473130cd598e3103db34fa"}, - {file = "pymongo-3.11.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:510cd3bfabb63a07405b7b79fae63127e34c118b7531a2cbbafc7a24fd878594"}, - {file = "pymongo-3.11.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:071552b065e809d24c5653fcc14968cfd6fde4e279408640d5ac58e3353a3c5f"}, - {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:f4ba58157e8ae33ee86fadf9062c506e535afd904f07f9be32731f4410a23b7f"}, - {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:b413117210fa6d92664c3d860571e8e8727c3e8f2ff197276c5d0cb365abd3ad"}, - {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:08b8723248730599c9803ae4c97b8f3f76c55219104303c88cb962a31e3bb5ee"}, - {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:8a41fdc751dc4707a4fafb111c442411816a7c225ebb5cadb57599534b5d5372"}, - {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:f664ed7613b8b18f0ce5696b146776266a038c19c5cd6efffa08ecc189b01b73"}, - {file = "pymongo-3.11.4-cp35-cp35m-win32.whl", hash = "sha256:5c36428cc4f7fae56354db7f46677fd21222fc3cb1e8829549b851172033e043"}, - {file = "pymongo-3.11.4-cp35-cp35m-win_amd64.whl", hash = "sha256:d0a70151d7de8a3194cdc906bcc1a42e14594787c64b0c1c9c975e5a2af3e251"}, - {file = "pymongo-3.11.4-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:9b9298964389c180a063a9e8bac8a80ed42de11d04166b20249bfa0a489e0e0f"}, - {file = "pymongo-3.11.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b2f41261b648cf5dee425f37ff14f4ad151c2f24b827052b402637158fd056ef"}, - {file = "pymongo-3.11.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e02beaab433fd1104b2804f909e694cfbdb6578020740a9051597adc1cd4e19f"}, - {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:8898f6699f740ca93a0879ed07d8e6db02d68af889d0ebb3d13ab017e6b1af1e"}, - {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:62c29bc36a6d9be68fe7b5aaf1e120b4aa66a958d1e146601fcd583eb12cae7b"}, - {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:424799c71ff435094e5fb823c40eebb4500f0e048133311e9c026467e8ccebac"}, - {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:3551912f5c34d8dd7c32c6bb00ae04192af47f7b9f653608f107d19c1a21a194"}, - {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:5db59223ed1e634d842a053325f85f908359c6dac9c8ddce8ef145061fae7df8"}, - {file = "pymongo-3.11.4-cp36-cp36m-win32.whl", hash = "sha256:fea5cb1c63efe1399f0812532c7cf65458d38fd011be350bc5021dfcac39fba8"}, - {file = "pymongo-3.11.4-cp36-cp36m-win_amd64.whl", hash = "sha256:d4e62417e89b717a7bcd8576ac3108cd063225942cc91c5b37ff5465fdccd386"}, - {file = "pymongo-3.11.4-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:4c7e8c8e1e1918dcf6a652ac4b9d87164587c26fd2ce5dd81e73a5ab3b3d492f"}, - {file = "pymongo-3.11.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38a7b5140a48fc91681cdb5cb95b7cd64640b43d19259fdd707fa9d5a715f2b2"}, - {file = "pymongo-3.11.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:aff3656af2add93f290731a6b8930b23b35c0c09569150130a58192b3ec6fc61"}, - {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:03be7ad107d252bb7325d4af6309fdd2c025d08854d35f0e7abc8bf048f4245e"}, - {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:6060794aac9f7b0644b299f46a9c6cbc0bc470bd01572f4134df140afd41ded6"}, - {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:73326b211e7410c8bd6a74500b1e3f392f39cf10862e243d00937e924f112c01"}, - {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:20d75ea11527331a2980ab04762a9d960bcfea9475c54bbeab777af880de61cd"}, - {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:3135dd574ef1286189f3f04a36c8b7a256376914f8cbbce66b94f13125ded858"}, - {file = "pymongo-3.11.4-cp37-cp37m-win32.whl", hash = "sha256:7c97554ea521f898753d9773891d0347ebfaddcc1dee2ad94850b163171bf1f1"}, - {file = "pymongo-3.11.4-cp37-cp37m-win_amd64.whl", hash = "sha256:a08c8b322b671857c81f4c30cd3c8df2895fd3c0e9358714f39e0ef8fb327702"}, - {file = "pymongo-3.11.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f3d851af3852f16ad4adc7ee054fd9c90a7a5063de94d815b7f6a88477b9f4c6"}, - {file = "pymongo-3.11.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3bfc7689a1bacb9bcd2f2d5185d99507aa29f667a58dd8adaa43b5a348139e46"}, - {file = "pymongo-3.11.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b8f94acd52e530a38f25e4d5bf7ddfdd4bea9193e718f58419def0d4406b58d3"}, - {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e4b631688dfbdd61b5610e20b64b99d25771c6d52d9da73349342d2a0f11c46a"}, - {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:474e21d0e07cd09679e357d1dac76e570dab86665e79a9d3354b10a279ac6fb3"}, - {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:421d13523d11c57f57f257152bc4a6bb463aadf7a3918e9c96fefdd6be8dbfb8"}, - {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:0cabfc297f4cf921f15bc789a8fbfd7115eb9f813d3f47a74b609894bc66ab0d"}, - {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:fe4189846448df013cd9df11bba38ddf78043f8c290a9f06430732a7a8601cce"}, - {file = "pymongo-3.11.4-cp38-cp38-win32.whl", hash = "sha256:eb4d176394c37a76e8b0afe54b12d58614a67a60a7f8c0dd3a5afbb013c01092"}, - {file = "pymongo-3.11.4-cp38-cp38-win_amd64.whl", hash = "sha256:fffff7bfb6799a763d3742c59c6ee7ffadda21abed557637bc44ed1080876484"}, - {file = "pymongo-3.11.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:13acf6164ead81c9fc2afa0e1ea6d6134352973ce2bb35496834fee057063c04"}, - {file = "pymongo-3.11.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d360e5d5dd3d55bf5d1776964625018d85b937d1032bae1926dd52253decd0db"}, - {file = "pymongo-3.11.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:0aaf4d44f1f819360f9432df538d54bbf850f18152f34e20337c01b828479171"}, - {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:08bda7b2c522ff9f1e554570da16298271ebb0c56ab9699446aacba249008988"}, - {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:1a994a42f49dab5b6287e499be7d3d2751776486229980d8857ad53b8333d469"}, - {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:161fcd3281c42f644aa8dec7753cca2af03ce654e17d76da4f0dab34a12480ca"}, - {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:78f07961f4f214ea8e80be63cffd5cc158eb06cd922ffbf6c7155b11728f28f9"}, - {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:ad31f184dcd3271de26ab1f9c51574afb99e1b0e484ab1da3641256b723e4994"}, - {file = "pymongo-3.11.4-cp39-cp39-win32.whl", hash = "sha256:5e606846c049ed40940524057bfdf1105af6066688c0e6a1a3ce2038589bae70"}, - {file = "pymongo-3.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:3491c7de09e44eded16824cb58cf9b5cc1dc6f066a0bb7aa69929d02aa53b828"}, - {file = "pymongo-3.11.4-py2.7-macosx-10.14-intel.egg", hash = "sha256:506a6dab4c7ffdcacdf0b8e70bd20eb2e77fa994519547c9d88d676400fcad58"}, - {file = "pymongo-3.11.4.tar.gz", hash = "sha256:539d4cb1b16b57026999c53e5aab857fe706e70ae5310cc8c232479923f932e6"}, + {file = "pymongo-3.12.0-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:072ba7cb65c8aa4d5c5659bf6722ee85781c9d7816dc00679b8b6f3dff1ddafc"}, + {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:d6e11ffd43184d529d6752d6dcb62b994f903038a17ea2168ef1910c96324d26"}, + {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7412a36798966624dc4c57d64aa43c2d1100b348abd98daaac8e99e57d87e1d7"}, + {file = "pymongo-3.12.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8a82e35d52ad6f867e88096a1a2b9bdc7ec4d5e65c7b4976a248bf2d1a32a93"}, + {file = "pymongo-3.12.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dcd3d0009fbb6e454d729f8b22d0063bd9171c31a55e0f0271119bd4f2700023"}, + {file = "pymongo-3.12.0-cp27-cp27m-win32.whl", hash = "sha256:1bc6fe7279ff40c6818db002bf5284aa03ec181ea1b1ceaeee33c289d412afa7"}, + {file = "pymongo-3.12.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e2b7670c0c8c6b501464150dd49dd0d6be6cb7f049e064124911cec5514fa19e"}, + {file = "pymongo-3.12.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:316c1b8723afa9870567cd6dff35d440b2afeda53aa13da6c5ab85f98ed6f5ca"}, + {file = "pymongo-3.12.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:255a35bf29185f44b412e31a927d9dcedda7c2c380127ecc4fbf2f61b72fa978"}, + {file = "pymongo-3.12.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ffbae429ba9e42d0582d3ac63fdb410338892468a2107d8ff68228ec9a39a0ed"}, + {file = "pymongo-3.12.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c188db6cf9e14dbbb42f5254292be96f05374a35e7dfa087cc2140f0ff4f10f6"}, + {file = "pymongo-3.12.0-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:6fb3f85870ae26896bb44e67db94045f2ebf00c5d41e6b66cdcbb5afd644fc18"}, + {file = "pymongo-3.12.0-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:aaa038eafb7186a4abbb311fcf20724be9363645882bbce540bef4797e812a7a"}, + {file = "pymongo-3.12.0-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:7d98ce3c42921bb91566121b658e0d9d59a9082a9bd6f473190607ff25ab637f"}, + {file = "pymongo-3.12.0-cp34-cp34m-win32.whl", hash = "sha256:b0a0cf39f589e52d801fdef418305562bc030cdf8929217463c8433c65fd5c2f"}, + {file = "pymongo-3.12.0-cp34-cp34m-win_amd64.whl", hash = "sha256:ceae3ab9e11a27aaab42878f1d203600dfd24f0e43678b47298219a0f10c0d30"}, + {file = "pymongo-3.12.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:5e574664f1468872cd40f74e4811e22b1aa4de9399d6bcfdf1ee6ea94c017fcf"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73b400fdc22de84bae0dbf1a22613928a41612ec0a3d6ed47caf7ad4d3d0f2ff"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:cbf8672edeb7b7128c4a939274801f0e32bbf5159987815e3d1eace625264a46"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:a634a4730ce0b0934ed75e45beba730968e12b4dafbb22f69b3b2f616d9e644e"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:c55782a55f4a013a78ac5b6ee4b8731a192dea7ab09f1b6b3044c96d5128edd4"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:11f9e0cfc84ade088a38df2708d0b958bb76360181df1b2e1e1a41beaa57952b"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:186104a94d39b8412f8e3de385acd990a628346a4402d4f3a288a82b8660bd22"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:70761fd3c576b027eec882b43ee0a8e5b22ff9c20cdf4d0400e104bc29e53e34"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:333bfad77aa9cd11711febfb75eed0bb537a1d022e1c252714dad38993590240"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fa8957e9a1b202cb45e6b839c241cd986c897be1e722b81d2f32e9c6aeee80b0"}, + {file = "pymongo-3.12.0-cp35-cp35m-win32.whl", hash = "sha256:4ba0def4abef058c0e5101e05e3d5266e6fffb9795bbf8be0fe912a7361a0209"}, + {file = "pymongo-3.12.0-cp35-cp35m-win_amd64.whl", hash = "sha256:a0e5dff6701fa615f165306e642709e1c1550d5b237c5a7a6ea299886828bd50"}, + {file = "pymongo-3.12.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:b542d56ed1b8d5cf3bb36326f814bd2fbe8812dfd2582b80a15689ea433c0e35"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a325600c83e61e3c9cebc0c2b1c8c4140fa887f789085075e8f44c8ff2547eb9"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:48d5bc80ab0af6b60c4163c5617f5cd23f2f880d7600940870ea5055816af024"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c5cab230e7cabdae9ff23c12271231283efefb944c1b79bed79a91beb65ba547"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d73e10772152605f6648ba4410318594f1043bbfe36d2fadee7c4b8912eff7c5"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:b1c4874331ab960429caca81acb9d2932170d66d6d6f87e65dc4507a85aca152"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:a3566acfbcde46911c52810374ecc0354fdb841284a3efef6ff7105bc007e9a8"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:b3b5b3cbc3fdf4fcfa292529df2a85b5d9c7053913a739d3069af1e12e12219f"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd3854148005c808c485c754a184c71116372263709958b42aefbef2e5dd373a"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f55c1ddcc1f6050b07d468ce594f55dbf6107b459e16f735d26818d7be1e9538"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ced944dcdd561476deef7cb7bfd4987c69fffbfeff6d02ca4d5d4fd592d559b7"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78ecb8d42f50d393af912bfb1fb1dcc9aabe9967973efb49ee577e8f1cea494c"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1970cfe2aec1bf74b40cf30c130ad10cd968941694630386db33e1d044c22a2e"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8bf42d3b32f586f4c9e37541769993783a534ad35531ce8a4379f6fa664fba9"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bc9ac81e73573516070d24ce15da91281922811f385645df32bd3c8a45ab4684"}, + {file = "pymongo-3.12.0-cp36-cp36m-win32.whl", hash = "sha256:d04ca462cb99077e6c059e97c072957caf2918e6e4191e3161c01c439e0193de"}, + {file = "pymongo-3.12.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f2acf9bbcd514e901f82c4ca6926bbd2ae61716728f110b4343eb0a69612d018"}, + {file = "pymongo-3.12.0-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:b754240daafecd9d5fce426b0fbaaed03f4ebb130745c8a4ae9231fffb8d75e5"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:af586e85144023686fb0af09c8cdf672484ea182f352e7ceead3d832de381e1b"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fe5872ce6f9627deac8314bdffd3862624227c3de4c17ef0cc78bbf0402999eb"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f6977a520bd96e097c8a37a8cbb9faa1ea99d21bf84190195056e25f688af73d"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:2dbfbbded947a83a3dffc2bd1ec4750c17e40904692186e2c55a3ad314ca0222"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:a752ecd1a26000a6d67be7c9a2e93801994a8b3f866ac95b672fbc00225ca91a"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:1bab889ae7640eba739f67fcbf8eff252dddc60d4495e6ddd3a87cd9a95fdb52"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:f94c7d22fb36b184734dded7345a04ec5f95130421c775b8b0c65044ef073f34"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec5ca7c0007ce268048bbe0ffc6846ed1616cf3d8628b136e81d5e64ff3f52a2"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c72d08acdf573455b2b9d2b75b8237654841d63a48bc2327dc102c6ee89b75a"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6ea08758b6673610b3c5bdf47189286cf9c58b1077558706a2f6f8744922527"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46d5ec90276f71af3a29917b30f2aec2315a2759b5f8d45b3b63a07ca8a070a3"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:625befa3bc9b40746a749115cc6a15bf20b9bd7597ca55d646205b479a2c99c7"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d1131562ddc2ea8a446f66c2648d7dabec2b3816fc818528eb978a75a6d23b2e"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eee42a1cc06565f6b21caa1f504ec15e07de7ebfd520ab57f8cb3308bc118e22"}, + {file = "pymongo-3.12.0-cp37-cp37m-win32.whl", hash = "sha256:94d38eba4d1b5eb3e6bfece0651b855a35c44f32fd91f512ab4ba41b8c0d3e66"}, + {file = "pymongo-3.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e018a4921657c2d3f89c720b7b90b9182e277178a04a7e9542cc79d7d787ca51"}, + {file = "pymongo-3.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7c6a9948916a7bbcc6d3a9f6fb75db1acb5546078023bfb3db6efabcd5a67527"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e9faf8d4712d5ea301d74abfcf6dafe4b7f4af7936e91f283b0ad7bf69ed3e3a"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cc2894fe91f31a513860238ede69fe47fada21f9e7ddfe73f7f9fef93a971e41"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:053b4ebf91c7395d1fcd2ce6a9edff0024575b7b2de6781554a4114448a8adc9"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:39dafa2eaf577d1969f289dc9a44501859a1897eb45bd589e93ce843fc610800"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:246ec420e4c8744fceb4e259f906211b9c198e1f345e6158dcd7cbad3737e11e"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:208debdcf76ed39ebf24f38509f50dc1c100e31e8653817fedb8e1f867850a13"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:18290649759f9db660972442aa606f845c368db9b08c4c73770f6da14113569b"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657ad80de8ec9ed656f28844efc801a0802961e8c6a85038d97ff6f555ef4919"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b772bab31cbd9cb911e41e1a611ebc9497f9a32a7348e2747c38210f75c00f41"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2399a85b54f68008e483b2871f4a458b4c980469c7fe921595ede073e4844f1e"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e66780f14c2efaf989cd3ac613b03ee6a8e3a0ba7b96c0bb14adca71a427e55"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02dc0b0f48ed3cd06c13b7e31b066bf91e00dac5f8147b0a0a45f9009bfab857"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:070a4ef689c9438a999ec3830e69b208ff0d12251846e064d947f97d819d1d05"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db93608a246da44d728842b8fa9e45aa9782db76955f634a707739a8d53ff544"}, + {file = "pymongo-3.12.0-cp38-cp38-win32.whl", hash = "sha256:5af390fa9faf56c93252dab09ea57cd020c9123aa921b63a0ed51832fdb492e7"}, + {file = "pymongo-3.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:a2239556ff7241584ce57be1facf25081669bb457a9e5cbe68cce4aae6567aa1"}, + {file = "pymongo-3.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cda9e628b1315beec8341e8c04aac9a0b910650b05e0751e42e399d5694aeacb"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:845a8b83798b2fb11b09928413cb32692866bfbc28830a433d9fa4c8c3720dd0"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:da8288bc4a7807c6715416deed1c57d94d5e03e93537889e002bf985be503f1a"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a9ba2a63777027b06b116e1ea8248e66fd1bedc2c644f93124b81a91ddbf6d88"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:9a13661681d17e43009bb3e85e837aa1ec5feeea1e3654682a01b8821940f8b3"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:6b89dc51206e4971c5568c797991eaaef5dc2a6118d67165858ad11752dba055"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:701e08457183da70ed96b35a6b43e6ba1df0b47c837b063cde39a1fbe1aeda81"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e7a33322e08021c37e89cae8ff06327503e8a1719e97c69f32c31cbf6c30d72c"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd1f49f949a658c4e8f81ed73f9aad25fcc7d4f62f767f591e749e30038c4e1d"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6d055f01b83b1a4df8bb0c61983d3bdffa913764488910af3620e5c2450bf83"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd6ff2192f34bd622883c745a56f492b1c9ccd44e14953e8051c33024a2947d5"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19d4bd0fc29aa405bb1781456c9cfff9fceabb68543741eb17234952dbc2bbb0"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24f8aeec4d6b894a6128844e50ff423dd02462ee83addf503c598ee3a80ddf3d"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b6055e0ef451ff73c93d0348d122a0750dddf323b9361de5835dac2f6cf7fc1"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6261bee7c5abadeac7497f8f1c43e521da78dd13b0a2439f526a7b0fc3788824"}, + {file = "pymongo-3.12.0-cp39-cp39-win32.whl", hash = "sha256:2e92aa32300a0b5e4175caec7769f482b292769807024a86d674b3f19b8e3755"}, + {file = "pymongo-3.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ce83f17f641a62a4dfb0ba1b8a3c1ced7c842f511b5450d90c030c7828e3693"}, + {file = "pymongo-3.12.0-py2.7-macosx-10.14-intel.egg", hash = "sha256:d1740776b70367277323fafb76bcf09753a5cc9824f5d705bac22a34ff3668ea"}, + {file = "pymongo-3.12.0.tar.gz", hash = "sha256:b88d1742159bc93a078733f9789f563cef26f5e370eba810476a71aa98e5fbc2"}, ] pynput = [ {file = "pynput-1.7.3-py2.py3-none-any.whl", hash = "sha256:fea5777454f896bd79d35393088cd29a089f3b2da166f0848a922b1d5a807d4f"}, @@ -2210,27 +2332,47 @@ pyqt5-sip = [ {file = "PyQt5_sip-12.9.0.tar.gz", hash = "sha256:d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32"}, ] pyrsistent = [ - {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-win32.whl", hash = "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-win32.whl", hash = "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-win_amd64.whl", hash = "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2"}, + {file = "pyrsistent-0.18.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427"}, + {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef"}, + {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c"}, + {file = "pyrsistent-0.18.0-cp38-cp38-win32.whl", hash = "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78"}, + {file = "pyrsistent-0.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b"}, + {file = "pyrsistent-0.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4"}, + {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680"}, + {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426"}, + {file = "pyrsistent-0.18.0-cp39-cp39-win32.whl", hash = "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b"}, + {file = "pyrsistent-0.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea"}, + {file = "pyrsistent-0.18.0.tar.gz", hash = "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b"}, ] pytest = [ - {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, - {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, + {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, + {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] pytest-cov = [ {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, ] pytest-print = [ - {file = "pytest_print-0.2.1-py2.py3-none-any.whl", hash = "sha256:2cfcdeee8b398457d3e3488f1fde5f8303b404c30187be5fcb4c7818df5f4529"}, - {file = "pytest_print-0.2.1.tar.gz", hash = "sha256:8f61e5bb2d031ee88d19a5a7695a0c863caee7b1478f1a82d080c2128b76ad83"}, + {file = "pytest_print-0.3.0-py2.py3-none-any.whl", hash = "sha256:53fb0f71d371f137ac2e7171d92f204eb45055580e8c7920df619d9b2ee45359"}, + {file = "pytest_print-0.3.0.tar.gz", hash = "sha256:769f1b1b0943b2941dbeeaac6985766e76b341130ed538f88c23ebcd7087b90d"}, ] python-dateutil = [ - {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, - {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] python-xlib = [ - {file = "python-xlib-0.30.tar.gz", hash = "sha256:74131418faf9e7b83178c71d9d80297fbbd678abe99ae9258f5a20cd027acb5f"}, - {file = "python_xlib-0.30-py2.py3-none-any.whl", hash = "sha256:c4c92cd47e07588b2cbc7d52de18407b2902c3812d7cdec39cd2177b060828e2"}, + {file = "python-xlib-0.31.tar.gz", hash = "sha256:74d83a081f532bc07f6d7afcd6416ec38403d68f68b9b9dc9e1f28fbf2d799e9"}, + {file = "python_xlib-0.31-py2.py3-none-any.whl", hash = "sha256:1ec6ce0de73d9e6592ead666779a5732b384e5b8fb1f1886bd0a81cafa477759"}, ] python3-xlib = [ {file = "python3-xlib-0.15.tar.gz", hash = "sha256:dc4245f3ae4aa5949c1d112ee4723901ade37a96721ba9645f2bfa56e5b383f8"}, @@ -2256,16 +2398,16 @@ pywin32-ctypes = [ {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, ] "qt.py" = [ - {file = "Qt.py-1.3.3-py2.py3-none-any.whl", hash = "sha256:9e3f5417187c98d246918a9b27a9e1f8055e089bdb2b063a2739986bc19a3d2e"}, - {file = "Qt.py-1.3.3.tar.gz", hash = "sha256:601606127f70be9adc82c248d209d696cccbd1df242c24d3fb1a9e399f3ecaf1"}, + {file = "Qt.py-1.3.6-py2.py3-none-any.whl", hash = "sha256:7edf6048d07a6924707506b5ba34a6e05d66dde9a3f4e3a62f9996ccab0b91c7"}, + {file = "Qt.py-1.3.6.tar.gz", hash = "sha256:0d78656a2f814602eee304521c7bf5da0cec414818b3833712c77524294c404a"}, ] recommonmark = [ {file = "recommonmark-0.7.1-py2.py3-none-any.whl", hash = "sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f"}, {file = "recommonmark-0.7.1.tar.gz", hash = "sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67"}, ] requests = [ - {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, - {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, ] rsa = [ {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, @@ -2284,8 +2426,8 @@ six = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] slack-sdk = [ - {file = "slack_sdk-3.6.0-py2.py3-none-any.whl", hash = "sha256:e1b257923a1ef88b8620dd3abff94dc5b3eee16ef37975d101ba9e60123ac3af"}, - {file = "slack_sdk-3.6.0.tar.gz", hash = "sha256:195f044e02a2844579a7a26818ce323e85dde8de224730c859644918d793399e"}, + {file = "slack_sdk-3.10.1-py2.py3-none-any.whl", hash = "sha256:f17b71a578e94204d9033bffded634475f4ca0a6274c6c7a4fd8a9cb0ac7cd8b"}, + {file = "slack_sdk-3.10.1.tar.gz", hash = "sha256:2b4dde7728eb4ff5a581025d204578ccff25a5d8f0fe11ae175e3ce6e074434f"}, ] smmap = [ {file = "smmap-4.0.0-py2.py3-none-any.whl", hash = "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"}, @@ -2300,8 +2442,8 @@ speedcopy = [ {file = "speedcopy-2.1.0.tar.gz", hash = "sha256:8bb1a6c735900b83901a7be84ba2175ed3887c13c6786f97dea48f2ea7d504c2"}, ] sphinx = [ - {file = "Sphinx-4.0.2-py3-none-any.whl", hash = "sha256:d1cb10bee9c4231f1700ec2e24a91be3f3a3aba066ea4ca9f3bbe47e59d5a1d4"}, - {file = "Sphinx-4.0.2.tar.gz", hash = "sha256:b5c2ae4120bf00c799ba9b3699bc895816d272d120080fbc967292f29b52b48c"}, + {file = "Sphinx-4.1.2-py3-none-any.whl", hash = "sha256:46d52c6cee13fec44744b8c01ed692c18a640f6910a725cbb938bc36e8d64544"}, + {file = "Sphinx-4.1.2.tar.gz", hash = "sha256:3092d929cd807926d846018f2ace47ba2f3b671b309c7a89cd3306e80c826b13"}, ] sphinx-qt-documentation = [ {file = "sphinx_qt_documentation-0.3-py3-none-any.whl", hash = "sha256:bee247cb9e4fc03fc496d07adfdb943100e1103320c3e5e820e0cfa7c790d9b6"}, @@ -2379,17 +2521,17 @@ typed-ast = [ {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, - {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, - {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] uritemplate = [ {file = "uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"}, {file = "uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"}, ] urllib3 = [ - {file = "urllib3-1.26.5-py2.py3-none-any.whl", hash = "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c"}, - {file = "urllib3-1.26.5.tar.gz", hash = "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"}, + {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, + {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, @@ -2446,6 +2588,6 @@ yarl = [ {file = "yarl-1.6.3.tar.gz", hash = "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10"}, ] zipp = [ - {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, - {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, + {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, + {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, ] diff --git a/pyproject.toml b/pyproject.toml index a57ae19224..24e51a17bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,7 @@ slack-sdk = "^3.6.0" flake8 = "^3.7" autopep8 = "^1.4" coverage = "*" -cx_freeze = "*" +cx_freeze = { version = "6.7", source = "openpype" } GitPython = "^3.1.17" jedi = "^0.13" Jinja2 = "^2.11" diff --git a/tools/docker_build.sh b/tools/docker_build.sh index c27041a1af..d2dbef2e48 100755 --- a/tools/docker_build.sh +++ b/tools/docker_build.sh @@ -27,17 +27,15 @@ create_container () { fi local id=$(<"$openpype_root/build/docker-image.id") echo -e "${BIYellow}---${RST} Creating container from $id ..." - local cid="$(docker create $id bash)" + cid="$(docker create $id bash)" if [ $? -ne 0 ] ; then echo -e "${BIRed}!!!${RST} Cannot create container." exit 1 fi - return $cid } retrieve_build_log () { create_container - local cid=$? echo -e "${BIYellow}***${RST} Copying build log to ${BIWhite}$openpype_root/build/build.log${RST}" docker cp "$cid:/opt/openpype/build/build.log" "$openpype_root/build" } @@ -65,7 +63,6 @@ main () { echo -e "${BIGreen}>>>${RST} Copying build from container ..." create_container - local cid=$? echo -e "${BIYellow}---${RST} Copying ..." docker cp "$cid:/opt/openpype/build/exe.linux-x86_64-3.7" "$openpype_root/build" docker cp "$cid:/opt/openpype/build/build.log" "$openpype_root/build" @@ -79,7 +76,7 @@ main () { chown -R $username ./build echo -e "${BIGreen}>>>${RST} All done, you can delete container:" - echo -e "${BIYellow}$id${RST}" + echo -e "${BIYellow}$cid${RST}" } return_code=0 From 2167671d8e8adf8f2ea4eeaf2745266899494f2b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 9 Sep 2021 14:18:13 +0200 Subject: [PATCH 062/150] #1784 - fixing Hound, typos, run_tests command Added documentation --- openpype/pype_commands.py | 14 ++++++++++---- tests/README.md | 15 ++++++++++++++- .../hosts/maya/test_publish_in_maya.py | 2 -- tests/lib/file_handler.py | 15 +++++++-------- tests/lib/testing_classes.py | 2 +- .../modules/sync_server/test_site_operations.py | 5 ++++- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/openpype/pype_commands.py b/openpype/pype_commands.py index c309ee8c09..5288749e8b 100644 --- a/openpype/pype_commands.py +++ b/openpype/pype_commands.py @@ -268,13 +268,19 @@ class PypeCommands: """ print("run_tests") import subprocess - folder = folder or "../tests" + + if folder: + folder = " ".join(list(folder)) + else: + folder = "../tests" + mark_str = pyargs_str = '' if mark: - mark_str = "- m {}".format(mark) + mark_str = "-m {}".format(mark) if pyargs: pyargs_str = "--pyargs {}".format(pyargs) - subprocess.run("pytest {} {} {}".format(folder, mark_str, pyargs_str)) - + cmd = "pytest {} {} {}".format(folder, mark_str, pyargs_str) + print("Running {}".format(cmd)) + subprocess.run(cmd) diff --git a/tests/README.md b/tests/README.md index 727b89a86e..6317b2ab3c 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,7 +1,7 @@ Automatic tests for OpenPype ============================ Structure: -- integration - end to end tests, slow +- integration - end to end tests, slow (see README.md in the integration folder for more info) - openpype/modules/MODULE_NAME - structure follow directory structure in code base - fixture - sample data `(MongoDB dumps, test files etc.)` - `tests.py` - single or more pytest files for MODULE_NAME @@ -10,3 +10,16 @@ Structure: - fixture - `tests.py` +How to run: +---------- +- single test class could be run by PyCharm and its pytest runner directly +- OR +- use Openpype command 'runtests' from command line +-- `${OPENPYPE_ROOT}/start.py runtests` + +By default, this command will run all tests in ${OPENPYPE_ROOT}/tests. + +Specific location could be provided to this command as an argument, either as absolute path, or relative path to ${OPENPYPE_ROOT}. +(eg. `${OPENPYPE_ROOT}/start.py runtests ../tests/integration`) will trigger only tests in `integration` folder. + +See `${OPENPYPE_ROOT}/cli.py:runtests` for other arguments. diff --git a/tests/integration/hosts/maya/test_publish_in_maya.py b/tests/integration/hosts/maya/test_publish_in_maya.py index b9c63651f1..c178a6687e 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya.py +++ b/tests/integration/hosts/maya/test_publish_in_maya.py @@ -1,8 +1,6 @@ import pytest -import sys import os import shutil -import glob from tests.lib.testing_classes import PublishTest diff --git a/tests/lib/file_handler.py b/tests/lib/file_handler.py index 98e14b0541..ee3abc6ecb 100644 --- a/tests/lib/file_handler.py +++ b/tests/lib/file_handler.py @@ -193,11 +193,10 @@ class RemoteFileHandler: urllib.request.Request(url, headers={"User-Agent": USER_AGENT})) \ as response: - for chunk in iter(lambda: response.read(chunk_size), - ""): - if not chunk: - break - fh.write(chunk) + for chunk in iter(lambda: response.read(chunk_size), ""): + if not chunk: + break + fh.write(chunk) @staticmethod def _get_redirect_url(url, max_hops): @@ -218,7 +217,7 @@ class RemoteFileHandler: ) @staticmethod - def _get_confirm_token(response): # type: ignore[name-defined] + def _get_confirm_token(response): for key, value in response.cookies.items(): if key.startswith('download_warning'): return value @@ -227,7 +226,7 @@ class RemoteFileHandler: @staticmethod def _save_response_content( - response_gen, destination, # type: ignore[name-defined] + response_gen, destination, ): with open(destination, "wb") as f: pbar = enlighten.Counter( @@ -241,7 +240,7 @@ class RemoteFileHandler: pbar.close() @staticmethod - def _quota_exceeded(first_chunk): # type: ignore[name-defined] + def _quota_exceeded(first_chunk): try: return "Google Drive - Quota exceeded" in first_chunk.decode() except UnicodeDecodeError: diff --git a/tests/lib/testing_classes.py b/tests/lib/testing_classes.py index 6cd3c10d3e..1832efb7ed 100644 --- a/tests/lib/testing_classes.py +++ b/tests/lib/testing_classes.py @@ -260,4 +260,4 @@ class PublishTest(ModuleUnitTest): f != expected_dir_base and os.path.exists(f)) not_matched = expected.difference(published) - assert not not_matched, "Missing {} files".format(not_matched) \ No newline at end of file + assert not not_matched, "Missing {} files".format(not_matched) diff --git a/tests/unit/openpype/modules/sync_server/test_site_operations.py b/tests/unit/openpype/modules/sync_server/test_site_operations.py index ab15025399..6a861100a4 100644 --- a/tests/unit/openpype/modules/sync_server/test_site_operations.py +++ b/tests/unit/openpype/modules/sync_server/test_site_operations.py @@ -21,6 +21,9 @@ class TestSiteOperation(ModuleUnitTest): REPRESENTATION_ID = "60e578d0c987036c6a7b741d" + TEST_FILES = [("1eCwPljuJeOI8A3aisfOIBKKjcmIycTEt", + "test_site_operations.zip", '')] + @pytest.fixture(scope="module") def setup_sync_server_module(self, dbcon): """Get sync_server_module from ModulesManager""" @@ -109,7 +112,7 @@ class TestSiteOperation(ModuleUnitTest): site_names = [site["name"] for site in ret["files"][0]["sites"]] assert 'test_site' not in site_names, "Site name wasn't removed" - + @pytest.mark.usefixtures("setup_sync_server_module") def test_remove_site_again(self, dbcon, setup_sync_server_module): """Depends on test_add_site, must trow exception""" From 6cced73ac9e07b36112311b2aa03653089571354 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 9 Sep 2021 16:36:50 +0200 Subject: [PATCH 063/150] change to debian, add platform selection --- Dockerfile | 84 +++++++++++++++++------------------------ Dockerfile.centos7 | 87 +++++++++++++++++++++++++++++++++++++++++++ README.md | 11 ++++++ tools/docker_build.sh | 17 ++++++++- 4 files changed, 148 insertions(+), 51 deletions(-) create mode 100644 Dockerfile.centos7 diff --git a/Dockerfile b/Dockerfile index 78611860ea..cef83b5811 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,9 @@ # Build Pype docker image -FROM centos:7 AS builder -ARG OPENPYPE_PYTHON_VERSION=3.7.10 +FROM debian:bookworm-slim AS builder +ARG OPENPYPE_PYTHON_VERSION=3.7.12 +LABEL maintainer="info@openpype.io" +LABEL description="Docker Image to build and run OpenPype" LABEL org.opencontainers.image.name="pypeclub/openpype" LABEL org.opencontainers.image.title="OpenPype Docker Image" LABEL org.opencontainers.image.url="https://openpype.io/" @@ -9,57 +11,49 @@ LABEL org.opencontainers.image.source="https://github.com/pypeclub/pype" USER root -# update base -RUN yum -y install deltarpm \ - && yum -y update \ - && yum clean all +ARG DEBIAN_FRONTEND=noninteractive -# add tools we need -RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ - && yum -y install centos-release-scl \ - && yum -y install \ +# update base +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ bash \ - which \ git \ - devtoolset-7-gcc* \ - make \ cmake \ + make \ curl \ wget \ - gcc \ - zlib-devel \ - bzip2 \ - bzip2-devel \ - readline-devel \ - sqlite sqlite-devel \ - openssl-devel \ - openssl-libs \ - tk-devel libffi-devel \ - qt5-qtbase-devel \ - patchelf \ - && yum clean all + build-essential \ + checkinstall \ + libssl-dev \ + zlib1g-dev \ + libbz2-dev \ + libreadline-dev \ + libsqlite3-dev \ + llvm \ + libncursesw5-dev \ + xz-utils \ + tk-dev \ + libxml2-dev \ + libxmlsec1-dev \ + libffi-dev \ + liblzma-dev \ + patchelf + +SHELL ["/bin/bash", "-c"] RUN mkdir /opt/openpype -# RUN useradd -m pype -# RUN chown pype /opt/openpype -# USER pype -RUN curl https://pyenv.run | bash -ENV PYTHON_CONFIGURE_OPTS --enable-shared - -RUN echo 'export PATH="$HOME/.pyenv/bin:$PATH"'>> $HOME/.bashrc \ +RUN curl https://pyenv.run | bash \ + && echo 'export PATH="$HOME/.pyenv/bin:$PATH"'>> $HOME/.bashrc \ && echo 'eval "$(pyenv init -)"' >> $HOME/.bashrc \ && echo 'eval "$(pyenv virtualenv-init -)"' >> $HOME/.bashrc \ - && echo 'eval "$(pyenv init --path)"' >> $HOME/.bashrc -RUN source $HOME/.bashrc && pyenv install ${OPENPYPE_PYTHON_VERSION} + && echo 'eval "$(pyenv init --path)"' >> $HOME/.bashrc \ + && source $HOME/.bashrc && pyenv install ${OPENPYPE_PYTHON_VERSION} COPY . /opt/openpype/ -RUN rm -rf /openpype/.poetry || echo "No Poetry installed yet." -# USER root -# RUN chown -R pype /opt/openpype -RUN chmod +x /opt/openpype/tools/create_env.sh && chmod +x /opt/openpype/tools/build.sh -# USER pype +RUN chmod +x /opt/openpype/tools/create_env.sh && chmod +x /opt/openpype/tools/build.sh WORKDIR /opt/openpype @@ -68,18 +62,8 @@ RUN cd /opt/openpype \ && pyenv local ${OPENPYPE_PYTHON_VERSION} RUN source $HOME/.bashrc \ - && ./tools/create_env.sh - -RUN source $HOME/.bashrc \ + && ./tools/create_env.sh \ && ./tools/fetch_thirdparty_libs.sh RUN source $HOME/.bashrc \ && bash ./tools/build.sh - -RUN cp /usr/lib64/libffi* ./build/exe.linux-x86_64-3.7/lib \ - && cp /usr/lib64/libssl* ./build/exe.linux-x86_64-3.7/lib \ - && cp /usr/lib64/libcrypto* ./build/exe.linux-x86_64-3.7/lib \ - && cp /root/.pyenv/versions/${OPENPYPE_PYTHON_VERSION}/lib/libpython* ./build/exe.linux-x86_64-3.7/lib - -RUN cd /opt/openpype \ - rm -rf ./vendor/bin diff --git a/Dockerfile.centos7 b/Dockerfile.centos7 new file mode 100644 index 0000000000..0e2fdd4ba0 --- /dev/null +++ b/Dockerfile.centos7 @@ -0,0 +1,87 @@ +# Build Pype docker image +FROM centos:7 AS builder +ARG OPENPYPE_PYTHON_VERSION=3.7.10 + +LABEL org.opencontainers.image.name="pypeclub/openpype" +LABEL org.opencontainers.image.title="OpenPype Docker Image" +LABEL org.opencontainers.image.url="https://openpype.io/" +LABEL org.opencontainers.image.source="https://github.com/pypeclub/pype" + +USER root + +# update base +RUN yum -y install deltarpm \ + && yum -y update \ + && yum clean all + +# add tools we need +RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \ + && yum -y install centos-release-scl \ + && yum -y install \ + bash \ + which \ + git \ + devtoolset-7-gcc* \ + make \ + cmake \ + curl \ + wget \ + gcc \ + zlib-devel \ + bzip2 \ + bzip2-devel \ + readline-devel \ + sqlite sqlite-devel \ + openssl-devel \ + openssl-libs \ + tk-devel libffi-devel \ + qt5-qtbase-devel \ + patchelf \ + ncurses \ + ncurses-devel \ + && yum clean all + +RUN mkdir /opt/openpype +# RUN useradd -m pype +# RUN chown pype /opt/openpype +# USER pype + +RUN curl https://pyenv.run | bash +# ENV PYTHON_CONFIGURE_OPTS --enable-shared + +RUN echo 'export PATH="$HOME/.pyenv/bin:$PATH"'>> $HOME/.bashrc \ + && echo 'eval "$(pyenv init -)"' >> $HOME/.bashrc \ + && echo 'eval "$(pyenv virtualenv-init -)"' >> $HOME/.bashrc \ + && echo 'eval "$(pyenv init --path)"' >> $HOME/.bashrc +RUN source $HOME/.bashrc && pyenv install ${OPENPYPE_PYTHON_VERSION} + +COPY . /opt/openpype/ +RUN rm -rf /openpype/.poetry || echo "No Poetry installed yet." +# USER root +# RUN chown -R pype /opt/openpype +RUN chmod +x /opt/openpype/tools/create_env.sh && chmod +x /opt/openpype/tools/build.sh + +# USER pype + +WORKDIR /opt/openpype + +RUN cd /opt/openpype \ + && source $HOME/.bashrc \ + && pyenv local ${OPENPYPE_PYTHON_VERSION} + +RUN source $HOME/.bashrc \ + && ./tools/create_env.sh + +RUN source $HOME/.bashrc \ + && ./tools/fetch_thirdparty_libs.sh + +RUN source $HOME/.bashrc \ + && bash ./tools/build.sh + +RUN cp /usr/lib64/libffi* ./build/exe.linux-x86_64-3.7/lib \ + && cp /usr/lib64/libssl* ./build/exe.linux-x86_64-3.7/lib \ + && cp /usr/lib64/libcrypto* ./build/exe.linux-x86_64-3.7/lib \ + && cp /root/.pyenv/versions/${OPENPYPE_PYTHON_VERSION}/lib/libpython* ./build/exe.linux-x86_64-3.7/lib + +RUN cd /opt/openpype \ + rm -rf ./vendor/bin diff --git a/README.md b/README.md index 209af24c75..0e450fc48d 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,12 @@ Easiest way to build OpenPype on Linux is using [Docker](https://www.docker.com/ sudo ./tools/docker_build.sh ``` +This will by default use Debian as base image. If you need to make Centos 7 compatible build, please run: + +```sh +sudo ./tools/docker_build.sh centos7 +``` + If all is successful, you'll find built OpenPype in `./build/` folder. #### Manual build @@ -158,6 +164,11 @@ you'll need also additional libraries for Qt5: ```sh sudo apt install qt5-default ``` +or if you are on Ubuntu > 20.04, there is no `qt5-default` packages so you need to install its content individually: + +```sh +sudo apt-get install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools +```
diff --git a/tools/docker_build.sh b/tools/docker_build.sh index d2dbef2e48..04c26424eb 100755 --- a/tools/docker_build.sh +++ b/tools/docker_build.sh @@ -40,6 +40,21 @@ retrieve_build_log () { docker cp "$cid:/opt/openpype/build/build.log" "$openpype_root/build" } +openpype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) + + +if [ -z $1 ]; then + dockerfile="Dockerfile" +else + dockerfile="Dockerfile.$1" + if [ ! -f "$openpype_root/$dockerfile" ]; then + echo -e "${BIRed}!!!${RST} Dockerfile for specifed platform ${BIWhite}$1${RST} doesn't exist." + exit 1 + else + echo -e "${BIGreen}>>>${RST} Using Dockerfile for ${BIWhite}$1${RST} ..." + fi +fi + # Main main () { openpype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) @@ -53,7 +68,7 @@ main () { echo -e "${BIGreen}>>>${RST} Running docker build ..." # docker build --pull --no-cache -t pypeclub/openpype:$openpype_version . - docker build --pull --iidfile $openpype_root/build/docker-image.id -t pypeclub/openpype:$openpype_version . + docker build --pull --iidfile $openpype_root/build/docker-image.id -t pypeclub/openpype:$openpype_version -f $dockerfile . if [ $? -ne 0 ] ; then echo $? echo -e "${BIRed}!!!${RST} Docker build failed." From d90a866b5bbcc55878068f20777c9db2ad6e68b1 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 9 Sep 2021 17:11:40 +0200 Subject: [PATCH 064/150] =?UTF-8?q?add=20changes=20to=20docs=20?= =?UTF-8?q?=F0=9F=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- website/docs/dev_build.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/website/docs/dev_build.md b/website/docs/dev_build.md index b3e0c24fc2..f71118eba6 100644 --- a/website/docs/dev_build.md +++ b/website/docs/dev_build.md @@ -84,6 +84,13 @@ You can use Docker to build OpenPype. Just run: ```shell $ sudo ./tools/docker_build.sh ``` + +This will by default use Debian as base image. If you need to make Centos 7 compatible build, please run: + +```sh +sudo ./tools/docker_build.sh centos7 +``` + and you should have built OpenPype in `build` directory. It is using **Centos 7** as a base image. @@ -323,14 +330,18 @@ Same as: poetry run python ./tools/create_zip.py ``` -### docker_build.sh +### docker_build.sh *[variant]* Script to build OpenPype on [Docker](https://www.docker.com/) enabled systems - usually Linux and Windows with [Docker Desktop](https://docs.docker.com/docker-for-windows/install/) and [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/about) (WSL) installed. It must be run with administrative privileges - `sudo ./docker_build.sh`. -It will use **Centos 7** base image to build OpenPype. You'll see your build in `./build` folder. +It will use latest **Debian** base image to build OpenPype. If you need to build OpenPype for +older systems like Centos 7, use `centos7` as argument. This will use another Dockerfile to build +OpenPype with **Centos 7** as base image. + +You'll see your build in `./build` folder. ### fetch_thirdparty_libs This script will download necessary tools for OpenPype defined in `pyproject.toml` like FFMpeg, From aa9a945b9ca537b91aef4722a18389e8ad6f3f7f Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 15 Sep 2021 14:02:02 +0200 Subject: [PATCH 065/150] remove devtoolset-7 from centos build --- Dockerfile.centos7 | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile.centos7 b/Dockerfile.centos7 index 0e2fdd4ba0..e39fc2dc8c 100644 --- a/Dockerfile.centos7 +++ b/Dockerfile.centos7 @@ -21,7 +21,6 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n bash \ which \ git \ - devtoolset-7-gcc* \ make \ cmake \ curl \ From 595f441947a6bb149a349dc9212fc8bcdaa0c00c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Mon, 20 Sep 2021 18:21:44 +0200 Subject: [PATCH 066/150] remove submodules --- openpype/modules/ftrack/python2_vendor/arrow | 1 - openpype/modules/ftrack/python2_vendor/ftrack-python-api | 1 - 2 files changed, 2 deletions(-) delete mode 160000 openpype/modules/ftrack/python2_vendor/arrow delete mode 160000 openpype/modules/ftrack/python2_vendor/ftrack-python-api diff --git a/openpype/modules/ftrack/python2_vendor/arrow b/openpype/modules/ftrack/python2_vendor/arrow deleted file mode 160000 index b746fedf72..0000000000 --- a/openpype/modules/ftrack/python2_vendor/arrow +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b746fedf7286c3755a46f07ab72f4c414cd41fc0 diff --git a/openpype/modules/ftrack/python2_vendor/ftrack-python-api b/openpype/modules/ftrack/python2_vendor/ftrack-python-api deleted file mode 160000 index d277f474ab..0000000000 --- a/openpype/modules/ftrack/python2_vendor/ftrack-python-api +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d277f474ab016e7b53479c36af87cb861d0cc53e From 1cd8aec44c07c75c264110b0a9bfecb035e093d2 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 22 Sep 2021 03:07:20 +0200 Subject: [PATCH 067/150] wip on fixing camera tokens --- openpype/hosts/maya/api/lib_renderproducts.py | 106 ++++++++++++------ .../plugins/publish/submit_publish_job.py | 7 +- 2 files changed, 77 insertions(+), 36 deletions(-) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index fb99584c5d..29f216be8c 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -114,6 +114,8 @@ class RenderProduct(object): aov = attr.ib(default=None) # source aov driver = attr.ib(default=None) # source driver multipart = attr.ib(default=False) # multichannel file + camera = attr.ib(default=None) # used only when rendering + # from multiple cameras def get(layer, render_instance=None): @@ -307,7 +309,7 @@ class ARenderProducts: # Deadline allows submitting renders with a custom frame list # to support those cases we might want to allow 'custom frames' # to be overridden to `ExpectFiles` class? - layer_data = LayerMetadata( + return LayerMetadata( frameStart=int(self.get_render_attribute("startFrame")), frameEnd=int(self.get_render_attribute("endFrame")), frameStep=int(self.get_render_attribute("byFrameStep")), @@ -321,7 +323,6 @@ class ARenderProducts: defaultExt=self._get_attr("defaultRenderGlobals.imfPluginKey"), filePrefix=file_prefix ) - return layer_data def _generate_file_sequence( self, layer_data, @@ -330,7 +331,7 @@ class ARenderProducts: force_cameras=None): # type: (LayerMetadata, str, str, list) -> list expected_files = [] - cameras = force_cameras if force_cameras else layer_data.cameras + cameras = force_cameras or layer_data.cameras ext = force_ext or layer_data.defaultExt for cam in cameras: file_prefix = layer_data.filePrefix @@ -460,15 +461,19 @@ class RenderProductsArnold(ARenderProducts): return prefix - def _get_aov_render_products(self, aov): + def _get_aov_render_products(self, aov, cameras=None): """Return all render products for the AOV""" - products = list() + products = [] aov_name = self._get_attr(aov, "name") ai_drivers = cmds.listConnections("{}.outputs".format(aov), source=True, destination=False, type="aiAOVDriver") or [] + use_single_camera = False + if not cameras: + cameras = ["__default__"] + use_single_camera = True for ai_driver in ai_drivers: # todo: check aiAOVDriver.prefix as it could have @@ -497,30 +502,43 @@ class RenderProductsArnold(ARenderProducts): name = "beauty" # Support Arnold light groups for AOVs - # Global AOV: When disabled the main layer is not written: `{pass}` + # Global AOV: When disabled the main layer is + # not written: `{pass}` # All Light Groups: When enabled, a `{pass}_lgroups` file is - # written and is always merged into a single file - # Light Groups List: When set, a product per light group is written + # written and is always merged into a + # single file + # Light Groups List: When set, a product per light + # group is written # e.g. {pass}_front, {pass}_rim global_aov = self._get_attr(aov, "globalAov") if global_aov: - product = RenderProduct(productName=name, - ext=ext, - aov=aov_name, - driver=ai_driver) - products.append(product) + for camera in cameras: + c = camera + if use_single_camera: + c = None + product = RenderProduct(productName=name, + ext=ext, + aov=aov_name, + driver=ai_driver, + camera=c) + products.append(product) all_light_groups = self._get_attr(aov, "lightGroups") if all_light_groups: # All light groups is enabled. A single multipart # Render Product - product = RenderProduct(productName=name + "_lgroups", - ext=ext, - aov=aov_name, - driver=ai_driver, - # Always multichannel output - multipart=True) - products.append(product) + for camera in cameras: + c = camera + if use_single_camera: + c = None + product = RenderProduct(productName=name + "_lgroups", + ext=ext, + aov=aov_name, + driver=ai_driver, + # Always multichannel output + multipart=True, + camera=c) + products.append(product) else: value = self._get_attr(aov, "lightGroupsList") if not value: @@ -529,11 +547,16 @@ class RenderProductsArnold(ARenderProducts): for light_group in selected_light_groups: # Render Product per selected light group aov_light_group_name = "{}_{}".format(name, light_group) - product = RenderProduct(productName=aov_light_group_name, - aov=aov_name, - driver=ai_driver, - ext=ext) - products.append(product) + for camera in cameras: + c = camera + if use_single_camera: + c = None + product = RenderProduct(productName=aov_light_group_name, + aov=aov_name, + driver=ai_driver, + ext=ext, + camera=c) + products.append(product) return products @@ -556,17 +579,31 @@ class RenderProductsArnold(ARenderProducts): # anyway. return [] - default_ext = self._get_attr("defaultRenderGlobals.imfPluginKey") - beauty_product = RenderProduct(productName="beauty", - ext=default_ext, - driver="defaultArnoldDriver") + # check if camera token is in prefix. If so, and we have list of + # renderable cameras, generate render product for each and every + # of them. + has_camera_token = ( + "" in self.layer_data.filePrefix.lower() + ) + cameras = [] + if has_camera_token: + cameras = [ + self.sanitize_camera_name(c) + for c in self.get_renderable_cameras() + ] + default_ext = self._get_attr("defaultRenderGlobals.imfPluginKey") + beauty_products = [RenderProduct( + productName="beauty", + ext=default_ext, + driver="defaultArnoldDriver", + camera=camera) for camera in cameras] # AOVs > Legacy > Maya Render View > Mode aovs_enabled = bool( self._get_attr("defaultArnoldRenderOptions.aovMode") ) if not aovs_enabled: - return [beauty_product] + return beauty_products # Common > File Output > Merge AOVs or # We don't need to check for Merge AOVs due to overridden @@ -575,8 +612,7 @@ class RenderProductsArnold(ARenderProducts): "" in self.layer_data.filePrefix.lower() ) if not has_renderpass_token: - beauty_product.multipart = True - return [beauty_product] + return [setattr(bp, "multipart", True) for bp in beauty_products] # AOVs are set to be rendered separately. We should expect # token in path. @@ -598,14 +634,14 @@ class RenderProductsArnold(ARenderProducts): continue # For now stick to the legacy output format. - aov_products = self._get_aov_render_products(aov) + aov_products = self._get_aov_render_products(aov, cameras) products.extend(aov_products) - if not any(product.aov == "RGBA" for product in products): + if all(product.aov != "RGBA" for product in products): # Append default 'beauty' as this is arnolds default. # However, it is excluded whenever a RGBA pass is enabled. # For legibility add the beauty layer as first entry - products.insert(0, beauty_product) + products += beauty_products # TODO: Output Denoising AOVs? diff --git a/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py index 19e3174384..6b07749819 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py @@ -385,6 +385,7 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): """ task = os.environ["AVALON_TASK"] subset = instance_data["subset"] + cameras = instance_data.get("cameras", []) instances = [] # go through aovs in expected files for aov, files in exp_files[0].items(): @@ -410,7 +411,11 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): task[0].upper(), task[1:], subset[0].upper(), subset[1:]) - subset_name = '{}_{}'.format(group_name, aov) + cam = [c for c in cameras if c in col.head] + if cam: + subset_name = '{}_{}_{}'.format(group_name, cam, aov) + else: + subset_name = '{}_{}'.format(group_name, aov) if isinstance(col, (list, tuple)): staging = os.path.dirname(col[0]) From c2a51824d589175cbcb65f5150ddb6e7d95acc9c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 09:47:15 +0200 Subject: [PATCH 068/150] add more required libraries to centos docker --- Dockerfile.centos7 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dockerfile.centos7 b/Dockerfile.centos7 index 0095ddff53..8b87654775 100644 --- a/Dockerfile.centos7 +++ b/Dockerfile.centos7 @@ -35,12 +35,15 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n openssl-devel \ openssl-libs \ tk-devel libffi-devel \ - qt5-qtbase-devel \ patchelf \ automake \ autoconf \ ncurses \ ncurses-devel \ + qt5-qtbase-devel \ + libxcb libxcb-devel \ + xcb-util xcb-util-devel \ + libxkbcommon-devel libxkbcommon-x11-devel && yum clean all # we need to build our own patchelf From 3d1f4fcdd42b8f87c0ebf728dc47e6d5815dee6a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 10:20:31 +0200 Subject: [PATCH 069/150] fixed endline --- Dockerfile.centos7 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.centos7 b/Dockerfile.centos7 index 8b87654775..67d45ce3b2 100644 --- a/Dockerfile.centos7 +++ b/Dockerfile.centos7 @@ -43,7 +43,7 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n qt5-qtbase-devel \ libxcb libxcb-devel \ xcb-util xcb-util-devel \ - libxkbcommon-devel libxkbcommon-x11-devel + libxkbcommon-devel libxkbcommon-x11-devel \ && yum clean all # we need to build our own patchelf From a10f2379e5aa0ef9f9768631d71bc57923fd7201 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 17:16:50 +0200 Subject: [PATCH 070/150] define openpype_root in build_dependencies --- tools/build_dependencies.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/build_dependencies.py b/tools/build_dependencies.py index e5a430e220..dcdae3814d 100644 --- a/tools/build_dependencies.py +++ b/tools/build_dependencies.py @@ -93,18 +93,18 @@ _print("Getting venv site-packages ...") assert site_pkg, "No venv site-packages are found." _print(f"Working with: {site_pkg}", 2) - -build_dir = "exe.{}-{}".format(get_platform(), sys.version[0:3]) +openpype_root = Path(os.path.dirname(__file__)).parent # create full path if platform.system().lower() == "darwin": - build_dir = Path(os.path.dirname(__file__)).parent.joinpath( + build_dir = openpype_root.joinpath( "build", "OpenPype.app", "Contents", "MacOS") else: - build_dir = Path(os.path.dirname(__file__)).parent / "build" / build_dir + build_subdir = "exe.{}-{}".format(get_platform(), sys.version[0:3]) + build_dir = openpype_root / "build" / build_subdir _print(f"Using build at {build_dir}", 2) if not build_dir.exists(): From cd52b1e1805649c5f242a03e661dc51bbf9aabc0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 17:17:30 +0200 Subject: [PATCH 071/150] added rpath modifications using patchelf --- tools/build_dependencies.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tools/build_dependencies.py b/tools/build_dependencies.py index dcdae3814d..05ae07d406 100644 --- a/tools/build_dependencies.py +++ b/tools/build_dependencies.py @@ -23,6 +23,7 @@ import sys import site from distutils.util import get_platform import platform +import subprocess from pathlib import Path import shutil import blessed @@ -145,6 +146,29 @@ if platform.system().lower() == "windows": _print("Could not find {}".format(src), 1) sys.exit(1) +# On Linux use rpath from source libraries in destination libraries +if platform.system().lower() == "linux": + src_pyside_dir = openpype_root / "vendor" / "python" / "PySide2" + dst_pyside_dir = build_dir / "vendor" / "python" / "PySide2" + src_rpath_per_so_file = {} + for filepath in src_pyside_dir.glob("*.so"): + filename = filepath.name + rpath = ( + subprocess.check_output(["patchelf", "--print-rpath", filepath]) + .decode("utf-8") + .strip() + ) + src_rpath_per_so_file[filename] = rpath + + for filepath in dst_pyside_dir.glob("*.so"): + filename = filepath.name + if filename not in src_rpath_per_so_file: + continue + src_rpath = src_rpath_per_so_file[filename] + subprocess.check_call( + ["patchelf", "--set-rpath", src_rpath, filepath] + ) + to_delete = [] # _print("Finding duplicates ...") deps_items = list(deps_dir.iterdir()) From da57732b226a4ca37d96a0c0de1165babb6ba611 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 17:23:12 +0200 Subject: [PATCH 072/150] removed PyQt special code --- tools/build_dependencies.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tools/build_dependencies.py b/tools/build_dependencies.py index 05ae07d406..1798b7ca8f 100644 --- a/tools/build_dependencies.py +++ b/tools/build_dependencies.py @@ -136,15 +136,6 @@ progress_bar.close() # iterate over frozen libs and create list to delete libs_dir = build_dir / "lib" -# On Windows "python3.dll" is needed for PyQt5 from the build. -if platform.system().lower() == "windows": - src = Path(libs_dir / "PyQt5" / "python3.dll") - dst = Path(deps_dir / "PyQt5" / "python3.dll") - if src.exists(): - shutil.copyfile(src, dst) - else: - _print("Could not find {}".format(src), 1) - sys.exit(1) # On Linux use rpath from source libraries in destination libraries if platform.system().lower() == "linux": From 7d2d621c9ab589d1b34638fec182e2939290f77c Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 22 Sep 2021 18:07:48 +0200 Subject: [PATCH 073/150] camera token for all renderers --- openpype/hosts/maya/api/lib_renderproducts.py | 150 +++++++++++------- .../maya/plugins/publish/collect_render.py | 14 +- .../publish/validate_rendersettings.py | 6 +- 3 files changed, 107 insertions(+), 63 deletions(-) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index 29f216be8c..39d894a204 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -185,6 +185,16 @@ class ARenderProducts: self.layer_data = self._get_layer_data() self.layer_data.products = self.get_render_products() + def has_camera_token(self): + # type: () -> bool + """Check if camera token is in image prefix. + + Returns: + bool: True/False if camera token is present. + + """ + return "" in self.layer_data.filePrefix.lower() + @abstractmethod def get_render_products(self): """To be implemented by renderer class. @@ -362,8 +372,8 @@ class ARenderProducts: ) return expected_files - def get_files(self, product, camera): - # type: (RenderProduct, str) -> list + def get_files(self, product): + # type: (RenderProduct) -> list """Return list of expected files. It will translate render token strings ('', etc.) to @@ -374,7 +384,6 @@ class ARenderProducts: Args: product (RenderProduct): Render product to be used for file generation. - camera (str): Camera name. Returns: List of files @@ -384,7 +393,7 @@ class ARenderProducts: self.layer_data, force_aov_name=product.productName, force_ext=product.ext, - force_cameras=[camera] + force_cameras=[product.camera] or None ) def get_renderable_cameras(self): @@ -470,10 +479,11 @@ class RenderProductsArnold(ARenderProducts): source=True, destination=False, type="aiAOVDriver") or [] - use_single_camera = False if not cameras: - cameras = ["__default__"] - use_single_camera = True + cameras = [ + self.sanitize_camera_name( + self.get_renderable_cameras()[0]) + ] for ai_driver in ai_drivers: # todo: check aiAOVDriver.prefix as it could have @@ -513,14 +523,11 @@ class RenderProductsArnold(ARenderProducts): global_aov = self._get_attr(aov, "globalAov") if global_aov: for camera in cameras: - c = camera - if use_single_camera: - c = None product = RenderProduct(productName=name, ext=ext, aov=aov_name, driver=ai_driver, - camera=c) + camera=camera) products.append(product) all_light_groups = self._get_attr(aov, "lightGroups") @@ -528,16 +535,13 @@ class RenderProductsArnold(ARenderProducts): # All light groups is enabled. A single multipart # Render Product for camera in cameras: - c = camera - if use_single_camera: - c = None product = RenderProduct(productName=name + "_lgroups", ext=ext, aov=aov_name, driver=ai_driver, # Always multichannel output multipart=True, - camera=c) + camera=camera) products.append(product) else: value = self._get_attr(aov, "lightGroupsList") @@ -548,14 +552,11 @@ class RenderProductsArnold(ARenderProducts): # Render Product per selected light group aov_light_group_name = "{}_{}".format(name, light_group) for camera in cameras: - c = camera - if use_single_camera: - c = None product = RenderProduct(productName=aov_light_group_name, aov=aov_name, driver=ai_driver, ext=ext, - camera=c) + camera=camera) products.append(product) return products @@ -582,15 +583,10 @@ class RenderProductsArnold(ARenderProducts): # check if camera token is in prefix. If so, and we have list of # renderable cameras, generate render product for each and every # of them. - has_camera_token = ( - "" in self.layer_data.filePrefix.lower() - ) - cameras = [] - if has_camera_token: - cameras = [ - self.sanitize_camera_name(c) - for c in self.get_renderable_cameras() - ] + cameras = [ + self.sanitize_camera_name(c) + for c in self.get_renderable_cameras() + ] default_ext = self._get_attr("defaultRenderGlobals.imfPluginKey") beauty_products = [RenderProduct( @@ -706,6 +702,11 @@ class RenderProductsVray(ARenderProducts): # anyway. return [] + cameras = [ + self.sanitize_camera_name(c) + for c in self.get_renderable_cameras() + ] + image_format_str = self._get_attr("vraySettings.imageFormatStr") default_ext = image_format_str if default_ext in {"exr (multichannel)", "exr (deep)"}: @@ -716,13 +717,21 @@ class RenderProductsVray(ARenderProducts): # add beauty as default when not disabled dont_save_rgb = self._get_attr("vraySettings.dontSaveRgbChannel") if not dont_save_rgb: - products.append(RenderProduct(productName="", ext=default_ext)) + for camera in cameras: + products.append( + RenderProduct(productName="", + ext=default_ext, + camera=camera)) # separate alpha file separate_alpha = self._get_attr("vraySettings.separateAlpha") if separate_alpha: - products.append(RenderProduct(productName="Alpha", - ext=default_ext)) + for camera in cameras: + products.append( + RenderProduct(productName="Alpha", + ext=default_ext, + camera=camera) + ) if image_format_str == "exr (multichannel)": # AOVs are merged in m-channel file, only main layer is rendered @@ -752,19 +761,23 @@ class RenderProductsVray(ARenderProducts): # instead seems to output multiple Render Products, # specifically "Self_Illumination" and "Environment" product_names = ["Self_Illumination", "Environment"] - for name in product_names: - product = RenderProduct(productName=name, - ext=default_ext, - aov=aov) - products.append(product) + for camera in cameras: + for name in product_names: + product = RenderProduct(productName=name, + ext=default_ext, + aov=aov, + camera=camera) + products.append(product) # Continue as we've processed this special case AOV continue aov_name = self._get_vray_aov_name(aov) - product = RenderProduct(productName=aov_name, - ext=default_ext, - aov=aov) - products.append(product) + for camera in cameras: + product = RenderProduct(productName=aov_name, + ext=default_ext, + aov=aov, + camera=camera) + products.append(product) return products @@ -911,6 +924,11 @@ class RenderProductsRedshift(ARenderProducts): # anyway. return [] + cameras = [ + self.sanitize_camera_name(c) + for c in self.get_renderable_cameras() + ] + # For Redshift we don't directly return upon forcing multilayer # due to some AOVs still being written into separate files, # like Cryptomatte. @@ -969,11 +987,13 @@ class RenderProductsRedshift(ARenderProducts): for light_group in light_groups: aov_light_group_name = "{}_{}".format(aov_name, light_group) - product = RenderProduct(productName=aov_light_group_name, - aov=aov_name, - ext=ext, - multipart=aov_multipart) - products.append(product) + for camera in cameras: + product = RenderProduct(productName=aov_light_group_name, + aov=aov_name, + ext=ext, + multipart=aov_multipart, + camera=camera) + products.append(product) if light_groups: light_groups_enabled = True @@ -981,11 +1001,13 @@ class RenderProductsRedshift(ARenderProducts): # Redshift AOV Light Select always renders the global AOV # even when light groups are present so we don't need to # exclude it when light groups are active - product = RenderProduct(productName=aov_name, - aov=aov_name, - ext=ext, - multipart=aov_multipart) - products.append(product) + for camera in cameras: + product = RenderProduct(productName=aov_name, + aov=aov_name, + ext=ext, + multipart=aov_multipart, + camera=camera) + products.append(product) # When a Beauty AOV is added manually, it will be rendered as # 'Beauty_other' in file name and "standard" beauty will have @@ -995,10 +1017,12 @@ class RenderProductsRedshift(ARenderProducts): return products beauty_name = "Beauty_other" if has_beauty_aov else "" - products.insert(0, - RenderProduct(productName=beauty_name, - ext=ext, - multipart=multipart)) + for camera in cameras: + products.insert(0, + RenderProduct(productName=beauty_name, + ext=ext, + multipart=multipart, + camera=camera)) return products @@ -1023,6 +1047,16 @@ class RenderProductsRenderman(ARenderProducts): :func:`ARenderProducts.get_render_products()` """ + cameras = [ + self.sanitize_camera_name(c) + for c in self.get_renderable_cameras() + ] + + if not cameras: + cameras = [ + self.sanitize_camera_name( + self.get_renderable_cameras()[0]) + ] products = [] default_ext = "exr" @@ -1036,9 +1070,11 @@ class RenderProductsRenderman(ARenderProducts): if aov_name == "rmanDefaultDisplay": aov_name = "beauty" - product = RenderProduct(productName=aov_name, - ext=default_ext) - products.append(product) + for camera in cameras: + product = RenderProduct(productName=aov_name, + ext=default_ext, + camera=camera) + products.append(product) return products diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index 5049647ff9..46d1c9350d 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -174,10 +174,16 @@ class CollectMayaRender(pyblish.api.ContextPlugin): assert render_products, "no render products generated" exp_files = [] for product in render_products: - for camera in layer_render_products.layer_data.cameras: - exp_files.append( - {product.productName: layer_render_products.get_files( - product, camera)}) + product_name = product.productName + if product.camera and layer_render_products.has_camera_token(): + product_name = "{}{}".format( + product.camera, + "_" + product_name if product_name else "") + exp_files.append( + { + product_name: layer_render_products.get_files( + product) + }) self.log.info("multipart: {}".format( layer_render_products.multipart)) diff --git a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py index 7c795db43d..65ddacfc57 100644 --- a/openpype/hosts/maya/plugins/publish/validate_rendersettings.py +++ b/openpype/hosts/maya/plugins/publish/validate_rendersettings.py @@ -76,7 +76,7 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): r'%a||', re.IGNORECASE) R_LAYER_TOKEN = re.compile( r'%l||', re.IGNORECASE) - R_CAMERA_TOKEN = re.compile(r'%c|', re.IGNORECASE) + R_CAMERA_TOKEN = re.compile(r'%c|Camera>') R_SCENE_TOKEN = re.compile(r'%s|', re.IGNORECASE) DEFAULT_PADDING = 4 @@ -126,7 +126,9 @@ class ValidateRenderSettings(pyblish.api.InstancePlugin): if len(cameras) > 1 and not re.search(cls.R_CAMERA_TOKEN, prefix): invalid = True cls.log.error("Wrong image prefix [ {} ] - " - "doesn't have: '' token".format(prefix)) + "doesn't have: '' token".format(prefix)) + cls.log.error( + "Note that to needs to have capital 'C' at the beginning") # renderer specific checks if renderer == "vray": From 39eb48abe31909222ccc996fedb6fe53158557d5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 18:52:27 +0200 Subject: [PATCH 074/150] removed pyqt5 from poetry.lock --- poetry.lock | 60 ----------------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6dae442c9d..968fda3d7b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -975,34 +975,6 @@ category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -[[package]] -name = "pyqt5" -version = "5.15.4" -description = "Python bindings for the Qt cross platform application toolkit" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -PyQt5-Qt5 = ">=5.15" -PyQt5-sip = ">=12.8,<13" - -[[package]] -name = "pyqt5-qt5" -version = "5.15.2" -description = "The subset of a Qt installation needed by PyQt5." -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "pyqt5-sip" -version = "12.9.0" -description = "The sip module support for PyQt5" -category = "main" -optional = false -python-versions = ">=3.5" - [[package]] name = "pyrsistent" version = "0.18.0" @@ -2299,38 +2271,6 @@ pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] -pyqt5 = [ - {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:8c0848ba790a895801d5bfd171da31cad3e551dbcc4e59677a3b622de2ceca98"}, - {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:883a549382fc22d29a0568f3ef20b38c8e7ab633a59498ac4eb63a3bf36d3fd3"}, - {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:a88526a271e846e44779bb9ad7a738c6d3c4a9d01e15a128ecfc6dd4696393b7"}, - {file = "PyQt5-5.15.4-cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:213bebd51821ed89b4d5b35bb10dbe67564228b3568f463a351a08e8b1677025"}, - {file = "PyQt5-5.15.4.tar.gz", hash = "sha256:2a69597e0dd11caabe75fae133feca66387819fc9bc050f547e5551bce97e5be"}, -] -pyqt5-qt5 = [ - {file = "PyQt5_Qt5-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154"}, - {file = "PyQt5_Qt5-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a"}, - {file = "PyQt5_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327"}, - {file = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"}, -] -pyqt5-sip = [ - {file = "PyQt5_sip-12.9.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:d85002238b5180bce4b245c13d6face848faa1a7a9e5c6e292025004f2fd619a"}, - {file = "PyQt5_sip-12.9.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:83c3220b1ca36eb8623ba2eb3766637b19eb0ce9f42336ad8253656d32750c0a"}, - {file = "PyQt5_sip-12.9.0-cp36-cp36m-win32.whl", hash = "sha256:d8b2bdff7bbf45bc975c113a03b14fd669dc0c73e1327f02706666a7dd51a197"}, - {file = "PyQt5_sip-12.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:69a3ad4259172e2b1aa9060de211efac39ddd734a517b1924d9c6c0cc4f55f96"}, - {file = "PyQt5_sip-12.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42274a501ab4806d2c31659170db14c282b8313d2255458064666d9e70d96206"}, - {file = "PyQt5_sip-12.9.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6a8701892a01a5a2a4720872361197cc80fdd5f49c8482d488ddf38c9c84f055"}, - {file = "PyQt5_sip-12.9.0-cp37-cp37m-win32.whl", hash = "sha256:ac57d796c78117eb39edd1d1d1aea90354651efac9d3590aac67fa4983f99f1f"}, - {file = "PyQt5_sip-12.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4347bd81d30c8e3181e553b3734f91658cfbdd8f1a19f254777f906870974e6d"}, - {file = "PyQt5_sip-12.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c446971c360a0a1030282a69375a08c78e8a61d568bfd6dab3dcc5cf8817f644"}, - {file = "PyQt5_sip-12.9.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fc43f2d7c438517ee33e929e8ae77132749c15909afab6aeece5fcf4147ffdb5"}, - {file = "PyQt5_sip-12.9.0-cp38-cp38-win32.whl", hash = "sha256:055581c6fed44ba4302b70eeb82e979ff70400037358908f251cd85cbb3dbd93"}, - {file = "PyQt5_sip-12.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:c5216403d4d8d857ec4a61f631d3945e44fa248aa2415e9ee9369ab7c8a4d0c7"}, - {file = "PyQt5_sip-12.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a25b9843c7da6a1608f310879c38e6434331aab1dc2fe6cb65c14f1ecf33780e"}, - {file = "PyQt5_sip-12.9.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:dd05c768c2b55ffe56a9d49ce6cc77cdf3d53dbfad935258a9e347cbfd9a5850"}, - {file = "PyQt5_sip-12.9.0-cp39-cp39-win32.whl", hash = "sha256:4f8e05fe01d54275877c59018d8e82dcdd0bc5696053a8b830eecea3ce806121"}, - {file = "PyQt5_sip-12.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:b09f4cd36a4831229fb77c424d89635fa937d97765ec90685e2f257e56a2685a"}, - {file = "PyQt5_sip-12.9.0.tar.gz", hash = "sha256:d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32"}, -] pyrsistent = [ {file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"}, {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d"}, From 0bbea713fb6357708798aa530a07d7ef40b0cda0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 18:58:14 +0200 Subject: [PATCH 075/150] added current develop lock file --- poetry.lock | 684 +++++++++++++++++++++------------------------------- 1 file changed, 271 insertions(+), 413 deletions(-) diff --git a/poetry.lock b/poetry.lock index 968fda3d7b..e43c788d74 100644 --- a/poetry.lock +++ b/poetry.lock @@ -80,7 +80,7 @@ python-dateutil = ">=2.7.0" [[package]] name = "astroid" -version = "2.7.3" +version = "2.5.6" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false @@ -89,7 +89,6 @@ python-versions = "~=3.6" [package.dependencies] lazy-object-proxy = ">=1.4.0" typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} -typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} wrapt = ">=1.11,<1.13" [[package]] @@ -147,11 +146,11 @@ pytz = ">=2015.7" [[package]] name = "blessed" -version = "1.18.1" +version = "1.18.0" description = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities." category = "main" optional = false -python-versions = ">=2.7" +python-versions = "*" [package.dependencies] jinxed = {version = ">=0.5.4", markers = "platform_system == \"Windows\""} @@ -176,7 +175,7 @@ python-versions = "*" [[package]] name = "cffi" -version = "1.14.6" +version = "1.14.5" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -193,17 +192,6 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -[[package]] -name = "charset-normalizer" -version = "2.0.4" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" -optional = false -python-versions = ">=3.5.0" - -[package.extras] -unicode_backport = ["unicodedata2"] - [[package]] name = "click" version = "7.1.2" @@ -265,7 +253,7 @@ toml = ["toml"] [[package]] name = "cryptography" -version = "3.4.8" +version = "3.4.7" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false @@ -284,20 +272,15 @@ test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pret [[package]] name = "cx-freeze" -version = "6.7" +version = "6.6" description = "Create standalone executables from Python scripts" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -cx-logging = {version = ">=3.0", markers = "sys_platform == \"win32\""} -importlib-metadata = ">=4.3.1" - -[package.source] -type = "legacy" -url = "https://distribute.openpype.io/wheels" -reference = "openpype" +cx-Logging = {version = ">=3.0", markers = "sys_platform == \"win32\""} +importlib-metadata = ">=3.1.1" [[package]] name = "cx-logging" @@ -403,19 +386,19 @@ smmap = ">=3.0.1,<5" [[package]] name = "gitpython" -version = "3.1.20" +version = "3.1.17" description = "Python Git Library" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.5" [package.dependencies] gitdb = ">=4.0.1,<5" -typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=3.7.4.0", markers = "python_version < \"3.8\""} [[package]] name = "google-api-core" -version = "1.31.2" +version = "1.30.0" description = "Google API client core library" category = "main" optional = false @@ -453,7 +436,7 @@ uritemplate = ">=3.0.0,<4dev" [[package]] name = "google-auth" -version = "1.35.0" +version = "1.31.0" description = "Google Authentication Library" category = "main" optional = false @@ -510,11 +493,11 @@ pyparsing = ">=2.4.2,<3" [[package]] name = "idna" -version = "3.2" +version = "2.10" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "imagesize" @@ -526,7 +509,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.8.1" +version = "4.5.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -538,8 +521,7 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -perf = ["ipython"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "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" @@ -551,17 +533,16 @@ python-versions = "*" [[package]] name = "isort" -version = "5.9.3" +version = "5.8.0" description = "A Python utility / library to sort Python imports." category = "dev" optional = false -python-versions = ">=3.6.1,<4.0" +python-versions = ">=3.6,<4.0" [package.extras] pipfile_deprecated_finder = ["pipreqs", "requirementslib"] requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] -plugins = ["setuptools"] [[package]] name = "jedi" @@ -579,15 +560,14 @@ testing = ["colorama", "docopt", "pytest (>=3.1.0)"] [[package]] name = "jeepney" -version = "0.7.1" +version = "0.6.0" description = "Low-level, pure Python DBus protocol wrapper." category = "main" optional = false python-versions = ">=3.6" [package.extras] -test = ["pytest", "pytest-trio", "pytest-asyncio", "testpath", "trio", "async-timeout"] -trio = ["trio", "async-generator"] +test = ["pytest", "pytest-trio", "pytest-asyncio", "testpath", "trio"] [[package]] name = "jinja2" @@ -715,11 +695,11 @@ reference = "openpype" [[package]] name = "packaging" -version = "21.0" +version = "20.9" description = "Core utilities for Python packages" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pyparsing = ">=2.0.2" @@ -738,7 +718,7 @@ testing = ["docopt", "pytest (<6.0.0)"] [[package]] name = "pathlib2" -version = "2.3.6" +version = "2.3.5" description = "Object-oriented filesystem paths" category = "main" optional = false @@ -749,38 +729,25 @@ six = "*" [[package]] name = "pillow" -version = "8.3.2" +version = "8.2.0" description = "Python Imaging Library (Fork)" category = "main" optional = false python-versions = ">=3.6" -[[package]] -name = "platformdirs" -version = "2.3.0" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] - [[package]] name = "pluggy" -version = "1.0.0" +version = "0.13.1" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] [[package]] name = "prefixed" @@ -882,7 +849,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.10.0" +version = "2.9.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false @@ -890,23 +857,22 @@ python-versions = ">=3.5" [[package]] name = "pylint" -version = "2.10.2" +version = "2.8.3" description = "python code static checker" category = "dev" optional = false python-versions = "~=3.6" [package.dependencies] -astroid = ">=2.7.2,<2.8" +astroid = "2.5.6" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" -platformdirs = ">=2.2.0" toml = ">=0.7.1" [[package]] name = "pymongo" -version = "3.12.0" +version = "3.11.4" description = "Python driver for MongoDB " category = "main" optional = false @@ -914,9 +880,9 @@ python-versions = "*" [package.extras] aws = ["pymongo-auth-aws (<2.0.0)"] -encryption = ["pymongocrypt (>=1.1.0,<2.0.0)"] +encryption = ["pymongocrypt (<2.0.0)"] gssapi = ["pykerberos"] -ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)", "certifi"] +ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] srv = ["dnspython (>=1.16.0,<1.17.0)"] tls = ["ipaddress"] @@ -977,15 +943,15 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "pyrsistent" -version = "0.18.0" +version = "0.17.3" description = "Persistent/Functional/Immutable data structures" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.5" [[package]] name = "pytest" -version = "6.2.5" +version = "6.2.4" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -998,7 +964,7 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" +pluggy = ">=0.12,<1.0.0a1" py = ">=1.8.2" toml = "*" @@ -1023,21 +989,21 @@ testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtuale [[package]] name = "pytest-print" -version = "0.3.0" +version = "0.2.1" description = "pytest-print adds the printer fixture you can use to print messages to the user (directly to the pytest runner, not stdout)" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] -pytest = ">=6" +pytest = ">=3.0.0" [package.extras] -test = ["coverage (>=5)"] +test = ["coverage (>=5)", "pytest (>=4)"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.8.1" description = "Extensions to the standard Python datetime module" category = "main" optional = false @@ -1048,7 +1014,7 @@ six = ">=1.5" [[package]] name = "python-xlib" -version = "0.31" +version = "0.30" description = "Python X Library" category = "main" optional = false @@ -1091,7 +1057,7 @@ python-versions = "*" [[package]] name = "qt.py" -version = "1.3.6" +version = "1.3.3" description = "Python 2 & 3 compatibility wrapper around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5." category = "main" optional = false @@ -1112,21 +1078,21 @@ sphinx = ">=1.3.1" [[package]] name = "requests" -version = "2.26.0" +version = "2.25.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +chardet = ">=3.0.2,<5" +idna = ">=2.5,<3" urllib3 = ">=1.21.1,<1.27" [package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "rsa" @@ -1169,15 +1135,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "slack-sdk" -version = "3.10.1" +version = "3.6.0" description = "The Slack API Platform SDK for Python" category = "main" optional = false python-versions = ">=3.6.0" [package.extras] -optional = ["aiodns (>1.0)", "aiohttp (>=3.7.3,<4)", "boto3 (<=2)", "SQLAlchemy (>=1,<2)", "websockets (>=9.1,<10)", "websocket-client (>=1,<2)"] -testing = ["pytest (>=5.4,<6)", "pytest-asyncio (<1)", "Flask-Sockets (>=0.2,<1)", "Flask (>=1,<2)", "Werkzeug (<2)", "pytest-cov (>=2,<3)", "codecov (>=2,<3)", "flake8 (>=3,<4)", "black (==21.7b0)", "psutil (>=5,<6)", "databases (>=0.3)", "boto3 (<=2)", "moto (<2)"] +optional = ["aiodns (>1.0)", "aiohttp (>=3.7.3,<4)", "boto3 (<=2)", "SQLAlchemy (>=1,<2)", "websockets (>=9.1,<10)", "websocket-client (>=0.57,<1)"] +testing = ["pytest (>=5.4,<6)", "pytest-asyncio (<1)", "Flask-Sockets (>=0.2,<1)", "pytest-cov (>=2,<3)", "codecov (>=2,<3)", "flake8 (>=3,<4)", "black (==21.5b1)", "psutil (>=5,<6)", "databases (>=0.3)"] [[package]] name = "smmap" @@ -1205,7 +1171,7 @@ python-versions = "*" [[package]] name = "sphinx" -version = "4.1.2" +version = "4.0.2" description = "Python documentation generator" category = "dev" optional = false @@ -1224,14 +1190,14 @@ requests = ">=2.5.0" snowballstemmer = ">=1.1" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-htmlhelp = "*" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" +sphinxcontrib-serializinghtml = "*" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.900)", "docutils-stubs", "types-typed-ast", "types-pkg-resources", "types-requests"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.800)", "docutils-stubs"] test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] @@ -1373,7 +1339,7 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.10.0.2" +version = "3.10.0.0" description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false @@ -1389,7 +1355,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "urllib3" -version = "1.26.6" +version = "1.26.5" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -1459,7 +1425,7 @@ typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [[package]] name = "zipp" -version = "3.5.0" +version = "3.4.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false @@ -1467,12 +1433,12 @@ python-versions = ">=3.6" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "ca2a0258a784674ff489a07d0dc8dd2a22373ee39add02cb4676898b8a6993a1" +content-hash = "8875d530ae66f9763b5b0cb84d9d35edc184ef5c141b63d38bf1ff5a1226e556" [metadata.files] acre = [] @@ -1536,8 +1502,8 @@ arrow = [ {file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"}, ] astroid = [ - {file = "astroid-2.7.3-py3-none-any.whl", hash = "sha256:dc1e8b28427d6bbef6b8842b18765ab58f558c42bb80540bd7648c98412af25e"}, - {file = "astroid-2.7.3.tar.gz", hash = "sha256:3b680ce0419b8a771aba6190139a3998d14b413852506d99aff8dc2bf65ee67c"}, + {file = "astroid-2.5.6-py3-none-any.whl", hash = "sha256:4db03ab5fc3340cf619dbc25e42c2cc3755154ce6009469766d7143d1fc2ee4e"}, + {file = "astroid-2.5.6.tar.gz", hash = "sha256:8a398dfce302c13f14bab13e2b14fe385d32b73f4e4853b9bdfb64598baa1975"}, ] async-timeout = [ {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, @@ -1560,8 +1526,8 @@ babel = [ {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, ] blessed = [ - {file = "blessed-1.18.1-py2.py3-none-any.whl", hash = "sha256:dd7c0d33db9a2e7f597b446996484d0ed46e1586239db064fb5025008937dcae"}, - {file = "blessed-1.18.1.tar.gz", hash = "sha256:8b09936def6bc06583db99b65636b980075733e13550cb6af262ce724a55da23"}, + {file = "blessed-1.18.0-py2.py3-none-any.whl", hash = "sha256:5b5e2f0563d5a668c282f3f5946f7b1abb70c85829461900e607e74d7725106e"}, + {file = "blessed-1.18.0.tar.gz", hash = "sha256:1312879f971330a1b7f2c6341f2ae7e2cbac244bfc9d0ecfbbecd4b0293bc755"}, ] cachetools = [ {file = "cachetools-4.2.2-py3-none-any.whl", hash = "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001"}, @@ -1572,60 +1538,48 @@ certifi = [ {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, ] cffi = [ - {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, - {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, - {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, - {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, - {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, - {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, - {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, - {file = "cffi-1.14.6-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534"}, - {file = "cffi-1.14.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a"}, - {file = "cffi-1.14.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5"}, - {file = "cffi-1.14.6-cp35-cp35m-win32.whl", hash = "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca"}, - {file = "cffi-1.14.6-cp35-cp35m-win_amd64.whl", hash = "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218"}, - {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, - {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, - {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, - {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, - {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, - {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, - {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, - {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, - {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, - {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, - {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, - {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, - {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, + {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"}, + {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"}, + {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"}, + {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"}, + {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"}, + {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"}, + {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"}, + {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"}, + {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"}, + {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"}, + {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"}, + {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"}, + {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, + {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, + {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, + {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, + {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, + {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, + {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, + {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, + {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, + {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, + {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, + {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, + {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, + {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, + {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, + {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, + {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, ] chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] -charset-normalizer = [ - {file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"}, - {file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"}, -] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, @@ -1701,25 +1655,30 @@ coverage = [ {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] cryptography = [ - {file = "cryptography-3.4.8-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14"}, - {file = "cryptography-3.4.8-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7"}, - {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e"}, - {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085"}, - {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b"}, - {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb"}, - {file = "cryptography-3.4.8-cp36-abi3-win32.whl", hash = "sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7"}, - {file = "cryptography-3.4.8-cp36-abi3-win_amd64.whl", hash = "sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc"}, - {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5"}, - {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af"}, - {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a"}, - {file = "cryptography-3.4.8-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06"}, - {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498"}, - {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7"}, - {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9"}, - {file = "cryptography-3.4.8-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e"}, - {file = "cryptography-3.4.8.tar.gz", hash = "sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c"}, + {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.6-cp36-cp36m-win32.whl", hash = "sha256:b3d3a6bcd1a07c50b4e1c907f14842642156110e63a99cd5c73b8a24751e9b97"}, + {file = "cx_Freeze-6.6-cp36-cp36m-win_amd64.whl", hash = "sha256:1935266ec644ea4f7e584985f44cefc0622a449a09980d990833a1a2afcadac8"}, + {file = "cx_Freeze-6.6-cp37-cp37m-win32.whl", hash = "sha256:1eac2b0f254319cc641ce25bd83337effd7936092562fde701f3ffb40e0274ec"}, + {file = "cx_Freeze-6.6-cp37-cp37m-win_amd64.whl", hash = "sha256:2bc46ef6d510811b6002f34a3ae4cbfdea44e18644febd2a404d3ee8e48a9fc4"}, + {file = "cx_Freeze-6.6-cp38-cp38-win32.whl", hash = "sha256:46eb50ebc46f7ae236d16c6a52671ab0f7bb479bea668da19f4b6de3cc413e9e"}, + {file = "cx_Freeze-6.6-cp38-cp38-win_amd64.whl", hash = "sha256:8c3b00476ce385bb58595bffce55aed031e5a6e16ab6e14d8bee9d1d569e46c3"}, + {file = "cx_Freeze-6.6-cp39-cp39-win32.whl", hash = "sha256:6e9340cbcf52d4836980ecc83ddba4f7704ff6654dd41168c146b74f512977ce"}, + {file = "cx_Freeze-6.6-cp39-cp39-win_amd64.whl", hash = "sha256:2fcf1c8b77ae5c06f45be3a9aff79e1dd808c0d624e97561f840dec5ea9b214a"}, + {file = "cx_Freeze-6.6.tar.gz", hash = "sha256:c4af8ad3f7e7d71e291c1dec5d0fb26bbe92df834b098ed35434c901fbd6762f"}, ] -cx-freeze = [] cx-logging = [ {file = "cx_Logging-3.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:9fcd297e5c51470521c47eff0f86ba844aeca6be97e13c3e2114ebdf03fa3c96"}, {file = "cx_Logging-3.0-cp36-cp36m-win32.whl", hash = "sha256:0df4be47c5022cc54316949e283403214568ef599817ced0c0972183d6d4fabb"}, @@ -1766,20 +1725,20 @@ gitdb = [ {file = "gitdb-4.0.7.tar.gz", hash = "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"}, ] gitpython = [ - {file = "GitPython-3.1.20-py3-none-any.whl", hash = "sha256:b1e1c269deab1b08ce65403cf14e10d2ef1f6c89e33ea7c5e5bb0222ea593b8a"}, - {file = "GitPython-3.1.20.tar.gz", hash = "sha256:df0e072a200703a65387b0cfdf0466e3bab729c0458cf6b7349d0e9877636519"}, + {file = "GitPython-3.1.17-py3-none-any.whl", hash = "sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135"}, + {file = "GitPython-3.1.17.tar.gz", hash = "sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"}, ] google-api-core = [ - {file = "google-api-core-1.31.2.tar.gz", hash = "sha256:8500aded318fdb235130bf183c726a05a9cb7c4b09c266bd5119b86cdb8a4d10"}, - {file = "google_api_core-1.31.2-py2.py3-none-any.whl", hash = "sha256:384459a0dc98c1c8cd90b28dc5800b8705e0275a673a7144a513ae80fc77950b"}, + {file = "google-api-core-1.30.0.tar.gz", hash = "sha256:0724d354d394b3d763bc10dfee05807813c5210f0bd9b8e2ddf6b6925603411c"}, + {file = "google_api_core-1.30.0-py2.py3-none-any.whl", hash = "sha256:92cd9e9f366e84bfcf2524e34d2dc244906c645e731962617ba620da1620a1e0"}, ] 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.35.0.tar.gz", hash = "sha256:b7033be9028c188ee30200b204ea00ed82ea1162e8ac1df4aa6ded19a191d88e"}, - {file = "google_auth-1.35.0-py2.py3-none-any.whl", hash = "sha256:997516b42ecb5b63e8d80f5632c1a61dddf41d2a4c2748057837e06e00014258"}, + {file = "google-auth-1.31.0.tar.gz", hash = "sha256:154f7889c5d679a6f626f36adb12afbd4dbb0a9a04ec575d989d6ba79c4fd65e"}, + {file = "google_auth-1.31.0-py2.py3-none-any.whl", hash = "sha256:6d47c79b5d09fbc7e8355fd9594cc4cf65fdde5d401c63951eaac4baa1ba2ae1"}, ] google-auth-httplib2 = [ {file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"}, @@ -1794,32 +1753,32 @@ httplib2 = [ {file = "httplib2-0.19.1.tar.gz", hash = "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d"}, ] idna = [ - {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, - {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] imagesize = [ {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, - {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, + {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, + {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, ] 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.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, - {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, + {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"}, {file = "jedi-0.13.3.tar.gz", hash = "sha256:2bb0603e3506f708e792c7f4ad8fc2a7a9d9c2d292a358fbbd58da531695595b"}, ] jeepney = [ - {file = "jeepney-0.7.1-py3-none-any.whl", hash = "sha256:1b5a0ea5c0e7b166b2f5895b91a08c14de8915afda4407fb5022a195224958ac"}, - {file = "jeepney-0.7.1.tar.gz", hash = "sha256:fa9e232dfa0c498bd0b8a3a73b8d8a31978304dcef0515adc859d4e096f96f4f"}, + {file = "jeepney-0.6.0-py3-none-any.whl", hash = "sha256:aec56c0eb1691a841795111e184e13cad504f7703b9a64f63020816afa79a8ae"}, + {file = "jeepney-0.6.0.tar.gz", hash = "sha256:7d59b6622675ca9e993a6bd38de845051d315f8b0c72cca3aef733a20b648657"}, ] jinja2 = [ {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, @@ -1865,22 +1824,12 @@ log4mongo = [ {file = "log4mongo-1.7.0.tar.gz", hash = "sha256:dc374617206162a0b14167fbb5feac01dbef587539a235dadba6200362984a68"}, ] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, @@ -1889,21 +1838,14 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, @@ -1913,9 +1855,6 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, @@ -1965,79 +1904,56 @@ multidict = [ ] opentimelineio = [] packaging = [ - {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, - {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, + {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, + {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] parso = [ {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.6-py2.py3-none-any.whl", hash = "sha256:3a130b266b3a36134dcc79c17b3c7ac9634f083825ca6ea9d8f557ee6195c9c8"}, - {file = "pathlib2-2.3.6.tar.gz", hash = "sha256:7d8bcb5555003cdf4a8d2872c538faa3a0f5d20630cb360e518ca3b981795e5f"}, + {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.3.2-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4"}, - {file = "Pillow-8.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a"}, - {file = "Pillow-8.3.2-cp310-cp310-win32.whl", hash = "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228"}, - {file = "Pillow-8.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875"}, - {file = "Pillow-8.3.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15ccb81a6ffc57ea0137f9f3ac2737ffa1d11f786244d719639df17476d399a7"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8f284dc1695caf71a74f24993b7c7473d77bc760be45f776a2c2f4e04c170550"}, - {file = "Pillow-8.3.2-cp36-cp36m-win32.whl", hash = "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073"}, - {file = "Pillow-8.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196"}, - {file = "Pillow-8.3.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1bd983c565f92779be456ece2479840ec39d386007cd4ae83382646293d681b"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4326ea1e2722f3dc00ed77c36d3b5354b8fb7399fb59230249ea6d59cbed90da"}, - {file = "Pillow-8.3.2-cp37-cp37m-win32.whl", hash = "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9"}, - {file = "Pillow-8.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3"}, - {file = "Pillow-8.3.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616"}, - {file = "Pillow-8.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bcb04ff12e79b28be6c9988f275e7ab69f01cc2ba319fb3114f87817bb7c74b6"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b9911ec70731711c3b6ebcde26caea620cbdd9dcb73c67b0730c8817f24711b"}, - {file = "Pillow-8.3.2-cp38-cp38-win32.whl", hash = "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341"}, - {file = "Pillow-8.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb"}, - {file = "Pillow-8.3.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9"}, - {file = "Pillow-8.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bff50ba9891be0a004ef48828e012babaaf7da204d81ab9be37480b9020a82b"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7dbfbc0020aa1d9bc1b0b8bcf255a7d73f4ad0336f8fd2533fcc54a4ccfb9441"}, - {file = "Pillow-8.3.2-cp39-cp39-win32.whl", hash = "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09"}, - {file = "Pillow-8.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:548794f99ff52a73a156771a0402f5e1c35285bd981046a502d7e4793e8facaa"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b68f565a4175e12e68ca900af8910e8fe48aaa48fd3ca853494f384e11c8bcd"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd4fd83aa912d7b89b4b4a1580d30e2a4242f3936882a3f433586e5ab97ed0d5"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0c8ebbfd439c37624db98f3877d9ed12c137cadd99dde2d2eae0dab0bbfc355"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96"}, - {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, -] -platformdirs = [ - {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, - {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, + {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-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8b56553c0345ad6dcb2e9b433ae47d67f95fc23fe28a0bde15a120f25257e291"}, + {file = "Pillow-8.2.0.tar.gz", hash = "sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1"}, ] pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] prefixed = [ {file = "prefixed-0.3.2-py2.py3-none-any.whl", hash = "sha256:5e107306462d63f2f03c529dbf11b0026fdfec621a9a008ca639d71de22995c3"}, @@ -2062,13 +1978,9 @@ protobuf = [ {file = "protobuf-3.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ae692bb6d1992afb6b74348e7bb648a75bb0d3565a3f5eea5bec8f62bd06d87"}, {file = "protobuf-3.17.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:99938f2a2d7ca6563c0ade0c5ca8982264c484fdecf418bd68e880a7ab5730b1"}, {file = "protobuf-3.17.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6902a1e4b7a319ec611a7345ff81b6b004b36b0d2196ce7a748b3493da3d226d"}, - {file = "protobuf-3.17.3-cp38-cp38-win32.whl", hash = "sha256:59e5cf6b737c3a376932fbfb869043415f7c16a0cf176ab30a5bbc419cd709c1"}, - {file = "protobuf-3.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ebcb546f10069b56dc2e3da35e003a02076aaa377caf8530fe9789570984a8d2"}, {file = "protobuf-3.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ffbd23640bb7403574f7aff8368e2aeb2ec9a5c6306580be48ac59a6bac8bde"}, {file = "protobuf-3.17.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:26010f693b675ff5a1d0e1bdb17689b8b716a18709113288fead438703d45539"}, {file = "protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76d9686e088fece2450dbc7ee905f9be904e427341d289acbe9ad00b78ebd47"}, - {file = "protobuf-3.17.3-cp39-cp39-win32.whl", hash = "sha256:a38bac25f51c93e4be4092c88b2568b9f407c27217d3dd23c7a57fa522a17554"}, - {file = "protobuf-3.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:85d6303e4adade2827e43c2b54114d9a6ea547b671cb63fafd5011dc47d0e13d"}, {file = "protobuf-3.17.3-py2.py3-none-any.whl", hash = "sha256:2bfb815216a9cd9faec52b16fd2bfa68437a44b67c56bee59bc3926522ecb04e"}, {file = "protobuf-3.17.3.tar.gz", hash = "sha256:72804ea5eaa9c22a090d2803813e280fb273b62d5ae497aaf3553d141c4fdd7b"}, ] @@ -2131,112 +2043,78 @@ pyflakes = [ {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pygments = [ - {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, - {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, + {file = "Pygments-2.9.0-py3-none-any.whl", hash = "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"}, + {file = "Pygments-2.9.0.tar.gz", hash = "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f"}, ] pylint = [ - {file = "pylint-2.10.2-py3-none-any.whl", hash = "sha256:e178e96b6ba171f8ef51fbce9ca30931e6acbea4a155074d80cc081596c9e852"}, - {file = "pylint-2.10.2.tar.gz", hash = "sha256:6758cce3ddbab60c52b57dcc07f0c5d779e5daf0cf50f6faacbef1d3ea62d2a1"}, + {file = "pylint-2.8.3-py3-none-any.whl", hash = "sha256:792b38ff30903884e4a9eab814ee3523731abd3c463f3ba48d7b627e87013484"}, + {file = "pylint-2.8.3.tar.gz", hash = "sha256:0a049c5d47b629d9070c3932d13bff482b12119b6a241a93bc460b0be16953c8"}, ] pymongo = [ - {file = "pymongo-3.12.0-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:072ba7cb65c8aa4d5c5659bf6722ee85781c9d7816dc00679b8b6f3dff1ddafc"}, - {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:d6e11ffd43184d529d6752d6dcb62b994f903038a17ea2168ef1910c96324d26"}, - {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7412a36798966624dc4c57d64aa43c2d1100b348abd98daaac8e99e57d87e1d7"}, - {file = "pymongo-3.12.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8a82e35d52ad6f867e88096a1a2b9bdc7ec4d5e65c7b4976a248bf2d1a32a93"}, - {file = "pymongo-3.12.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dcd3d0009fbb6e454d729f8b22d0063bd9171c31a55e0f0271119bd4f2700023"}, - {file = "pymongo-3.12.0-cp27-cp27m-win32.whl", hash = "sha256:1bc6fe7279ff40c6818db002bf5284aa03ec181ea1b1ceaeee33c289d412afa7"}, - {file = "pymongo-3.12.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e2b7670c0c8c6b501464150dd49dd0d6be6cb7f049e064124911cec5514fa19e"}, - {file = "pymongo-3.12.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:316c1b8723afa9870567cd6dff35d440b2afeda53aa13da6c5ab85f98ed6f5ca"}, - {file = "pymongo-3.12.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:255a35bf29185f44b412e31a927d9dcedda7c2c380127ecc4fbf2f61b72fa978"}, - {file = "pymongo-3.12.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ffbae429ba9e42d0582d3ac63fdb410338892468a2107d8ff68228ec9a39a0ed"}, - {file = "pymongo-3.12.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c188db6cf9e14dbbb42f5254292be96f05374a35e7dfa087cc2140f0ff4f10f6"}, - {file = "pymongo-3.12.0-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:6fb3f85870ae26896bb44e67db94045f2ebf00c5d41e6b66cdcbb5afd644fc18"}, - {file = "pymongo-3.12.0-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:aaa038eafb7186a4abbb311fcf20724be9363645882bbce540bef4797e812a7a"}, - {file = "pymongo-3.12.0-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:7d98ce3c42921bb91566121b658e0d9d59a9082a9bd6f473190607ff25ab637f"}, - {file = "pymongo-3.12.0-cp34-cp34m-win32.whl", hash = "sha256:b0a0cf39f589e52d801fdef418305562bc030cdf8929217463c8433c65fd5c2f"}, - {file = "pymongo-3.12.0-cp34-cp34m-win_amd64.whl", hash = "sha256:ceae3ab9e11a27aaab42878f1d203600dfd24f0e43678b47298219a0f10c0d30"}, - {file = "pymongo-3.12.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:5e574664f1468872cd40f74e4811e22b1aa4de9399d6bcfdf1ee6ea94c017fcf"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73b400fdc22de84bae0dbf1a22613928a41612ec0a3d6ed47caf7ad4d3d0f2ff"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:cbf8672edeb7b7128c4a939274801f0e32bbf5159987815e3d1eace625264a46"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:a634a4730ce0b0934ed75e45beba730968e12b4dafbb22f69b3b2f616d9e644e"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:c55782a55f4a013a78ac5b6ee4b8731a192dea7ab09f1b6b3044c96d5128edd4"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:11f9e0cfc84ade088a38df2708d0b958bb76360181df1b2e1e1a41beaa57952b"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:186104a94d39b8412f8e3de385acd990a628346a4402d4f3a288a82b8660bd22"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:70761fd3c576b027eec882b43ee0a8e5b22ff9c20cdf4d0400e104bc29e53e34"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:333bfad77aa9cd11711febfb75eed0bb537a1d022e1c252714dad38993590240"}, - {file = "pymongo-3.12.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fa8957e9a1b202cb45e6b839c241cd986c897be1e722b81d2f32e9c6aeee80b0"}, - {file = "pymongo-3.12.0-cp35-cp35m-win32.whl", hash = "sha256:4ba0def4abef058c0e5101e05e3d5266e6fffb9795bbf8be0fe912a7361a0209"}, - {file = "pymongo-3.12.0-cp35-cp35m-win_amd64.whl", hash = "sha256:a0e5dff6701fa615f165306e642709e1c1550d5b237c5a7a6ea299886828bd50"}, - {file = "pymongo-3.12.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:b542d56ed1b8d5cf3bb36326f814bd2fbe8812dfd2582b80a15689ea433c0e35"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a325600c83e61e3c9cebc0c2b1c8c4140fa887f789085075e8f44c8ff2547eb9"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:48d5bc80ab0af6b60c4163c5617f5cd23f2f880d7600940870ea5055816af024"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c5cab230e7cabdae9ff23c12271231283efefb944c1b79bed79a91beb65ba547"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d73e10772152605f6648ba4410318594f1043bbfe36d2fadee7c4b8912eff7c5"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:b1c4874331ab960429caca81acb9d2932170d66d6d6f87e65dc4507a85aca152"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:a3566acfbcde46911c52810374ecc0354fdb841284a3efef6ff7105bc007e9a8"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:b3b5b3cbc3fdf4fcfa292529df2a85b5d9c7053913a739d3069af1e12e12219f"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd3854148005c808c485c754a184c71116372263709958b42aefbef2e5dd373a"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f55c1ddcc1f6050b07d468ce594f55dbf6107b459e16f735d26818d7be1e9538"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ced944dcdd561476deef7cb7bfd4987c69fffbfeff6d02ca4d5d4fd592d559b7"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78ecb8d42f50d393af912bfb1fb1dcc9aabe9967973efb49ee577e8f1cea494c"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1970cfe2aec1bf74b40cf30c130ad10cd968941694630386db33e1d044c22a2e"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8bf42d3b32f586f4c9e37541769993783a534ad35531ce8a4379f6fa664fba9"}, - {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bc9ac81e73573516070d24ce15da91281922811f385645df32bd3c8a45ab4684"}, - {file = "pymongo-3.12.0-cp36-cp36m-win32.whl", hash = "sha256:d04ca462cb99077e6c059e97c072957caf2918e6e4191e3161c01c439e0193de"}, - {file = "pymongo-3.12.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f2acf9bbcd514e901f82c4ca6926bbd2ae61716728f110b4343eb0a69612d018"}, - {file = "pymongo-3.12.0-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:b754240daafecd9d5fce426b0fbaaed03f4ebb130745c8a4ae9231fffb8d75e5"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:af586e85144023686fb0af09c8cdf672484ea182f352e7ceead3d832de381e1b"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fe5872ce6f9627deac8314bdffd3862624227c3de4c17ef0cc78bbf0402999eb"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f6977a520bd96e097c8a37a8cbb9faa1ea99d21bf84190195056e25f688af73d"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:2dbfbbded947a83a3dffc2bd1ec4750c17e40904692186e2c55a3ad314ca0222"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:a752ecd1a26000a6d67be7c9a2e93801994a8b3f866ac95b672fbc00225ca91a"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:1bab889ae7640eba739f67fcbf8eff252dddc60d4495e6ddd3a87cd9a95fdb52"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:f94c7d22fb36b184734dded7345a04ec5f95130421c775b8b0c65044ef073f34"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec5ca7c0007ce268048bbe0ffc6846ed1616cf3d8628b136e81d5e64ff3f52a2"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c72d08acdf573455b2b9d2b75b8237654841d63a48bc2327dc102c6ee89b75a"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6ea08758b6673610b3c5bdf47189286cf9c58b1077558706a2f6f8744922527"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46d5ec90276f71af3a29917b30f2aec2315a2759b5f8d45b3b63a07ca8a070a3"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:625befa3bc9b40746a749115cc6a15bf20b9bd7597ca55d646205b479a2c99c7"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d1131562ddc2ea8a446f66c2648d7dabec2b3816fc818528eb978a75a6d23b2e"}, - {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eee42a1cc06565f6b21caa1f504ec15e07de7ebfd520ab57f8cb3308bc118e22"}, - {file = "pymongo-3.12.0-cp37-cp37m-win32.whl", hash = "sha256:94d38eba4d1b5eb3e6bfece0651b855a35c44f32fd91f512ab4ba41b8c0d3e66"}, - {file = "pymongo-3.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e018a4921657c2d3f89c720b7b90b9182e277178a04a7e9542cc79d7d787ca51"}, - {file = "pymongo-3.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7c6a9948916a7bbcc6d3a9f6fb75db1acb5546078023bfb3db6efabcd5a67527"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e9faf8d4712d5ea301d74abfcf6dafe4b7f4af7936e91f283b0ad7bf69ed3e3a"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cc2894fe91f31a513860238ede69fe47fada21f9e7ddfe73f7f9fef93a971e41"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:053b4ebf91c7395d1fcd2ce6a9edff0024575b7b2de6781554a4114448a8adc9"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:39dafa2eaf577d1969f289dc9a44501859a1897eb45bd589e93ce843fc610800"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:246ec420e4c8744fceb4e259f906211b9c198e1f345e6158dcd7cbad3737e11e"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:208debdcf76ed39ebf24f38509f50dc1c100e31e8653817fedb8e1f867850a13"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:18290649759f9db660972442aa606f845c368db9b08c4c73770f6da14113569b"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657ad80de8ec9ed656f28844efc801a0802961e8c6a85038d97ff6f555ef4919"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b772bab31cbd9cb911e41e1a611ebc9497f9a32a7348e2747c38210f75c00f41"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2399a85b54f68008e483b2871f4a458b4c980469c7fe921595ede073e4844f1e"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e66780f14c2efaf989cd3ac613b03ee6a8e3a0ba7b96c0bb14adca71a427e55"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02dc0b0f48ed3cd06c13b7e31b066bf91e00dac5f8147b0a0a45f9009bfab857"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:070a4ef689c9438a999ec3830e69b208ff0d12251846e064d947f97d819d1d05"}, - {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db93608a246da44d728842b8fa9e45aa9782db76955f634a707739a8d53ff544"}, - {file = "pymongo-3.12.0-cp38-cp38-win32.whl", hash = "sha256:5af390fa9faf56c93252dab09ea57cd020c9123aa921b63a0ed51832fdb492e7"}, - {file = "pymongo-3.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:a2239556ff7241584ce57be1facf25081669bb457a9e5cbe68cce4aae6567aa1"}, - {file = "pymongo-3.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cda9e628b1315beec8341e8c04aac9a0b910650b05e0751e42e399d5694aeacb"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:845a8b83798b2fb11b09928413cb32692866bfbc28830a433d9fa4c8c3720dd0"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:da8288bc4a7807c6715416deed1c57d94d5e03e93537889e002bf985be503f1a"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a9ba2a63777027b06b116e1ea8248e66fd1bedc2c644f93124b81a91ddbf6d88"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:9a13661681d17e43009bb3e85e837aa1ec5feeea1e3654682a01b8821940f8b3"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:6b89dc51206e4971c5568c797991eaaef5dc2a6118d67165858ad11752dba055"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:701e08457183da70ed96b35a6b43e6ba1df0b47c837b063cde39a1fbe1aeda81"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e7a33322e08021c37e89cae8ff06327503e8a1719e97c69f32c31cbf6c30d72c"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd1f49f949a658c4e8f81ed73f9aad25fcc7d4f62f767f591e749e30038c4e1d"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6d055f01b83b1a4df8bb0c61983d3bdffa913764488910af3620e5c2450bf83"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd6ff2192f34bd622883c745a56f492b1c9ccd44e14953e8051c33024a2947d5"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19d4bd0fc29aa405bb1781456c9cfff9fceabb68543741eb17234952dbc2bbb0"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24f8aeec4d6b894a6128844e50ff423dd02462ee83addf503c598ee3a80ddf3d"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b6055e0ef451ff73c93d0348d122a0750dddf323b9361de5835dac2f6cf7fc1"}, - {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6261bee7c5abadeac7497f8f1c43e521da78dd13b0a2439f526a7b0fc3788824"}, - {file = "pymongo-3.12.0-cp39-cp39-win32.whl", hash = "sha256:2e92aa32300a0b5e4175caec7769f482b292769807024a86d674b3f19b8e3755"}, - {file = "pymongo-3.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ce83f17f641a62a4dfb0ba1b8a3c1ced7c842f511b5450d90c030c7828e3693"}, - {file = "pymongo-3.12.0-py2.7-macosx-10.14-intel.egg", hash = "sha256:d1740776b70367277323fafb76bcf09753a5cc9824f5d705bac22a34ff3668ea"}, - {file = "pymongo-3.12.0.tar.gz", hash = "sha256:b88d1742159bc93a078733f9789f563cef26f5e370eba810476a71aa98e5fbc2"}, + {file = "pymongo-3.11.4-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:b7efc7e7049ef366777cfd35437c18a4166bb50a5606a1c840ee3b9624b54fc9"}, + {file = "pymongo-3.11.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:517ba47ca04a55b1f50ee8df9fd97f6c37df5537d118fb2718952b8623860466"}, + {file = "pymongo-3.11.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:225c61e08fe517aede7912937939e09adf086c8e6f7e40d4c85ad678c2c2aea3"}, + {file = "pymongo-3.11.4-cp27-cp27m-win32.whl", hash = "sha256:e4e9db78b71db2b1684ee4ecc3e32c4600f18cdf76e6b9ae03e338e52ee4b168"}, + {file = "pymongo-3.11.4-cp27-cp27m-win_amd64.whl", hash = "sha256:8e0004b0393d72d76de94b4792a006cb960c1c65c7659930fbf9a81ce4341982"}, + {file = "pymongo-3.11.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:fedf0dee7a412ca6d1d6d92c158fe9cbaa8ea0cae90d268f9ccc0744de7a97d0"}, + {file = "pymongo-3.11.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f947b359cc4769af8b49be7e37af01f05fcf15b401da2528021148e4a54426d1"}, + {file = "pymongo-3.11.4-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:3a3498a8326111221560e930f198b495ea6926937e249f475052ffc6893a6680"}, + {file = "pymongo-3.11.4-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:9a4f6e0b01df820ba9ed0b4e618ca83a1c089e48d4f268d0e00dcd49893d4549"}, + {file = "pymongo-3.11.4-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d65bac5f6724d9ea6f0b5a0f0e4952fbbf209adcf6b5583b54c54bd2fcd74dc0"}, + {file = "pymongo-3.11.4-cp34-cp34m-win32.whl", hash = "sha256:15b083d1b789b230e5ac284442d9ecb113c93f3785a6824f748befaab803b812"}, + {file = "pymongo-3.11.4-cp34-cp34m-win_amd64.whl", hash = "sha256:f08665d3cc5abc2f770f472a9b5f720a9b3ab0b8b3bb97c7c1487515e5653d39"}, + {file = "pymongo-3.11.4-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:977b1d4f868986b4ba5d03c317fde4d3b66e687d74473130cd598e3103db34fa"}, + {file = "pymongo-3.11.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:510cd3bfabb63a07405b7b79fae63127e34c118b7531a2cbbafc7a24fd878594"}, + {file = "pymongo-3.11.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:071552b065e809d24c5653fcc14968cfd6fde4e279408640d5ac58e3353a3c5f"}, + {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:f4ba58157e8ae33ee86fadf9062c506e535afd904f07f9be32731f4410a23b7f"}, + {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:b413117210fa6d92664c3d860571e8e8727c3e8f2ff197276c5d0cb365abd3ad"}, + {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:08b8723248730599c9803ae4c97b8f3f76c55219104303c88cb962a31e3bb5ee"}, + {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:8a41fdc751dc4707a4fafb111c442411816a7c225ebb5cadb57599534b5d5372"}, + {file = "pymongo-3.11.4-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:f664ed7613b8b18f0ce5696b146776266a038c19c5cd6efffa08ecc189b01b73"}, + {file = "pymongo-3.11.4-cp35-cp35m-win32.whl", hash = "sha256:5c36428cc4f7fae56354db7f46677fd21222fc3cb1e8829549b851172033e043"}, + {file = "pymongo-3.11.4-cp35-cp35m-win_amd64.whl", hash = "sha256:d0a70151d7de8a3194cdc906bcc1a42e14594787c64b0c1c9c975e5a2af3e251"}, + {file = "pymongo-3.11.4-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:9b9298964389c180a063a9e8bac8a80ed42de11d04166b20249bfa0a489e0e0f"}, + {file = "pymongo-3.11.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b2f41261b648cf5dee425f37ff14f4ad151c2f24b827052b402637158fd056ef"}, + {file = "pymongo-3.11.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e02beaab433fd1104b2804f909e694cfbdb6578020740a9051597adc1cd4e19f"}, + {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:8898f6699f740ca93a0879ed07d8e6db02d68af889d0ebb3d13ab017e6b1af1e"}, + {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:62c29bc36a6d9be68fe7b5aaf1e120b4aa66a958d1e146601fcd583eb12cae7b"}, + {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:424799c71ff435094e5fb823c40eebb4500f0e048133311e9c026467e8ccebac"}, + {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:3551912f5c34d8dd7c32c6bb00ae04192af47f7b9f653608f107d19c1a21a194"}, + {file = "pymongo-3.11.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:5db59223ed1e634d842a053325f85f908359c6dac9c8ddce8ef145061fae7df8"}, + {file = "pymongo-3.11.4-cp36-cp36m-win32.whl", hash = "sha256:fea5cb1c63efe1399f0812532c7cf65458d38fd011be350bc5021dfcac39fba8"}, + {file = "pymongo-3.11.4-cp36-cp36m-win_amd64.whl", hash = "sha256:d4e62417e89b717a7bcd8576ac3108cd063225942cc91c5b37ff5465fdccd386"}, + {file = "pymongo-3.11.4-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:4c7e8c8e1e1918dcf6a652ac4b9d87164587c26fd2ce5dd81e73a5ab3b3d492f"}, + {file = "pymongo-3.11.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38a7b5140a48fc91681cdb5cb95b7cd64640b43d19259fdd707fa9d5a715f2b2"}, + {file = "pymongo-3.11.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:aff3656af2add93f290731a6b8930b23b35c0c09569150130a58192b3ec6fc61"}, + {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:03be7ad107d252bb7325d4af6309fdd2c025d08854d35f0e7abc8bf048f4245e"}, + {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:6060794aac9f7b0644b299f46a9c6cbc0bc470bd01572f4134df140afd41ded6"}, + {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:73326b211e7410c8bd6a74500b1e3f392f39cf10862e243d00937e924f112c01"}, + {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:20d75ea11527331a2980ab04762a9d960bcfea9475c54bbeab777af880de61cd"}, + {file = "pymongo-3.11.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:3135dd574ef1286189f3f04a36c8b7a256376914f8cbbce66b94f13125ded858"}, + {file = "pymongo-3.11.4-cp37-cp37m-win32.whl", hash = "sha256:7c97554ea521f898753d9773891d0347ebfaddcc1dee2ad94850b163171bf1f1"}, + {file = "pymongo-3.11.4-cp37-cp37m-win_amd64.whl", hash = "sha256:a08c8b322b671857c81f4c30cd3c8df2895fd3c0e9358714f39e0ef8fb327702"}, + {file = "pymongo-3.11.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f3d851af3852f16ad4adc7ee054fd9c90a7a5063de94d815b7f6a88477b9f4c6"}, + {file = "pymongo-3.11.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3bfc7689a1bacb9bcd2f2d5185d99507aa29f667a58dd8adaa43b5a348139e46"}, + {file = "pymongo-3.11.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b8f94acd52e530a38f25e4d5bf7ddfdd4bea9193e718f58419def0d4406b58d3"}, + {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e4b631688dfbdd61b5610e20b64b99d25771c6d52d9da73349342d2a0f11c46a"}, + {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:474e21d0e07cd09679e357d1dac76e570dab86665e79a9d3354b10a279ac6fb3"}, + {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:421d13523d11c57f57f257152bc4a6bb463aadf7a3918e9c96fefdd6be8dbfb8"}, + {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:0cabfc297f4cf921f15bc789a8fbfd7115eb9f813d3f47a74b609894bc66ab0d"}, + {file = "pymongo-3.11.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:fe4189846448df013cd9df11bba38ddf78043f8c290a9f06430732a7a8601cce"}, + {file = "pymongo-3.11.4-cp38-cp38-win32.whl", hash = "sha256:eb4d176394c37a76e8b0afe54b12d58614a67a60a7f8c0dd3a5afbb013c01092"}, + {file = "pymongo-3.11.4-cp38-cp38-win_amd64.whl", hash = "sha256:fffff7bfb6799a763d3742c59c6ee7ffadda21abed557637bc44ed1080876484"}, + {file = "pymongo-3.11.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:13acf6164ead81c9fc2afa0e1ea6d6134352973ce2bb35496834fee057063c04"}, + {file = "pymongo-3.11.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d360e5d5dd3d55bf5d1776964625018d85b937d1032bae1926dd52253decd0db"}, + {file = "pymongo-3.11.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:0aaf4d44f1f819360f9432df538d54bbf850f18152f34e20337c01b828479171"}, + {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:08bda7b2c522ff9f1e554570da16298271ebb0c56ab9699446aacba249008988"}, + {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:1a994a42f49dab5b6287e499be7d3d2751776486229980d8857ad53b8333d469"}, + {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:161fcd3281c42f644aa8dec7753cca2af03ce654e17d76da4f0dab34a12480ca"}, + {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:78f07961f4f214ea8e80be63cffd5cc158eb06cd922ffbf6c7155b11728f28f9"}, + {file = "pymongo-3.11.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:ad31f184dcd3271de26ab1f9c51574afb99e1b0e484ab1da3641256b723e4994"}, + {file = "pymongo-3.11.4-cp39-cp39-win32.whl", hash = "sha256:5e606846c049ed40940524057bfdf1105af6066688c0e6a1a3ce2038589bae70"}, + {file = "pymongo-3.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:3491c7de09e44eded16824cb58cf9b5cc1dc6f066a0bb7aa69929d02aa53b828"}, + {file = "pymongo-3.11.4-py2.7-macosx-10.14-intel.egg", hash = "sha256:506a6dab4c7ffdcacdf0b8e70bd20eb2e77fa994519547c9d88d676400fcad58"}, + {file = "pymongo-3.11.4.tar.gz", hash = "sha256:539d4cb1b16b57026999c53e5aab857fe706e70ae5310cc8c232479923f932e6"}, ] pynput = [ {file = "pynput-1.7.3-py2.py3-none-any.whl", hash = "sha256:fea5777454f896bd79d35393088cd29a089f3b2da166f0848a922b1d5a807d4f"}, @@ -2272,47 +2150,27 @@ pyparsing = [ {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] pyrsistent = [ - {file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"}, - {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d"}, - {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2"}, - {file = "pyrsistent-0.18.0-cp36-cp36m-win32.whl", hash = "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1"}, - {file = "pyrsistent-0.18.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7"}, - {file = "pyrsistent-0.18.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396"}, - {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710"}, - {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35"}, - {file = "pyrsistent-0.18.0-cp37-cp37m-win32.whl", hash = "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f"}, - {file = "pyrsistent-0.18.0-cp37-cp37m-win_amd64.whl", hash = "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2"}, - {file = "pyrsistent-0.18.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427"}, - {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef"}, - {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c"}, - {file = "pyrsistent-0.18.0-cp38-cp38-win32.whl", hash = "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78"}, - {file = "pyrsistent-0.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b"}, - {file = "pyrsistent-0.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4"}, - {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680"}, - {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426"}, - {file = "pyrsistent-0.18.0-cp39-cp39-win32.whl", hash = "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b"}, - {file = "pyrsistent-0.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea"}, - {file = "pyrsistent-0.18.0.tar.gz", hash = "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b"}, + {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, ] pytest = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, + {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, + {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, ] pytest-cov = [ {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, ] pytest-print = [ - {file = "pytest_print-0.3.0-py2.py3-none-any.whl", hash = "sha256:53fb0f71d371f137ac2e7171d92f204eb45055580e8c7920df619d9b2ee45359"}, - {file = "pytest_print-0.3.0.tar.gz", hash = "sha256:769f1b1b0943b2941dbeeaac6985766e76b341130ed538f88c23ebcd7087b90d"}, + {file = "pytest_print-0.2.1-py2.py3-none-any.whl", hash = "sha256:2cfcdeee8b398457d3e3488f1fde5f8303b404c30187be5fcb4c7818df5f4529"}, + {file = "pytest_print-0.2.1.tar.gz", hash = "sha256:8f61e5bb2d031ee88d19a5a7695a0c863caee7b1478f1a82d080c2128b76ad83"}, ] python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, + {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, ] python-xlib = [ - {file = "python-xlib-0.31.tar.gz", hash = "sha256:74d83a081f532bc07f6d7afcd6416ec38403d68f68b9b9dc9e1f28fbf2d799e9"}, - {file = "python_xlib-0.31-py2.py3-none-any.whl", hash = "sha256:1ec6ce0de73d9e6592ead666779a5732b384e5b8fb1f1886bd0a81cafa477759"}, + {file = "python-xlib-0.30.tar.gz", hash = "sha256:74131418faf9e7b83178c71d9d80297fbbd678abe99ae9258f5a20cd027acb5f"}, + {file = "python_xlib-0.30-py2.py3-none-any.whl", hash = "sha256:c4c92cd47e07588b2cbc7d52de18407b2902c3812d7cdec39cd2177b060828e2"}, ] python3-xlib = [ {file = "python3-xlib-0.15.tar.gz", hash = "sha256:dc4245f3ae4aa5949c1d112ee4723901ade37a96721ba9645f2bfa56e5b383f8"}, @@ -2338,16 +2196,16 @@ pywin32-ctypes = [ {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, ] "qt.py" = [ - {file = "Qt.py-1.3.6-py2.py3-none-any.whl", hash = "sha256:7edf6048d07a6924707506b5ba34a6e05d66dde9a3f4e3a62f9996ccab0b91c7"}, - {file = "Qt.py-1.3.6.tar.gz", hash = "sha256:0d78656a2f814602eee304521c7bf5da0cec414818b3833712c77524294c404a"}, + {file = "Qt.py-1.3.3-py2.py3-none-any.whl", hash = "sha256:9e3f5417187c98d246918a9b27a9e1f8055e089bdb2b063a2739986bc19a3d2e"}, + {file = "Qt.py-1.3.3.tar.gz", hash = "sha256:601606127f70be9adc82c248d209d696cccbd1df242c24d3fb1a9e399f3ecaf1"}, ] recommonmark = [ {file = "recommonmark-0.7.1-py2.py3-none-any.whl", hash = "sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f"}, {file = "recommonmark-0.7.1.tar.gz", hash = "sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67"}, ] requests = [ - {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, - {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, + {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, + {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, ] rsa = [ {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, @@ -2366,8 +2224,8 @@ six = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] slack-sdk = [ - {file = "slack_sdk-3.10.1-py2.py3-none-any.whl", hash = "sha256:f17b71a578e94204d9033bffded634475f4ca0a6274c6c7a4fd8a9cb0ac7cd8b"}, - {file = "slack_sdk-3.10.1.tar.gz", hash = "sha256:2b4dde7728eb4ff5a581025d204578ccff25a5d8f0fe11ae175e3ce6e074434f"}, + {file = "slack_sdk-3.6.0-py2.py3-none-any.whl", hash = "sha256:e1b257923a1ef88b8620dd3abff94dc5b3eee16ef37975d101ba9e60123ac3af"}, + {file = "slack_sdk-3.6.0.tar.gz", hash = "sha256:195f044e02a2844579a7a26818ce323e85dde8de224730c859644918d793399e"}, ] smmap = [ {file = "smmap-4.0.0-py2.py3-none-any.whl", hash = "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"}, @@ -2382,8 +2240,8 @@ speedcopy = [ {file = "speedcopy-2.1.0.tar.gz", hash = "sha256:8bb1a6c735900b83901a7be84ba2175ed3887c13c6786f97dea48f2ea7d504c2"}, ] sphinx = [ - {file = "Sphinx-4.1.2-py3-none-any.whl", hash = "sha256:46d52c6cee13fec44744b8c01ed692c18a640f6910a725cbb938bc36e8d64544"}, - {file = "Sphinx-4.1.2.tar.gz", hash = "sha256:3092d929cd807926d846018f2ace47ba2f3b671b309c7a89cd3306e80c826b13"}, + {file = "Sphinx-4.0.2-py3-none-any.whl", hash = "sha256:d1cb10bee9c4231f1700ec2e24a91be3f3a3aba066ea4ca9f3bbe47e59d5a1d4"}, + {file = "Sphinx-4.0.2.tar.gz", hash = "sha256:b5c2ae4120bf00c799ba9b3699bc895816d272d120080fbc967292f29b52b48c"}, ] sphinx-qt-documentation = [ {file = "sphinx_qt_documentation-0.3-py3-none-any.whl", hash = "sha256:bee247cb9e4fc03fc496d07adfdb943100e1103320c3e5e820e0cfa7c790d9b6"}, @@ -2461,17 +2319,17 @@ typed-ast = [ {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, + {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, + {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, + {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, ] uritemplate = [ {file = "uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"}, {file = "uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"}, ] urllib3 = [ - {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, - {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, + {file = "urllib3-1.26.5-py2.py3-none-any.whl", hash = "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c"}, + {file = "urllib3-1.26.5.tar.gz", hash = "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, @@ -2528,6 +2386,6 @@ yarl = [ {file = "yarl-1.6.3.tar.gz", hash = "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10"}, ] zipp = [ - {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, - {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, + {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, + {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, ] From 7a34b728e33ba709faee0e2d3767aeac2b419109 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 19:18:34 +0200 Subject: [PATCH 076/150] change cx freeze --- poetry.lock | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index e43c788d74..357623b74d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -272,15 +272,20 @@ test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pret [[package]] name = "cx-freeze" -version = "6.6" +version = "6.7" description = "Create standalone executables from Python scripts" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -cx-Logging = {version = ">=3.0", markers = "sys_platform == \"win32\""} -importlib-metadata = ">=3.1.1" +cx-logging = {version = ">=3.0", markers = "sys_platform == \"win32\""} +importlib-metadata = ">=4.3.1" + +[package.source] +type = "legacy" +url = "https://distribute.openpype.io/wheels" +reference = "openpype" [[package]] name = "cx-logging" @@ -1668,17 +1673,7 @@ cryptography = [ {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.6-cp36-cp36m-win32.whl", hash = "sha256:b3d3a6bcd1a07c50b4e1c907f14842642156110e63a99cd5c73b8a24751e9b97"}, - {file = "cx_Freeze-6.6-cp36-cp36m-win_amd64.whl", hash = "sha256:1935266ec644ea4f7e584985f44cefc0622a449a09980d990833a1a2afcadac8"}, - {file = "cx_Freeze-6.6-cp37-cp37m-win32.whl", hash = "sha256:1eac2b0f254319cc641ce25bd83337effd7936092562fde701f3ffb40e0274ec"}, - {file = "cx_Freeze-6.6-cp37-cp37m-win_amd64.whl", hash = "sha256:2bc46ef6d510811b6002f34a3ae4cbfdea44e18644febd2a404d3ee8e48a9fc4"}, - {file = "cx_Freeze-6.6-cp38-cp38-win32.whl", hash = "sha256:46eb50ebc46f7ae236d16c6a52671ab0f7bb479bea668da19f4b6de3cc413e9e"}, - {file = "cx_Freeze-6.6-cp38-cp38-win_amd64.whl", hash = "sha256:8c3b00476ce385bb58595bffce55aed031e5a6e16ab6e14d8bee9d1d569e46c3"}, - {file = "cx_Freeze-6.6-cp39-cp39-win32.whl", hash = "sha256:6e9340cbcf52d4836980ecc83ddba4f7704ff6654dd41168c146b74f512977ce"}, - {file = "cx_Freeze-6.6-cp39-cp39-win_amd64.whl", hash = "sha256:2fcf1c8b77ae5c06f45be3a9aff79e1dd808c0d624e97561f840dec5ea9b214a"}, - {file = "cx_Freeze-6.6.tar.gz", hash = "sha256:c4af8ad3f7e7d71e291c1dec5d0fb26bbe92df834b098ed35434c901fbd6762f"}, -] +cx-freeze = [] cx-logging = [ {file = "cx_Logging-3.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:9fcd297e5c51470521c47eff0f86ba844aeca6be97e13c3e2114ebdf03fa3c96"}, {file = "cx_Logging-3.0-cp36-cp36m-win32.whl", hash = "sha256:0df4be47c5022cc54316949e283403214568ef599817ced0c0972183d6d4fabb"}, From 0e9ece13e97fc9abec2ad82276db423fd0cdd476 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 22 Sep 2021 19:18:50 +0200 Subject: [PATCH 077/150] define requests version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9cbf4e5383..8d329cc2b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ jinxed = [ python3-xlib = { version="*", markers = "sys_platform == 'linux'"} enlighten = "^1.9.0" slack-sdk = "^3.6.0" +requests = "2.25.1" [tool.poetry.dev-dependencies] flake8 = "^3.7" @@ -86,7 +87,6 @@ wheel = "*" enlighten = "*" # cool terminal progress bars toml = "^0.10.2" # for parsing pyproject.toml - [tool.poetry.urls] "Bug Tracker" = "https://github.com/pypeclub/openpype/issues" "Discussions" = "https://github.com/pypeclub/openpype/discussions" From 3cff1e38a870cc13bc343c39437c9b92e08c704a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Sep 2021 15:59:07 +0200 Subject: [PATCH 078/150] added info about thirdparty python modules and about PySide2 --- website/docs/dev_build.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/website/docs/dev_build.md b/website/docs/dev_build.md index f71118eba6..bf606ae7c0 100644 --- a/website/docs/dev_build.md +++ b/website/docs/dev_build.md @@ -19,6 +19,7 @@ We use [CX_Freeze](https://cx-freeze.readthedocs.io/en/latest) to freeze the cod This is outline of build steps. Most of them are done automatically via scripts: - Virtual environment is created using **Poetry** in `.venv` +- Necessary python modules outside of `.venv` are stored to `./vendor/python` (like `PySide2`) - Necessary third-party tools (like [ffmpeg](https://www.ffmpeg.org/), [OpenImageIO](https://github.com/OpenImageIO/oiio) and [usd libraries](https://developer.nvidia.com/usd)) are downloaded to `./vendor/bin` - OpenPype code is frozen with **cx_freeze** to `./build` @@ -55,14 +56,14 @@ For development purposes it is possible to run OpenPype directly from the source To start OpenPype from source you need to 1. Run `.\tools\create_env.ps1` to create virtual environment in `.venv` -2. Run `.\tools\fetch_thirdparty_libs.ps1` to get **ffmpeg**, **oiio** and other tools needed. +2. Run `.\tools\fetch_thirdparty_libs.ps1` to get **PySide2**, **ffmpeg**, **oiio** and other tools needed. 3. Run `.\tools\run_tray.ps1` if you have all required dependencies on your machine you should be greeted with OpenPype igniter window and once you give it your Mongo URL, with OpenPype icon in the system tray. Step 1 and 2 needs to be run only once (or when something was changed). #### To build OpenPype: 1. Run `.\tools\create_env.ps1` to create virtual environment in `.venv` -2. Run `.\tools\fetch_thirdparty_libs.ps1` to get **ffmpeg**, **oiio** and other tools needed. +2. Run `.\tools\fetch_thirdparty_libs.ps1` to get **PySide2**, **ffmpeg**, **oiio** and other tools needed. 3. `.\tools\build.ps1` to build OpenPype to `.\build` @@ -185,7 +186,7 @@ For more information about setting your build environment please refer to [pyenv #### To build Pype: 1. Run `./tools/create_env.sh` to create virtual environment in `./venv` -2. Run `./tools/fetch_thirdparty_libs.sh` to get **ffmpeg**, **oiio** and other tools needed. +2. Run `./tools/fetch_thirdparty_libs.sh` to get **PySide2**, **ffmpeg**, **oiio** and other tools needed. 3. Run `./tools/build.sh` to build pype executables in `.\build\` @@ -273,6 +274,19 @@ pywin32 = { version = "300", markers = "sys_platform == 'win32'" } For more information see [Poetry documentation](https://python-poetry.org/docs/dependency-specification/). +### Python modules as thirdparty +There are some python modules that can be available only in OpenPype and should not be propagated to any subprocess. +Best example is **PySide2** which is required to run OpenPype but can be used only in OpenPype and should not be in PYTHONPATH for most of host applications. +We've decided to separate these breaking dependencies to be able run OpenPype from code and from build the same way. + +:::warning +**PySide2** has handled special cases related to it's build process. +### Linux +- We're fixing rpath of shared objects on linux which is modified during cx freeze processing. +### MacOS +- **QtSql** libraries are removed on MacOS because their dependencies are not available and would require to modify rpath of Postgre library. +::: + ### Binary dependencies To add some binary tool or something that doesn't fit standard Python distribution methods, you can use [fetch_thirdparty_libs](#fetch_thirdparty_libs) script. It will take things defined in From b7fee7f332a76d9d1249b5e1853828b2947e5220 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Sep 2021 16:03:25 +0200 Subject: [PATCH 079/150] remove sql drivers on mac --- tools/fetch_thirdparty_libs.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tools/fetch_thirdparty_libs.py b/tools/fetch_thirdparty_libs.py index 803d092186..b616beab27 100644 --- a/tools/fetch_thirdparty_libs.py +++ b/tools/fetch_thirdparty_libs.py @@ -78,18 +78,28 @@ except AttributeError: _print("No PySide2 version was specified, using latest available.", 2) pyside2_arg = "PySide2" if not pyside2_version else "PySide2{}".format(pyside2_version) # noqa: E501 +python_vendor_dir = openpype_root / "vendor" / "python" try: subprocess.run( [sys.executable, "-m", "pip", "install", "--upgrade", - pyside2_arg, "-t", str(openpype_root / "vendor/python")], + pyside2_arg, "-t", str(python_vendor_dir)], check=True, stdout=subprocess.DEVNULL) except subprocess.CalledProcessError as e: _print("Error during PySide2 installation.", 1) _print(str(e), 1) sys.exit(1) -_print("Processing third-party dependencies ...") +# Remove libraries for QtSql which don't have available libraries +# by default and Postgre library would require to modify rpath of dependency platform_name = platform.system().lower() +if platform_name == "darwin": + pyside2_sqldrivers_dir = ( + python_vendor_dir / "PySide2" / "Qt" / "plugins" / "sqldrivers" + ) + for filepath in pyside2_sqldrivers_dir.iterdir(): + os.remove(str(filepath)) + +_print("Processing third-party dependencies ...") try: thirdparty = pyproject["openpype"]["thirdparty"] From de69cd69c75596da40755d6cb3bc8f9d19ad1f3a Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 23 Sep 2021 16:42:54 +0200 Subject: [PATCH 080/150] support `` token for directories --- .../maya/plugins/publish/collect_render.py | 21 +++++++++++++++++++ .../plugins/publish/submit_maya_deadline.py | 6 ++++++ 2 files changed, 27 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index 46d1c9350d..1c9b6c95ef 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -205,12 +205,14 @@ class CollectMayaRender(pyblish.api.ContextPlugin): # replace relative paths with absolute. Render products are # returned as list of dictionaries. + publish_meta_path = None for aov in exp_files: full_paths = [] for file in aov[aov.keys()[0]]: full_path = os.path.join(workspace, "renders", file) full_path = full_path.replace("\\", "/") full_paths.append(full_path) + publish_meta_path = os.path.dirname(full_path) aov_dict[aov.keys()[0]] = full_paths frame_start_render = int(self.get_render_attribute( @@ -236,6 +238,24 @@ class CollectMayaRender(pyblish.api.ContextPlugin): frame_end_handle = frame_end_render full_exp_files.append(aov_dict) + + # find common path to store metadata + # so if image prefix is branching to many directories + # metadata file will be located in top-most common + # directory. + # TODO: use `os.path.commonpath()` after switch to Python 3 + common_publish_meta_path = os.path.splitdrive( + publish_meta_path)[0] + if common_publish_meta_path: + common_publish_meta_path += os.path.sep + for part in publish_meta_path.split("/"): + common_publish_meta_path = os.path.join( + common_publish_meta_path, part) + if part == expected_layer_name: + break + common_publish_meta_path = common_publish_meta_path.replace("\\", "/") + self.log.info("Publish meta path: {}".format(common_publish_meta_path)) + self.log.info(full_exp_files) self.log.info("collecting layer: {}".format(layer_name)) # Get layer specific settings, might be overrides @@ -268,6 +288,7 @@ class CollectMayaRender(pyblish.api.ContextPlugin): # which was submitted originally "source": filepath, "expectedFiles": full_exp_files, + "publishRenderMetadataFolder": common_publish_meta_path, "resolutionWidth": cmds.getAttr("defaultResolution.width"), "resolutionHeight": cmds.getAttr("defaultResolution.height"), "pixelAspect": cmds.getAttr("defaultResolution.pixelAspect"), diff --git a/openpype/modules/default_modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/default_modules/deadline/plugins/publish/submit_maya_deadline.py index 1ab3dc2554..5936e600ee 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/submit_maya_deadline.py @@ -351,6 +351,12 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): f.replace(orig_scene, new_scene) ) instance.data["expectedFiles"] = [new_exp] + + if instance.data.get("publishRenderMetadataFolder"): + instance.data["publishRenderMetadataFolder"] = \ + instance.data["publishRenderMetadataFolder"].replace( + orig_scene, new_scene + ) self.log.info("Scene name was switched {} -> {}".format( orig_scene, new_scene )) From ee7ebc11fac6f9e9c1ff9fab4a2d56385ae3e23c Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 23 Sep 2021 17:41:45 +0200 Subject: [PATCH 081/150] =?UTF-8?q?fix=20hound=20=F0=9F=90=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/hosts/maya/api/lib_renderproducts.py | 32 +++++++++++-------- .../maya/plugins/publish/collect_render.py | 6 ++-- .../plugins/publish/submit_maya_deadline.py | 3 +- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index 39d894a204..bdb1c619ff 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -482,8 +482,9 @@ class RenderProductsArnold(ARenderProducts): if not cameras: cameras = [ self.sanitize_camera_name( - self.get_renderable_cameras()[0]) - ] + self.get_renderable_cameras()[0] + ) + ] for ai_driver in ai_drivers: # todo: check aiAOVDriver.prefix as it could have @@ -552,11 +553,13 @@ class RenderProductsArnold(ARenderProducts): # Render Product per selected light group aov_light_group_name = "{}_{}".format(name, light_group) for camera in cameras: - product = RenderProduct(productName=aov_light_group_name, - aov=aov_name, - driver=ai_driver, - ext=ext, - camera=camera) + product = RenderProduct( + productName=aov_light_group_name, + aov=aov_name, + driver=ai_driver, + ext=ext, + camera=camera + ) products.append(product) return products @@ -608,7 +611,9 @@ class RenderProductsArnold(ARenderProducts): "" in self.layer_data.filePrefix.lower() ) if not has_renderpass_token: - return [setattr(bp, "multipart", True) for bp in beauty_products] + for product in beauty_products: + product.multipart = True + return beauty_products # AOVs are set to be rendered separately. We should expect # token in path. @@ -988,11 +993,12 @@ class RenderProductsRedshift(ARenderProducts): aov_light_group_name = "{}_{}".format(aov_name, light_group) for camera in cameras: - product = RenderProduct(productName=aov_light_group_name, - aov=aov_name, - ext=ext, - multipart=aov_multipart, - camera=camera) + product = RenderProduct( + productName=aov_light_group_name, + aov=aov_name, + ext=ext, + multipart=aov_multipart, + camera=camera) products.append(product) if light_groups: diff --git a/openpype/hosts/maya/plugins/publish/collect_render.py b/openpype/hosts/maya/plugins/publish/collect_render.py index 1c9b6c95ef..575cc2456b 100644 --- a/openpype/hosts/maya/plugins/publish/collect_render.py +++ b/openpype/hosts/maya/plugins/publish/collect_render.py @@ -253,8 +253,10 @@ class CollectMayaRender(pyblish.api.ContextPlugin): common_publish_meta_path, part) if part == expected_layer_name: break - common_publish_meta_path = common_publish_meta_path.replace("\\", "/") - self.log.info("Publish meta path: {}".format(common_publish_meta_path)) + common_publish_meta_path = common_publish_meta_path.replace( + "\\", "/") + self.log.info( + "Publish meta path: {}".format(common_publish_meta_path)) self.log.info(full_exp_files) self.log.info("collecting layer: {}".format(layer_name)) diff --git a/openpype/modules/default_modules/deadline/plugins/publish/submit_maya_deadline.py b/openpype/modules/default_modules/deadline/plugins/publish/submit_maya_deadline.py index 5936e600ee..2d43b0d085 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/submit_maya_deadline.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/submit_maya_deadline.py @@ -355,8 +355,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): if instance.data.get("publishRenderMetadataFolder"): instance.data["publishRenderMetadataFolder"] = \ instance.data["publishRenderMetadataFolder"].replace( - orig_scene, new_scene - ) + orig_scene, new_scene) self.log.info("Scene name was switched {} -> {}".format( orig_scene, new_scene )) From f907eb00fbc6d03772a9b7da8cefafb5b6565fab Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 23 Sep 2021 17:43:41 +0200 Subject: [PATCH 082/150] =?UTF-8?q?fix=20hound=20=F0=9F=90=95=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/hosts/maya/api/lib_renderproducts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index bdb1c619ff..b198052c93 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -482,7 +482,7 @@ class RenderProductsArnold(ARenderProducts): if not cameras: cameras = [ self.sanitize_camera_name( - self.get_renderable_cameras()[0] + self.get_renderable_cameras()[0] ) ] From 22664f777d1dece5db6279092549b09303b6d4bf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Sep 2021 18:04:41 +0200 Subject: [PATCH 083/150] removed not needed packages --- Dockerfile.centos7 | 3 --- 1 file changed, 3 deletions(-) diff --git a/Dockerfile.centos7 b/Dockerfile.centos7 index 67d45ce3b2..f3b257e66b 100644 --- a/Dockerfile.centos7 +++ b/Dockerfile.centos7 @@ -41,9 +41,6 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n ncurses \ ncurses-devel \ qt5-qtbase-devel \ - libxcb libxcb-devel \ - xcb-util xcb-util-devel \ - libxkbcommon-devel libxkbcommon-x11-devel \ && yum clean all # we need to build our own patchelf From 8b11a574c4b504f269c88a347362e3b1e6afa299 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Mon, 27 Sep 2021 09:30:51 +0100 Subject: [PATCH 084/150] Update get_task_time --- .../timers_manager/timers_manager.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/openpype/modules/default_modules/timers_manager/timers_manager.py b/openpype/modules/default_modules/timers_manager/timers_manager.py index 69f7c26fc2..829a6badb4 100644 --- a/openpype/modules/default_modules/timers_manager/timers_manager.py +++ b/openpype/modules/default_modules/timers_manager/timers_manager.py @@ -106,13 +106,14 @@ class TimersManager( self.timer_started(None, data) def get_task_time(self, project_name, asset_name, task_name): - time = {} - for module in self.modules: - time[module.name] = module.get_task_time( - project_name, asset_name, task_name - ) - - return time + times = {} + for module_id, connector in self._connectors_by_module_id.items(): + if hasattr(connector, "get_task_time"): + module = self._modules_by_id[module_id] + times[module.name] = connector.get_task_time( + project_name, asset_name, task_name + ) + return times def timer_started(self, source_id, data): for module in self.modules: From 9d6c2583ed7f822b90619a793fdb9c8e009d5c33 Mon Sep 17 00:00:00 2001 From: karimmozilla Date: Mon, 27 Sep 2021 11:36:29 +0200 Subject: [PATCH 085/150] Change mayaAscii family to mayaScene --- openpype/hosts/maya/plugins/create/create_mayaascii.py | 6 +++--- openpype/hosts/maya/plugins/load/load_reference.py | 4 ++-- openpype/hosts/maya/plugins/publish/collect_mayaascii.py | 4 ++-- .../hosts/maya/plugins/publish/extract_maya_scene_raw.py | 2 +- openpype/plugins/publish/collect_resources_path.py | 2 +- openpype/plugins/publish/integrate_new.py | 2 +- openpype/settings/defaults/project_settings/global.json | 2 +- openpype/settings/defaults/project_settings/maya.json | 2 +- .../schemas/projects_schema/schemas/schema_maya_load.json | 2 +- website/docs/pype2/admin_presets_plugins.md | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_mayaascii.py b/openpype/hosts/maya/plugins/create/create_mayaascii.py index f51e126c00..5ce634cec4 100644 --- a/openpype/hosts/maya/plugins/create/create_mayaascii.py +++ b/openpype/hosts/maya/plugins/create/create_mayaascii.py @@ -1,11 +1,11 @@ from openpype.hosts.maya.api import plugin -class CreateMayaAscii(plugin.Creator): +class CreateMayaScene(plugin.Creator): """Raw Maya Ascii file export""" - name = "mayaAscii" + name = "mayaScene" label = "Maya Ascii" - family = "mayaAscii" + family = "mayaScene" icon = "file-archive-o" defaults = ['Main'] diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index d5952ed267..544544a823 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -12,7 +12,7 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): families = ["model", "pointcache", "animation", - "mayaAscii", + "mayaScene", "setdress", "layout", "camera", @@ -71,7 +71,7 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): except: # noqa: E722 pass - if family not in ["layout", "setdress", "mayaAscii"]: + if family not in ["layout", "setdress", "mayaScene"]: for root in roots: root.setParent(world=True) diff --git a/openpype/hosts/maya/plugins/publish/collect_mayaascii.py b/openpype/hosts/maya/plugins/publish/collect_mayaascii.py index b02f61b7c6..199fb4197c 100644 --- a/openpype/hosts/maya/plugins/publish/collect_mayaascii.py +++ b/openpype/hosts/maya/plugins/publish/collect_mayaascii.py @@ -3,14 +3,14 @@ from maya import cmds import pyblish.api -class CollectMayaAscii(pyblish.api.InstancePlugin): +class CollectMayaScene(pyblish.api.InstancePlugin): """Collect May Ascii Data """ order = pyblish.api.CollectorOrder + 0.2 label = 'Collect Model Data' - families = ["mayaAscii"] + families = ["mayaScene"] def process(self, instance): # Extract only current frame (override) diff --git a/openpype/hosts/maya/plugins/publish/extract_maya_scene_raw.py b/openpype/hosts/maya/plugins/publish/extract_maya_scene_raw.py index 3c2b70900d..ccae7351dc 100644 --- a/openpype/hosts/maya/plugins/publish/extract_maya_scene_raw.py +++ b/openpype/hosts/maya/plugins/publish/extract_maya_scene_raw.py @@ -16,7 +16,7 @@ class ExtractMayaSceneRaw(openpype.api.Extractor): label = "Maya Scene (Raw)" hosts = ["maya"] - families = ["mayaAscii", + families = ["mayaScene", "setdress", "layout", "camerarig", diff --git a/openpype/plugins/publish/collect_resources_path.py b/openpype/plugins/publish/collect_resources_path.py index 98b59332da..4f15a391c7 100644 --- a/openpype/plugins/publish/collect_resources_path.py +++ b/openpype/plugins/publish/collect_resources_path.py @@ -25,7 +25,7 @@ class CollectResourcesPath(pyblish.api.InstancePlugin): "camera", "animation", "model", - "mayaAscii", + "mayaScene", "setdress", "layout", "ass", diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index f9e9b43f08..1c3a8adb78 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -62,7 +62,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "camera", "animation", "model", - "mayaAscii", + "mayaScene", "setdress", "layout", "ass", diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index a53ae14914..1de2b172a2 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -19,7 +19,7 @@ "animation", "setdress", "layout", - "mayaAscii" + "mayaScene" ] }, "ExtractJpegEXR": { diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index f9911897d7..6bda996eef 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -473,7 +473,7 @@ 255, 255 ], - "mayaAscii": [ + "mayaScene": [ 67, 174, 255, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json index 0b09d08700..a21f59c8e5 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json @@ -48,7 +48,7 @@ { "type": "color", "label": "Maya Scene:", - "key": "mayaAscii" + "key": "mayaScene" }, { "type": "color", diff --git a/website/docs/pype2/admin_presets_plugins.md b/website/docs/pype2/admin_presets_plugins.md index 797995d2b7..eb97a1262f 100644 --- a/website/docs/pype2/admin_presets_plugins.md +++ b/website/docs/pype2/admin_presets_plugins.md @@ -468,7 +468,7 @@ maya outliner colours for various families "ass": [1.0, 0.332, 0.312], "camera": [0.447, 0.312, 1.0], "fbx": [1.0, 0.931, 0.312], - "mayaAscii": [0.312, 1.0, 0.747], + "mayaScene": [0.312, 1.0, 0.747], "setdress": [0.312, 1.0, 0.747], "layout": [0.312, 1.0, 0.747], "vdbcache": [0.312, 1.0, 0.428], From 53c9c9c0eb8d60166e803ec883da5e45460f4175 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 28 Sep 2021 11:42:32 +0200 Subject: [PATCH 086/150] return default deadline url if instance does not containe deadlineServers --- .../collect_deadline_server_from_instance.py | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py b/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py index 784616615d..2e512add57 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py @@ -46,24 +46,25 @@ class CollectDeadlineServerFromInstance(pyblish.api.InstancePlugin): ["deadline"] ) - try: - default_servers = deadline_settings["deadline_urls"] - project_servers = ( - render_instance.context.data - ["project_settings"] - ["deadline"] - ["deadline_servers"] - ) - deadline_servers = { - k: default_servers[k] - for k in project_servers - if k in default_servers - } - - except AttributeError: - # Handle situation were we had only one url for deadline. - return render_instance.context.data["defaultDeadline"] + default_server = render_instance.context.data["defaultDeadline"] + instance_server = render_instance.data.get("deadlineServers") + if not instance_server: + return default_server + default_servers = deadline_settings["deadline_urls"] + project_servers = ( + render_instance.context.data + ["project_settings"] + ["deadline"] + ["deadline_servers"] + ) + deadline_servers = { + k: default_servers[k] + for k in project_servers + if k in default_servers + } + # This is Maya specific and may not reflect real selection of deadline + # url as dictionary keys in Python 2 are not ordered return deadline_servers[ list(deadline_servers.keys())[ int(render_instance.data.get("deadlineServers")) From f8037602131b3751df6430b55df3936617fa0d95 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Fri, 1 Oct 2021 11:25:45 +0200 Subject: [PATCH 087/150] Disable Relative paths --- openpype/hosts/nuke/api/lib.py | 3 +- openpype/hosts/nuke/startup/write_to_read.py | 41 +++++++++++--------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 8948cb4d78..a7c4ec6f41 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -288,7 +288,8 @@ def script_name(): def add_button_write_to_read(node): name = "createReadNode" label = "Create Read From Rendered" - value = "import write_to_read;write_to_read.write_to_read(nuke.thisNode())" + value = "import write_to_read;\ + write_to_read.write_to_read(nuke.thisNode(), allow_relative=False)" knob = nuke.PyScript_Knob(name, label, value) knob.clearFlag(nuke.STARTLINE) node.addKnob(knob) diff --git a/openpype/hosts/nuke/startup/write_to_read.py b/openpype/hosts/nuke/startup/write_to_read.py index 295a6e3c85..f5cf66b357 100644 --- a/openpype/hosts/nuke/startup/write_to_read.py +++ b/openpype/hosts/nuke/startup/write_to_read.py @@ -9,7 +9,9 @@ SINGLE_FILE_FORMATS = ['avi', 'mp4', 'mxf', 'mov', 'mpg', 'mpeg', 'wmv', 'm4v', 'm2v'] -def evaluate_filepath_new(k_value, k_eval, project_dir, first_frame): +def evaluate_filepath_new( + k_value, k_eval, project_dir, first_frame, allow_relative): + # get combined relative path combined_relative_path = None if k_eval is not None and project_dir is not None: @@ -26,8 +28,9 @@ def evaluate_filepath_new(k_value, k_eval, project_dir, first_frame): combined_relative_path = None try: - k_value = k_value % first_frame - if os.path.exists(k_value): + # k_value = k_value % first_frame + if os.path.isdir(os.path.basename(k_value)): + # doesn't check for file, only parent dir filepath = k_value elif os.path.exists(k_eval): filepath = k_eval @@ -37,10 +40,12 @@ def evaluate_filepath_new(k_value, k_eval, project_dir, first_frame): filepath = os.path.abspath(filepath) except Exception as E: - log.error("Cannot create Read node. Perhaps it needs to be rendered first :) Error: `{}`".format(E)) + log.error("Cannot create Read node. Perhaps it needs to be \ + rendered first :) Error: `{}`".format(E)) return None filepath = filepath.replace('\\', '/') + # assumes last number is a sequence counter current_frame = re.findall(r'\d+', filepath)[-1] padding = len(current_frame) basename = filepath[: filepath.rfind(current_frame)] @@ -51,11 +56,13 @@ def evaluate_filepath_new(k_value, k_eval, project_dir, first_frame): pass else: # Image sequence needs hashes + # to do still with no number not handled filepath = basename + '#' * padding + '.' + filetype # relative path? make it relative again - if not isinstance(project_dir, type(None)): - filepath = filepath.replace(project_dir, '.') + if allow_relative: + if (not isinstance(project_dir, type(None))) and project_dir != "": + filepath = filepath.replace(project_dir, '.') # get first and last frame from disk frames = [] @@ -95,41 +102,40 @@ def create_read_node(ndata, comp_start): return -def write_to_read(gn): +def write_to_read(gn, + allow_relative=False): + comp_start = nuke.Root().knob('first_frame').value() - comp_end = nuke.Root().knob('last_frame').value() project_dir = nuke.Root().knob('project_directory').getValue() if not os.path.exists(project_dir): project_dir = nuke.Root().knob('project_directory').evaluate() group_read_nodes = [] - with gn: height = gn.screenHeight() # get group height and position new_xpos = int(gn.knob('xpos').value()) new_ypos = int(gn.knob('ypos').value()) + height + 20 group_writes = [n for n in nuke.allNodes() if n.Class() == "Write"] - print("__ group_writes: {}".format(group_writes)) if group_writes != []: # there can be only 1 write node, taking first n = group_writes[0] if n.knob('file') is not None: - file_path_new = evaluate_filepath_new( + myfile, firstFrame, lastFrame = evaluate_filepath_new( n.knob('file').getValue(), n.knob('file').evaluate(), project_dir, - comp_start + comp_start, + allow_relative ) - if not file_path_new: + if not myfile: return - myfiletranslated, firstFrame, lastFrame = file_path_new # get node data ndata = { - 'filepath': myfiletranslated, - 'firstframe': firstFrame, - 'lastframe': lastFrame, + 'filepath': myfile, + 'firstframe': int(firstFrame), + 'lastframe': int(lastFrame), 'new_xpos': new_xpos, 'new_ypos': new_ypos, 'colorspace': n.knob('colorspace').getValue(), @@ -139,7 +145,6 @@ def write_to_read(gn): } group_read_nodes.append(ndata) - # create reads in one go for oneread in group_read_nodes: # create read node From 5be0af5b42f2a565db253c6d6323b056b3ad7206 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 4 Oct 2021 11:14:51 +0200 Subject: [PATCH 088/150] updating avalon-core submodul repo --- repos/avalon-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repos/avalon-core b/repos/avalon-core index 8aee68fa10..4b80f81e66 160000 --- a/repos/avalon-core +++ b/repos/avalon-core @@ -1 +1 @@ -Subproject commit 8aee68fa10ab4d79be1a91e7728a609748e7c3c6 +Subproject commit 4b80f81e66aca593784be8b299110a0b6541276f From da23042db96482991cfccd6257ed98946dad1249 Mon Sep 17 00:00:00 2001 From: Simone Barbieri Date: Mon, 4 Oct 2021 12:32:40 +0100 Subject: [PATCH 089/150] Fix NoneType error when animationdata is missing for a rig --- openpype/hosts/blender/plugins/load/load_rig.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/blender/plugins/load/load_rig.py b/openpype/hosts/blender/plugins/load/load_rig.py index c385dc237e..6062c293df 100644 --- a/openpype/hosts/blender/plugins/load/load_rig.py +++ b/openpype/hosts/blender/plugins/load/load_rig.py @@ -111,7 +111,8 @@ class BlendRigLoader(plugin.AssetLoader): if action is not None: local_obj.animation_data.action = action - elif local_obj.animation_data.action is not None: + elif (local_obj.animation_data and + local_obj.animation_data.action is not None): plugin.prepare_data( local_obj.animation_data.action, group_name) From ebdd47a47a9b6650438361e4aab47eeb85727ece Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 5 Oct 2021 09:43:14 +0200 Subject: [PATCH 090/150] Fixed avalon-core branch commit --- repos/avalon-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repos/avalon-core b/repos/avalon-core index b90847b476..4b80f81e66 160000 --- a/repos/avalon-core +++ b/repos/avalon-core @@ -1 +1 @@ -Subproject commit b90847b4763cb571be9324759c041f1b32b35752 +Subproject commit 4b80f81e66aca593784be8b299110a0b6541276f From 39f009ed7c3efb9fb3bde86019fa58f788daf85c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 5 Oct 2021 10:21:57 +0200 Subject: [PATCH 091/150] Apply suggestions from code review Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/lib/applications.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/lib/applications.py b/openpype/lib/applications.py index 05ed67a6f0..b9badedb69 100644 --- a/openpype/lib/applications.py +++ b/openpype/lib/applications.py @@ -1344,8 +1344,8 @@ def _prepare_last_workfile(data, workdir, workfile_template_key): ) # Last workfile path - last_workfile_path = "" - if not data.get("last_workfile_path"): # to inject explicitly + last_workfile_path = data.get("last_workfile_path") or "" + if not last_workfile_path: extensions = avalon.api.HOST_WORKFILE_EXTENSIONS.get(app.host_name) if extensions: @@ -1361,8 +1361,6 @@ def _prepare_last_workfile(data, workdir, workfile_template_key): last_workfile_path = avalon.api.last_workfile( workdir, file_template, workdir_data, extensions, True ) - else: - last_workfile_path = data.get("last_workfile_path") if os.path.exists(last_workfile_path): log.debug(( From 4830120abbc5760ad794c5211053a53755e22a7c Mon Sep 17 00:00:00 2001 From: karimmozilla Date: Tue, 5 Oct 2021 11:42:35 +0200 Subject: [PATCH 092/150] add mayaAscii in loading --- openpype/hosts/maya/plugins/create/create_mayaascii.py | 2 +- openpype/hosts/maya/plugins/load/load_reference.py | 3 ++- .../hosts/maya/plugins/publish/extract_maya_scene_raw.py | 3 ++- openpype/plugins/publish/collect_resources_path.py | 1 + openpype/plugins/publish/integrate_new.py | 1 + .../schemas/projects_schema/schemas/schema_maya_load.json | 5 +++++ website/docs/pype2/admin_presets_plugins.md | 1 + 7 files changed, 13 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/create/create_mayaascii.py b/openpype/hosts/maya/plugins/create/create_mayaascii.py index 5ce634cec4..7be867e2d5 100644 --- a/openpype/hosts/maya/plugins/create/create_mayaascii.py +++ b/openpype/hosts/maya/plugins/create/create_mayaascii.py @@ -5,7 +5,7 @@ class CreateMayaScene(plugin.Creator): """Raw Maya Ascii file export""" name = "mayaScene" - label = "Maya Ascii" + label = "Maya Scene" family = "mayaScene" icon = "file-archive-o" defaults = ['Main'] diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index 544544a823..c2b07ea373 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -12,6 +12,7 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): families = ["model", "pointcache", "animation", + "mayaAscii", "mayaScene", "setdress", "layout", @@ -71,7 +72,7 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): except: # noqa: E722 pass - if family not in ["layout", "setdress", "mayaScene"]: + if family not in ["layout", "setdress", "mayaAscii" , "mayaScene"]: for root in roots: root.setParent(world=True) diff --git a/openpype/hosts/maya/plugins/publish/extract_maya_scene_raw.py b/openpype/hosts/maya/plugins/publish/extract_maya_scene_raw.py index ccae7351dc..e7fb5bc8cb 100644 --- a/openpype/hosts/maya/plugins/publish/extract_maya_scene_raw.py +++ b/openpype/hosts/maya/plugins/publish/extract_maya_scene_raw.py @@ -16,7 +16,8 @@ class ExtractMayaSceneRaw(openpype.api.Extractor): label = "Maya Scene (Raw)" hosts = ["maya"] - families = ["mayaScene", + families = ["mayaAscii", + "mayaScene", "setdress", "layout", "camerarig", diff --git a/openpype/plugins/publish/collect_resources_path.py b/openpype/plugins/publish/collect_resources_path.py index 4f15a391c7..c21f09ab8d 100644 --- a/openpype/plugins/publish/collect_resources_path.py +++ b/openpype/plugins/publish/collect_resources_path.py @@ -25,6 +25,7 @@ class CollectResourcesPath(pyblish.api.InstancePlugin): "camera", "animation", "model", + "mayaAscii", "mayaScene", "setdress", "layout", diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py index 1c3a8adb78..6275973cdf 100644 --- a/openpype/plugins/publish/integrate_new.py +++ b/openpype/plugins/publish/integrate_new.py @@ -62,6 +62,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "camera", "animation", "model", + "mayaAscii", "mayaScene", "setdress", "layout", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json index a21f59c8e5..7c87644817 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json @@ -45,6 +45,11 @@ "label": "FBX:", "key": "fbx" }, + { + "type": "color", + "label": "Maya Ascii:", + "key": "mayaAscii" + }, { "type": "color", "label": "Maya Scene:", diff --git a/website/docs/pype2/admin_presets_plugins.md b/website/docs/pype2/admin_presets_plugins.md index eb97a1262f..9c838d4a64 100644 --- a/website/docs/pype2/admin_presets_plugins.md +++ b/website/docs/pype2/admin_presets_plugins.md @@ -468,6 +468,7 @@ maya outliner colours for various families "ass": [1.0, 0.332, 0.312], "camera": [0.447, 0.312, 1.0], "fbx": [1.0, 0.931, 0.312], + "mayaAscii": [0.312, 1.0, 0.747], "mayaScene": [0.312, 1.0, 0.747], "setdress": [0.312, 1.0, 0.747], "layout": [0.312, 1.0, 0.747], From 502d5d56479e052909fcedad92be1339c8bad445 Mon Sep 17 00:00:00 2001 From: karimmozilla Date: Tue, 5 Oct 2021 11:52:51 +0200 Subject: [PATCH 093/150] edit comments --- openpype/hosts/maya/plugins/create/create_mayaascii.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/create/create_mayaascii.py b/openpype/hosts/maya/plugins/create/create_mayaascii.py index 7be867e2d5..8bbdf107c6 100644 --- a/openpype/hosts/maya/plugins/create/create_mayaascii.py +++ b/openpype/hosts/maya/plugins/create/create_mayaascii.py @@ -2,7 +2,7 @@ from openpype.hosts.maya.api import plugin class CreateMayaScene(plugin.Creator): - """Raw Maya Ascii file export""" + """Raw Maya Scene file export""" name = "mayaScene" label = "Maya Scene" From ea949146d1b65f76f050980d235dc7e6b67ec7cb Mon Sep 17 00:00:00 2001 From: karimmozilla Date: Tue, 5 Oct 2021 11:56:56 +0200 Subject: [PATCH 094/150] add color --- openpype/settings/defaults/project_settings/maya.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 6bda996eef..b464149966 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -473,6 +473,12 @@ 255, 255 ], + "mayaAscii": [ + 67, + 174, + 255, + 255 + ], "mayaScene": [ 67, 174, From 0d2d878e8a50d9f5787d2cc8e6aef892e74b4b13 Mon Sep 17 00:00:00 2001 From: karimmozilla <82811760+karimmozilla@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:59:55 +0200 Subject: [PATCH 095/150] delete white space --- openpype/hosts/maya/plugins/load/load_reference.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index c2b07ea373..6dd161cf98 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -72,7 +72,7 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): except: # noqa: E722 pass - if family not in ["layout", "setdress", "mayaAscii" , "mayaScene"]: + if family not in ["layout", "setdress", "mayaAscii", "mayaScene"]: for root in roots: root.setParent(world=True) From dd7ed45af2601ce4df2fb70e01873f9818d0b353 Mon Sep 17 00:00:00 2001 From: "felix.wang" Date: Tue, 5 Oct 2021 16:18:38 -0700 Subject: [PATCH 096/150] Add startup script for Houdini Core. This is equivalent to 123.py for HoudiniFX. --- openpype/hosts/houdini/startup/scripts/houdinicore.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 openpype/hosts/houdini/startup/scripts/houdinicore.py diff --git a/openpype/hosts/houdini/startup/scripts/houdinicore.py b/openpype/hosts/houdini/startup/scripts/houdinicore.py new file mode 100644 index 0000000000..4233d68c15 --- /dev/null +++ b/openpype/hosts/houdini/startup/scripts/houdinicore.py @@ -0,0 +1,9 @@ +from avalon import api, houdini + + +def main(): + print("Installing OpenPype ...") + api.install(houdini) + + +main() From 81c6987dbf84cb6d721f98eb1aa6296915e530ac Mon Sep 17 00:00:00 2001 From: karimmozilla Date: Wed, 6 Oct 2021 12:02:04 +0200 Subject: [PATCH 097/150] rename collect_maya_scene --- .../publish/{collect_mayaascii.py => collect_maya_scene.py} | 2 +- .../plugins/publish/{collect_scene.py => collect_workfile.py} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename openpype/hosts/maya/plugins/publish/{collect_mayaascii.py => collect_maya_scene.py} (95%) rename openpype/hosts/maya/plugins/publish/{collect_scene.py => collect_workfile.py} (97%) diff --git a/openpype/hosts/maya/plugins/publish/collect_mayaascii.py b/openpype/hosts/maya/plugins/publish/collect_maya_scene.py similarity index 95% rename from openpype/hosts/maya/plugins/publish/collect_mayaascii.py rename to openpype/hosts/maya/plugins/publish/collect_maya_scene.py index 199fb4197c..eb21b17989 100644 --- a/openpype/hosts/maya/plugins/publish/collect_mayaascii.py +++ b/openpype/hosts/maya/plugins/publish/collect_maya_scene.py @@ -4,7 +4,7 @@ import pyblish.api class CollectMayaScene(pyblish.api.InstancePlugin): - """Collect May Ascii Data + """Collect Maya Scene Data """ diff --git a/openpype/hosts/maya/plugins/publish/collect_scene.py b/openpype/hosts/maya/plugins/publish/collect_workfile.py similarity index 97% rename from openpype/hosts/maya/plugins/publish/collect_scene.py rename to openpype/hosts/maya/plugins/publish/collect_workfile.py index be2a294f26..ee676f50d0 100644 --- a/openpype/hosts/maya/plugins/publish/collect_scene.py +++ b/openpype/hosts/maya/plugins/publish/collect_workfile.py @@ -4,7 +4,7 @@ import os from maya import cmds -class CollectMayaScene(pyblish.api.ContextPlugin): +class CollectWorkfile(pyblish.api.ContextPlugin): """Inject the current working file into context""" order = pyblish.api.CollectorOrder - 0.01 From 9761b0a79f628bf5c460e91547820aee1d966992 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 6 Oct 2021 13:27:53 +0200 Subject: [PATCH 098/150] Small fixes --- .../hosts/maya/test_publish_in_maya.py | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/integration/hosts/maya/test_publish_in_maya.py b/tests/integration/hosts/maya/test_publish_in_maya.py index c178a6687e..1babf30029 100644 --- a/tests/integration/hosts/maya/test_publish_in_maya.py +++ b/tests/integration/hosts/maya/test_publish_in_maya.py @@ -8,6 +8,8 @@ from tests.lib.testing_classes import PublishTest class TestPublishInMaya(PublishTest): """Basic test case for publishing in Maya + Shouldnt be running standalone only via 'runtests' pype command! (??) + Uses generic TestCase to prepare fixtures for test data, testing DBs, env vars. @@ -61,38 +63,39 @@ class TestPublishInMaya(PublishTest): "startup") original_pythonpath = os.environ.get("PYTHONPATH") monkeypatch_session.setenv("PYTHONPATH", - "{};{}".format(original_pythonpath, - startup_path)) + "{}{}{}".format(startup_path, + os.pathsep, + original_pythonpath)) def test_db_asserts(self, dbcon, publish_finished): """Host and input data dependent expected results in DB.""" print("test_db_asserts") - assert 5 == dbcon.find({"type": "version"}).count(), \ + assert 5 == dbcon.count_documents({"type": "version"}), \ "Not expected no of versions" - assert 0 == dbcon.find({"type": "version", - "name": {"$ne": 1}}).count(), \ + assert 0 == dbcon.count_documents({"type": "version", + "name": {"$ne": 1}}), \ "Only versions with 1 expected" - assert 1 == dbcon.find({"type": "subset", - "name": "modelMain"}).count(), \ + assert 1 == dbcon.count_documents({"type": "subset", + "name": "modelMain"}), \ "modelMain subset must be present" - assert 1 == dbcon.find({"type": "subset", - "name": "workfileTest_task"}).count(), \ + assert 1 == dbcon.count_documents({"type": "subset", + "name": "workfileTest_task"}), \ "workfileTest_task subset must be present" - assert 11 == dbcon.find({"type": "representation"}).count(), \ + assert 11 == dbcon.count_documents({"type": "representation"}), \ "Not expected no of representations" - assert 2 == dbcon.find({"type": "representation", - "context.subset": "modelMain", - "context.ext": "abc"}).count(), \ + assert 2 == dbcon.count_documents({"type": "representation", + "context.subset": "modelMain", + "context.ext": "abc"}), \ "Not expected no of representations with ext 'abc'" - assert 2 == dbcon.find({"type": "representation", - "context.subset": "modelMain", - "context.ext": "ma"}).count(), \ + assert 2 == dbcon.count_documents({"type": "representation", + "context.subset": "modelMain", + "context.ext": "ma"}), \ "Not expected no of representations with ext 'abc'" From 2681caacd7058de35bbae60e75be5740024c0621 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 6 Oct 2021 13:47:42 +0200 Subject: [PATCH 099/150] swapped order of CollectDefaultDeadlineServerand and CollectDeadlineServerFromInstance --- .../plugins/publish/collect_deadline_server_from_instance.py | 2 +- .../deadline/plugins/publish/collect_default_deadline_server.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py b/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py index 2e512add57..968bffd890 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py @@ -11,7 +11,7 @@ import pyblish.api class CollectDeadlineServerFromInstance(pyblish.api.InstancePlugin): """Collect Deadline Webservice URL from instance.""" - order = pyblish.api.CollectorOrder + order = pyblish.api.CollectorOrder + 0.01 label = "Deadline Webservice from the Instance" families = ["rendering"] diff --git a/openpype/modules/default_modules/deadline/plugins/publish/collect_default_deadline_server.py b/openpype/modules/default_modules/deadline/plugins/publish/collect_default_deadline_server.py index 53231bd7e4..afb8583069 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/collect_default_deadline_server.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/collect_default_deadline_server.py @@ -6,7 +6,7 @@ import pyblish.api class CollectDefaultDeadlineServer(pyblish.api.ContextPlugin): """Collect default Deadline Webservice URL.""" - order = pyblish.api.CollectorOrder + 0.01 + order = pyblish.api.CollectorOrder label = "Default Deadline Webservice" def process(self, context): From aefbfa638aef9106d7b0d74657efeec031edbaf1 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 6 Oct 2021 16:30:01 +0200 Subject: [PATCH 100/150] remove unused assignment --- openpype/hosts/maya/api/lib_renderproducts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/lib_renderproducts.py b/openpype/hosts/maya/api/lib_renderproducts.py index b198052c93..4983109d58 100644 --- a/openpype/hosts/maya/api/lib_renderproducts.py +++ b/openpype/hosts/maya/api/lib_renderproducts.py @@ -393,7 +393,7 @@ class ARenderProducts: self.layer_data, force_aov_name=product.productName, force_ext=product.ext, - force_cameras=[product.camera] or None + force_cameras=[product.camera] ) def get_renderable_cameras(self): From 947139f425218c51618e09d7d1de748521b03039 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 6 Oct 2021 18:14:37 +0200 Subject: [PATCH 101/150] downgrade setuptools --- tools/create_env.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/create_env.sh b/tools/create_env.sh index 4ed6412c43..6fe6cdafb9 100755 --- a/tools/create_env.sh +++ b/tools/create_env.sh @@ -188,10 +188,11 @@ main () { # reinstall these because of bug in poetry? or cx_freeze? # cx_freeze will crash on missing __pychache__ on these but # reinstalling them solves the problem. - echo -e "${BIGreen}>>>${RST} Fixing pycache bug ..." - "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall setuptools + echo -e "${BIGreen}>>>${RST} Post-venv creation fixes ..." + "$POETRY_HOME/bin/poetry" run pip install setuptools==49.6.0 "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall wheel "$POETRY_HOME/bin/poetry" run python -m pip install --disable-pip-version-check --force-reinstall pip + "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall cx_freeze } return_code=0 From 4d612931ef6295ef848ba11f3894c452115e4f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Thu, 7 Oct 2021 09:46:16 +0200 Subject: [PATCH 102/150] pyproject parser for shell scripts --- tools/parse_pyproject.py | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tools/parse_pyproject.py diff --git a/tools/parse_pyproject.py b/tools/parse_pyproject.py new file mode 100644 index 0000000000..0aed321fcf --- /dev/null +++ b/tools/parse_pyproject.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +"""Parse pyproject.toml and return its values. + +Useful for shell scripts to know more about OpenPype build. +""" +import os +import blessed +import toml +from pathlib import Path +import click + +term = blessed.Terminal() + + +def _print(msg: str, message_type: int = 0) -> None: + """Print message to console. + + Args: + msg (str): message to print + message_type (int): type of message (0 info, 1 error, 2 note) + + """ + if message_type == 0: + header = term.aquamarine3(">>> ") + elif message_type == 1: + header = term.orangered2("!!! ") + elif message_type == 2: + header = term.tan1("... ") + else: + header = term.darkolivegreen3("--- ") + + print("{}{}".format(header, msg)) + + +@click.command() +@click.argument("key", nargs=-1, type=click.STRING) +def main(key): + _print("Reading build metadata ...") + openpype_root = Path(os.path.dirname(__file__)).parent + py_project = toml.load(openpype_root / "pyproject.toml") + query = key.split(".") + data = py_project + for k in query: + if isinstance(data, dict): + data = data.get(k) + else: + break + print(data) + + +if __name__ == "__main__": + main() From 94d4926084a594cfd1170c7f7cbaaf77a16a1fea Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 7 Oct 2021 12:51:50 +0200 Subject: [PATCH 103/150] PYPE-1218 - changed namespace to contain subset name --- openpype/hosts/maya/api/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 448cb814d9..fdad0e0989 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -123,7 +123,7 @@ class ReferenceLoader(api.Loader): count = options.get("count") or 1 for c in range(0, count): namespace = namespace or lib.unique_namespace( - asset["name"] + "_", + "{}_{}_".format(asset["name"], context["subset"]["name"]), prefix="_" if asset["name"][0].isdigit() else "", suffix="_", ) From dd71de1b70776541f41b1a9977a402a29ee94c43 Mon Sep 17 00:00:00 2001 From: jrsndlr Date: Thu, 7 Oct 2021 16:53:17 +0200 Subject: [PATCH 104/150] get path for the first time publish --- openpype/plugins/publish/collect_resources_path.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openpype/plugins/publish/collect_resources_path.py b/openpype/plugins/publish/collect_resources_path.py index c21f09ab8d..fa181301ee 100644 --- a/openpype/plugins/publish/collect_resources_path.py +++ b/openpype/plugins/publish/collect_resources_path.py @@ -68,6 +68,12 @@ class CollectResourcesPath(pyblish.api.InstancePlugin): "representation": "TEMP" }) + # For the first time publish + if instance.data.get("hierarchy"): + template_data.update({ + "hierarchy": instance.data["hierarchy"] + }) + anatomy_filled = anatomy.format(template_data) if "folder" in anatomy.templates["publish"]: From 9f9caafb0d3b80e9bf0d2a4e2fae288db7d30056 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 7 Oct 2021 18:18:33 +0200 Subject: [PATCH 105/150] reinstall cx_freeze with downgraded setuptools --- setup.py | 5 ++-- tools/build_dependencies.py | 25 ++++++++++++---- tools/create_env.sh | 4 ++- tools/parse_pyproject.py | 60 +++++++++++++++++-------------------- 4 files changed, 52 insertions(+), 42 deletions(-) diff --git a/setup.py b/setup.py index 55098cb0b4..cd3ed4f82c 100644 --- a/setup.py +++ b/setup.py @@ -59,13 +59,14 @@ includes = [] excludes = [ "openpype" ] -bin_includes = [] +bin_includes = [ + "vendor" +] include_files = [ "igniter", "openpype", "repos", "schema", - "vendor", "LICENSE", "README.md" ] diff --git a/tools/build_dependencies.py b/tools/build_dependencies.py index 1798b7ca8f..75d6e0c315 100644 --- a/tools/build_dependencies.py +++ b/tools/build_dependencies.py @@ -113,7 +113,26 @@ if not build_dir.exists(): _print("Probably freezing of code failed. Check ./build/build.log", 3) sys.exit(1) +def _progress(_base, _names): + progress_bar.update() + return [] + deps_dir = build_dir / "dependencies" +vendor_dir = build_dir / "vendor" +vendor_src = openpype_root / "vendor" + +# copy vendor files +_print("Copying vendor files ...") + +total_files = count_folders(vendor_src) +progress_bar = enlighten.Counter( + total=total_files, desc="Copying vendor files ...", + units="%", color=(64, 128, 222)) + +shutil.copytree(vendor_src.as_posix(), + vendor_dir.as_posix(), + ignore=_progress) +progress_bar.close() # copy all files _print("Copying dependencies ...") @@ -123,12 +142,6 @@ progress_bar = enlighten.Counter( total=total_files, desc="Processing Dependencies", units="%", color=(53, 178, 202)) - -def _progress(_base, _names): - progress_bar.update() - return [] - - shutil.copytree(site_pkg.as_posix(), deps_dir.as_posix(), ignore=_progress) diff --git a/tools/create_env.sh b/tools/create_env.sh index 6fe6cdafb9..917ddc36ba 100755 --- a/tools/create_env.sh +++ b/tools/create_env.sh @@ -189,10 +189,12 @@ main () { # cx_freeze will crash on missing __pychache__ on these but # reinstalling them solves the problem. echo -e "${BIGreen}>>>${RST} Post-venv creation fixes ..." + local openpype_index=$("$POETRY_HOME/bin/poetry" run python "$openpype_root/tools/parse_pyproject.py" tool.poetry.source.0.url) + echo -e "${BIGreen}- ${RST} Using index: ${BIWhite}$openpype_index${RST}" "$POETRY_HOME/bin/poetry" run pip install setuptools==49.6.0 "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall wheel "$POETRY_HOME/bin/poetry" run python -m pip install --disable-pip-version-check --force-reinstall pip - "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall cx_freeze + "$POETRY_HOME/bin/poetry" run pip install --disable-pip-version-check --force-reinstall cx_freeze -i $openpype_index --extra-index-url https://pypi.org/simple } return_code=0 diff --git a/tools/parse_pyproject.py b/tools/parse_pyproject.py index 0aed321fcf..296d73654d 100644 --- a/tools/parse_pyproject.py +++ b/tools/parse_pyproject.py @@ -3,49 +3,43 @@ Useful for shell scripts to know more about OpenPype build. """ +import sys import os -import blessed import toml from pathlib import Path import click -term = blessed.Terminal() - - -def _print(msg: str, message_type: int = 0) -> None: - """Print message to console. - - Args: - msg (str): message to print - message_type (int): type of message (0 info, 1 error, 2 note) - - """ - if message_type == 0: - header = term.aquamarine3(">>> ") - elif message_type == 1: - header = term.orangered2("!!! ") - elif message_type == 2: - header = term.tan1("... ") - else: - header = term.darkolivegreen3("--- ") - - print("{}{}".format(header, msg)) @click.command() -@click.argument("key", nargs=-1, type=click.STRING) -def main(key): - _print("Reading build metadata ...") +@click.argument("keys", nargs=-1, type=click.STRING) +def main(keys): + """Get values from `pyproject.toml`. + + You can specify dot separated keys from `pyproject.toml` + as arguments and this script will return them on separate + lines. If key doesn't exists, None is returned. + + + """ openpype_root = Path(os.path.dirname(__file__)).parent py_project = toml.load(openpype_root / "pyproject.toml") - query = key.split(".") - data = py_project - for k in query: - if isinstance(data, dict): - data = data.get(k) - else: - break - print(data) + for q in keys: + query = q.split(".") + data = py_project + for i, k in enumerate(query): + + if isinstance(data, list): + try: + data = data[int(k)] + except IndexError: + print("None") + sys.exit() + continue + + if isinstance(data, dict): + data = data.get(k) + print(data) if __name__ == "__main__": From 4276f34a301fe65ed1960e9a87935121907a0016 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 7 Oct 2021 23:04:48 +0200 Subject: [PATCH 106/150] fix hound --- tools/build_dependencies.py | 2 ++ tools/parse_pyproject.py | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/build_dependencies.py b/tools/build_dependencies.py index 75d6e0c315..8eaf9d87e3 100644 --- a/tools/build_dependencies.py +++ b/tools/build_dependencies.py @@ -113,10 +113,12 @@ if not build_dir.exists(): _print("Probably freezing of code failed. Check ./build/build.log", 3) sys.exit(1) + def _progress(_base, _names): progress_bar.update() return [] + deps_dir = build_dir / "dependencies" vendor_dir = build_dir / "vendor" vendor_src = openpype_root / "vendor" diff --git a/tools/parse_pyproject.py b/tools/parse_pyproject.py index 296d73654d..dacecd88d0 100644 --- a/tools/parse_pyproject.py +++ b/tools/parse_pyproject.py @@ -10,7 +10,6 @@ from pathlib import Path import click - @click.command() @click.argument("keys", nargs=-1, type=click.STRING) def main(keys): @@ -19,7 +18,6 @@ def main(keys): You can specify dot separated keys from `pyproject.toml` as arguments and this script will return them on separate lines. If key doesn't exists, None is returned. - """ openpype_root = Path(os.path.dirname(__file__)).parent @@ -27,8 +25,8 @@ def main(keys): for q in keys: query = q.split(".") data = py_project - for i, k in enumerate(query): + for k in query: if isinstance(data, list): try: data = data[int(k)] From 8312412cd6105fd18a38a3193cfbc7fe237ca89f Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 9 Oct 2021 03:38:41 +0000 Subject: [PATCH 107/150] [Automated] Bump version --- CHANGELOG.md | 19 ++++++++++++------- openpype/version.py | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32943834d0..c88f5c9ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ # Changelog -## [3.5.0-nightly.4](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.5.0-nightly.5](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.4.1...HEAD) +**Deprecated:** + +- Maya: Change mayaAscii family to mayaScene [\#2106](https://github.com/pypeclub/OpenPype/pull/2106) + **πŸ†• New features** - Added running configurable disk mapping command before start of OP [\#2091](https://github.com/pypeclub/OpenPype/pull/2091) @@ -13,6 +17,7 @@ **πŸš€ Enhancements** - Settings UI: Project model refreshing and sorting [\#2104](https://github.com/pypeclub/OpenPype/pull/2104) +- Create Read From Rendered - Disable Relative paths by default [\#2093](https://github.com/pypeclub/OpenPype/pull/2093) - Added choosing different dirmap mapping if workfile synched locally [\#2088](https://github.com/pypeclub/OpenPype/pull/2088) - General: Remove IdleManager module [\#2084](https://github.com/pypeclub/OpenPype/pull/2084) - Tray UI: Message box about missing settings defaults [\#2080](https://github.com/pypeclub/OpenPype/pull/2080) @@ -27,6 +32,7 @@ **πŸ› Bug fixes** +- Add startup script for Houdini Core. [\#2110](https://github.com/pypeclub/OpenPype/pull/2110) - TVPaint: Behavior name of loop also accept repeat [\#2109](https://github.com/pypeclub/OpenPype/pull/2109) - Ftrack: Project settings save custom attributes skip unknown attributes [\#2103](https://github.com/pypeclub/OpenPype/pull/2103) - Fix broken import in sftp provider [\#2100](https://github.com/pypeclub/OpenPype/pull/2100) @@ -35,11 +41,14 @@ - TVPaint: Creator use context from workfile [\#2087](https://github.com/pypeclub/OpenPype/pull/2087) - Blender: fix texture missing when publishing blend files [\#2085](https://github.com/pypeclub/OpenPype/pull/2085) - General: Startup validations oiio tool path fix on linux [\#2083](https://github.com/pypeclub/OpenPype/pull/2083) +- Deadline: Collect deadline server does not check existence of deadline key [\#2082](https://github.com/pypeclub/OpenPype/pull/2082) - Blender: fixed Curves with modifiers in Rigs [\#2081](https://github.com/pypeclub/OpenPype/pull/2081) +- Maya: Fix multi-camera renders [\#2065](https://github.com/pypeclub/OpenPype/pull/2065) - Fix Sync Queue when project disabled [\#2063](https://github.com/pypeclub/OpenPype/pull/2063) **Merged pull requests:** +- Blender: Fix NoneType error when animation\_data is missing for a rig [\#2101](https://github.com/pypeclub/OpenPype/pull/2101) - Delivery Action Files Sequence fix [\#2096](https://github.com/pypeclub/OpenPype/pull/2096) - Bump pywin32 from 300 to 301 [\#2086](https://github.com/pypeclub/OpenPype/pull/2086) - Nuke UI scaling [\#2077](https://github.com/pypeclub/OpenPype/pull/2077) @@ -60,7 +69,6 @@ - Settings UI: Deffered set value on entity [\#2044](https://github.com/pypeclub/OpenPype/pull/2044) - Loader: Families filtering [\#2043](https://github.com/pypeclub/OpenPype/pull/2043) - Settings UI: Project view enhancements [\#2042](https://github.com/pypeclub/OpenPype/pull/2042) -- Added possibility to configure of synchronization of workfile version… [\#2041](https://github.com/pypeclub/OpenPype/pull/2041) - Settings for Nuke IncrementScriptVersion [\#2039](https://github.com/pypeclub/OpenPype/pull/2039) - Loader & Library loader: Use tools from OpenPype [\#2038](https://github.com/pypeclub/OpenPype/pull/2038) - Adding predefined project folders creation in PM [\#2030](https://github.com/pypeclub/OpenPype/pull/2030) @@ -75,7 +83,6 @@ - Differentiate jpg sequences from thumbnail [\#2056](https://github.com/pypeclub/OpenPype/pull/2056) - FFmpeg: Split command to list does not work [\#2046](https://github.com/pypeclub/OpenPype/pull/2046) - Removed shell flag in subprocess call [\#2045](https://github.com/pypeclub/OpenPype/pull/2045) -- Hiero: Fix "none" named tags [\#2033](https://github.com/pypeclub/OpenPype/pull/2033) **Merged pull requests:** @@ -95,6 +102,7 @@ **πŸš€ Enhancements** +- Added possibility to configure of synchronization of workfile version… [\#2041](https://github.com/pypeclub/OpenPype/pull/2041) - General: Task types in profiles [\#2036](https://github.com/pypeclub/OpenPype/pull/2036) - Console interpreter: Handle invalid sizes on initialization [\#2022](https://github.com/pypeclub/OpenPype/pull/2022) - Ftrack: Show OpenPype versions in event server status [\#2019](https://github.com/pypeclub/OpenPype/pull/2019) @@ -113,6 +121,7 @@ - Workfiles tool: Task selection [\#2040](https://github.com/pypeclub/OpenPype/pull/2040) - Ftrack: Delete old versions missing settings key [\#2037](https://github.com/pypeclub/OpenPype/pull/2037) - Nuke: typo on a button [\#2034](https://github.com/pypeclub/OpenPype/pull/2034) +- Hiero: Fix "none" named tags [\#2033](https://github.com/pypeclub/OpenPype/pull/2033) - FFmpeg: Subprocess arguments as list [\#2032](https://github.com/pypeclub/OpenPype/pull/2032) - General: Fix Python 2 breaking line [\#2016](https://github.com/pypeclub/OpenPype/pull/2016) - Bugfix/webpublisher task type [\#2006](https://github.com/pypeclub/OpenPype/pull/2006) @@ -121,10 +130,6 @@ - nuke, resolve, hiero: precollector order lest then 0.5 [\#1984](https://github.com/pypeclub/OpenPype/pull/1984) - Last workfile with multiple work templates [\#1981](https://github.com/pypeclub/OpenPype/pull/1981) - Collectors order [\#1977](https://github.com/pypeclub/OpenPype/pull/1977) -- Stop timer was within validator order range. [\#1975](https://github.com/pypeclub/OpenPype/pull/1975) -- Ftrack: arrow submodule has https url source [\#1974](https://github.com/pypeclub/OpenPype/pull/1974) -- Ftrack: Fix hosts attribute in collect ftrack username [\#1972](https://github.com/pypeclub/OpenPype/pull/1972) -- Deadline: Houdini plugins in different hierarchy [\#1970](https://github.com/pypeclub/OpenPype/pull/1970) ## [3.3.1](https://github.com/pypeclub/OpenPype/tree/3.3.1) (2021-08-20) diff --git a/openpype/version.py b/openpype/version.py index 99ba3fd543..f6ace59d7d 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.5.0-nightly.4" +__version__ = "3.5.0-nightly.5" From d9e63d0a69e086067b241f3735e614656d81fde2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 11 Oct 2021 11:35:58 +0200 Subject: [PATCH 108/150] PYPE-1218 - update to namespace name for groups --- openpype/hosts/maya/plugins/load/load_reference.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index 6dd161cf98..cfe8149218 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -41,14 +41,13 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): family = "model" with maya.maintained_selection(): - - groupName = "{}:{}".format(namespace, name) + groupName = "{}:_GRP".format(namespace) cmds.loadPlugin("AbcImport.mll", quiet=True) nodes = cmds.file(self.fname, namespace=namespace, sharedReferenceFile=False, groupReference=True, - groupName="{}:{}".format(namespace, name), + groupName=groupName, reference=True, returnNewNodes=True) From c8b1037e99e829be086ab092e94103e5eb115ef6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 11 Oct 2021 16:35:32 +0200 Subject: [PATCH 109/150] added few magic attributes to getattr --- openpype/modules/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/modules/base.py b/openpype/modules/base.py index 748c7857a9..7779fff6ec 100644 --- a/openpype/modules/base.py +++ b/openpype/modules/base.py @@ -48,7 +48,7 @@ class _ModuleClass(object): def __getattr__(self, attr_name): if attr_name not in self.__attributes__: - if attr_name in ("__path__"): + if attr_name in ("__path__", "__file__"): return None raise ImportError("No module named {}.{}".format( self.name, attr_name @@ -104,6 +104,9 @@ class _InterfacesClass(_ModuleClass): """ def __getattr__(self, attr_name): if attr_name not in self.__attributes__: + if attr_name in ("__path__", "__file__"): + return None + # Fake Interface if is not missing self.__attributes__[attr_name] = type( attr_name, From 45b39792e3d18c409e076a0d9788e981cd630001 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 11 Oct 2021 16:35:48 +0200 Subject: [PATCH 110/150] removed boolean from setFocus --- openpype/tools/settings/settings/categories.py | 2 +- openpype/tools/settings/settings/dict_mutable_widget.py | 6 +++--- openpype/tools/settings/settings/list_item_widget.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index be2264340b..5f9051344d 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -508,7 +508,7 @@ class SettingsCategoryWidget(QtWidgets.QWidget): first_invalid_item = invalid_items[0] self.scroll_widget.ensureWidgetVisible(first_invalid_item) if first_invalid_item.isVisible(): - first_invalid_item.setFocus(True) + first_invalid_item.setFocus() return False def on_saved(self, saved_tab_widget): diff --git a/openpype/tools/settings/settings/dict_mutable_widget.py b/openpype/tools/settings/settings/dict_mutable_widget.py index cfb9d4a4b1..9afce7259e 100644 --- a/openpype/tools/settings/settings/dict_mutable_widget.py +++ b/openpype/tools/settings/settings/dict_mutable_widget.py @@ -128,9 +128,9 @@ class ModifiableDictEmptyItem(QtWidgets.QWidget): def add_new_item(self, key=None, label=None): input_field = self.entity_widget.add_new_key(key, label) if self.collapsible_key: - self.key_input.setFocus(True) + self.key_input.setFocus() else: - input_field.key_input.setFocus(True) + input_field.key_input.setFocus() return input_field def _on_add_clicked(self): @@ -563,7 +563,7 @@ class ModifiableDictItem(QtWidgets.QWidget): def on_add_clicked(self): widget = self.entity_widget.add_new_key(None, None) - widget.key_input.setFocus(True) + widget.key_input.setFocus() def on_edit_pressed(self): if not self.key_input.isVisible(): diff --git a/openpype/tools/settings/settings/list_item_widget.py b/openpype/tools/settings/settings/list_item_widget.py index 17412a30b9..128af92631 100644 --- a/openpype/tools/settings/settings/list_item_widget.py +++ b/openpype/tools/settings/settings/list_item_widget.py @@ -357,7 +357,7 @@ class ListWidget(InputWidget): new_entity = self.entity.add_new_item(row) input_field = self._input_fields_by_entity_id.get(new_entity.id) if input_field is not None: - input_field.input_field.setFocus(True) + input_field.input_field.setFocus() return new_entity def add_row(self, child_entity, row=None): From e3303f88322290143beffbc3b4b2bf116291bb63 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 11 Oct 2021 16:40:16 +0200 Subject: [PATCH 111/150] avoid garbage collection of clipboard --- openpype/tools/settings/settings/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index ab6b27bdaf..92fffe6f9c 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -214,7 +214,8 @@ class BaseWidget(QtWidgets.QWidget): def _paste_value_actions(self, menu): output = [] # Allow paste of value only if were copied from this UI - mime_data = QtWidgets.QApplication.clipboard().mimeData() + clipboard = QtWidgets.QApplication.clipboard() + mime_data = clipboard.mimeData() mime_value = mime_data.data("application/copy_settings_value") # Skip if there is nothing to do if not mime_value: From 330d61cf00658e591b35fc4c8f48d4543df030a0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 11 Oct 2021 17:40:41 +0200 Subject: [PATCH 112/150] make sure that mapping is set to iterable --- start.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/start.py b/start.py index ada613b4eb..a4c58b8fc7 100644 --- a/start.py +++ b/start.py @@ -287,9 +287,8 @@ def run_disk_mapping_commands(mongo_url): if not disk_mapping: return - for mapping in disk_mapping.get(low_platform): - source, destination = mapping - + mappings = disk_mapping.get(low_platform) or [] + for source, destination in mappings: args = ["subst", destination.rstrip('/'), source.rstrip('/')] _print("disk mapping args:: {}".format(args)) try: From 7a956f495f7d37ee71c368bc65aee7416ce6e9b4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 11 Oct 2021 17:40:55 +0200 Subject: [PATCH 113/150] disk mapping is now group --- .../settings/entities/schemas/system_schema/schema_general.json | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/settings/entities/schemas/system_schema/schema_general.json b/openpype/settings/entities/schemas/system_schema/schema_general.json index 31cd997d14..51a58a6e27 100644 --- a/openpype/settings/entities/schemas/system_schema/schema_general.json +++ b/openpype/settings/entities/schemas/system_schema/schema_general.json @@ -44,6 +44,7 @@ "type": "dict", "key": "disk_mapping", "label": "Disk mapping", + "is_group": true, "use_label_wrap": false, "collapsible": false, "children": [ From e969cd188395b34b447978ff44989fb0d210ff01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20LORRAIN?= Date: Tue, 12 Oct 2021 16:41:02 +0200 Subject: [PATCH 114/150] Add photoshop extractReview plugin options for representations tags --- .../plugins/publish/extract_review.py | 9 +++-- openpype/plugins/publish/extract_burnin.py | 3 +- .../defaults/project_settings/photoshop.json | 12 +++++++ .../schema_project_photoshop.json | 34 ++++++++++++++++++- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/photoshop/plugins/publish/extract_review.py b/openpype/hosts/photoshop/plugins/publish/extract_review.py index 1c53c3a2ef..8c4d05b282 100644 --- a/openpype/hosts/photoshop/plugins/publish/extract_review.py +++ b/openpype/hosts/photoshop/plugins/publish/extract_review.py @@ -17,6 +17,10 @@ class ExtractReview(openpype.api.Extractor): hosts = ["photoshop"] families = ["review"] + # Extract Options + jpg_options = None + mov_options = None + def process(self, instance): staging_dir = self.staging_dir(instance) self.log.info("Outputting image to {}".format(staging_dir)) @@ -53,7 +57,8 @@ class ExtractReview(openpype.api.Extractor): "name": "jpg", "ext": "jpg", "files": output_image, - "stagingDir": staging_dir + "stagingDir": staging_dir, + "tags": self.jpg_options['tags'] }) instance.data["stagingDir"] = staging_dir @@ -97,7 +102,7 @@ class ExtractReview(openpype.api.Extractor): "frameEnd": 1, "fps": 25, "preview": True, - "tags": ["review", "ftrackreview"] + "tags": self.mov_options['tags'] }) # Required for extract_review plugin (L222 onwards). diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index 207e696fb1..06eb85c593 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -45,7 +45,8 @@ class ExtractBurnin(openpype.api.Extractor): "aftereffects", "tvpaint", "webpublisher", - "aftereffects" + "aftereffects", + "photoshop" # "resolve" ] optional = True diff --git a/openpype/settings/defaults/project_settings/photoshop.json b/openpype/settings/defaults/project_settings/photoshop.json index 4c36e4bd49..36c30bad6c 100644 --- a/openpype/settings/defaults/project_settings/photoshop.json +++ b/openpype/settings/defaults/project_settings/photoshop.json @@ -17,6 +17,18 @@ "png", "jpg" ] + }, + "ExtractReview": { + "jpg_options": { + "tags": [ + ] + }, + "mov_options": { + "tags": [ + "review", + "ftrackreview" + ] + } } }, "workfile_builder": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_photoshop.json b/openpype/settings/entities/schemas/projects_schema/schema_project_photoshop.json index 3b65f08ac4..6f5577650c 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_photoshop.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_photoshop.json @@ -60,7 +60,39 @@ "object_type": "text" } ] - } + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractReview", + "label": "Extract Review", + "children": [ + { + "type": "dict", + "collapsible": false, + "key": "jpg_options", + "label": "Extracted jpg Options", + "children": [ + { + "type": "schema", + "name": "schema_representation_tags" + } + ] + }, + { + "type": "dict", + "collapsible": false, + "key": "mov_options", + "label": "Extracted mov Options", + "children": [ + { + "type": "schema", + "name": "schema_representation_tags" + } + ] + } + ] + } ] }, { From 50742bba5c6b3d620bf13042ecd61dff352fc544 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 16:45:29 +0200 Subject: [PATCH 115/150] nuke: adding supporting plugin function --- openpype/hosts/nuke/api/plugin.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 0ad98146b1..71329c0d46 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -23,3 +23,19 @@ class PypeCreator(PypeCreatorMixin, avalon.nuke.pipeline.Creator): self.log.error(msg + '\n\nPlease use other subset name!') raise NameError("`{0}: {1}".format(__name__, msg)) return + + +def get_review_presets_config(): + settings = get_current_project_settings() + review_profiles = ( + settings["global"] + ["publish"] + ["ExtractReview"] + ["profiles"] + ) + + outputs = {} + for profile in review_profiles: + outputs.update(profile.get("outputs", {})) + + return [str(name) for name, _prop in outputs.items()] From ad2be29831e483bdbf1c4c61622e40884e23b0a6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 16:45:53 +0200 Subject: [PATCH 116/150] nuke: adding repair inventory action --- .../plugins/inventory/repair_old_loaders.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 openpype/hosts/nuke/plugins/inventory/repair_old_loaders.py diff --git a/openpype/hosts/nuke/plugins/inventory/repair_old_loaders.py b/openpype/hosts/nuke/plugins/inventory/repair_old_loaders.py new file mode 100644 index 0000000000..e7ae51fa86 --- /dev/null +++ b/openpype/hosts/nuke/plugins/inventory/repair_old_loaders.py @@ -0,0 +1,37 @@ +from avalon import api, style +from avalon.nuke import lib as anlib +from openpype.api import ( + Logger) + + +class RepairOldLoaders(api.InventoryAction): + + label = "Repair Old Loaders" + icon = "gears" + color = style.colors.alert + + log = Logger().get_logger(__name__) + + def process(self, containers): + import nuke + new_loader = "LoadClip" + + for cdata in containers: + orig_loader = cdata["loader"] + orig_name = cdata["objectName"] + if orig_loader not in ["LoadSequence", "LoadMov"]: + self.log.warning( + "This repair action is only working on " + "`LoadSequence` and `LoadMov` Loaders") + continue + + new_name = orig_name.replace(orig_loader, new_loader) + node = nuke.toNode(cdata["objectName"]) + + cdata.update({ + "loader": new_loader, + "objectName": new_name + }) + node["name"].setValue(new_name) + # get data from avalon knob + anlib.set_avalon_knob_data(node, cdata) From fcd9ebda39459eccf407875217f920745ef8d5d7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 16:46:17 +0200 Subject: [PATCH 117/150] nuke: removing unused code --- .../nuke/plugins/inventory/set_tool_color.py | 68 ------------------- 1 file changed, 68 deletions(-) delete mode 100644 openpype/hosts/nuke/plugins/inventory/set_tool_color.py diff --git a/openpype/hosts/nuke/plugins/inventory/set_tool_color.py b/openpype/hosts/nuke/plugins/inventory/set_tool_color.py deleted file mode 100644 index 7a81444c90..0000000000 --- a/openpype/hosts/nuke/plugins/inventory/set_tool_color.py +++ /dev/null @@ -1,68 +0,0 @@ -# from avalon import api, style -# from avalon.vendor.Qt import QtGui, QtWidgets -# -# import avalon.fusion -# -# -# class FusionSetToolColor(api.InventoryAction): -# """Update the color of the selected tools""" -# -# label = "Set Tool Color" -# icon = "plus" -# color = "#d8d8d8" -# _fallback_color = QtGui.QColor(1.0, 1.0, 1.0) -# -# def process(self, containers): -# """Color all selected tools the selected colors""" -# -# result = [] -# comp = avalon.fusion.get_current_comp() -# -# # Get tool color -# first = containers[0] -# tool = first["_node"] -# color = tool.TileColor -# -# if color is not None: -# qcolor = QtGui.QColor().fromRgbF(color["R"], color["G"], color["B"]) -# else: -# qcolor = self._fallback_color -# -# # Launch pick color -# picked_color = self.get_color_picker(qcolor) -# if not picked_color: -# return -# -# with avalon.fusion.comp_lock_and_undo_chunk(comp): -# for container in containers: -# # Convert color to RGB 0-1 floats -# rgb_f = picked_color.getRgbF() -# rgb_f_table = {"R": rgb_f[0], "G": rgb_f[1], "B": rgb_f[2]} -# -# # Update tool -# tool = container["_node"] -# tool.TileColor = rgb_f_table -# -# result.append(container) -# -# return result -# -# def get_color_picker(self, color): -# """Launch color picker and return chosen color -# -# Args: -# color(QtGui.QColor): Start color to display -# -# Returns: -# QtGui.QColor -# -# """ -# -# color_dialog = QtWidgets.QColorDialog(color) -# color_dialog.setStyleSheet(style.load_stylesheet()) -# -# accepted = color_dialog.exec_() -# if not accepted: -# return -# -# return color_dialog.selectedColor() From 3ed84b3bc932d41c1ae2a49dfb67b81120740cee Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 16:46:54 +0200 Subject: [PATCH 118/150] nuke: fixing inventory action obsolete way of accessing nodes --- openpype/hosts/nuke/plugins/inventory/select_containers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/inventory/select_containers.py b/openpype/hosts/nuke/plugins/inventory/select_containers.py index b420f53431..bd00983172 100644 --- a/openpype/hosts/nuke/plugins/inventory/select_containers.py +++ b/openpype/hosts/nuke/plugins/inventory/select_containers.py @@ -8,10 +8,10 @@ class SelectContainers(api.InventoryAction): color = "#d8d8d8" def process(self, containers): - + import nuke import avalon.nuke - nodes = [i["_node"] for i in containers] + nodes = [nuke.toNode(i["objectName"]) for i in containers] with avalon.nuke.viewer_update_and_undo_stop(): # clear previous_selection From d1029a30426706ef5f4ad169ab49ee116e19cb94 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 16:54:36 +0200 Subject: [PATCH 119/150] Nuke: new way of adding representation from settings to plugins --- .../hosts/nuke/plugins/load/load_image.py | 14 +++++- .../defaults/project_settings/nuke.json | 45 ++----------------- .../schemas/schema_nuke_load.json | 8 +--- .../schemas/template_loader_plugin_nuke.json | 8 +--- 4 files changed, 19 insertions(+), 56 deletions(-) diff --git a/openpype/hosts/nuke/plugins/load/load_image.py b/openpype/hosts/nuke/plugins/load/load_image.py index 9b8bc43d12..2af44d6eba 100644 --- a/openpype/hosts/nuke/plugins/load/load_image.py +++ b/openpype/hosts/nuke/plugins/load/load_image.py @@ -12,7 +12,15 @@ from openpype.hosts.nuke.api.lib import ( class LoadImage(api.Loader): """Load still image into Nuke""" - families = ["render", "source", "plate", "review", "image"] + families = [ + "render2d", + "source", + "plate", + "render", + "prerender", + "review", + "image" + ] representations = ["exr", "dpx", "jpg", "jpeg", "png", "psd", "tiff"] label = "Load Image" @@ -33,6 +41,10 @@ class LoadImage(api.Loader): ) ] + @classmethod + def get_representations(cls): + return cls.representations + cls._representations + def load(self, context, name, namespace, options): from avalon.nuke import ( containerise, diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index dd65df02e5..e3c7834e4a 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -117,16 +117,7 @@ "load": { "LoadImage": { "enabled": true, - "families": [ - "render2d", - "source", - "plate", - "render", - "prerender", - "review", - "image" - ], - "representations": [ + "_representations": [ "exr", "dpx", "jpg", @@ -137,39 +128,9 @@ ], "node_name_template": "{class_name}_{ext}" }, - "LoadMov": { + "LoadClip": { "enabled": true, - "families": [ - "source", - "plate", - "render", - "prerender", - "review" - ], - "representations": [ - "mov", - "review", - "mp4", - "h264" - ], - "node_name_template": "{class_name}_{ext}" - }, - "LoadSequence": { - "enabled": true, - "families": [ - "render2d", - "source", - "plate", - "render", - "prerender", - "review" - ], - "representations": [ - "exr", - "dpx", - "jpg", - "jpeg", - "png" + "_representations": [ ], "node_name_template": "{class_name}_{ext}" } diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_load.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_load.json index 737843ad98..5bd8337e4c 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_load.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_load.json @@ -13,12 +13,8 @@ "label": "Image Loader" }, { - "key": "LoadMov", - "label": "Movie Loader" - }, - { - "key": "LoadSequence", - "label": "Image Sequence Loader" + "key": "LoadClip", + "label": "Clip Loader" } ] } diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin_nuke.json b/openpype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin_nuke.json index d01691ed5f..7ee8d0bda0 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin_nuke.json @@ -13,13 +13,7 @@ }, { "type": "list", - "key": "families", - "label": "Families", - "object_type": "text" - }, - { - "type": "list", - "key": "representations", + "key": "_representations", "label": "Representations", "object_type": "text" }, From 4d1eef14f16518b6bac1966021b4700660f2f333 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 16:55:19 +0200 Subject: [PATCH 120/150] Nuke: new unified plugin for all clip data (sequence, video) --- openpype/hosts/nuke/plugins/load/load_clip.py | 340 ++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 openpype/hosts/nuke/plugins/load/load_clip.py diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py new file mode 100644 index 0000000000..532d3dba2a --- /dev/null +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -0,0 +1,340 @@ +import nuke +from avalon.vendor import qargparse +from avalon import api, io + +from openpype.hosts.nuke.api.lib import ( + get_imageio_input_colorspace +) + +from openpype.hosts.nuke.api.plugin import ( + get_review_presets_config) + + +class LoadClip(api.Loader): + """Load clip into Nuke + + Either it is image sequence or video file. + """ + + families = [ + "source", + "plate", + "render", + "prerender", + "review" + ] + representations = ([ + "exr", "dpx", "mov", + "review", "mp4"] + + get_review_presets_config()) + + label = "Load Clip" + order = -20 + icon = "file-video-o" + color = "white" + + script_start = nuke.root()["first_frame"].value() + + # option gui + defaults = { + "start_at_workfile": True + } + + options = [ + qargparse.Boolean( + "start_at_workfile", + help="Load at workfile start frame", + default=True + ) + ] + + node_name_template = "" + + @classmethod + def get_representations(cls): + return cls.representations + cls._representations + + def load(self, context, name, namespace, options): + from avalon.nuke import ( + containerise, + viewer_update_and_undo_stop + ) + + start_at_workfile = options.get( + "start_at_workfile", self.defaults["start_at_workfile"]) + + version = context['version'] + version_data = version.get("data", {}) + repr_id = context["representation"]["_id"] + + self.log.info("version_data: {}\n".format(version_data)) + self.log.debug( + "Representation id `{}` ".format(repr_id)) + + self.first_frame = int(nuke.root()["first_frame"].getValue()) + self.handle_start = version_data.get("handleStart", 0) + self.handle_end = version_data.get("handleEnd", 0) + + first = version_data.get("frameStart", None) + last = version_data.get("frameEnd", None) + + # Fallback to asset name when namespace is None + if namespace is None: + namespace = context['asset']['name'] + + first -= self.handle_start + last += self.handle_end + + file = self.fname + + if not file: + repr_id = context["representation"]["_id"] + self.log.warning( + "Representation id `{}` is failing to load".format(repr_id)) + return + + file = file.replace("\\", "/") + + repr_cont = context["representation"]["context"] + assert repr_cont.get("frame"), "Representation is not sequence" + + if "#" not in file: + frame = repr_cont.get("frame") + if frame: + padding = len(frame) + file = file.replace(frame, "#" * padding) + + name_data = { + "asset": repr_cont["asset"], + "subset": repr_cont["subset"], + "representation": context["representation"]["name"], + "ext": repr_cont["representation"], + "id": context["representation"]["_id"], + "class_name": self.__class__.__name__ + } + + read_name = self.node_name_template.format(**name_data) + + # Create the Loader with the filename path set + read_node = nuke.createNode( + "Read", + "name {}".format(read_name)) + + # to avoid multiple undo steps for rest of process + # we will switch off undo-ing + with viewer_update_and_undo_stop(): + read_node["file"].setValue(file) + + # Set colorspace defined in version data + colorspace = context["version"]["data"].get("colorspace") + if colorspace: + read_node["colorspace"].setValue(str(colorspace)) + + preset_clrsp = get_imageio_input_colorspace(file) + + if preset_clrsp is not None: + read_node["colorspace"].setValue(preset_clrsp) + + # set start frame depending on workfile or version + self.loader_shift(read_node, start_at_workfile) + read_node["origfirst"].setValue(int(first)) + read_node["first"].setValue(int(first)) + read_node["origlast"].setValue(int(last)) + read_node["last"].setValue(int(last)) + + # add additional metadata from the version to imprint Avalon knob + add_keys = ["frameStart", "frameEnd", + "source", "colorspace", "author", "fps", "version", + "handleStart", "handleEnd"] + + data_imprint = {} + for k in add_keys: + if k == 'version': + data_imprint.update({k: context["version"]['name']}) + else: + data_imprint.update( + {k: context["version"]['data'].get(k, str(None))}) + + data_imprint.update({"objectName": read_name}) + + read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) + + if version_data.get("retime", None): + speed = version_data.get("speed", 1) + time_warp_nodes = version_data.get("timewarps", []) + self.make_retimes(speed, time_warp_nodes) + + return containerise(read_node, + name=name, + namespace=namespace, + context=context, + loader=self.__class__.__name__, + data=data_imprint) + + def switch(self, container, representation): + self.update(container, representation) + + def update(self, container, representation): + """Update the Loader's path + + Nuke automatically tries to reset some variables when changing + the loader's path to a new file. These automatic changes are to its + inputs: + + """ + + from avalon.nuke import ( + update_container + ) + + read_node = nuke.toNode(container['objectName']) + + assert read_node.Class() == "Read", "Must be Read" + + repr_cont = representation["context"] + assert repr_cont.get("frame"), "Representation is not sequence" + + file = api.get_representation_path(representation) + + if not file: + repr_id = representation["_id"] + self.log.warning( + "Representation id `{}` is failing to load".format(repr_id)) + return + + file = file.replace("\\", "/") + + if "#" not in file: + frame = repr_cont.get("frame") + if frame: + padding = len(frame) + file = file.replace(frame, "#" * padding) + + # Get start frame from version data + version = io.find_one({ + "type": "version", + "_id": representation["parent"] + }) + + # get all versions in list + versions = io.find({ + "type": "version", + "parent": version["parent"] + }).distinct('name') + + max_version = max(versions) + + version_data = version.get("data", {}) + + self.first_frame = int(nuke.root()["first_frame"].getValue()) + self.handle_start = version_data.get("handleStart", 0) + self.handle_end = version_data.get("handleEnd", 0) + + first = version_data.get("frameStart") + last = version_data.get("frameEnd") + + if first is None: + self.log.warning( + "Missing start frame for updated version" + "assuming starts at frame 0 for: " + "{} ({})".format(read_node['name'].value(), representation)) + first = 0 + + first -= self.handle_start + last += self.handle_end + + read_node["file"].setValue(file) + + # set start frame depending on workfile or version + self.loader_shift( + read_node, + bool("start at" in read_node['frame_mode'].value())) + + read_node["origfirst"].setValue(int(first)) + read_node["first"].setValue(int(first)) + read_node["origlast"].setValue(int(last)) + read_node["last"].setValue(int(last)) + + updated_dict = {} + updated_dict.update({ + "representation": str(representation["_id"]), + "frameStart": str(first), + "frameEnd": str(last), + "version": str(version.get("name")), + "colorspace": version_data.get("colorspace"), + "source": version_data.get("source"), + "handleStart": str(self.handle_start), + "handleEnd": str(self.handle_end), + "fps": str(version_data.get("fps")), + "author": version_data.get("author"), + "outputDir": version_data.get("outputDir"), + }) + + # change color of read_node + if version.get("name") not in [max_version]: + read_node["tile_color"].setValue(int("0xd84f20ff", 16)) + else: + read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) + + if version_data.get("retime", None): + speed = version_data.get("speed", 1) + time_warp_nodes = version_data.get("timewarps", []) + self.make_retimes(speed, time_warp_nodes) + + # Update the imprinted representation + update_container( + read_node, + updated_dict + ) + self.log.info("udated to version: {}".format(version.get("name"))) + + def remove(self, container): + + from avalon.nuke import viewer_update_and_undo_stop + + read_node = nuke.toNode(container['objectName']) + assert read_node.Class() == "Read", "Must be Read" + + with viewer_update_and_undo_stop(): + nuke.delete(read_node) + + def make_retimes(self, speed, time_warp_nodes): + ''' Create all retime and timewarping nodes with coppied animation ''' + if speed != 1: + rtn = nuke.createNode( + "Retime", + "speed {}".format(speed)) + rtn["before"].setValue("continue") + rtn["after"].setValue("continue") + rtn["input.first_lock"].setValue(True) + rtn["input.first"].setValue( + self.first_frame + ) + + if time_warp_nodes != []: + start_anim = self.first_frame + (self.handle_start / speed) + for timewarp in time_warp_nodes: + twn = nuke.createNode(timewarp["Class"], + "name {}".format(timewarp["name"])) + if isinstance(timewarp["lookup"], list): + # if array for animation + twn["lookup"].setAnimated() + for i, value in enumerate(timewarp["lookup"]): + twn["lookup"].setValueAt( + (start_anim + i) + value, + (start_anim + i)) + else: + # if static value `int` + twn["lookup"].setValue(timewarp["lookup"]) + + def loader_shift(self, read_node, workfile_start=False): + """ Set start frame of read node to a workfile start + + Args: + read_node (nuke.Node): The nuke's read node + workfile_start (bool): set workfile start frame if true + + """ + if workfile_start: + read_node['frame_mode'].setValue("start at") + read_node['frame'].setValue(str(self.script_start)) From 6177281a7fca6f1eba796a03078ac60b444ca5f9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 17:01:19 +0200 Subject: [PATCH 121/150] Nuke: improving code of get_representation on loadClip --- openpype/hosts/nuke/plugins/load/load_clip.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index 532d3dba2a..97b91b53a3 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -23,10 +23,13 @@ class LoadClip(api.Loader): "prerender", "review" ] - representations = ([ - "exr", "dpx", "mov", - "review", "mp4"] - + get_review_presets_config()) + representations = [ + "exr", + "dpx", + "mov", + "review", + "mp4" + ] label = "Load Clip" order = -20 @@ -52,7 +55,11 @@ class LoadClip(api.Loader): @classmethod def get_representations(cls): - return cls.representations + cls._representations + return ( + cls.representations + + cls._representations + + get_review_presets_config() + ) def load(self, context, name, namespace, options): from avalon.nuke import ( From 9a662f1a5d7b6b4b115ec5fecf5adcb0437a433f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 17:03:33 +0200 Subject: [PATCH 122/150] Nuke: returning back node name template --- openpype/hosts/nuke/plugins/load/load_clip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index 97b91b53a3..f4fb765a43 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -51,7 +51,7 @@ class LoadClip(api.Loader): ) ] - node_name_template = "" + node_name_template = "{class_name}_{ext}" @classmethod def get_representations(cls): From 7991c806d645b91921557cf1bd0a62590982d7b9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 12 Oct 2021 17:35:39 +0200 Subject: [PATCH 123/150] Nuke: LoadClip wip integrating video file loading --- openpype/hosts/nuke/plugins/load/load_clip.py | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index f4fb765a43..0bb030564a 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -36,7 +36,7 @@ class LoadClip(api.Loader): icon = "file-video-o" color = "white" - script_start = nuke.root()["first_frame"].value() + script_start = int(nuke.root()["first_frame"].value()) # option gui defaults = { @@ -66,6 +66,9 @@ class LoadClip(api.Loader): containerise, viewer_update_and_undo_stop ) + is_sequence = len(context["representation"]["files"]) <= 1 + + file = self.fname.replace("\\", "/") start_at_workfile = options.get( "start_at_workfile", self.defaults["start_at_workfile"]) @@ -73,44 +76,42 @@ class LoadClip(api.Loader): version = context['version'] version_data = version.get("data", {}) repr_id = context["representation"]["_id"] + colorspace = version_data.get("colorspace") + repr_cont = context["representation"]["context"] self.log.info("version_data: {}\n".format(version_data)) self.log.debug( "Representation id `{}` ".format(repr_id)) - self.first_frame = int(nuke.root()["first_frame"].getValue()) self.handle_start = version_data.get("handleStart", 0) self.handle_end = version_data.get("handleEnd", 0) first = version_data.get("frameStart", None) last = version_data.get("frameEnd", None) + first -= self.handle_start + last += self.handle_end + + if not is_sequence: + duration = last - first + 1 + first = 1 + last = first + duration + elif "#" not in file: + frame = repr_cont.get("frame") + assert frame, "Representation is not sequence" + + padding = len(frame) + file = file.replace(frame, "#" * padding) # Fallback to asset name when namespace is None if namespace is None: namespace = context['asset']['name'] - first -= self.handle_start - last += self.handle_end - - file = self.fname - if not file: repr_id = context["representation"]["_id"] self.log.warning( "Representation id `{}` is failing to load".format(repr_id)) return - file = file.replace("\\", "/") - - repr_cont = context["representation"]["context"] - assert repr_cont.get("frame"), "Representation is not sequence" - - if "#" not in file: - frame = repr_cont.get("frame") - if frame: - padding = len(frame) - file = file.replace(frame, "#" * padding) - name_data = { "asset": repr_cont["asset"], "subset": repr_cont["subset"], @@ -133,7 +134,6 @@ class LoadClip(api.Loader): read_node["file"].setValue(file) # Set colorspace defined in version data - colorspace = context["version"]["data"].get("colorspace") if colorspace: read_node["colorspace"].setValue(str(colorspace)) @@ -233,7 +233,6 @@ class LoadClip(api.Loader): version_data = version.get("data", {}) - self.first_frame = int(nuke.root()["first_frame"].getValue()) self.handle_start = version_data.get("handleStart", 0) self.handle_end = version_data.get("handleEnd", 0) @@ -315,11 +314,11 @@ class LoadClip(api.Loader): rtn["after"].setValue("continue") rtn["input.first_lock"].setValue(True) rtn["input.first"].setValue( - self.first_frame + self.script_start ) if time_warp_nodes != []: - start_anim = self.first_frame + (self.handle_start / speed) + start_anim = self.script_start + (self.handle_start / speed) for timewarp in time_warp_nodes: twn = nuke.createNode(timewarp["Class"], "name {}".format(timewarp["name"])) From a1cc57d8ef8e2914e7e8a1726f65787a662fb989 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 13 Oct 2021 03:39:34 +0000 Subject: [PATCH 124/150] [Automated] Bump version --- CHANGELOG.md | 9 ++++----- openpype/version.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c88f5c9ca0..7f92fdc9f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [3.5.0-nightly.5](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.5.0-nightly.6](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.4.1...HEAD) @@ -28,10 +28,11 @@ - Nuke: Adding `still` image family workflow [\#2064](https://github.com/pypeclub/OpenPype/pull/2064) - Maya: validate authorized loaded plugins [\#2062](https://github.com/pypeclub/OpenPype/pull/2062) - Tools: add support for pyenv on windows [\#2051](https://github.com/pypeclub/OpenPype/pull/2051) -- SyncServer: Dropbox Provider [\#1979](https://github.com/pypeclub/OpenPype/pull/1979) **πŸ› Bug fixes** +- General: Disk mapping group [\#2120](https://github.com/pypeclub/OpenPype/pull/2120) +- Hiero: publishing effect first time makes wrong resources path [\#2115](https://github.com/pypeclub/OpenPype/pull/2115) - Add startup script for Houdini Core. [\#2110](https://github.com/pypeclub/OpenPype/pull/2110) - TVPaint: Behavior name of loop also accept repeat [\#2109](https://github.com/pypeclub/OpenPype/pull/2109) - Ftrack: Project settings save custom attributes skip unknown attributes [\#2103](https://github.com/pypeclub/OpenPype/pull/2103) @@ -65,7 +66,6 @@ - General: Startup validations [\#2054](https://github.com/pypeclub/OpenPype/pull/2054) - Nuke: proxy mode validator [\#2052](https://github.com/pypeclub/OpenPype/pull/2052) -- Ftrack: Removed ftrack interface [\#2049](https://github.com/pypeclub/OpenPype/pull/2049) - Settings UI: Deffered set value on entity [\#2044](https://github.com/pypeclub/OpenPype/pull/2044) - Loader: Families filtering [\#2043](https://github.com/pypeclub/OpenPype/pull/2043) - Settings UI: Project view enhancements [\#2042](https://github.com/pypeclub/OpenPype/pull/2042) @@ -102,6 +102,7 @@ **πŸš€ Enhancements** +- Ftrack: Removed ftrack interface [\#2049](https://github.com/pypeclub/OpenPype/pull/2049) - Added possibility to configure of synchronization of workfile version… [\#2041](https://github.com/pypeclub/OpenPype/pull/2041) - General: Task types in profiles [\#2036](https://github.com/pypeclub/OpenPype/pull/2036) - Console interpreter: Handle invalid sizes on initialization [\#2022](https://github.com/pypeclub/OpenPype/pull/2022) @@ -114,7 +115,6 @@ - Configurable items for providers without Settings [\#1987](https://github.com/pypeclub/OpenPype/pull/1987) - Global: Example addons [\#1986](https://github.com/pypeclub/OpenPype/pull/1986) - Standalone Publisher: Extract harmony zip handle workfile template [\#1982](https://github.com/pypeclub/OpenPype/pull/1982) -- Settings UI: Number sliders [\#1978](https://github.com/pypeclub/OpenPype/pull/1978) **πŸ› Bug fixes** @@ -129,7 +129,6 @@ - Nuke: last version from path gets correct version [\#1990](https://github.com/pypeclub/OpenPype/pull/1990) - nuke, resolve, hiero: precollector order lest then 0.5 [\#1984](https://github.com/pypeclub/OpenPype/pull/1984) - Last workfile with multiple work templates [\#1981](https://github.com/pypeclub/OpenPype/pull/1981) -- Collectors order [\#1977](https://github.com/pypeclub/OpenPype/pull/1977) ## [3.3.1](https://github.com/pypeclub/OpenPype/tree/3.3.1) (2021-08-20) diff --git a/openpype/version.py b/openpype/version.py index f6ace59d7d..3a589bac75 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.5.0-nightly.5" +__version__ = "3.5.0-nightly.6" From 26790f65f0c51b8ac61a01dbc8cf8bed839242f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 13 Oct 2021 10:08:37 +0200 Subject: [PATCH 125/150] openpype tray does not require to use it's qapplication --- openpype/tools/tray/pype_tray.py | 77 +++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/openpype/tools/tray/pype_tray.py b/openpype/tools/tray/pype_tray.py index 3050e206ce..0f817d7130 100644 --- a/openpype/tools/tray/pype_tray.py +++ b/openpype/tools/tray/pype_tray.py @@ -268,7 +268,6 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): # Set modules self.tray_man = TrayManager(self, self.parent) - self.tray_man.initialize_modules() # Add menu to Context of SystemTrayIcon self.setContextMenu(self.menu) @@ -291,6 +290,17 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): self._doubleclick = False self._click_pos = None + self._initializing_modules = False + + @property + def initializing_modules(self): + return self._initializing_modules + + def initialize_modules(self): + self._initializing_modules = True + self.tray_man.initialize_modules() + self._initializing_modules = False + def _click_timer_timeout(self): self._click_timer.stop() doubleclick = self._doubleclick @@ -334,38 +344,48 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): QtCore.QCoreApplication.exit() -class TrayMainWindow(QtWidgets.QMainWindow): - """ TrayMainWindow is base of Pype application. - - Every widget should have set this window as parent because - QSystemTrayIcon widget is not allowed to be a parent of any widget. - """ - +class PypeTrayStarter(QtCore.QObject): def __init__(self, app): - super(TrayMainWindow, self).__init__() - self.app = app + app.setQuitOnLastWindowClosed(False) + self._app = app + self._splash = None - self.tray_widget = SystemTrayIcon(self) - self.tray_widget.show() + main_window = QtWidgets.QMainWindow() + tray_widget = SystemTrayIcon(main_window) + start_timer = QtCore.QTimer() + start_timer.setInterval(100) + start_timer.start() -class PypeTrayApplication(QtWidgets.QApplication): - """Qt application manages application's control flow.""" + start_timer.timeout.connect(self._on_start_timer) - def __init__(self): - super(PypeTrayApplication, self).__init__(sys.argv) - # Allows to close widgets without exiting app - self.setQuitOnLastWindowClosed(False) + self._main_window = main_window + self._tray_widget = tray_widget + self._timer_counter = 0 + self._start_timer = start_timer - # Sets up splash - splash_widget = self.set_splash() + def _on_start_timer(self): + if self._timer_counter == 0: + self._timer_counter += 1 + splash = self._get_splash() + splash.show() + self._tray_widget.show() - splash_widget.show() - self.processEvents() - self.main_window = TrayMainWindow(self) - splash_widget.hide() + elif self._timer_counter == 1: + self._timer_counter += 1 + self._tray_widget.initialize_modules() - def set_splash(self): + elif not self._tray_widget.initializing_modules: + splash = self._get_splash() + splash.hide() + self._start_timer.stop() + + def _get_splash(self): + if self._splash is None: + self._splash = self._create_splash() + return self._splash + + def _create_splash(self): splash_pix = QtGui.QPixmap(resources.get_openpype_splash_filepath()) splash = QtWidgets.QSplashScreen(splash_pix) splash.setMask(splash_pix.mask()) @@ -377,7 +397,12 @@ class PypeTrayApplication(QtWidgets.QApplication): def main(): - app = PypeTrayApplication() + app = QtWidgets.QApplication.instance() + if not app: + app = QtWidgets.QApplication([]) + + starter = PypeTrayStarter(app) + # TODO remove when pype.exe will have an icon if os.name == "nt": import ctypes From c9b760fcdee596771434c1ce8141198ff0aaa4ed Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 13 Oct 2021 10:55:21 +0200 Subject: [PATCH 126/150] stop all threads in ftrack --- openpype/modules/default_modules/ftrack/ftrack_module.py | 2 +- openpype/modules/default_modules/ftrack/tray/ftrack_tray.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openpype/modules/default_modules/ftrack/ftrack_module.py b/openpype/modules/default_modules/ftrack/ftrack_module.py index 5a1fdbc276..73a4dfee82 100644 --- a/openpype/modules/default_modules/ftrack/ftrack_module.py +++ b/openpype/modules/default_modules/ftrack/ftrack_module.py @@ -371,7 +371,7 @@ class FtrackModule( return self.tray_module.validate() def tray_exit(self): - return self.tray_module.stop_action_server() + self.tray_module.tray_exit() def set_credentials_to_env(self, username, api_key): os.environ["FTRACK_API_USER"] = username or "" diff --git a/openpype/modules/default_modules/ftrack/tray/ftrack_tray.py b/openpype/modules/default_modules/ftrack/tray/ftrack_tray.py index 34e4646767..c6201a94f6 100644 --- a/openpype/modules/default_modules/ftrack/tray/ftrack_tray.py +++ b/openpype/modules/default_modules/ftrack/tray/ftrack_tray.py @@ -289,6 +289,10 @@ class FtrackTrayWrapper: parent_menu.addMenu(tray_menu) + def tray_exit(self): + self.stop_action_server() + self.stop_timer_thread() + # Definition of visibility of each menu actions def set_menu_visibility(self): self.tray_server_menu.menuAction().setVisible(self.bool_logged) From 339df3a586b3fc7c61e8e9755940d2f775f1e14f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 13 Oct 2021 10:58:20 +0200 Subject: [PATCH 127/150] wait for idle manager stop --- .../modules/default_modules/timers_manager/timers_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/modules/default_modules/timers_manager/timers_manager.py b/openpype/modules/default_modules/timers_manager/timers_manager.py index 1199db0611..7687d056f8 100644 --- a/openpype/modules/default_modules/timers_manager/timers_manager.py +++ b/openpype/modules/default_modules/timers_manager/timers_manager.py @@ -150,6 +150,7 @@ class TimersManager(OpenPypeModule, ITrayService): def tray_exit(self): if self._idle_manager: self._idle_manager.stop() + self._idle_manager.wait() def start_timer(self, project_name, asset_name, task_name, hierarchy): """ From 3f74b6b3854005ec238a8e3b3d551eed43bb187b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 13 Oct 2021 14:16:16 +0200 Subject: [PATCH 128/150] make sure CollectDefaultDeadlineServer is after CollectModules --- .../plugins/publish/collect_deadline_server_from_instance.py | 2 +- .../deadline/plugins/publish/collect_default_deadline_server.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py b/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py index 968bffd890..1bc4eaa067 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/collect_deadline_server_from_instance.py @@ -11,7 +11,7 @@ import pyblish.api class CollectDeadlineServerFromInstance(pyblish.api.InstancePlugin): """Collect Deadline Webservice URL from instance.""" - order = pyblish.api.CollectorOrder + 0.01 + order = pyblish.api.CollectorOrder + 0.02 label = "Deadline Webservice from the Instance" families = ["rendering"] diff --git a/openpype/modules/default_modules/deadline/plugins/publish/collect_default_deadline_server.py b/openpype/modules/default_modules/deadline/plugins/publish/collect_default_deadline_server.py index afb8583069..53231bd7e4 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/collect_default_deadline_server.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/collect_default_deadline_server.py @@ -6,7 +6,7 @@ import pyblish.api class CollectDefaultDeadlineServer(pyblish.api.ContextPlugin): """Collect default Deadline Webservice URL.""" - order = pyblish.api.CollectorOrder + order = pyblish.api.CollectorOrder + 0.01 label = "Default Deadline Webservice" def process(self, context): From 620909d0c7a6c328037cd88cfa312710032ccd68 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 13 Oct 2021 16:25:57 +0200 Subject: [PATCH 129/150] nuke: loadClip with update and retime creating parent nukeLoader --- openpype/hosts/nuke/api/plugin.py | 55 ++++ openpype/hosts/nuke/plugins/load/load_clip.py | 295 ++++++++++-------- 2 files changed, 215 insertions(+), 135 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index 71329c0d46..62eadecaf4 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -1,4 +1,10 @@ +import random +import string + import avalon.nuke +from avalon.nuke import lib as anlib +from avalon import api + from openpype.api import ( get_current_project_settings, PypeCreatorMixin @@ -39,3 +45,52 @@ def get_review_presets_config(): outputs.update(profile.get("outputs", {})) return [str(name) for name, _prop in outputs.items()] + + +class NukeLoader(api.Loader): + container_id_knob = "containerId" + container_id = ''.join(random.choice( + string.ascii_uppercase + string.digits) for _ in range(10)) + + def get_container_id(self, node): + id_knob = node.knobs().get(self.container_id_knob) + return id_knob.value() if id_knob else None + + def get_members(self, source): + """Return nodes that has same 'containerId' as `source`""" + source_id = self.get_container_id(source) + return [node for node in nuke.allNodes(recurseGroups=True) + if self.get_container_id(node) == source_id + and node is not source] if source_id else [] + + def set_as_member(self, node): + source_id = self.get_container_id(node) + + if source_id: + node[self.container_id_knob].setValue(self.container_id) + else: + HIDEN_FLAG = 0x00040000 + _knob = anlib.Knobby( + "String_Knob", + self.container_id, + flags=[nuke.READ_ONLY, HIDEN_FLAG]) + knob = _knob.create(self.container_id_knob) + node.addKnob(knob) + + def clear_members(self, parent_node): + members = self.get_members(parent_node) + + dependent_nodes = None + for node in members: + _depndc = [n for n in node.dependent() if n not in members] + if not _depndc: + continue + + dependent_nodes = _depndc + break + + for member in members: + self.log.info("removing node: `{}".format(member.name())) + nuke.delete(member) + + return dependent_nodes diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index 0bb030564a..f56120ae0a 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -5,12 +5,18 @@ from avalon import api, io from openpype.hosts.nuke.api.lib import ( get_imageio_input_colorspace ) +from avalon.nuke import ( + containerise, + update_container, + viewer_update_and_undo_stop, + maintained_selection +) +from openpype.hosts.nuke.api import plugin -from openpype.hosts.nuke.api.plugin import ( - get_review_presets_config) +reload(plugin) -class LoadClip(api.Loader): +class LoadClip(plugin.NukeLoader): """Load clip into Nuke Either it is image sequence or video file. @@ -58,15 +64,12 @@ class LoadClip(api.Loader): return ( cls.representations + cls._representations - + get_review_presets_config() + + plugin.get_review_presets_config() ) def load(self, context, name, namespace, options): - from avalon.nuke import ( - containerise, - viewer_update_and_undo_stop - ) - is_sequence = len(context["representation"]["files"]) <= 1 + + is_sequence = len(context["representation"]["files"]) > 1 file = self.fname.replace("\\", "/") @@ -77,6 +80,7 @@ class LoadClip(api.Loader): version_data = version.get("data", {}) repr_id = context["representation"]["_id"] colorspace = version_data.get("colorspace") + iio_colorspace = get_imageio_input_colorspace(file) repr_cont = context["representation"]["context"] self.log.info("version_data: {}\n".format(version_data)) @@ -107,7 +111,6 @@ class LoadClip(api.Loader): namespace = context['asset']['name'] if not file: - repr_id = context["representation"]["_id"] self.log.warning( "Representation id `{}` is failing to load".format(repr_id)) return @@ -127,6 +130,7 @@ class LoadClip(api.Loader): read_node = nuke.createNode( "Read", "name {}".format(read_name)) + self.set_as_member(read_node) # to avoid multiple undo steps for rest of process # we will switch off undo-ing @@ -136,18 +140,11 @@ class LoadClip(api.Loader): # Set colorspace defined in version data if colorspace: read_node["colorspace"].setValue(str(colorspace)) + elif iio_colorspace is not None: + read_node["colorspace"].setValue(iio_colorspace) - preset_clrsp = get_imageio_input_colorspace(file) + self.set_range_to_node(read_node, first, last, start_at_workfile) - if preset_clrsp is not None: - read_node["colorspace"].setValue(preset_clrsp) - - # set start frame depending on workfile or version - self.loader_shift(read_node, start_at_workfile) - read_node["origfirst"].setValue(int(first)) - read_node["first"].setValue(int(first)) - read_node["origlast"].setValue(int(last)) - read_node["last"].setValue(int(last)) # add additional metadata from the version to imprint Avalon knob add_keys = ["frameStart", "frameEnd", @@ -166,17 +163,18 @@ class LoadClip(api.Loader): read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) - if version_data.get("retime", None): - speed = version_data.get("speed", 1) - time_warp_nodes = version_data.get("timewarps", []) - self.make_retimes(speed, time_warp_nodes) + container = containerise( + read_node, + name=name, + namespace=namespace, + context=context, + loader=self.__class__.__name__, + data=data_imprint) - return containerise(read_node, - name=name, - namespace=namespace, - context=context, - loader=self.__class__.__name__, - data=data_imprint) + if version_data.get("retime", None): + self.make_retimes(read_node, version_data) + + return container def switch(self, container, representation): self.update(container, representation) @@ -190,109 +188,111 @@ class LoadClip(api.Loader): """ - from avalon.nuke import ( - update_container - ) + is_sequence = len(representation["files"]) > 1 read_node = nuke.toNode(container['objectName']) + file = api.get_representation_path(representation).replace("\\", "/") - assert read_node.Class() == "Read", "Must be Read" + start_at_workfile = bool("start at" in read_node['frame_mode'].value()) - repr_cont = representation["context"] - assert repr_cont.get("frame"), "Representation is not sequence" - - file = api.get_representation_path(representation) - - if not file: - repr_id = representation["_id"] - self.log.warning( - "Representation id `{}` is failing to load".format(repr_id)) - return - - file = file.replace("\\", "/") - - if "#" not in file: - frame = repr_cont.get("frame") - if frame: - padding = len(frame) - file = file.replace(frame, "#" * padding) - - # Get start frame from version data version = io.find_one({ "type": "version", "_id": representation["parent"] }) - - # get all versions in list - versions = io.find({ - "type": "version", - "parent": version["parent"] - }).distinct('name') - - max_version = max(versions) - version_data = version.get("data", {}) + repr_id = representation["_id"] + colorspace = version_data.get("colorspace") + iio_colorspace = get_imageio_input_colorspace(file) + repr_cont = representation["context"] self.handle_start = version_data.get("handleStart", 0) self.handle_end = version_data.get("handleEnd", 0) - first = version_data.get("frameStart") - last = version_data.get("frameEnd") - - if first is None: - self.log.warning( - "Missing start frame for updated version" - "assuming starts at frame 0 for: " - "{} ({})".format(read_node['name'].value(), representation)) - first = 0 - + first = version_data.get("frameStart", None) + last = version_data.get("frameEnd", None) first -= self.handle_start last += self.handle_end + if not is_sequence: + duration = last - first + 1 + first = 1 + last = first + duration + elif "#" not in file: + frame = repr_cont.get("frame") + assert frame, "Representation is not sequence" + + padding = len(frame) + file = file.replace(frame, "#" * padding) + + if not file: + self.log.warning( + "Representation id `{}` is failing to load".format(repr_id)) + return + read_node["file"].setValue(file) - # set start frame depending on workfile or version - self.loader_shift( - read_node, - bool("start at" in read_node['frame_mode'].value())) + # to avoid multiple undo steps for rest of process + # we will switch off undo-ing + with viewer_update_and_undo_stop(): - read_node["origfirst"].setValue(int(first)) - read_node["first"].setValue(int(first)) - read_node["origlast"].setValue(int(last)) - read_node["last"].setValue(int(last)) + # Set colorspace defined in version data + if colorspace: + read_node["colorspace"].setValue(str(colorspace)) + elif iio_colorspace is not None: + read_node["colorspace"].setValue(iio_colorspace) - updated_dict = {} - updated_dict.update({ - "representation": str(representation["_id"]), - "frameStart": str(first), - "frameEnd": str(last), - "version": str(version.get("name")), - "colorspace": version_data.get("colorspace"), - "source": version_data.get("source"), - "handleStart": str(self.handle_start), - "handleEnd": str(self.handle_end), - "fps": str(version_data.get("fps")), - "author": version_data.get("author"), - "outputDir": version_data.get("outputDir"), - }) + self.set_range_to_node(read_node, first, last, start_at_workfile) - # change color of read_node - if version.get("name") not in [max_version]: - read_node["tile_color"].setValue(int("0xd84f20ff", 16)) - else: - read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) + updated_dict = { + "representation": str(representation["_id"]), + "frameStart": str(first), + "frameEnd": str(last), + "version": str(version.get("name")), + "colorspace": colorspace, + "source": version_data.get("source"), + "handleStart": str(self.handle_start), + "handleEnd": str(self.handle_end), + "fps": str(version_data.get("fps")), + "author": version_data.get("author"), + "outputDir": version_data.get("outputDir"), + } + + # change color of read_node + # get all versions in list + versions = io.find({ + "type": "version", + "parent": version["parent"] + }).distinct('name') + + max_version = max(versions) + + if version.get("name") not in [max_version]: + read_node["tile_color"].setValue(int("0xd84f20ff", 16)) + else: + read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) + + # Update the imprinted representation + update_container( + read_node, + updated_dict + ) + self.log.info("udated to version: {}".format(version.get("name"))) if version_data.get("retime", None): - speed = version_data.get("speed", 1) - time_warp_nodes = version_data.get("timewarps", []) - self.make_retimes(speed, time_warp_nodes) + self.make_retimes(read_node, version_data) + else: + self.clear_members(read_node) - # Update the imprinted representation - update_container( - read_node, - updated_dict - ) - self.log.info("udated to version: {}".format(version.get("name"))) + self.set_as_member(read_node) + + def set_range_to_node(self, read_node, first, last, start_at_workfile): + read_node['origfirst'].setValue(int(first)) + read_node['first'].setValue(int(first)) + read_node['origlast'].setValue(int(last)) + read_node['last'].setValue(int(last)) + + # set start frame depending on workfile or version + self.loader_shift(read_node, start_at_workfile) def remove(self, container): @@ -302,36 +302,61 @@ class LoadClip(api.Loader): assert read_node.Class() == "Read", "Must be Read" with viewer_update_and_undo_stop(): + members = self.get_members(read_node) nuke.delete(read_node) + for member in members: + nuke.delete(member) - def make_retimes(self, speed, time_warp_nodes): + def make_retimes(self, parent_node, version_data): ''' Create all retime and timewarping nodes with coppied animation ''' - if speed != 1: - rtn = nuke.createNode( - "Retime", - "speed {}".format(speed)) - rtn["before"].setValue("continue") - rtn["after"].setValue("continue") - rtn["input.first_lock"].setValue(True) - rtn["input.first"].setValue( - self.script_start - ) + speed = version_data.get('speed', 1) + time_warp_nodes = version_data.get('timewarps', []) + last_node = None + source_id = self.get_container_id(parent_node) + self.log.info("__ source_id: {}".format(source_id)) + self.log.info("__ members: {}".format(self.get_members(parent_node))) + dependent_nodes = self.clear_members(parent_node) - if time_warp_nodes != []: - start_anim = self.script_start + (self.handle_start / speed) - for timewarp in time_warp_nodes: - twn = nuke.createNode(timewarp["Class"], - "name {}".format(timewarp["name"])) - if isinstance(timewarp["lookup"], list): - # if array for animation - twn["lookup"].setAnimated() - for i, value in enumerate(timewarp["lookup"]): - twn["lookup"].setValueAt( - (start_anim + i) + value, - (start_anim + i)) - else: - # if static value `int` - twn["lookup"].setValue(timewarp["lookup"]) + with maintained_selection(): + parent_node['selected'].setValue(True) + + if speed != 1: + rtn = nuke.createNode( + "Retime", + "speed {}".format(speed)) + + rtn["before"].setValue("continue") + rtn["after"].setValue("continue") + rtn["input.first_lock"].setValue(True) + rtn["input.first"].setValue( + self.script_start + ) + self.set_as_member(rtn) + last_node = rtn + + if time_warp_nodes != []: + start_anim = self.script_start + (self.handle_start / speed) + for timewarp in time_warp_nodes: + twn = nuke.createNode(timewarp["Class"], + "name {}".format(timewarp["name"])) + if isinstance(timewarp["lookup"], list): + # if array for animation + twn["lookup"].setAnimated() + for i, value in enumerate(timewarp["lookup"]): + twn["lookup"].setValueAt( + (start_anim + i) + value, + (start_anim + i)) + else: + # if static value `int` + twn["lookup"].setValue(timewarp["lookup"]) + + self.set_as_member(twn) + last_node = twn + + if dependent_nodes: + # connect to original inputs + for i, n in enumerate(dependent_nodes): + last_node.setInput(i, n) def loader_shift(self, read_node, workfile_start=False): """ Set start frame of read node to a workfile start From e4dc590242975ae6bca97e037db9d66697de1e74 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 13 Oct 2021 16:26:41 +0200 Subject: [PATCH 130/150] nuke: removing obsolete loader plugins --- openpype/hosts/nuke/plugins/load/load_mov.py | 347 ------------------ .../hosts/nuke/plugins/load/load_sequence.py | 320 ---------------- 2 files changed, 667 deletions(-) delete mode 100644 openpype/hosts/nuke/plugins/load/load_mov.py delete mode 100644 openpype/hosts/nuke/plugins/load/load_sequence.py diff --git a/openpype/hosts/nuke/plugins/load/load_mov.py b/openpype/hosts/nuke/plugins/load/load_mov.py deleted file mode 100644 index f7523d0a6e..0000000000 --- a/openpype/hosts/nuke/plugins/load/load_mov.py +++ /dev/null @@ -1,347 +0,0 @@ -import nuke -from avalon.vendor import qargparse -from avalon import api, io -from openpype.api import get_current_project_settings -from openpype.hosts.nuke.api.lib import ( - get_imageio_input_colorspace -) - - -def add_review_presets_config(): - returning = { - "families": list(), - "representations": list() - } - settings = get_current_project_settings() - review_profiles = ( - settings["global"] - ["publish"] - ["ExtractReview"] - ["profiles"] - ) - - outputs = {} - for profile in review_profiles: - outputs.update(profile.get("outputs", {})) - - for output, properities in outputs.items(): - returning["representations"].append(output) - returning["families"] += properities.get("families", []) - - return returning - - -class LoadMov(api.Loader): - """Load mov file into Nuke""" - families = ["render", "source", "plate", "review"] - representations = ["mov", "review", "mp4"] - - label = "Load mov" - order = -10 - icon = "code-fork" - color = "orange" - - first_frame = nuke.root()["first_frame"].value() - - # options gui - defaults = { - "start_at_workfile": True - } - - options = [ - qargparse.Boolean( - "start_at_workfile", - help="Load at workfile start frame", - default=True - ) - ] - - node_name_template = "{class_name}_{ext}" - - def load(self, context, name, namespace, options): - from avalon.nuke import ( - containerise, - viewer_update_and_undo_stop - ) - - start_at_workfile = options.get( - "start_at_workfile", self.defaults["start_at_workfile"]) - - version = context['version'] - version_data = version.get("data", {}) - repr_id = context["representation"]["_id"] - - self.handle_start = version_data.get("handleStart", 0) - self.handle_end = version_data.get("handleEnd", 0) - - orig_first = version_data.get("frameStart") - orig_last = version_data.get("frameEnd") - diff = orig_first - 1 - - first = orig_first - diff - last = orig_last - diff - - colorspace = version_data.get("colorspace") - repr_cont = context["representation"]["context"] - - self.log.debug( - "Representation id `{}` ".format(repr_id)) - - context["representation"]["_id"] - # create handles offset (only to last, because of mov) - last += self.handle_start + self.handle_end - - # Fallback to asset name when namespace is None - if namespace is None: - namespace = context['asset']['name'] - - file = self.fname - - if not file: - self.log.warning( - "Representation id `{}` is failing to load".format(repr_id)) - return - - file = file.replace("\\", "/") - - name_data = { - "asset": repr_cont["asset"], - "subset": repr_cont["subset"], - "representation": context["representation"]["name"], - "ext": repr_cont["representation"], - "id": context["representation"]["_id"], - "class_name": self.__class__.__name__ - } - - read_name = self.node_name_template.format(**name_data) - - read_node = nuke.createNode( - "Read", - "name {}".format(read_name) - ) - - # to avoid multiple undo steps for rest of process - # we will switch off undo-ing - with viewer_update_and_undo_stop(): - read_node["file"].setValue(file) - - read_node["origfirst"].setValue(first) - read_node["first"].setValue(first) - read_node["origlast"].setValue(last) - read_node["last"].setValue(last) - read_node['frame_mode'].setValue("start at") - - if start_at_workfile: - # start at workfile start - read_node['frame'].setValue(str(self.first_frame)) - else: - # start at version frame start - read_node['frame'].setValue( - str(orig_first - self.handle_start)) - - if colorspace: - read_node["colorspace"].setValue(str(colorspace)) - - preset_clrsp = get_imageio_input_colorspace(file) - - if preset_clrsp is not None: - read_node["colorspace"].setValue(preset_clrsp) - - # add additional metadata from the version to imprint Avalon knob - add_keys = [ - "frameStart", "frameEnd", "handles", "source", "author", - "fps", "version", "handleStart", "handleEnd" - ] - - data_imprint = {} - for key in add_keys: - if key == 'version': - data_imprint.update({ - key: context["version"]['name'] - }) - else: - data_imprint.update({ - key: context["version"]['data'].get(key, str(None)) - }) - - data_imprint.update({"objectName": read_name}) - - read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) - - if version_data.get("retime", None): - speed = version_data.get("speed", 1) - time_warp_nodes = version_data.get("timewarps", []) - self.make_retimes(speed, time_warp_nodes) - - return containerise( - read_node, - name=name, - namespace=namespace, - context=context, - loader=self.__class__.__name__, - data=data_imprint - ) - - def switch(self, container, representation): - self.update(container, representation) - - def update(self, container, representation): - """Update the Loader's path - - Nuke automatically tries to reset some variables when changing - the loader's path to a new file. These automatic changes are to its - inputs: - - """ - - from avalon.nuke import ( - update_container - ) - - read_node = nuke.toNode(container['objectName']) - - assert read_node.Class() == "Read", "Must be Read" - - file = self.fname - - if not file: - repr_id = representation["_id"] - self.log.warning( - "Representation id `{}` is failing to load".format(repr_id)) - return - - file = file.replace("\\", "/") - - # Get start frame from version data - version = io.find_one({ - "type": "version", - "_id": representation["parent"] - }) - - # get all versions in list - versions = io.find({ - "type": "version", - "parent": version["parent"] - }).distinct('name') - - max_version = max(versions) - - version_data = version.get("data", {}) - - orig_first = version_data.get("frameStart") - orig_last = version_data.get("frameEnd") - diff = orig_first - 1 - - # set first to 1 - first = orig_first - diff - last = orig_last - diff - self.handle_start = version_data.get("handleStart", 0) - self.handle_end = version_data.get("handleEnd", 0) - colorspace = version_data.get("colorspace") - - if first is None: - self.log.warning(( - "Missing start frame for updated version" - "assuming starts at frame 0 for: " - "{} ({})").format( - read_node['name'].value(), representation)) - first = 0 - - # create handles offset (only to last, because of mov) - last += self.handle_start + self.handle_end - - read_node["file"].setValue(file) - - # Set the global in to the start frame of the sequence - read_node["origfirst"].setValue(first) - read_node["first"].setValue(first) - read_node["origlast"].setValue(last) - read_node["last"].setValue(last) - read_node['frame_mode'].setValue("start at") - - if int(float(self.first_frame)) == int( - float(read_node['frame'].value())): - # start at workfile start - read_node['frame'].setValue(str(self.first_frame)) - else: - # start at version frame start - read_node['frame'].setValue(str(orig_first - self.handle_start)) - - if colorspace: - read_node["colorspace"].setValue(str(colorspace)) - - preset_clrsp = get_imageio_input_colorspace(file) - - if preset_clrsp is not None: - read_node["colorspace"].setValue(preset_clrsp) - - updated_dict = {} - updated_dict.update({ - "representation": str(representation["_id"]), - "frameStart": str(first), - "frameEnd": str(last), - "version": str(version.get("name")), - "colorspace": version_data.get("colorspace"), - "source": version_data.get("source"), - "handleStart": str(self.handle_start), - "handleEnd": str(self.handle_end), - "fps": str(version_data.get("fps")), - "author": version_data.get("author"), - "outputDir": version_data.get("outputDir") - }) - - # change color of node - if version.get("name") not in [max_version]: - read_node["tile_color"].setValue(int("0xd84f20ff", 16)) - else: - read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) - - if version_data.get("retime", None): - speed = version_data.get("speed", 1) - time_warp_nodes = version_data.get("timewarps", []) - self.make_retimes(speed, time_warp_nodes) - - # Update the imprinted representation - update_container( - read_node, updated_dict - ) - self.log.info("udated to version: {}".format(version.get("name"))) - - def remove(self, container): - - from avalon.nuke import viewer_update_and_undo_stop - - read_node = nuke.toNode(container['objectName']) - assert read_node.Class() == "Read", "Must be Read" - - with viewer_update_and_undo_stop(): - nuke.delete(read_node) - - def make_retimes(self, speed, time_warp_nodes): - ''' Create all retime and timewarping nodes with coppied animation ''' - if speed != 1: - rtn = nuke.createNode( - "Retime", - "speed {}".format(speed)) - rtn["before"].setValue("continue") - rtn["after"].setValue("continue") - rtn["input.first_lock"].setValue(True) - rtn["input.first"].setValue( - self.first_frame - ) - - if time_warp_nodes != []: - start_anim = self.first_frame + (self.handle_start / speed) - for timewarp in time_warp_nodes: - twn = nuke.createNode(timewarp["Class"], - "name {}".format(timewarp["name"])) - if isinstance(timewarp["lookup"], list): - # if array for animation - twn["lookup"].setAnimated() - for i, value in enumerate(timewarp["lookup"]): - twn["lookup"].setValueAt( - (start_anim + i) + value, - (start_anim + i)) - else: - # if static value `int` - twn["lookup"].setValue(timewarp["lookup"]) diff --git a/openpype/hosts/nuke/plugins/load/load_sequence.py b/openpype/hosts/nuke/plugins/load/load_sequence.py deleted file mode 100644 index 003b406ee7..0000000000 --- a/openpype/hosts/nuke/plugins/load/load_sequence.py +++ /dev/null @@ -1,320 +0,0 @@ -import nuke -from avalon.vendor import qargparse -from avalon import api, io -from openpype.hosts.nuke.api.lib import ( - get_imageio_input_colorspace -) - - -class LoadSequence(api.Loader): - """Load image sequence into Nuke""" - - families = ["render", "source", "plate", "review"] - representations = ["exr", "dpx"] - - label = "Load Image Sequence" - order = -20 - icon = "file-video-o" - color = "white" - - script_start = nuke.root()["first_frame"].value() - - # option gui - defaults = { - "start_at_workfile": True - } - - options = [ - qargparse.Boolean( - "start_at_workfile", - help="Load at workfile start frame", - default=True - ) - ] - - node_name_template = "{class_name}_{ext}" - - def load(self, context, name, namespace, options): - from avalon.nuke import ( - containerise, - viewer_update_and_undo_stop - ) - - start_at_workfile = options.get( - "start_at_workfile", self.defaults["start_at_workfile"]) - - version = context['version'] - version_data = version.get("data", {}) - repr_id = context["representation"]["_id"] - - self.log.info("version_data: {}\n".format(version_data)) - self.log.debug( - "Representation id `{}` ".format(repr_id)) - - self.first_frame = int(nuke.root()["first_frame"].getValue()) - self.handle_start = version_data.get("handleStart", 0) - self.handle_end = version_data.get("handleEnd", 0) - - first = version_data.get("frameStart", None) - last = version_data.get("frameEnd", None) - - # Fallback to asset name when namespace is None - if namespace is None: - namespace = context['asset']['name'] - - first -= self.handle_start - last += self.handle_end - - file = self.fname - - if not file: - repr_id = context["representation"]["_id"] - self.log.warning( - "Representation id `{}` is failing to load".format(repr_id)) - return - - file = file.replace("\\", "/") - - repr_cont = context["representation"]["context"] - assert repr_cont.get("frame"), "Representation is not sequence" - - if "#" not in file: - frame = repr_cont.get("frame") - if frame: - padding = len(frame) - file = file.replace(frame, "#" * padding) - - name_data = { - "asset": repr_cont["asset"], - "subset": repr_cont["subset"], - "representation": context["representation"]["name"], - "ext": repr_cont["representation"], - "id": context["representation"]["_id"], - "class_name": self.__class__.__name__ - } - - read_name = self.node_name_template.format(**name_data) - - # Create the Loader with the filename path set - read_node = nuke.createNode( - "Read", - "name {}".format(read_name)) - - # to avoid multiple undo steps for rest of process - # we will switch off undo-ing - with viewer_update_and_undo_stop(): - read_node["file"].setValue(file) - - # Set colorspace defined in version data - colorspace = context["version"]["data"].get("colorspace") - if colorspace: - read_node["colorspace"].setValue(str(colorspace)) - - preset_clrsp = get_imageio_input_colorspace(file) - - if preset_clrsp is not None: - read_node["colorspace"].setValue(preset_clrsp) - - # set start frame depending on workfile or version - self.loader_shift(read_node, start_at_workfile) - read_node["origfirst"].setValue(int(first)) - read_node["first"].setValue(int(first)) - read_node["origlast"].setValue(int(last)) - read_node["last"].setValue(int(last)) - - # add additional metadata from the version to imprint Avalon knob - add_keys = ["frameStart", "frameEnd", - "source", "colorspace", "author", "fps", "version", - "handleStart", "handleEnd"] - - data_imprint = {} - for k in add_keys: - if k == 'version': - data_imprint.update({k: context["version"]['name']}) - else: - data_imprint.update( - {k: context["version"]['data'].get(k, str(None))}) - - data_imprint.update({"objectName": read_name}) - - read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) - - if version_data.get("retime", None): - speed = version_data.get("speed", 1) - time_warp_nodes = version_data.get("timewarps", []) - self.make_retimes(speed, time_warp_nodes) - - return containerise(read_node, - name=name, - namespace=namespace, - context=context, - loader=self.__class__.__name__, - data=data_imprint) - - def switch(self, container, representation): - self.update(container, representation) - - def update(self, container, representation): - """Update the Loader's path - - Nuke automatically tries to reset some variables when changing - the loader's path to a new file. These automatic changes are to its - inputs: - - """ - - from avalon.nuke import ( - update_container - ) - - read_node = nuke.toNode(container['objectName']) - - assert read_node.Class() == "Read", "Must be Read" - - repr_cont = representation["context"] - assert repr_cont.get("frame"), "Representation is not sequence" - - file = api.get_representation_path(representation) - - if not file: - repr_id = representation["_id"] - self.log.warning( - "Representation id `{}` is failing to load".format(repr_id)) - return - - file = file.replace("\\", "/") - - if "#" not in file: - frame = repr_cont.get("frame") - if frame: - padding = len(frame) - file = file.replace(frame, "#" * padding) - - # Get start frame from version data - version = io.find_one({ - "type": "version", - "_id": representation["parent"] - }) - - # get all versions in list - versions = io.find({ - "type": "version", - "parent": version["parent"] - }).distinct('name') - - max_version = max(versions) - - version_data = version.get("data", {}) - - self.first_frame = int(nuke.root()["first_frame"].getValue()) - self.handle_start = version_data.get("handleStart", 0) - self.handle_end = version_data.get("handleEnd", 0) - - first = version_data.get("frameStart") - last = version_data.get("frameEnd") - - if first is None: - self.log.warning( - "Missing start frame for updated version" - "assuming starts at frame 0 for: " - "{} ({})".format(read_node['name'].value(), representation)) - first = 0 - - first -= self.handle_start - last += self.handle_end - - read_node["file"].setValue(file) - - # set start frame depending on workfile or version - self.loader_shift( - read_node, - bool("start at" in read_node['frame_mode'].value())) - - read_node["origfirst"].setValue(int(first)) - read_node["first"].setValue(int(first)) - read_node["origlast"].setValue(int(last)) - read_node["last"].setValue(int(last)) - - updated_dict = {} - updated_dict.update({ - "representation": str(representation["_id"]), - "frameStart": str(first), - "frameEnd": str(last), - "version": str(version.get("name")), - "colorspace": version_data.get("colorspace"), - "source": version_data.get("source"), - "handleStart": str(self.handle_start), - "handleEnd": str(self.handle_end), - "fps": str(version_data.get("fps")), - "author": version_data.get("author"), - "outputDir": version_data.get("outputDir"), - }) - - # change color of read_node - if version.get("name") not in [max_version]: - read_node["tile_color"].setValue(int("0xd84f20ff", 16)) - else: - read_node["tile_color"].setValue(int("0x4ecd25ff", 16)) - - if version_data.get("retime", None): - speed = version_data.get("speed", 1) - time_warp_nodes = version_data.get("timewarps", []) - self.make_retimes(speed, time_warp_nodes) - - # Update the imprinted representation - update_container( - read_node, - updated_dict - ) - self.log.info("udated to version: {}".format(version.get("name"))) - - def remove(self, container): - - from avalon.nuke import viewer_update_and_undo_stop - - read_node = nuke.toNode(container['objectName']) - assert read_node.Class() == "Read", "Must be Read" - - with viewer_update_and_undo_stop(): - nuke.delete(read_node) - - def make_retimes(self, speed, time_warp_nodes): - ''' Create all retime and timewarping nodes with coppied animation ''' - if speed != 1: - rtn = nuke.createNode( - "Retime", - "speed {}".format(speed)) - rtn["before"].setValue("continue") - rtn["after"].setValue("continue") - rtn["input.first_lock"].setValue(True) - rtn["input.first"].setValue( - self.first_frame - ) - - if time_warp_nodes != []: - start_anim = self.first_frame + (self.handle_start / speed) - for timewarp in time_warp_nodes: - twn = nuke.createNode(timewarp["Class"], - "name {}".format(timewarp["name"])) - if isinstance(timewarp["lookup"], list): - # if array for animation - twn["lookup"].setAnimated() - for i, value in enumerate(timewarp["lookup"]): - twn["lookup"].setValueAt( - (start_anim + i) + value, - (start_anim + i)) - else: - # if static value `int` - twn["lookup"].setValue(timewarp["lookup"]) - - def loader_shift(self, read_node, workfile_start=False): - """ Set start frame of read node to a workfile start - - Args: - read_node (nuke.Node): The nuke's read node - workfile_start (bool): set workfile start frame if true - - """ - if workfile_start: - read_node['frame_mode'].setValue("start at") - read_node['frame'].setValue(str(self.script_start)) From 818ffa1ac0442966989fc085bb0c1a280488e959 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 13 Oct 2021 16:54:33 +0200 Subject: [PATCH 131/150] global: patch discovery on pipeline too --- openpype/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/__init__.py b/openpype/__init__.py index 9d55006a67..11b563ebfe 100644 --- a/openpype/__init__.py +++ b/openpype/__init__.py @@ -69,6 +69,7 @@ def install(): """Install Pype to Avalon.""" from pyblish.lib import MessageHandler from openpype.modules import load_modules + from avalon import pipeline # Make sure modules are loaded load_modules() @@ -117,7 +118,9 @@ def install(): # apply monkey patched discover to original one log.info("Patching discovery") + avalon.discover = patched_discover + pipeline.discover = patched_discover avalon.on("taskChanged", _on_task_change) From 1b6da8f6981e2e794c6313198ac45ae76d98ae07 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 13 Oct 2021 16:55:07 +0200 Subject: [PATCH 132/150] nuke: replacing position of add to member --- openpype/hosts/nuke/plugins/load/load_clip.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index f56120ae0a..265ab39b07 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -130,7 +130,6 @@ class LoadClip(plugin.NukeLoader): read_node = nuke.createNode( "Read", "name {}".format(read_name)) - self.set_as_member(read_node) # to avoid multiple undo steps for rest of process # we will switch off undo-ing @@ -174,6 +173,8 @@ class LoadClip(plugin.NukeLoader): if version_data.get("retime", None): self.make_retimes(read_node, version_data) + self.set_as_member(read_node) + return container def switch(self, container, representation): From 2ae4b12f218cbf82ef15753bcf3b7a388b420ff1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 14 Oct 2021 12:07:13 +0200 Subject: [PATCH 133/150] Fix - oiiotool wasn't recognized even if present This caused to DWAA support not working even if it could --- openpype/lib/plugin_tools.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openpype/lib/plugin_tools.py b/openpype/lib/plugin_tools.py index 9dccadc44e..a982983805 100644 --- a/openpype/lib/plugin_tools.py +++ b/openpype/lib/plugin_tools.py @@ -377,7 +377,7 @@ def oiio_supported(): """ Checks if oiiotool is configured for this platform. - Expects full path to executable. + Triggers simple subprocess, handles exception if fails. 'should_decompress' will throw exception if configured, but not present or not working. @@ -385,7 +385,13 @@ def oiio_supported(): (bool) """ oiio_path = get_oiio_tools_path() - if not oiio_path or not os.path.exists(oiio_path): + if oiio_path: + try: + _ = run_subprocess([oiio_path, "-v"]) + except FileNotFoundError: + oiio_path = None + + if not oiio_path: log.debug("OIIOTool is not configured or not present at {}". format(oiio_path)) return False From d757793587b6f61fb6d8fd8b5a9a9f5332d9fb3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= <33513211+antirotor@users.noreply.github.com> Date: Thu, 14 Oct 2021 13:10:06 +0200 Subject: [PATCH 134/150] return when not sets --- openpype/hosts/maya/plugins/publish/extract_look.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/hosts/maya/plugins/publish/extract_look.py b/openpype/hosts/maya/plugins/publish/extract_look.py index bbf25ebdc7..e0b85907e9 100644 --- a/openpype/hosts/maya/plugins/publish/extract_look.py +++ b/openpype/hosts/maya/plugins/publish/extract_look.py @@ -205,6 +205,9 @@ class ExtractLook(openpype.api.Extractor): lookdata = instance.data["lookData"] relationships = lookdata["relationships"] sets = relationships.keys() + if not sets: + self.log.info("No sets found") + return results = self.process_resources(instance, staging_dir=dir_path) transfers = results["fileTransfers"] From 0c410bb2b1d05e9d253bd0f867fdb5ed670b74ed Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Thu, 14 Oct 2021 13:47:00 +0200 Subject: [PATCH 135/150] add UI booleans --- .../defaults/project_settings/maya.json | 15 +++++++++++ .../schemas/schema_maya_publish.json | 25 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index c592d74350..72a0ab362d 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -315,6 +315,21 @@ "optional": true, "active": true }, + "ValidateRigContents": { + "enabled": false, + "optional": true, + "active": true + }, + "ValidateJointsHidden": { + "enabled": false, + "optional": true, + "active": true + }, + "ValidateRigControllers": { + "enabled": false, + "optional": true, + "active": true + }, "ValidateCameraAttributes": { "enabled": false, "optional": true, diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json index 26ebfb2bd7..f676094e90 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json @@ -166,7 +166,6 @@ } ] }, - { "type": "collapsible-wrap", "label": "Model", @@ -329,6 +328,30 @@ } ] }, + { + "type": "collapsible-wrap", + "label": "Rig", + "children": [ + { + "type": "schema_template", + "name": "template_publish_plugin", + "template_data": [ + { + "key": "ValidateRigContents", + "label": "Validate Rig Contents" + }, + { + "key": "ValidateJointsHidden", + "label": "Validate Joints Hidden" + }, + { + "key": "ValidateRigControllers", + "label": "Validate Rig Controllers" + } + ] + } + ] + }, { "type": "schema_template", "name": "template_publish_plugin", From 184ae8c2685af4ca87f846c36d9a7f738dce15af Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Thu, 14 Oct 2021 13:58:12 +0200 Subject: [PATCH 136/150] ValidateRigJointsHidden typo --- openpype/settings/defaults/project_settings/maya.json | 2 +- .../schemas/projects_schema/schemas/schema_maya_publish.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index 72a0ab362d..f8f3432d0f 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -320,7 +320,7 @@ "optional": true, "active": true }, - "ValidateJointsHidden": { + "ValidateRigJointsHidden": { "enabled": false, "optional": true, "active": true diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json index f676094e90..bde8c15958 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json @@ -341,8 +341,8 @@ "label": "Validate Rig Contents" }, { - "key": "ValidateJointsHidden", - "label": "Validate Joints Hidden" + "key": "ValidateRigJointsHidden", + "label": "Validate Rig JointsHidden" }, { "key": "ValidateRigControllers", From 8d69283b8a592ebf969bf6e61ce8735d14eec4a5 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 14 Oct 2021 16:27:43 +0200 Subject: [PATCH 137/150] PYPE-1343 - added project and task into context window --- openpype/hosts/maya/api/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/api/__init__.py b/openpype/hosts/maya/api/__init__.py index 725a075417..13f8a4cb78 100644 --- a/openpype/hosts/maya/api/__init__.py +++ b/openpype/hosts/maya/api/__init__.py @@ -313,9 +313,15 @@ def on_task_changed(*args): lib.set_context_settings() lib.update_content_on_context_change() + msg = " project: {}\n asset: {}\n task:{}".format( + avalon.Session["AVALON_PROJECT"], + avalon.Session["AVALON_ASSET"], + avalon.Session["AVALON_TASK"] + ) + lib.show_message( "Context was changed", - ("Context was changed to {}".format(avalon.Session["AVALON_ASSET"])), + ("Context was changed to:\n{}".format(msg)), ) From a10963188d1aaabdb170540e6d1635409d5829ba Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 14 Oct 2021 17:32:00 +0200 Subject: [PATCH 138/150] Fix - better approach for oiio_supported --- openpype/lib/plugin_tools.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/lib/plugin_tools.py b/openpype/lib/plugin_tools.py index a982983805..4eabb4d1ca 100644 --- a/openpype/lib/plugin_tools.py +++ b/openpype/lib/plugin_tools.py @@ -6,6 +6,7 @@ import logging import re import json import tempfile +import distutils from .execute import run_subprocess from .profiles_filtering import filter_profiles @@ -386,10 +387,7 @@ def oiio_supported(): """ oiio_path = get_oiio_tools_path() if oiio_path: - try: - _ = run_subprocess([oiio_path, "-v"]) - except FileNotFoundError: - oiio_path = None + oiio_path = distutils.spawn.find_executable(oiio_path) if not oiio_path: log.debug("OIIOTool is not configured or not present at {}". From df482e51b4e451ebd9ef38412b78a9c8b0a20077 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 14 Oct 2021 17:43:02 +0200 Subject: [PATCH 139/150] updated readme for entity types in settings --- openpype/settings/entities/schemas/README.md | 151 ++++++++++++------ .../schemas/system_schema/example_schema.json | 6 +- 2 files changed, 103 insertions(+), 54 deletions(-) diff --git a/openpype/settings/entities/schemas/README.md b/openpype/settings/entities/schemas/README.md index c8432f0f2e..5258fef9ec 100644 --- a/openpype/settings/entities/schemas/README.md +++ b/openpype/settings/entities/schemas/README.md @@ -2,7 +2,7 @@ ## Basic rules - configurations does not define GUI, but GUI defines configurations! -- output is always json (yaml is not needed for anatomy templates anymore) +- output is always json serializable - GUI schema has multiple input types, all inputs are represented by a dictionary - each input may have "input modifiers" (keys in dictionary) that are required or optional - only required modifier for all input items is key `"type"` which says what type of item it is @@ -13,16 +13,16 @@ - `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides - this keys is not allowed for all inputs as they may have not reason for that - key is validated, can be only once in hierarchy but is not required -- currently there are `system configurations` and `project configurations` +- currently there are `system settings` and `project settings` ## Inner schema - GUI schemas are huge json files, to be able to split whole configuration into multiple schema there's type `schema` -- system configuration schemas are stored in `~/tools/settings/settings/gui_schemas/system_schema/` and project configurations in `~/tools/settings/settings/gui_schemas/projects_schema/` +- system configuration schemas are stored in `~/openpype/settings/entities/schemas/system_schema/` and project configurations in `~/openpype/settings/entities/schemas/projects_schema/` - each schema name is filename of json file except extension (without ".json") - if content is dictionary content will be used as `schema` else will be used as `schema_template` ### schema -- can have only key `"children"` which is list of strings, each string should represent another schema (order matters) string represebts name of the schema +- can have only key `"children"` which is list of strings, each string should represent another schema (order matters) string represents name of the schema - will just paste schemas from other schema file in order of "children" list ``` @@ -32,8 +32,9 @@ } ``` -### schema_template +### template - allows to define schema "templates" to not duplicate same content multiple times +- legacy name is `schema_template` (still usable) ```javascript // EXAMPLE json file content (filename: example_template.json) [ @@ -59,11 +60,11 @@ // EXAMPLE usage of the template in schema { "type": "dict", - "key": "schema_template_examples", + "key": "template_examples", "label": "Schema template examples", "children": [ { - "type": "schema_template", + "type": "template", // filename of template (example_template.json) "name": "example_template", "template_data": { @@ -72,7 +73,7 @@ "multipath_executables": false } }, { - "type": "schema_template", + "type": "template", "name": "example_template", "template_data": { "host_label": "Maya 2020", @@ -98,8 +99,16 @@ ... } ``` -- Unfilled fields can be also used for non string values, in that case value must contain only one key and value for fill must contain right type. +- Unfilled fields can be also used for non string values(e.g. dictionary), in that case value must contain only one key and value for fill must contain right type. ```javascript +// Passed data +{ + "executable_multiplatform": { + "type": "schema", + "name": "my_multiplatform_schema" + } +} +// Template content { ... // Allowed @@ -121,32 +130,34 @@ "name": "project_settings/global" } ``` -- all valid `ModuleSettingsDef` classes where calling of `get_settings_schemas` +- all valid `BaseModuleSettingsDef` classes where calling of `get_settings_schemas` will return dictionary where is key "project_settings/global" with schemas will extend and replace this item -- works almost the same way as templates +- dynamic schemas work almost the same way as templates - one item can be replaced by multiple items (or by 0 items) - goal is to dynamically loaded settings of OpenPype addons without having their schemas or default values in main repository + - values of these schemas are saved using the `BaseModuleSettingsDef` methods +- easiest is to use `JsonFilesSettingsDef` which has full implementation of storing default values to json files all you have to implement is method `get_settings_root_path` which should return path to root directory where settings schema can be found and will be saved ## Basic Dictionary inputs - these inputs wraps another inputs into {key: value} relation ## dict -- this is another dictionary input wrapping more inputs but visually makes them different -- item may be used as widget (in `list` or `dict-modifiable`) +- this is dictionary type wrapping more inputs with keys defined in schema +- may be used as dynamic children (e.g. in `list` or `dict-modifiable`) - in that case the only key modifier is `children` which is list of it's keys - USAGE: e.g. List of dictionaries where each dictionary have same structure. -- item may be with or without `"label"` if is not used as widget - - required keys are `"key"` under which will be stored - - without label it is just wrap item holding `"key"` - - can't have `"is_group"` key set to True as it breaks visual override showing - - if `"label"` is entetered there which will be shown in GUI - - item with label can be collapsible - - that can be set with key `"collapsible"` as `True`/`False` (Default: `True`) - - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) - - it is possible to add darker background with `"highlight_content"` (Default: `False`) - - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color +- if is not used as dynamic children then must have defined `"key"` under which are it's values stored +- may be with or without `"label"` (only for GUI) + - `"label"` must be set to be able mark item as group with `"is_group"` key set to True +- item with label can visually wrap it's children + - this option is enabled by default to turn off set `"use_label_wrap"` to `False` + - label wrap is by default collapsible + - that can be set with key `"collapsible"` to `True`/`False` + - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) + - it is possible to add lighter background with `"highlight_content"` (Default: `False`) + - lighter background has limits of maximum applies after 3-4 nested highlighted items there is not much difference in the color - output is dictionary `{the "key": children values}` ``` # Example @@ -198,8 +209,8 @@ ``` ## dict-conditional -- is similar to `dict` but has only one child entity that will be always available -- the one entity is enumerator of possible values and based on value of the entity are defined and used other children entities +- is similar to `dict` but has always available one enum entity + - the enum entity has single selection and it's value define other children entities - each value of enumerator have defined children that will be used - there is no way how to have shared entities across multiple enum items - value from enumerator is also stored next to other values @@ -207,22 +218,27 @@ - `enum_key` must match key regex and any enum item can't have children with same key - `enum_label` is label of the entity for UI purposes - enum items are define with `enum_children` - - it's a list where each item represents enum item + - it's a list where each item represents single item for the enum - all items in `enum_children` must have at least `key` key which represents value stored under `enum_key` - - items can define `label` for UI purposes + - enum items can define `label` for UI purposes - most important part is that item can define `children` key where are definitions of it's children (`children` value works the same way as in `dict`) - to set default value for `enum_key` set it with `enum_default` - entity must have defined `"label"` if is not used as widget -- is set as group if any parent is not group -- if `"label"` is entetered there which will be shown in GUI - - item with label can be collapsible - - that can be set with key `"collapsible"` as `True`/`False` (Default: `True`) - - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) - - it is possible to add darker background with `"highlight_content"` (Default: `False`) - - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color - - output is dictionary `{the "key": children values}` +- is set as group if any parent is not group (can't have children as group) +- may be with or without `"label"` (only for GUI) + - `"label"` must be set to be able mark item as group with `"is_group"` key set to True +- item with label can visually wrap it's children + - this option is enabled by default to turn off set `"use_label_wrap"` to `False` + - label wrap is by default collapsible + - that can be set with key `"collapsible"` to `True`/`False` + - with key `"collapsed"` as `True`/`False` can be set that is collapsed when GUI is opened (Default: `False`) + - it is possible to add lighter background with `"highlight_content"` (Default: `False`) + - lighter background has limits of maximum applies after 3-4 nested highlighted items there is not much difference in the color - for UI porposes was added `enum_is_horizontal` which will make combobox appear next to children inputs instead of on top of them (Default: `False`) - this has extended ability of `enum_on_right` which will move combobox to right side next to children widgets (Default: `False`) +- output is dictionary `{the "key": children values}` +- using this type as template item for list type can be used to create infinite hierarchies + ``` # Example { @@ -298,8 +314,8 @@ How output of the schema could look like on save: ``` ## Inputs for setting any kind of value (`Pure` inputs) -- all these input must have defined `"key"` under which will be stored and `"label"` which will be shown next to input - - unless they are used in different types of inputs (later) "as widgets" in that case `"key"` and `"label"` are not required as there is not place where to set them +- all inputs must have defined `"key"` if are not used as dynamic item + - they can also have defined `"label"` ### boolean - simple checkbox, nothing more to set @@ -355,21 +371,15 @@ How output of the schema could look like on save: ``` ### path-input -- enhanced text input - - does not allow to enter backslash, is auto-converted to forward slash - - may be added another validations, like do not allow end path with slash - this input is implemented to add additional features to text input -- this is meant to be used in proxy input `path-widget` +- this is meant to be used in proxy input `path` - DO NOT USE this input in schema please ### raw-json - a little bit enhanced text input for raw json +- can store dictionary (`{}`) or list (`[]`) but not both + - by default stores dictionary to change it to list set `is_list` to `True` - has validations of json format - - empty value is invalid value, always must be json serializable - - valid value types are list `[]` and dictionary `{}` -- schema also defines valid value type - - by default it is dictionary - - to be able use list it is required to define `is_list` to `true` - output can be stored as string - this is to allow any keys in dictionary - set key `store_as_string` to `true` @@ -385,7 +395,7 @@ How output of the schema could look like on save: ``` ### enum -- returns value of single on multiple items from predefined values +- enumeration of values that are predefined in schema - multiselection can be allowed with setting key `"multiselection"` to `True` (Default: `False`) - values are defined under value of key `"enum_items"` as list - each item in list is simple dictionary where value is label and key is value which will be stored @@ -415,6 +425,8 @@ How output of the schema could look like on save: - have only single selection mode - it is possible to define default value `default` - `"work"` is used if default value is not specified +- enum values are not updated on the fly it is required to save templates and + reset settings to recache values ``` { "key": "host", @@ -449,6 +461,42 @@ How output of the schema could look like on save: } ``` +### apps-enum +- enumeration of available application and their variants from system settings + - applications without host name are excluded +- can be used only in project settings +- has only `multiselection` +- used only in project anatomy +``` +{ + "type": "apps-enum", + "key": "applications", + "label": "Applications" +} +``` + +### tools-enum +- enumeration of available tools and their variants from system settings +- can be used only in project settings +- has only `multiselection` +- used only in project anatomy +``` +{ + "type": "tools-enum", + "key": "tools_env", + "label": "Tools" +} +``` + +### task-types-enum +- enumeration of task types from current project +- enum values are not updated on the fly and modifications of task types on project require save and reset to be propagated to this enum +- has set `multiselection` to `True` but can be changed to `False` in schema + +### deadline_url-enum +- deadline module specific enumerator using deadline system settings to fill it's values +- TODO: move this type to deadline module + ## Inputs for setting value using Pure inputs - these inputs also have required `"key"` - attribute `"label"` is required in few conditions @@ -594,7 +642,7 @@ How output of the schema could look like on save: } ``` -### path-widget +### path - input for paths, use `path-input` internally - has 2 input modifiers `"multiplatform"` and `"multipath"` - `"multiplatform"` - adds `"windows"`, `"linux"` and `"darwin"` path inputs result is dictionary @@ -685,12 +733,13 @@ How output of the schema could look like on save: } ``` -### splitter -- visual splitter of items (more divider than splitter) +### separator +- legacy name is `splitter` (still usable) +- visual separator of items (more divider than separator) ``` { - "type": "splitter" + "type": "separator" } ``` diff --git a/openpype/settings/entities/schemas/system_schema/example_schema.json b/openpype/settings/entities/schemas/system_schema/example_schema.json index af6a2d49f4..c30e1f6848 100644 --- a/openpype/settings/entities/schemas/system_schema/example_schema.json +++ b/openpype/settings/entities/schemas/system_schema/example_schema.json @@ -95,11 +95,11 @@ }, { "type": "dict", - "key": "schema_template_exaples", + "key": "template_exaples", "label": "Schema template examples", "children": [ { - "type": "schema_template", + "type": "template", "name": "example_template", "template_data": { "host_label": "Application 1", @@ -108,7 +108,7 @@ } }, { - "type": "schema_template", + "type": "template", "name": "example_template", "template_data": { "host_label": "Application 2", From dd74ab89488a9369695bb528b906b0ffb68758f0 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 15 Oct 2021 14:16:22 +0200 Subject: [PATCH 140/150] hound: suggestions --- openpype/hosts/nuke/plugins/load/load_clip.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/nuke/plugins/load/load_clip.py b/openpype/hosts/nuke/plugins/load/load_clip.py index 265ab39b07..f8fc5e3928 100644 --- a/openpype/hosts/nuke/plugins/load/load_clip.py +++ b/openpype/hosts/nuke/plugins/load/load_clip.py @@ -13,8 +13,6 @@ from avalon.nuke import ( ) from openpype.hosts.nuke.api import plugin -reload(plugin) - class LoadClip(plugin.NukeLoader): """Load clip into Nuke @@ -144,7 +142,6 @@ class LoadClip(plugin.NukeLoader): self.set_range_to_node(read_node, first, last, start_at_workfile) - # add additional metadata from the version to imprint Avalon knob add_keys = ["frameStart", "frameEnd", "source", "colorspace", "author", "fps", "version", @@ -338,8 +335,10 @@ class LoadClip(plugin.NukeLoader): if time_warp_nodes != []: start_anim = self.script_start + (self.handle_start / speed) for timewarp in time_warp_nodes: - twn = nuke.createNode(timewarp["Class"], - "name {}".format(timewarp["name"])) + twn = nuke.createNode( + timewarp["Class"], + "name {}".format(timewarp["name"]) + ) if isinstance(timewarp["lookup"], list): # if array for animation twn["lookup"].setAnimated() From f91760cf1267e7b054f42feeb804c7e6b89b4765 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Fri, 15 Oct 2021 14:21:26 +0200 Subject: [PATCH 141/150] ValidateRigJointsHidden typo --- .../schemas/projects_schema/schemas/schema_maya_publish.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json index bde8c15958..cbacd12efa 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json @@ -342,7 +342,7 @@ }, { "key": "ValidateRigJointsHidden", - "label": "Validate Rig JointsHidden" + "label": "Validate Rig Joints Hidden" }, { "key": "ValidateRigControllers", From e39ffb35c55f974d4fad5dc231f1ae716e41e0ff Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 15 Oct 2021 14:23:00 +0200 Subject: [PATCH 142/150] updating avalon core --- repos/avalon-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repos/avalon-core b/repos/avalon-core index 4b80f81e66..7e5efd6885 160000 --- a/repos/avalon-core +++ b/repos/avalon-core @@ -1 +1 @@ -Subproject commit 4b80f81e66aca593784be8b299110a0b6541276f +Subproject commit 7e5efd6885330d84bb8495975bcab84df49bfa3d From 9f02356237614f15e96d7bebd715d31863137f27 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 16 Oct 2021 03:38:58 +0000 Subject: [PATCH 143/150] [Automated] Bump version --- CHANGELOG.md | 18 +++++++++--------- openpype/version.py | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f92fdc9f5..fe06b590f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [3.5.0-nightly.6](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.5.0-nightly.7](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.4.1...HEAD) @@ -10,12 +10,16 @@ **πŸ†• New features** +- Added project and task into context change message in Maya [\#2131](https://github.com/pypeclub/OpenPype/pull/2131) +- PYPE-1218 - changed namespace to contain subset name in Maya [\#2114](https://github.com/pypeclub/OpenPype/pull/2114) - Added running configurable disk mapping command before start of OP [\#2091](https://github.com/pypeclub/OpenPype/pull/2091) - SFTP provider [\#2073](https://github.com/pypeclub/OpenPype/pull/2073) - Maya: Validate setdress top group [\#2068](https://github.com/pypeclub/OpenPype/pull/2068) **πŸš€ Enhancements** +- Settings: Updated readme for entity types in settings [\#2132](https://github.com/pypeclub/OpenPype/pull/2132) +- Nuke: unified clip loader [\#2128](https://github.com/pypeclub/OpenPype/pull/2128) - Settings UI: Project model refreshing and sorting [\#2104](https://github.com/pypeclub/OpenPype/pull/2104) - Create Read From Rendered - Disable Relative paths by default [\#2093](https://github.com/pypeclub/OpenPype/pull/2093) - Added choosing different dirmap mapping if workfile synched locally [\#2088](https://github.com/pypeclub/OpenPype/pull/2088) @@ -31,6 +35,7 @@ **πŸ› Bug fixes** +- Fix - oiiotool wasn't recognized even if present [\#2129](https://github.com/pypeclub/OpenPype/pull/2129) - General: Disk mapping group [\#2120](https://github.com/pypeclub/OpenPype/pull/2120) - Hiero: publishing effect first time makes wrong resources path [\#2115](https://github.com/pypeclub/OpenPype/pull/2115) - Add startup script for Houdini Core. [\#2110](https://github.com/pypeclub/OpenPype/pull/2110) @@ -66,12 +71,11 @@ - General: Startup validations [\#2054](https://github.com/pypeclub/OpenPype/pull/2054) - Nuke: proxy mode validator [\#2052](https://github.com/pypeclub/OpenPype/pull/2052) -- Settings UI: Deffered set value on entity [\#2044](https://github.com/pypeclub/OpenPype/pull/2044) +- Ftrack: Removed ftrack interface [\#2049](https://github.com/pypeclub/OpenPype/pull/2049) - Loader: Families filtering [\#2043](https://github.com/pypeclub/OpenPype/pull/2043) - Settings UI: Project view enhancements [\#2042](https://github.com/pypeclub/OpenPype/pull/2042) - Settings for Nuke IncrementScriptVersion [\#2039](https://github.com/pypeclub/OpenPype/pull/2039) - Loader & Library loader: Use tools from OpenPype [\#2038](https://github.com/pypeclub/OpenPype/pull/2038) -- Adding predefined project folders creation in PM [\#2030](https://github.com/pypeclub/OpenPype/pull/2030) - WebserverModule: Removed interface of webserver module [\#2028](https://github.com/pypeclub/OpenPype/pull/2028) - TimersManager: Removed interface of timers manager [\#2024](https://github.com/pypeclub/OpenPype/pull/2024) - Feature Maya import asset from scene inventory [\#2018](https://github.com/pypeclub/OpenPype/pull/2018) @@ -102,9 +106,10 @@ **πŸš€ Enhancements** -- Ftrack: Removed ftrack interface [\#2049](https://github.com/pypeclub/OpenPype/pull/2049) +- Settings UI: Deffered set value on entity [\#2044](https://github.com/pypeclub/OpenPype/pull/2044) - Added possibility to configure of synchronization of workfile version… [\#2041](https://github.com/pypeclub/OpenPype/pull/2041) - General: Task types in profiles [\#2036](https://github.com/pypeclub/OpenPype/pull/2036) +- Adding predefined project folders creation in PM [\#2030](https://github.com/pypeclub/OpenPype/pull/2030) - Console interpreter: Handle invalid sizes on initialization [\#2022](https://github.com/pypeclub/OpenPype/pull/2022) - Ftrack: Show OpenPype versions in event server status [\#2019](https://github.com/pypeclub/OpenPype/pull/2019) - General: Staging icon [\#2017](https://github.com/pypeclub/OpenPype/pull/2017) @@ -112,9 +117,6 @@ - Modules: Connect method is not required [\#2009](https://github.com/pypeclub/OpenPype/pull/2009) - Settings UI: Number with configurable steps [\#2001](https://github.com/pypeclub/OpenPype/pull/2001) - Moving project folder structure creation out of ftrack module \#1989 [\#1996](https://github.com/pypeclub/OpenPype/pull/1996) -- Configurable items for providers without Settings [\#1987](https://github.com/pypeclub/OpenPype/pull/1987) -- Global: Example addons [\#1986](https://github.com/pypeclub/OpenPype/pull/1986) -- Standalone Publisher: Extract harmony zip handle workfile template [\#1982](https://github.com/pypeclub/OpenPype/pull/1982) **πŸ› Bug fixes** @@ -127,8 +129,6 @@ - Bugfix/webpublisher task type [\#2006](https://github.com/pypeclub/OpenPype/pull/2006) - Nuke thumbnails generated from middle of the sequence [\#1992](https://github.com/pypeclub/OpenPype/pull/1992) - Nuke: last version from path gets correct version [\#1990](https://github.com/pypeclub/OpenPype/pull/1990) -- nuke, resolve, hiero: precollector order lest then 0.5 [\#1984](https://github.com/pypeclub/OpenPype/pull/1984) -- Last workfile with multiple work templates [\#1981](https://github.com/pypeclub/OpenPype/pull/1981) ## [3.3.1](https://github.com/pypeclub/OpenPype/tree/3.3.1) (2021-08-20) diff --git a/openpype/version.py b/openpype/version.py index 3a589bac75..3bdad62e73 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.5.0-nightly.6" +__version__ = "3.5.0-nightly.7" From 81b271dd04020a0373c69d2046c8a65553984880 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sun, 17 Oct 2021 19:03:37 +0000 Subject: [PATCH 144/150] [Automated] Bump version --- CHANGELOG.md | 13 +++++++------ openpype/version.py | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe06b590f5..c011c000fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [3.5.0-nightly.7](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.5.0-nightly.8](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.4.1...HEAD) @@ -18,6 +18,7 @@ **πŸš€ Enhancements** +- Maya: make rig validators configurable in settings [\#2137](https://github.com/pypeclub/OpenPype/pull/2137) - Settings: Updated readme for entity types in settings [\#2132](https://github.com/pypeclub/OpenPype/pull/2132) - Nuke: unified clip loader [\#2128](https://github.com/pypeclub/OpenPype/pull/2128) - Settings UI: Project model refreshing and sorting [\#2104](https://github.com/pypeclub/OpenPype/pull/2104) @@ -50,10 +51,11 @@ - Deadline: Collect deadline server does not check existence of deadline key [\#2082](https://github.com/pypeclub/OpenPype/pull/2082) - Blender: fixed Curves with modifiers in Rigs [\#2081](https://github.com/pypeclub/OpenPype/pull/2081) - Maya: Fix multi-camera renders [\#2065](https://github.com/pypeclub/OpenPype/pull/2065) -- Fix Sync Queue when project disabled [\#2063](https://github.com/pypeclub/OpenPype/pull/2063) **Merged pull requests:** +- Maya: fix model publishing [\#2130](https://github.com/pypeclub/OpenPype/pull/2130) +- Add ExtractBurnin to photoshop review [\#2124](https://github.com/pypeclub/OpenPype/pull/2124) - Blender: Fix NoneType error when animation\_data is missing for a rig [\#2101](https://github.com/pypeclub/OpenPype/pull/2101) - Delivery Action Files Sequence fix [\#2096](https://github.com/pypeclub/OpenPype/pull/2096) - Bump pywin32 from 300 to 301 [\#2086](https://github.com/pypeclub/OpenPype/pull/2086) @@ -72,16 +74,19 @@ - General: Startup validations [\#2054](https://github.com/pypeclub/OpenPype/pull/2054) - Nuke: proxy mode validator [\#2052](https://github.com/pypeclub/OpenPype/pull/2052) - Ftrack: Removed ftrack interface [\#2049](https://github.com/pypeclub/OpenPype/pull/2049) +- Settings UI: Deffered set value on entity [\#2044](https://github.com/pypeclub/OpenPype/pull/2044) - Loader: Families filtering [\#2043](https://github.com/pypeclub/OpenPype/pull/2043) - Settings UI: Project view enhancements [\#2042](https://github.com/pypeclub/OpenPype/pull/2042) - Settings for Nuke IncrementScriptVersion [\#2039](https://github.com/pypeclub/OpenPype/pull/2039) - Loader & Library loader: Use tools from OpenPype [\#2038](https://github.com/pypeclub/OpenPype/pull/2038) +- Adding predefined project folders creation in PM [\#2030](https://github.com/pypeclub/OpenPype/pull/2030) - WebserverModule: Removed interface of webserver module [\#2028](https://github.com/pypeclub/OpenPype/pull/2028) - TimersManager: Removed interface of timers manager [\#2024](https://github.com/pypeclub/OpenPype/pull/2024) - Feature Maya import asset from scene inventory [\#2018](https://github.com/pypeclub/OpenPype/pull/2018) **πŸ› Bug fixes** +- Fix Sync Queue when project disabled [\#2063](https://github.com/pypeclub/OpenPype/pull/2063) - Timers manger: Typo fix [\#2058](https://github.com/pypeclub/OpenPype/pull/2058) - Hiero: Editorial fixes [\#2057](https://github.com/pypeclub/OpenPype/pull/2057) - Differentiate jpg sequences from thumbnail [\#2056](https://github.com/pypeclub/OpenPype/pull/2056) @@ -106,10 +111,8 @@ **πŸš€ Enhancements** -- Settings UI: Deffered set value on entity [\#2044](https://github.com/pypeclub/OpenPype/pull/2044) - Added possibility to configure of synchronization of workfile version… [\#2041](https://github.com/pypeclub/OpenPype/pull/2041) - General: Task types in profiles [\#2036](https://github.com/pypeclub/OpenPype/pull/2036) -- Adding predefined project folders creation in PM [\#2030](https://github.com/pypeclub/OpenPype/pull/2030) - Console interpreter: Handle invalid sizes on initialization [\#2022](https://github.com/pypeclub/OpenPype/pull/2022) - Ftrack: Show OpenPype versions in event server status [\#2019](https://github.com/pypeclub/OpenPype/pull/2019) - General: Staging icon [\#2017](https://github.com/pypeclub/OpenPype/pull/2017) @@ -127,8 +130,6 @@ - FFmpeg: Subprocess arguments as list [\#2032](https://github.com/pypeclub/OpenPype/pull/2032) - General: Fix Python 2 breaking line [\#2016](https://github.com/pypeclub/OpenPype/pull/2016) - Bugfix/webpublisher task type [\#2006](https://github.com/pypeclub/OpenPype/pull/2006) -- Nuke thumbnails generated from middle of the sequence [\#1992](https://github.com/pypeclub/OpenPype/pull/1992) -- Nuke: last version from path gets correct version [\#1990](https://github.com/pypeclub/OpenPype/pull/1990) ## [3.3.1](https://github.com/pypeclub/OpenPype/tree/3.3.1) (2021-08-20) diff --git a/openpype/version.py b/openpype/version.py index 3bdad62e73..5c8555c6a7 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.5.0-nightly.7" +__version__ = "3.5.0-nightly.8" From 8be1113edcb3e38333ce14842d530a57d2fbaaf6 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sun, 17 Oct 2021 19:33:06 +0000 Subject: [PATCH 145/150] [Automated] Release --- CHANGELOG.md | 24 ++++++++++++------------ openpype/version.py | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c011c000fd..95792f8a7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [3.5.0-nightly.8](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.5.0](https://github.com/pypeclub/OpenPype/tree/3.5.0) (2021-10-17) -[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.4.1...HEAD) +[Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.4.1...3.5.0) **Deprecated:** @@ -11,6 +11,7 @@ **πŸ†• New features** - Added project and task into context change message in Maya [\#2131](https://github.com/pypeclub/OpenPype/pull/2131) +- Add ExtractBurnin to photoshop review [\#2124](https://github.com/pypeclub/OpenPype/pull/2124) - PYPE-1218 - changed namespace to contain subset name in Maya [\#2114](https://github.com/pypeclub/OpenPype/pull/2114) - Added running configurable disk mapping command before start of OP [\#2091](https://github.com/pypeclub/OpenPype/pull/2091) - SFTP provider [\#2073](https://github.com/pypeclub/OpenPype/pull/2073) @@ -36,30 +37,30 @@ **πŸ› Bug fixes** +- Maya: fix model publishing [\#2130](https://github.com/pypeclub/OpenPype/pull/2130) - Fix - oiiotool wasn't recognized even if present [\#2129](https://github.com/pypeclub/OpenPype/pull/2129) - General: Disk mapping group [\#2120](https://github.com/pypeclub/OpenPype/pull/2120) - Hiero: publishing effect first time makes wrong resources path [\#2115](https://github.com/pypeclub/OpenPype/pull/2115) - Add startup script for Houdini Core. [\#2110](https://github.com/pypeclub/OpenPype/pull/2110) - TVPaint: Behavior name of loop also accept repeat [\#2109](https://github.com/pypeclub/OpenPype/pull/2109) - Ftrack: Project settings save custom attributes skip unknown attributes [\#2103](https://github.com/pypeclub/OpenPype/pull/2103) +- Blender: Fix NoneType error when animation\_data is missing for a rig [\#2101](https://github.com/pypeclub/OpenPype/pull/2101) - Fix broken import in sftp provider [\#2100](https://github.com/pypeclub/OpenPype/pull/2100) - Global: Fix docstring on publish plugin extract review [\#2097](https://github.com/pypeclub/OpenPype/pull/2097) +- Delivery Action Files Sequence fix [\#2096](https://github.com/pypeclub/OpenPype/pull/2096) - General: Cloud mongo ca certificate issue [\#2095](https://github.com/pypeclub/OpenPype/pull/2095) - TVPaint: Creator use context from workfile [\#2087](https://github.com/pypeclub/OpenPype/pull/2087) - Blender: fix texture missing when publishing blend files [\#2085](https://github.com/pypeclub/OpenPype/pull/2085) - General: Startup validations oiio tool path fix on linux [\#2083](https://github.com/pypeclub/OpenPype/pull/2083) - Deadline: Collect deadline server does not check existence of deadline key [\#2082](https://github.com/pypeclub/OpenPype/pull/2082) - Blender: fixed Curves with modifiers in Rigs [\#2081](https://github.com/pypeclub/OpenPype/pull/2081) +- Nuke UI scaling [\#2077](https://github.com/pypeclub/OpenPype/pull/2077) - Maya: Fix multi-camera renders [\#2065](https://github.com/pypeclub/OpenPype/pull/2065) +- Fix Sync Queue when project disabled [\#2063](https://github.com/pypeclub/OpenPype/pull/2063) **Merged pull requests:** -- Maya: fix model publishing [\#2130](https://github.com/pypeclub/OpenPype/pull/2130) -- Add ExtractBurnin to photoshop review [\#2124](https://github.com/pypeclub/OpenPype/pull/2124) -- Blender: Fix NoneType error when animation\_data is missing for a rig [\#2101](https://github.com/pypeclub/OpenPype/pull/2101) -- Delivery Action Files Sequence fix [\#2096](https://github.com/pypeclub/OpenPype/pull/2096) - Bump pywin32 from 300 to 301 [\#2086](https://github.com/pypeclub/OpenPype/pull/2086) -- Nuke UI scaling [\#2077](https://github.com/pypeclub/OpenPype/pull/2077) ## [3.4.1](https://github.com/pypeclub/OpenPype/tree/3.4.1) (2021-09-23) @@ -86,7 +87,6 @@ **πŸ› Bug fixes** -- Fix Sync Queue when project disabled [\#2063](https://github.com/pypeclub/OpenPype/pull/2063) - Timers manger: Typo fix [\#2058](https://github.com/pypeclub/OpenPype/pull/2058) - Hiero: Editorial fixes [\#2057](https://github.com/pypeclub/OpenPype/pull/2057) - Differentiate jpg sequences from thumbnail [\#2056](https://github.com/pypeclub/OpenPype/pull/2056) @@ -101,10 +101,6 @@ [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.4.0-nightly.6...3.4.0) -### πŸ“– Documentation - -- Documentation: Ftrack launch argsuments update [\#2014](https://github.com/pypeclub/OpenPype/pull/2014) - **πŸ†• New features** - Nuke: Compatibility with Nuke 13 [\#2003](https://github.com/pypeclub/OpenPype/pull/2003) @@ -131,6 +127,10 @@ - General: Fix Python 2 breaking line [\#2016](https://github.com/pypeclub/OpenPype/pull/2016) - Bugfix/webpublisher task type [\#2006](https://github.com/pypeclub/OpenPype/pull/2006) +### πŸ“– Documentation + +- Documentation: Ftrack launch argsuments update [\#2014](https://github.com/pypeclub/OpenPype/pull/2014) + ## [3.3.1](https://github.com/pypeclub/OpenPype/tree/3.3.1) (2021-08-20) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.3.1-nightly.1...3.3.1) diff --git a/openpype/version.py b/openpype/version.py index 5c8555c6a7..d88d79b995 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.5.0-nightly.8" +__version__ = "3.5.0" From c2e22ba7d669421aee76e690c52a85f3e16b40cd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 18 Oct 2021 13:15:38 +0200 Subject: [PATCH 146/150] Use dnxhd profile from input metadata --- openpype/scripts/otio_burnin.py | 34 ++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/openpype/scripts/otio_burnin.py b/openpype/scripts/otio_burnin.py index 184d7689e3..206abfc0b4 100644 --- a/openpype/scripts/otio_burnin.py +++ b/openpype/scripts/otio_burnin.py @@ -109,9 +109,7 @@ def _prores_codec_args(ffprobe_data, source_ffmpeg_cmd): def _h264_codec_args(ffprobe_data, source_ffmpeg_cmd): - output = [] - - output.extend(["-codec:v", "h264"]) + output = ["-codec:v", "h264"] # Use arguments from source if are available source arguments if source_ffmpeg_cmd: @@ -137,6 +135,32 @@ def _h264_codec_args(ffprobe_data, source_ffmpeg_cmd): return output +def _dnxhd_codec_args(ffprobe_data, source_ffmpeg_cmd): + output = ["-codec:v", "dnxhd"] + + # Use source profile (profiles in metadata are not usable in args directly) + profile = ffprobe_data.get("profile") or "" + # Lower profile and replace space with underscore + cleaned_profile = profile.lower().replace(" ", "_") + dnx_profiles = { + "dnxhd", + "dnxhr_lb", + "dnxhr_sq", + "dnxhr_hq", + "dnxhr_hqx", + "dnxhr_444" + } + if cleaned_profile in dnx_profiles: + output.extend(["-profile:v", cleaned_profile]) + + pix_fmt = ffprobe_data.get("pix_fmt") + if pix_fmt: + output.extend(["-pix_fmt", pix_fmt]) + + output.extend(["-g", "1"]) + return output + + def get_codec_args(ffprobe_data, source_ffmpeg_cmd): codec_name = ffprobe_data.get("codec_name") # Codec "prores" @@ -147,6 +171,10 @@ def get_codec_args(ffprobe_data, source_ffmpeg_cmd): if codec_name == "h264": return _h264_codec_args(ffprobe_data, source_ffmpeg_cmd) + # Coded DNxHD + if codec_name == "dnxhd": + return _dnxhd_codec_args(ffprobe_data, source_ffmpeg_cmd) + output = [] if codec_name: output.extend(["-codec:v", codec_name]) From 60eb375b67cb56b6737c43a2971f6f00c1a41bda Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 10:05:58 +0200 Subject: [PATCH 147/150] renamed 'new_publisher' to 'publisher' --- openpype/hosts/testhost/run_publish.py | 2 +- .../tools/{new_publisher => publisher}/__init__.py | 0 openpype/tools/{new_publisher => publisher}/app.py | 0 .../tools/{new_publisher => publisher}/constants.py | 0 .../tools/{new_publisher => publisher}/control.py | 0 .../publish_report_viewer/__init__.py | 0 .../publish_report_viewer/constants.py | 0 .../publish_report_viewer/delegates.py | 0 .../publish_report_viewer/model.py | 0 .../publish_report_viewer/widgets.py | 0 .../publish_report_viewer/window.py | 0 .../widgets/__init__.py | 0 .../widgets/border_label_widget.py | 0 .../widgets/card_view_widgets.py | 0 .../widgets/create_dialog.py | 0 .../{new_publisher => publisher}/widgets/icons.py | 0 .../widgets/images/add.png | Bin .../widgets/images/branch_closed.png | Bin .../widgets/images/branch_open.png | Bin .../widgets/images/change_view.png | Bin .../widgets/images/delete.png | Bin .../widgets/images/play.png | Bin .../widgets/images/refresh.png | Bin .../widgets/images/stop.png | Bin .../widgets/images/thumbnail.png | Bin .../widgets/images/validate.png | Bin .../widgets/images/warning.png | Bin .../widgets/list_view_widgets.py | 0 .../{new_publisher => publisher}/widgets/models.py | 0 .../widgets/publish_widget.py | 0 .../widgets/validations_widget.py | 0 .../{new_publisher => publisher}/widgets/widgets.py | 0 .../tools/{new_publisher => publisher}/window.py | 0 33 files changed, 1 insertion(+), 1 deletion(-) rename openpype/tools/{new_publisher => publisher}/__init__.py (100%) rename openpype/tools/{new_publisher => publisher}/app.py (100%) rename openpype/tools/{new_publisher => publisher}/constants.py (100%) rename openpype/tools/{new_publisher => publisher}/control.py (100%) rename openpype/tools/{new_publisher => publisher}/publish_report_viewer/__init__.py (100%) rename openpype/tools/{new_publisher => publisher}/publish_report_viewer/constants.py (100%) rename openpype/tools/{new_publisher => publisher}/publish_report_viewer/delegates.py (100%) rename openpype/tools/{new_publisher => publisher}/publish_report_viewer/model.py (100%) rename openpype/tools/{new_publisher => publisher}/publish_report_viewer/widgets.py (100%) rename openpype/tools/{new_publisher => publisher}/publish_report_viewer/window.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/__init__.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/border_label_widget.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/card_view_widgets.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/create_dialog.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/icons.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/add.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/branch_closed.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/branch_open.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/change_view.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/delete.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/play.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/refresh.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/stop.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/thumbnail.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/validate.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/images/warning.png (100%) rename openpype/tools/{new_publisher => publisher}/widgets/list_view_widgets.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/models.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/publish_widget.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/validations_widget.py (100%) rename openpype/tools/{new_publisher => publisher}/widgets/widgets.py (100%) rename openpype/tools/{new_publisher => publisher}/window.py (100%) diff --git a/openpype/hosts/testhost/run_publish.py b/openpype/hosts/testhost/run_publish.py index 1bb9c46806..5aa2df75fa 100644 --- a/openpype/hosts/testhost/run_publish.py +++ b/openpype/hosts/testhost/run_publish.py @@ -42,7 +42,7 @@ for path in [ from Qt import QtWidgets, QtCore -from openpype.tools.new_publisher.window import PublisherWindow +from openpype.tools.publisher.window import PublisherWindow def main(): diff --git a/openpype/tools/new_publisher/__init__.py b/openpype/tools/publisher/__init__.py similarity index 100% rename from openpype/tools/new_publisher/__init__.py rename to openpype/tools/publisher/__init__.py diff --git a/openpype/tools/new_publisher/app.py b/openpype/tools/publisher/app.py similarity index 100% rename from openpype/tools/new_publisher/app.py rename to openpype/tools/publisher/app.py diff --git a/openpype/tools/new_publisher/constants.py b/openpype/tools/publisher/constants.py similarity index 100% rename from openpype/tools/new_publisher/constants.py rename to openpype/tools/publisher/constants.py diff --git a/openpype/tools/new_publisher/control.py b/openpype/tools/publisher/control.py similarity index 100% rename from openpype/tools/new_publisher/control.py rename to openpype/tools/publisher/control.py diff --git a/openpype/tools/new_publisher/publish_report_viewer/__init__.py b/openpype/tools/publisher/publish_report_viewer/__init__.py similarity index 100% rename from openpype/tools/new_publisher/publish_report_viewer/__init__.py rename to openpype/tools/publisher/publish_report_viewer/__init__.py diff --git a/openpype/tools/new_publisher/publish_report_viewer/constants.py b/openpype/tools/publisher/publish_report_viewer/constants.py similarity index 100% rename from openpype/tools/new_publisher/publish_report_viewer/constants.py rename to openpype/tools/publisher/publish_report_viewer/constants.py diff --git a/openpype/tools/new_publisher/publish_report_viewer/delegates.py b/openpype/tools/publisher/publish_report_viewer/delegates.py similarity index 100% rename from openpype/tools/new_publisher/publish_report_viewer/delegates.py rename to openpype/tools/publisher/publish_report_viewer/delegates.py diff --git a/openpype/tools/new_publisher/publish_report_viewer/model.py b/openpype/tools/publisher/publish_report_viewer/model.py similarity index 100% rename from openpype/tools/new_publisher/publish_report_viewer/model.py rename to openpype/tools/publisher/publish_report_viewer/model.py diff --git a/openpype/tools/new_publisher/publish_report_viewer/widgets.py b/openpype/tools/publisher/publish_report_viewer/widgets.py similarity index 100% rename from openpype/tools/new_publisher/publish_report_viewer/widgets.py rename to openpype/tools/publisher/publish_report_viewer/widgets.py diff --git a/openpype/tools/new_publisher/publish_report_viewer/window.py b/openpype/tools/publisher/publish_report_viewer/window.py similarity index 100% rename from openpype/tools/new_publisher/publish_report_viewer/window.py rename to openpype/tools/publisher/publish_report_viewer/window.py diff --git a/openpype/tools/new_publisher/widgets/__init__.py b/openpype/tools/publisher/widgets/__init__.py similarity index 100% rename from openpype/tools/new_publisher/widgets/__init__.py rename to openpype/tools/publisher/widgets/__init__.py diff --git a/openpype/tools/new_publisher/widgets/border_label_widget.py b/openpype/tools/publisher/widgets/border_label_widget.py similarity index 100% rename from openpype/tools/new_publisher/widgets/border_label_widget.py rename to openpype/tools/publisher/widgets/border_label_widget.py diff --git a/openpype/tools/new_publisher/widgets/card_view_widgets.py b/openpype/tools/publisher/widgets/card_view_widgets.py similarity index 100% rename from openpype/tools/new_publisher/widgets/card_view_widgets.py rename to openpype/tools/publisher/widgets/card_view_widgets.py diff --git a/openpype/tools/new_publisher/widgets/create_dialog.py b/openpype/tools/publisher/widgets/create_dialog.py similarity index 100% rename from openpype/tools/new_publisher/widgets/create_dialog.py rename to openpype/tools/publisher/widgets/create_dialog.py diff --git a/openpype/tools/new_publisher/widgets/icons.py b/openpype/tools/publisher/widgets/icons.py similarity index 100% rename from openpype/tools/new_publisher/widgets/icons.py rename to openpype/tools/publisher/widgets/icons.py diff --git a/openpype/tools/new_publisher/widgets/images/add.png b/openpype/tools/publisher/widgets/images/add.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/add.png rename to openpype/tools/publisher/widgets/images/add.png diff --git a/openpype/tools/new_publisher/widgets/images/branch_closed.png b/openpype/tools/publisher/widgets/images/branch_closed.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/branch_closed.png rename to openpype/tools/publisher/widgets/images/branch_closed.png diff --git a/openpype/tools/new_publisher/widgets/images/branch_open.png b/openpype/tools/publisher/widgets/images/branch_open.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/branch_open.png rename to openpype/tools/publisher/widgets/images/branch_open.png diff --git a/openpype/tools/new_publisher/widgets/images/change_view.png b/openpype/tools/publisher/widgets/images/change_view.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/change_view.png rename to openpype/tools/publisher/widgets/images/change_view.png diff --git a/openpype/tools/new_publisher/widgets/images/delete.png b/openpype/tools/publisher/widgets/images/delete.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/delete.png rename to openpype/tools/publisher/widgets/images/delete.png diff --git a/openpype/tools/new_publisher/widgets/images/play.png b/openpype/tools/publisher/widgets/images/play.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/play.png rename to openpype/tools/publisher/widgets/images/play.png diff --git a/openpype/tools/new_publisher/widgets/images/refresh.png b/openpype/tools/publisher/widgets/images/refresh.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/refresh.png rename to openpype/tools/publisher/widgets/images/refresh.png diff --git a/openpype/tools/new_publisher/widgets/images/stop.png b/openpype/tools/publisher/widgets/images/stop.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/stop.png rename to openpype/tools/publisher/widgets/images/stop.png diff --git a/openpype/tools/new_publisher/widgets/images/thumbnail.png b/openpype/tools/publisher/widgets/images/thumbnail.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/thumbnail.png rename to openpype/tools/publisher/widgets/images/thumbnail.png diff --git a/openpype/tools/new_publisher/widgets/images/validate.png b/openpype/tools/publisher/widgets/images/validate.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/validate.png rename to openpype/tools/publisher/widgets/images/validate.png diff --git a/openpype/tools/new_publisher/widgets/images/warning.png b/openpype/tools/publisher/widgets/images/warning.png similarity index 100% rename from openpype/tools/new_publisher/widgets/images/warning.png rename to openpype/tools/publisher/widgets/images/warning.png diff --git a/openpype/tools/new_publisher/widgets/list_view_widgets.py b/openpype/tools/publisher/widgets/list_view_widgets.py similarity index 100% rename from openpype/tools/new_publisher/widgets/list_view_widgets.py rename to openpype/tools/publisher/widgets/list_view_widgets.py diff --git a/openpype/tools/new_publisher/widgets/models.py b/openpype/tools/publisher/widgets/models.py similarity index 100% rename from openpype/tools/new_publisher/widgets/models.py rename to openpype/tools/publisher/widgets/models.py diff --git a/openpype/tools/new_publisher/widgets/publish_widget.py b/openpype/tools/publisher/widgets/publish_widget.py similarity index 100% rename from openpype/tools/new_publisher/widgets/publish_widget.py rename to openpype/tools/publisher/widgets/publish_widget.py diff --git a/openpype/tools/new_publisher/widgets/validations_widget.py b/openpype/tools/publisher/widgets/validations_widget.py similarity index 100% rename from openpype/tools/new_publisher/widgets/validations_widget.py rename to openpype/tools/publisher/widgets/validations_widget.py diff --git a/openpype/tools/new_publisher/widgets/widgets.py b/openpype/tools/publisher/widgets/widgets.py similarity index 100% rename from openpype/tools/new_publisher/widgets/widgets.py rename to openpype/tools/publisher/widgets/widgets.py diff --git a/openpype/tools/new_publisher/window.py b/openpype/tools/publisher/window.py similarity index 100% rename from openpype/tools/new_publisher/window.py rename to openpype/tools/publisher/window.py From 169b3d578febd412868f1c01f9c8ba08dbca8fcf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 10:12:27 +0200 Subject: [PATCH 148/150] reorganized variables --- openpype/hosts/testhost/run_publish.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openpype/hosts/testhost/run_publish.py b/openpype/hosts/testhost/run_publish.py index 5aa2df75fa..44860a30e4 100644 --- a/openpype/hosts/testhost/run_publish.py +++ b/openpype/hosts/testhost/run_publish.py @@ -1,6 +1,6 @@ import os import sys -openpype_dir = "" + mongo_url = "" project_name = "" asset_name = "" @@ -9,9 +9,6 @@ ftrack_url = "" ftrack_username = "" ftrack_api_key = "" -host_name = "testhost" -current_file = os.path.abspath(__file__) - def multi_dirname(path, times=1): for _ in range(times): @@ -19,8 +16,12 @@ def multi_dirname(path, times=1): return path +host_name = "testhost" +current_file = os.path.abspath(__file__) +openpype_dir = multi_dirname(current_file, 4) + os.environ["OPENPYPE_MONGO"] = mongo_url -os.environ["OPENPYPE_ROOT"] = multi_dirname(current_file, 4) +os.environ["OPENPYPE_ROOT"] = openpype_dir os.environ["AVALON_MONGO"] = mongo_url os.environ["AVALON_PROJECT"] = project_name os.environ["AVALON_ASSET"] = asset_name From 0150397174cfe65dfcaefe826834af19e0235908 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 10:13:23 +0200 Subject: [PATCH 149/150] removed unused import --- openpype/hosts/testhost/plugins/publish/collect_context.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/testhost/plugins/publish/collect_context.py b/openpype/hosts/testhost/plugins/publish/collect_context.py index 5aff76a42d..0ab98fb84b 100644 --- a/openpype/hosts/testhost/plugins/publish/collect_context.py +++ b/openpype/hosts/testhost/plugins/publish/collect_context.py @@ -1,5 +1,4 @@ import pyblish.api -from avalon import io from openpype.pipeline import ( OpenPypePyblishPluginMixin, From 715f6f42d668e552e9c0debcd13be74b50704960 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 19 Oct 2021 11:29:25 +0200 Subject: [PATCH 150/150] added import of window to init --- openpype/tools/publisher/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/tools/publisher/__init__.py b/openpype/tools/publisher/__init__.py index 2d81de8fee..a7b597eece 100644 --- a/openpype/tools/publisher/__init__.py +++ b/openpype/tools/publisher/__init__.py @@ -1,5 +1,7 @@ from .app import show +from .window import PublisherWindow __all__ = ( "show", + "PublisherWindow" )