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