diff --git a/README.md b/README.md index f95064eb88..c43b8c0d4b 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,17 @@ or high availability options are recommended. Building Pype ------------- +To build Pype you currently need [Python 3.7](https://www.python.org/downloads/) as we are following +[vfx platform](https://vfxplatform.com). Because of some Linux distros comes with newer Python version +already, you need to install **3.7** version and make use of it. You can use perhaps [pyenv](https://github.com/pyenv/pyenv) for this on Linux. + ### Windows -You will need [Python 3.7 and newer](https://www.python.org/downloads/) and [git](https://git-scm.com/downloads). +You will need [Python 3.7](https://www.python.org/downloads/) and [git](https://git-scm.com/downloads). More tools might be needed for installing dependencies (for example for **OpenTimelineIO**) - mostly development tools like [CMake](https://cmake.org/) and [Visual Studio](https://visualstudio.microsoft.com/cs/downloads/) -Clone repository: +#### Clone repository: ```sh git clone --recurse-submodules git@github.com:pypeclub/pype.git ``` @@ -59,17 +63,43 @@ Pype is build using [CX_Freeze](https://cx-freeze.readthedocs.io/en/latest) to f ### macOS -You will need [Python 3.7 and newer](https://www.python.org/downloads/) and [git](https://git-scm.com/downloads). You'll need also other tools to build +You will need [Python 3.7](https://www.python.org/downloads/) and [git](https://git-scm.com/downloads). You'll need also other tools to build some Pype dependencies like [CMake](https://cmake.org/) and **XCode Command Line Tools** (or some other build system). -You can install **XCode Command Line Tools** from Terminal: +Easy way of installing everything necessary is to use [Homebrew](https://brew.sh): + +1) Install **Homebrew**: ```sh -xcode-select --install +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` -Before building Pype be sure to make **CMake** available in `PATH`: +2) Install **cmake**: ```sh -export PATH=$PATH:/Applications/CMake.app/Contents/bin +brew install cmake +``` + +3) Install [pyenv](https://github.com/pyenv/pyenv): +```sh +brew install pyenv +echo 'eval "$(pypenv init -)"' >> ~/.zshrc +pyenv init +exec "$SHELL" +PATH=$(pyenv root)/shims:$PATH +``` + +4) Pull in required Python version 3.7.x +```sh +# install Python build dependences +brew install openssl readline sqlite3 xz zlib + +# replace with up-to-date 3.7.x version +pyenv install 3.7.9 +``` + +5) Set local Python version +```sh +# switch to Pype source directory +pyenv local 3.7.9 ``` #### To build Pype: @@ -80,15 +110,35 @@ export PATH=$PATH:/Applications/CMake.app/Contents/bin ### Linux -You will need [Python 3.7 and newer](https://www.python.org/downloads/) and [git](https://git-scm.com/downloads). You'll need also other tools to build +You will need [Python 3.7](https://www.python.org/downloads/) and [git](https://git-scm.com/downloads). You'll also need [curl](https://curl.se) on systems that doesn't have one preinstalled. + +To build Python related stuff, you need Python header files installed (`python3-dev` on Ubuntu for example). + +You'll need also other tools to build some Pype dependencies like [CMake](https://cmake.org/). Python 3 should be part of all modern distributions. You can use your package manager to install **git** and **cmake**. -For Ubuntu: -```sh -sudo apt install git cmake -``` -For CentOS: +
+Details for Ubuntu +Install git, cmake and curl + +```sh +sudo apt install build-essential checkinstall +sudo apt install git cmake curl +``` +#### Note: +In case you run in error about `xcb` when running Pype, +you'll need also additional libraries for Qt5: + +```sh +sudo apt install qt5-default +``` +
+ +
+Details for Centos +Install git, cmake and curl + ```sh sudo yum install qit cmake ``` @@ -97,14 +147,44 @@ sudo yum install qit cmake In case you run in error about `xcb` when running Pype, you'll need also additional libraries for Qt5: -For Ubuntu: -```sh -sudo apt install qt5-default -``` -For CentOS: ```sh sudo yum install qt5-qtbase-devel ``` +
+ +
+Use pyenv to install Python version for Pype build + +You will need **bzip2**, **readline** and **sqlite3** libraries. + +**Ubuntu:** +```sh +sudo apt install libbz2-dev libreadline-dev libsqlite3-dev +``` + +1) install **pyenv** +```sh +curl https://pyenv.run | bash + +# you can add those to ~/.bashrc +export PATH="$HOME/.pyenv/bin:$PATH" +eval "$(pyenv init -)" +eval "$(pyenv virtualenv-init -)" + +# reload shell +exec $SHELL + +# install Python 3.7.9 +pyenv install -v 3.7.9 + +# change path to pype 3 +cd /path/to/pype-3 + +# set local python version +pyenv local 3.7.9 + +``` +
#### To build Pype: @@ -112,7 +192,6 @@ sudo yum install qt5-qtbase-devel 2) Run `.\tools\build.sh` to build Pype executables in `.\build\` - Running Pype ------------ diff --git a/poetry.lock b/poetry.lock index c670dcd6af..e879514789 100644 --- a/poetry.lock +++ b/poetry.lock @@ -15,7 +15,7 @@ resolved_reference = "9bf19573acb9328a3e5f5de96c619060177795cf" [[package]] name = "aiohttp" -version = "3.7.3" +version = "3.7.4" description = "Async http client/server framework (asyncio)" category = "main" optional = false @@ -80,17 +80,16 @@ python-dateutil = ">=2.7.0" [[package]] name = "astroid" -version = "2.4.2" +version = "2.5" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] -lazy-object-proxy = ">=1.4.0,<1.5.0" -six = ">=1.12,<2.0" +lazy-object-proxy = ">=1.4.0" typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} -wrapt = ">=1.11,<2.0" +wrapt = ">=1.11,<1.13" [[package]] name = "async-timeout" @@ -124,7 +123,7 @@ tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (> [[package]] name = "autopep8" -version = "1.5.4" +version = "1.5.5" description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" category = "dev" optional = false @@ -147,7 +146,7 @@ pytz = ">=2015.7" [[package]] name = "blessed" -version = "1.17.12" +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 @@ -176,7 +175,7 @@ python-versions = "*" [[package]] name = "cffi" -version = "1.14.4" +version = "1.14.5" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -246,22 +245,22 @@ toml = ["toml"] [[package]] name = "cryptography" -version = "3.3.1" +version = "3.4.6" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" +python-versions = ">=3.6" [package.dependencies] cffi = ">=1.12" -six = ">=1.4.1" [package.extras] docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pytest (>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] [[package]] name = "cx-freeze" @@ -332,7 +331,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "google-api-core" -version = "1.25.1" +version = "1.26.0" description = "Google API client core library" category = "main" optional = false @@ -341,6 +340,7 @@ python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" [package.dependencies] google-auth = ">=1.21.1,<2.0dev" googleapis-common-protos = ">=1.6.0,<2.0dev" +packaging = ">=14.3" protobuf = ">=3.12.0" pytz = "*" requests = ">=2.18.0,<3.0.0dev" @@ -369,7 +369,7 @@ uritemplate = ">=3.0.0,<4dev" [[package]] name = "google-auth" -version = "1.24.0" +version = "1.27.0" description = "Google Authentication Library" category = "main" optional = false @@ -383,6 +383,7 @@ six = ">=1.9.0" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"] +pyopenssl = ["pyopenssl (>=20.0.0)"] [[package]] name = "google-auth-httplib2" @@ -399,26 +400,29 @@ six = "*" [[package]] name = "googleapis-common-protos" -version = "1.52.0" +version = "1.53.0" description = "Common protobufs used in Google APIs" category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +python-versions = ">=3.6" [package.dependencies] -protobuf = ">=3.6.0" +protobuf = ">=3.12.0" [package.extras] grpc = ["grpcio (>=1.0.0)"] [[package]] name = "httplib2" -version = "0.18.1" +version = "0.19.0" description = "A comprehensive HTTP client library." category = "main" optional = false python-versions = "*" +[package.dependencies] +pyparsing = ">=2.4.2,<3" + [[package]] name = "idna" version = "2.10" @@ -437,7 +441,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "3.4.0" +version = "3.7.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -534,7 +538,7 @@ format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator [[package]] name = "keyring" -version = "22.0.1" +version = "22.2.0" description = "Store and access your passwords safely." category = "main" optional = false @@ -548,15 +552,15 @@ SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pytest-black (>=0.3.7)", "pytest-mypy"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pytest-black (>=0.3.7)", "pytest-mypy"] [[package]] name = "lazy-object-proxy" -version = "1.4.3" +version = "1.5.2" description = "A fast and thorough lazy object proxy." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "log4mongo" @@ -587,7 +591,7 @@ python-versions = "*" [[package]] name = "more-itertools" -version = "8.6.0" +version = "8.7.0" description = "More routines for operating on iterables, beyond itertools" category = "dev" optional = false @@ -602,32 +606,30 @@ optional = false python-versions = ">=3.6" [[package]] -name = "OpenTimelineIO" +name = "opentimelineio" version = "0.14.0.dev1" -description = "" +description = "Editorial interchange format and API" category = "main" optional = false python-versions = "*" -develop = false [package.dependencies] pyaaf2 = "1.4.0" [package.extras] -dev = ["flake8 (>=3.5)", "coverage (>=4.5)", "tox (>=3.0)", "urllib3 (>=1.24.3)"] -view = ["PySide2 (>=5.11,<6.0)", "Qt.py (>=1.1.0)"] +dev = ["check-manifest", "flake8 (>=3.5)", "coverage (>=4.5)", "urllib3 (>=1.24.3)"] +view = ["PySide2 (>=5.11,<6.0)"] [package.source] -type = "git" -url = "https://github.com/pypeclub/OpenTimelineIO.git" -reference = "develop" -resolved_reference = "26c960eb1b3c654aacafba4da80da2e7034e09c5" +type = "legacy" +url = "https://d.r1.wbsprt.com/pype.club/distribute" +reference = "pype" [[package]] name = "packaging" version = "20.9" description = "Core utilities for Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -681,7 +683,7 @@ dev = ["pre-commit", "tox"] [[package]] name = "protobuf" -version = "3.14.0" +version = "3.15.3" description = "Protocol Buffers" category = "main" optional = false @@ -771,7 +773,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.7.4" +version = "2.8.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false @@ -779,22 +781,25 @@ python-versions = ">=3.5" [[package]] name = "pylint" -version = "2.6.0" +version = "2.7.1" description = "python code static checker" category = "dev" optional = false -python-versions = ">=3.5.*" +python-versions = "~=3.6" [package.dependencies] -astroid = ">=2.4.0,<=2.5" +astroid = "2.5.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" toml = ">=0.7.1" +[package.extras] +docs = ["sphinx (>=3.2,<4.0)", "python-docs-theme"] + [[package]] name = "pymongo" -version = "3.11.2" +version = "3.11.3" description = "Python driver for MongoDB " category = "main" optional = false @@ -812,7 +817,7 @@ zstd = ["zstandard"] [[package]] name = "pynput" -version = "1.7.2" +version = "1.7.3" description = "Monitor and control user input devices" category = "main" optional = false @@ -820,7 +825,7 @@ python-versions = "*" [package.dependencies] evdev = {version = ">=1.3", markers = "sys_platform in \"linux\""} -pyobjc-framework-Quartz = {version = ">=3.0", markers = "sys_platform == \"darwin\""} +pyobjc-framework-Quartz = {version = ">=7.0", markers = "sys_platform == \"darwin\""} python-xlib = {version = ">=0.17", markers = "sys_platform in \"linux\""} six = "*" @@ -865,15 +870,24 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "pyqt5" -version = "5.15.2" +version = "5.15.3" description = "Python bindings for the Qt cross platform application toolkit" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] +PyQt5-Qt = ">=5.15" PyQt5-sip = ">=12.8,<13" +[[package]] +name = "pyqt5-qt" +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.8.1" @@ -964,6 +978,14 @@ python-versions = "*" [package.dependencies] six = ">=1.10.0" +[[package]] +name = "python3-xlib" +version = "0.15" +description = "Python3 X Library" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "pytz" version = "2021.1" @@ -1029,7 +1051,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] name = "rsa" -version = "4.7" +version = "4.7.2" description = "Pure-Python RSA implementation" category = "main" optional = false @@ -1040,7 +1062,7 @@ pyasn1 = ">=0.1.3" [[package]] name = "secretstorage" -version = "3.3.0" +version = "3.3.1" description = "Python bindings to FreeDesktop.org Secret Service API" category = "main" optional = false @@ -1076,7 +1098,7 @@ python-versions = "*" [[package]] name = "sphinx" -version = "3.4.3" +version = "3.5.1" description = "Python documentation generator" category = "dev" optional = false @@ -1102,7 +1124,7 @@ sphinxcontrib-serializinghtml = "*" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.790)", "docutils-stubs"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.800)", "docutils-stubs"] test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] @@ -1235,7 +1257,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tqdm" -version = "4.56.0" +version = "4.58.0" description = "Fast, Extensible Progress Meter" category = "dev" optional = false @@ -1354,48 +1376,48 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "3.7.*" -content-hash = "923189591ed78935c05c922eda38f0b993e3d310aa13e53a438b2c27fa4fc9f7" +content-hash = "22fb546eefa7ced2769c1dcb3220fd2ef4b22f0dc8436e023774e50e2ee6bde1" [metadata.files] acre = [] aiohttp = [ - {file = "aiohttp-3.7.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:328b552513d4f95b0a2eea4c8573e112866107227661834652a8984766aa7656"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c733ef3bdcfe52a1a75564389bad4064352274036e7e234730526d155f04d914"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:2858b2504c8697beb9357be01dc47ef86438cc1cb36ecb6991796d19475faa3e"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d2cfac21e31e841d60dc28c0ec7d4ec47a35c608cb8906435d47ef83ffb22150"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:3228b7a51e3ed533f5472f54f70fd0b0a64c48dc1649a0f0e809bec312934d7a"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:dcc119db14757b0c7bce64042158307b9b1c76471e655751a61b57f5a0e4d78e"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:7d9b42127a6c0bdcc25c3dcf252bb3ddc70454fac593b1b6933ae091396deb13"}, - {file = "aiohttp-3.7.3-cp36-cp36m-win32.whl", hash = "sha256:df48a623c58180874d7407b4d9ec06a19b84ed47f60a3884345b1a5099c1818b"}, - {file = "aiohttp-3.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:0b795072bb1bf87b8620120a6373a3c61bfcb8da7e5c2377f4bb23ff4f0b62c9"}, - {file = "aiohttp-3.7.3-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:0d438c8ca703b1b714e82ed5b7a4412c82577040dadff479c08405e2a715564f"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8389d6044ee4e2037dca83e3f6994738550f6ee8cfb746762283fad9b932868f"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3ea8c252d8df5e9166bcf3d9edced2af132f4ead8ac422eac723c5781063709a"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:78e2f18a82b88cbc37d22365cf8d2b879a492faedb3f2975adb4ed8dfe994d3a"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:df3a7b258cc230a65245167a202dd07320a5af05f3d41da1488ba0fa05bc9347"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:f326b3c1bbfda5b9308252ee0dcb30b612ee92b0e105d4abec70335fab5b1245"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5e479df4b2d0f8f02133b7e4430098699450e1b2a826438af6bec9a400530957"}, - {file = "aiohttp-3.7.3-cp37-cp37m-win32.whl", hash = "sha256:6d42debaf55450643146fabe4b6817bb2a55b23698b0434107e892a43117285e"}, - {file = "aiohttp-3.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9c58b0b84055d8bc27b7df5a9d141df4ee6ff59821f922dd73155861282f6a3"}, - {file = "aiohttp-3.7.3-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:f411cb22115cb15452d099fec0ee636b06cf81bfb40ed9c02d30c8dc2bc2e3d1"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c1e0920909d916d3375c7a1fdb0b1c78e46170e8bb42792312b6eb6676b2f87f"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:59d11674964b74a81b149d4ceaff2b674b3b0e4d0f10f0be1533e49c4a28408b"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:41608c0acbe0899c852281978492f9ce2c6fbfaf60aff0cefc54a7c4516b822c"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:16a3cb5df5c56f696234ea9e65e227d1ebe9c18aa774d36ff42f532139066a5f"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:6ccc43d68b81c424e46192a778f97da94ee0630337c9bbe5b2ecc9b0c1c59001"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:d03abec50df423b026a5aa09656bd9d37f1e6a49271f123f31f9b8aed5dc3ea3"}, - {file = "aiohttp-3.7.3-cp38-cp38-win32.whl", hash = "sha256:39f4b0a6ae22a1c567cb0630c30dd082481f95c13ca528dc501a7766b9c718c0"}, - {file = "aiohttp-3.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:c68fdf21c6f3573ae19c7ee65f9ff185649a060c9a06535e9c3a0ee0bbac9235"}, - {file = "aiohttp-3.7.3-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:710376bf67d8ff4500a31d0c207b8941ff4fba5de6890a701d71680474fe2a60"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2406dc1dda01c7f6060ab586e4601f18affb7a6b965c50a8c90ff07569cf782a"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:2a7b7640167ab536c3cb90cfc3977c7094f1c5890d7eeede8b273c175c3910fd"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:684850fb1e3e55c9220aad007f8386d8e3e477c4ec9211ae54d968ecdca8c6f9"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:1edfd82a98c5161497bbb111b2b70c0813102ad7e0aa81cbeb34e64c93863005"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:77149002d9386fae303a4a162e6bce75cc2161347ad2ba06c2f0182561875d45"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:756ae7efddd68d4ea7d89c636b703e14a0c686688d42f588b90778a3c2fc0564"}, - {file = "aiohttp-3.7.3-cp39-cp39-win32.whl", hash = "sha256:3b0036c978cbcc4a4512278e98e3e6d9e6b834dc973206162eddf98b586ef1c6"}, - {file = "aiohttp-3.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:e1b95972a0ae3f248a899cdbac92ba2e01d731225f566569311043ce2226f5e7"}, - {file = "aiohttp-3.7.3.tar.gz", hash = "sha256:9c1a81af067e72261c9cbe33ea792893e83bc6aa987bfbd6fdc1e5e7b22777c4"}, + {file = "aiohttp-3.7.4-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6c8200abc9dc5f27203986100579fc19ccad7a832c07d2bc151ce4ff17190076"}, + {file = "aiohttp-3.7.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:dd7936f2a6daa861143e376b3a1fb56e9b802f4980923594edd9ca5670974895"}, + {file = "aiohttp-3.7.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:bc3d14bf71a3fb94e5acf5bbf67331ab335467129af6416a437bd6024e4f743d"}, + {file = "aiohttp-3.7.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:8ec1a38074f68d66ccb467ed9a673a726bb397142c273f90d4ba954666e87d54"}, + {file = "aiohttp-3.7.4-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:b84ad94868e1e6a5e30d30ec419956042815dfaea1b1df1cef623e4564c374d9"}, + {file = "aiohttp-3.7.4-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:d5d102e945ecca93bcd9801a7bb2fa703e37ad188a2f81b1e65e4abe4b51b00c"}, + {file = "aiohttp-3.7.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:c2a80fd9a8d7e41b4e38ea9fe149deed0d6aaede255c497e66b8213274d6d61b"}, + {file = "aiohttp-3.7.4-cp36-cp36m-win32.whl", hash = "sha256:481d4b96969fbfdcc3ff35eea5305d8565a8300410d3d269ccac69e7256b1329"}, + {file = "aiohttp-3.7.4-cp36-cp36m-win_amd64.whl", hash = "sha256:16d0683ef8a6d803207f02b899c928223eb219111bd52420ef3d7a8aa76227b6"}, + {file = "aiohttp-3.7.4-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:eab51036cac2da8a50d7ff0ea30be47750547c9aa1aa2cf1a1b710a1827e7dbe"}, + {file = "aiohttp-3.7.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:feb24ff1226beeb056e247cf2e24bba5232519efb5645121c4aea5b6ad74c1f2"}, + {file = "aiohttp-3.7.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:119feb2bd551e58d83d1b38bfa4cb921af8ddedec9fad7183132db334c3133e0"}, + {file = "aiohttp-3.7.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:6ca56bdfaf825f4439e9e3673775e1032d8b6ea63b8953d3812c71bd6a8b81de"}, + {file = "aiohttp-3.7.4-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:5563ad7fde451b1986d42b9bb9140e2599ecf4f8e42241f6da0d3d624b776f40"}, + {file = "aiohttp-3.7.4-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:62bc216eafac3204877241569209d9ba6226185aa6d561c19159f2e1cbb6abfb"}, + {file = "aiohttp-3.7.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:f4496d8d04da2e98cc9133e238ccebf6a13ef39a93da2e87146c8c8ac9768242"}, + {file = "aiohttp-3.7.4-cp37-cp37m-win32.whl", hash = "sha256:2ffea7904e70350da429568113ae422c88d2234ae776519549513c8f217f58a9"}, + {file = "aiohttp-3.7.4-cp37-cp37m-win_amd64.whl", hash = "sha256:5e91e927003d1ed9283dee9abcb989334fc8e72cf89ebe94dc3e07e3ff0b11e9"}, + {file = "aiohttp-3.7.4-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:4c1bdbfdd231a20eee3e56bd0ac1cd88c4ff41b64ab679ed65b75c9c74b6c5c2"}, + {file = "aiohttp-3.7.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:71680321a8a7176a58dfbc230789790639db78dad61a6e120b39f314f43f1907"}, + {file = "aiohttp-3.7.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7dbd087ff2f4046b9b37ba28ed73f15fd0bc9f4fdc8ef6781913da7f808d9536"}, + {file = "aiohttp-3.7.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:dee68ec462ff10c1d836c0ea2642116aba6151c6880b688e56b4c0246770f297"}, + {file = "aiohttp-3.7.4-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:99c5a5bf7135607959441b7d720d96c8e5c46a1f96e9d6d4c9498be8d5f24212"}, + {file = "aiohttp-3.7.4-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:5dde6d24bacac480be03f4f864e9a67faac5032e28841b00533cd168ab39cad9"}, + {file = "aiohttp-3.7.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:418597633b5cd9639e514b1d748f358832c08cd5d9ef0870026535bd5eaefdd0"}, + {file = "aiohttp-3.7.4-cp38-cp38-win32.whl", hash = "sha256:e76e78863a4eaec3aee5722d85d04dcbd9844bc6cd3bfa6aa880ff46ad16bfcb"}, + {file = "aiohttp-3.7.4-cp38-cp38-win_amd64.whl", hash = "sha256:950b7ef08b2afdab2488ee2edaff92a03ca500a48f1e1aaa5900e73d6cf992bc"}, + {file = "aiohttp-3.7.4-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:2eb3efe243e0f4ecbb654b08444ae6ffab37ac0ef8f69d3a2ffb958905379daf"}, + {file = "aiohttp-3.7.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:822bd4fd21abaa7b28d65fc9871ecabaddc42767884a626317ef5b75c20e8a2d"}, + {file = "aiohttp-3.7.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:58c62152c4c8731a3152e7e650b29ace18304d086cb5552d317a54ff2749d32a"}, + {file = "aiohttp-3.7.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:7c7820099e8b3171e54e7eedc33e9450afe7cd08172632d32128bd527f8cb77d"}, + {file = "aiohttp-3.7.4-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:5b50e0b9460100fe05d7472264d1975f21ac007b35dcd6fd50279b72925a27f4"}, + {file = "aiohttp-3.7.4-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:c44d3c82a933c6cbc21039326767e778eface44fca55c65719921c4b9661a3f7"}, + {file = "aiohttp-3.7.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:cc31e906be1cc121ee201adbdf844522ea3349600dd0a40366611ca18cd40e81"}, + {file = "aiohttp-3.7.4-cp39-cp39-win32.whl", hash = "sha256:fbd3b5e18d34683decc00d9a360179ac1e7a320a5fee10ab8053ffd6deab76e0"}, + {file = "aiohttp-3.7.4-cp39-cp39-win_amd64.whl", hash = "sha256:40bd1b101b71a18a528ffce812cc14ff77d4a2a1272dfb8b11b200967489ef3e"}, + {file = "aiohttp-3.7.4.tar.gz", hash = "sha256:5d84ecc73141d0a0d61ece0742bb7ff5751b0657dab8405f899d3ceb104cc7de"}, ] aiohttp-json-rpc = [ {file = "aiohttp-json-rpc-0.13.3.tar.gz", hash = "sha256:6237a104478c22c6ef96c7227a01d6832597b414e4b79a52d85593356a169e99"}, @@ -1418,8 +1440,8 @@ arrow = [ {file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"}, ] astroid = [ - {file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"}, - {file = "astroid-2.4.2.tar.gz", hash = "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703"}, + {file = "astroid-2.5-py3-none-any.whl", hash = "sha256:87ae7f2398b8a0ae5638ddecf9987f081b756e0e9fc071aeebdca525671fc4dc"}, + {file = "astroid-2.5.tar.gz", hash = "sha256:b31c92f545517dcc452f284bc9c044050862fbe6d93d2b3de4a215a6b384bf0d"}, ] async-timeout = [ {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, @@ -1434,15 +1456,16 @@ attrs = [ {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, ] autopep8 = [ - {file = "autopep8-1.5.4.tar.gz", hash = "sha256:d21d3901cb0da6ebd1e83fc9b0dfbde8b46afc2ede4fe32fbda0c7c6118ca094"}, + {file = "autopep8-1.5.5-py2.py3-none-any.whl", hash = "sha256:9e136c472c475f4ee4978b51a88a494bfcd4e3ed17950a44a988d9e434837bea"}, + {file = "autopep8-1.5.5.tar.gz", hash = "sha256:cae4bc0fb616408191af41d062d7ec7ef8679c7f27b068875ca3a9e2878d5443"}, ] babel = [ {file = "Babel-2.9.0-py2.py3-none-any.whl", hash = "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5"}, {file = "Babel-2.9.0.tar.gz", hash = "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"}, ] blessed = [ - {file = "blessed-1.17.12-py2.py3-none-any.whl", hash = "sha256:0a74a8d3f0366db600d061273df77d44f0db07daade7bb7a4d49c8bc22ed9f74"}, - {file = "blessed-1.17.12.tar.gz", hash = "sha256:580429e7e0c6f6a42ea81b0ae5a4993b6205c6ccbb635d034b4277af8175753e"}, + {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.1-py3-none-any.whl", hash = "sha256:1d9d5f567be80f7c07d765e21b814326d78c61eb0c3a637dffc0e5d1796cb2e2"}, @@ -1453,43 +1476,43 @@ certifi = [ {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, ] cffi = [ - {file = "cffi-1.14.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775"}, - {file = "cffi-1.14.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06"}, - {file = "cffi-1.14.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26"}, - {file = "cffi-1.14.4-cp27-cp27m-win32.whl", hash = "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c"}, - {file = "cffi-1.14.4-cp27-cp27m-win_amd64.whl", hash = "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b"}, - {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d"}, - {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca"}, - {file = "cffi-1.14.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698"}, - {file = "cffi-1.14.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b"}, - {file = "cffi-1.14.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293"}, - {file = "cffi-1.14.4-cp35-cp35m-win32.whl", hash = "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2"}, - {file = "cffi-1.14.4-cp35-cp35m-win_amd64.whl", hash = "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7"}, - {file = "cffi-1.14.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec"}, - {file = "cffi-1.14.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b"}, - {file = "cffi-1.14.4-cp36-cp36m-win32.whl", hash = "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668"}, - {file = "cffi-1.14.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009"}, - {file = "cffi-1.14.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03"}, - {file = "cffi-1.14.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01"}, - {file = "cffi-1.14.4-cp37-cp37m-win32.whl", hash = "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e"}, - {file = "cffi-1.14.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35"}, - {file = "cffi-1.14.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53"}, - {file = "cffi-1.14.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e"}, - {file = "cffi-1.14.4-cp38-cp38-win32.whl", hash = "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d"}, - {file = "cffi-1.14.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375"}, - {file = "cffi-1.14.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a"}, - {file = "cffi-1.14.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e"}, - {file = "cffi-1.14.4-cp39-cp39-win32.whl", hash = "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3"}, - {file = "cffi-1.14.4-cp39-cp39-win_amd64.whl", hash = "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b"}, - {file = "cffi-1.14.4.tar.gz", hash = "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c"}, + {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-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, @@ -1563,20 +1586,18 @@ coverage = [ {file = "coverage-5.4.tar.gz", hash = "sha256:6d2e262e5e8da6fa56e774fb8e2643417351427604c2b177f8e8c5f75fc928ca"}, ] cryptography = [ - {file = "cryptography-3.3.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:c366df0401d1ec4e548bebe8f91d55ebcc0ec3137900d214dd7aac8427ef3030"}, - {file = "cryptography-3.3.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f6b0492d111b43de5f70052e24c1f0951cb9e6022188ebcb1cc3a3d301469b0"}, - {file = "cryptography-3.3.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a69bd3c68b98298f490e84519b954335154917eaab52cf582fa2c5c7efc6e812"}, - {file = "cryptography-3.3.1-cp27-cp27m-win32.whl", hash = "sha256:84ef7a0c10c24a7773163f917f1cb6b4444597efd505a8aed0a22e8c4780f27e"}, - {file = "cryptography-3.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:594a1db4511bc4d960571536abe21b4e5c3003e8750ab8365fafce71c5d86901"}, - {file = "cryptography-3.3.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0003a52a123602e1acee177dc90dd201f9bb1e73f24a070db7d36c588e8f5c7d"}, - {file = "cryptography-3.3.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:83d9d2dfec70364a74f4e7c70ad04d3ca2e6a08b703606993407bf46b97868c5"}, - {file = "cryptography-3.3.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:dc42f645f8f3a489c3dd416730a514e7a91a59510ddaadc09d04224c098d3302"}, - {file = "cryptography-3.3.1-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:788a3c9942df5e4371c199d10383f44a105d67d401fb4304178020142f020244"}, - {file = "cryptography-3.3.1-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:69e836c9e5ff4373ce6d3ab311c1a2eed274793083858d3cd4c7d12ce20d5f9c"}, - {file = "cryptography-3.3.1-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:9e21301f7a1e7c03dbea73e8602905a4ebba641547a462b26dd03451e5769e7c"}, - {file = "cryptography-3.3.1-cp36-abi3-win32.whl", hash = "sha256:b4890d5fb9b7a23e3bf8abf5a8a7da8e228f1e97dc96b30b95685df840b6914a"}, - {file = "cryptography-3.3.1-cp36-abi3-win_amd64.whl", hash = "sha256:0e85aaae861d0485eb5a79d33226dd6248d2a9f133b81532c8f5aae37de10ff7"}, - {file = "cryptography-3.3.1.tar.gz", hash = "sha256:7e177e4bea2de937a584b13645cab32f25e3d96fc0bc4a4cf99c27dc77682be6"}, + {file = "cryptography-3.4.6-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799"}, + {file = "cryptography-3.4.6-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7"}, + {file = "cryptography-3.4.6-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3"}, + {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b"}, + {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"}, + {file = "cryptography-3.4.6-cp36-abi3-win32.whl", hash = "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2"}, + {file = "cryptography-3.4.6-cp36-abi3-win_amd64.whl", hash = "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0"}, + {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b"}, + {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df"}, + {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336"}, + {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724"}, + {file = "cryptography-3.4.6.tar.gz", hash = "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87"}, ] cx-freeze = [ {file = "cx_Freeze-6.5.3-cp36-cp36m-win32.whl", hash = "sha256:0a1babae574546b622303da53e1a9829aa3a7e53e62b41eb260250220f83164b"}, @@ -1608,28 +1629,28 @@ future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, ] google-api-core = [ - {file = "google-api-core-1.25.1.tar.gz", hash = "sha256:0e152ec37b8481d1be1258d95844a5a7031cd3d83d7c7046d9e9b2d807042440"}, - {file = "google_api_core-1.25.1-py2.py3-none-any.whl", hash = "sha256:292dd636ed381098d24b7093ccb826b2278a12d886a3fc982084069aa24a8fbb"}, + {file = "google-api-core-1.26.0.tar.gz", hash = "sha256:4230ec764d48ca934fe69b85cc217e31e844e176f68df93e252acd55350e730b"}, + {file = "google_api_core-1.26.0-py2.py3-none-any.whl", hash = "sha256:002e44c533299aecd9dd265d200f9eacd9957cddd2c72e2cd1cb5cea127e972d"}, ] 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.24.0.tar.gz", hash = "sha256:0b0e026b412a0ad096e753907559e4bdb180d9ba9f68dd9036164db4fdc4ad2e"}, - {file = "google_auth-1.24.0-py2.py3-none-any.whl", hash = "sha256:ce752cc51c31f479dbf9928435ef4b07514b20261b021c7383bee4bda646acb8"}, + {file = "google-auth-1.27.0.tar.gz", hash = "sha256:da5218cbf33b8461d7661d6b4ad91c12c0107e2767904d5e3ae6408031d5463e"}, + {file = "google_auth-1.27.0-py2.py3-none-any.whl", hash = "sha256:d3640ea61ee025d5af00e3ffd82ba0a06dd99724adaf50bdd52f49daf29f3f65"}, ] google-auth-httplib2 = [ {file = "google-auth-httplib2-0.0.4.tar.gz", hash = "sha256:8d092cc60fb16517b12057ec0bba9185a96e3b7169d86ae12eae98e645b7bc39"}, {file = "google_auth_httplib2-0.0.4-py2.py3-none-any.whl", hash = "sha256:aeaff501738b289717fac1980db9711d77908a6c227f60e4aa1923410b43e2ee"}, ] googleapis-common-protos = [ - {file = "googleapis-common-protos-1.52.0.tar.gz", hash = "sha256:560716c807117394da12cecb0a54da5a451b5cf9866f1d37e9a5e2329a665351"}, - {file = "googleapis_common_protos-1.52.0-py2.py3-none-any.whl", hash = "sha256:c8961760f5aad9a711d37b675be103e0cc4e9a39327e0d6d857872f698403e24"}, + {file = "googleapis-common-protos-1.53.0.tar.gz", hash = "sha256:a88ee8903aa0a81f6c3cec2d5cf62d3c8aa67c06439b0496b49048fb1854ebf4"}, + {file = "googleapis_common_protos-1.53.0-py2.py3-none-any.whl", hash = "sha256:f6d561ab8fb16b30020b940e2dd01cd80082f4762fa9f3ee670f4419b4b8dbd0"}, ] httplib2 = [ - {file = "httplib2-0.18.1-py3-none-any.whl", hash = "sha256:ca2914b015b6247791c4866782fa6042f495b94401a0f0bd3e1d6e0ba2236782"}, - {file = "httplib2-0.18.1.tar.gz", hash = "sha256:8af66c1c52c7ffe1aa5dc4bcd7c769885254b0756e6e69f953c7f0ab49a70ba3"}, + {file = "httplib2-0.19.0-py3-none-any.whl", hash = "sha256:749c32603f9bf16c1277f59531d502e8f1c2ca19901ae653b49c4ed698f0820e"}, + {file = "httplib2-0.19.0.tar.gz", hash = "sha256:e0d428dad43c72dbce7d163b7753ffc7a39c097e6788ef10f4198db69b92f08e"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, @@ -1640,8 +1661,8 @@ imagesize = [ {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"}, - {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"}, + {file = "importlib_metadata-3.7.0-py3-none-any.whl", hash = "sha256:c6af5dbf1126cd959c4a8d8efd61d4d3c83bddb0459a17e554284a077574b614"}, + {file = "importlib_metadata-3.7.0.tar.gz", hash = "sha256:24499ffde1b80be08284100393955842be4a59c7c16bbf2738aad0e464a8e0aa"}, ] isort = [ {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"}, @@ -1668,31 +1689,34 @@ jsonschema = [ {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, ] keyring = [ - {file = "keyring-22.0.1-py3-none-any.whl", hash = "sha256:9f44660a5d4931bdc14c08a1d01ef30b18a7a8147380710d8c9f9531e1f6c3c0"}, - {file = "keyring-22.0.1.tar.gz", hash = "sha256:9acb3e1452edbb7544822b12fd25459078769e560fa51f418b6d00afaa6178df"}, + {file = "keyring-22.2.0-py3-none-any.whl", hash = "sha256:8ae8e53d744e3e395e7402fd04c7474d46c8ad2d65e095bcde8a622dc643f7cd"}, + {file = "keyring-22.2.0.tar.gz", hash = "sha256:c73c66c4ca89bee6a233b1638e1d2f5bcba4da35f8713ad4f98decc46e64cccd"}, ] lazy-object-proxy = [ - {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win32.whl", hash = "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a"}, - {file = "lazy_object_proxy-1.4.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win32.whl", hash = "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e"}, - {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win_amd64.whl", hash = "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db"}, - {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531"}, - {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142"}, - {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-win32.whl", hash = "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd"}, - {file = "lazy_object_proxy-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239"}, + {file = "lazy-object-proxy-1.5.2.tar.gz", hash = "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4"}, + {file = "lazy_object_proxy-1.5.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315"}, + {file = "lazy_object_proxy-1.5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871"}, + {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9"}, + {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128"}, + {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win32.whl", hash = "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847"}, + {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108"}, + {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068"}, + {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7"}, + {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win32.whl", hash = "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb"}, + {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a"}, + {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39"}, + {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0"}, + {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win32.whl", hash = "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef"}, + {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302"}, + {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163"}, + {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f"}, + {file = "lazy_object_proxy-1.5.2-cp38-cp38-win32.whl", hash = "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694"}, + {file = "lazy_object_proxy-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa"}, + {file = "lazy_object_proxy-1.5.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c"}, + {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d"}, + {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458"}, + {file = "lazy_object_proxy-1.5.2-cp39-cp39-win32.whl", hash = "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166"}, + {file = "lazy_object_proxy-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84"}, ] log4mongo = [ {file = "log4mongo-1.7.0.tar.gz", hash = "sha256:dc374617206162a0b14167fbb5feac01dbef587539a235dadba6200362984a68"}, @@ -1756,8 +1780,8 @@ mccabe = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] more-itertools = [ - {file = "more-itertools-8.6.0.tar.gz", hash = "sha256:b3a9005928e5bed54076e6e549c792b306fddfe72b2d1d22dd63d42d5d3899cf"}, - {file = "more_itertools-8.6.0-py3-none-any.whl", hash = "sha256:8e1a2a43b2f2727425f2b5839587ae37093f19153dc26c0927d1048ff6557330"}, + {file = "more-itertools-8.7.0.tar.gz", hash = "sha256:c5d6da9ca3ff65220c3bfd2a8db06d698f05d4d2b9be57e1deb2be5a45019713"}, + {file = "more_itertools-8.7.0-py3-none-any.whl", hash = "sha256:5652a9ac72209ed7df8d9c15daf4e1aa0e3d2ccd3c87f8265a0673cd9cbc9ced"}, ] multidict = [ {file = "multidict-5.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f"}, @@ -1798,7 +1822,7 @@ multidict = [ {file = "multidict-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359"}, {file = "multidict-5.1.0.tar.gz", hash = "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5"}, ] -OpenTimelineIO = [] +opentimelineio = [] packaging = [ {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, @@ -1850,24 +1874,26 @@ pluggy = [ {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] protobuf = [ - {file = "protobuf-3.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:629b03fd3caae7f815b0c66b41273f6b1900a579e2ccb41ef4493a4f5fb84f3a"}, - {file = "protobuf-3.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5b7a637212cc9b2bcf85dd828b1178d19efdf74dbfe1ddf8cd1b8e01fdaaa7f5"}, - {file = "protobuf-3.14.0-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:43b554b9e73a07ba84ed6cf25db0ff88b1e06be610b37656e292e3cbb5437472"}, - {file = "protobuf-3.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5e9806a43232a1fa0c9cf5da8dc06f6910d53e4390be1fa06f06454d888a9142"}, - {file = "protobuf-3.14.0-cp35-cp35m-win32.whl", hash = "sha256:1c51fda1bbc9634246e7be6016d860be01747354ed7015ebe38acf4452f470d2"}, - {file = "protobuf-3.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:4b74301b30513b1a7494d3055d95c714b560fbb630d8fb9956b6f27992c9f980"}, - {file = "protobuf-3.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:86a75477addde4918e9a1904e5c6af8d7b691f2a3f65587d73b16100fbe4c3b2"}, - {file = "protobuf-3.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecc33531a213eee22ad60e0e2aaea6c8ba0021f0cce35dbf0ab03dee6e2a23a1"}, - {file = "protobuf-3.14.0-cp36-cp36m-win32.whl", hash = "sha256:72230ed56f026dd664c21d73c5db73ebba50d924d7ba6b7c0d81a121e390406e"}, - {file = "protobuf-3.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:0fc96785262042e4863b3f3b5c429d4636f10d90061e1840fce1baaf59b1a836"}, - {file = "protobuf-3.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4e75105c9dfe13719b7293f75bd53033108f4ba03d44e71db0ec2a0e8401eafd"}, - {file = "protobuf-3.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2a7e2fe101a7ace75e9327b9c946d247749e564a267b0515cf41dfe450b69bac"}, - {file = "protobuf-3.14.0-cp37-cp37m-win32.whl", hash = "sha256:b0d5d35faeb07e22a1ddf8dce620860c8fe145426c02d1a0ae2688c6e8ede36d"}, - {file = "protobuf-3.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8971c421dbd7aad930c9bd2694122f332350b6ccb5202a8b7b06f3f1a5c41ed5"}, - {file = "protobuf-3.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9616f0b65a30851e62f1713336c931fcd32c057202b7ff2cfbfca0fc7d5e3043"}, - {file = "protobuf-3.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:22bcd2e284b3b1d969c12e84dc9b9a71701ec82d8ce975fdda19712e1cfd4e00"}, - {file = "protobuf-3.14.0-py2.py3-none-any.whl", hash = "sha256:0e247612fadda953047f53301a7b0407cb0c3cb4ae25a6fde661597a04039b3c"}, - {file = "protobuf-3.14.0.tar.gz", hash = "sha256:1d63eb389347293d8915fb47bee0951c7b5dab522a4a60118b9a18f33e21f8ce"}, + {file = "protobuf-3.15.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:822341974a28d895f0b39df13b3e2f27577498c1d85b5e876ff1d53fbdf2ef97"}, + {file = "protobuf-3.15.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:31460706eb7c3bcc3c153877e580b78efa624b9626bd084fb882f20681ffa81a"}, + {file = "protobuf-3.15.3-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:405fbe27eeccd90b07e7cc20f2bcce477a86027435016aef71f15473dede92b5"}, + {file = "protobuf-3.15.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a98195be29b2622961896893a6e92a4e0812e4e367078ac20f0c7982e51ff7ea"}, + {file = "protobuf-3.15.3-cp35-cp35m-win32.whl", hash = "sha256:7141c37a5af565908c3da10575c517c59a8e67591c507cf36f2655590200ddfc"}, + {file = "protobuf-3.15.3-cp35-cp35m-win_amd64.whl", hash = "sha256:ffc556af23c7e1278b43719999dd215619f73f8d42f40275c55a1de09938214f"}, + {file = "protobuf-3.15.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9aa4c216e48236c6af4e71f64afc0c13c12401d3067a323b9fe543bb676bac3"}, + {file = "protobuf-3.15.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0c678e11b7b6d6e5baa9710f44de01d48bc81b7db617ad5283a76f1f4c73df99"}, + {file = "protobuf-3.15.3-cp36-cp36m-win32.whl", hash = "sha256:1fe832e1a5c51c71c2d6e949e597f3c47ef39c817264086293e4037941ab9bd7"}, + {file = "protobuf-3.15.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8a8157ff82760105cf435dbb8f4e7042a39c6d92f673fba8c2c815432b3f1063"}, + {file = "protobuf-3.15.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:970b9f648fc12d28ce6f1f10575bbf063e828e1fd8d95339602cad2312a4fefa"}, + {file = "protobuf-3.15.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:492beef9386706f84f683489fe18d1a7d8be5f4ab050782b3a484de1d1b01a69"}, + {file = "protobuf-3.15.3-cp37-cp37m-win32.whl", hash = "sha256:af760e4fe6f30e1af3d5dac6767444ff61ef621ac857b3405b8f3cd29f16ac55"}, + {file = "protobuf-3.15.3-cp37-cp37m-win_amd64.whl", hash = "sha256:21911af1fc692e7ca6a73c0fab3912a5d792ed7603350dbabd34a9722cbfe4d5"}, + {file = "protobuf-3.15.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a3e18453d91040dad1985d1ea8a237fb7522a84fcefc17b452f756833b066d71"}, + {file = "protobuf-3.15.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d7761bd18fc3d197e50459c37abb95b64cd614e7b9014239a1e7c952433e380b"}, + {file = "protobuf-3.15.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f52c66f361de32096ba88c73ad0ff53585dafc569d8bf11968412175ddf297c"}, + {file = "protobuf-3.15.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3bbaed8e63cd62533a80adfa51f91b34bf7da29ac0335412dbebd21dac2d68b9"}, + {file = "protobuf-3.15.3-py2.py3-none-any.whl", hash = "sha256:ad8e808b572e6ee38131e7b58d94aa5c438e3a3469d055e8989ea73a8e2308c0"}, + {file = "protobuf-3.15.3.tar.gz", hash = "sha256:f3348af83391cdb842030e774d9bb01565ed4c62c93554cd1c69723411ec5e9d"}, ] py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, @@ -1928,83 +1954,83 @@ pyflakes = [ {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] pygments = [ - {file = "Pygments-2.7.4-py3-none-any.whl", hash = "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435"}, - {file = "Pygments-2.7.4.tar.gz", hash = "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337"}, + {file = "Pygments-2.8.0-py3-none-any.whl", hash = "sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88"}, + {file = "Pygments-2.8.0.tar.gz", hash = "sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0"}, ] pylint = [ - {file = "pylint-2.6.0-py3-none-any.whl", hash = "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f"}, - {file = "pylint-2.6.0.tar.gz", hash = "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210"}, + {file = "pylint-2.7.1-py3-none-any.whl", hash = "sha256:a251b238db462b71d25948f940568bb5b3ae0e37dbaa05e10523f54f83e6cc7e"}, + {file = "pylint-2.7.1.tar.gz", hash = "sha256:81ce108f6342421169ea039ff1f528208c99d2e5a9c4ca95cfc5291be6dfd982"}, ] pymongo = [ - {file = "pymongo-3.11.2-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:9be785bd4e1ba0148fb00ca84e4dbfbd1c74df3af3a648559adc60b0782f34de"}, - {file = "pymongo-3.11.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:646d4d30c5aa7c0ddbfe9b990f0f77a88621024a21ad0b792bd9d58caa9611f0"}, - {file = "pymongo-3.11.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8d669c720891781e7c82d412cad39f9730ef277e3957b48a3344dae47d3caa03"}, - {file = "pymongo-3.11.2-cp27-cp27m-win32.whl", hash = "sha256:ce53c00be204ec4428d3c1f3c478ae89d388efec575544c27f57b61e9fa4a7f2"}, - {file = "pymongo-3.11.2-cp27-cp27m-win_amd64.whl", hash = "sha256:82d5ded5834b6c92380847860eb28dcaf20b847a27cee5811c4aaceef87fd280"}, - {file = "pymongo-3.11.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:fcc66d17a3363b7bd6d2655de8706e25a3cd1be2bd1b8e8d8a5c504a6ef893ae"}, - {file = "pymongo-3.11.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:b875bb4b438931dce550e170bfb558597189b8d0160f4ac60f14a21955161699"}, - {file = "pymongo-3.11.2-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:6700e251c6396cc05d7460dc05ef8e19e60a7b53b62c007725b48e123aaa2b1c"}, - {file = "pymongo-3.11.2-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:c046e09e886f4539f8626afba17fa8f2e6552731f9384e2827154e3e3b7fda4e"}, - {file = "pymongo-3.11.2-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:4942a5659ae927bb764a123a6409870ca5dd572d83b3bfb71412c9a191bbf792"}, - {file = "pymongo-3.11.2-cp34-cp34m-win32.whl", hash = "sha256:422069f2cebf58c9dd9e8040b4768f7be4f228c95bc4505e8fa8e7b4f7191ad8"}, - {file = "pymongo-3.11.2-cp34-cp34m-win_amd64.whl", hash = "sha256:44376a657717de8847d5d71a9305f3595c7e78c91ac77edbb87058d12ede87a6"}, - {file = "pymongo-3.11.2-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:36b9b98a39565a8f33803c81569442b35e749a72fb1aa7d0bcdb1a33052f8bcc"}, - {file = "pymongo-3.11.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a118a1df7280ffab7fe0f3eab325868339ff1c4d5b8e0750db0f0a796da8f849"}, - {file = "pymongo-3.11.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c812b6e53344e92f10f12235219fb769c491a4a87a02c9c3f93fe632e493bda8"}, - {file = "pymongo-3.11.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:cc421babc687dc52ce0fc19787b2404518ca749d9db59576100946ff886f38ed"}, - {file = "pymongo-3.11.2-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:6aac7e0e8de92f11a410eb68c24a2decbac6f094e82fd95d22546d0168e7a18b"}, - {file = "pymongo-3.11.2-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:c6cf288c9e03195d8e12b72a6388b32f18a5e9c2545622417a963e428e1fe496"}, - {file = "pymongo-3.11.2-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:5980509801cbd2942df31714d055d89863684b4de26829c349362e610a48694e"}, - {file = "pymongo-3.11.2-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:264843ce2af0640994a4331148ef5312989bc004678c457460758766c9b4decc"}, - {file = "pymongo-3.11.2-cp35-cp35m-win32.whl", hash = "sha256:ef18aa15b1aa18c42933deed5233b3284186e9ed85c25d2704ceff5099a3964c"}, - {file = "pymongo-3.11.2-cp35-cp35m-win_amd64.whl", hash = "sha256:019ddf7ced8e42cc6c8c608927c799be8097237596c94ffe551f6ef70e55237e"}, - {file = "pymongo-3.11.2-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:96c6aef7ffb0d37206c0342abb82d874fa8cdc344267277ec63f562b94335c22"}, - {file = "pymongo-3.11.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:82f6e42ba40440a7e0a20bfe12465a3b62d65966a4c7ad1a21b36ffff88de6fe"}, - {file = "pymongo-3.11.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5ad7b96c27acd7e256b33f47cf3d23bd7dd902f9c033ae43f32ffcbc37bebafd"}, - {file = "pymongo-3.11.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:45728e6aae3023afb5b2829586d1d2bfd9f0d71cfd7d3c924b71a5e9aef617a8"}, - {file = "pymongo-3.11.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:ce9964c117cbe5cf6269f30a2b334d28675956e988b7dbd0b4f7370924afda2e"}, - {file = "pymongo-3.11.2-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:1222025db539641071a1b67f6950f65a6342a39db5b454bf306abd6954f1ad8a"}, - {file = "pymongo-3.11.2-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:fc4946acb6cdada08f60aca103b61334995523da65be5fe816ea8571c9967d46"}, - {file = "pymongo-3.11.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:76579fcf77052b39796fe4a11818d1289dd48cffe15951b3403288fa163c29f6"}, - {file = "pymongo-3.11.2-cp36-cp36m-win32.whl", hash = "sha256:d6f82e86896a8db70e8ae8fa4b7556a0f188f1d8a6c53b2ba229889d55a59308"}, - {file = "pymongo-3.11.2-cp36-cp36m-win_amd64.whl", hash = "sha256:082832a59da18efab4d9148cca396451bac99da9757f31767f706e828b5b8500"}, - {file = "pymongo-3.11.2-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:3646c2286d889618d43e01d9810ac1fc17709d2b4dec61366df5edc8ba228b3e"}, - {file = "pymongo-3.11.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3ec8f8e106a1476659d8c020228b45614daabdbdb6c6454a843a1d4f77d13339"}, - {file = "pymongo-3.11.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:202ea1d4edc8a5439fc179802d807b49e7e563207fea5610779e56674ac770c6"}, - {file = "pymongo-3.11.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b50af6701b4a5288b77fb4db44a363aa9485caf2c3e7a40c0373fd45e34440af"}, - {file = "pymongo-3.11.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:46792b71ab802d9caf1fc9d52e83399ef8e1a36e91eef4d827c06e36b8df2230"}, - {file = "pymongo-3.11.2-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:21d7b48567a1c80f9266e0ab61c1218a31279d911da345679188733e354f81cc"}, - {file = "pymongo-3.11.2-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:29a6840c2ac778010547cad5870f3db2e080ad7fad01197b07fff993c08692c8"}, - {file = "pymongo-3.11.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:6122470dfa61d4909b75c98012c1577404ba4ab860d0095e0c6980560cb3711f"}, - {file = "pymongo-3.11.2-cp37-cp37m-win32.whl", hash = "sha256:047cc2007b280672ddfdf2e7b862aad8d898f481f65bbc9067bfa4e420a019a9"}, - {file = "pymongo-3.11.2-cp37-cp37m-win_amd64.whl", hash = "sha256:1580fad512c678b720784e5c9018621b1b3bd37fb5b1633e874738862d6435c7"}, - {file = "pymongo-3.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e69fa025a1db189443428f345fea5555d16413df6addc056e17bb8c9794b006"}, - {file = "pymongo-3.11.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:813db97e9955b6b1b50b5cebd18cb148580603bb9b067ea4c5cc656b333bc906"}, - {file = "pymongo-3.11.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:523804bd8fcb5255508052b50073a27c701b90a73ea46e29be46dad5fe01bde6"}, - {file = "pymongo-3.11.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fa741e9c805567239f845c7e9a016aff797f9bb02ff9bc8ccd2fbd9eafefedd4"}, - {file = "pymongo-3.11.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:b95d2c2829b5956bf54d9a22ffec911dea75abf0f0f7e0a8a57423434bfbde91"}, - {file = "pymongo-3.11.2-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:6e7a6057481a644970e43475292e1c0af095ca39a20fe83781196bd6e6690a38"}, - {file = "pymongo-3.11.2-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:540dafd6f4a0590fc966465c726b80fa7c0804490c39786ef29236fe68c94401"}, - {file = "pymongo-3.11.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:d9d3ae537f61011191b2fd6f8527b9f9f8a848b37d4c85a0f7bb28004c42b546"}, - {file = "pymongo-3.11.2-cp38-cp38-win32.whl", hash = "sha256:047c325c4a96e7be7d11acf58639bcf71a81ca212d9c6590e3369bc28678647a"}, - {file = "pymongo-3.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:b4294ddf76452459433ecfa6a93258608b5e462c76ef15e4695ed5e2762f009f"}, - {file = "pymongo-3.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:061d59f525831c4051af0b6dbafa62b0b8b168d4ef5b6e3c46d0811b8499d100"}, - {file = "pymongo-3.11.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ed98683d8f01f1c46ef2d02469e04e9a8fe9a73a9741a4e6e66677a73b59bec8"}, - {file = "pymongo-3.11.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7f0c507e1f108790840d6c4b594019ebf595025c324c9f7e9c9b2b15b41f884e"}, - {file = "pymongo-3.11.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9d19843568df9d263dc92ae4cc2279879add8a26996473f9155590cac635b321"}, - {file = "pymongo-3.11.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:6175fd105da74a09adb38f93be96e1f64873294c906e5e722cbbc5bd10c44e3b"}, - {file = "pymongo-3.11.2-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:944ed467feb949e103555863fa934fb84216a096b0004ca364d3ddf9d18e2b9e"}, - {file = "pymongo-3.11.2-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:4be4fe9d18523da98deeb0b554ac76e1dc1562ee879d62572b34dda8593efcc1"}, - {file = "pymongo-3.11.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:270a1f6a331eac3a393090af06df68297cb31a8b2df0bdcbd97dc613c5758e78"}, - {file = "pymongo-3.11.2-cp39-cp39-win32.whl", hash = "sha256:e565d1e4388765c135052717f15f9e0314f9d172062444c6b3fc0002e93ed04b"}, - {file = "pymongo-3.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:0a53a751d977ad02f1bd22ddb6288bb4816c4758f44a50225462aeeae9cbf6a0"}, - {file = "pymongo-3.11.2-py2.7-macosx-10.14-intel.egg", hash = "sha256:c1d1992bbdf363b22b5a9543ab7d7c6f27a1498826d50d91319b803ddcf1142e"}, - {file = "pymongo-3.11.2.tar.gz", hash = "sha256:c2b67881392a9e85aa108e75f62cdbe372d5a3f17ea5f8d3436dcf4662052f14"}, + {file = "pymongo-3.11.3-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:4d959e929cec805c2bf391418b1121590b4e7d5cb00af7b1ba521443d45a0918"}, + {file = "pymongo-3.11.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9fbffc5bad4df99a509783cbd449ed0d24fcd5a450c28e7756c8f20eda3d2aa5"}, + {file = "pymongo-3.11.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:bd351ceb2decd23d523fc50bad631ee9ae6e97e7cdc355ce5600fe310484f96e"}, + {file = "pymongo-3.11.3-cp27-cp27m-win32.whl", hash = "sha256:7d2ae2f7c50adec20fde46a73465de31a6a6fbb4903240f8b7304549752ca7a1"}, + {file = "pymongo-3.11.3-cp27-cp27m-win_amd64.whl", hash = "sha256:b1aa62903a2c5768b0001632efdea2e8da6c80abdd520c2e8a16001cc9affb23"}, + {file = "pymongo-3.11.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:180511abfef70feb022360b35f4863dd68e08334197089201d5c52208de9ca2e"}, + {file = "pymongo-3.11.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:42f9ec9d77358f557fe17cc15e796c4d4d492ede1a30cba3664822cae66e97c5"}, + {file = "pymongo-3.11.3-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:3dbc67754882d740f17809342892f0b24398770bd99d48c5cb5ba89f5f5dee4e"}, + {file = "pymongo-3.11.3-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:733e1cfffc4cd99848230e2999c8a86e284c6af6746482f8ad2ad554dce14e39"}, + {file = "pymongo-3.11.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:622a5157ffcd793d305387c1c9fb94185f496c8c9fd66dafb59de0807bc14ad7"}, + {file = "pymongo-3.11.3-cp34-cp34m-win32.whl", hash = "sha256:2aeb108da1ed8e066800fb447ba5ae89d560e6773d228398a87825ac3630452d"}, + {file = "pymongo-3.11.3-cp34-cp34m-win_amd64.whl", hash = "sha256:7c77801620e5e75fb9c7abae235d3cc45d212a67efa98f4972eef63e736a8daa"}, + {file = "pymongo-3.11.3-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:29390c39ca873737689a0749c9c3257aad96b323439b11279fbc0ba8626ec9c5"}, + {file = "pymongo-3.11.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a8b02e0119d6ee381a265d8d2450a38096f82916d895fed2dfd81d4c7a54d6e4"}, + {file = "pymongo-3.11.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28633868be21a187702a8613913e13d1987d831529358c29fc6f6670413df040"}, + {file = "pymongo-3.11.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:685b884fa41bd2913fd20af85866c4ff886b7cbb7e4833b918996aa5d45a04be"}, + {file = "pymongo-3.11.3-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:7cd42c66d49ffb68dea065e1c8a4323e7ceab386e660fee9863d4fa227302ba9"}, + {file = "pymongo-3.11.3-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:950710f7370613a6bfa2ccd842b488c5b8072e83fb6b7d45d99110bf44651d06"}, + {file = "pymongo-3.11.3-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:c7fd18d4b7939408df9315fedbdb05e179760960a92b3752498e2fcd03f24c3d"}, + {file = "pymongo-3.11.3-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:cc359e408712faf9ea775f4c0ec8f2bfc843afe47747a657808d9595edd34d71"}, + {file = "pymongo-3.11.3-cp35-cp35m-win32.whl", hash = "sha256:7814b2cf23aad23464859973c5cd2066ca2fd99e0b934acefbb0b728ac2525bf"}, + {file = "pymongo-3.11.3-cp35-cp35m-win_amd64.whl", hash = "sha256:e1414599a97554d451e441afb362dbee1505e4550852c0068370d843757a3fe2"}, + {file = "pymongo-3.11.3-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:0384d76b409278ddb34ac19cdc4664511685959bf719adbdc051875ded4689aa"}, + {file = "pymongo-3.11.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:22ee2c94fee1e391735be63aa1c9af4c69fdcb325ae9e5e4ddff770248ef60a6"}, + {file = "pymongo-3.11.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:db6fd53ef5f1914ad801830406440c3bfb701e38a607eda47c38adba267ba300"}, + {file = "pymongo-3.11.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:66b688fc139c6742057795510e3b12c4acbf90d11af1eff9689a41d9c84478d6"}, + {file = "pymongo-3.11.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:6a5834e392c97f19f36670e34bf9d346d733ad89ee0689a6419dd737dfa4308a"}, + {file = "pymongo-3.11.3-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:87981008d565f647142869d99915cc4760b7725858da3d39ecb2a606e23f36fd"}, + {file = "pymongo-3.11.3-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:413b18ac2222f5d961eb8d1c8dcca6c6ca176c8613636d8c13aa23abae7f7a21"}, + {file = "pymongo-3.11.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:610d5cbbfd026e2f6d15665af51e048e49b68363fedece2ed318cc8fe080dd94"}, + {file = "pymongo-3.11.3-cp36-cp36m-win32.whl", hash = "sha256:3873866534b6527e6863e742eb23ea2a539e3c7ee00ad3f9bec9da27dbaaff6f"}, + {file = "pymongo-3.11.3-cp36-cp36m-win_amd64.whl", hash = "sha256:b17e627844d86031c77147c40bf992a6e1114025a460874deeda6500d0f34862"}, + {file = "pymongo-3.11.3-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:05e2bda928a3a6bc6ddff9e5a8579d41928b75d7417b18f9a67c82bb52150ac6"}, + {file = "pymongo-3.11.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:19d52c60dc37520385f538d6d1a4c40bc398e0885f4ed6a36ce10b631dab2852"}, + {file = "pymongo-3.11.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2163d736d6f62b20753be5da3dc07a188420b355f057fcbb3075b05ee6227b2f"}, + {file = "pymongo-3.11.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b4535d98df83abebb572035754fb3d4ad09ce7449375fa09fa9ede2dbc87b62b"}, + {file = "pymongo-3.11.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:cd8fc35d4c0c717cc29b0cb894871555cb7137a081e179877ecc537e2607f0b9"}, + {file = "pymongo-3.11.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:92e2376ce3ca0e3e443b3c5c2bb5d584c7e59221edfb0035313c6306049ba55a"}, + {file = "pymongo-3.11.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:4ca92e15fcf02e02e7c24b448a16599b98c9d0e6a46cd85cc50804450ebf7245"}, + {file = "pymongo-3.11.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5a03ae5ac85b04b2034a0689add9ff597b16d5e24066a87f6ab0e9fa67049156"}, + {file = "pymongo-3.11.3-cp37-cp37m-win32.whl", hash = "sha256:bc2eb67387b8376120a2be6cba9d23f9d6a6c3828e00fb0a64c55ad7b54116d1"}, + {file = "pymongo-3.11.3-cp37-cp37m-win_amd64.whl", hash = "sha256:5e1341276ce8b7752db9aeac6bbb0cbe82a3f6a6186866bf6b4906d8d328d50b"}, + {file = "pymongo-3.11.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4ac387ac1be71b798d1c372a924f9c30352f30e684e06f086091297352698ac0"}, + {file = "pymongo-3.11.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:728313cc0d59d1a1a004f675607dcf5c711ced3f55e75d82b3f264fd758869f3"}, + {file = "pymongo-3.11.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:daa44cefde19978af57ac1d50413cd86ebf2b497328e7a27832f5824bda47439"}, + {file = "pymongo-3.11.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:322f6cc7bf23a264151ebc5229a92600c4b55ac83c83c91c9bab1ec92c888a8d"}, + {file = "pymongo-3.11.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:6043d251fac27ca04ff22ed8deb5ff7a43dc18e8a4a15b4c442d2a20fa313162"}, + {file = "pymongo-3.11.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:66573c8c7808cce4f3b56c23cb7cad6c3d7f4c464b9016d35f5344ad743896d7"}, + {file = "pymongo-3.11.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bf70097bd497089f1baabf9cbb3ec4f69c022dc7a70c41ba9c238fa4d0fff7ab"}, + {file = "pymongo-3.11.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:f23abcf6eca5859a2982beadfb5111f8c5e76e30ff99aaee3c1c327f814f9f10"}, + {file = "pymongo-3.11.3-cp38-cp38-win32.whl", hash = "sha256:1d559a76ae87143ad96c2ecd6fdd38e691721e175df7ced3fcdc681b4638bca1"}, + {file = "pymongo-3.11.3-cp38-cp38-win_amd64.whl", hash = "sha256:152e4ac3158b776135d8fce28d2ac06e682b885fcbe86690d66465f262ab244e"}, + {file = "pymongo-3.11.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34c15f5798f23488e509eae82fbf749c3d17db74379a88c07c869ece1aa806b9"}, + {file = "pymongo-3.11.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:210ec4a058480b9c3869082e52b66d80c4a48eda9682d7a569a1a5a48100ea54"}, + {file = "pymongo-3.11.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b44fa04720bbfd617b6aef036989c8c30435f11450c0a59136291d7b41ed647f"}, + {file = "pymongo-3.11.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b32e4eed2ef19a20dfb57698497a9bc54e74efb2e260c003e9056c145f130dc7"}, + {file = "pymongo-3.11.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:5091aacbdb667b418b751157f48f6daa17142c4f9063d58e5a64c90b2afbdf9a"}, + {file = "pymongo-3.11.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:bb6a5777bf558f444cd4883d617546182cfeff8f2d4acd885253f11a16740534"}, + {file = "pymongo-3.11.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:980527f4ccc6644855bb68056fe7835da6d06d37776a52df5bcc1882df57c3db"}, + {file = "pymongo-3.11.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:65b67637f0a25ac9d25efb13c1578eb065870220ffa82f132c5b2d8e43ac39c3"}, + {file = "pymongo-3.11.3-cp39-cp39-win32.whl", hash = "sha256:f6748c447feeadda059719ef5ab1fb9d84bd370e205b20049a0e8b45ef4ad593"}, + {file = "pymongo-3.11.3-cp39-cp39-win_amd64.whl", hash = "sha256:ee42a8f850143ae7c67ea09a183a6a4ad8d053e1dbd9a1134e21a7b5c1bc6c73"}, + {file = "pymongo-3.11.3-py2.7-macosx-10.14-intel.egg", hash = "sha256:7edff02e44dd0badd749d7342e40705a398d98c5d8f7570f57cff9568c2351fa"}, + {file = "pymongo-3.11.3.tar.gz", hash = "sha256:db5098587f58fbf8582d9bda2462762b367207246d3e19623782fb449c3c5fcc"}, ] pynput = [ - {file = "pynput-1.7.2-py2.py3-none-any.whl", hash = "sha256:3ee18347a20be07b7185c9aa29f37c75d322f85ac8ec689ebb49ee39fa9dcb94"}, - {file = "pynput-1.7.2-py3.8.egg", hash = "sha256:65b3e826cc8f3397b67cd34bd1e0d340a1194f926cabd8b3bed8285c6af93dfd"}, - {file = "pynput-1.7.2.tar.gz", hash = "sha256:dd8b1ff2451e2b76c753e115ab20b6cfa73801c395f22987474f942726558fec"}, + {file = "pynput-1.7.3-py2.py3-none-any.whl", hash = "sha256:fea5777454f896bd79d35393088cd29a089f3b2da166f0848a922b1d5a807d4f"}, + {file = "pynput-1.7.3-py3.8.egg", hash = "sha256:6626e8ea9ca482bb5628a7169e1193824e382c4ad3053e40f4f24f41ee7b41c9"}, + {file = "pynput-1.7.3.tar.gz", hash = "sha256:4e50b1a0ab86847e87e58f6d1993688b9a44f9f4c88d4712315ea8eb552ef828"}, ] pyobjc-core = [ {file = "pyobjc-core-7.1.tar.gz", hash = "sha256:a0616d5d816b4471f8f782c3a9a8923d2cc85014d88ad4f7fec694be9e6ea349"}, @@ -2035,11 +2061,17 @@ pyparsing = [ {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] pyqt5 = [ - {file = "PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:894ca4ae767a8d6cf5903784b71f755073c78cb8c167eecf6e4ed6b3b055ac6a"}, - {file = "PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:29889845688a54d62820585ad5b2e0200a36b304ff3d7a555e95599f110ba4ce"}, - {file = "PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:ea24f24b7679bf393dd2e4f53fe0ce65021be18304c1ff7a226c2fc5c356d0da"}, - {file = "PyQt5-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:faaecb76ec65e12673a968e7f5bc02495957e6996f0a3fa0d98895f9e4113746"}, - {file = "PyQt5-5.15.2.tar.gz", hash = "sha256:372b08dc9321d1201e4690182697c5e7ffb2e0770e6b4a45519025134b12e4fc"}, + {file = "PyQt5-5.15.3-cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:69fdceed983ebd388f44ceab9b8a6c2c086c79c705182fcc7b06837e2ccf7ba3"}, + {file = "PyQt5-5.15.3-cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:8b9e07094382d51dc34f63c5a417b735dae1ad934a9dd9bc08bbc0a39452bfe8"}, + {file = "PyQt5-5.15.3-cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:ef2682dc829d6603fb5c958274d721fb076fd84a88fcb8f9fc7655cbb72b2bfc"}, + {file = "PyQt5-5.15.3-cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:4e0fc6993df120e686528de46f2e002e930e24f99f103788724f0bd8bec9b4f7"}, + {file = "PyQt5-5.15.3.tar.gz", hash = "sha256:965ba50e7029b37f218a54ace24e87c77db3e5a9f0b83baeb21fb57b4154b838"}, +] +pyqt5-qt = [ + {file = "PyQt5_Qt-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:962511bfdc847f0746e1de92499cbb1ae127ca5ec356f009a6d9f924fe1230d5"}, + {file = "PyQt5_Qt-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:dec2e88fbfabc0d3365bb4007c88c75fc99fc75cfb418399aeb5acd1d5f7d484"}, + {file = "PyQt5_Qt-5.15.2-py3-none-win32.whl", hash = "sha256:8aba4f0a245c42f186a235c47011ee422a14b949e52fc64e697b10d1c433ff39"}, + {file = "PyQt5_Qt-5.15.2-py3-none-win_amd64.whl", hash = "sha256:756b8c055033b2d96d18e74e1380bdb64984b150879fa92cd62d327f78636153"}, ] pyqt5-sip = [ {file = "PyQt5_sip-12.8.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:bb5a87b66fc1445915104ee97f7a20a69decb42f52803e3b0795fa17ff88226c"}, @@ -2087,6 +2119,9 @@ python-xlib = [ {file = "python-xlib-0.29.tar.gz", hash = "sha256:e4bcb756f4aa05be7b82ee21de0ba04d73414018727b42ebd9fbcf409ea75d13"}, {file = "python_xlib-0.29-py2.py3-none-any.whl", hash = "sha256:044095d1b1a5eab5a79f8d0b66f811a9ac6acd038dd3bae00cb3dbe90b32a7e3"}, ] +python3-xlib = [ + {file = "python3-xlib-0.15.tar.gz", hash = "sha256:dc4245f3ae4aa5949c1d112ee4723901ade37a96721ba9645f2bfa56e5b383f8"}, +] pytz = [ {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, @@ -2120,12 +2155,12 @@ requests = [ {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, ] rsa = [ - {file = "rsa-4.7-py3-none-any.whl", hash = "sha256:a8774e55b59fd9fc893b0d05e9bfc6f47081f46ff5b46f39ccf24631b7be356b"}, - {file = "rsa-4.7.tar.gz", hash = "sha256:69805d6b69f56eb05b62daea3a7dbd7aa44324ad1306445e05da8060232d00f4"}, + {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, + {file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"}, ] secretstorage = [ - {file = "SecretStorage-3.3.0-py3-none-any.whl", hash = "sha256:5c36f6537a523ec5f969ef9fad61c98eb9e017bc601d811e53aa25bece64892f"}, - {file = "SecretStorage-3.3.0.tar.gz", hash = "sha256:30cfdef28829dad64d6ea1ed08f8eff6aa115a77068926bcc9f5225d5a3246aa"}, + {file = "SecretStorage-3.3.1-py3-none-any.whl", hash = "sha256:422d82c36172d88d6a0ed5afdec956514b189ddbfb72fefab0c8a1cee4eaf71f"}, + {file = "SecretStorage-3.3.1.tar.gz", hash = "sha256:fd666c51a6bf200643495a04abb261f83229dcb6fd8472ec393df7ffc8b6f195"}, ] six = [ {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, @@ -2140,8 +2175,8 @@ speedcopy = [ {file = "speedcopy-2.1.0.tar.gz", hash = "sha256:8bb1a6c735900b83901a7be84ba2175ed3887c13c6786f97dea48f2ea7d504c2"}, ] sphinx = [ - {file = "Sphinx-3.4.3-py3-none-any.whl", hash = "sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8"}, - {file = "Sphinx-3.4.3.tar.gz", hash = "sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c"}, + {file = "Sphinx-3.5.1-py3-none-any.whl", hash = "sha256:e90161222e4d80ce5fc811ace7c6787a226b4f5951545f7f42acf97277bfc35c"}, + {file = "Sphinx-3.5.1.tar.gz", hash = "sha256:11d521e787d9372c289472513d807277caafb1684b33eb4f08f7574c405893a9"}, ] sphinx-qt-documentation = [ {file = "sphinx_qt_documentation-0.3-py3-none-any.whl", hash = "sha256:bee247cb9e4fc03fc496d07adfdb943100e1103320c3e5e820e0cfa7c790d9b6"}, @@ -2187,8 +2222,8 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tqdm = [ - {file = "tqdm-4.56.0-py2.py3-none-any.whl", hash = "sha256:4621f6823bab46a9cc33d48105753ccbea671b68bab2c50a9f0be23d4065cb5a"}, - {file = "tqdm-4.56.0.tar.gz", hash = "sha256:fe3d08dd00a526850568d542ff9de9bbc2a09a791da3c334f3213d8d0bbbca65"}, + {file = "tqdm-4.58.0-py2.py3-none-any.whl", hash = "sha256:2c44efa73b8914dba7807aefd09653ac63c22b5b4ea34f7a80973f418f1a3089"}, + {file = "tqdm-4.58.0.tar.gz", hash = "sha256:c23ac707e8e8aabb825e4d91f8e17247f9cc14b0d64dd9e97be0781e9e525bba"}, ] typed-ast = [ {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, diff --git a/poetry.toml b/poetry.toml index ab1033bd37..f05df6491a 100644 --- a/poetry.toml +++ b/poetry.toml @@ -1,2 +1,5 @@ [virtualenvs] in-project = true + +[repositories.pype] +url = "http://d.r1.wbsprt.com/pype.club/distribute/" diff --git a/pype/api.py b/pype/api.py index 71c31efa93..44caa7632f 100644 --- a/pype/api.py +++ b/pype/api.py @@ -22,7 +22,9 @@ from .lib import ( get_app_environments_for_context, source_hash, get_latest_version, - get_global_environments + get_global_environments, + get_local_site_id, + change_pype_mongo_url ) from .lib.mongo import ( @@ -109,5 +111,8 @@ __all__ = [ "run_subprocess", "get_latest_version", - "get_global_environments" + "get_global_environments", + + "get_local_site_id", + "change_pype_mongo_url" ] diff --git a/pype/cli.py b/pype/cli.py index 7d499cbc75..f67cf10ea1 100644 --- a/pype/cli.py +++ b/pype/cli.py @@ -108,6 +108,27 @@ def eventserver(debug, ) +@main.command() +@click.argument("output_json_path") +@click.option("--project", help="Project name", default=None) +@click.option("--asset", help="Asset name", default=None) +@click.option("--task", help="Task name", default=None) +@click.option("--app", help="Application name", default=None) +def extractenvironments(output_json_path, project, asset, task, app): + """Extract environment variables for entered context to a json file. + + Entered output filepath will be created if does not exists. + + All context options must be passed otherwise only pype's global + environments will be extracted. + + Context options are "project", "asset", "task", "app" + """ + PypeCommands.extractenvironments( + output_json_path, project, asset, task, app + ) + + @main.command() @click.argument("paths", nargs=-1) @click.option("-d", "--debug", is_flag=True, help="Print debug messages") diff --git a/pype/hosts/harmony/plugins/publish/collect_palettes.py b/pype/hosts/harmony/plugins/publish/collect_palettes.py index 26b83ff171..e6795f894b 100644 --- a/pype/hosts/harmony/plugins/publish/collect_palettes.py +++ b/pype/hosts/harmony/plugins/publish/collect_palettes.py @@ -2,6 +2,7 @@ """Collect palettes from Harmony.""" import os import json +import re import pyblish.api from avalon import harmony @@ -11,8 +12,10 @@ class CollectPalettes(pyblish.api.ContextPlugin): """Gather palettes from scene when publishing templates.""" label = "Palettes" - order = pyblish.api.CollectorOrder + order = pyblish.api.CollectorOrder + 0.003 hosts = ["harmony"] + # list of regexes for task names where collecting should happen + allowed_tasks = [] def process(self, context): """Collector entry point.""" @@ -22,6 +25,13 @@ class CollectPalettes(pyblish.api.ContextPlugin): "function": f"PypeHarmony.Publish.{self_name}.getPalettes", })["result"] + # skip collecting if not in allowed task + if self.allowed_tasks: + task_name = context.data["anatomyData"]["task"].lower() + if (not any([re.search(pattern, task_name) + for pattern in self.allowed_tasks])): + return + for name, id in palettes.items(): instance = context.create_instance(name) instance.data.update({ diff --git a/pype/hosts/maya/api/attributes.py b/pype/hosts/maya/api/attributes.py new file mode 100644 index 0000000000..a98548301a --- /dev/null +++ b/pype/hosts/maya/api/attributes.py @@ -0,0 +1,334 @@ +# -*- coding: utf-8 -*- +"""Code to get attributes from render layer without switching to it. + +https://github.com/Colorbleed/colorbleed-config/blob/acre/colorbleed/maya/lib_rendersetup.py +Credits: Roy Nieterau (BigRoy) / Colorbleed +Modified for use in Pype + +""" + +from maya import cmds +import maya.api.OpenMaya as om +import pymel.core as pm + +import maya.app.renderSetup.model.utils as utils +from maya.app.renderSetup.model import renderSetup +from maya.app.renderSetup.model.override import ( + AbsOverride, + RelOverride, + UniqueOverride +) + +EXACT_MATCH = 0 +PARENT_MATCH = 1 +CLIENT_MATCH = 2 + +DEFAULT_RENDER_LAYER = "defaultRenderLayer" + + +def get_rendersetup_layer(layer): + """Return render setup layer name. + + This also converts names from legacy renderLayer node name to render setup + name. + + Note: `DEFAULT_RENDER_LAYER` is not a renderSetupLayer node but it is + however the valid layer name for Render Setup - so we return that as + is. + + Example: + >>> for legacy_layer in cmds.ls(type="renderLayer"): + >>> layer = get_rendersetup_layer(legacy_layer) + + Returns: + str or None: Returns renderSetupLayer node name if `layer` is a valid + layer name in legacy renderlayers or render setup layers. + Returns None if the layer can't be found or Render Setup is + currently disabled. + """ + if layer == DEFAULT_RENDER_LAYER: + # DEFAULT_RENDER_LAYER doesn't have a `renderSetupLayer` + return layer + + if not cmds.mayaHasRenderSetup(): + return None + + if not cmds.objExists(layer): + return None + + if cmds.nodeType(layer) == "renderSetupLayer": + return layer + + # By default Render Setup renames the legacy renderlayer + # to `rs_` but lets not rely on that as the + # layer node can be renamed manually + connections = cmds.listConnections(layer + ".message", + type="renderSetupLayer", + exactType=True, + source=False, + destination=True, + plugs=True) or [] + return next((conn.split(".", 1)[0] for conn in connections + if conn.endswith(".legacyRenderLayer")), None) + + +def get_attr_in_layer(node_attr, layer): + """Return attribute value in Render Setup layer. + + This will only work for attributes which can be + retrieved with `maya.cmds.getAttr` and for which + Relative and Absolute overrides are applicable. + + Examples: + >>> get_attr_in_layer("defaultResolution.width", layer="layer1") + >>> get_attr_in_layer("defaultRenderGlobals.startFrame", layer="layer") + >>> get_attr_in_layer("transform.translate", layer="layer3") + + Args: + attr (str): attribute name as 'node.attribute' + layer (str): layer name + + Returns: + object: attribute value in layer + + """ + def _layer_needs_update(layer): + """Return whether layer needs updating.""" + # Use `getattr` as e.g. DEFAULT_RENDER_LAYER does not have + # the attribute + return getattr(layer, "needsMembershipUpdate", False) or \ + getattr(layer, "needsApplyUpdate", False) + + def get_default_layer_value(node_attr_): + """Return attribute value in `DEFAULT_RENDER_LAYER`.""" + inputs = cmds.listConnections(node_attr_, + source=True, + destination=False, + type="applyOverride") or [] + if inputs: + override = inputs[0] + history_overrides = cmds.ls(cmds.listHistory(override, + pruneDagObjects=True), + type="applyOverride") + node = history_overrides[-1] if history_overrides else override + node_attr_ = node + ".original" + + return pm.getAttr(node_attr_, asString=True) + + layer = get_rendersetup_layer(layer) + rs = renderSetup.instance() + current_layer = rs.getVisibleRenderLayer() + if current_layer.name() == layer: + + # Ensure layer is up-to-date + if _layer_needs_update(current_layer): + try: + rs.switchToLayer(current_layer) + except RuntimeError: + # Some cases can cause errors on switching + # the first time with Render Setup layers + # e.g. different overrides to compounds + # and its children plugs. So we just force + # it another time. If it then still fails + # we will let it error out. + rs.switchToLayer(current_layer) + + return pm.getAttr(node_attr, asString=True) + + overrides = get_attr_overrides(node_attr, layer) + default_layer_value = get_default_layer_value(node_attr) + if not overrides: + return default_layer_value + + value = default_layer_value + for match, layer_override, index in overrides: + if isinstance(layer_override, AbsOverride): + # Absolute override + value = pm.getAttr(layer_override.name() + ".attrValue") + if match == EXACT_MATCH: + # value = value + pass + if match == PARENT_MATCH: + value = value[index] + if match == CLIENT_MATCH: + value[index] = value + + elif isinstance(layer_override, RelOverride): + # Relative override + # Value = Original * Multiply + Offset + multiply = pm.getAttr(layer_override.name() + ".multiply") + offset = pm.getAttr(layer_override.name() + ".offset") + + if match == EXACT_MATCH: + value = value * multiply + offset + if match == PARENT_MATCH: + value = value * multiply[index] + offset[index] + if match == CLIENT_MATCH: + value[index] = value[index] * multiply + offset + + else: + raise TypeError("Unsupported override: %s" % layer_override) + + return value + + +def get_attr_overrides(node_attr, layer, + skip_disabled=True, + skip_local_render=True, + stop_at_absolute_override=True): + """Return all Overrides applicable to the attribute. + + Overrides are returned as a 3-tuple: + (Match, Override, Index) + Match: + This is any of EXACT_MATCH, PARENT_MATCH, CLIENT_MATCH + and defines whether the override is exactly on the + plug, on the parent or on a child plug. + Override: + This is the RenderSetup Override instance. + Index: + This is the Plug index under the parent or for + the child that matches. The EXACT_MATCH index will + always be None. For PARENT_MATCH the index is which + index the plug is under the parent plug. For CLIENT_MATCH + the index is which child index matches the plug. + + Args: + node_attr (str): attribute name as 'node.attribute' + layer (str): layer name + skip_disabled (bool): exclude disabled overrides + skip_local_render (bool): exclude overrides marked + as local render. + stop_at_absolute_override: exclude overrides prior + to the last absolute override as they have + no influence on the resulting value. + + Returns: + list: Ordered Overrides in order of strength + + """ + def get_mplug_children(plug): + """Return children MPlugs of compound `MPlug`.""" + children = [] + if plug.isCompound: + for i in range(plug.numChildren()): + children.append(plug.child(i)) + return children + + def get_mplug_names(mplug): + """Return long and short name of `MPlug`.""" + long_name = mplug.partialName(useLongNames=True) + short_name = mplug.partialName(useLongNames=False) + return {long_name, short_name} + + def iter_override_targets(override): + try: + for target in override._targets(): + yield target + except AssertionError: + # Workaround: There is a bug where the private `_targets()` method + # fails on some attribute plugs. For example overrides + # to the defaultRenderGlobals.endFrame + # (Tested in Maya 2020.2) + print("Workaround for %s" % override) + from maya.app.renderSetup.common.utils import findPlug + + attr = override.attributeName() + if isinstance(override, UniqueOverride): + node = override.targetNodeName() + yield findPlug(node, attr) + else: + nodes = override.parent().selector().nodes() + for node in nodes: + if cmds.attributeQuery(attr, node=node, exists=True): + yield findPlug(node, attr) + + # Get the MPlug for the node.attr + sel = om.MSelectionList() + sel.add(node_attr) + plug = sel.getPlug(0) + + layer = get_rendersetup_layer(layer) + if layer == DEFAULT_RENDER_LAYER: + # DEFAULT_RENDER_LAYER will never have overrides + # since it's the default layer + return [] + + rs_layer = renderSetup.instance().getRenderLayer(layer) + if rs_layer is None: + # Renderlayer does not exist + return + + # Get any parent or children plugs as we also + # want to include them in the attribute match + # for overrides + parent = plug.parent() if plug.isChild else None + parent_index = None + if parent: + parent_index = get_mplug_children(parent).index(plug) + + children = get_mplug_children(plug) + + # Create lookup for the attribute by both long + # and short names + attr_names = get_mplug_names(plug) + for child in children: + attr_names.update(get_mplug_names(child)) + if parent: + attr_names.update(get_mplug_names(parent)) + + # Get all overrides of the layer + # And find those that are relevant to the attribute + plug_overrides = [] + + # Iterate over the overrides in reverse so we get the last + # overrides first and can "break" whenever an absolute + # override is reached + layer_overrides = list(utils.getOverridesRecursive(rs_layer)) + for layer_override in reversed(layer_overrides): + + if skip_disabled and not layer_override.isEnabled(): + # Ignore disabled overrides + continue + + if skip_local_render and layer_override.isLocalRender(): + continue + + # The targets list can be very large so we'll do + # a quick filter by attribute name to detect whether + # it matches the attribute name, or its parent or child + if layer_override.attributeName() not in attr_names: + continue + + override_match = None + for override_plug in iter_override_targets(layer_override): + + override_match = None + if plug == override_plug: + override_match = (EXACT_MATCH, layer_override, None) + + elif parent and override_plug == parent: + override_match = (PARENT_MATCH, layer_override, parent_index) + + elif children and override_plug in children: + child_index = children.index(override_plug) + override_match = (CLIENT_MATCH, layer_override, child_index) + + if override_match: + plug_overrides.append(override_match) + break + + if ( + override_match and + stop_at_absolute_override and + isinstance(layer_override, AbsOverride) and + # When the override is only on a child plug then it doesn't + # override the entire value so we not stop at this override + not override_match[0] == CLIENT_MATCH + ): + # If override is absolute override, then BREAK out + # of parent loop we don't need to look any further as + # this is the absolute override + break + + return reversed(plug_overrides) diff --git a/pype/hosts/maya/plugins/publish/collect_renderable_camera.py b/pype/hosts/maya/plugins/publish/collect_renderable_camera.py index b90b85e7ec..5b3468424a 100644 --- a/pype/hosts/maya/plugins/publish/collect_renderable_camera.py +++ b/pype/hosts/maya/plugins/publish/collect_renderable_camera.py @@ -2,7 +2,7 @@ import pyblish.api from maya import cmds -from pype.hosts.maya.api import lib +from pype.hosts.maya.api.attributes import get_attr_in_layer class CollectRenderableCamera(pyblish.api.InstancePlugin): @@ -24,7 +24,7 @@ class CollectRenderableCamera(pyblish.api.InstancePlugin): self.log.info("layer: {}".format(layer)) cameras = cmds.ls(type="camera", long=True) renderable = [c for c in cameras if - lib.get_attr_in_layer("%s.renderable" % c, layer=layer)] + get_attr_in_layer("%s.renderable" % c, layer)] self.log.info("Found cameras %s: %s" % (len(renderable), renderable)) diff --git a/pype/hosts/maya/plugins/publish/validate_model_name.py b/pype/hosts/maya/plugins/publish/validate_model_name.py index f0004dc81e..2f1586538e 100644 --- a/pype/hosts/maya/plugins/publish/validate_model_name.py +++ b/pype/hosts/maya/plugins/publish/validate_model_name.py @@ -22,7 +22,6 @@ class ValidateModelName(pyblish.api.InstancePlugin): # path to shader names definitions # TODO: move it to preset file material_file = None - active = False regex = '(.*)_(\\d)*_(.*)_(GEO)' @classmethod diff --git a/pype/hosts/maya/plugins/publish/validate_joints_hidden.py b/pype/hosts/maya/plugins/publish/validate_rig_joints_hidden.py similarity index 93% rename from pype/hosts/maya/plugins/publish/validate_joints_hidden.py rename to pype/hosts/maya/plugins/publish/validate_rig_joints_hidden.py index 61dfcd563d..a102df50de 100644 --- a/pype/hosts/maya/plugins/publish/validate_joints_hidden.py +++ b/pype/hosts/maya/plugins/publish/validate_rig_joints_hidden.py @@ -6,7 +6,7 @@ import pype.hosts.maya.api.action from pype.hosts.maya.api import lib -class ValidateJointsHidden(pyblish.api.InstancePlugin): +class ValidateRigJointsHidden(pyblish.api.InstancePlugin): """Validate all joints are hidden visually. This includes being hidden: @@ -20,7 +20,6 @@ class ValidateJointsHidden(pyblish.api.InstancePlugin): order = pype.api.ValidateContentsOrder hosts = ['maya'] families = ['rig'] - category = 'rig' version = (0, 1, 0) label = "Joints Hidden" actions = [pype.hosts.maya.api.action.SelectInvalidAction, diff --git a/pype/hosts/maya/plugins/publish/validate_shader_name.py b/pype/hosts/maya/plugins/publish/validate_shader_name.py index 4a42ec6e35..a2951d5551 100644 --- a/pype/hosts/maya/plugins/publish/validate_shader_name.py +++ b/pype/hosts/maya/plugins/publish/validate_shader_name.py @@ -13,7 +13,6 @@ class ValidateShaderName(pyblish.api.InstancePlugin): """ optional = True - active = False order = pype.api.ValidateContentsOrder families = ["look"] hosts = ['maya'] diff --git a/pype/hosts/maya/plugins/publish/validate_transform_naming_suffix.py b/pype/hosts/maya/plugins/publish/validate_transform_naming_suffix.py index 14d4e7d5c8..bd290c73c7 100644 --- a/pype/hosts/maya/plugins/publish/validate_transform_naming_suffix.py +++ b/pype/hosts/maya/plugins/publish/validate_transform_naming_suffix.py @@ -35,11 +35,11 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin): version = (0, 1, 0) label = 'Suffix Naming Conventions' actions = [pype.hosts.maya.api.action.SelectInvalidAction] - SUFFIX_NAMING_TABLE = {'mesh': ["_GEO", "_GES", "_GEP", "_OSD"], - 'nurbsCurve': ["_CRV"], - 'nurbsSurface': ["_NRB"], - 'locator': ["_LOC"], - None: ['_GRP']} + SUFFIX_NAMING_TABLE = {"mesh": ["_GEO", "_GES", "_GEP", "_OSD"], + "nurbsCurve": ["_CRV"], + "nurbsSurface": ["_NRB"], + "locator": ["_LOC"], + "group": ["_GRP"]} ALLOW_IF_NOT_IN_SUFFIX_TABLE = True @@ -88,7 +88,7 @@ class ValidateTransformNamingSuffix(pyblish.api.InstancePlugin): fullPath=True, noIntermediate=True) - shape_type = cmds.nodeType(shapes[0]) if shapes else None + shape_type = cmds.nodeType(shapes[0]) if shapes else "group" if not cls.is_valid_name(transform, shape_type, cls.SUFFIX_NAMING_TABLE, cls.ALLOW_IF_NOT_IN_SUFFIX_TABLE): diff --git a/pype/hosts/maya/plugins/publish/validate_unicode_strings.py b/pype/hosts/maya/plugins/publish/validate_unicode_strings.py deleted file mode 100644 index cfcba4f514..0000000000 --- a/pype/hosts/maya/plugins/publish/validate_unicode_strings.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -from maya import cmds - -import pyblish.api -import pype.api -import pype.hosts.maya.api.action - - -class ValidateUnicodeStrings(pyblish.api.Validator): - """Validate all environment variables are string type. - - """ - - order = pype.api.ValidateContentsOrder - hosts = ['maya'] - families = ['review'] - label = 'Unicode Strings' - actions = [pype.api.RepairAction] - - def process(self, instance): - invalid = self.get_invalid(instance) - if invalid: - raise RuntimeError("Found unicode strings in environment variables.") - - @classmethod - def get_invalid(cls, instance): - invalid = [] - for key, value in os.environ.items(): - if type(value) is type(u't'): - invalid.append((key, value)) - - return invalid - - @classmethod - def repair(cls, instance): - """Retype all unicodes to strings.""" - - for key, value in os.environ.items(): - if type(value) is type(u't'): - os.environ[key] = str(value) diff --git a/pype/hosts/nuke/plugins/publish/validate_knobs.py b/pype/hosts/nuke/plugins/publish/validate_knobs.py index ce15831c9c..cbc02690cb 100644 --- a/pype/hosts/nuke/plugins/publish/validate_knobs.py +++ b/pype/hosts/nuke/plugins/publish/validate_knobs.py @@ -9,7 +9,7 @@ class ValidateKnobs(pyblish.api.ContextPlugin): Knobs to validate and their values comes from the - Controled by plugin settings that require json in following structure: + Controlled by plugin settings that require json in following structure: "ValidateKnobs": { "enabled": true, "knobs": { diff --git a/pype/hosts/tvpaint/plugins/publish/extract_sequence.py b/pype/hosts/tvpaint/plugins/publish/extract_sequence.py index c213b468c7..aa625a497a 100644 --- a/pype/hosts/tvpaint/plugins/publish/extract_sequence.py +++ b/pype/hosts/tvpaint/plugins/publish/extract_sequence.py @@ -157,8 +157,8 @@ class ExtractSequence(pyblish.api.Extractor): "ext": ext, "files": repre_files, "stagingDir": output_dir, - "frameStart": frame_start, - "frameEnd": frame_end, + "frameStart": frame_start + 1, + "frameEnd": frame_end + 1, "tags": tags } self.log.debug("Creating new representation: {}".format(new_repre)) diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 4b7e59ab3d..67a31d1737 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -23,6 +23,7 @@ from .mongo import ( decompose_url, compose_url, get_default_components, + validate_mongo_connection, PypeMongoConnection ) from .anatomy import ( @@ -91,10 +92,12 @@ from .plugin_tools import ( should_decompress ) -from .user_settings import ( +from .local_settings import ( IniSettingRegistry, JSONSettingRegistry, - PypeSettingsRegistry + PypeSettingsRegistry, + get_local_site_id, + change_pype_mongo_url ) from .path_tools import ( @@ -191,11 +194,15 @@ __all__ = [ "decompose_url", "compose_url", "get_default_components", + "validate_mongo_connection", "PypeMongoConnection", "IniSettingRegistry", "JSONSettingRegistry", "PypeSettingsRegistry", + "get_local_site_id", + "change_pype_mongo_url", + "timeit", "is_overlapping_otio_ranges", diff --git a/pype/lib/execute.py b/pype/lib/execute.py index 7e37e5d6da..f815d05f1b 100644 --- a/pype/lib/execute.py +++ b/pype/lib/execute.py @@ -94,7 +94,7 @@ def run_subprocess(*args, **kwargs): # not passed. env = kwargs.get("env") or os.environ # Make sure environment contains only strings - filtered_env = {k: str(v) for k, v in env.items()} + filtered_env = {str(k): str(v) for k, v in env.items()} # Use lib's logger if was not passed with kwargs. logger = kwargs.pop("logger", log) diff --git a/pype/lib/user_settings.py b/pype/lib/local_settings.py similarity index 92% rename from pype/lib/user_settings.py rename to pype/lib/local_settings.py index 00ce68cb0b..aa372a52d2 100644 --- a/pype/lib/user_settings.py +++ b/pype/lib/local_settings.py @@ -28,6 +28,8 @@ import platform import appdirs import six +from .import validate_mongo_connection + @six.add_metaclass(ABCMeta) class ASettingRegistry(): @@ -118,7 +120,7 @@ class ASettingRegistry(): """Delete item from settings. Note: - see :meth:`pype.lib.user_settings.ARegistrySettings.delete_item` + see :meth:`pype.lib.local_settings.ARegistrySettings.delete_item` """ pass @@ -464,3 +466,43 @@ class PypeSettingsRegistry(JSONSettingRegistry): self.product = "pype" path = appdirs.user_data_dir(self.product, self.vendor) super(PypeSettingsRegistry, self).__init__("pype_settings", path) + + +def _create_local_site_id(registry=None): + """Create a local site identifier.""" + from uuid import uuid4 + + if registry is None: + registry = PypeSettingsRegistry() + + new_id = str(uuid4()) + + print("Created local site id \"{}\"".format(new_id)) + + registry.set_item("localId", new_id) + + return new_id + + +def get_local_site_id(): + """Get local site identifier. + + Identifier is created if does not exists yet. + """ + registry = PypeSettingsRegistry() + try: + return registry.get_item("localId") + except ValueError: + return _create_local_site_id() + + +def change_pype_mongo_url(new_mongo_url): + """Change mongo url in pype registry. + + Change of Pype mongo URL require restart of running pype processes or + processes using pype. + """ + + validate_mongo_connection(new_mongo_url) + registry = PypeSettingsRegistry() + registry.set_secure_item("pypeMongo", new_mongo_url) diff --git a/pype/lib/mongo.py b/pype/lib/mongo.py index f82c8b5e23..04798d88ff 100644 --- a/pype/lib/mongo.py +++ b/pype/lib/mongo.py @@ -93,6 +93,42 @@ def extract_port_from_url(url): return parsed_url.port +def validate_mongo_connection(mongo_uri): + """Check if provided mongodb URL is valid. + + Args: + mongo_uri (str): URL to validate. + + Raises: + ValueError: When port in mongo uri is not valid. + pymongo.errors.InvalidURI: If passed mongo is invalid. + pymongo.errors.ServerSelectionTimeoutError: If connection timeout + passed so probably couldn't connect to mongo server. + + """ + parsed = urlparse(mongo_uri) + # Force validation of scheme + if parsed.scheme not in ["mongodb", "mongodb+srv"]: + raise pymongo.errors.InvalidURI(( + "Invalid URI scheme:" + " URI must begin with 'mongodb://' or 'mongodb+srv://'" + )) + # we have mongo connection string. Let's try if we can connect. + components = decompose_url(mongo_uri) + mongo_args = { + "host": compose_url(**components), + "serverSelectionTimeoutMS": 1000 + } + port = components.get("port") + if port is not None: + mongo_args["port"] = int(port) + + # Create connection + client = pymongo.MongoClient(**mongo_args) + client.server_info() + client.close() + + class PypeMongoConnection: """Singleton MongoDB connection. diff --git a/pype/modules/__init__.py b/pype/modules/__init__.py index 93fc92f9d5..e0481d0c92 100644 --- a/pype/modules/__init__.py +++ b/pype/modules/__init__.py @@ -9,7 +9,10 @@ from .base import ( ModulesManager, TrayModulesManager ) -from .settings_action import SettingsAction +from .settings_action import ( + SettingsAction, + LocalSettingsAction +) from .rest_api import ( RestApiModule, IRestApi @@ -52,6 +55,7 @@ __all__ = ( "TrayModulesManager", "SettingsAction", + "LocalSettingsAction", "UserModule", "IUserModule", diff --git a/pype/modules/base.py b/pype/modules/base.py index ad0fecb8f7..7efd00e39e 100644 --- a/pype/modules/base.py +++ b/pype/modules/base.py @@ -627,6 +627,7 @@ class TrayModulesManager(ModulesManager): "clockify", "standalonepublish_tool", "log_viewer", + "local_settings", "settings" ) diff --git a/pype/modules/deadline/plugins/publish/submit_nuke_deadline.py b/pype/modules/deadline/plugins/publish/submit_nuke_deadline.py index b36e1fdbba..af8694dd22 100644 --- a/pype/modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/pype/modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -23,12 +23,12 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin): optional = True # presets - deadline_priority = 50 - deadline_chunk_size = 1 - deadline_pool = "" - deadline_pool_secondary = "" - deadline_group = "" - deadline_department = "" + priority = 50 + chunk_size = 1 + primary_pool = "" + secondary_pool = "" + group = "" + department = "" def process(self, instance): instance.data["toBeRenderedOn"] = "deadline" @@ -142,12 +142,12 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin): # define chunk and priority chunk_size = instance.data.get("deadlineChunkSize") - if chunk_size == 0 and self.deadline_chunk_size: - chunk_size = self.deadline_chunk_size + if chunk_size == 0 and self.chunk_size: + chunk_size = self.chunk_size priority = instance.data.get("deadlinePriority") if not priority: - priority = self.deadline_priority + priority = self.priority payload = { "JobInfo": { @@ -165,11 +165,11 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin): "Priority": priority, "ChunkSize": chunk_size, - "Department": self.deadline_department, + "Department": self.department, - "Pool": self.deadline_pool, - "SecondaryPool": self.deadline_pool_secondary, - "Group": self.deadline_group, + "Pool": self.primary_pool, + "SecondaryPool": self.secondary_pool, + "Group": self.group, "Plugin": "Nuke", "Frames": "{start}-{end}".format( diff --git a/pype/modules/ftrack/events/event_sync_to_avalon.py b/pype/modules/ftrack/events/event_sync_to_avalon.py index daab3425f3..527f3996e1 100644 --- a/pype/modules/ftrack/events/event_sync_to_avalon.py +++ b/pype/modules/ftrack/events/event_sync_to_avalon.py @@ -1677,15 +1677,15 @@ class SyncToAvalonEvent(BaseEvent): self.updates[mongo_id]["data"] = {} vis_par_id = None + ent_path_items = [self.cur_project["full_name"]] if par_av_ent["type"].lower() != "project": vis_par_id = par_av_ent["_id"] + ent_path_items.extend(par_av_ent["data"]["parents"]) + ent_path_items.append(par_av_ent["name"]) + self.updates[mongo_id]["data"]["visualParent"] = vis_par_id self.moved_in_avalon.append(mongo_id) - # TODO logging - ent_path_items = [self.cur_project["full_name"]] - ent_path_items.extend(par_av_ent["data"]["parents"]) - ent_path_items.append(par_av_ent["name"]) ent_path_items.append(avalon_ent["name"]) ent_path = "/".join(ent_path_items) self.log.debug(( diff --git a/pype/modules/settings_action.py b/pype/modules/settings_action.py index c1fa8a68bc..aab10e9ebf 100644 --- a/pype/modules/settings_action.py +++ b/pype/modules/settings_action.py @@ -58,3 +58,58 @@ class SettingsAction(PypeModule, ITrayAction): # Reset content if was not visible if not was_visible: self.settings_window.reset() + + +class LocalSettingsAction(PypeModule, ITrayAction): + """Action to show Setttings tool.""" + name = "local_settings" + label = "Local Settings" + + def initialize(self, _modules_settings): + # This action is always enabled + self.enabled = True + + # Tray attributes + self.settings_window = None + + def connect_with_modules(self, *_a, **_kw): + return + + def tray_init(self): + """Initialization in tray implementation of ITrayAction.""" + self.create_settings_window() + + def on_action_trigger(self): + """Implementation for action trigger of ITrayAction.""" + self.show_settings_window() + + def create_settings_window(self): + """Initializa Settings Qt window.""" + if self.settings_window: + return + from pype.tools.settings import LocalSettingsWindow + self.settings_window = LocalSettingsWindow() + + def show_settings_window(self): + """Show settings tool window. + + Raises: + AssertionError: Window must be already created. Call + `create_settings_window` before callint this method. + """ + if not self.settings_window: + raise AssertionError("Window is not initialized.") + + # Store if was visible + was_visible = self.settings_window.isVisible() + + # Show settings gui + self.settings_window.show() + + # Pull window to the front. + self.settings_window.raise_() + self.settings_window.activateWindow() + + # Reset content if was not visible + if not was_visible: + self.settings_window.reset() diff --git a/pype/plugins/publish/collect_anatomy_instance_data.py b/pype/plugins/publish/collect_anatomy_instance_data.py index 446f671b86..99fbe8a52e 100644 --- a/pype/plugins/publish/collect_anatomy_instance_data.py +++ b/pype/plugins/publish/collect_anatomy_instance_data.py @@ -123,8 +123,7 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): self.log.debug("Qeurying latest versions for instances.") hierarchy = {} - subset_names = set() - asset_ids = set() + subset_filters = [] for instance in context: # Make sure `"latestVersion"` key is set latest_version = instance.data.get("latestVersion") @@ -138,8 +137,6 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): # Store asset ids and subset names for queries asset_id = asset_doc["_id"] subset_name = instance.data["subset"] - asset_ids.add(asset_id) - subset_names.add(subset_name) # Prepare instance hiearchy for faster filling latest versions if asset_id not in hierarchy: @@ -147,11 +144,14 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): if subset_name not in hierarchy[asset_id]: hierarchy[asset_id][subset_name] = [] hierarchy[asset_id][subset_name].append(instance) + subset_filters.append({ + "parent": asset_id, + "name": subset_name + }) subset_docs = list(io.find({ "type": "subset", - "parent": {"$in": list(asset_ids)}, - "name": {"$in": list(subset_names)} + "$or": subset_filters })) subset_ids = [ diff --git a/pype/plugins/publish/repair_unicode_strings.py b/pype/plugins/publish/repair_unicode_strings.py new file mode 100644 index 0000000000..fdd4bb7d03 --- /dev/null +++ b/pype/plugins/publish/repair_unicode_strings.py @@ -0,0 +1,15 @@ +import os +import pyblish.api + + +class RepairUnicodeStrings(pyblish.api.Collector): + """Validate all environment variables are string type. + + """ + + order = pyblish.api.CollectorOrder + label = 'Unicode Strings' + + def process(self, context): + for key, value in os.environ.items(): + os.environ[str(key)] = str(value) diff --git a/pype/pype_commands.py b/pype/pype_commands.py index 41824d0f7f..a07c3a7083 100644 --- a/pype/pype_commands.py +++ b/pype/pype_commands.py @@ -2,6 +2,7 @@ """Implementation of Pype commands.""" import os import sys +import json from pathlib import Path from pype.lib import PypeLogger @@ -85,6 +86,21 @@ class PypeCommands: log.info("Publish finished.") uninstall() + def extractenvironments(output_json_path, project, asset, task, app): + env = os.environ.copy() + if all((project, asset, task, app)): + from pype.api import get_app_environments_for_context + env = get_app_environments_for_context( + project, asset, task, app, env + ) + + output_dir = os.path.dirname(output_json_path) + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + with open(output_json_path, "w") as file_stream: + json.dump(env, file_stream, indent=4) + def texture_copy(self, project, asset, path): pass diff --git a/pype/settings/constants.py b/pype/settings/constants.py index c68826f45b..ce19ad3f93 100644 --- a/pype/settings/constants.py +++ b/pype/settings/constants.py @@ -15,7 +15,9 @@ METADATA_KEYS = ( SYSTEM_SETTINGS_KEY = "system_settings" PROJECT_SETTINGS_KEY = "project_settings" PROJECT_ANATOMY_KEY = "project_anatomy" +LOCAL_SETTING_KEY = "local_settings" +DEFAULT_PROJECT_KEY = "__default_project__" __all__ = ( "M_OVERRIDEN_KEY", @@ -26,5 +28,6 @@ __all__ = ( "SYSTEM_SETTINGS_KEY", "PROJECT_SETTINGS_KEY", - "PROJECT_ANATOMY_KEY" + "PROJECT_ANATOMY_KEY", + "LOCAL_SETTING_KEY" ) diff --git a/pype/settings/defaults/project_settings/deadline.json b/pype/settings/defaults/project_settings/deadline.json new file mode 100644 index 0000000000..6844979ddb --- /dev/null +++ b/pype/settings/defaults/project_settings/deadline.json @@ -0,0 +1,44 @@ +{ + "publish": { + "MayaSubmitDeadline": { + "enabled": true, + "optional": false, + "tile_assembler_plugin": "oiio", + "use_published": true, + "asset_dependencies": true + }, + "NukeSubmitDeadline": { + "enabled": true, + "optional": false, + "use_published": true, + "priority": 50, + "Chunk Size": 10, + "primary_pool": "", + "secondary_pool": "", + "group": "", + "department": "" + }, + "HarmonySubmitDeadline": { + "enabled": true, + "optional": false, + "use_published": true, + "priority": 50, + "Chunk Size": 10000, + "primary_pool": "", + "secondary_pool": "", + "group": "", + "department": "" + }, + "AfterEffectsSubmitDeadline": { + "enabled": true, + "optional": false, + "use_published": true, + "priority": 50, + "Chunk Size": 10000, + "primary_pool": "", + "secondary_pool": "", + "group": "", + "department": "" + } + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/harmony.json b/pype/settings/defaults/project_settings/harmony.json index 83d63d3392..e1de4485a4 100644 --- a/pype/settings/defaults/project_settings/harmony.json +++ b/pype/settings/defaults/project_settings/harmony.json @@ -1,7 +1,20 @@ { - "publish": {}, "general": { "skip_resolution_check": [], "skip_timelines_check": [] + }, + "publish": { + "CollectPalettes": { + "allowed_tasks": [ + "." + ] + }, + "HarmonySubmitDeadline": { + "use_published": false, + "priority": 50, + "primary_pool": "", + "secondary_pool": "", + "chunk_size": 0 + } } } \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/maya.json b/pype/settings/defaults/project_settings/maya.json index 2307fd8b82..03955732d2 100644 --- a/pype/settings/defaults/project_settings/maya.json +++ b/pype/settings/defaults/project_settings/maya.json @@ -107,37 +107,249 @@ "overscan": 1.0 } }, - "ext_mapping": {}, + "create": { + "CreateAnimation": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateAss": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateAssembly": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateCamera": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateLayout": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateLook": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateMayaScene": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateModel": { + "enabled": true, + "defaults": [ + "Main", + "Proxy", + "Sculpt" + ] + }, + "CreatePointCache": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateRender": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateRenderSetup": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateReview": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateRig": { + "enabled": true, + "defaults": [ + "Main", + "Sim", + "Cloth" + ] + }, + "CreateSetDress": { + "enabled": true, + "defaults": [ + "Main", + "Anim" + ] + }, + "CreateUnrealStaticMesh": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateVrayProxy": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateVRayScene": { + "enabled": true, + "defaults": [ + "Main" + ] + }, + "CreateYetiRig": { + "enabled": true, + "defaults": [ + "Main" + ] + } + }, "publish": { "CollectMayaRender": { "sync_workfile_version": false }, - "ValidateCameraAttributes": { + "ValidateShaderName": { "enabled": false, - "optional": true + "regex": "(?P.*)_(.*)_SHD" + }, + "ValidateAttributes": { + "enabled": false, + "attributes": {} }, "ValidateModelName": { - "enabled": true, + "enabled": false, "material_file": { "windows": "", "darwin": "", "linux": "" }, - "regex": "" + "regex": "(.*)_(\\\\d)*_(.*)_(GEO)" }, - "ValidateAssemblyName": { - "enabled": true - }, - "ValidateShaderName": { + "ValidateTransformNamingSuffix": { "enabled": true, - "regex": "" + "SUFFIX_NAMING_TABLE": { + "mesh": [ + "_GEO", + "_GES", + "_GEP", + "_OSD" + ], + "nurbsCurve": [ + "_CRV" + ], + "nurbsSurface": [ + "_NRB" + ], + "locator": [ + "_LOC" + ], + "group": [ + "_GRP" + ] + }, + "ALLOW_IF_NOT_IN_SUFFIX_TABLE": true + }, + "ValidateColorSets": { + "enabled": false, + "optional": true }, "ValidateMeshHasOverlappingUVs": { - "enabled": false - }, - "ValidateAttributes": { "enabled": false, - "attributes": {} + "optional": true + }, + "ValidateMeshArnoldAttributes": { + "enabled": false, + "optional": true + }, + "ValidateMeshShaderConnections": { + "enabled": true, + "optional": true + }, + "ValidateMeshSingleUVSet": { + "enabled": false, + "optional": true + }, + "ValidateMeshHasUVs": { + "enabled": true, + "optional": true + }, + "ValidateMeshLaminaFaces": { + "enabled": false, + "optional": true + }, + "ValidateMeshNonManifold": { + "enabled": false, + "optional": true + }, + "ValidateMeshUVSetMap1": { + "enabled": false, + "optional": true + }, + "ValidateMeshVerticesHaveEdges": { + "enabled": true, + "optional": true + }, + "ValidateNoAnimation": { + "enabled": false, + "optional": true + }, + "ValidateNoNamespace": { + "enabled": true, + "optional": true + }, + "ValidateNoNullTransforms": { + "enabled": true, + "optional": true + }, + "ValidateNoUnknownNodes": { + "enabled": true, + "optional": true + }, + "ValidateNodeNoGhosting": { + "enabled": false, + "optional": true + }, + "ValidateShapeDefaultNames": { + "enabled": false, + "optional": true + }, + "ValidateShapeRenderStats": { + "enabled": false, + "optional": true + }, + "ValidateTransformZero": { + "enabled": true, + "optional": true + }, + "ValidateCameraAttributes": { + "enabled": false, + "optional": true + }, + "ValidateAssemblyName": { + "enabled": true, + "optional": true + }, + "ValidateAssRelativePaths": { + "enabled": true, + "optional": true }, "ExtractCameraAlembic": { "enabled": true, @@ -221,6 +433,39 @@ 0.8, 0.5 ] + }, + "ReferenceLoader": { + "enabled": true, + "representations": [ + "ma", + "mb", + "abc", + "fbx" + ] + }, + "AudioLoader": { + "enabled": true, + "representations": [ + "wav" + ] + }, + "GpuCacheLoader": { + "enabled": true, + "representations": [ + "abc" + ] + }, + "ImagePlaneLoader": { + "enabled": true, + "representations": [ + "jpg", + "png", + "mov" + ] + }, + "MatchmoveLoader": { + "enabled": true, + "representations": [] } }, "workfile_build": { diff --git a/pype/settings/defaults/project_settings/nuke.json b/pype/settings/defaults/project_settings/nuke.json index 94cd712639..517065f79a 100644 --- a/pype/settings/defaults/project_settings/nuke.json +++ b/pype/settings/defaults/project_settings/nuke.json @@ -61,6 +61,22 @@ "deadline_pool": "", "deadline_pool_secondary": "", "deadline_chunk_size": 1 + }, + "ValidateOutputResolution": { + "enabled": true, + "optional": true + }, + "ValidateGizmo": { + "enabled": true, + "optional": true + }, + "ValidateScript": { + "enabled": true, + "optional": true + }, + "ValidateNukeWriteBoundingBox": { + "enabled": true, + "optional": true } }, "workfile_build": { diff --git a/pype/settings/entities/base_entity.py b/pype/settings/entities/base_entity.py index b2be6819d5..9003a66d76 100644 --- a/pype/settings/entities/base_entity.py +++ b/pype/settings/entities/base_entity.py @@ -695,6 +695,12 @@ class ItemEntity(BaseItemEntity): is_dynamic_item (bool): Entity should behave like dynamically created entity. """ + _default_label_wrap = { + "use_label_wrap": False, + "collapsible": True, + "collapsed": False + } + def __init__(self, schema_data, parent, is_dynamic_item=False): super(ItemEntity, self).__init__(schema_data) @@ -736,12 +742,50 @@ class ItemEntity(BaseItemEntity): self.key = self.schema_data.get("key") self.label = self.schema_data.get("label") + # GUI attributes + _default_label_wrap = self.__class__._default_label_wrap + for key, value in ItemEntity._default_label_wrap.items(): + if key not in _default_label_wrap: + self.log.warning( + "Class {} miss default label wrap key \"{}\"".format( + self.__class__.__name__, key + ) + ) + _default_label_wrap[key] = value + + use_label_wrap = self.schema_data.get("use_label_wrap") + if use_label_wrap is None: + if not self.label: + use_label_wrap = False + else: + use_label_wrap = _default_label_wrap["use_label_wrap"] + self.use_label_wrap = use_label_wrap + + # Used only if `use_label_wrap` is set to True + self.collapsible = self.schema_data.get( + "collapsible", + _default_label_wrap["collapsible"] + ) + self.collapsed = self.schema_data.get( + "collapsed", + _default_label_wrap["collapsed"] + ) + self._item_initalization() def save(self): """Call save on root item.""" self.root_item.save() + def schema_validations(self): + if not self.label and self.use_label_wrap: + raise ValueError(( + "{} Entity has set `use_label_wrap` to true but" + " does not have set `label`." + ).format(self.path)) + + super(ItemEntity, self).schema_validations() + def create_schema_object(self, *args, **kwargs): """Reference method for creation of entities defined in RootEntity.""" return self.root_item.create_schema_object(*args, **kwargs) diff --git a/pype/settings/entities/dict_immutable_keys_entity.py b/pype/settings/entities/dict_immutable_keys_entity.py index 854c904f3c..af0ddcb758 100644 --- a/pype/settings/entities/dict_immutable_keys_entity.py +++ b/pype/settings/entities/dict_immutable_keys_entity.py @@ -27,6 +27,11 @@ class DictImmutableKeysEntity(ItemEntity): are not real settings values but entities representing the value. """ schema_types = ["dict"] + _default_label_wrap = { + "use_label_wrap": True, + "collapsible": True, + "collapsed": True + } def __getitem__(self, key): """Return entity inder key.""" @@ -130,7 +135,7 @@ class DictImmutableKeysEntity(ItemEntity): continue if child_obj.key in self.non_gui_children: - raise SchemaDuplicatedKeys(self.path, child_obj.key) + raise SchemaDuplicatedKeys("", child_obj.key) self.non_gui_children[child_obj.key] = child_obj if not first: @@ -169,11 +174,6 @@ class DictImmutableKeysEntity(ItemEntity): "highlight_content", False ) self.show_borders = self.schema_data.get("show_borders", True) - self.collapsible = self.schema_data.get("collapsible", True) - self.collapsed = self.schema_data.get("collapsed", True) - - # Not yet implemented - self.use_label_wrap = self.schema_data.get("use_label_wrap") or True def get_child_path(self, child_obj): """Get hierarchical path of child entity. diff --git a/pype/settings/entities/dict_mutable_keys_entity.py b/pype/settings/entities/dict_mutable_keys_entity.py index 8fe71db2a3..2fd2b87311 100644 --- a/pype/settings/entities/dict_mutable_keys_entity.py +++ b/pype/settings/entities/dict_mutable_keys_entity.py @@ -29,6 +29,12 @@ class DictMutableKeysEntity(EndpointEntity): - clear callbacks """ schema_types = ["dict-modifiable"] + _default_label_wrap = { + "use_label_wrap": True, + "collapsible": True, + "collapsed": True + } + _miss_arg = object() def __getitem__(self, key): @@ -174,8 +180,6 @@ class DictMutableKeysEntity(EndpointEntity): self.hightlight_content = ( self.schema_data.get("highlight_content") or False ) - self.collapsible = self.schema_data.get("collapsible", True) - self.collapsed = self.schema_data.get("collapsed", True) object_type = self.schema_data["object_type"] if not isinstance(object_type, dict): diff --git a/pype/settings/entities/list_entity.py b/pype/settings/entities/list_entity.py index 07221929b7..752347489a 100644 --- a/pype/settings/entities/list_entity.py +++ b/pype/settings/entities/list_entity.py @@ -15,6 +15,11 @@ from .exceptions import ( class ListEntity(EndpointEntity): schema_types = ["list"] + _default_label_wrap = { + "use_label_wrap": False, + "collapsible": True, + "collapsed": False + } def __iter__(self): for item in self.children: @@ -139,12 +144,6 @@ class ListEntity(EndpointEntity): # Value that was set on set_override_state self.initial_value = [] - # GUI attributes - self.use_label_wrap = self.schema_data.get("use_label_wrap") or False - # Used only if `use_label_wrap` is set to True - self.collapsible = self.schema_data.get("collapsible") or True - self.collapsed = self.schema_data.get("collapsed") or False - def schema_validations(self): super(ListEntity, self).schema_validations() diff --git a/pype/settings/entities/schemas/projects_schema/schema_main.json b/pype/settings/entities/schemas/projects_schema/schema_main.json index 8ad059f1c7..31d7373873 100644 --- a/pype/settings/entities/schemas/projects_schema/schema_main.json +++ b/pype/settings/entities/schemas/projects_schema/schema_main.json @@ -45,6 +45,10 @@ "type": "schema", "name": "schema_project_ftrack" }, + { + "type": "schema", + "name": "schema_project_deadline" + }, { "type": "schema", "name": "schema_project_maya" diff --git a/pype/settings/entities/schemas/projects_schema/schema_plugins.json b/pype/settings/entities/schemas/projects_schema/schema_plugins.json deleted file mode 100644 index a7ed64be17..0000000000 --- a/pype/settings/entities/schemas/projects_schema/schema_plugins.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "type": "dict", - "collapsible": true, - "key": "plugins", - "label": "Plugins", - "children": [ - { - "type": "dict", - "collapsible": true, - "key": "standalonepublisher", - "label": "Standalone Publisher", - "children": [ - { - "type": "dict", - "collapsible": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsible": true, - "key": "ExtractThumbnailSP", - "label": "ExtractThumbnailSP", - "is_group": true, - "children": [ - { - "type": "dict", - "collapsible": false, - "key": "ffmpeg_args", - "label": "ffmpeg_args", - "children": [ - { - "type": "list", - "object_type": "text", - "key": "input", - "label": "input" - }, - { - "type": "list", - "object_type": "text", - "key": "output", - "label": "output" - } - ] - } - ] - } - ] - } - ] - } - ] -} diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_deadline.json b/pype/settings/entities/schemas/projects_schema/schema_project_deadline.json new file mode 100644 index 0000000000..ea76f4e62e --- /dev/null +++ b/pype/settings/entities/schemas/projects_schema/schema_project_deadline.json @@ -0,0 +1,223 @@ +{ + "type": "dict", + "key": "deadline", + "label": "Deadline", + "collapsible": true, + "is_file": true, + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "MayaSubmitDeadline", + "label": "Submit maya job to deadline", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "enum", + "key": "tile_assembler_plugin", + "label": "Tile Assembler Plugin", + "multiselection": false, + "enum_items": [ + { + "DraftTileAssembler": "Draft Tile Assembler" + }, + { + "oiio": "Open Image IO" + } + ] + }, + { + "type": "boolean", + "key": "use_published", + "label": "Use Published scene" + }, + { + "type": "boolean", + "key": "asset_dependencies", + "label": "Use Asset dependencies" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "NukeSubmitDeadline", + "label": "Nuke Submit to Deadline", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "use_published", + "label": "Use Published scene" + }, + { + "type": "number", + "key": "priority", + "label": "Priority" + }, + { + "type": "number", + "key": "Chunk Size", + "label": "Chunk Size" + }, + { + "type": "text", + "key": "primary_pool", + "label": "Primary Pool" + }, + { + "type": "text", + "key": "secondary_pool", + "label": "Secondary Pool" + }, + { + "type": "text", + "key": "group", + "label": "Group" + }, + { + "type": "text", + "key": "department", + "label": "Department" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "HarmonySubmitDeadline", + "label": "Harmony Submit to Deadline", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "use_published", + "label": "Use Published scene" + }, + { + "type": "number", + "key": "priority", + "label": "Priority" + }, + { + "type": "number", + "key": "Chunk Size", + "label": "Chunk Size" + }, + { + "type": "text", + "key": "primary_pool", + "label": "Primary Pool" + }, + { + "type": "text", + "key": "secondary_pool", + "label": "Secondary Pool" + }, + { + "type": "text", + "key": "group", + "label": "Group" + }, + { + "type": "text", + "key": "department", + "label": "Department" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "AfterEffectsSubmitDeadline", + "label": "After Effects Submit to Deadline", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "boolean", + "key": "use_published", + "label": "Use Published scene" + }, + { + "type": "number", + "key": "priority", + "label": "Priority" + }, + { + "type": "number", + "key": "Chunk Size", + "label": "Chunk Size" + }, + { + "type": "text", + "key": "primary_pool", + "label": "Primary Pool" + }, + { + "type": "text", + "key": "secondary_pool", + "label": "Secondary Pool" + }, + { + "type": "text", + "key": "group", + "label": "Group" + }, + { + "type": "text", + "key": "department", + "label": "Department" + } + ] + } + ] + } + ] +} diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_global.json b/pype/settings/entities/schemas/projects_schema/schema_project_global.json index fa5db9af88..1733e04f67 100644 --- a/pype/settings/entities/schemas/projects_schema/schema_project_global.json +++ b/pype/settings/entities/schemas/projects_schema/schema_project_global.json @@ -16,7 +16,8 @@ { "type": "raw-json", "label": "Project Folder Structure", - "key": "project_folder_structure" + "key": "project_folder_structure", + "use_label_wrap": true }, { "type": "schema", diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_harmony.json b/pype/settings/entities/schemas/projects_schema/schema_project_harmony.json index 5d1cbff1b8..c4cdccff42 100644 --- a/pype/settings/entities/schemas/projects_schema/schema_project_harmony.json +++ b/pype/settings/entities/schemas/projects_schema/schema_project_harmony.json @@ -5,13 +5,6 @@ "label": "Harmony", "is_file": true, "children": [ - { - "type": "dict", - "collapsible": true, - "key": "publish", - "label": "Publish plugins", - "children": [] - }, { "type": "dict", "collapsible": true, @@ -31,6 +24,61 @@ "label": "Skip Timeliene Check for Tasks" } ] + }, + { + "type": "dict", + "collapsible": true, + "key": "publish", + "label": "Publish plugins", + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "CollectPalettes", + "label": "Collect Palettes", + "children": [ + { + "type": "list", + "key": "allowed_tasks", + "label": "Allowed tasks", + "object_type": "text" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "HarmonySubmitDeadline", + "label": "Harmony Submit to Deadline", + "children": [ + { + "type": "boolean", + "key": "use_published", + "label": "Use Published scene" + }, + { + "type": "number", + "key": "priority", + "label": "priority" + }, + { + "type": "text", + "key": "primary_pool", + "label": "Primary Pool" + }, + { + "type": "text", + "key": "secondary_pool", + "label": "Secondary Pool" + }, + { + "type": "number", + "key": "chunk_size", + "label": "Chunk Size" + } + ] + } + ] } ] } diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_maya.json b/pype/settings/entities/schemas/projects_schema/schema_project_maya.json index 5ba5de1557..7a270b0046 100644 --- a/pype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/pype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -9,6 +9,10 @@ "type": "schema", "name": "schema_maya_capture" }, + { + "type": "schema", + "name": "schema_maya_create" + }, { "type": "schema", "name": "schema_maya_publish" diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/pype/settings/entities/schemas/projects_schema/schema_project_nuke.json index b60b548cb0..0548bd3544 100644 --- a/pype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/pype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -9,7 +9,7 @@ "type": "dict", "collapsible": true, "key": "create", - "label": "Create plugins", + "label": "Creator plugins", "children": [ { "type": "dict", @@ -42,144 +42,9 @@ ] }, { - "type": "dict", - "collapsible": true, - "key": "publish", - "label": "Publish plugins", - "children": [ - { - "type": "dict", - "collapsible": true, - "key": "PreCollectNukeInstances", - "label": "PreCollectNukeInstances", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "sync_workfile_version", - "label": "Sync Version from workfile" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "checkbox_key": "enabled", - "key": "ExtractThumbnail", - "label": "ExtractThumbnail", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "raw-json", - "key": "nodes", - "label": "Nodes" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "checkbox_key": "enabled", - "key": "ValidateKnobs", - "label": "ValidateKnobs", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "raw-json", - "key": "knobs", - "label": "Knobs" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "checkbox_key": "enabled", - "key": "ExtractReviewDataLut", - "label": "ExtractReviewDataLut", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "checkbox_key": "enabled", - "key": "ExtractReviewDataMov", - "label": "ExtractReviewDataMov", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "boolean", - "key": "viewer_lut_raw", - "label": "Viewer LUT raw" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "key": "ExtractSlateFrame", - "label": "ExtractSlateFrame", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "viewer_lut_raw", - "label": "Viewer LUT raw" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "key": "NukeSubmitDeadline", - "label": "NukeSubmitDeadline", - "is_group": true, - "children": [ - { - "type": "number", - "key": "deadline_priority", - "label": "deadline_priority" - }, - { - "type": "text", - "key": "deadline_pool", - "label": "deadline_pool" - }, - { - "type": "text", - "key": "deadline_pool_secondary", - "label": "deadline_pool_secondary" - }, - { - "type": "number", - "key": "deadline_chunk_size", - "label": "deadline_chunk_size" - } - ] - } - ] + "type": "schema", + "name": "schema_nuke_publish", + "template_data": [] }, { "type": "schema", diff --git a/pype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json b/pype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json index 735b9611d2..47eea3441c 100644 --- a/pype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json +++ b/pype/settings/entities/schemas/projects_schema/schema_project_standalonepublisher.json @@ -5,44 +5,6 @@ "label": "Standalone Publisher", "is_file": true, "children": [ - { - "type": "dict", - "collapsible": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsible": true, - "key": "ExtractThumbnailSP", - "label": "ExtractThumbnailSP", - "is_group": true, - "children": [ - { - "type": "dict", - "collapsible": false, - "key": "ffmpeg_args", - "label": "ffmpeg_args", - "children": [ - { - "type": "list", - "object_type": "text", - "key": "input", - "label": "input" - }, - { - "type": "list", - "object_type": "text", - "key": "output", - "label": "output" - } - ] - } - ] - } - ] - }, { "type": "dict-modifiable", "collapsible": true, @@ -88,6 +50,44 @@ } ] } + }, + { + "type": "dict", + "collapsible": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "ExtractThumbnailSP", + "label": "ExtractThumbnailSP", + "is_group": true, + "children": [ + { + "type": "dict", + "collapsible": false, + "key": "ffmpeg_args", + "label": "ffmpeg_args", + "children": [ + { + "type": "list", + "object_type": "text", + "key": "input", + "label": "input" + }, + { + "type": "list", + "object_type": "text", + "key": "output", + "label": "output" + } + ] + } + ] + } + ] } ] } diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json index 648fca28e6..4745a19075 100644 --- a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json +++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_capture.json @@ -1,595 +1,581 @@ { - "type": "collapsible-wrap", - "label": "Collapsible Wrapper without key", + "type": "dict", + "collapsible": true, + "key": "capture", + "label": "Maya Playblast settings", + "is_file": true, "children": [ { "type": "dict", - "collapsible": true, - "key": "capture", - "label": "Maya Playblast settings", - "is_file": true, + "key": "Codec", "children": [ { - "type": "dict", - "key": "Codec", - "children": [ - { - "type": "label", - "label": "Codec" - }, - { - "type": "text", - "key": "compression", - "label": "Compression type" - }, - { - "type": "text", - "key": "format", - "label": "Data format" - }, - { - "type": "number", - "key": "quality", - "label": "Quality", - "decimal": 0, - "minimum": 0, - "maximum": 100 - }, + "type": "label", + "label": "Codec" + }, + { + "type": "text", + "key": "compression", + "label": "Compression type" + }, + { + "type": "text", + "key": "format", + "label": "Data format" + }, + { + "type": "number", + "key": "quality", + "label": "Quality", + "decimal": 0, + "minimum": 0, + "maximum": 100 + }, - { - "type": "splitter" - } - ] - }, - { - "type": "dict", - "key": "Display Options", - "children": [ - { - "type": "label", - "label": "Display Options" - }, - { - "type": "list-strict", - "key": "background", - "label": "Background Color: ", - "object_types": [ - { - "label": "Red", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - }, - { - "label": "Green", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - }, - { - "label": "Blue", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - } - ] - }, - { - "type": "list-strict", - "key": "backgroundBottom", - "label": "Background Bottom: ", - "object_types": [ - { - "label": "Red", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - }, - { - "label": "Green", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - }, - { - "label": "Blue", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - } - ] - }, - { - "type": "list-strict", - "key": "backgroundTop", - "label": "Background Top: ", - "object_types": [ - { - "label": "Red", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - }, - { - "label": "Green", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - }, - { - "label": "Blue", - "type": "number", - "minimum": 0, - "maximum": 1, - "decimal": 3 - } - ] - }, - { - "type": "boolean", - "key": "override_display", - "label": "Override display options" - } - ] - }, { "type": "splitter" - }, - { - "type": "dict", - "key": "Generic", - "children": [ - { - "type": "label", - "label": "Generic" - }, - { - "type": "boolean", - "key": "isolate_view", - "label": " Isolate view" - }, - { - "type": "boolean", - "key": "off_screen", - "label": " Off Screen" - } - ] - }, - { - "type": "dict", - "key": "IO", - "children": [ - { - "type": "label", - "label": "IO" - }, - { - "type": "text", - "key": "name", - "label": "Name" - }, - { - "type": "boolean", - "key": "open_finished", - "label": "Open finished" - }, - { - "type": "boolean", - "key": "raw_frame_numbers", - "label": "Raw frame numbers" - }, - { - "type": "list", - "key": "recent_playblasts", - "label": "Recent Playblasts", - "object_type": "text" - }, - { - "type": "boolean", - "key": "save_file", - "label": "Save file" - } - ] - }, - { - "type": "dict", - "key": "PanZoom", - "children": [ - { - "type": "boolean", - "key": "pan_zoom", - "label": " Pan Zoom" - } - ] - }, - { - "type": "splitter" - }, - { - "type": "dict", - "key": "Renderer", - "children": [ - { - "type": "label", - "label": "Renderer" - }, - { - "type": "text", - "key": "rendererName", - "label": " Renderer name" - } - ] - }, - { - "type": "dict", - "key": "Resolution", - "children": [ - { - "type": "splitter" - }, - { - "type": "label", - "label": "Resolution" - }, - { - "type": "number", - "key": "width", - "label": " Width", - "decimal": 0, - "minimum": 0, - "maximum": 99999 - }, - { - "type": "number", - "key": "height", - "label": "Height", - "decimal": 0, - "minimum": 0, - "maximum": 99999 - }, - { - "type": "number", - "key": "percent", - "label": "percent", - "decimal": 1, - "minimum": 0, - "maximum": 200 - }, - { - "type": "text", - "key": "mode", - "label": "Mode" - } - ] - }, - { - "type": "splitter" - }, - { - "type": "dict", - "key": "Time Range", - "children": [ - { - "type": "label", - "label": "Time Range" - }, - { - "type": "number", - "key": "start_frame", - "label": " Start frame", - "decimal": 0, - "minimum": 0, - "maximum": 999999 - }, - { - "type": "number", - "key": "end_frame", - "label": "End frame", - "decimal": 0, - "minimum": 0, - "maximum": 999999 - }, - { - "type": "text", - "key": "frame", - "label": "Frame" - }, - { - "type": "text", - "key": "time", - "label": "Time" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "key": "Viewport Options", - "label": "Viewport Options", - "children": [ - { - "type": "boolean", - "key": "cameras", - "label": "cameras" - }, - { - "type": "boolean", - "key": "clipGhosts", - "label": "clipGhosts" - }, - { - "type": "boolean", - "key": "controlVertices", - "label": "controlVertices" - }, - { - "type": "boolean", - "key": "deformers", - "label": "deformers" - }, - { - "type": "boolean", - "key": "dimensions", - "label": "dimensions" - }, - { - "type": "number", - "key": "displayLights", - "label": "displayLights", - "decimal": 0, - "minimum": 0, - "maximum": 10 - }, - { - "type": "boolean", - "key": "dynamicConstraints", - "label": "dynamicConstraints" - }, - { - "type": "boolean", - "key": "dynamics", - "label": "dynamics" - }, - { - "type": "boolean", - "key": "fluids", - "label": "fluids" - }, - { - "type": "boolean", - "key": "follicles", - "label": "follicles" - }, - { - "type": "boolean", - "key": "gpuCacheDisplayFilter", - "label": "gpuCacheDisplayFilter" - }, - { - "type": "boolean", - "key": "greasePencils", - "label": "greasePencils" - }, - { - "type": "boolean", - "key": "grid", - "label": "grid" - }, - { - "type": "boolean", - "key": "hairSystems", - "label": "hairSystems" - }, - { - "type": "boolean", - "key": "handles", - "label": "handles" - }, - { - "type": "boolean", - "key": "high_quality", - "label": "high_quality" - }, - { - "type": "boolean", - "key": "hud", - "label": "hud" - }, - { - "type": "boolean", - "key": "hulls", - "label": "hulls" - }, - { - "type": "boolean", - "key": "ikHandles", - "label": "ikHandles" - }, - { - "type": "boolean", - "key": "imagePlane", - "label": "imagePlane" - }, - { - "type": "boolean", - "key": "joints", - "label": "joints" - }, - { - "type": "boolean", - "key": "lights", - "label": "lights" - }, - { - "type": "boolean", - "key": "locators", - "label": "locators" - }, - { - "type": "boolean", - "key": "manipulators", - "label": "manipulators" - }, - { - "type": "boolean", - "key": "motionTrails", - "label": "motionTrails" - }, - { - "type": "boolean", - "key": "nCloths", - "label": "nCloths" - }, - { - "type": "boolean", - "key": "nParticles", - "label": "nParticles" - }, - { - "type": "boolean", - "key": "nRigids", - "label": "nRigids" - }, - { - "type": "boolean", - "key": "nurbsCurves", - "label": "nurbsCurves" - }, - { - "type": "boolean", - "key": "nurbsSurfaces", - "label": "nurbsSurfaces" - }, - { - "type": "boolean", - "key": "override_viewport_options", - "label": "override_viewport_options" - }, - { - "type": "boolean", - "key": "particleInstancers", - "label": "particleInstancers" - }, - { - "type": "boolean", - "key": "pivots", - "label": "pivots" - }, - { - "type": "boolean", - "key": "planes", - "label": "planes" - }, - { - "type": "boolean", - "key": "pluginShapes", - "label": "pluginShapes" - }, - { - "type": "boolean", - "key": "polymeshes", - "label": "polymeshes" - }, - { - "type": "boolean", - "key": "shadows", - "label": "shadows" - }, - { - "type": "boolean", - "key": "strokes", - "label": "strokes" - }, - { - "type": "boolean", - "key": "subdivSurfaces", - "label": "subdivSurfaces" - }, - { - "type": "boolean", - "key": "textures", - "label": "textures" - }, - { - "type": "boolean", - "key": "twoSidedLighting", - "label": "twoSidedLighting" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "key": "Camera Options", - "label": "Camera Options", - "children": [ - { - "type": "boolean", - "key": "displayGateMask", - "label": "displayGateMask" - }, - { - "type": "boolean", - "key": "displayResolution", - "label": "displayResolution" - }, - { - "type": "boolean", - "key": "displayFilmGate", - "label": "displayFilmGate" - }, - { - "type": "boolean", - "key": "displayFieldChart", - "label": "displayFieldChart" - }, - { - "type": "boolean", - "key": "displaySafeAction", - "label": "displaySafeAction" - }, - { - "type": "boolean", - "key": "displaySafeTitle", - "label": "displaySafeTitle" - }, - { - "type": "boolean", - "key": "displayFilmPivot", - "label": "displayFilmPivot" - }, - { - "type": "boolean", - "key": "displayFilmOrigin", - "label": "displayFilmOrigin" - }, - { - "type": "number", - "key": "overscan", - "label": "overscan", - "decimal": 1, - "minimum": 0, - "maximum": 10 - } - ] } ] }, { - "type": "dict-modifiable", - "key": "ext_mapping", - "label": "Extension Mapping", - "object_type": { - "type": "text" - } + "type": "dict", + "key": "Display Options", + "children": [ + { + "type": "label", + "label": "Display Options" + }, + { + "type": "list-strict", + "key": "background", + "label": "Background Color: ", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, + { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, + { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + } + ] + }, + { + "type": "list-strict", + "key": "backgroundBottom", + "label": "Background Bottom: ", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, + { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, + { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + } + ] + }, + { + "type": "list-strict", + "key": "backgroundTop", + "label": "Background Top: ", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, + { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, + { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + } + ] + }, + { + "type": "boolean", + "key": "override_display", + "label": "Override display options" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "Generic", + "children": [ + { + "type": "label", + "label": "Generic" + }, + { + "type": "boolean", + "key": "isolate_view", + "label": " Isolate view" + }, + { + "type": "boolean", + "key": "off_screen", + "label": " Off Screen" + } + ] + }, + { + "type": "dict", + "key": "IO", + "children": [ + { + "type": "label", + "label": "IO" + }, + { + "type": "text", + "key": "name", + "label": "Name" + }, + { + "type": "boolean", + "key": "open_finished", + "label": "Open finished" + }, + { + "type": "boolean", + "key": "raw_frame_numbers", + "label": "Raw frame numbers" + }, + { + "type": "list", + "key": "recent_playblasts", + "label": "Recent Playblasts", + "object_type": "text" + }, + { + "type": "boolean", + "key": "save_file", + "label": "Save file" + } + ] + }, + { + "type": "dict", + "key": "PanZoom", + "children": [ + { + "type": "boolean", + "key": "pan_zoom", + "label": " Pan Zoom" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "Renderer", + "children": [ + { + "type": "label", + "label": "Renderer" + }, + { + "type": "text", + "key": "rendererName", + "label": " Renderer name" + } + ] + }, + { + "type": "dict", + "key": "Resolution", + "children": [ + { + "type": "splitter" + }, + { + "type": "label", + "label": "Resolution" + }, + { + "type": "number", + "key": "width", + "label": " Width", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + }, + { + "type": "number", + "key": "height", + "label": "Height", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + }, + { + "type": "number", + "key": "percent", + "label": "percent", + "decimal": 1, + "minimum": 0, + "maximum": 200 + }, + { + "type": "text", + "key": "mode", + "label": "Mode" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "dict", + "key": "Time Range", + "children": [ + { + "type": "label", + "label": "Time Range" + }, + { + "type": "number", + "key": "start_frame", + "label": " Start frame", + "decimal": 0, + "minimum": 0, + "maximum": 999999 + }, + { + "type": "number", + "key": "end_frame", + "label": "End frame", + "decimal": 0, + "minimum": 0, + "maximum": 999999 + }, + { + "type": "text", + "key": "frame", + "label": "Frame" + }, + { + "type": "text", + "key": "time", + "label": "Time" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "Viewport Options", + "label": "Viewport Options", + "children": [ + { + "type": "boolean", + "key": "cameras", + "label": "cameras" + }, + { + "type": "boolean", + "key": "clipGhosts", + "label": "clipGhosts" + }, + { + "type": "boolean", + "key": "controlVertices", + "label": "controlVertices" + }, + { + "type": "boolean", + "key": "deformers", + "label": "deformers" + }, + { + "type": "boolean", + "key": "dimensions", + "label": "dimensions" + }, + { + "type": "number", + "key": "displayLights", + "label": "displayLights", + "decimal": 0, + "minimum": 0, + "maximum": 10 + }, + { + "type": "boolean", + "key": "dynamicConstraints", + "label": "dynamicConstraints" + }, + { + "type": "boolean", + "key": "dynamics", + "label": "dynamics" + }, + { + "type": "boolean", + "key": "fluids", + "label": "fluids" + }, + { + "type": "boolean", + "key": "follicles", + "label": "follicles" + }, + { + "type": "boolean", + "key": "gpuCacheDisplayFilter", + "label": "gpuCacheDisplayFilter" + }, + { + "type": "boolean", + "key": "greasePencils", + "label": "greasePencils" + }, + { + "type": "boolean", + "key": "grid", + "label": "grid" + }, + { + "type": "boolean", + "key": "hairSystems", + "label": "hairSystems" + }, + { + "type": "boolean", + "key": "handles", + "label": "handles" + }, + { + "type": "boolean", + "key": "high_quality", + "label": "high_quality" + }, + { + "type": "boolean", + "key": "hud", + "label": "hud" + }, + { + "type": "boolean", + "key": "hulls", + "label": "hulls" + }, + { + "type": "boolean", + "key": "ikHandles", + "label": "ikHandles" + }, + { + "type": "boolean", + "key": "imagePlane", + "label": "imagePlane" + }, + { + "type": "boolean", + "key": "joints", + "label": "joints" + }, + { + "type": "boolean", + "key": "lights", + "label": "lights" + }, + { + "type": "boolean", + "key": "locators", + "label": "locators" + }, + { + "type": "boolean", + "key": "manipulators", + "label": "manipulators" + }, + { + "type": "boolean", + "key": "motionTrails", + "label": "motionTrails" + }, + { + "type": "boolean", + "key": "nCloths", + "label": "nCloths" + }, + { + "type": "boolean", + "key": "nParticles", + "label": "nParticles" + }, + { + "type": "boolean", + "key": "nRigids", + "label": "nRigids" + }, + { + "type": "boolean", + "key": "nurbsCurves", + "label": "nurbsCurves" + }, + { + "type": "boolean", + "key": "nurbsSurfaces", + "label": "nurbsSurfaces" + }, + { + "type": "boolean", + "key": "override_viewport_options", + "label": "override_viewport_options" + }, + { + "type": "boolean", + "key": "particleInstancers", + "label": "particleInstancers" + }, + { + "type": "boolean", + "key": "pivots", + "label": "pivots" + }, + { + "type": "boolean", + "key": "planes", + "label": "planes" + }, + { + "type": "boolean", + "key": "pluginShapes", + "label": "pluginShapes" + }, + { + "type": "boolean", + "key": "polymeshes", + "label": "polymeshes" + }, + { + "type": "boolean", + "key": "shadows", + "label": "shadows" + }, + { + "type": "boolean", + "key": "strokes", + "label": "strokes" + }, + { + "type": "boolean", + "key": "subdivSurfaces", + "label": "subdivSurfaces" + }, + { + "type": "boolean", + "key": "textures", + "label": "textures" + }, + { + "type": "boolean", + "key": "twoSidedLighting", + "label": "twoSidedLighting" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "Camera Options", + "label": "Camera Options", + "children": [ + { + "type": "boolean", + "key": "displayGateMask", + "label": "displayGateMask" + }, + { + "type": "boolean", + "key": "displayResolution", + "label": "displayResolution" + }, + { + "type": "boolean", + "key": "displayFilmGate", + "label": "displayFilmGate" + }, + { + "type": "boolean", + "key": "displayFieldChart", + "label": "displayFieldChart" + }, + { + "type": "boolean", + "key": "displaySafeAction", + "label": "displaySafeAction" + }, + { + "type": "boolean", + "key": "displaySafeTitle", + "label": "displaySafeTitle" + }, + { + "type": "boolean", + "key": "displayFilmPivot", + "label": "displayFilmPivot" + }, + { + "type": "boolean", + "key": "displayFilmOrigin", + "label": "displayFilmOrigin" + }, + { + "type": "number", + "key": "overscan", + "label": "overscan", + "decimal": 1, + "minimum": 0, + "maximum": 10 + } + ] } ] } diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json new file mode 100644 index 0000000000..575e04c85d --- /dev/null +++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_create.json @@ -0,0 +1,86 @@ +{ + "type": "dict", + "collapsible": true, + "key": "create", + "label": "Creator plugins", + "children": [ + { + "type": "schema_template", + "name": "template_create_plugin", + "template_data": [ + { + "key": "CreateAnimation", + "label": "Create Animation" + }, + { + "key": "CreateAss", + "label": "Create Ass" + }, + { + "key": "CreateAssembly", + "label": "Create Assembly" + }, + { + "key": "CreateCamera", + "label": "Create Camera" + }, + { + "key": "CreateLayout", + "label": "Create Layout" + }, + { + "key": "CreateLook", + "label": "Create Look" + }, + { + "key": "CreateMayaScene", + "label": "Create Maya Scene" + }, + { + "key": "CreateModel", + "label": "Create Model" + }, + { + "key": "CreatePointCache", + "label": "Create Cache" + }, + { + "key": "CreateRender", + "label": "Create Render" + }, + { + "key": "CreateRenderSetup", + "label": "Create Render Setup" + }, + { + "key": "CreateReview", + "label": "Create Review" + }, + { + "key": "CreateRig", + "label": "Create Rig" + }, + { + "key": "CreateSetDress", + "label": "Create Set Dress" + }, + { + "key": "CreateUnrealStaticMesh", + "label": "Create Unreal - Static Mesh" + }, + { + "key": "CreateVrayProxy", + "label": "Create VRay Proxy" + }, + { + "key": "CreateVRayScene", + "label": "Create VRay Scene" + }, + { + "key": "CreateYetiRig", + "label": "Create Yeti Rig" + } + ] + } + ] +} diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json index dd9d0508b4..3615c1477c 100644 --- a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json +++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_load.json @@ -151,6 +151,32 @@ ] } ] + }, + { + "type": "schema_template", + "name": "template_loader_plugin", + "template_data": [ + { + "key": "ReferenceLoader", + "label": "Reference Loader" + }, + { + "key": "AudioLoader", + "label": "Audio Loader" + }, + { + "key": "GpuCacheLoader", + "label": "GpuCache Loader" + }, + { + "key": "ImagePlaneLoader", + "label": "Imageplane Loader" + }, + { + "key": "MatchmoveLoader", + "label": "Matchmove Loader" + } + ] } ] } diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json index 0d705d3d02..58a21c185a 100644 --- a/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json +++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_maya_publish.json @@ -26,71 +26,9 @@ }, { "type": "label", - "label": "Collectors" - }, - { - "type": "dict", - "collapsible": true, - "key": "ValidateCameraAttributes", - "label": "Validate Camera Attributes", - "checkbox_key": "enabled", - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "boolean", - "key": "optional", - "label": "Optional" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "key": "ValidateModelName", - "label": "Validate Model Name", - "checkbox_key": "enabled", - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "label", - "label": "Path to material file defining list of material names to check. This is material name per line simple text file.
It will be checked against named group shader in your Validation regex.

For example:
^.*(?P=<shader>.+)_GEO

" - }, - { - "type": "path-widget", - "key": "material_file", - "label": "Material File", - "multiplatform": true, - "multipath": false - }, - { - "type": "text", - "key": "regex", - "label": "Validation regex" - } - ] - }, - { - "type": "dict", - "collapsible": true, - "key": "ValidateAssemblyName", - "label": "Validate Assembly Name", - "checkbox_key": "enabled", - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] + "label": "Validators" }, + { "type": "dict", "collapsible": true, @@ -114,20 +52,7 @@ } ] }, - { - "type": "dict", - "collapsible": true, - "key": "ValidateMeshHasOverlappingUVs", - "label": "ValidateMeshHasOverlappingUVs", - "checkbox_key": "enabled", - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - }, + { "type": "dict", "collapsible": true, @@ -147,6 +72,169 @@ } ] }, + { + "type": "collapsible-wrap", + "label": "Model", + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "ValidateModelName", + "label": "Validate Model Name", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Path to material file defining list of material names to check. This is material name per line simple text file.
It will be checked against named group shader in your Validation regex.

For example:
^.*(?P=<shader>.+)_GEO

" + }, + { + "type": "path-widget", + "key": "material_file", + "label": "Material File", + "multiplatform": true, + "multipath": false + }, + { + "type": "text", + "key": "regex", + "label": "Validation regex" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ValidateTransformNamingSuffix", + "label": "ValidateTransformNamingSuffix", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Validates transform suffix based on the type of its children shapes." + }, + { + "type": "raw-json", + "key": "SUFFIX_NAMING_TABLE", + "label": "Suffix Naming Table" + }, + { + "type": "boolean", + "key": "ALLOW_IF_NOT_IN_SUFFIX_TABLE", + "label": "Allow if suffix not in table" + } + ] + }, + { + "type": "schema_template", + "name": "template_publish_plugin", + "template_data": [ + { + "key": "ValidateColorSets", + "label": "ValidateColorSets" + }, + { + "key": "ValidateMeshHasOverlappingUVs", + "label": "ValidateMeshHasOverlappingUVs" + }, + { + "key": "ValidateMeshArnoldAttributes", + "label": "ValidateMeshArnoldAttributes" + }, + { + "key": "ValidateMeshShaderConnections", + "label": "ValidateMeshShaderConnections" + }, + { + "key": "ValidateMeshSingleUVSet", + "label": "ValidateMeshSingleUVSet" + }, + { + "key": "ValidateMeshHasUVs", + "label": "ValidateMeshHasUVs" + }, + { + "key": "ValidateMeshLaminaFaces", + "label": "ValidateMeshLaminaFaces" + }, + { + "key": "ValidateMeshNonManifold", + "label": "ValidateMeshNonManifold" + }, + { + "key": "ValidateMeshUVSetMap1", + "label": "ValidateMeshUVSetMap1", + "docstring": "Validate model's default uv set exists and is named 'map1'.

In Maya meshes by default have a uv set named 'map1' that cannot be deleted. It can be renamed, however,
introducing some issues with some renderers. As such we ensure the first (default) UV set index is named 'map1'." + }, + { + "key": "ValidateMeshVerticesHaveEdges", + "label": "ValidateMeshVerticesHaveEdges" + }, + { + "key": "ValidateNoAnimation", + "label": "ValidateNoAnimation", + "docstring": "Ensure no keyframes on nodes in the Instance.
Even though a Model would extract without animCurves correctly this avoids getting different
output from a model when extracted from a different frame than the first frame. (Might be overly restrictive though)." + }, + { + "key": "ValidateNoNamespace", + "label": "ValidateNoNamespace" + }, + { + "key": "ValidateNoNullTransforms", + "label": "ValidateNoNullTransforms" + }, + { + "key": "ValidateNoUnknownNodes", + "label": "ValidateNoUnknownNodes" + }, + { + "key": "ValidateNodeNoGhosting", + "label": "ValidateNodeNoGhosting" + }, + { + "key": "ValidateShapeDefaultNames", + "label": "ValidateShapeDefaultNames" + }, + { + "key": "ValidateShapeRenderStats", + "label": "ValidateShapeRenderStats" + }, + { + "key": "ValidateTransformZero", + "label": "ValidateTransformZero" + } + ] + } + ] + }, + { + "type": "schema_template", + "name": "template_publish_plugin", + "template_data": [ + { + "key": "ValidateCameraAttributes", + "label": "Validate Camera Attributes", + "docstring": "" + }, + { + "key": "ValidateAssemblyName", + "label": "Validate Assembly Name" + }, + { + "key": "ValidateAssRelativePaths", + "label": "ValidateAssRelativePaths" + } + ] + }, { "type": "splitter" }, diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json new file mode 100644 index 0000000000..0e3770ac78 --- /dev/null +++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json @@ -0,0 +1,180 @@ +{ + "type": "dict", + "collapsible": true, + "key": "publish", + "label": "Publish plugins", + "children": [ + { + "type": "label", + "label": "Collectors" + }, + { + "type": "dict", + "collapsible": true, + "key": "PreCollectNukeInstances", + "label": "PreCollectNukeInstances", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "sync_workfile_version", + "label": "Sync Version from workfile" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Validators" + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ValidateKnobs", + "label": "ValidateKnobs", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "raw-json", + "key": "knobs", + "label": "Knobs" + } + ] + }, + { + "type": "schema_template", + "name": "template_publish_plugin", + "template_data": [ + { + "key": "ValidateOutputResolution", + "label": "Validate Output Resolution" + }, + { + "key": "ValidateGizmo", + "label": "Validate Gizmo (Group)" + }, + { + "key": "ValidateScript", + "label": "Validate script settings" + }, + { + "key": "ValidateNukeWriteBoundingBox", + "label": "Validate and Write Bounding Box" + } + ] + }, + { + "type": "splitter" + }, + { + "type": "label", + "label": "Extractors" + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ExtractThumbnail", + "label": "ExtractThumbnail", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "raw-json", + "key": "nodes", + "label": "Nodes" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ExtractReviewDataLut", + "label": "ExtractReviewDataLut", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "ExtractReviewDataMov", + "label": "ExtractReviewDataMov", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "viewer_lut_raw", + "label": "Viewer LUT raw" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "ExtractSlateFrame", + "label": "ExtractSlateFrame", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "viewer_lut_raw", + "label": "Viewer LUT raw" + } + ] + }, + { + "type": "dict", + "collapsible": true, + "key": "NukeSubmitDeadline", + "label": "NukeSubmitDeadline", + "is_group": true, + "children": [ + { + "type": "number", + "key": "deadline_priority", + "label": "deadline_priority" + }, + { + "type": "text", + "key": "deadline_pool", + "label": "deadline_pool" + }, + { + "type": "text", + "key": "deadline_pool_secondary", + "label": "deadline_pool_secondary" + }, + { + "type": "number", + "key": "deadline_chunk_size", + "label": "deadline_chunk_size" + } + ] + } + ] +} diff --git a/pype/settings/entities/schemas/projects_schema/schemas/template_create_plugin.json b/pype/settings/entities/schemas/projects_schema/schemas/template_create_plugin.json new file mode 100644 index 0000000000..14d15e7840 --- /dev/null +++ b/pype/settings/entities/schemas/projects_schema/schemas/template_create_plugin.json @@ -0,0 +1,22 @@ +[ + { + "type": "dict", + "collapsible": true, + "key": "{key}", + "label": "{label}", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "defaults", + "label": "Default Subsets", + "object_type": "text" + } + ] + } +] diff --git a/pype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin.json b/pype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin.json new file mode 100644 index 0000000000..20dca6df17 --- /dev/null +++ b/pype/settings/entities/schemas/projects_schema/schemas/template_loader_plugin.json @@ -0,0 +1,22 @@ +[ + { + "type": "dict", + "collapsible": true, + "key": "{key}", + "label": "{label}", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "representations", + "label": "Representations", + "object_type": "text" + } + ] + } +] diff --git a/pype/settings/entities/schemas/projects_schema/schemas/template_publish_plugin.json b/pype/settings/entities/schemas/projects_schema/schemas/template_publish_plugin.json new file mode 100644 index 0000000000..88151f7534 --- /dev/null +++ b/pype/settings/entities/schemas/projects_schema/schemas/template_publish_plugin.json @@ -0,0 +1,30 @@ +[ + { + "__default_values__": { + "docstring": "" + } + }, + { + "type": "dict", + "collapsible": true, + "key": "{key}", + "label": "{label}", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "boolean", + "key": "optional", + "label": "Optional" + }, + { + "type": "label", + "label": "{docstring}" + } + ] + } +] \ No newline at end of file diff --git a/pype/settings/handlers.py b/pype/settings/handlers.py index 0df4c98820..89f9645be7 100644 --- a/pype/settings/handlers.py +++ b/pype/settings/handlers.py @@ -10,7 +10,8 @@ import pype from .constants import ( SYSTEM_SETTINGS_KEY, PROJECT_SETTINGS_KEY, - PROJECT_ANATOMY_KEY + PROJECT_ANATOMY_KEY, + LOCAL_SETTING_KEY ) from .lib import load_json_file @@ -103,6 +104,28 @@ class SettingsHandler: pass +@six.add_metaclass(ABCMeta) +class LocalSettingsHandler: + """Handler that should handle about storing and loading of local settings. + + Local settings are "workstation" specific modifications that modify how + system and project settings look on the workstation and only there. + """ + @abstractmethod + def save_local_settings(self, data): + """Save local data of local settings. + + Args: + data(dict): Data of local data with override metadata. + """ + pass + + @abstractmethod + def get_local_settings(self): + """Studio overrides of system settings.""" + pass + + class SettingsFileHandler(SettingsHandler): def __init__(self): self.log = logging.getLogger("SettingsFileHandler") @@ -495,3 +518,76 @@ class MongoSettingsHandler(SettingsHandler): if not project_name: return {} return self._get_project_anatomy_overrides(project_name) + + +class MongoLocalSettingsHandler(LocalSettingsHandler): + """Settings handler that use mongo for store and load local settings. + + Data have 2 query criteria. First is key "type" stored in constant + `LOCAL_SETTING_KEY`. Second is key "site_id" which value can be obstained + with `get_local_site_id` function. + """ + + def __init__(self, local_site_id=None): + # Get mongo connection + from pype.lib import ( + PypeMongoConnection, + get_local_site_id + ) + + if local_site_id is None: + local_site_id = get_local_site_id() + settings_collection = PypeMongoConnection.get_mongo_client() + + # TODO prepare version of pype + # - pype version should define how are settings saved and loaded + + # TODO modify to not use hardcoded keys + database_name = "pype" + collection_name = "settings" + + self.settings_collection = settings_collection + + self.database_name = database_name + self.collection_name = collection_name + + self.collection = settings_collection[database_name][collection_name] + + self.local_site_id = local_site_id + + self.local_settings_cache = CacheValues() + + def save_local_settings(self, data): + """Save local settings. + + Args: + data(dict): Data of studio overrides with override metadata. + """ + data = data or {} + + self.local_settings_cache.update_data(data) + + self.collection.replace_one( + { + "type": LOCAL_SETTING_KEY, + "site_id": self.local_site_id + }, + { + "type": LOCAL_SETTING_KEY, + "site_id": self.local_site_id, + "value": self.local_settings_cache.to_json_string() + }, + upsert=True + ) + + def get_local_settings(self): + """Local settings for local site id.""" + if self.local_settings_cache.is_outdated: + document = self.collection.find_one({ + "type": LOCAL_SETTING_KEY, + "site_id": self.local_site_id + }) + + self.local_settings_cache.update_from_document(document) + + return self.local_settings_cache.data_copy() diff --git a/pype/settings/lib.py b/pype/settings/lib.py index dfc46e1a5a..feeeaf3813 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -2,6 +2,7 @@ import os import json import functools import logging +import platform import copy from .constants import ( M_OVERRIDEN_KEY, @@ -11,7 +12,8 @@ from .constants import ( SYSTEM_SETTINGS_KEY, PROJECT_SETTINGS_KEY, - PROJECT_ANATOMY_KEY + PROJECT_ANATOMY_KEY, + DEFAULT_PROJECT_KEY ) log = logging.getLogger(__name__) @@ -32,6 +34,9 @@ _DEFAULT_SETTINGS = None # Handler of studio overrides _SETTINGS_HANDLER = None +# Handler of local settings +_LOCAL_SETTINGS_HANDLER = None + def require_handler(func): @functools.wraps(func) @@ -43,6 +48,16 @@ def require_handler(func): return wrapper +def require_local_handler(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + global _LOCAL_SETTINGS_HANDLER + if _LOCAL_SETTINGS_HANDLER is None: + _LOCAL_SETTINGS_HANDLER = create_local_settings_handler() + return func(*args, **kwargs) + return wrapper + + def create_settings_handler(): from .handlers import MongoSettingsHandler # Handler can't be created in global space on initialization but only when @@ -50,6 +65,11 @@ def create_settings_handler(): return MongoSettingsHandler() +def create_local_settings_handler(): + from .handlers import MongoLocalSettingsHandler + return MongoLocalSettingsHandler() + + @require_handler def save_studio_settings(data): return _SETTINGS_HANDLER.save_studio_settings(data) @@ -90,6 +110,16 @@ def get_project_anatomy_overrides(project_name): return _SETTINGS_HANDLER.get_project_anatomy_overrides(project_name) +@require_local_handler +def save_local_settings(data): + return _LOCAL_SETTINGS_HANDLER.save_local_settings(data) + + +@require_local_handler +def get_local_settings(): + return _LOCAL_SETTINGS_HANDLER.get_local_settings() + + class DuplicatedEnvGroups(Exception): def __init__(self, duplicated): self.origin_duplicated = duplicated @@ -309,6 +339,109 @@ def apply_overrides(source_data, override_data): return merge_overrides(_source_data, override_data) +def apply_local_settings_on_system_settings(system_settings, local_settings): + """Apply local settings on studio system settings. + + ATM local settings can modify only application executables. Executable + values are not overriden but prepended. + """ + if not local_settings or "applications" not in local_settings: + return + + current_platform = platform.system().lower() + for app_group_name, value in local_settings["applications"].items(): + if not value or app_group_name not in system_settings["applications"]: + continue + + variants = system_settings["applications"][app_group_name]["variants"] + for app_name, app_value in value.items(): + if not app_value or app_name not in variants: + continue + + executable = app_value.get("executable") + if not executable: + continue + platform_executables = variants[app_name]["executables"].get( + current_platform + ) + # TODO This is temporary fix until launch arguments will be stored + # per platform and not per executable. + # - local settings store only executable + new_executables = [[executable, ""]] + new_executables.extend(platform_executables) + variants[app_name]["executables"] = new_executables + + +def apply_local_settings_on_anatomy_settings( + anatomy_settings, local_settings, project_name +): + """Apply local settings on anatomy settings. + + ATM local settings can modify project roots. Project name is required as + local settings have data stored data by project's name. + + Local settings override root values in this order: + 1.) Check if local settings contain overrides for default project and + apply it's values on roots if there are any. + 2.) If passed `project_name` is not None then check project specific + overrides in local settings for the project and apply it's value on + roots if there are any. + + NOTE: Root values of default project from local settings are always applied + if are set. + + Args: + anatomy_settings (dict): Data for anatomy settings. + local_settings (dict): Data of local settings. + project_name (str): Name of project for which anatomy data are. + """ + if not local_settings: + return + + local_project_settings = local_settings.get("projects") + if not local_project_settings: + return + + project_locals = local_project_settings.get(project_name) or {} + default_locals = local_project_settings.get(DEFAULT_PROJECT_KEY) or {} + active_site = project_locals.get("active_site") + if not active_site: + active_site = default_locals.get("active_site") + + if not active_site: + project_settings = get_project_settings(project_name) + active_site = ( + project_settings + ["global"] + ["sync_server"] + ["config"] + ["active_site"] + ) + + # QUESTION should raise an exception? + if not active_site: + return + + roots_locals = default_locals.get("roots", {}).get(active_site, {}) + if project_name != DEFAULT_PROJECT_KEY: + roots_locals.update( + project_locals.get("roots", {}).get(active_site, {}) + ) + + if not roots_locals: + return + + current_platform = platform.system().lower() + + root_data = anatomy_settings["roots"] + for root_name, path in roots_locals.items(): + if root_name not in root_data: + continue + anatomy_settings["roots"][root_name][current_platform] = ( + path + ) + + def get_system_settings(clear_metadata=True): """System settings with applied studio overrides.""" default_values = get_default_settings()[SYSTEM_SETTINGS_KEY] @@ -316,6 +449,10 @@ def get_system_settings(clear_metadata=True): result = apply_overrides(default_values, studio_values) if clear_metadata: clear_metadata_from_settings(result) + # TODO local settings may be required to apply for environments + local_settings = get_local_settings() + apply_local_settings_on_system_settings(result, local_settings) + return result @@ -343,6 +480,8 @@ def get_default_anatomy_settings(clear_metadata=True): result[key] = value if clear_metadata: clear_metadata_from_settings(result) + local_settings = get_local_settings() + apply_local_settings_on_anatomy_settings(result, local_settings, None) return result @@ -368,6 +507,10 @@ def get_anatomy_settings(project_name, clear_metadata=True): result[key] = value if clear_metadata: clear_metadata_from_settings(result) + local_settings = get_local_settings() + apply_local_settings_on_anatomy_settings( + result, local_settings, project_name + ) return result diff --git a/pype/settings/local_settings.md b/pype/settings/local_settings.md new file mode 100644 index 0000000000..fbb5cf3df1 --- /dev/null +++ b/pype/settings/local_settings.md @@ -0,0 +1,79 @@ +# Structure of local settings +- local settings do not have any validation schemas right now this should help to see what is stored to local settings and how it works +- they are stored by identifier site_id which should be unified identifier of workstation +- all keys may and may not available on load +- contain main categories: `general`, `applications`, `projects` + +## Categories +### General +- ATM contain only label of site +```json +{ + "general": { + "site_label": "MySite" + } +} +``` + +### Applications +- modifications of application executables +- output should match application groups and variants +```json +{ + "applications": { + "": { + "": { + "executable": "/my/path/to/nuke_12_2" + } + } + } +} +``` + +### Projects +- project specific modifications +- default project is stored under constant key defined in `pype.settings.contants` +```json +{ + "projects": { + "": { + "active_site": "", + "remote_site": "", + "roots": { + "": { + "": "" + } + } + } + } +} +``` + +## Final document +```json +{ + "_id": "", + "site_id": "", + "general": { + "site_label": "MySite" + }, + "applications": { + "": { + "": { + "executable": "" + } + } + }, + "projects": { + "": { + "active_site": "", + "remote_site": "", + "roots": { + "": { + "": "" + } + } + } + } +} +``` diff --git a/pype/tools/settings/__init__.py b/pype/tools/settings/__init__.py index 7bc54f9ab6..3f47d1c2c3 100644 --- a/pype/tools/settings/__init__.py +++ b/pype/tools/settings/__init__.py @@ -1,6 +1,6 @@ import sys from Qt import QtWidgets, QtGui - +from .local_settings import LocalSettingsWindow from .settings import ( style, MainWidget, @@ -33,5 +33,6 @@ __all__ = ( "style", "MainWidget", "ProjectListWidget", + "LocalSettingsWindow", "main" ) diff --git a/pype/tools/settings/local_settings/__init__.py b/pype/tools/settings/local_settings/__init__.py new file mode 100644 index 0000000000..135a719a09 --- /dev/null +++ b/pype/tools/settings/local_settings/__init__.py @@ -0,0 +1,6 @@ +from .window import LocalSettingsWindow + + +__all__ = ( + "LocalSettingsWindow", +) diff --git a/pype/tools/settings/local_settings/apps_widget.py b/pype/tools/settings/local_settings/apps_widget.py new file mode 100644 index 0000000000..d63cd6a834 --- /dev/null +++ b/pype/tools/settings/local_settings/apps_widget.py @@ -0,0 +1,205 @@ +import platform +from Qt import QtWidgets +from .widgets import ( + Separator, + ExpandingWidget +) +from .constants import CHILD_OFFSET + + +class AppVariantWidget(QtWidgets.QWidget): + exec_placeholder = "< Specific path for this machine >" + + def __init__(self, group_label, variant_entity, parent): + super(AppVariantWidget, self).__init__(parent) + + self.executable_input_widget = None + + label = " ".join([group_label, variant_entity.label]) + + expading_widget = ExpandingWidget(label, self) + content_widget = QtWidgets.QWidget(expading_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + + expading_widget.set_content_widget(content_widget) + + # Add expanding widget to main layout + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(expading_widget) + + # TODO For celaction - not sure what is "Celaction publish" for + if not variant_entity["executables"].multiplatform: + warn_label = QtWidgets.QLabel( + "Application without multiplatform paths" + ) + content_layout.addWidget(warn_label) + return + + executable_input_widget = QtWidgets.QLineEdit(content_widget) + executable_input_widget.setPlaceholderText(self.exec_placeholder) + content_layout.addWidget(executable_input_widget) + + self.executable_input_widget = executable_input_widget + + studio_executables = ( + variant_entity["executables"][platform.system().lower()] + ) + if len(studio_executables) < 1: + return + + content_layout.addWidget(Separator(parent=self)) + content_layout.addWidget( + QtWidgets.QLabel("Studio paths:", self) + ) + + for item in studio_executables: + path_widget = QtWidgets.QLineEdit(content_widget) + path_widget.setText(item.value[0]) + path_widget.setEnabled(False) + content_layout.addWidget(path_widget) + + def update_local_settings(self, value): + if not self.executable_input_widget: + return + + if not value: + value = {} + elif not isinstance(value, dict): + print("Got invalid value type {}. Expected {}".format( + type(value), dict + )) + value = {} + + executable_path = value.get("executable") + if not executable_path: + executable_path = "" + elif isinstance(executable_path, list): + print("Got list in executable path so using first item as value") + executable_path = executable_path[0] + + if not isinstance(executable_path, str): + executable_path = "" + print(( + "Got invalid value type of app executable {}. Expected {}" + ).format(type(value), str)) + + self.executable_input_widget.setText(executable_path) + + def settings_value(self): + if not self.executable_input_widget: + return None + value = self.executable_input_widget.text() + if not value: + return None + return {"executable": value} + + +class AppGroupWidget(QtWidgets.QWidget): + def __init__(self, group_entity, parent): + super(AppGroupWidget, self).__init__(parent) + + valid_variants = {} + for key, entity in group_entity["variants"].items(): + if entity["enabled"].value: + valid_variants[key] = entity + + group_label = group_entity.label + expading_widget = ExpandingWidget(group_label, self) + content_widget = QtWidgets.QWidget(expading_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + + widgets_by_variant_name = {} + for variant_name, variant_entity in valid_variants.items(): + variant_widget = AppVariantWidget( + group_label, variant_entity, content_widget + ) + widgets_by_variant_name[variant_name] = variant_widget + content_layout.addWidget(variant_widget) + + expading_widget.set_content_widget(content_widget) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(expading_widget) + + self.widgets_by_variant_name = widgets_by_variant_name + + def update_local_settings(self, value): + if not value: + value = {} + + for variant_name, widget in self.widgets_by_variant_name.items(): + widget.update_local_settings(value.get(variant_name)) + + def settings_value(self): + output = {} + for variant_name, widget in self.widgets_by_variant_name.items(): + value = widget.settings_value() + if value: + output[variant_name] = value + + if not output: + return None + return output + + +class LocalApplicationsWidgets(QtWidgets.QWidget): + def __init__(self, system_settings_entity, parent): + super(LocalApplicationsWidgets, self).__init__(parent) + + self.widgets_by_group_name = {} + self.system_settings_entity = system_settings_entity + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + + self.content_layout = layout + + def _reset_app_widgets(self): + while self.content_layout.count() > 0: + item = self.content_layout.itemAt(0) + item.widget().hide() + self.content_layout.removeItem(item) + self.widgets_by_group_name.clear() + + for key, entity in self.system_settings_entity["applications"].items(): + # Filter not enabled app groups + if not entity["enabled"].value: + continue + + # Check if has enabled any variant + enabled_variant = False + for variant_entity in entity["variants"].values(): + if variant_entity["enabled"].value: + enabled_variant = True + break + + if not enabled_variant: + continue + + # Create App group specific widget and store it by the key + group_widget = AppGroupWidget(entity, self) + self.widgets_by_group_name[key] = group_widget + self.content_layout.addWidget(group_widget) + + def update_local_settings(self, value): + if not value: + value = {} + + self._reset_app_widgets() + + for group_name, widget in self.widgets_by_group_name.items(): + widget.update_local_settings(value.get(group_name)) + + def settings_value(self): + output = {} + for group_name, widget in self.widgets_by_group_name.items(): + value = widget.settings_value() + if value: + output[group_name] = value + if not output: + return None + return output diff --git a/pype/tools/settings/local_settings/constants.py b/pype/tools/settings/local_settings/constants.py new file mode 100644 index 0000000000..83c45afba8 --- /dev/null +++ b/pype/tools/settings/local_settings/constants.py @@ -0,0 +1,32 @@ +# Action labels +LABEL_REMOVE_DEFAULT = "Remove from default" +LABEL_ADD_DEFAULT = "Add to default" +LABEL_REMOVE_PROJECT = "Remove from project" +LABEL_ADD_PROJECT = "Add to project" +LABEL_DISCARD_CHANGES = "Discard changes" + +# Local setting contants +# TODO move to settings constants +LOCAL_GENERAL_KEY = "general" +LOCAL_PROJECTS_KEY = "projects" +LOCAL_APPS_KEY = "applications" + +# Roots key constant +LOCAL_ROOTS_KEY = "roots" + +# Child offset in expandable widget +CHILD_OFFSET = 15 + +__all__ = ( + "LABEL_REMOVE_DEFAULT", + "LABEL_ADD_DEFAULT", + "LABEL_REMOVE_PROJECT", + "LABEL_ADD_PROJECT", + "LABEL_DISCARD_CHANGES", + + "LOCAL_GENERAL_KEY", + "LOCAL_PROJECTS_KEY", + "LOCAL_APPS_KEY", + + "LOCAL_ROOTS_KEY" +) diff --git a/pype/tools/settings/local_settings/general_widget.py b/pype/tools/settings/local_settings/general_widget.py new file mode 100644 index 0000000000..7732157122 --- /dev/null +++ b/pype/tools/settings/local_settings/general_widget.py @@ -0,0 +1,32 @@ +from Qt import QtWidgets + + +class LocalGeneralWidgets(QtWidgets.QWidget): + def __init__(self, parent): + super(LocalGeneralWidgets, self).__init__(parent) + + local_site_name_input = QtWidgets.QLineEdit(self) + + layout = QtWidgets.QFormLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + + layout.addRow("Local site label", local_site_name_input) + + self.local_site_name_input = local_site_name_input + + def update_local_settings(self, value): + site_label = "" + if value: + site_label = value.get("site_label", site_label) + self.local_site_name_input.setText(site_label) + + def settings_value(self): + # Add changed + # If these have changed then + output = {} + local_site_name = self.local_site_name_input.text() + if local_site_name: + output["site_label"] = local_site_name + # Do not return output yet since we don't have mechanism to save or + # load these data through api calls + return output diff --git a/pype/tools/settings/local_settings/mongo_widget.py b/pype/tools/settings/local_settings/mongo_widget.py new file mode 100644 index 0000000000..c6f6ab1591 --- /dev/null +++ b/pype/tools/settings/local_settings/mongo_widget.py @@ -0,0 +1,80 @@ +import os +import sys +import traceback + +from Qt import QtWidgets +from pymongo.errors import ServerSelectionTimeoutError + +from pype.api import change_pype_mongo_url + + +class PypeMongoWidget(QtWidgets.QWidget): + def __init__(self, parent): + super(PypeMongoWidget, self).__init__(parent) + + # Warning label + warning_label = QtWidgets.QLabel(( + "WARNING: Requires restart. Change of Pype Mongo requires to" + " restart of all running Pype processes and process using Pype" + " (Including this)." + "\n- all changes in different categories won't be saved." + ), self) + warning_label.setStyleSheet("font-weight: bold;") + + # Label + mongo_url_label = QtWidgets.QLabel("Pype Mongo URL", self) + + # Input + mongo_url_input = QtWidgets.QLineEdit(self) + mongo_url_input.setPlaceholderText("< Pype Mongo URL >") + mongo_url_input.setText(os.environ["PYPE_MONGO"]) + + # Confirm button + mongo_url_change_btn = QtWidgets.QPushButton("Confirm Change", self) + + layout = QtWidgets.QGridLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(warning_label, 0, 0, 1, 3) + layout.addWidget(mongo_url_label, 1, 0) + layout.addWidget(mongo_url_input, 1, 1) + layout.addWidget(mongo_url_change_btn, 1, 2) + + mongo_url_change_btn.clicked.connect(self._on_confirm_click) + + self.mongo_url_input = mongo_url_input + + def _on_confirm_click(self): + value = self.mongo_url_input.text() + + dialog = QtWidgets.QMessageBox(self) + + title = "Pype mongo changed" + message = ( + "Pype mongo url was successfully changed. Restart Pype please." + ) + details = None + + try: + change_pype_mongo_url(value) + except Exception as exc: + if isinstance(exc, ServerSelectionTimeoutError): + error_message = ( + "Connection timeout passed." + " Probably can't connect to the Mongo server." + ) + else: + error_message = str(exc) + + title = "Pype mongo change failed" + # TODO catch exception message more gracefully + message = ( + "Pype mongo change was not successful." + " Full traceback can be found in details section.\n\n" + "Error message:\n{}" + ).format(error_message) + details = "\n".join(traceback.format_exception(*sys.exc_info())) + dialog.setWindowTitle(title) + dialog.setText(message) + if details: + dialog.setDetailedText(details) + dialog.exec_() diff --git a/pype/tools/settings/local_settings/projects_widget.py b/pype/tools/settings/local_settings/projects_widget.py new file mode 100644 index 0000000000..28765155c2 --- /dev/null +++ b/pype/tools/settings/local_settings/projects_widget.py @@ -0,0 +1,731 @@ +import platform +import copy +from Qt import QtWidgets, QtCore, QtGui +from pype.tools.settings.settings import ProjectListWidget +from pype.settings.constants import ( + PROJECT_ANATOMY_KEY, + DEFAULT_PROJECT_KEY +) +from .widgets import ( + SpacerWidget, + ProxyLabelWidget +) +from .constants import ( + LABEL_REMOVE_DEFAULT, + LABEL_ADD_DEFAULT, + LABEL_REMOVE_PROJECT, + LABEL_ADD_PROJECT, + LABEL_DISCARD_CHANGES, + LOCAL_ROOTS_KEY +) + +NOT_SET = type("NOT_SET", (), {})() + + +def get_active_sites(project_settings): + global_entity = project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) + + +class _ProjectListWidget(ProjectListWidget): + def on_item_clicked(self, new_index): + new_project_name = new_index.data(QtCore.Qt.DisplayRole) + if new_project_name is None: + return + + if self.current_project == new_project_name: + return + + self.select_project(new_project_name) + self.current_project = new_project_name + self.project_changed.emit() + + +class RootInputWidget(QtWidgets.QWidget): + def __init__( + self, + local_project_settings, + local_project_settings_orig, + platform_root_entity, + root_name, + project_name, + site_name, + parent + ): + super(RootInputWidget, self).__init__(parent) + + self.local_project_settings = local_project_settings + self.local_project_settings_orig = local_project_settings_orig + self.platform_root_entity = platform_root_entity + self.root_name = root_name + self.site_name = site_name + self.project_name = project_name + + self.origin_value = self._get_site_value_for_project( + self.project_name, self.local_project_settings_orig + ) or "" + + is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) + + default_input_value = self._get_site_value_for_project( + DEFAULT_PROJECT_KEY + ) + if is_default_project: + input_value = default_input_value + project_value = None + else: + input_value = self._get_site_value_for_project(self.project_name) + project_value = input_value + + # Placeholder + placeholder = None + if not is_default_project: + placeholder = default_input_value + + if not placeholder: + placeholder = platform_root_entity.value + + key_label = ProxyLabelWidget( + root_name, + self._mouse_release_callback, + self + ) + value_input = QtWidgets.QLineEdit(self) + value_input.setPlaceholderText("< {} >".format(placeholder)) + + # Root value + if input_value: + value_input.setText(input_value) + + value_input.textChanged.connect(self._on_value_change) + + root_layout = QtWidgets.QHBoxLayout(self) + root_layout.addWidget(key_label) + root_layout.addWidget(value_input) + + self.value_input = value_input + self.label_widget = key_label + + self.studio_value = platform_root_entity.value + self.default_value = default_input_value + self.project_value = project_value + self.placeholder_value = placeholder + + self._update_style() + + def is_modified(self): + return self.origin_value != self.value_input.text() + + def _mouse_release_callback(self, event): + if event.button() != QtCore.Qt.RightButton: + return + self._show_actions() + event.accept() + + def _get_style_state(self): + if self.project_name is None: + return "" + + if self.is_modified(): + return "modified" + + current_value = self.value_input.text() + if self.project_name == DEFAULT_PROJECT_KEY: + if current_value: + return "studio" + else: + if current_value: + return "overriden" + + studio_value = self._get_site_value_for_project( + DEFAULT_PROJECT_KEY + ) + if studio_value: + return "studio" + return "" + + def _update_style(self): + state = self._get_style_state() + + self.value_input.setProperty("input-state", state) + self.value_input.style().polish(self.value_input) + + self.label_widget.set_label_property("state", state) + + def _remove_from_local(self): + self.value_input.setText("") + self._update_style() + + def _add_to_local(self): + self.value_input.setText(self.placeholder_value) + self._update_style() + + def discard_changes(self): + self.value_input.setText(self.origin_value) + self._update_style() + + def _show_actions(self): + if self.project_name is None: + return + + menu = QtWidgets.QMenu(self) + actions_mapping = {} + + if self.project_name == DEFAULT_PROJECT_KEY: + remove_label = LABEL_REMOVE_DEFAULT + add_label = LABEL_ADD_DEFAULT + else: + remove_label = LABEL_REMOVE_PROJECT + add_label = LABEL_ADD_PROJECT + + if self.value_input.text(): + action = QtWidgets.QAction(remove_label) + callback = self._remove_from_local + else: + action = QtWidgets.QAction(add_label) + callback = self._add_to_local + + actions_mapping[action] = callback + menu.addAction(action) + + if self.is_modified(): + discard_changes_action = QtWidgets.QAction(LABEL_DISCARD_CHANGES) + actions_mapping[discard_changes_action] = self.discard_changes + menu.addAction(discard_changes_action) + + result = menu.exec_(QtGui.QCursor.pos()) + if result: + to_run = actions_mapping[result] + if to_run: + to_run() + + def _get_site_value_for_project(self, project_name, data=None): + if data is None: + data = self.local_project_settings + project_values = data.get(project_name) + site_value = {} + if project_values: + root_value = project_values.get(LOCAL_ROOTS_KEY) + if root_value: + site_value = root_value.get(self.site_name) or {} + return site_value.get(self.root_name) + + def _on_value_change(self): + value = self.value_input.text() + data = self.local_project_settings + for key in (self.project_name, LOCAL_ROOTS_KEY, self.site_name): + if key not in data: + data[key] = {} + data = data[key] + data[self.root_name] = value + self._update_style() + + +class RootsWidget(QtWidgets.QWidget): + def __init__(self, project_settings, parent): + super(RootsWidget, self).__init__(parent) + + self.project_settings = project_settings + self.site_widgets = [] + self.local_project_settings = None + self.local_project_settings_orig = None + self._project_name = None + + self.content_layout = QtWidgets.QVBoxLayout(self) + + def _clear_widgets(self): + while self.content_layout.count(): + item = self.content_layout.itemAt(0) + item.widget().hide() + self.content_layout.removeItem(item) + self.site_widgets = [] + + def refresh(self): + self._clear_widgets() + + if self._project_name is None: + return + + roots_entity = ( + self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] + ) + # Site label + for site_name in get_active_sites(self.project_settings): + site_widget = QtWidgets.QWidget(self) + site_layout = QtWidgets.QVBoxLayout(site_widget) + + site_label = QtWidgets.QLabel(site_name, site_widget) + + site_layout.addWidget(site_label) + + # Root inputs + for root_name, path_entity in roots_entity.items(): + platform_entity = path_entity[platform.system().lower()] + root_widget = RootInputWidget( + self.local_project_settings, + self.local_project_settings_orig, + platform_entity, + root_name, + self._project_name, + site_name, + site_widget + ) + + site_layout.addWidget(root_widget) + + self.site_widgets.append(site_widget) + self.content_layout.addWidget(site_widget) + + # Add spacer so other widgets are squeezed to top + self.content_layout.addWidget(SpacerWidget(self), 1) + + def update_local_settings(self, local_project_settings): + self.local_project_settings = local_project_settings + self.local_project_settings_orig = copy.deepcopy( + dict(local_project_settings) + ) + + def change_project(self, project_name): + self._project_name = project_name + self.refresh() + + +class _SiteCombobox(QtWidgets.QWidget): + input_label = None + + def __init__(self, project_settings, parent): + super(_SiteCombobox, self).__init__(parent) + self.project_settings = project_settings + + self.local_project_settings = None + self.local_project_settings_orig = None + self.project_name = None + + self.default_override_value = None + self.project_override_value = None + + label_widget = ProxyLabelWidget( + self.input_label, + self._mouse_release_callback, + self + ) + combobox_input = QtWidgets.QComboBox(self) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.addWidget(label_widget) + main_layout.addWidget(combobox_input) + + combobox_input.currentIndexChanged.connect(self._on_index_change) + self.label_widget = label_widget + self.combobox_input = combobox_input + + def _set_current_text(self, text): + index = None + if text: + idx = self.combobox_input.findText(text) + if idx >= 0: + index = idx + + if index is not None: + self.combobox_input.setCurrentIndex(index) + return True + return False + + def is_modified(self, current_value=NOT_SET, orig_value=NOT_SET): + if current_value is NOT_SET: + current_value = self._get_local_settings_item(self.project_name) + if orig_value is NOT_SET: + orig_value = self._get_local_settings_item( + self.project_name, self.local_project_settings_orig + ) + if current_value and orig_value: + modified = current_value != orig_value + elif not current_value and not orig_value: + modified = False + else: + modified = True + return modified + + def _get_style_state(self): + if self.project_name is None: + return "" + + current_value = self._get_local_settings_item(self.project_name) + orig_value = self._get_local_settings_item( + self.project_name, self.local_project_settings_orig + ) + + if self.is_modified(current_value, orig_value): + return "modified" + + if self.project_name == DEFAULT_PROJECT_KEY: + if current_value: + return "studio" + else: + if current_value: + return "overriden" + + studio_value = self._get_local_settings_item(DEFAULT_PROJECT_KEY) + if studio_value: + return "studio" + return "" + + def _update_style(self): + state = self._get_style_state() + + self.combobox_input.setProperty("input-state", state) + self.combobox_input.style().polish(self.combobox_input) + + self.label_widget.set_label_property("state", state) + + def _mouse_release_callback(self, event): + if event.button() != QtCore.Qt.RightButton: + return + self._show_actions() + + def _remove_from_local(self): + settings_value = self._get_value_from_project_settings() + combobox_value = None + if self.project_name == DEFAULT_PROJECT_KEY: + combobox_value = self._get_local_settings_item(DEFAULT_PROJECT_KEY) + if combobox_value: + idx = self.combobox_input.findText(combobox_value) + if idx < 0: + combobox_value = None + + if not combobox_value: + combobox_value = settings_value + + if combobox_value: + _project_name = self.project_name + self.project_name = None + self._set_current_text(combobox_value) + self.project_name = _project_name + + self._set_local_settings_value("") + self._update_style() + + def _add_to_local(self): + self._set_local_settings_value(self.current_text()) + self._update_style() + + def discard_changes(self): + orig_value = self._get_local_settings_item( + self.project_name, self.local_project_settings_orig + ) + self._set_current_text(orig_value) + + def _show_actions(self): + if self.project_name is None: + return + + menu = QtWidgets.QMenu(self) + actions_mapping = {} + + if self.project_name == DEFAULT_PROJECT_KEY: + remove_label = LABEL_REMOVE_DEFAULT + add_label = LABEL_ADD_DEFAULT + else: + remove_label = LABEL_REMOVE_PROJECT + add_label = LABEL_ADD_PROJECT + + has_value = self._get_local_settings_item(self.project_name) + if has_value: + action = QtWidgets.QAction(remove_label) + callback = self._remove_from_local + else: + action = QtWidgets.QAction(add_label) + callback = self._add_to_local + + actions_mapping[action] = callback + menu.addAction(action) + + if self.is_modified(): + discard_changes_action = QtWidgets.QAction(LABEL_DISCARD_CHANGES) + actions_mapping[discard_changes_action] = self.discard_changes + menu.addAction(discard_changes_action) + + result = menu.exec_(QtGui.QCursor.pos()) + if result: + to_run = actions_mapping[result] + if to_run: + to_run() + + def update_local_settings(self, local_project_settings): + self.local_project_settings = local_project_settings + self.local_project_settings_orig = copy.deepcopy( + dict(local_project_settings) + ) + + def current_text(self): + return self.combobox_input.currentText() + + def change_project(self, project_name): + self.default_override_value = None + self.project_override_value = None + + self.project_name = None + self.combobox_input.clear() + if project_name is None: + self._update_style() + return + + is_default_project = bool(project_name == DEFAULT_PROJECT_KEY) + site_items = self._get_project_sites() + self.combobox_input.addItems(site_items) + + default_item = self._get_local_settings_item(DEFAULT_PROJECT_KEY) + if is_default_project: + project_item = None + else: + project_item = self._get_local_settings_item(project_name) + + index = None + if project_item: + idx = self.combobox_input.findText(project_item) + if idx >= 0: + self.project_override_value = project_item + index = idx + + if default_item: + idx = self.combobox_input.findText(default_item) + if idx >= 0: + self.default_override_value = default_item + if index is None: + index = idx + + if index is None: + settings_value = self._get_value_from_project_settings() + idx = self.combobox_input.findText(settings_value) + if idx >= 0: + index = idx + + if index is not None: + self.combobox_input.setCurrentIndex(index) + + self.project_name = project_name + self._update_style() + + def _on_index_change(self): + if self.project_name is None: + return + + self._set_local_settings_value(self.current_text()) + self._update_style() + + def _set_local_settings_value(self, value): + raise NotImplementedError( + "{} `_set_local_settings_value` not implemented".format( + self.__class__.__name__ + ) + ) + + def _get_project_sites(self): + raise NotImplementedError( + "{} `_get_project_sites` not implemented".format( + self.__class__.__name__ + ) + ) + + def _get_local_settings_item(self, project_name=None, data=None): + raise NotImplementedError( + "{}`_get_local_settings_item` not implemented".format( + self.__class__.__name__ + ) + ) + + def _get_value_from_project_settings(self): + raise NotImplementedError( + "{}`_get_value_from_project_settings` not implemented".format( + self.__class__.__name__ + ) + ) + + +class AciveSiteCombo(_SiteCombobox): + input_label = "Active site" + + def _get_project_sites(self): + return get_active_sites(self.project_settings) + + def _get_local_settings_item(self, project_name=None, data=None): + if project_name is None: + project_name = self.project_name + + if data is None: + data = self.local_project_settings + project_values = data.get(project_name) + value = None + if project_values: + value = project_values.get("active_site") + return value + + def _get_value_from_project_settings(self): + global_entity = self.project_settings["project_settings"]["global"] + return global_entity["sync_server"]["config"]["active_site"].value + + def _set_local_settings_value(self, value): + if self.project_name not in self.local_project_settings: + self.local_project_settings[self.project_name] = {} + self.local_project_settings[self.project_name]["active_site"] = value + + +class RemoteSiteCombo(_SiteCombobox): + input_label = "Remote site" + + def _get_project_sites(self): + global_entity = self.project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) + + def _get_local_settings_item(self, project_name=None, data=None): + if project_name is None: + project_name = self.project_name + if data is None: + data = self.local_project_settings + project_values = data.get(project_name) + value = None + if project_values: + value = project_values.get("remote_site") + return value + + def _get_value_from_project_settings(self): + global_entity = self.project_settings["project_settings"]["global"] + return global_entity["sync_server"]["config"]["remote_site"].value + + def _set_local_settings_value(self, value): + if self.project_name not in self.local_project_settings: + self.local_project_settings[self.project_name] = {} + self.local_project_settings[self.project_name]["remote_site"] = value + + +class RootSiteWidget(QtWidgets.QWidget): + def __init__(self, project_settings, parent): + self._parent_widget = parent + super(RootSiteWidget, self).__init__(parent) + + self.project_settings = project_settings + self._project_name = None + + sites_widget = QtWidgets.QWidget(self) + + active_site_widget = AciveSiteCombo(project_settings, sites_widget) + remote_site_widget = RemoteSiteCombo(project_settings, sites_widget) + + sites_layout = QtWidgets.QHBoxLayout(sites_widget) + sites_layout.setContentsMargins(0, 0, 0, 0) + sites_layout.addWidget(active_site_widget) + sites_layout.addWidget(remote_site_widget) + sites_layout.addWidget(SpacerWidget(self), 1) + + roots_widget = RootsWidget(project_settings, self) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.addWidget(sites_widget) + main_layout.addWidget(roots_widget) + main_layout.addWidget(SpacerWidget(self), 1) + + self.active_site_widget = active_site_widget + self.remote_site_widget = remote_site_widget + self.roots_widget = roots_widget + + def _active_site_values(self): + global_entity = self.project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) + + def _remote_site_values(self): + global_entity = self.project_settings["project_settings"]["global"] + sites_entity = global_entity["sync_server"]["sites"] + return tuple(sites_entity.keys()) + + def update_local_settings(self, local_project_settings): + self.local_project_settings = local_project_settings + self.active_site_widget.update_local_settings(local_project_settings) + self.remote_site_widget.update_local_settings(local_project_settings) + self.roots_widget.update_local_settings(local_project_settings) + project_name = self._project_name + if project_name is None: + project_name = DEFAULT_PROJECT_KEY + + self.change_project(project_name) + + def change_project(self, project_name): + self._project_name = project_name + # Set roots project to None so all changes below are ignored + self.roots_widget.change_project(None) + + # Aply changes in site comboboxes + self.active_site_widget.change_project(project_name) + self.remote_site_widget.change_project(project_name) + + # Change project name in roots widget + self.roots_widget.change_project(project_name) + + +class ProjectValue(dict): + pass + + +class ProjectSettingsWidget(QtWidgets.QWidget): + def __init__(self, project_settings, parent): + super(ProjectSettingsWidget, self).__init__(parent) + + self.local_project_settings = {} + + projects_widget = _ProjectListWidget(self) + roos_site_widget = RootSiteWidget(project_settings, self) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.addWidget(projects_widget, 0) + main_layout.addWidget(roos_site_widget, 1) + + projects_widget.project_changed.connect(self._on_project_change) + + self.project_settings = project_settings + + self.projects_widget = projects_widget + self.roos_site_widget = roos_site_widget + + def project_name(self): + return self.projects_widget.project_name() + + def _on_project_change(self): + project_name = self.project_name() + self.project_settings.change_project(project_name) + if project_name is None: + project_name = DEFAULT_PROJECT_KEY + self.roos_site_widget.change_project(project_name) + + def update_local_settings(self, value): + if not value: + value = {} + self.local_project_settings = ProjectValue(value) + + self.roos_site_widget.update_local_settings( + self.local_project_settings + ) + + self.projects_widget.refresh() + + def _clear_value(self, value): + if not value: + return None + + if not isinstance(value, dict): + return value + + output = {} + for _key, _value in value.items(): + _modified_value = self._clear_value(_value) + if _modified_value: + output[_key] = _modified_value + return output + + def settings_value(self): + output = self._clear_value(self.local_project_settings) + if not output: + return None + return output diff --git a/pype/tools/settings/local_settings/widgets.py b/pype/tools/settings/local_settings/widgets.py new file mode 100644 index 0000000000..1b077f93be --- /dev/null +++ b/pype/tools/settings/local_settings/widgets.py @@ -0,0 +1,59 @@ +from Qt import QtWidgets, QtCore +from pype.tools.settings.settings.widgets.widgets import ( + ExpandingWidget, + SpacerWidget +) + + +class Separator(QtWidgets.QFrame): + def __init__(self, height=None, parent=None): + super(Separator, self).__init__(parent) + if height is None: + height = 2 + + splitter_item = QtWidgets.QWidget(self) + splitter_item.setStyleSheet("background-color: #21252B;") + splitter_item.setMinimumHeight(height) + splitter_item.setMaximumHeight(height) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(5, 5, 5, 5) + layout.addWidget(splitter_item) + + +class ProxyLabelWidget(QtWidgets.QWidget): + def __init__(self, label, mouse_release_callback, parent=None): + super(ProxyLabelWidget, self).__init__(parent) + + self.mouse_release_callback = mouse_release_callback + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + label_widget = QtWidgets.QLabel(label, self) + layout.addWidget(label_widget) + + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + self.label_widget = label_widget + + def setText(self, text): + self.label_widget.setText(text) + + def set_label_property(self, *args, **kwargs): + self.label_widget.setProperty(*args, **kwargs) + self.label_widget.style().polish(self.label_widget) + + def mouseReleaseEvent(self, event): + if self.mouse_release_callback: + return self.mouse_release_callback(event) + return super(ProxyLabelWidget, self).mouseReleaseEvent(event) + + +__all__ = ( + "ExpandingWidget", + "SpacerWidget", + "Separator", + "SpacerWidget" +) diff --git a/pype/tools/settings/local_settings/window.py b/pype/tools/settings/local_settings/window.py new file mode 100644 index 0000000000..87a276c78c --- /dev/null +++ b/pype/tools/settings/local_settings/window.py @@ -0,0 +1,204 @@ +import logging +from Qt import QtWidgets, QtGui + +from ..settings import style + +from pype.settings.lib import ( + get_local_settings, + save_local_settings +) +from pype.api import ( + SystemSettings, + ProjectSettings +) + +from .widgets import ( + SpacerWidget, + ExpandingWidget +) +from .mongo_widget import PypeMongoWidget +from .general_widget import LocalGeneralWidgets +from .apps_widget import LocalApplicationsWidgets +from .projects_widget import ProjectSettingsWidget + +from .constants import ( + CHILD_OFFSET, + LOCAL_GENERAL_KEY, + LOCAL_PROJECTS_KEY, + LOCAL_APPS_KEY +) + +log = logging.getLogger(__name__) + + +class LocalSettingsWidget(QtWidgets.QWidget): + def __init__(self, parent=None): + super(LocalSettingsWidget, self).__init__(parent) + + self.system_settings = SystemSettings() + self.project_settings = ProjectSettings() + + self.main_layout = QtWidgets.QVBoxLayout(self) + + self.pype_mongo_widget = None + self.general_widget = None + self.apps_widget = None + self.projects_widget = None + + self._create_pype_mongo_ui() + self._create_general_ui() + self._create_app_ui() + self._create_project_ui() + + # Add spacer to main layout + self.main_layout.addWidget(SpacerWidget(self), 1) + + def _create_pype_mongo_ui(self): + pype_mongo_expand_widget = ExpandingWidget("Pype Mongo URL", self) + pype_mongo_content = QtWidgets.QWidget(self) + pype_mongo_layout = QtWidgets.QVBoxLayout(pype_mongo_content) + pype_mongo_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + pype_mongo_expand_widget.set_content_widget(pype_mongo_content) + + pype_mongo_widget = PypeMongoWidget(self) + pype_mongo_layout.addWidget(pype_mongo_widget) + + self.main_layout.addWidget(pype_mongo_expand_widget) + + self.pype_mongo_widget = pype_mongo_widget + + def _create_general_ui(self): + # General + general_expand_widget = ExpandingWidget("General", self) + + general_content = QtWidgets.QWidget(self) + general_layout = QtWidgets.QVBoxLayout(general_content) + general_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + general_expand_widget.set_content_widget(general_content) + + general_widget = LocalGeneralWidgets(general_content) + general_layout.addWidget(general_widget) + + self.main_layout.addWidget(general_expand_widget) + + self.general_widget = general_widget + + def _create_app_ui(self): + # Applications + app_expand_widget = ExpandingWidget("Applications", self) + + app_content = QtWidgets.QWidget(self) + app_layout = QtWidgets.QVBoxLayout(app_content) + app_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + app_expand_widget.set_content_widget(app_content) + + app_widget = LocalApplicationsWidgets( + self.system_settings, app_content + ) + app_layout.addWidget(app_widget) + + self.main_layout.addWidget(app_expand_widget) + + self.app_widget = app_widget + + def _create_project_ui(self): + project_expand_widget = ExpandingWidget("Project settings", self) + project_content = QtWidgets.QWidget(self) + project_layout = QtWidgets.QVBoxLayout(project_content) + project_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + project_expand_widget.set_content_widget(project_content) + + projects_widget = ProjectSettingsWidget(self.project_settings, self) + project_layout.addWidget(projects_widget) + + self.main_layout.addWidget(project_expand_widget) + + self.projects_widget = projects_widget + + def update_local_settings(self, value): + if not value: + value = {} + + self.system_settings.reset() + self.project_settings.reset() + + self.general_widget.update_local_settings( + value.get(LOCAL_GENERAL_KEY) + ) + self.app_widget.update_local_settings( + value.get(LOCAL_APPS_KEY) + ) + self.projects_widget.update_local_settings( + value.get(LOCAL_PROJECTS_KEY) + ) + + def settings_value(self): + output = {} + general_value = self.general_widget.settings_value() + if general_value: + output[LOCAL_GENERAL_KEY] = general_value + + app_value = self.app_widget.settings_value() + if app_value: + output[LOCAL_APPS_KEY] = app_value + + projects_value = self.projects_widget.settings_value() + if projects_value: + output[LOCAL_PROJECTS_KEY] = projects_value + return output + + +class LocalSettingsWindow(QtWidgets.QWidget): + def __init__(self, parent=None): + super(LocalSettingsWindow, self).__init__(parent) + + self.resize(1000, 600) + + self.setWindowTitle("Pype Local settings") + + stylesheet = style.load_stylesheet() + self.setStyleSheet(stylesheet) + self.setWindowIcon(QtGui.QIcon(style.app_icon_path())) + + scroll_widget = QtWidgets.QScrollArea(self) + scroll_widget.setObjectName("GroupWidget") + settings_widget = LocalSettingsWidget(scroll_widget) + + scroll_widget.setWidget(settings_widget) + scroll_widget.setWidgetResizable(True) + + footer = QtWidgets.QWidget(self) + + save_btn = QtWidgets.QPushButton("Save", footer) + reset_btn = QtWidgets.QPushButton("Reset", footer) + + footer_layout = QtWidgets.QHBoxLayout(footer) + footer_layout.addWidget(reset_btn, 0) + footer_layout.addWidget(SpacerWidget(footer), 1) + footer_layout.addWidget(save_btn, 0) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.addWidget(scroll_widget, 1) + main_layout.addWidget(footer, 0) + + save_btn.clicked.connect(self._on_save_clicked) + reset_btn.clicked.connect(self._on_reset_clicked) + + self.settings_widget = settings_widget + self.reset_btn = reset_btn + self.save_btn = save_btn + + self.reset() + + def reset(self): + value = get_local_settings() + self.settings_widget.update_local_settings(value) + + def _on_reset_clicked(self): + self.reset() + + def _on_save_clicked(self): + value = self.settings_widget.settings_value() + save_local_settings(value) + self.reset() diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 692e9a9859..4010b8ab20 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -1,4 +1,6 @@ from Qt import QtWidgets, QtGui, QtCore +from .lib import CHILD_OFFSET +from .widgets import ExpandingWidget class BaseWidget(QtWidgets.QWidget): @@ -161,27 +163,92 @@ class BaseWidget(QtWidgets.QWidget): class InputWidget(BaseWidget): + def create_ui(self): + if self.entity.use_label_wrap: + label = None + self._create_label_wrap_ui() + else: + label = self.entity.label + self.label_widget = None + self.body_widget = None + self.content_widget = self + self.content_layout = self._create_layout(self) + + self._add_inputs_to_layout() + + self.entity_widget.add_widget_to_layout(self, label) + + def _create_label_wrap_ui(self): + content_widget = QtWidgets.QWidget(self) + content_widget.setObjectName("ContentWidget") + + content_widget.setProperty("content_state", "") + content_layout_margins = (CHILD_OFFSET, 5, 0, 0) + + body_widget = ExpandingWidget(self.entity.label, self) + label_widget = body_widget.label_widget + body_widget.set_content_widget(content_widget) + + content_layout = self._create_layout(content_widget) + content_layout.setContentsMargins(*content_layout_margins) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + main_layout.addWidget(body_widget) + + self.label_widget = label_widget + self.body_widget = body_widget + self.content_widget = content_widget + self.content_layout = content_layout + + def _create_layout(self, parent_widget): + layout = QtWidgets.QHBoxLayout(parent_widget) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + return layout + + def _add_inputs_to_layout(self): + raise NotImplementedError( + "Method `_add_inputs_to_layout` not implemented {}".format( + self.__class__.__name__ + ) + ) + def update_style(self): has_unsaved_changes = self.entity.has_unsaved_changes if not has_unsaved_changes and self.entity.group_item: has_unsaved_changes = self.entity.group_item.has_unsaved_changes - state = self.get_style_state( + style_state = self.get_style_state( self.is_invalid, has_unsaved_changes, self.entity.has_project_override, self.entity.has_studio_override ) - if self._style_state == state: + if self._style_state == style_state: return - self._style_state = state + self._style_state = style_state - self.input_field.setProperty("input-state", state) + self.input_field.setProperty("input-state", style_state) self.input_field.style().polish(self.input_field) if self.label_widget: - self.label_widget.setProperty("state", state) + self.label_widget.setProperty("state", style_state) self.label_widget.style().polish(self.label_widget) + if self.body_widget: + if style_state: + child_style_state = "child-{}".format(style_state) + else: + child_style_state = "" + + self.body_widget.side_line_widget.setProperty( + "state", child_style_state + ) + self.body_widget.side_line_widget.style().polish( + self.body_widget.side_line_widget + ) + @property def child_invalid(self): return self.is_invalid diff --git a/pype/tools/settings/settings/widgets/item_widgets.py b/pype/tools/settings/settings/widgets/item_widgets.py index fd33f337d7..bdc96840f2 100644 --- a/pype/tools/settings/settings/widgets/item_widgets.py +++ b/pype/tools/settings/settings/widgets/item_widgets.py @@ -24,21 +24,30 @@ from .lib import CHILD_OFFSET class DictImmutableKeysWidget(BaseWidget): def create_ui(self): - self._child_style_state = "" self.input_fields = [] self.checkbox_child = None - if not self.entity.is_dynamic_item and not self.entity.label: - self._ui_item_without_label() + + self.label_widget = None + self.body_widget = None + self.content_widget = None + self.content_layout = None + + label = None + if self.entity.is_dynamic_item: + self._ui_as_dynamic_item() + + elif self.entity.use_label_wrap: + self._ui_label_wrap() + self.checkbox_child = self.entity.non_gui_children.get( + self.entity.checkbox_key + ) else: - self._ui_item_or_as_widget() - if not self.entity.is_dynamic_item: - self.checkbox_child = self.entity.non_gui_children.get( - self.entity.checkbox_key - ) + self._ui_item_base() + label = self.entity.label - self.widget_mapping = {} - self.wrapper_widgets_by_id = {} + self._parent_widget_by_entity_id = {} + self._added_wrapper_ids = set() self._prepare_entity_layouts( self.entity.gui_layout, self.content_widget ) @@ -50,13 +59,13 @@ class DictImmutableKeysWidget(BaseWidget): ) ) - self.entity_widget.add_widget_to_layout(self) + self.entity_widget.add_widget_to_layout(self, label) def _prepare_entity_layouts(self, children, widget): for child in children: if not isinstance(child, dict): if child is not self.checkbox_child: - self.widget_mapping[child.id] = widget + self._parent_widget_by_entity_id[child.id] = widget continue if child["type"] == "collapsible-wrap": @@ -70,73 +79,77 @@ class DictImmutableKeysWidget(BaseWidget): "Unknown Wrapper type \"{}\"".format(child["type"]) ) - self.widget_mapping[wrapper.id] = widget - self.wrapper_widgets_by_id[wrapper.id] = wrapper - self.add_widget_to_layout(wrapper) + self._parent_widget_by_entity_id[wrapper.id] = widget + self._prepare_entity_layouts(child["children"], wrapper) - def _ui_item_without_label(self): + def _ui_item_base(self): self.setObjectName("DictInvisible") - self.body_widget = None self.content_widget = self self.content_layout = QtWidgets.QGridLayout(self) self.content_layout.setContentsMargins(0, 0, 0, 0) self.content_layout.setSpacing(5) - def _ui_item_or_as_widget(self): + def _ui_as_dynamic_item(self): content_widget = QtWidgets.QWidget(self) + content_widget.setObjectName("DictAsWidgetBody") - if self.entity.is_dynamic_item: - content_widget.setObjectName("DictAsWidgetBody") - show_borders = str(int(self.entity.show_borders)) - content_widget.setProperty("show_borders", show_borders) - content_layout_margins = (5, 5, 5, 5) - main_layout_spacing = 5 - body_widget = None - label_widget = QtWidgets.QLabel(self.entity.label) + show_borders = str(int(self.entity.show_borders)) + content_widget.setProperty("show_borders", show_borders) + label_widget = QtWidgets.QLabel(self.entity.label) + + content_layout = QtWidgets.QGridLayout(content_widget) + content_layout.setContentsMargins(5, 5, 5, 5) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(5) + main_layout.addWidget(content_widget) + + self.label_widget = label_widget + self.content_widget = content_widget + self.content_layout = content_layout + + def _ui_label_wrap(self): + content_widget = QtWidgets.QWidget(self) + content_widget.setObjectName("ContentWidget") + + if self.entity.highlight_content: + content_state = "hightlighted" + bottom_margin = 5 else: - content_widget.setObjectName("ContentWidget") - if self.entity.highlight_content: - content_state = "hightlighted" - bottom_margin = 5 - else: - content_state = "" - bottom_margin = 0 - content_widget.setProperty("content_state", content_state) - content_layout_margins = (CHILD_OFFSET, 5, 0, bottom_margin) - main_layout_spacing = 0 + content_state = "" + bottom_margin = 0 + content_widget.setProperty("content_state", content_state) + content_layout_margins = (CHILD_OFFSET, 5, 0, bottom_margin) - body_widget = ExpandingWidget(self.entity.label, self) - label_widget = body_widget.label_widget - body_widget.set_content_widget(content_widget) + body_widget = ExpandingWidget(self.entity.label, self) + label_widget = body_widget.label_widget + body_widget.set_content_widget(content_widget) content_layout = QtWidgets.QGridLayout(content_widget) content_layout.setContentsMargins(*content_layout_margins) main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) - main_layout.setSpacing(main_layout_spacing) - if not body_widget: - main_layout.addWidget(content_widget) - else: - main_layout.addWidget(body_widget) + main_layout.setSpacing(0) + main_layout.addWidget(body_widget) self.label_widget = label_widget self.body_widget = body_widget self.content_widget = content_widget self.content_layout = content_layout - if body_widget: - if len(self.input_fields) == 1 and self.checkbox_widget: - body_widget.hide_toolbox(hide_content=True) + if len(self.input_fields) == 1 and self.checkbox_widget: + body_widget.hide_toolbox(hide_content=True) - elif self.entity.collapsible: - if not self.entity.collapsed: - body_widget.toggle_content() - else: - body_widget.hide_toolbox(hide_content=False) + elif self.entity.collapsible: + if not self.entity.collapsed: + body_widget.toggle_content() + else: + body_widget.hide_toolbox(hide_content=False) def add_widget_to_layout(self, widget, label=None): if self.checkbox_child and widget.entity is self.checkbox_child: @@ -148,9 +161,12 @@ class DictImmutableKeysWidget(BaseWidget): else: map_id = widget.entity.id - wrapper = self.widget_mapping[map_id] + wrapper = self._parent_widget_by_entity_id[map_id] if wrapper is not self.content_widget: wrapper.add_widget_to_layout(widget, label) + if wrapper.id not in self._added_wrapper_ids: + self.add_widget_to_layout(wrapper) + self._added_wrapper_ids.add(wrapper.id) return row = self.content_layout.rowCount() @@ -172,7 +188,7 @@ class DictImmutableKeysWidget(BaseWidget): for input_field in self.input_fields: input_field.hierarchical_style_update() - def update_style(self, is_overriden=None): + def update_style(self): if not self.body_widget and not self.label_widget: return @@ -186,36 +202,8 @@ class DictImmutableKeysWidget(BaseWidget): has_project_override = self.entity.has_project_override has_studio_override = self.entity.has_studio_override - is_invalid = self.is_invalid - if self.body_widget: - child_style_state = self.get_style_state( - is_invalid, - has_unsaved_changes, - has_project_override, - has_studio_override - ) - - if child_style_state: - child_style_state = "child-{}".format(child_style_state) - - if self._child_style_state != child_style_state: - self.body_widget.side_line_widget.setProperty( - "state", child_style_state - ) - self.body_widget.side_line_widget.style().polish( - self.body_widget.side_line_widget - ) - self._child_style_state = child_style_state - - # There is nothing to care if there is no label - if not self.label_widget: - return - # Don't change label if is not group or under group item - if not self.entity.is_group and not self.entity.group_item: - return - style_state = self.get_style_state( - is_invalid, + self.is_invalid, has_unsaved_changes, has_project_override, has_studio_override @@ -223,11 +211,32 @@ class DictImmutableKeysWidget(BaseWidget): if self._style_state == style_state: return + self._style_state = style_state + + if self.body_widget: + if style_state: + child_style_state = "child-{}".format(style_state) + else: + child_style_state = "" + + self.body_widget.side_line_widget.setProperty( + "state", child_style_state + ) + self.body_widget.side_line_widget.style().polish( + self.body_widget.side_line_widget + ) + + # There is nothing to care if there is no label + if not self.label_widget: + return + + # Don't change label if is not group or under group item + if not self.entity.is_group and not self.entity.group_item: + return + self.label_widget.setProperty("state", style_state) self.label_widget.style().polish(self.label_widget) - self._style_state = style_state - def _on_entity_change(self): pass @@ -250,26 +259,23 @@ class DictImmutableKeysWidget(BaseWidget): class BoolWidget(InputWidget): - def create_ui(self): + def _add_inputs_to_layout(self): checkbox_height = self.style().pixelMetric( QtWidgets.QStyle.PM_IndicatorHeight ) - self.input_field = NiceCheckbox(height=checkbox_height, parent=self) + self.input_field = NiceCheckbox( + height=checkbox_height, parent=self.content_widget + ) - spacer = QtWidgets.QWidget(self) + spacer = QtWidgets.QWidget(self.content_widget) spacer.setAttribute(QtCore.Qt.WA_TranslucentBackground) - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - layout.addWidget(self.input_field, 0) - layout.addWidget(spacer, 1) + self.content_layout.addWidget(self.input_field, 0) + self.content_layout.addWidget(spacer, 1) self.setFocusProxy(self.input_field) self.input_field.stateChanged.connect(self._on_value_change) - self.entity_widget.add_widget_to_layout(self, self.entity.label) def _on_entity_change(self): if self.entity.value != self.input_field.isChecked(): @@ -285,12 +291,12 @@ class BoolWidget(InputWidget): class TextWidget(InputWidget): - def create_ui(self): + def _add_inputs_to_layout(self): multiline = self.entity.multiline if multiline: - self.input_field = QtWidgets.QPlainTextEdit(self) + self.input_field = QtWidgets.QPlainTextEdit(self.content_widget) else: - self.input_field = QtWidgets.QLineEdit(self) + self.input_field = QtWidgets.QLineEdit(self.content_widget) placeholder_text = self.entity.placeholder_text if placeholder_text: @@ -302,15 +308,10 @@ class TextWidget(InputWidget): if multiline: layout_kwargs["alignment"] = QtCore.Qt.AlignTop - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - layout.addWidget(self.input_field, 1, **layout_kwargs) + self.content_layout.addWidget(self.input_field, 1, **layout_kwargs) self.input_field.textChanged.connect(self._on_value_change) - self.entity_widget.add_widget_to_layout(self, self.entity.label) - def _on_entity_change(self): if self.entity.value != self.input_value(): self.set_entity_value() @@ -335,26 +336,20 @@ class TextWidget(InputWidget): class NumberWidget(InputWidget): - def create_ui(self): - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - + def _add_inputs_to_layout(self): kwargs = { "minimum": self.entity.minimum, "maximum": self.entity.maximum, "decimal": self.entity.decimal } - self.input_field = NumberSpinBox(self, **kwargs) + self.input_field = NumberSpinBox(self.content_widget, **kwargs) self.setFocusProxy(self.input_field) - layout.addWidget(self.input_field, 1) + self.content_layout.addWidget(self.input_field, 1) self.input_field.valueChanged.connect(self._on_value_change) - self.entity_widget.add_widget_to_layout(self, self.entity.label) - def _on_entity_change(self): if self.entity.value != self.input_field.value(): self.set_entity_value() @@ -419,12 +414,8 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): class RawJsonWidget(InputWidget): - def create_ui(self): - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - self.input_field = RawJsonInput(self) + def _add_inputs_to_layout(self): + self.input_field = RawJsonInput(self.content_widget) self.input_field.setSizePolicy( QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding @@ -432,10 +423,11 @@ class RawJsonWidget(InputWidget): self.setFocusProxy(self.input_field) - layout.addWidget(self.input_field, 1, alignment=QtCore.Qt.AlignTop) + self.content_layout.addWidget( + self.input_field, 1, alignment=QtCore.Qt.AlignTop + ) self.input_field.textChanged.connect(self._on_value_change) - self.entity_widget.add_widget_to_layout(self, self.entity.label) def set_entity_value(self): self.input_field.set_value(self.entity.value) @@ -463,31 +455,24 @@ class RawJsonWidget(InputWidget): class EnumeratorWidget(InputWidget): - def create_ui(self): - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - + def _add_inputs_to_layout(self): if self.entity.multiselection: self.input_field = MultiSelectionComboBox( - placeholder=self.entity.placeholder, parent=self + placeholder=self.entity.placeholder, parent=self.content_widget ) - model = self.input_field.model() - for idx in range(self.input_field.count()): - model.item(idx).setCheckable(True) + else: - self.input_field = ComboBox(self) + self.input_field = ComboBox(self.content_widget) for enum_item in self.entity.enum_items: for value, label in enum_item.items(): self.input_field.addItem(label, value) - layout.addWidget(self.input_field, 0) + self.content_layout.addWidget(self.input_field, 0) self.setFocusProxy(self.input_field) self.input_field.value_changed.connect(self._on_value_change) - self.entity_widget.add_widget_to_layout(self, self.entity.label) def _on_entity_change(self): if self.entity.value != self.input_field.value(): @@ -572,12 +557,8 @@ class PathWidget(BaseWidget): class PathInputWidget(InputWidget): - def create_ui(self, label_widget=None): - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - self.input_field = QtWidgets.QLineEdit(self) + def _add_inputs_to_layout(self): + self.input_field = QtWidgets.QLineEdit(self.content_widget) self.args_input_field = None if self.entity.with_arguments: self.input_field.setPlaceholderText("Executable path") @@ -585,15 +566,13 @@ class PathInputWidget(InputWidget): self.args_input_field.setPlaceholderText("Arguments") self.setFocusProxy(self.input_field) - layout.addWidget(self.input_field, 8) + self.content_layout.addWidget(self.input_field, 8) self.input_field.textChanged.connect(self._on_value_change) if self.args_input_field: - layout.addWidget(self.args_input_field, 2) + self.content_layout.addWidget(self.args_input_field, 2) self.args_input_field.textChanged.connect(self._on_value_change) - self.entity_widget.add_widget_to_layout(self, self.entity.label) - def _on_entity_change(self): if self.entity.value != self.input_value(): self.set_entity_value() diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 9a99561ea8..da9cdd75cf 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -54,11 +54,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self.setItemDelegate(self.delegate) self.lines = {} - self.item_height = ( - self.fontMetrics().height() - + (2 * self.top_bottom_padding) - + (2 * self.top_bottom_margins) - ) + self.item_height = None def mousePressEvent(self, event): """Reimplemented.""" @@ -157,6 +153,11 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): return super(MultiSelectionComboBox, self).eventFilter(obj, event) + def addItem(self, *args, **kwargs): + idx = self.count() + super(MultiSelectionComboBox, self).addItem(*args, **kwargs) + self.model().item(idx).setCheckable(True) + def paintEvent(self, event): """Reimplemented.""" painter = QtWidgets.QStylePainter(self) @@ -173,6 +174,12 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): return font_metricts = self.fontMetrics() + + if self.item_height is None: + self.updateGeometry() + self.update() + return + for line, items in self.lines.items(): top_y = ( option.rect.top() @@ -187,11 +194,13 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): label_rect.moveTop(top_y) label_rect.moveLeft(left_x) label_rect.setHeight(self.item_height) + label_rect.setWidth( + label_rect.width() + self.left_right_padding + ) bg_rect = QtCore.QRectF(label_rect) bg_rect.setWidth( - label_rect.width() - + (2 * self.left_right_padding) + label_rect.width() + self.left_right_padding ) left_x = bg_rect.right() + self.item_spacing @@ -264,6 +273,13 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): lines = len(self.lines) if lines == 0: lines = 1 + + if self.item_height is None: + self.item_height = ( + self.fontMetrics().height() + + (2 * self.top_bottom_padding) + + (2 * self.top_bottom_margins) + ) value.setHeight( (lines * self.item_height) + (2 * self.top_bottom_margins) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index fd8d9d753c..656aaaa652 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -664,9 +664,8 @@ class ProjectListWidget(QtWidgets.QWidget): self.current_project = None if self.dbcon: - for project_doc in tuple(self.dbcon.projects()): - items.append(project_doc["name"]) - + for project_name in self.dbcon.database.collection_names(): + items.append(project_name) for item in items: model.appendRow(QtGui.QStandardItem(item)) diff --git a/pyproject.toml b/pyproject.toml index dc2a956cb5..0b5e8b451c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,15 +4,18 @@ version = "3.0.0" description = "Multi-platform open-source pipeline built around the Avalon platform, expanding it with extra features and integrations." authors = ["Pype Club "] license = "MIT License" +homepage = "https://pype.club" +documentation = "https://pype.club/docs/artist_getting_started" +repository = "https://github.com/pypeclub/pype" +readme = "README.md" +keywords = ["Pipeline", "Avalon", "VFX", "animation", "automation", "tracking", "asset management"] [tool.poetry.dependencies] python = "3.7.*" +aiohttp = "^3.7" aiohttp_json_rpc = "*" # TVPaint server acre = { git = "https://github.com/pypeclub/acre.git" } -opentimelineio = [ - { git = "https://github.com/pypeclub/OpenTimelineIO.git", branch="develop", markers = "sys_platform == 'win32'" }, - { git = "https://github.com/PixarAnimationStudios/OpenTimelineIO.git", markers = "sys_platform == 'darwin'" } -] +opentimelineio = { version = "0.14.0.dev1", source = "pype" } appdirs = "^1.4.3" blessed = "^1.17" # pype terminal formatting clique = "1.5.*" @@ -33,13 +36,17 @@ speedcopy = "^2.1" six = "^1.15" wsrpc_aiohttp = "^3.1.1" # websocket server pywin32 = { version = "300", markers = "sys_platform == 'win32'" } -jinxed = { version = "^1.0.1", markers = "sys_platform == 'darwin'" } +jinxed = [ + { version = "^1.0.1", markers = "sys_platform == 'darwin'" }, + { version = "^1.0.1", markers = "sys_platform == 'linux'" } +] +python3-xlib = { version="*", markers = "sys_platform == 'linux'"} [tool.poetry.dev-dependencies] flake8 = "^3.7" autopep8 = "^1.4" coverage = "*" -cx_freeze = "^6.1" +cx_freeze = "^6.5" jedi = "^0.13" Jinja2 = "^2.11" pycodestyle = "^2.5.0" @@ -56,6 +63,14 @@ recommonmark = "*" tqdm = "*" wheel = "*" +[tool.poetry.urls] +"Bug Tracker" = "https://github.com/pypeclub/pype/issues" +"Discussions" = "https://github.com/pypeclub/pype/discussions" + +[[tool.poetry.source]] +name = "pype" +url = "https://d.r1.wbsprt.com/pype.club/distribute/" + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/repos/avalon-core b/repos/avalon-core index 93c4a89b3e..eae14f2960 160000 --- a/repos/avalon-core +++ b/repos/avalon-core @@ -1 +1 @@ -Subproject commit 93c4a89b3e98ae88030e62bb9ad6c07220b23234 +Subproject commit eae14f2960c4ccf2f0211e0726e88563129c0296 diff --git a/tools/build.sh b/tools/build.sh index 0b97e8d8df..27d10f1d4d 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -62,7 +62,7 @@ BIWhite='\033[1;97m' # White # None ############################################################################### detect_python () { - echo -e "${BIGreen}>>>${RST} Using Python \c" + echo -e "${BIGreen}>>>${RST} Using python \c" local version_command version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))" local python_version @@ -72,9 +72,13 @@ detect_python () { set -- $python_version IFS="$oIFS" if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then - echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" + if [ "$2" -gt "7" ] ; then + echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1; + else + echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" + fi else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; } + command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } fi } @@ -88,7 +92,8 @@ detect_python () { # None ############################################################################### clean_pyc () { - path=${1:-$pype_root} + local path + path=$pype_root echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" @@ -107,28 +112,58 @@ realpath () { echo $(cd $(dirname "$1") || return; pwd)/$(basename "$1") } +############################################################################## +# Install Poetry when needed +# Globals: +# PATH +# Arguments: +# None +# Returns: +# None +############################################################################### +install_poetry () { + echo -e "${BIGreen}>>>${RST} Installing Poetry ..." + command -v curl >/dev/null 2>&1 || { echo -e "${BIRed}!!!${RST}${BIYellow} Missing ${RST}${BIBlue}curl${BIYellow} command.${RST}"; return 1; } + curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - + export PATH="$PATH:$HOME/.poetry/bin" +} + # Main -echo -e "${BGreen}" -art -echo -e "${RST}" -detect_python || return 1 +main () { + echo -e "${BGreen}" + art + echo -e "${RST}" + detect_python || return 1 -# Directories -pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) -pushd "$pype_root" || return > /dev/null + # Directories + pype_root=$(dirname $(dirname "$(realpath ${BASH_SOURCE[0]})")) + pushd "$pype_root" > /dev/null || return > /dev/null -version_command="import os;exec(open(os.path.join('$pype_root', 'pype', 'version.py')).read());print(__version__);" -pype_version="$(python3 <<< ${version_command})" + version_command="import os;exec(open(os.path.join('$pype_root', 'pype', 'version.py')).read());print(__version__);" + pype_version="$(python3 <<< ${version_command})" -echo -e "${BIYellow}---${RST} Cleaning build directory ..." -rm -rf "$pype_root/build" && mkdir "$pype_root/build" > /dev/null + echo -e "${BIYellow}---${RST} Cleaning build directory ..." + rm -rf "$pype_root/build" && mkdir "$pype_root/build" > /dev/null -echo -e "${BIGreen}>>>${RST} Building Pype ${BIWhite}[${RST} ${BIGreen}$pype_version${RST} ${BIWhite}]${RST}" -echo -e "${BIGreen}>>>${RST} Cleaning cache files ..." -clean_pyc -echo -e "${BIGreen}>>>${RST} Building ..." -poetry run python "$pype_root/setup.py" build > "$pype_root/build/build.log" -poetry run python "$pype_root/tools/build_dependencies.py" + echo -e "${BIGreen}>>>${RST} Building Pype ${BIWhite}[${RST} ${BIGreen}$pype_version${RST} ${BIWhite}]${RST}" + echo -e "${BIGreen}>>>${RST} Cleaning cache files ..." + clean_pyc -echo -e "${BICyan}>>>${RST} All done. You will find Pype and build log in \c" -echo -e "${BIWhite}$pype_root/build${RST} directory." + echo -e "${BIGreen}>>>${RST} Reading Poetry ... \c" + if [ -f "$HOME/.poetry/bin/poetry" ]; then + echo -e "${BIGreen}OK${RST}" + export PATH="$PATH:$HOME/.poetry/bin" + else + echo -e "${BIYellow}NOT FOUND${RST}" + install_poetry || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return; } + fi + + echo -e "${BIGreen}>>>${RST} Building ..." + poetry run python3 "$pype_root/setup.py" build > "$pype_root/build/build.log" || { echo -e "${BIRed}!!!${RST} Build failed, see the build log."; return; } + poetry run python3 "$pype_root/tools/build_dependencies.py" + + echo -e "${BICyan}>>>${RST} All done. You will find Pype and build log in \c" + echo -e "${BIWhite}$pype_root/build${RST} directory." +} + +main diff --git a/tools/create_env.ps1 b/tools/create_env.ps1 index 1c5e6e35e6..1ea983cdd2 100644 --- a/tools/create_env.ps1 +++ b/tools/create_env.ps1 @@ -13,6 +13,12 @@ PS> .\create_env.ps1 #> +$arguments=$ARGS +$poetry_verbosity="" +if($arguments -eq "--verbose") { + $poetry_verbosity="-vvv" +} + function Exit-WithCode($exitcode) { # Only exit this host process if it's a child of another PowerShell parent process... $parentPID = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$PID" | Select-Object -Property ParentProcessId).ParentProcessId @@ -43,8 +49,40 @@ function Install-Poetry() { } -$current_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent -$pype_root = (Get-Item $current_dir).parent.FullName +function Test-Python() { + Write-Host ">>> " -NoNewline -ForegroundColor green + Write-Host "Detecting host Python ... " -NoNewline + if (-not (Get-Command "python" -ErrorAction SilentlyContinue)) { + Write-Host "!!! Python not detected" -ForegroundColor red + Set-Location -Path $current_dir + Exit-WithCode 1 + } + $version_command = @' +import sys +print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1])) +'@ + + $p = & python -c $version_command + $env:PYTHON_VERSION = $p + $m = $p -match '(\d+)\.(\d+)' + if(-not $m) { + Write-Host "!!! Cannot determine version" -ForegroundColor red + Set-Location -Path $current_dir + Exit-WithCode 1 + } + # We are supporting python 3.6 and up + if(($matches[1] -lt 3) -or ($matches[2] -lt 7)) { + Write-Host "FAILED Version [ $p ] is old and unsupported" -ForegroundColor red + Set-Location -Path $current_dir + Exit-WithCode 1 + } + Write-Host "OK [ $p ]" -ForegroundColor green +} + + +$current_dir = Get-Location +$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent +$pype_root = (Get-Item $script_dir).parent.FullName Set-Location -Path $pype_root @@ -72,33 +110,14 @@ $pype_version = $result[0].Groups['version'].Value if (-not $pype_version) { Write-Host "!!! " -ForegroundColor yellow -NoNewline Write-Host "Cannot determine Pype version." + Set-Location -Path $current_dir Exit-WithCode 1 } +Write-Host ">>> " -NoNewline -ForegroundColor Green +Write-Host "Found Pype version " -NoNewline +Write-Host "[ $($pype_version) ]" -ForegroundColor Green -Write-Host ">>> " -NoNewline -ForegroundColor green -Write-Host "Detecting host Python ... " -NoNewline -if (-not (Get-Command "python" -ErrorAction SilentlyContinue)) { - Write-Host "!!! Python not detected" -ForegroundColor red - Exit-WithCode 1 -} -$version_command = @' -import sys -print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1])) -'@ - -$p = & python -c $version_command -$env:PYTHON_VERSION = $p -$m = $p -match '(\d+)\.(\d+)' -if(-not $m) { - Write-Host "!!! Cannot determine version" -ForegroundColor red - Exit-WithCode 1 -} -# We are supporting python 3.6 and up -if(($matches[1] -lt 3) -or ($matches[2] -lt 7)) { - Write-Host "FAILED Version [ $p ] is old and unsupported" -ForegroundColor red - Exit-WithCode 1 -} -Write-Host "OK [ $p ]" -ForegroundColor green +Test-Python Write-Host ">>> " -NoNewline -ForegroundColor Green Write-Host "Reading Poetry ... " -NoNewline @@ -112,12 +131,17 @@ if (-not (Test-Path -PathType Container -Path "$($env:USERPROFILE)\.poetry\bin") if (-not (Test-Path -PathType Leaf -Path "$($pype_root)\poetry.lock")) { Write-Host ">>> " -NoNewline -ForegroundColor green - Write-Host "Creating virtual environment." - & poetry install + Write-Host "Installing virtual environment and creating lock." } else { Write-Host ">>> " -NoNewline -ForegroundColor green - Write-Host "Updating virtual environment." - & poetry update + Write-Host "Installing virtual environment from lock." +} +& poetry install $poetry_verbosity +if ($LASTEXITCODE -ne 0) { + Write-Host "!!! " -ForegroundColor yellow -NoNewline + Write-Host "Poetry command failed." + Set-Location -Path $current_dir + Exit-WithCode 1 } Set-Location -Path $current_dir Write-Host ">>> " -NoNewline -ForegroundColor green diff --git a/tools/create_env.sh b/tools/create_env.sh index 5e9f21abcc..52bc79ca83 100755 --- a/tools/create_env.sh +++ b/tools/create_env.sh @@ -52,6 +52,24 @@ BIPurple='\033[1;95m' # Purple BICyan='\033[1;96m' # Cyan BIWhite='\033[1;97m' # White + +poetry_verbosity="" +while :; do + case $1 in + --verbose) + poetry_verbosity="-vvv" + ;; + --) + shift + break + ;; + *) + break + esac + shift +done + + ############################################################################## # Detect required version of python # Globals: @@ -71,16 +89,20 @@ detect_python () { set -- $python_version IFS="$oIFS" if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then - echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" - PYTHON="python3" + if [ "$2" -gt "7" ] ; then + echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1; + else + echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" + fi else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; } + command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } fi } install_poetry () { echo -e "${BIGreen}>>>${RST} Installing Poetry ..." - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - + command -v curl >/dev/null 2>&1 || { echo -e "${BIRed}!!!${RST}${BIYellow} Missing ${RST}${BIBlue}curl${BIYellow} command.${RST}"; return 1; } + curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - export PATH="$PATH:$HOME/.poetry/bin" } @@ -94,8 +116,9 @@ install_poetry () { # None ############################################################################### clean_pyc () { - path=${1:-$pype_root} - echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" + local path + path=$pype_root + echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -113,32 +136,44 @@ realpath () { echo $(cd $(dirname "$1"); pwd)/$(basename "$1") } -# Main -echo -e "${BGreen}" -art -echo -e "${RST}" -detect_python || return 1 +main () { + # Main + echo -e "${BGreen}" + art + echo -e "${RST}" + detect_python || return 1 -# Directories -pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) -pushd "$pype_root" || return > /dev/null + # Directories + pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) + pushd "$pype_root" > /dev/null || return > /dev/null -echo -e "${BIGreen}>>>${RST} Reading Poetry ... \c" -if [ -f "$HOME/.poetry/bin/poetry" ]; then - echo -e "${BIGreen}OK${RST}" -else - echo -e "${BIYellow}NOT FOUND${RST}" - install_poetry -fi + echo -e "${BIGreen}>>>${RST} Reading Poetry ... \c" + if [ -f "$HOME/.poetry/bin/poetry" ]; then + echo -e "${BIGreen}OK${RST}" + export PATH="$PATH:$HOME/.poetry/bin" + else + echo -e "${BIYellow}NOT FOUND${RST}" + install_poetry || { echo -e "${BIRed}!!!${RST} Poetry installation failed"; return; } + fi -if [ -f "$pype_root/poetry.lock" ]; then - echo -e "${BIGreen}>>>${RST} Updating dependencies ..." - poetry update -else - echo -e "${BIGreen}>>>${RST} Installing dependencies ..." - poetry install -fi + if [ -f "$pype_root/poetry.lock" ]; then + echo -e "${BIGreen}>>>${RST} Updating dependencies ..." + else + echo -e "${BIGreen}>>>${RST} Installing dependencies ..." + fi -echo -e "${BIGreen}>>>${RST} Cleaning cache files ..." -clean_pyc + poetry install $poetry_verbosity || { echo -e "${BIRed}!!!${RST} Poetry environment installation failed"; return; } + echo -e "${BIGreen}>>>${RST} Cleaning cache files ..." + clean_pyc + + # 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 run python -m pip install --upgrade pip + poetry run pip install --force-reinstall setuptools + poetry run pip install --force-reinstall wheel +} + +main -3 diff --git a/tools/create_zip.ps1 b/tools/create_zip.ps1 index ee8da5acec..1780b0bb9a 100644 --- a/tools/create_zip.ps1 +++ b/tools/create_zip.ps1 @@ -33,8 +33,9 @@ function Show-PSWarning() { } } -$current_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent -$pype_root = (Get-Item $current_dir).parent.FullName +$current_dir = Get-Location +$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent +$pype_root = (Get-Item $script_dir).parent.FullName Set-Location -Path $pype_root $art = @" diff --git a/tools/create_zip.sh b/tools/create_zip.sh index a44d9d4be9..839b1c4827 100755 --- a/tools/create_zip.sh +++ b/tools/create_zip.sh @@ -70,10 +70,13 @@ detect_python () { set -- $python_version IFS="$oIFS" if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then - echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" - PYTHON="python3" + if [ "$2" -gt "7" ] ; then + echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1; + else + echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" + fi else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; } + command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } fi } @@ -87,8 +90,9 @@ detect_python () { # None ############################################################################### clean_pyc () { - path=${1:-$pype_root} - echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" + local path + path=$pype_root + echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -107,14 +111,18 @@ realpath () { } # Main -echo -e "${BGreen}" -art -echo -e "${RST}" -detect_python || return 1 +main () { + echo -e "${BGreen}" + art + echo -e "${RST}" + detect_python || return 1 -# Directories -pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))) -pushd "$pype_root" || return > /dev/null + # Directories + pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) + pushd "$pype_root" > /dev/null || return > /dev/null -echo -e "${BIGreen}>>>${RST} Generating zip from current sources ..." -poetry run python "$pype_root/start.py" generate-zip "$@" + echo -e "${BIGreen}>>>${RST} Generating zip from current sources ..." + poetry run python3 "$pype_root/start.py" generate-zip "$@" +} + +main "$@" diff --git a/tools/make_docs.sh b/tools/make_docs.sh index 68582ff5ae..ed5c72b055 100755 --- a/tools/make_docs.sh +++ b/tools/make_docs.sh @@ -65,17 +65,21 @@ realpath () { } # Main -echo -e "${BGreen}" -art -echo -e "${RST}" +main () { + echo -e "${BGreen}" + art + echo -e "${RST}" -# Directories -pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))) -pushd "$pype_root" || return > /dev/null + # Directories + pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) + pushd "$pype_root" > /dev/null || return > /dev/null -echo -e "${BIGreen}>>>${RST} Running apidoc ..." -poetry run sphinx-apidoc -M -e -d 10 --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode -o "$pype_root/docs/source" igniter -poetry run sphinx-apidoc -M -e -d 10 --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode -o "$pype_root/docs/source" pype vendor, pype\vendor + echo -e "${BIGreen}>>>${RST} Running apidoc ..." + poetry run sphinx-apidoc -M -e -d 10 --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode -o "$pype_root/docs/source" igniter + poetry run sphinx-apidoc -M -e -d 10 --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode -o "$pype_root/docs/source" pype vendor, pype\vendor -echo -e "${BIGreen}>>>${RST} Building html ..." -poetry run python "$pype_root/setup.py" build_sphinx + echo -e "${BIGreen}>>>${RST} Building html ..." + poetry run python3 "$pype_root/setup.py" build_sphinx +} + +main diff --git a/tools/run_mongo.ps1 b/tools/run_mongo.ps1 index 1b6d95ca57..a72c8b1210 100644 --- a/tools/run_mongo.ps1 +++ b/tools/run_mongo.ps1 @@ -44,18 +44,20 @@ function Find-Mongo { # we have mongo server installed on standard Windows location # so we can inject it to the PATH. We'll use latest version available. $mongoVersions = Get-ChildItem -Directory 'C:\Program Files\MongoDB\Server' | Sort-Object -Property {$_.Name -as [int]} - if(Test-Path "C:\Program Files\MongoDB\Server\$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) { - $env:PATH="$($env:PATH);C:\Program Files\MongoDB\Server\$($mongoVersions[-1])\bin\" + if(Test-Path "$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) { + $env:PATH="$($env:PATH);$($mongoVersions[-1])\bin\" Write-Host "OK" -ForegroundColor Green Write-Host " - auto-added from [ " -NoNewline - Write-Host "C:\Program Files\MongoDB\Server\$($mongoVersions[-1])\bin\" -NoNewLine -ForegroundColor Cyan + Write-Host "$($mongoVersions[-1])\bin\" -NoNewLine -ForegroundColor Cyan Write-Host " ]" } else { Write-Host "FAILED " -NoNewLine -ForegroundColor Red Write-Host "MongoDB not detected" -ForegroundColor Yellow - Write-Host "Tried to find it on standard location [ " -NoNewline -ForegroundColor Gray - Write-Host "C:\Program Files\MongoDB\Server\$($mongoVersions[-1])\bin\" -NoNewline -ForegroundColor White - Write-Host " ] but failed." -ForegroundColor Gray + Write-Host "Tried to find it on standard location " -NoNewline -ForegroundColor Gray + Write-Host " [ " -NoNewline -ForegroundColor Cyan + Write-Host "$($mongoVersions[-1])\bin\" -NoNewline -ForegroundColor White + Write-Host " ] " -NonNewLine -ForegroundColor Cyan + Write-Host "but failed." -ForegroundColor Gray Exit-WithCode 1 } } else { diff --git a/tools/run_mongo.sh b/tools/run_mongo.sh index 6f9e0f5411..209e80ac5b 100755 --- a/tools/run_mongo.sh +++ b/tools/run_mongo.sh @@ -66,18 +66,20 @@ realpath () { } # Main -echo -e "${BGreen}" -art -echo -e "${RST}" +main () { + echo -e "${BGreen}" + art + echo -e "${RST}" -# Directories -pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))) -pushd "$pype_root" > /dev/null + # Directories + pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))) + pushd "$pype_root" > /dev/null || return > /dev/null -mongo_port=2707 -echo $pype_root -dbpath="$(dirname $pype_root)/mongo_db_data" + mongo_port=2707 + dbpath="$(dirname $pype_root)/mongo_db_data" + + echo -e "${BIGreen}>>>${RST} Running mongodb ..." + mongod --dbpath "$dbpath" --port $mongo_port + echo -e "${BIGreen}>>>${RST} Detached to background." +} -echo -e "${BIGreen}>>>${RST} Running mongodb ..." -mongod --dbpath "$dbpath" --port $mongo_port -echo -e "${BIGreen}>>>${RST} Detached to background." diff --git a/tools/run_settings.ps1 b/tools/run_settings.ps1 index 48ea9befdf..acecae0bb6 100644 --- a/tools/run_settings.ps1 +++ b/tools/run_settings.ps1 @@ -11,6 +11,7 @@ PS> .\run_settings.ps1 #> +$current_dir = Get-Location $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent $pype_root = (Get-Item $script_dir).parent.FullName Set-Location -Path $pype_root diff --git a/tools/run_settings.sh b/tools/run_settings.sh index dbf1c5ba30..99148456c0 100755 --- a/tools/run_settings.sh +++ b/tools/run_settings.sh @@ -70,10 +70,13 @@ detect_python () { set -- $python_version IFS="$oIFS" if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then - echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" - PYTHON="python3" + if [ "$2" -gt "7" ] ; then + echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1; + else + echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" + fi else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; } + command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } fi } @@ -87,8 +90,9 @@ detect_python () { # None ############################################################################### clean_pyc () { - path=${1:-$pype_root} - echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" + local path + path=$pype_root + echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -107,15 +111,18 @@ realpath () { } # Main -echo -e "${BGreen}" -art -echo -e "${RST}" -detect_python || return 1 +main () { + echo -e "${BGreen}" + art + echo -e "${RST}" + detect_python || return 1 -# Directories -pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))) -pushd "$pype_root" || return> /dev/null + # Directories + pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) + pushd "$pype_root" > /dev/null || return > /dev/null -echo -e "${BIGreen}>>>${RST} Generating zip from current sources ..." -poetry run python "$pype_root/start.py" settings --dev + echo -e "${BIGreen}>>>${RST} Generating zip from current sources ..." + poetry run python3 "$pype_root/start.py" settings --dev +} +main diff --git a/tools/run_tests.sh b/tools/run_tests.sh index 7e68e0b0ab..df001dce97 100755 --- a/tools/run_tests.sh +++ b/tools/run_tests.sh @@ -71,7 +71,6 @@ detect_python () { IFS="$oIFS" if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" - PYTHON="python3" else command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; } fi @@ -87,8 +86,9 @@ detect_python () { # None ############################################################################### clean_pyc () { - path=${1:-$pype_root} - echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" + local path + path=$pype_root + echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -107,19 +107,22 @@ realpath () { } # Main -echo -e "${BGreen}" -art -echo -e "${RST}" -detect_python || return 1 +main () { + echo -e "${BGreen}" + art + echo -e "${RST}" + detect_python || return 1 -# Directories -pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))) -pushd "$pype_root" || return > /dev/null + # Directories + pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) + pushd "$pype_root" || return > /dev/null + + echo -e "${BIGreen}>>>${RST} Testing Pype ..." + original_pythonpath=$PYTHONPATH + export PYTHONPATH="$pype_root:$PYTHONPATH" + poetry run pytest -x --capture=sys --print -W ignore::DeprecationWarning "$pype_root/tests" + PYTHONPATH=$original_pythonpath +} -echo -e "${BIGreen}>>>${RST} Testing Pype ..." -original_pythonpath=$PYTHONPATH -export PYTHONPATH="$pype_root:$PYTHONPATH" -poetry run pytest -x --capture=sys --print -W ignore::DeprecationWarning "$pype_root/tests" -PYTHONPATH=$original_pythonpath diff --git a/tools/run_tray.ps1 b/tools/run_tray.ps1 index 2c7a665fcf..9584c05925 100644 --- a/tools/run_tray.ps1 +++ b/tools/run_tray.ps1 @@ -10,6 +10,7 @@ PS> .\run_tray.ps1 #> +$current_dir = Get-Location $script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent $pype_root = (Get-Item $script_dir).parent.FullName Set-Location -Path $pype_root diff --git a/tools/run_tray.sh b/tools/run_tray.sh index d7d3b979dc..3c63d0babe 100755 --- a/tools/run_tray.sh +++ b/tools/run_tray.sh @@ -70,10 +70,14 @@ detect_python () { set -- $python_version IFS="$oIFS" if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then - echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" + if [ "$2" -gt "7" ] ; then + echo -e "${BIWhite}[${RST} ${BIRed}$1.$2 ${BIWhite}]${RST} - ${BIRed}FAILED${RST} ${BIYellow}Version is new and unsupported, use${RST} ${BIPurple}3.7.x${RST}"; return 1; + else + echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" + fi PYTHON="python3" else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; } + command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}$1.$2$ - ${BIRed}FAILED${RST} ${BIYellow}Version is old and unsupported${RST}"; return 1; } fi } @@ -87,8 +91,9 @@ detect_python () { # None ############################################################################### clean_pyc () { - path=${1:-$pype_root} - echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" + local path + path=$pype_root + echo -e "${BIGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete echo -e "${BIGreen}DONE${RST}" } @@ -107,14 +112,18 @@ realpath () { } # Main -echo -e "${BGreen}" -art -echo -e "${RST}" -detect_python || return 1 +main () { + echo -e "${BGreen}" + art + echo -e "${RST}" + detect_python || return 1 -# Directories -pype_root=$(dirname $(realpath $(dirname $(dirname "${BASH_SOURCE[0]}")))) -pushd "$pype_root" || return > /dev/null + # Directories + pype_root=$(realpath $(dirname $(dirname "${BASH_SOURCE[0]}"))) + pushd "$pype_root" > /dev/null || return > /dev/null -echo -e "${BIGreen}>>>${RST} Running Pype Tray with debug option ..." -poetry run python "$pype_root/start.py" tray --debug + echo -e "${BIGreen}>>>${RST} Running Pype Tray with debug option ..." + poetry run python3 "$pype_root/start.py" tray --debug +} + +main \ No newline at end of file diff --git a/tools/update_submodules.ps1 b/tools/update_submodules.ps1 index 22792ff6da..ca29c7ecc4 100644 --- a/tools/update_submodules.ps1 +++ b/tools/update_submodules.ps1 @@ -35,8 +35,9 @@ function Exit-WithCode($exitcode) { exit $exitcode } -$current_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent -$pype_root = (Get-Item $current_dir).parent.FullName +$current_dir = Get-Location +$script_dir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent +$pype_root = (Get-Item $script_dir).parent.FullName Set-Location -Path $pype_root diff --git a/tools/update_submodules.sh b/tools/update_submodules.sh index c0b98f2c5e..35d943dea5 100644 --- a/tools/update_submodules.sh +++ b/tools/update_submodules.sh @@ -51,61 +51,6 @@ BICyan='\033[1;96m' # Cyan BIWhite='\033[1;97m' # White -############################################################################## -# Detect required version of python -# Globals: -# colors -# PYTHON -# Arguments: -# None -# Returns: -# None -############################################################################### -detect_python () { - echo -e "${BIGreen}>>>${RST} Using python \c" - local version_command="import sys;print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))" - local python_version="$(python3 <<< ${version_command})" - oIFS="$IFS" - IFS=. - set -- $python_version - IFS="$oIFS" - if [ "$1" -ge "3" ] && [ "$2" -ge "6" ] ; then - echo -e "${BIWhite}[${RST} ${BIGreen}$1.$2${RST} ${BIWhite}]${RST}" - PYTHON="python3" - else - command -v python3 >/dev/null 2>&1 || { echo -e "${BIRed}FAILED${RST} ${BIYellow} Version [${RST}${BICyan}$1.$2${RST}]${BIYellow} is old and unsupported${RST}"; return 1; } - fi -} - -############################################################################## -# Clean pyc files in specified directory -# Globals: -# None -# Arguments: -# Optional path to clean -# Returns: -# None -############################################################################### -clean_pyc () { - path=${1:-$pype_root} - echo -e "${IGreen}>>>${RST} Cleaning pyc at [ ${BIWhite}$path${RST} ] ... \c" - find "$path" -regex '^.*\(__pycache__\|\.py[co]\)$' -delete - echo -e "${BIGreen}DONE${RST}" -} - -############################################################################## -# Return absolute path -# Globals: -# None -# Arguments: -# Path to resolve -# Returns: -# None -############################################################################### -realpath () { - echo $(cd $(dirname "$1"); pwd)/$(basename "$1") -} - # Main echo -e "${BGreen}" art