diff --git a/.gitmodules b/.gitmodules index a282ef169d..31e7764741 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,9 +5,6 @@ [submodule "repos/avalon-unreal-integration"] path = repos/avalon-unreal-integration url = git@github.com:pypeclub/avalon-unreal-integration.git -[submodule "repos/maya-look-assigner"] - path = repos/maya-look-assigner - url = git@github.com:pypeclub/maya-look-assigner.git [submodule "pype/modules/ftrack/python2_vendor/ftrack-python-api"] path = pype/modules/ftrack/python2_vendor/ftrack-python-api url = https://bitbucket.org/ftrack/ftrack-python-api.git 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 44caa7632f..37e878580a 100644 --- a/pype/api.py +++ b/pype/api.py @@ -44,6 +44,9 @@ from .lib.avalon_context import ( from . import resources from .plugin import ( + PypeCreatorMixin, + Creator, + Extractor, ValidatePipelineOrder, @@ -86,6 +89,9 @@ __all__ = [ # Resources "resources", + # Pype creator mixin + "PypeCreatorMixin", + "Creator", # plugin classes "Extractor", # ordering diff --git a/pype/hosts/aftereffects/plugins/create/create_render.py b/pype/hosts/aftereffects/plugins/create/create_render.py index 6d876e349d..b346bc60d8 100644 --- a/pype/hosts/aftereffects/plugins/create/create_render.py +++ b/pype/hosts/aftereffects/plugins/create/create_render.py @@ -1,4 +1,4 @@ -from avalon import api +import pype.api from avalon.vendor import Qt from avalon import aftereffects @@ -7,7 +7,7 @@ import logging log = logging.getLogger(__name__) -class CreateRender(api.Creator): +class CreateRender(pype.api.Creator): """Render folder for publish.""" name = "renderDefault" diff --git a/pype/hosts/blender/api/plugin.py b/pype/hosts/blender/api/plugin.py index d0b81148c3..f216eb28be 100644 --- a/pype/hosts/blender/api/plugin.py +++ b/pype/hosts/blender/api/plugin.py @@ -6,6 +6,8 @@ from typing import Dict, List, Optional import bpy from avalon import api +import avalon.blender +from pype.api import PypeCreatorMixin VALID_EXTENSIONS = [".blend", ".json"] @@ -100,6 +102,10 @@ def get_local_collection_with_name(name): return None +class Creator(PypeCreatorMixin, avalon.blender.Creator): + pass + + class AssetLoader(api.Loader): """A basic AssetLoader for Blender diff --git a/pype/hosts/blender/plugins/create/create_action.py b/pype/hosts/blender/plugins/create/create_action.py index d402998843..b8ad24e711 100644 --- a/pype/hosts/blender/plugins/create/create_action.py +++ b/pype/hosts/blender/plugins/create/create_action.py @@ -3,11 +3,11 @@ import bpy from avalon import api -from avalon.blender import Creator, lib import pype.hosts.blender.api.plugin +from avalon.blender import lib -class CreateAction(Creator): +class CreateAction(pype.hosts.blender.api.plugin.Creator): """Action output for character rigs""" name = "actionMain" diff --git a/pype/hosts/blender/plugins/create/create_animation.py b/pype/hosts/blender/plugins/create/create_animation.py index 9d68768201..79744ad7e9 100644 --- a/pype/hosts/blender/plugins/create/create_animation.py +++ b/pype/hosts/blender/plugins/create/create_animation.py @@ -6,7 +6,7 @@ from avalon import api, blender import pype.hosts.blender.api.plugin -class CreateAnimation(blender.Creator): +class CreateAnimation(pype.hosts.blender.api.plugin.Creator): """Animation output for character rigs""" name = "animationMain" diff --git a/pype/hosts/blender/plugins/create/create_camera.py b/pype/hosts/blender/plugins/create/create_camera.py index a40ddc63d4..177d26e08b 100644 --- a/pype/hosts/blender/plugins/create/create_camera.py +++ b/pype/hosts/blender/plugins/create/create_camera.py @@ -3,11 +3,11 @@ import bpy from avalon import api -from avalon.blender import Creator, lib +from avalon.blender import lib import pype.hosts.blender.api.plugin -class CreateCamera(Creator): +class CreateCamera(pype.hosts.blender.api.plugin.Creator): """Polygonal static geometry""" name = "cameraMain" diff --git a/pype/hosts/blender/plugins/create/create_layout.py b/pype/hosts/blender/plugins/create/create_layout.py index ef765d741b..f45b58d137 100644 --- a/pype/hosts/blender/plugins/create/create_layout.py +++ b/pype/hosts/blender/plugins/create/create_layout.py @@ -3,11 +3,11 @@ import bpy from avalon import api -from avalon.blender import Creator, lib +from avalon.blender import lib import pype.hosts.blender.api.plugin -class CreateLayout(Creator): +class CreateLayout(pype.hosts.blender.api.plugin.Creator): """Layout output for character rigs""" name = "layoutMain" diff --git a/pype/hosts/blender/plugins/create/create_model.py b/pype/hosts/blender/plugins/create/create_model.py index 2bf8aedb48..7404b3a157 100644 --- a/pype/hosts/blender/plugins/create/create_model.py +++ b/pype/hosts/blender/plugins/create/create_model.py @@ -3,11 +3,11 @@ import bpy from avalon import api -from avalon.blender import Creator, lib +from avalon.blender import lib import pype.hosts.blender.api.plugin -class CreateModel(Creator): +class CreateModel(pype.hosts.blender.api.plugin.Creator): """Polygonal static geometry""" name = "modelMain" diff --git a/pype/hosts/blender/plugins/create/create_rig.py b/pype/hosts/blender/plugins/create/create_rig.py index f3efa824f4..d96a88f71d 100644 --- a/pype/hosts/blender/plugins/create/create_rig.py +++ b/pype/hosts/blender/plugins/create/create_rig.py @@ -3,11 +3,11 @@ import bpy from avalon import api -from avalon.blender import Creator, lib +from avalon.blender import lib import pype.hosts.blender.api.plugin -class CreateRig(Creator): +class CreateRig(pype.hosts.blender.api.plugin.Creator): """Artist-friendly rig with controls to direct motion""" name = "rigMain" diff --git a/pype/hosts/blender/plugins/create/create_setdress.py b/pype/hosts/blender/plugins/create/create_setdress.py index c918949216..201893b3df 100644 --- a/pype/hosts/blender/plugins/create/create_setdress.py +++ b/pype/hosts/blender/plugins/create/create_setdress.py @@ -3,7 +3,8 @@ import bpy from avalon import api, blender import pype.hosts.blender.api.plugin -class CreateSetDress(blender.Creator): + +class CreateSetDress(pype.hosts.blender.api.plugin.Creator): """A grouped package of loaded content""" name = "setdressMain" diff --git a/pype/hosts/fusion/plugins/create/create_exr_saver.py b/pype/hosts/fusion/plugins/create/create_exr_saver.py index d5092d1d03..560f7deb7f 100644 --- a/pype/hosts/fusion/plugins/create/create_exr_saver.py +++ b/pype/hosts/fusion/plugins/create/create_exr_saver.py @@ -1,10 +1,10 @@ import os -import avalon.api +import pype.api from avalon import fusion -class CreateOpenEXRSaver(avalon.api.Creator): +class CreateOpenEXRSaver(pype.api.Creator): name = "openexrDefault" label = "Create OpenEXR Saver" diff --git a/pype/hosts/harmony/api/plugin.py b/pype/hosts/harmony/api/plugin.py new file mode 100644 index 0000000000..3525ad686d --- /dev/null +++ b/pype/hosts/harmony/api/plugin.py @@ -0,0 +1,6 @@ +from avalon import harmony +from pype.api import PypeCreatorMixin + + +class Creator(PypeCreatorMixin, harmony.Creator): + pass diff --git a/pype/hosts/harmony/plugins/create/create_farm_render.py b/pype/hosts/harmony/plugins/create/create_farm_render.py index e134f28f43..a1b198b672 100644 --- a/pype/hosts/harmony/plugins/create/create_farm_render.py +++ b/pype/hosts/harmony/plugins/create/create_farm_render.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- """Create Composite node for render on farm.""" from avalon import harmony +from pype.hosts.harmony.api import plugin -class CreateFarmRender(harmony.Creator): +class CreateFarmRender(plugin.Creator): """Composite node for publishing renders.""" name = "renderDefault" diff --git a/pype/hosts/harmony/plugins/create/create_render.py b/pype/hosts/harmony/plugins/create/create_render.py index 5034a1bb89..b9a0987b37 100644 --- a/pype/hosts/harmony/plugins/create/create_render.py +++ b/pype/hosts/harmony/plugins/create/create_render.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- """Create render node.""" from avalon import harmony +from pype.hosts.harmony.api import plugin -class CreateRender(harmony.Creator): +class CreateRender(plugin.Creator): """Composite node for publishing renders.""" name = "renderDefault" diff --git a/pype/hosts/harmony/plugins/create/create_template.py b/pype/hosts/harmony/plugins/create/create_template.py index babc3fe8d7..628606c9f4 100644 --- a/pype/hosts/harmony/plugins/create/create_template.py +++ b/pype/hosts/harmony/plugins/create/create_template.py @@ -1,7 +1,7 @@ -from avalon import harmony +from pype.hosts.harmony.api import plugin -class CreateTemplate(harmony.Creator): +class CreateTemplate(plugin.Creator): """Composite node for publishing to templates.""" name = "templateDefault" diff --git a/pype/hosts/hiero/api/plugin.py b/pype/hosts/hiero/api/plugin.py index db6720cbd6..06ee403a5b 100644 --- a/pype/hosts/hiero/api/plugin.py +++ b/pype/hosts/hiero/api/plugin.py @@ -592,7 +592,7 @@ class ClipLoader: return track_item -class Creator(avalon.Creator): +class Creator(pype.Creator): """Creator class wrapper """ clip_color = "Purple" diff --git a/pype/hosts/houdini/api/plugin.py b/pype/hosts/houdini/api/plugin.py new file mode 100644 index 0000000000..864cc59f09 --- /dev/null +++ b/pype/hosts/houdini/api/plugin.py @@ -0,0 +1,6 @@ +from avalon import houdini +from pype.api import PypeCreatorMixin + + +class Creator(PypeCreatorMixin, houdini.Creator): + pass diff --git a/pype/hosts/houdini/plugins/create/create_alembic_camera.py b/pype/hosts/houdini/plugins/create/create_alembic_camera.py index cf8ac41b62..2a849ddaa0 100644 --- a/pype/hosts/houdini/plugins/create/create_alembic_camera.py +++ b/pype/hosts/houdini/plugins/create/create_alembic_camera.py @@ -1,7 +1,7 @@ -from avalon import houdini +from pype.hosts.houdini.api import plugin -class CreateAlembicCamera(houdini.Creator): +class CreateAlembicCamera(plugin.Creator): """Single baked camera from Alembic ROP""" name = "camera" diff --git a/pype/hosts/houdini/plugins/create/create_pointcache.py b/pype/hosts/houdini/plugins/create/create_pointcache.py index ae7e845083..a36ee1c965 100644 --- a/pype/hosts/houdini/plugins/create/create_pointcache.py +++ b/pype/hosts/houdini/plugins/create/create_pointcache.py @@ -1,7 +1,7 @@ -from avalon import houdini +from pype.hosts.houdini.api import plugin -class CreatePointCache(houdini.Creator): +class CreatePointCache(plugin.Creator): """Alembic ROP to pointcache""" name = "pointcache" diff --git a/pype/hosts/houdini/plugins/create/create_vbd_cache.py b/pype/hosts/houdini/plugins/create/create_vbd_cache.py index e862d5c96d..01401f0ce4 100644 --- a/pype/hosts/houdini/plugins/create/create_vbd_cache.py +++ b/pype/hosts/houdini/plugins/create/create_vbd_cache.py @@ -1,7 +1,7 @@ -from avalon import houdini +from pype.hosts.houdini.api import plugin -class CreateVDBCache(houdini.Creator): +class CreateVDBCache(plugin.Creator): """OpenVDB from Geometry ROP""" name = "vbdcache" diff --git a/pype/hosts/maya/api/__init__.py b/pype/hosts/maya/api/__init__.py index 9caca205e6..27e15e0b25 100644 --- a/pype/hosts/maya/api/__init__.py +++ b/pype/hosts/maya/api/__init__.py @@ -151,7 +151,7 @@ def on_open(_): """On scene open let's assume the containers have changed.""" from avalon.vendor.Qt import QtWidgets - from ...widgets import popup + from pype.widgets import popup cmds.evalDeferred( "from pype.hosts.maya.api import lib;" @@ -223,4 +223,4 @@ def on_task_changed(*args): lib.show_message( "Context was changed", ("Context was changed to {}".format(avalon.Session["AVALON_ASSET"])), - ) \ No newline at end of file + ) diff --git a/pype/hosts/maya/api/customize.py b/pype/hosts/maya/api/customize.py index ee3ad4f239..3f3449b3c9 100644 --- a/pype/hosts/maya/api/customize.py +++ b/pype/hosts/maya/api/customize.py @@ -89,7 +89,7 @@ def override_toolbox_ui(): log.warning("Could not import Workfiles tool") try: - import mayalookassigner + from pype.tools import mayalookassigner except Exception: log.warning("Could not import Maya Look assigner tool") diff --git a/pype/hosts/maya/api/plugin.py b/pype/hosts/maya/api/plugin.py index c7416920df..81c89017ff 100644 --- a/pype/hosts/maya/api/plugin.py +++ b/pype/hosts/maya/api/plugin.py @@ -1,5 +1,7 @@ from avalon import api from avalon.vendor import qargparse +import avalon.maya +from pype.api import PypeCreatorMixin def get_reference_node_parents(ref): @@ -26,6 +28,10 @@ def get_reference_node_parents(ref): return parents +class Creator(PypeCreatorMixin, avalon.maya.Creator): + pass + + class ReferenceLoader(api.Loader): """A basic ReferenceLoader for Maya diff --git a/pype/hosts/maya/plugins/create/create_animation.py b/pype/hosts/maya/plugins/create/create_animation.py index 6894fffb5d..312357c173 100644 --- a/pype/hosts/maya/plugins/create/create_animation.py +++ b/pype/hosts/maya/plugins/create/create_animation.py @@ -1,8 +1,10 @@ -import avalon.maya -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) -class CreateAnimation(avalon.maya.Creator): +class CreateAnimation(plugin.Creator): """Animation output for character rigs""" name = "animationDefault" diff --git a/pype/hosts/maya/plugins/create/create_ass.py b/pype/hosts/maya/plugins/create/create_ass.py index b7d5f27114..2d19d20af8 100644 --- a/pype/hosts/maya/plugins/create/create_ass.py +++ b/pype/hosts/maya/plugins/create/create_ass.py @@ -1,12 +1,14 @@ from collections import OrderedDict -import avalon.maya -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) from maya import cmds -class CreateAss(avalon.maya.Creator): +class CreateAss(plugin.Creator): """Arnold Archive""" name = "ass" diff --git a/pype/hosts/maya/plugins/create/create_assembly.py b/pype/hosts/maya/plugins/create/create_assembly.py index 6d0321b718..254d3b6670 100644 --- a/pype/hosts/maya/plugins/create/create_assembly.py +++ b/pype/hosts/maya/plugins/create/create_assembly.py @@ -1,7 +1,7 @@ -import avalon.maya +from pype.hosts.maya.api import plugin -class CreateAssembly(avalon.maya.Creator): +class CreateAssembly(plugin.Creator): """A grouped package of loaded content""" name = "assembly" diff --git a/pype/hosts/maya/plugins/create/create_camera.py b/pype/hosts/maya/plugins/create/create_camera.py index cb438e68ba..4f0865c3c4 100644 --- a/pype/hosts/maya/plugins/create/create_camera.py +++ b/pype/hosts/maya/plugins/create/create_camera.py @@ -1,8 +1,10 @@ -import avalon.maya -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) -class CreateCamera(avalon.maya.Creator): +class CreateCamera(plugin.Creator): """Single baked camera""" name = "cameraMain" @@ -24,7 +26,7 @@ class CreateCamera(avalon.maya.Creator): self.data['bakeToWorldSpace'] = True -class CreateCameraRig(avalon.maya.Creator): +class CreateCameraRig(plugin.Creator): """Complex hierarchy with camera.""" name = "camerarigMain" diff --git a/pype/hosts/maya/plugins/create/create_layout.py b/pype/hosts/maya/plugins/create/create_layout.py index 7f0c82d80e..bae1bc89b1 100644 --- a/pype/hosts/maya/plugins/create/create_layout.py +++ b/pype/hosts/maya/plugins/create/create_layout.py @@ -1,7 +1,7 @@ -import avalon.maya +from pype.hosts.maya.api import plugin -class CreateLayout(avalon.maya.Creator): +class CreateLayout(plugin.Creator): """A grouped package of loaded content""" name = "layoutMain" diff --git a/pype/hosts/maya/plugins/create/create_look.py b/pype/hosts/maya/plugins/create/create_look.py index 2d8576a8b4..d81397c1c8 100644 --- a/pype/hosts/maya/plugins/create/create_look.py +++ b/pype/hosts/maya/plugins/create/create_look.py @@ -1,8 +1,10 @@ -import avalon.maya -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) -class CreateLook(avalon.maya.Creator): +class CreateLook(plugin.Creator): """Shader connections defining shape look""" name = "look" diff --git a/pype/hosts/maya/plugins/create/create_mayaascii.py b/pype/hosts/maya/plugins/create/create_mayaascii.py index e7cc40dc24..0248ebe45e 100644 --- a/pype/hosts/maya/plugins/create/create_mayaascii.py +++ b/pype/hosts/maya/plugins/create/create_mayaascii.py @@ -1,7 +1,7 @@ -import avalon.maya +from pype.hosts.maya.api import plugin -class CreateMayaAscii(avalon.maya.Creator): +class CreateMayaAscii(plugin.Creator): """Raw Maya Ascii file export""" name = "mayaAscii" diff --git a/pype/hosts/maya/plugins/create/create_model.py b/pype/hosts/maya/plugins/create/create_model.py index 241e2be7f9..f7b5847ae1 100644 --- a/pype/hosts/maya/plugins/create/create_model.py +++ b/pype/hosts/maya/plugins/create/create_model.py @@ -1,7 +1,7 @@ -import avalon.maya +from pype.hosts.maya.api import plugin -class CreateModel(avalon.maya.Creator): +class CreateModel(plugin.Creator): """Polygonal static geometry""" name = "modelMain" diff --git a/pype/hosts/maya/plugins/create/create_pointcache.py b/pype/hosts/maya/plugins/create/create_pointcache.py index 271257c85e..c179bec9f4 100644 --- a/pype/hosts/maya/plugins/create/create_pointcache.py +++ b/pype/hosts/maya/plugins/create/create_pointcache.py @@ -1,8 +1,10 @@ -import avalon.maya -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) -class CreatePointCache(avalon.maya.Creator): +class CreatePointCache(plugin.Creator): """Alembic pointcache for animated data""" name = "pointcache" diff --git a/pype/hosts/maya/plugins/create/create_render.py b/pype/hosts/maya/plugins/create/create_render.py index afa30f2d10..726433de92 100644 --- a/pype/hosts/maya/plugins/create/create_render.py +++ b/pype/hosts/maya/plugins/create/create_render.py @@ -8,13 +8,14 @@ import requests from maya import cmds import maya.app.renderSetup.model.renderSetup as renderSetup -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) from pype.api import get_system_settings -import avalon.maya - -class CreateRender(avalon.maya.Creator): +class CreateRender(plugin.Creator): """Create *render* instance. Render instances are not actually published, they hold options for diff --git a/pype/hosts/maya/plugins/create/create_rendersetup.py b/pype/hosts/maya/plugins/create/create_rendersetup.py index bbf46e2169..37eac4aae8 100644 --- a/pype/hosts/maya/plugins/create/create_rendersetup.py +++ b/pype/hosts/maya/plugins/create/create_rendersetup.py @@ -1,9 +1,11 @@ -import avalon.maya -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) from maya import cmds -class CreateRenderSetup(avalon.maya.Creator): +class CreateRenderSetup(plugin.Creator): """Create rendersetup template json data""" name = "rendersetup" diff --git a/pype/hosts/maya/plugins/create/create_review.py b/pype/hosts/maya/plugins/create/create_review.py index 8619f90964..3f91c8af15 100644 --- a/pype/hosts/maya/plugins/create/create_review.py +++ b/pype/hosts/maya/plugins/create/create_review.py @@ -1,9 +1,11 @@ from collections import OrderedDict -import avalon.maya -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) -class CreateReview(avalon.maya.Creator): +class CreateReview(plugin.Creator): """Single baked camera""" name = "reviewDefault" diff --git a/pype/hosts/maya/plugins/create/create_rig.py b/pype/hosts/maya/plugins/create/create_rig.py index 4692997934..186e8007ee 100644 --- a/pype/hosts/maya/plugins/create/create_rig.py +++ b/pype/hosts/maya/plugins/create/create_rig.py @@ -1,10 +1,12 @@ from maya import cmds -from pype.hosts.maya.api import lib -import avalon.maya +from pype.hosts.maya.api import ( + lib, + plugin +) -class CreateRig(avalon.maya.Creator): +class CreateRig(plugin.Creator): """Artist-friendly rig with controls to direct motion""" name = "rigDefault" diff --git a/pype/hosts/maya/plugins/create/create_setdress.py b/pype/hosts/maya/plugins/create/create_setdress.py index d5fc001299..e235d01b20 100644 --- a/pype/hosts/maya/plugins/create/create_setdress.py +++ b/pype/hosts/maya/plugins/create/create_setdress.py @@ -1,7 +1,7 @@ -import avalon.maya +from pype.hosts.maya.api import plugin -class CreateSetDress(avalon.maya.Creator): +class CreateSetDress(plugin.Creator): """A grouped package of loaded content""" name = "setdressMain" diff --git a/pype/hosts/maya/plugins/create/create_unreal_staticmesh.py b/pype/hosts/maya/plugins/create/create_unreal_staticmesh.py index 5a74cb22d5..06cec0f673 100644 --- a/pype/hosts/maya/plugins/create/create_unreal_staticmesh.py +++ b/pype/hosts/maya/plugins/create/create_unreal_staticmesh.py @@ -1,7 +1,7 @@ -import avalon.maya +from pype.hosts.maya.api import plugin -class CreateUnrealStaticMesh(avalon.maya.Creator): +class CreateUnrealStaticMesh(plugin.Creator): name = "staticMeshMain" label = "Unreal - Static Mesh" family = "unrealStaticMesh" diff --git a/pype/hosts/maya/plugins/create/create_vrayproxy.py b/pype/hosts/maya/plugins/create/create_vrayproxy.py index 010157ca9a..0af670a0d3 100644 --- a/pype/hosts/maya/plugins/create/create_vrayproxy.py +++ b/pype/hosts/maya/plugins/create/create_vrayproxy.py @@ -1,7 +1,7 @@ -import avalon.maya +from pype.hosts.maya.api import plugin -class CreateVrayProxy(avalon.maya.Creator): +class CreateVrayProxy(plugin.Creator): """Alembic pointcache for animated data""" name = "vrayproxy" diff --git a/pype/hosts/maya/plugins/create/create_vrayscene.py b/pype/hosts/maya/plugins/create/create_vrayscene.py index b2c3317540..5690fb9f51 100644 --- a/pype/hosts/maya/plugins/create/create_vrayscene.py +++ b/pype/hosts/maya/plugins/create/create_vrayscene.py @@ -8,13 +8,14 @@ import requests from maya import cmds import maya.app.renderSetup.model.renderSetup as renderSetup -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) from pype.api import get_system_settings -import avalon.maya - -class CreateVRayScene(avalon.maya.Creator): +class CreateVRayScene(plugin.Creator): """Create Vray Scene.""" label = "VRay Scene" diff --git a/pype/hosts/maya/plugins/create/create_yeti_cache.py b/pype/hosts/maya/plugins/create/create_yeti_cache.py index c9edb65d8b..cf4f32b207 100644 --- a/pype/hosts/maya/plugins/create/create_yeti_cache.py +++ b/pype/hosts/maya/plugins/create/create_yeti_cache.py @@ -1,10 +1,12 @@ from collections import OrderedDict -import avalon.maya -from pype.hosts.maya.api import lib +from pype.hosts.maya.api import ( + lib, + plugin +) -class CreateYetiCache(avalon.maya.Creator): +class CreateYetiCache(plugin.Creator): """Output for procedural plugin nodes of Yeti """ name = "yetiDefault" diff --git a/pype/hosts/maya/plugins/create/create_yeti_rig.py b/pype/hosts/maya/plugins/create/create_yeti_rig.py index c385ca662d..eda51824c1 100644 --- a/pype/hosts/maya/plugins/create/create_yeti_rig.py +++ b/pype/hosts/maya/plugins/create/create_yeti_rig.py @@ -1,10 +1,12 @@ from maya import cmds -from pype.hosts.maya.api import lib -import avalon.maya +from pype.hosts.maya.api import ( + lib, + plugin +) -class CreateYetiRig(avalon.maya.Creator): +class CreateYetiRig(plugin.Creator): """Output for procedural plugin nodes ( Yeti / XGen / etc)""" label = "Yeti Rig" diff --git a/pype/hosts/nuke/api/plugin.py b/pype/hosts/nuke/api/plugin.py index d6799ed6ca..1b3e3419c6 100644 --- a/pype/hosts/nuke/api/plugin.py +++ b/pype/hosts/nuke/api/plugin.py @@ -1,11 +1,13 @@ -import avalon.api import avalon.nuke -from pype.api import get_current_project_settings +from pype.api import ( + get_current_project_settings, + PypeCreatorMixin +) from .lib import check_subsetname_exists import nuke -class PypeCreator(avalon.nuke.pipeline.Creator): +class PypeCreator(PypeCreatorMixin, avalon.nuke.pipeline.Creator): """Pype Nuke Creator class wrapper """ def __init__(self, *args, **kwargs): diff --git a/pype/hosts/nuke/plugins/create/create_backdrop.py b/pype/hosts/nuke/plugins/create/create_backdrop.py index 243b14c2d8..6d8e6a0710 100644 --- a/pype/hosts/nuke/plugins/create/create_backdrop.py +++ b/pype/hosts/nuke/plugins/create/create_backdrop.py @@ -1,9 +1,9 @@ -import avalon.nuke from avalon.nuke import lib as anlib +from pype.hosts.nuke.api import plugin import nuke -class CreateBackdrop(avalon.nuke.Creator): +class CreateBackdrop(plugin.Creator): """Add Publishable Backdrop""" name = "nukenodes" diff --git a/pype/hosts/nuke/plugins/create/create_camera.py b/pype/hosts/nuke/plugins/create/create_camera.py index 919be0ea79..51278c6f91 100644 --- a/pype/hosts/nuke/plugins/create/create_camera.py +++ b/pype/hosts/nuke/plugins/create/create_camera.py @@ -1,9 +1,9 @@ -import avalon.nuke from avalon.nuke import lib as anlib +from pype.hosts.nuke.api import plugin import nuke -class CreateCamera(avalon.nuke.Creator): +class CreateCamera(plugin.PypeCreator): """Add Publishable Backdrop""" name = "camera" diff --git a/pype/hosts/nuke/plugins/create/create_gizmo.py b/pype/hosts/nuke/plugins/create/create_gizmo.py index 19b5bead8f..c3afbe22f2 100644 --- a/pype/hosts/nuke/plugins/create/create_gizmo.py +++ b/pype/hosts/nuke/plugins/create/create_gizmo.py @@ -1,9 +1,9 @@ -import avalon.nuke from avalon.nuke import lib as anlib +from pype.hosts.nuke.api import plugin import nuke -class CreateGizmo(avalon.nuke.Creator): +class CreateGizmo(plugin.PypeCreator): """Add Publishable "gizmo" group The name is symbolically gizmo as presumably diff --git a/pype/hosts/nuke/plugins/create/create_read.py b/pype/hosts/nuke/plugins/create/create_read.py index 591f9c14a2..d0912b46fa 100644 --- a/pype/hosts/nuke/plugins/create/create_read.py +++ b/pype/hosts/nuke/plugins/create/create_read.py @@ -2,11 +2,12 @@ from collections import OrderedDict import avalon.api import avalon.nuke from pype import api as pype +from pype.hosts.nuke.api import plugin import nuke -class CrateRead(avalon.nuke.Creator): +class CrateRead(plugin.PypeCreator): # change this to template preset name = "ReadCopy" label = "Create Read Copy" diff --git a/pype/hosts/photoshop/plugins/create/create_image.py b/pype/hosts/photoshop/plugins/create/create_image.py index c1a7d92a2c..54b6efad29 100644 --- a/pype/hosts/photoshop/plugins/create/create_image.py +++ b/pype/hosts/photoshop/plugins/create/create_image.py @@ -1,9 +1,9 @@ -from avalon import api +import pype.api from avalon.vendor import Qt from avalon import photoshop -class CreateImage(api.Creator): +class CreateImage(pype.api.Creator): """Image folder for publish.""" name = "imageDefault" diff --git a/pype/hosts/photoshop/plugins/publish/collect_workfile.py b/pype/hosts/photoshop/plugins/publish/collect_workfile.py index 766be02354..88817c3969 100644 --- a/pype/hosts/photoshop/plugins/publish/collect_workfile.py +++ b/pype/hosts/photoshop/plugins/publish/collect_workfile.py @@ -31,9 +31,10 @@ class CollectWorkfile(pyblish.api.ContextPlugin): }) # creating representation + _, ext = os.path.splitext(file_path) instance.data["representations"].append({ - "name": "psd", - "ext": "psd", + "name": ext[1:], + "ext": ext[1:], "files": base_name, "stagingDir": staging_dir, }) diff --git a/pype/hosts/photoshop/plugins/publish/increment_workfile.py b/pype/hosts/photoshop/plugins/publish/increment_workfile.py index eca2583595..2005973ea0 100644 --- a/pype/hosts/photoshop/plugins/publish/increment_workfile.py +++ b/pype/hosts/photoshop/plugins/publish/increment_workfile.py @@ -1,3 +1,4 @@ +import os import pyblish.api from pype.action import get_errored_plugins_from_data from pype.lib import version_up @@ -25,6 +26,7 @@ class IncrementWorkfile(pyblish.api.InstancePlugin): ) scene_path = version_up(instance.context.data["currentFile"]) - photoshop.stub().saveAs(scene_path, 'psd', True) + _, ext = os.path.splitext(scene_path) + photoshop.stub().saveAs(scene_path, ext[1:], True) self.log.info("Incremented workfile to: {}".format(scene_path)) diff --git a/pype/hosts/resolve/api/plugin.py b/pype/hosts/resolve/api/plugin.py index 2f7c516c8f..0423f15c2a 100644 --- a/pype/hosts/resolve/api/plugin.py +++ b/pype/hosts/resolve/api/plugin.py @@ -492,7 +492,7 @@ class TimelineItemLoader(api.Loader): pass -class Creator(api.Creator): +class Creator(pype.PypeCreatorMixin, api.Creator): """Creator class wrapper """ marker_color = "Purple" diff --git a/pype/hosts/tvpaint/api/plugin.py b/pype/hosts/tvpaint/api/plugin.py new file mode 100644 index 0000000000..6f069586a5 --- /dev/null +++ b/pype/hosts/tvpaint/api/plugin.py @@ -0,0 +1,6 @@ +from pype.api import PypeCreatorMixin +from avalon.tvpaint import pipeline + + +class Creator(PypeCreatorMixin, pipeline.Creator): + pass diff --git a/pype/hosts/tvpaint/plugins/create/create_render_layer.py b/pype/hosts/tvpaint/plugins/create/create_render_layer.py index c2921cebbe..ed7c96c904 100644 --- a/pype/hosts/tvpaint/plugins/create/create_render_layer.py +++ b/pype/hosts/tvpaint/plugins/create/create_render_layer.py @@ -1,7 +1,8 @@ from avalon.tvpaint import pipeline, lib +from pype.hosts.tvpaint.api import plugin -class CreateRenderlayer(pipeline.Creator): +class CreateRenderlayer(plugin.Creator): """Mark layer group as one instance.""" name = "render_layer" label = "RenderLayer" diff --git a/pype/hosts/tvpaint/plugins/create/create_render_pass.py b/pype/hosts/tvpaint/plugins/create/create_render_pass.py index 7e4b2a4e81..8583f20451 100644 --- a/pype/hosts/tvpaint/plugins/create/create_render_pass.py +++ b/pype/hosts/tvpaint/plugins/create/create_render_pass.py @@ -1,7 +1,8 @@ from avalon.tvpaint import pipeline, lib +from pype.hosts.tvpaint.api import plugin -class CreateRenderPass(pipeline.Creator): +class CreateRenderPass(plugin.Creator): """Render pass is combination of one or more layers from same group. Requirement to create Render Pass is to have already created beauty diff --git a/pype/hosts/tvpaint/plugins/create/create_review.py b/pype/hosts/tvpaint/plugins/create/create_review.py index 9f7ee1396e..cfc49a8ac6 100644 --- a/pype/hosts/tvpaint/plugins/create/create_review.py +++ b/pype/hosts/tvpaint/plugins/create/create_review.py @@ -1,7 +1,8 @@ from avalon.tvpaint import pipeline +from pype.hosts.tvpaint.api import plugin -class CreateReview(pipeline.Creator): +class CreateReview(plugin.Creator): """Review for global review of all layers.""" name = "review" label = "Review" 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/hosts/unreal/api/plugin.py b/pype/hosts/unreal/api/plugin.py index 0c00eb77d6..94ecd3083b 100644 --- a/pype/hosts/unreal/api/plugin.py +++ b/pype/hosts/unreal/api/plugin.py @@ -1,7 +1,8 @@ from avalon import api +import pype.api -class Creator(api.Creator): +class Creator(pype.api.Creator): """This serves as skeleton for future Pype specific functionality""" pass diff --git a/pype/lib/__init__.py b/pype/lib/__init__.py index 67a31d1737..62cd363d52 100644 --- a/pype/lib/__init__.py +++ b/pype/lib/__init__.py @@ -78,9 +78,13 @@ from .applications import ( EnvironmentPrepData, prepare_host_environments, prepare_context_environments, - get_app_environments_for_context + get_app_environments_for_context, + + compile_list_of_regexes ) +from .profiles_filtering import filter_profiles + from .plugin_tools import ( filter_pyblish_plugins, source_hash, @@ -167,6 +171,10 @@ __all__ = [ "prepare_context_environments", "get_app_environments_for_context", + "compile_list_of_regexes", + + "filter_profiles", + "filter_pyblish_plugins", "source_hash", "get_unique_layer_name", diff --git a/pype/lib/log.py b/pype/lib/log.py index b6cbff5648..f6e95eea8a 100644 --- a/pype/lib/log.py +++ b/pype/lib/log.py @@ -201,8 +201,11 @@ class PypeLogger: # Information about mongo url log_mongo_url = None log_mongo_url_components = None - log_database_name = None - log_collection_name = None + + # Database name in Mongo + log_database_name = "pype" + # Collection name under database in Mongo + log_collection_name = "logs" # PYPE_DEBUG pype_debug = 0 @@ -348,25 +351,14 @@ class PypeLogger: cls.pype_debug = int(os.getenv("PYPE_DEBUG") or "0") # Mongo URL where logs will be stored - cls.log_mongo_url = ( - os.environ.get("PYPE_LOG_MONGO_URL") - or os.environ.get("PYPE_MONGO") - ) + cls.log_mongo_url = os.environ.get("PYPE_MONGO") + if not cls.log_mongo_url: cls.use_mongo_logging = False else: # Decompose url cls.log_mongo_url_components = decompose_url(cls.log_mongo_url) - # Database name in Mongo - cls.log_database_name = ( - os.environ.get("PYPE_LOG_MONGO_DB") or "pype" - ) - # Collection name under database in Mongo - cls.log_collection_name = ( - os.environ.get("PYPE_LOG_MONGO_COL") or "logs" - ) - # Mark as initialized cls.initialized = True diff --git a/pype/lib/profiles_filtering.py b/pype/lib/profiles_filtering.py new file mode 100644 index 0000000000..32c17cbd12 --- /dev/null +++ b/pype/lib/profiles_filtering.py @@ -0,0 +1,193 @@ +import re +import logging +from .applications import compile_list_of_regexes + +log = logging.getLogger(__name__) + + +def _profile_exclusion(matching_profiles, logger): + """Find out most matching profile byt host, task and family match. + + Profiles are selectively filtered. Each item in passed argument must + contain tuple of (profile, profile's score) where score is list of + booleans. Each boolean represents existence of filter for specific key. + Profiles are looped in sequence. In each sequence are profiles split into + true_list and false_list. For next sequence loop are used profiles in + true_list if there are any profiles else false_list is used. + + Filtering ends when only one profile left in true_list. Or when all + existence booleans loops passed, in that case first profile from remainded + profiles is returned. + + Args: + matching_profiles (list): Profiles with same scores. Each item is tuple + with (profile, profile values) + + Returns: + dict: Most matching profile. + """ + + logger.info( + "Search for first most matching profile in match order:" + " Host name -> Task name -> Family." + ) + + if not matching_profiles: + return None + + if len(matching_profiles) == 1: + return matching_profiles[0][0] + + scores_len = len(matching_profiles[0][1]) + for idx in range(scores_len): + profiles_true = [] + profiles_false = [] + for profile, score in matching_profiles: + if score[idx]: + profiles_true.append((profile, score)) + else: + profiles_false.append((profile, score)) + + if profiles_true: + matching_profiles = profiles_true + else: + matching_profiles = profiles_false + + if len(matching_profiles) == 1: + return matching_profiles[0][0] + + return matching_profiles[0][0] + + +def validate_value_by_regexes(value, in_list): + """Validates in any regex from list match entered value. + + Args: + value (str): String where regexes is checked. + in_list (list): List with regexes. + + Returns: + int: Returns `0` when list is not set, is empty or contain "*". + Returns `1` when any regex match value and returns `-1` + when none of regexes match entered value. + """ + if not in_list: + return 0 + + if not isinstance(in_list, (list, tuple, set)): + in_list = [in_list] + + if "*" in in_list: + return 0 + + # If value is not set and in list has specific values then resolve value + # as not matching. + if not value: + return -1 + + regexes = compile_list_of_regexes(in_list) + for regex in regexes: + if re.match(regex, value): + return 1 + return -1 + + +def filter_profiles(profiles_data, key_values, keys_order=None, logger=None): + """ Filter profiles by entered key -> values. + + Profile if marked with score for each key/value from `key_values` with + points -1, 0 or 1. + - if profile contain the key and profile's value contain value from + `key_values` then profile gets 1 point + - if profile does not contain the key or profile's value is empty or + contain "*" then got 0 point + - if profile contain the key, profile's value is not empty and does not + contain "*" and value from `key_values` is not available in the value + then got -1 point + + If profile gets -1 point at any time then is skipped and not used for + output. Profile with higher score is returned. If there are multiple + profiles with same score then first in order is used (order of profiles + matter). + + Args: + profiles_data (list): Profile definitions as dictionaries. + key_values (dict): Mapping of Key <-> Value. Key is checked if is + available in profile and if Value is matching it's values. + keys_order (list, tuple): Order of keys from `key_values` which matters + only when multiple profiles have same score. + logger (logging.Logger): Optionally can be passed different logger. + + Returns: + dict/None: Return most matching profile or None if none of profiles + match at least one criteria. + """ + if not profiles_data: + return None + + if not logger: + logger = log + + if not keys_order: + keys_order = tuple(key_values.keys()) + else: + _keys_order = list(keys_order) + # Make all keys from `key_values` are passed + for key in key_values.keys(): + if key not in _keys_order: + _keys_order.append(key) + keys_order = tuple(_keys_order) + + matching_profiles = None + highest_profile_points = -1 + # Each profile get 1 point for each matching filter. Profile with most + # points is returned. For cases when more than one profile will match + # are also stored ordered lists of matching values. + for profile in profiles_data: + profile_points = 0 + profile_scores = [] + + for key in keys_order: + value = key_values[key] + match = validate_value_by_regexes(value, profile.get(key)) + if match == -1: + profile_value = profile.get(key) or [] + logger.debug( + "\"{}\" not found in {}".format(key, profile_value) + ) + profile_points = -1 + break + + profile_points += match + profile_scores.append(bool(match)) + + if ( + profile_points < 0 + or profile_points < highest_profile_points + ): + continue + + if profile_points > highest_profile_points: + matching_profiles = [] + highest_profile_points = profile_points + + if profile_points == highest_profile_points: + matching_profiles.append((profile, profile_scores)) + + log_parts = " | ".join([ + "{}: \"{}\"".format(*item) + for item in key_values.items() + ]) + + if not matching_profiles: + logger.warning( + "None of profiles match your setup. {}".format(log_parts) + ) + return None + + if len(matching_profiles) > 1: + logger.warning( + "More than one profile match your setup. {}".format(log_parts) + ) + + return _profile_exclusion(matching_profiles, logger) diff --git a/pype/modules/avalon_apps/avalon_app.py b/pype/modules/avalon_apps/avalon_app.py index 9a0b65cb34..dcc1a36934 100644 --- a/pype/modules/avalon_apps/avalon_app.py +++ b/pype/modules/avalon_apps/avalon_app.py @@ -38,11 +38,6 @@ class AvalonModule(PypeModule, ITrayModule, IRestApi): self.avalon_mongo_url = avalon_mongo_url self.avalon_mongo_timeout = avalon_mongo_timeout - self.schema_path = os.path.join( - os.path.dirname(pype.PACKAGE_DIR), - "schema" - ) - # Tray attributes self.libraryloader = None self.rest_api_obj = None @@ -50,23 +45,11 @@ class AvalonModule(PypeModule, ITrayModule, IRestApi): def get_global_environments(self): """Avalon global environments for pype implementation.""" return { - # 100% hardcoded - "AVALON_SCHEMA": self.schema_path, - "AVALON_CONFIG": "pype", - "AVALON_LABEL": "Pype", - - # Modifiable by settings - # - mongo ulr for avalon projects - "AVALON_MONGO": self.avalon_mongo_url, # TODO thumbnails root should be multiplafrom # - thumbnails root "AVALON_THUMBNAIL_ROOT": self.thumbnail_root, # - mongo timeout in ms "AVALON_TIMEOUT": str(self.avalon_mongo_timeout), - - # May be modifiable? - # - mongo database name where projects are stored - "AVALON_DB": "avalon" } def tray_init(self): diff --git a/pype/plugin.py b/pype/plugin.py index 2e365dbff4..855b3371d3 100644 --- a/pype/plugin.py +++ b/pype/plugin.py @@ -1,9 +1,9 @@ import tempfile import os import pyblish.api - +import avalon.api from pype.api import get_project_settings -import inspect +from pype.lib import filter_profiles ValidatePipelineOrder = pyblish.api.ValidatorOrder + 0.05 ValidateContentsOrder = pyblish.api.ValidatorOrder + 0.1 @@ -11,6 +11,89 @@ ValidateSceneOrder = pyblish.api.ValidatorOrder + 0.2 ValidateMeshOrder = pyblish.api.ValidatorOrder + 0.3 +class TaskNotSetError(KeyError): + def __init__(self, msg=None): + if not msg: + msg = "Creator's subset name template requires task name." + super(TaskNotSetError, self).__init__(msg) + + +class PypeCreatorMixin: + """Helper to override avalon's default class methods. + + Mixin class must be used as first in inheritance order to override methods. + """ + default_tempate = "{family}{Variant}" + + @classmethod + def get_subset_name( + cls, variant, task_name, asset_id, project_name, host_name=None + ): + if not cls.family: + return "" + + if not host_name: + host_name = os.environ["AVALON_APP"] + + # Use only last part of class family value split by dot (`.`) + family = cls.family.rsplit(".", 1)[-1] + + # Get settings + tools_settings = get_project_settings(project_name)["global"]["tools"] + profiles = tools_settings["creator"]["subset_name_profiles"] + filtering_criteria = { + "families": family, + "hosts": host_name, + "tasks": task_name + } + + matching_profile = filter_profiles(profiles, filtering_criteria) + template = None + if matching_profile: + template = matching_profile["template"] + + # Make sure template is set (matching may have empty string) + if not template: + template = cls.default_tempate + + # Simple check of task name existence for template with {task} in + # - missing task should be possible only in Standalone publisher + if not task_name and "{task" in template.lower(): + raise TaskNotSetError() + + fill_pairs = ( + ("variant", variant), + ("family", family), + ("task", task_name) + ) + fill_data = {} + for key, value in fill_pairs: + # Handle cases when value is `None` (standalone publisher) + if value is None: + continue + # Keep value as it is + fill_data[key] = value + # Both key and value are with upper case + fill_data[key.upper()] = value.upper() + + # Capitalize only first char of value + # - conditions are because of possible index errors + capitalized = "" + if value: + # Upper first character + capitalized += value[0].upper() + # Append rest of string if there is any + if len(value) > 1: + capitalized += value[1:] + fill_data[key.capitalize()] = capitalized + + return template.format(**fill_data) + + +class Creator(PypeCreatorMixin, avalon.api.Creator): + pass + + class ContextPlugin(pyblish.api.ContextPlugin): def process(cls, *args, **kwargs): super(ContextPlugin, cls).process(cls, *args, **kwargs) diff --git a/pype/plugins/publish/collect_anatomy_instance_data.py b/pype/plugins/publish/collect_anatomy_instance_data.py index 99fbe8a52e..4fd657167c 100644 --- a/pype/plugins/publish/collect_anatomy_instance_data.py +++ b/pype/plugins/publish/collect_anatomy_instance_data.py @@ -149,10 +149,12 @@ class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): "name": subset_name }) - subset_docs = list(io.find({ - "type": "subset", - "$or": subset_filters - })) + subset_docs = [] + if subset_filters: + subset_docs = list(io.find({ + "type": "subset", + "$or": subset_filters + })) subset_ids = [ subset_doc["_id"] diff --git a/pype/settings/defaults/project_settings/global.json b/pype/settings/defaults/project_settings/global.json index c74cc9a2c5..92ef9bdb28 100644 --- a/pype/settings/defaults/project_settings/global.json +++ b/pype/settings/defaults/project_settings/global.json @@ -130,7 +130,23 @@ "rigging", "rig" ] - } + }, + "subset_name_profiles": [ + { + "families": [], + "hosts": [], + "tasks": [], + "template": "{family}{Variant}" + }, + { + "families": [ + "render" + ], + "hosts": [], + "tasks": [], + "template": "{family}{Task}{Variant}" + } + ] }, "Workfiles": { "last_workfile_on_startup": [ diff --git a/pype/settings/defaults/system_settings/modules.json b/pype/settings/defaults/system_settings/modules.json index eb794b5f9d..10a5aa723a 100644 --- a/pype/settings/defaults/system_settings/modules.json +++ b/pype/settings/defaults/system_settings/modules.json @@ -1,13 +1,11 @@ { "avalon": { - "AVALON_MONGO": "", "AVALON_TIMEOUT": 1000, "AVALON_THUMBNAIL_ROOT": { "windows": "", "darwin": "", "linux": "" - }, - "AVALON_DB_DATA": "{PYPE_SETUP_PATH}/../mongo_db_data" + } }, "ftrack": { "enabled": true, diff --git a/pype/settings/entities/schemas/projects_schema/schemas/schema_global_tools.json b/pype/settings/entities/schemas/projects_schema/schemas/schema_global_tools.json index fa49e12fb7..224389d42e 100644 --- a/pype/settings/entities/schemas/projects_schema/schemas/schema_global_tools.json +++ b/pype/settings/entities/schemas/projects_schema/schemas/schema_global_tools.json @@ -12,13 +12,50 @@ "children": [ { "type": "dict-modifiable", - "collapsible": false, + "collapsible": true, "key": "families_smart_select", "label": "Families smart select", "object_type": { "type": "list", "object_type": "text" } + }, + { + "type": "list", + "key": "subset_name_profiles", + "label": "Subset name profiles", + "use_label_wrap": true, + "object_type": { + "type": "dict", + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, + { + "key": "tasks", + "label": "Task names", + "type": "list", + "object_type": "text" + }, + { + "type": "separator" + }, + { + "type": "text", + "key": "template", + "label": "Template" + } + ] + } } ] }, diff --git a/pype/settings/entities/schemas/system_schema/schema_modules.json b/pype/settings/entities/schemas/system_schema/schema_modules.json index 7c45cebabb..d9f2a23a80 100644 --- a/pype/settings/entities/schemas/system_schema/schema_modules.json +++ b/pype/settings/entities/schemas/system_schema/schema_modules.json @@ -11,12 +11,6 @@ "label": "Avalon", "collapsible": true, "children": [ - { - "type": "text", - "key": "AVALON_MONGO", - "label": "Avalon Mongo URL", - "placeholder": "Pype Mongo is used if not filled." - }, { "type": "number", "key": "AVALON_TIMEOUT", @@ -29,11 +23,6 @@ "key": "AVALON_THUMBNAIL_ROOT", "multiplatform": true, "multipath": false - }, - { - "type": "text", - "key": "AVALON_DB_DATA", - "label": "Avalon Mongo Data Location" } ] }, diff --git a/pype/tools/mayalookassigner/LICENSE b/pype/tools/mayalookassigner/LICENSE new file mode 100644 index 0000000000..852751dbe4 --- /dev/null +++ b/pype/tools/mayalookassigner/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Colorbleed + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pype/tools/mayalookassigner/__init__.py b/pype/tools/mayalookassigner/__init__.py new file mode 100644 index 0000000000..616a3e94d0 --- /dev/null +++ b/pype/tools/mayalookassigner/__init__.py @@ -0,0 +1,9 @@ +from .app import ( + App, + show +) + + +__all__ = [ + "App", + "show"] diff --git a/pype/tools/mayalookassigner/app.py b/pype/tools/mayalookassigner/app.py new file mode 100644 index 0000000000..92ab7046a8 --- /dev/null +++ b/pype/tools/mayalookassigner/app.py @@ -0,0 +1,248 @@ +import sys +import time +import logging + +from pype.hosts.maya.api.lib import assign_look_by_version + +from avalon import style, io +from avalon.tools import lib +from avalon.vendor.Qt import QtWidgets, QtCore + +from maya import cmds +# old api for MFileIO +import maya.OpenMaya +import maya.api.OpenMaya as om + +from . import widgets +from . import commands + +module = sys.modules[__name__] +module.window = None + + +class App(QtWidgets.QWidget): + + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent=parent) + + self.log = logging.getLogger(__name__) + + # Store callback references + self._callbacks = [] + + filename = commands.get_workfile() + + self.setObjectName("lookManager") + self.setWindowTitle("Look Manager 1.3.0 - [{}]".format(filename)) + self.setWindowFlags(QtCore.Qt.Window) + self.setParent(parent) + + # Force to delete the window on close so it triggers + # closeEvent only once. Otherwise it's retriggered when + # the widget gets garbage collected. + self.setAttribute(QtCore.Qt.WA_DeleteOnClose) + + self.resize(750, 500) + + self.setup_ui() + + self.setup_connections() + + # Force refresh check on initialization + self._on_renderlayer_switch() + + def setup_ui(self): + """Build the UI""" + + # Assets (left) + asset_outliner = widgets.AssetOutliner() + + # Looks (right) + looks_widget = QtWidgets.QWidget() + looks_layout = QtWidgets.QVBoxLayout(looks_widget) + + look_outliner = widgets.LookOutliner() # Database look overview + + assign_selected = QtWidgets.QCheckBox("Assign to selected only") + assign_selected.setToolTip("Whether to assign only to selected nodes " + "or to the full asset") + remove_unused_btn = QtWidgets.QPushButton("Remove Unused Looks") + + looks_layout.addWidget(look_outliner) + looks_layout.addWidget(assign_selected) + looks_layout.addWidget(remove_unused_btn) + + # Footer + status = QtWidgets.QStatusBar() + status.setSizeGripEnabled(False) + status.setFixedHeight(25) + warn_layer = QtWidgets.QLabel("Current Layer is not " + "defaultRenderLayer") + warn_layer.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) + warn_layer.setStyleSheet("color: #DD5555; font-weight: bold;") + warn_layer.setFixedHeight(25) + + footer = QtWidgets.QHBoxLayout() + footer.setContentsMargins(0, 0, 0, 0) + footer.addWidget(status) + footer.addWidget(warn_layer) + + # Build up widgets + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setSpacing(0) + main_splitter = QtWidgets.QSplitter() + main_splitter.setStyleSheet("QSplitter{ border: 0px; }") + main_splitter.addWidget(asset_outliner) + main_splitter.addWidget(looks_widget) + main_splitter.setSizes([350, 200]) + main_layout.addWidget(main_splitter) + main_layout.addLayout(footer) + + # Set column width + asset_outliner.view.setColumnWidth(0, 200) + look_outliner.view.setColumnWidth(0, 150) + + # Open widgets + self.asset_outliner = asset_outliner + self.look_outliner = look_outliner + self.status = status + self.warn_layer = warn_layer + + # Buttons + self.remove_unused = remove_unused_btn + self.assign_selected = assign_selected + + def setup_connections(self): + """Connect interactive widgets with actions""" + + self.asset_outliner.selection_changed.connect( + self.on_asset_selection_changed) + + self.asset_outliner.refreshed.connect( + lambda: self.echo("Loaded assets..")) + + self.look_outliner.menu_apply_action.connect(self.on_process_selected) + self.remove_unused.clicked.connect(commands.remove_unused_looks) + + # Maya renderlayer switch callback + callback = om.MEventMessage.addEventCallback( + "renderLayerManagerChange", + self._on_renderlayer_switch + ) + self._callbacks.append(callback) + + def closeEvent(self, event): + + # Delete callbacks + for callback in self._callbacks: + om.MMessage.removeCallback(callback) + + return super(App, self).closeEvent(event) + + def _on_renderlayer_switch(self, *args): + """Callback that updates on Maya renderlayer switch""" + + if maya.OpenMaya.MFileIO.isNewingFile(): + # Don't perform a check during file open or file new as + # the renderlayers will not be in a valid state yet. + return + + layer = cmds.editRenderLayerGlobals(query=True, + currentRenderLayer=True) + if layer != "defaultRenderLayer": + self.warn_layer.show() + else: + self.warn_layer.hide() + + def echo(self, message): + self.status.showMessage(message, 1500) + + def refresh(self): + """Refresh the content""" + + # Get all containers and information + self.asset_outliner.clear() + found_items = self.asset_outliner.get_all_assets() + if not found_items: + self.look_outliner.clear() + + def on_asset_selection_changed(self): + """Get selected items from asset loader and fill look outliner""" + + items = self.asset_outliner.get_selected_items() + self.look_outliner.clear() + self.look_outliner.add_items(items) + + def on_process_selected(self): + """Process all selected looks for the selected assets""" + + assets = self.asset_outliner.get_selected_items() + assert assets, "No asset selected" + + # Collect the looks we want to apply (by name) + look_items = self.look_outliner.get_selected_items() + looks = {look["subset"] for look in look_items} + + selection = self.assign_selected.isChecked() + asset_nodes = self.asset_outliner.get_nodes(selection=selection) + + start = time.time() + for i, (asset, item) in enumerate(asset_nodes.items()): + + # Label prefix + prefix = "({}/{})".format(i+1, len(asset_nodes)) + + # Assign the first matching look relevant for this asset + # (since assigning multiple to the same nodes makes no sense) + assign_look = next((subset for subset in item["looks"] + if subset["name"] in looks), None) + if not assign_look: + self.echo("{} No matching selected " + "look for {}".format(prefix, asset)) + continue + + # Get the latest version of this asset's look subset + version = io.find_one({"type": "version", + "parent": assign_look["_id"]}, + sort=[("name", -1)]) + + subset_name = assign_look["name"] + self.echo("{} Assigning {} to {}\t".format(prefix, + subset_name, + asset)) + + # Assign look + assign_look_by_version(nodes=item["nodes"], + version_id=version["_id"]) + + end = time.time() + + self.echo("Finished assigning.. ({0:.3f}s)".format(end - start)) + + +def show(): + """Display Loader GUI + + Arguments: + debug (bool, optional): Run loader in debug-mode, + defaults to False + + """ + + try: + module.window.close() + del module.window + except (RuntimeError, AttributeError): + pass + + # Get Maya main window + top_level_widgets = QtWidgets.QApplication.topLevelWidgets() + mainwindow = next(widget for widget in top_level_widgets + if widget.objectName() == "MayaWindow") + + with lib.application(): + window = App(parent=mainwindow) + window.setStyleSheet(style.load_stylesheet()) + window.show() + + module.window = window diff --git a/pype/tools/mayalookassigner/commands.py b/pype/tools/mayalookassigner/commands.py new file mode 100644 index 0000000000..a379a109f4 --- /dev/null +++ b/pype/tools/mayalookassigner/commands.py @@ -0,0 +1,191 @@ +from collections import defaultdict +import logging +import os + +import maya.cmds as cmds + +from pype.hosts.maya.api import lib + +from avalon import io, api + +log = logging.getLogger(__name__) + + +def get_workfile(): + path = cmds.file(query=True, sceneName=True) or "untitled" + return os.path.basename(path) + + +def get_workfolder(): + return os.path.dirname(cmds.file(query=True, sceneName=True)) + + +def select(nodes): + cmds.select(nodes) + + +def get_namespace_from_node(node): + """Get the namespace from the given node + + Args: + node (str): name of the node + + Returns: + namespace (str) + + """ + parts = node.rsplit("|", 1)[-1].rsplit(":", 1) + return parts[0] if len(parts) > 1 else u":" + + +def list_descendents(nodes): + """Include full descendant hierarchy of given nodes. + + This is a workaround to cmds.listRelatives(allDescendents=True) because + this way correctly keeps children instance paths (see Maya documentation) + + This fixes LKD-26: assignments not working as expected on instanced shapes. + + Return: + list: List of children descendents of nodes + + """ + result = [] + while True: + nodes = cmds.listRelatives(nodes, + fullPath=True) + if nodes: + result.extend(nodes) + else: + return result + + +def get_selected_nodes(): + """Get information from current selection""" + + selection = cmds.ls(selection=True, long=True) + hierarchy = list_descendents(selection) + nodes = list(set(selection + hierarchy)) + + return nodes + + +def get_all_asset_nodes(): + """Get all assets from the scene, container based + + Returns: + list: list of dictionaries + """ + + host = api.registered_host() + + nodes = [] + for container in host.ls(): + # We are not interested in looks but assets! + if container["loader"] == "LookLoader": + continue + + # Gather all information + container_name = container["objectName"] + nodes += cmds.sets(container_name, query=True, nodesOnly=True) or [] + + return nodes + + +def create_asset_id_hash(nodes): + """Create a hash based on cbId attribute value + Args: + nodes (list): a list of nodes + + Returns: + dict + """ + node_id_hash = defaultdict(list) + for node in nodes: + value = lib.get_id(node) + if value is None: + continue + + asset_id = value.split(":")[0] + node_id_hash[asset_id].append(node) + + return dict(node_id_hash) + + +def create_items_from_nodes(nodes): + """Create an item for the view based the container and content of it + + It fetches the look document based on the asset ID found in the content. + The item will contain all important information for the tool to work. + + If there is an asset ID which is not registered in the project's collection + it will log a warning message. + + Args: + nodes (list): list of maya nodes + + Returns: + list of dicts + + """ + + asset_view_items = [] + + id_hashes = create_asset_id_hash(nodes) + if not id_hashes: + return asset_view_items + + for _id, id_nodes in id_hashes.items(): + asset = io.find_one({"_id": io.ObjectId(_id)}, + projection={"name": True}) + + # Skip if asset id is not found + if not asset: + log.warning("Id not found in the database, skipping '%s'." % _id) + log.warning("Nodes: %s" % id_nodes) + continue + + # Collect available look subsets for this asset + looks = lib.list_looks(asset["_id"]) + + # Collect namespaces the asset is found in + namespaces = set() + for node in id_nodes: + namespace = get_namespace_from_node(node) + namespaces.add(namespace) + + asset_view_items.append({"label": asset["name"], + "asset": asset, + "looks": looks, + "namespaces": namespaces}) + + return asset_view_items + + +def remove_unused_looks(): + """Removes all loaded looks for which none of the shaders are used. + + This will cleanup all loaded "LookLoader" containers that are unused in + the current scene. + + """ + + host = api.registered_host() + + unused = list() + for container in host.ls(): + if container['loader'] == "LookLoader": + members = cmds.sets(container['objectName'], query=True) + look_sets = cmds.ls(members, type="objectSet") + for look_set in look_sets: + # If the set is used than we consider this look *in use* + if cmds.sets(look_set, query=True): + break + else: + unused.append(container) + + for container in unused: + log.info("Removing unused look container: %s", container['objectName']) + api.remove(container) + + log.info("Finished removing unused looks. (see log for details)") diff --git a/pype/tools/mayalookassigner/models.py b/pype/tools/mayalookassigner/models.py new file mode 100644 index 0000000000..7c5133de82 --- /dev/null +++ b/pype/tools/mayalookassigner/models.py @@ -0,0 +1,120 @@ +from collections import defaultdict +from avalon.tools import models + +from avalon.vendor.Qt import QtCore +from avalon.vendor import qtawesome +from avalon.style import colors + + +class AssetModel(models.TreeModel): + + Columns = ["label"] + + def add_items(self, items): + """ + Add items to model with needed data + Args: + items(list): collection of item data + + Returns: + None + """ + + self.beginResetModel() + + # Add the items sorted by label + sorter = lambda x: x["label"] + + for item in sorted(items, key=sorter): + + asset_item = models.Item() + asset_item.update(item) + asset_item["icon"] = "folder" + + # Add namespace children + namespaces = item["namespaces"] + for namespace in sorted(namespaces): + child = models.Item() + child.update(item) + child.update({ + "label": (namespace if namespace != ":" + else "(no namespace)"), + "namespace": namespace, + "looks": item["looks"], + "icon": "folder-o" + }) + asset_item.add_child(child) + + self.add_child(asset_item) + + self.endResetModel() + + def data(self, index, role): + + if not index.isValid(): + return + + if role == models.TreeModel.ItemRole: + node = index.internalPointer() + return node + + # Add icon + if role == QtCore.Qt.DecorationRole: + if index.column() == 0: + node = index.internalPointer() + icon = node.get("icon") + if icon: + return qtawesome.icon("fa.{0}".format(icon), + color=colors.default) + + return super(AssetModel, self).data(index, role) + + +class LookModel(models.TreeModel): + """Model displaying a list of looks and matches for assets""" + + Columns = ["label", "match"] + + def add_items(self, items): + """Add items to model with needed data + + An item exists of: + { + "subset": 'name of subset', + "asset": asset_document + } + + Args: + items(list): collection of item data + + Returns: + None + """ + + self.beginResetModel() + + # Collect the assets per look name (from the items of the AssetModel) + look_subsets = defaultdict(list) + for asset_item in items: + asset = asset_item["asset"] + for look in asset_item["looks"]: + look_subsets[look["name"]].append(asset) + + for subset, assets in sorted(look_subsets.iteritems()): + + # Define nice label without "look" prefix for readability + label = subset if not subset.startswith("look") else subset[4:] + + item_node = models.Item() + item_node["label"] = label + item_node["subset"] = subset + + # Amount of matching assets for this look + item_node["match"] = len(assets) + + # Store the assets that have this subset available + item_node["assets"] = assets + + self.add_child(item_node) + + self.endResetModel() diff --git a/pype/tools/mayalookassigner/views.py b/pype/tools/mayalookassigner/views.py new file mode 100644 index 0000000000..decf04ee57 --- /dev/null +++ b/pype/tools/mayalookassigner/views.py @@ -0,0 +1,50 @@ +from avalon.vendor.Qt import QtWidgets, QtCore + + +DEFAULT_COLOR = "#fb9c15" + + +class View(QtWidgets.QTreeView): + data_changed = QtCore.Signal() + + def __init__(self, parent=None): + super(View, self).__init__(parent=parent) + + # view settings + self.setAlternatingRowColors(False) + self.setSortingEnabled(True) + self.setSelectionMode(self.ExtendedSelection) + self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + + def get_indices(self): + """Get the selected rows""" + selection_model = self.selectionModel() + return selection_model.selectedRows() + + def extend_to_children(self, indices): + """Extend the indices to the children indices. + + Top-level indices are extended to its children indices. Sub-items + are kept as is. + + :param indices: The indices to extend. + :type indices: list + + :return: The children indices + :rtype: list + """ + + subitems = set() + for i in indices: + valid_parent = i.parent().isValid() + if valid_parent and i not in subitems: + subitems.add(i) + else: + # is top level node + model = i.model() + rows = model.rowCount(parent=i) + for row in range(rows): + child = model.index(row, 0, parent=i) + subitems.add(child) + + return list(subitems) diff --git a/pype/tools/mayalookassigner/widgets.py b/pype/tools/mayalookassigner/widgets.py new file mode 100644 index 0000000000..bfa8492e69 --- /dev/null +++ b/pype/tools/mayalookassigner/widgets.py @@ -0,0 +1,261 @@ +import logging +from collections import defaultdict + +from avalon.vendor.Qt import QtWidgets, QtCore + +# TODO: expose this better in avalon core +from avalon.tools import lib +from avalon.tools.models import TreeModel + +from . import models +from . import commands +from . import views + +from maya import cmds + +MODELINDEX = QtCore.QModelIndex() + + +class AssetOutliner(QtWidgets.QWidget): + + refreshed = QtCore.Signal() + selection_changed = QtCore.Signal() + + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + + layout = QtWidgets.QVBoxLayout() + + title = QtWidgets.QLabel("Assets") + title.setAlignment(QtCore.Qt.AlignCenter) + title.setStyleSheet("font-weight: bold; font-size: 12px") + + model = models.AssetModel() + view = views.View() + view.setModel(model) + view.customContextMenuRequested.connect(self.right_mouse_menu) + view.setSortingEnabled(False) + view.setHeaderHidden(True) + view.setIndentation(10) + + from_all_asset_btn = QtWidgets.QPushButton("Get All Assets") + from_selection_btn = QtWidgets.QPushButton("Get Assets From Selection") + + layout.addWidget(title) + layout.addWidget(from_all_asset_btn) + layout.addWidget(from_selection_btn) + layout.addWidget(view) + + # Build connections + from_selection_btn.clicked.connect(self.get_selected_assets) + from_all_asset_btn.clicked.connect(self.get_all_assets) + + selection_model = view.selectionModel() + selection_model.selectionChanged.connect(self.selection_changed) + + self.view = view + self.model = model + + self.setLayout(layout) + + self.log = logging.getLogger(__name__) + + def clear(self): + self.model.clear() + + # fix looks remaining visible when no items present after "refresh" + # todo: figure out why this workaround is needed. + self.selection_changed.emit() + + def add_items(self, items): + """Add new items to the outliner""" + + self.model.add_items(items) + self.refreshed.emit() + + def get_selected_items(self): + """Get current selected items from view + + Returns: + list: list of dictionaries + """ + + selection_model = self.view.selectionModel() + items = [row.data(TreeModel.ItemRole) for row in + selection_model.selectedRows(0)] + + return items + + def get_all_assets(self): + """Add all items from the current scene""" + + with lib.preserve_expanded_rows(self.view): + with lib.preserve_selection(self.view): + self.clear() + nodes = commands.get_all_asset_nodes() + items = commands.create_items_from_nodes(nodes) + self.add_items(items) + + return len(items) > 0 + + def get_selected_assets(self): + """Add all selected items from the current scene""" + + with lib.preserve_expanded_rows(self.view): + with lib.preserve_selection(self.view): + self.clear() + nodes = commands.get_selected_nodes() + items = commands.create_items_from_nodes(nodes) + self.add_items(items) + + def get_nodes(self, selection=False): + """Find the nodes in the current scene per asset.""" + + items = self.get_selected_items() + + # Collect all nodes by hash (optimization) + if not selection: + nodes = cmds.ls(dag=True, long=True) + else: + nodes = commands.get_selected_nodes() + id_nodes = commands.create_asset_id_hash(nodes) + + # Collect the asset item entries per asset + # and collect the namespaces we'd like to apply + assets = dict() + asset_namespaces = defaultdict(set) + for item in items: + asset_id = str(item["asset"]["_id"]) + asset_name = item["asset"]["name"] + asset_namespaces[asset_name].add(item.get("namespace")) + + if asset_name in assets: + continue + + assets[asset_name] = item + assets[asset_name]["nodes"] = id_nodes.get(asset_id, []) + + # Filter nodes to namespace (if only namespaces were selected) + for asset_name in assets: + namespaces = asset_namespaces[asset_name] + + # When None is present there should be no filtering + if None in namespaces: + continue + + # Else only namespaces are selected and *not* the top entry so + # we should filter to only those namespaces. + nodes = assets[asset_name]["nodes"] + nodes = [node for node in nodes if + commands.get_namespace_from_node(node) in namespaces] + assets[asset_name]["nodes"] = nodes + + return assets + + def select_asset_from_items(self): + """Select nodes from listed asset""" + + items = self.get_nodes(selection=False) + nodes = [] + for item in items.values(): + nodes.extend(item["nodes"]) + + commands.select(nodes) + + def right_mouse_menu(self, pos): + """Build RMB menu for asset outliner""" + + active = self.view.currentIndex() # index under mouse + active = active.sibling(active.row(), 0) # get first column + globalpos = self.view.viewport().mapToGlobal(pos) + + menu = QtWidgets.QMenu(self.view) + + # Direct assignment + apply_action = QtWidgets.QAction(menu, text="Select nodes") + apply_action.triggered.connect(self.select_asset_from_items) + + if not active.isValid(): + apply_action.setEnabled(False) + + menu.addAction(apply_action) + + menu.exec_(globalpos) + + +class LookOutliner(QtWidgets.QWidget): + + menu_apply_action = QtCore.Signal() + + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + + # look manager layout + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(10) + + # Looks from database + title = QtWidgets.QLabel("Looks") + title.setAlignment(QtCore.Qt.AlignCenter) + title.setStyleSheet("font-weight: bold; font-size: 12px") + title.setAlignment(QtCore.Qt.AlignCenter) + + model = models.LookModel() + + # Proxy for dynamic sorting + proxy = QtCore.QSortFilterProxyModel() + proxy.setSourceModel(model) + + view = views.View() + view.setModel(proxy) + view.setMinimumHeight(180) + view.setToolTip("Use right mouse button menu for direct actions") + view.customContextMenuRequested.connect(self.right_mouse_menu) + view.sortByColumn(0, QtCore.Qt.AscendingOrder) + + layout.addWidget(title) + layout.addWidget(view) + + self.view = view + self.model = model + + def clear(self): + self.model.clear() + + def add_items(self, items): + self.model.add_items(items) + + def get_selected_items(self): + """Get current selected items from view + + Returns: + list: list of dictionaries + """ + + datas = [i.data(TreeModel.ItemRole) for i in self.view.get_indices()] + items = [d for d in datas if d is not None] # filter Nones + + return items + + def right_mouse_menu(self, pos): + """Build RMB menu for look view""" + + active = self.view.currentIndex() # index under mouse + active = active.sibling(active.row(), 0) # get first column + globalpos = self.view.viewport().mapToGlobal(pos) + + if not active.isValid(): + return + + menu = QtWidgets.QMenu(self.view) + + # Direct assignment + apply_action = QtWidgets.QAction(menu, text="Assign looks..") + apply_action.triggered.connect(self.menu_apply_action) + + menu.addAction(apply_action) + + menu.exec_(globalpos) + + diff --git a/pype/tools/settings/settings/widgets/categories.py b/pype/tools/settings/settings/widgets/categories.py index 40bd687faf..07f7291e91 100644 --- a/pype/tools/settings/settings/widgets/categories.py +++ b/pype/tools/settings/settings/widgets/categories.py @@ -404,15 +404,6 @@ class ProjectWidget(SettingsCategoryWidget): if self is saved_tab_widget: return - system_settings = get_system_settings() - mongo_url = system_settings["modules"]["avalon"]["AVALON_MONGO"] - if not mongo_url: - mongo_url = os.environ["PYPE_MONGO"] - - # If mongo url is not the same as was then refresh projects - if mongo_url != os.environ["AVALON_MONGO"]: - self.project_list_widget.refresh() - def _create_root_entity(self): self.entity = ProjectSettings(change_state=False) self.entity.on_change_callbacks.append(self._on_entity_change) diff --git a/pype/tools/settings/settings/widgets/item_widgets.py b/pype/tools/settings/settings/widgets/item_widgets.py index cf290eb417..bdc96840f2 100644 --- a/pype/tools/settings/settings/widgets/item_widgets.py +++ b/pype/tools/settings/settings/widgets/item_widgets.py @@ -460,9 +460,7 @@ class EnumeratorWidget(InputWidget): self.input_field = MultiSelectionComboBox( 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.content_widget) 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 656aaaa652..ccd437ece3 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -643,10 +643,7 @@ class ProjectListWidget(QtWidgets.QWidget): items = [self.default] - system_settings = get_system_settings() - mongo_url = system_settings["modules"]["avalon"]["AVALON_MONGO"] - if not mongo_url: - mongo_url = os.environ["PYPE_MONGO"] + mongo_url = os.environ["PYPE_MONGO"] # Force uninstall of whole avalon connection if url does not match # to current environment and set it as environment diff --git a/pype/tools/standalonepublish/app.py b/pype/tools/standalonepublish/app.py index 920dd32f7c..54cde9e322 100644 --- a/pype/tools/standalonepublish/app.py +++ b/pype/tools/standalonepublish/app.py @@ -9,6 +9,7 @@ from Qt import QtWidgets, QtCore, QtGui from .widgets import ( AssetWidget, FamilyWidget, ComponentsWidget, ShadowWidget ) +from .widgets.constants import HOST_NAME from avalon import style from pype.api import resources from avalon.api import AvalonMongoDB @@ -73,6 +74,7 @@ class Window(QtWidgets.QDialog): # signals widget_assets.selection_changed.connect(self.on_asset_changed) + widget_assets.task_changed.connect(self._on_task_change) widget_assets.project_changed.connect(self.on_project_change) widget_family.stateChanged.connect(self.set_valid_family) @@ -150,6 +152,9 @@ class Window(QtWidgets.QDialog): self.widget_family.change_asset(None) self.widget_family.on_data_changed() + def _on_task_change(self): + self.widget_family.on_task_change() + def keyPressEvent(self, event): ''' Handling Ctrl+V KeyPress event Can handle: @@ -208,6 +213,8 @@ class Window(QtWidgets.QDialog): def main(): + os.environ["AVALON_APP"] = HOST_NAME + # Allow to change icon of running process in windows taskbar if os.name == "nt": ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID( diff --git a/pype/tools/standalonepublish/widgets/constants.py b/pype/tools/standalonepublish/widgets/constants.py new file mode 100644 index 0000000000..0ecc8e82e7 --- /dev/null +++ b/pype/tools/standalonepublish/widgets/constants.py @@ -0,0 +1 @@ +HOST_NAME = "standalonepublisher" diff --git a/pype/tools/standalonepublish/widgets/widget_asset.py b/pype/tools/standalonepublish/widgets/widget_asset.py index 91565668cc..4680e88344 100644 --- a/pype/tools/standalonepublish/widgets/widget_asset.py +++ b/pype/tools/standalonepublish/widgets/widget_asset.py @@ -125,6 +125,7 @@ class AssetWidget(QtWidgets.QWidget): assets_refreshed = QtCore.Signal() # on model refresh selection_changed = QtCore.Signal() # on view selection change current_changed = QtCore.Signal() # on view current index change + task_changed = QtCore.Signal() def __init__(self, dbcon, parent=None): super(AssetWidget, self).__init__(parent=parent) @@ -190,6 +191,9 @@ class AssetWidget(QtWidgets.QWidget): selection = view.selectionModel() selection.selectionChanged.connect(self.selection_changed) selection.currentChanged.connect(self.current_changed) + task_view.selectionModel().selectionChanged.connect( + self._on_task_change + ) refresh.clicked.connect(self.refresh) self.selection_changed.connect(self._refresh_tasks) @@ -269,7 +273,18 @@ class AssetWidget(QtWidgets.QWidget): def refresh(self): self._refresh_model() + def _on_task_change(self): + try: + index = self.task_view.selectedIndexes()[0] + task_name = self.task_model.itemData(index)[0] + except Exception: + task_name = None + + self.dbcon.Session["AVALON_TASK"] = task_name + self.task_changed.emit() + def _refresh_tasks(self): + self.dbcon.Session["AVALON_TASK"] = None tasks = [] selected = self.get_selected_assets() if len(selected) == 1: @@ -279,7 +294,8 @@ class AssetWidget(QtWidgets.QWidget): if asset: tasks = asset.get('data', {}).get('tasks', []) self.task_model.set_tasks(tasks) - self.task_view.setVisible(len(tasks)>0) + self.task_view.setVisible(len(tasks) > 0) + self.task_changed.emit() def get_active_asset(self): """Return the asset id the current asset.""" diff --git a/pype/tools/standalonepublish/widgets/widget_components.py b/pype/tools/standalonepublish/widgets/widget_components.py index 8d627b7eed..d4638ea437 100644 --- a/pype/tools/standalonepublish/widgets/widget_components.py +++ b/pype/tools/standalonepublish/widgets/widget_components.py @@ -7,6 +7,7 @@ import string from Qt import QtWidgets, QtCore from . import DropDataFrame +from .constants import HOST_NAME from avalon import io from pype.api import execute, Logger from pype.lib import get_pype_execute_args @@ -178,8 +179,8 @@ def set_context(project, asset, task): io.Session["current_dir"] = os.path.normpath(os.getcwd()) - os.environ["AVALON_APP"] = "standalonepublish" - io.Session["AVALON_APP"] = "standalonepublish" + os.environ["AVALON_APP"] = HOST_NAME + io.Session["AVALON_APP"] = HOST_NAME io.uninstall() diff --git a/pype/tools/standalonepublish/widgets/widget_family.py b/pype/tools/standalonepublish/widgets/widget_family.py index ed30dba420..5521503508 100644 --- a/pype/tools/standalonepublish/widgets/widget_family.py +++ b/pype/tools/standalonepublish/widgets/widget_family.py @@ -1,11 +1,16 @@ import os -from collections import namedtuple +import re from Qt import QtWidgets, QtCore from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole from . import FamilyDescriptionWidget -from pype.api import get_project_settings +from pype.api import ( + get_project_settings, + Creator +) +from pype.plugin import TaskNotSetError +from avalon.tools.creator.app import SubsetAllowedSymbols class FamilyWidget(QtWidgets.QWidget): @@ -123,6 +128,9 @@ class FamilyWidget(QtWidgets.QWidget): } return data + def on_task_change(self): + self.on_data_changed() + def change_asset(self, name): if name is None: name = self.NOT_SELECTED @@ -168,65 +176,113 @@ class FamilyWidget(QtWidgets.QWidget): def _on_data_changed(self): asset_name = self.asset_name - subset_name = self.input_subset.text() + user_input_text = self.input_subset.text() item = self.list_families.currentItem() if item is None: return - assets = None + asset_doc = None if asset_name != self.NOT_SELECTED: # Get the assets from the database which match with the name - assets_db = self.dbcon.find( - filter={"type": "asset"}, - projection={"name": 1} + asset_doc = self.dbcon.find_one( + { + "type": "asset", + "name": asset_name + }, + {"_id": 1} ) - assets = [ - asset for asset in assets_db if asset_name in asset["name"] - ] # Get plugin and family plugin = item.data(PluginRole) - if plugin is None: + + # Early exit if no asset name + if not asset_name.strip(): + self._build_menu([]) + item.setData(ExistsRole, False) + print("Asset name is required ..") + self.stateChanged.emit(False) return - family = plugin.family.rsplit(".", 1)[-1] + # Get the asset from the database which match with the name + asset_doc = self.dbcon.find_one( + {"name": asset_name, "type": "asset"}, + projection={"_id": 1} + ) + # Get plugin + plugin = item.data(PluginRole) + if asset_doc and plugin: + project_name = self.dbcon.Session["AVALON_PROJECT"] + asset_id = asset_doc["_id"] + task_name = self.dbcon.Session["AVALON_TASK"] - # Update the result - if subset_name: - subset_name = subset_name[0].upper() + subset_name[1:] - self.input_result.setText("{}{}".format(family, subset_name)) + # Calculate subset name with Creator plugin + try: + subset_name = plugin.get_subset_name( + user_input_text, task_name, asset_id, project_name + ) + # Force replacement of prohibited symbols + # QUESTION should Creator care about this and here should be + # only validated with schema regex? + subset_name = re.sub( + "[^{}]+".format(SubsetAllowedSymbols), + "", + subset_name + ) + self.input_result.setText(subset_name) + + except TaskNotSetError: + subset_name = "" + self.input_result.setText("Select task please") - if assets: # Get all subsets of the current asset - asset_ids = [asset["_id"] for asset in assets] - subsets = self.dbcon.find(filter={"type": "subset", - "name": {"$regex": "{}*".format(family), - "$options": "i"}, - "parent": {"$in": asset_ids}}) or [] + subset_docs = self.dbcon.find( + { + "type": "subset", + "parent": asset_id + }, + {"name": 1} + ) + existing_subset_names = set(subset_docs.distinct("name")) - # Get all subsets' their subset name, "Default", "High", "Low" - existed_subsets = [sub["name"].split(family)[-1] - for sub in subsets] + # Defaults to dropdown + defaults = [] + # Check if Creator plugin has set defaults + if ( + plugin.defaults + and isinstance(plugin.defaults, (list, tuple, set)) + ): + defaults = list(plugin.defaults) - if plugin.defaults and isinstance(plugin.defaults, list): - defaults = plugin.defaults[:] + [self.Separator] - lowered = [d.lower() for d in plugin.defaults] - for sub in [s for s in existed_subsets - if s.lower() not in lowered]: - defaults.append(sub) - else: - defaults = existed_subsets + # Replace + compare_regex = re.compile( + subset_name.replace(user_input_text, "(.+)") + ) + subset_hints = set() + if user_input_text: + for _name in existing_subset_names: + _result = compare_regex.search(_name) + if _result: + subset_hints |= set(_result.groups()) + subset_hints = subset_hints - set(defaults) + if subset_hints: + if defaults: + defaults.append(self.Separator) + defaults.extend(subset_hints) self._build_menu(defaults) item.setData(ExistsRole, True) + else: + subset_name = user_input_text self._build_menu([]) item.setData(ExistsRole, False) - if asset_name != self.NOT_SELECTED: - # TODO add logging into standalone_publish - print("'%s' not found .." % asset_name) + + if not plugin: + print("No registered families ..") + else: + print("Asset '%s' not found .." % asset_name) self.on_version_refresh() @@ -249,30 +305,46 @@ class FamilyWidget(QtWidgets.QWidget): subset_name = self.input_result.text() version = 1 + asset_doc = None + subset_doc = None + versions = None if ( asset_name != self.NOT_SELECTED and subset_name.strip() != '' ): - asset = self.dbcon.find_one({ - 'type': 'asset', - 'name': asset_name - }) - subset = self.dbcon.find_one({ - 'type': 'subset', - 'parent': asset['_id'], - 'name': subset_name - }) - if subset: - versions = self.dbcon.find({ + asset_doc = self.dbcon.find_one( + { + 'type': 'asset', + 'name': asset_name + }, + {"_id": 1} + ) + + if asset_doc: + subset_doc = self.dbcon.find_one( + { + 'type': 'subset', + 'parent': asset_doc['_id'], + 'name': subset_name + }, + {"_id": 1} + ) + + if subset_doc: + versions = self.dbcon.find( + { 'type': 'version', - 'parent': subset['_id'] - }) - if versions: - versions = sorted( - [v for v in versions], - key=lambda ver: ver['name'] - ) - version = int(versions[-1]['name']) + 1 + 'parent': subset_doc['_id'] + }, + {"name": 1} + ).distinct("name") + + if versions: + versions = sorted( + [v for v in versions], + key=lambda ver: ver['name'] + ) + version = int(versions[-1]['name']) + 1 self.version_spinbox.setValue(version) @@ -322,11 +394,8 @@ class FamilyWidget(QtWidgets.QWidget): settings = get_project_settings(project_name) sp_settings = settings.get('standalonepublisher', {}) - for key, creator in sp_settings.get("create", {}).items(): - if key == "__dynamic_keys_labels__": - continue - - creator = namedtuple("Creator", creator.keys())(*creator.values()) + for key, creator_data in sp_settings.get("create", {}).items(): + creator = type(key, (Creator, ), creator_data) label = creator.label or creator.family item = QtWidgets.QListWidgetItem(label) 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/start.py b/start.py index 182e033945..05d4dcc709 100644 --- a/start.py +++ b/start.py @@ -176,6 +176,38 @@ def run(arguments: list, env: dict = None) -> int: return p.returncode +def set_avalon_environments(): + """Set avalon specific environments. + + These are non modifiable environments for avalon workflow that must be set + before avalon module is imported because avalon works with globals set with + environment variables. + """ + from pype import PACKAGE_DIR + + # Path to pype's schema + schema_path = os.path.join( + os.path.dirname(PACKAGE_DIR), + "schema" + ) + # Avalon mongo URL + avalon_mongo_url = ( + os.environ.get("AVALON_MONGO") + or os.environ["PYPE_MONGO"] + ) + os.environ.update({ + # Mongo url (use same as pype has) + "AVALON_MONGO": avalon_mongo_url, + + "AVALON_SCHEMA": schema_path, + # Mongo DB name where avalon docs are stored + "AVALON_DB": "avalon", + # Name of config + "AVALON_CONFIG": "pype", + "AVALON_LABEL": "Pype" + }) + + def set_modules_environments(): """Set global environments for pype modules. @@ -550,6 +582,8 @@ def boot(): from pype.lib import terminal as t from pype.version import __version__ print(">>> loading environments ...") + # Must happen before `set_modules_environments` + set_avalon_environments() set_modules_environments() assert version_path, "Version path not defined." 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