Merge branch 'develop' into feature/1004-deadline-better-handling-of-pype

This commit is contained in:
Milan Kolar 2021-03-04 16:51:13 +01:00
commit f2ae1684f0
105 changed files with 2393 additions and 784 deletions

3
.gitmodules vendored
View file

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

117
README.md
View file

@ -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>
<summary>Details for Ubuntu</summary>
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>
<details>
<summary>Details for Centos</summary>
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
```
</details>
<details>
<summary>Use pyenv to install Python version for Pype build</summary>
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
```
</details>
#### 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
------------

599
poetry.lock generated
View file

@ -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 <http://www.mongodb.org>"
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"},

View file

@ -1,2 +1,5 @@
[virtualenvs]
in-project = true
[repositories.pype]
url = "http://d.r1.wbsprt.com/pype.club/distribute/"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,6 @@
from avalon import harmony
from pype.api import PypeCreatorMixin
class Creator(PypeCreatorMixin, harmony.Creator):
pass

View file

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

View file

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

View file

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

View file

@ -592,7 +592,7 @@ class ClipLoader:
return track_item
class Creator(avalon.Creator):
class Creator(pype.Creator):
"""Creator class wrapper
"""
clip_color = "Purple"

View file

@ -0,0 +1,6 @@
from avalon import houdini
from pype.api import PypeCreatorMixin
class Creator(PypeCreatorMixin, houdini.Creator):
pass

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,6 @@
from pype.api import PypeCreatorMixin
from avalon.tvpaint import pipeline
class Creator(PypeCreatorMixin, pipeline.Creator):
pass

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,9 @@
from .app import (
App,
show
)
__all__ = [
"App",
"show"]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1 @@
HOST_NAME = "standalonepublisher"

View file

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

View file

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

View file

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

View file

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

@ -1 +1 @@
Subproject commit 93c4a89b3e98ae88030e62bb9ad6c07220b23234
Subproject commit eae14f2960c4ccf2f0211e0726e88563129c0296

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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