Update to v0.6.0

- Add new `commands` setting to handle multiple commands
- Deprecate `command` and `subcommands`
- Drop support for python 2
- Handle dependancy and build with Poetry
commands
Christophe Mehay 4 years ago
parent 55907d1a8c
commit 1770ac87f6

@ -3,3 +3,5 @@
!setup.py
!README.md
!tests
!poetry.lock
!pyproject.toml

1
.gitignore vendored

@ -90,4 +90,3 @@ ENV/
# Rope project settings
.ropeproject

@ -1,19 +1,22 @@
- repo: git://github.com/pre-commit/pre-commit-hooks
sha: v0.9.2
hooks:
- id: check-added-large-files
- id: check-docstring-first
- id: check-merge-conflict
- id: check-yaml
- id: end-of-file-fixer
- id: flake8
args:
- --exclude=__init__.py,docs/conf.py
- id: autopep8-wrapper
- id: requirements-txt-fixer
- id: trailing-whitespace
- repo: git://github.com/asottile/reorder_python_imports
sha: v0.3.5
hooks:
- id: reorder-python-imports
language_version: 'python2.7'
repos:
- repo: git://github.com/pre-commit/pre-commit-hooks
rev: v2.5.0
hooks:
- id: check-added-large-files
- id: check-docstring-first
- id: check-merge-conflict
- id: check-yaml
- id: end-of-file-fixer
- id: flake8
language_version: python3
- id: requirements-txt-fixer
- id: trailing-whitespace
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v1.5.2
hooks:
- id: autopep8
- repo: git://github.com/asottile/reorder_python_imports
rev: v2.3.0
hooks:
- id: reorder-python-imports
language_version: python3

@ -3,13 +3,20 @@ services:
- docker
language: python
before_install:
- pip install -r requirements-dev.txt
- pip install poetry
- poetry install -v
script:
- make test
deploy:
provider: pypi
user: cmehay
password:
secure: P3Xz/ZKIwY5AxFKqzf86gwXRCThKzsXK/D7tKXGH4yETI9JZuh4EyWHI0ozNXzNSThnwLmDhlhaTjq+hVtMEpfBF3iEXQ9svlXHDW70+PXkEp81Zkm2yNBKM0uZB1DJDMXFKbVaBIKiFXHocUmOEGwwPxmPe+6QXNFUuNNTlb/iBnpSATyhvFRdgpVT327DOsco7fzFytAdi9yA4y11fTTo/mQlTaLcWqKRrUFNeP50LLKXB7a/YSC2HNYy2op6linkrCgx+kLj2FxTuWBh5jxAk97t146h7VaoYh4FhSjZ2gssbKQkU0CUD1SjELWHKrsquHI6qJJyGiIUd4GUmoNMv4GWvja9n0KjP2Dc+M5qBkHkBBpe7DIzltil5RH91Fq3m2SLeCFmNg7nYHwh5Ng3dr5gHwo9L5EmSaixFYeax2jxaInPpUfW7pIxCiRFoIFBp63w2TGg3MGRnWOZYmozzJVRHmx9wE5zgX19Eb1Tm1MA9q8Pk5xXs0US0AGnIZ/yKBLAj4pbhN57c29zfcSbzpNM/Yq69RxYBCrmq484oKDU7DhXZXgsnErTufDYJ3/o4qNjiOmXMwxLn8zmJAhJ63JGQNNz+XHGOvwNq+OI2g6SnI3f5EU9UxiZ0n3un8M5YYiG67b6KdSu+dsYKMCV3Tiv0zjJbasVr6TzXHts=
before_deploy:
- poetry config http-basic.pypi $PYPI_USER $PYPI_PASSWORD
- poetry build
deploy:
provider: script
script: poetry publish
on:
tags: true
env:
global:
- secure: p5Cm+cSzWB5MsCSbl9p+NHT3OrxBGhhtXJxVoYh2twrYbVOZiUVqmd1YIzMJ/kI3Vq7hDN7AX1XKQcCX7URlf/Ms6Xb66I2jsmeX/pzMkyT+SonjeDR4AHif1Spa5uoS+kn5HKKprgfd5sAgJL7G6ML34wvNsemM4MukbucpdVPLh+kIXaN1mIhBVda3i48rHO3A08GCZbd4rSaTK/eHSXgo7kkfWSSMNeGhBW61xZeR63wo4EB5Ih84XdCObOV1QHMISnF8NuqEvfmPz6cxJuRiSMarCqxdQ3jZWSaNORhHUPyrJUDeLcU9DN24IvF5BPomTneCwgGKmwgZfVPwVXBGKKK7FaX0K5PpshA/qZpi62LRGPuScsn27NEiGIezsfqFnRRvn+3Pgs1/fhuFsFVMcWqORhprwrCr1SEM7yz5pFQTJTnCEcfUaRe29EHMVPD+dJ0FlSykxfbFhu4dcKsR6yCZXsoiepKMYPb0MLO0qyQLwjKhMhd+NLlw/Jl0dNF761MRX4QPuC4ecRBCmHwajgo+mc5VLdZp0VQwN938HWe1lughbk34lLDvRP1uHkWpvB6U2F1JYmwUYAkhgVlbjgK6rQIMpHen594XwPQcXqPlechMrA3q86A/JewwcYYmn35d5yHxRXhWLd/0CktryxysOZ9oldhgNgPkysA=
- secure: KE27UMwkm3L7uCLO3fR7JEfBULAfd2/lfwxjmGXZAD4WTASlraKByYj6hq9Pzj3E6tu1yemCWfZWr52pKLg1iFO7+fNOP52spNayjK4gYDrkp3O2bTTQeI5o6mClYGssGK1CsND+PyXcpLqfgj0QmC+y1U9zOsJhE9zB0/4a4QY9P/yNuehaKfOrCdeNpWa4cWPwHUMhwHBZxwTA5AUe8jCmv4tBkpsmTwNvu7PV0pdKo/s9uth7ggVBt6VDap7dSTwNEQiG7s85wf7l4vLIuQ0hmy5EvAyLa6/HED67b2yAN6Yv9kXCmDclSQxQmwN3jrjGEIv/kC5tJ6FqGSFtL1suRGVPSZLRMBB+vERMYHEDaUZ3G6Kayf6TGfvWE++WaqrruqyV6mQcsoTP9X/7SiOQtYso3mRtdMmx7HySc+hGPZOsDkACipwTy1lfvM6Y0rLXreidFBeK/unV2P5lGFsjP8ow04MgJ8F21BvFq+HYVcfwzRbE6VQnJWdN2lRuS3hKOHZ0Y5t4gBe8qGFhIwSsN/rIMdzeg4dzKaVKAKSK9qwOUIVC9mAl/V1ZfN7CpC8biYEY1XlhmVV+KECR9SGapb2laLftDYfz3R4833nOCGjgyFB9DxG5Rc9HfGMVqdYaDURbblSRb5vjVMWZLIvfNttrLmjLJI+j5T2dfQM=

@ -1,17 +1,22 @@
# Testing with python 3
# Testing with last python 3
FROM python:3
RUN pip3 install pytest six pyyaml jinja2 colorlog watchdog pytest-mock
ENV POETRY_VIRTUALENVS_CREATE=false
RUN pip install poetry
RUN adduser --uid 1009 --system testuser
RUN addgroup --gid 1010 testgroup
ENV PYTHONPATH /opt/
ADD tests/test_template.yml.tpl /tmp/test_template.yml
ADD tests/test_template.yml.tpl /tmp/test_template2.yml.tpl
COPY tests/test_template.yml.tpl /tmp/test_template.yml
COPY tests/test_template.yml.tpl /tmp/test_template2.yml.tpl
COPY pyproject.toml poetry.lock /opt/
RUN cd /opt && poetry install
WORKDIR /opt/tests
CMD ["py.test", "--verbose", "-rw", "."]
CMD ["pytest", "--verbose", "-rw", "."]

@ -0,0 +1,24 @@
# Testing with python 3.6
FROM python:3.6
ENV POETRY_VIRTUALENVS_CREATE=false
RUN pip install poetry
RUN adduser --uid 1009 --system testuser
RUN addgroup --gid 1010 testgroup
ENV PYTHONPATH /opt/
ADD tests/test_template.yml.tpl /tmp/test_template.yml
ADD tests/test_template.yml.tpl /tmp/test_template2.yml.tpl
COPY pyproject.toml poetry.lock /opt/
RUN cd /opt && poetry install
WORKDIR /opt/tests
CMD ["pytest", "--verbose", "-rw", "."]

@ -1,8 +1,10 @@
# Testing with python 2
# Testing with python 3.7
FROM python:2
FROM python:3.7
ENV POETRY_VIRTUALENVS_CREATE=false
RUN pip install pytest six pyyaml jinja2 colorlog watchdog pytest-mock
RUN pip install poetry
RUN adduser --uid 1009 --system testuser
RUN addgroup --gid 1010 testgroup
@ -11,7 +13,11 @@ ENV PYTHONPATH /opt/
ADD tests/test_template.yml.tpl /tmp/test_template.yml
ADD tests/test_template.yml.tpl /tmp/test_template2.yml.tpl
COPY pyproject.toml poetry.lock /opt/
RUN cd /opt && poetry install
WORKDIR /opt/tests
CMD ["py.test", "--verbose", "-rw", "."]
CMD ["pytest", "--verbose", "-rw", "."]

@ -0,0 +1,22 @@
# Testing with python 3.8
FROM python:3.8
ENV POETRY_VIRTUALENVS_CREATE=false
RUN pip install poetry
RUN adduser --uid 1009 --system testuser
RUN addgroup --gid 1010 testgroup
ENV PYTHONPATH /opt/
COPY tests/test_template.yml.tpl /tmp/test_template.yml
COPY tests/test_template.yml.tpl /tmp/test_template2.yml.tpl
COPY pyproject.toml poetry.lock /opt/
RUN cd /opt && poetry install
WORKDIR /opt/tests
CMD ["pytest", "--verbose", "-rw", "."]

@ -1,12 +0,0 @@
FROM python:2
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip && \
python setup.py install && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .
ENTRYPOINT ["pyentrypoint"]

@ -1,12 +0,0 @@
FROM python:2-alpine
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip && \
python setup.py install && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .
ENTRYPOINT ["pyentrypoint"]

@ -1,10 +1,12 @@
FROM python:3
ENV POETRY_VIRTUALENVS_CREATE=false
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip && \
python setup.py install && \
pip install --upgrade pip poetry && \
poetry install --no-dev && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .

@ -1,10 +1,12 @@
FROM python:3-alpine
ENV POETRY_VIRTUALENVS_CREATE=false
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip && \
python setup.py install && \
pip install --upgrade pip poetry && \
poetry install --no-dev && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .

@ -0,0 +1,14 @@
FROM python:3.6
ENV POETRY_VIRTUALENVS_CREATE=false
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip poetry && \
poetry install --no-dev && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .
ENTRYPOINT ["pyentrypoint"]

@ -0,0 +1,14 @@
FROM python:3.6-alpine
ENV POETRY_VIRTUALENVS_CREATE=false
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip poetry && \
poetry install --no-dev && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .
ENTRYPOINT ["pyentrypoint"]

@ -0,0 +1,14 @@
FROM python:3.7
ENV POETRY_VIRTUALENVS_CREATE=false
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip poetry && \
poetry install --no-dev && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .
ENTRYPOINT ["pyentrypoint"]

@ -0,0 +1,14 @@
FROM python:3.7-alpine
ENV POETRY_VIRTUALENVS_CREATE=false
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip poetry && \
poetry install --no-dev && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .
ENTRYPOINT ["pyentrypoint"]

@ -0,0 +1,14 @@
FROM python:3.8
ENV POETRY_VIRTUALENVS_CREATE=false
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip poetry && \
poetry install --no-dev && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .
ENTRYPOINT ["pyentrypoint"]

@ -0,0 +1,14 @@
FROM python:3.8-alpine
ENV POETRY_VIRTUALENVS_CREATE=false
ADD . /tmp/
RUN cd /tmp && \
pip install --upgrade pip poetry && \
poetry install --no-dev && \
rm -rf *
ONBUILD ADD entrypoint-config.yml .
ENTRYPOINT ["pyentrypoint"]

@ -1,2 +1 @@
include README.md

@ -6,17 +6,20 @@ build:
clean:
docker-compose down --remove-orphans
test: build test-python2 test-python3 clean
test: build test-python3.6 test-python3.7 test-python3.8 clean
test-python2:
@docker-compose run --rm testpython2
test-python3.6:
@docker-compose run --rm testpython3.6
test-python3.7:
@docker-compose run --rm testpython3.7
test-python3.8:
@docker-compose run --rm testpython3.8
test-python3:
@docker-compose run --rm testpython3
test_debug: build
@docker-compose up --force-recreate testpython2_debug testpython3_debug
publish:
@python setup.py register && python setup.py sdist upload

@ -11,6 +11,13 @@ This tool avoids writing shell scripts to:
[![Documentation Status](https://readthedocs.org/projects/pyentrypoint/badge/?version=latest)](http://pyentrypoint.readthedocs.io/en/latest/?badge=latest) [![Build Status](https://travis-ci.org/cmehay/pyentrypoint.svg?branch=master)](https://travis-ci.org/cmehay/pyentrypoint)
## Changelog
* V0.6.0 (2020-05-10)
* Drop python 2 support
* Deprecation of `command` and `subcommands` settings for `commands` (see bellow)
## Usages
### Install in container
@ -56,10 +63,17 @@ FROM goldy/pyentrypoint:python3
Available with many flavours:
- `goldy/pyentrypoint:python2`
- `goldy/pyentrypoint:python3`
- `goldy/pyentrypoint:python2-alpine`
- `goldy/pyentrypoint:python3.6`
- `goldy/pyentrypoint:python3.7`
- `goldy/pyentrypoint:python3.8`
- `goldy/pyentrypoint:python3-alpine`
- `goldy/pyentrypoint:python3.6-alpine`
- `goldy/pyentrypoint:python3.7-alpine`
- `goldy/pyentrypoint:python3.8-alpine`
### Working examples
- [Tor hidden service](https://github.com/cmehay/docker-tor-hidden-service)
@ -71,12 +85,26 @@ This is an example of `entrypoint-config.yml` file.
```yaml
# Entrypoint configuration example
# This entry list commands handled by entrypoint.
# If you run the container with a command not in this list,
# pyentrypoint will run the command directly without any action
# If this option and `command` are not set, all commands will be handled.
# Support wildcard
commands:
- git
- sl*
# DEPRECATED: This option is remplaced by `commands`
# This entry should reflect CMD in Dockerfile
# If `commands` is present, this option will be ignored.
# DEPRECATED: This option is remplaced by `commands`
command: git
# DEPRECATED: This option will be dropped
# This is a list with some subcommands to handle
# when CMD is not `git` here.
# By default, all args started with hyphen are handled.
# DEPRECATED: This option will be dropped
subcommands:
- "-*"
- clone
@ -91,7 +119,7 @@ subcommands:
user: 1000
group: 1000
# These files should exist (ADD or COPY)
# These files should exist (ADD, COPY or mounted)
# and should be jinja templated.
# Note: if config files end with ".tpl", the extension will be removed.
config_files:

@ -13,9 +13,9 @@ testpython3:
file: common.yml
service: environ
testpython2:
testpython3.6:
build: .
dockerfile: Dockerfile-test.py2
dockerfile: Dockerfile-test.py3.6
volumes:
- ./pyentrypoint:/opt/pyentrypoint:ro
- ./tests:/opt/tests
@ -28,9 +28,9 @@ testpython2:
file: common.yml
service: environ
testpython3_debug:
testpython3.7:
build: .
dockerfile: Dockerfile-test.py3
dockerfile: Dockerfile-test.py3.7
volumes:
- ./pyentrypoint:/opt/pyentrypoint:ro
- ./tests:/opt/tests
@ -39,14 +39,13 @@ testpython3_debug:
- test2
- test3
- test4
command: ["py.test", "--verbose", "-s", "-rw", "."]
extends:
file: common.yml
service: environ
testpython2_debug:
testpython3.8:
build: .
dockerfile: Dockerfile-test.py2
dockerfile: Dockerfile-test.py3.8
volumes:
- ./pyentrypoint:/opt/pyentrypoint:ro
- ./tests:/opt/tests
@ -55,7 +54,6 @@ testpython2_debug:
- test2
- test3
- test4
command: ["py.test", "--verbose", "-s", "-rw", "."]
extends:
file: common.yml
service: environ

@ -15,9 +15,10 @@
import os
import sys
from setup import __version__
sys.path.insert(0, os.path.abspath('..'))
from setup import __version__
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the

@ -7,12 +7,26 @@ This is an example of ``entrypoint-config.yml`` file.
# Entrypoint configuration example
# This entry list commands handled by entrypoint.
# If you run the container with a command not in this list,
# pyentrypoint will run the command directly without any action
# If this option and `command` are not set, all commands will be handled.
# Support wildcard
commands:
- git
- sl*
# DEPRECATED: This option is remplaced by `commands`
# This entry should reflect CMD in Dockerfile
# If `commands` is present, this option will be ignored.
# DEPRECATED: This option is remplaced by `commands`
command: git
# DEPRECATED: This option will be dropped
# This is a list with some subcommands to handle
# when CMD is not `git` here.
# By default, all args started with hyphen are handled.
# DEPRECATED: This option will be dropped
subcommands:
- "-*"
- clone

@ -1,16 +1,31 @@
# Entrypoint configuration example
# This entry list commands handled by entrypoint.
# If you run the container with a command not in this list,
# pyentrypoint will run the command directly without any action
# If this option is not set, all commands will be handled.
# Support wildcard
commands:
- git
- l*
# DEPRECATED: This option is remplaced by `commands`
# This entry should reflect CMD in Dockerfile
command: git
# If `commands` is present, this option will be ignored.
# DEPRECATED: This option is remplaced by `commands`
# command: git
# DEPRECATED: This option will be dropped
# This is a list with some subcommands to handle
# when CMD is not `git` here.
# By default, all args started with hyphen are handled.
subcommands:
- "-*"
- clone
- init
- ls-files
# DEPRECATED: This option will be dropped
# subcommands:
# - "-*"
# - clone
# - init
# - ls-files
# etc...
# User and group to run the cmd.
@ -33,9 +48,11 @@ secret_env:
- SSHKEY
- '*' # Support globbing, all environment will be wiped
# DEPRECATED: Links are deprecated in `docker`
# Links are handled here
# Port, name, protocol or env variable can be used to identify the links
# Raise an error if the link could not be identified
# DEPRECATED: Links are deprecated in `docker`
links:
'ssh':
port: 22

992
poetry.lock generated

@ -0,0 +1,992 @@
[[package]]
category = "dev"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
name = "appdirs"
optional = false
python-versions = "*"
version = "1.4.3"
[[package]]
category = "dev"
description = "Atomic file writes."
marker = "sys_platform == \"win32\""
name = "atomicwrites"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.4.0"
[[package]]
category = "dev"
description = "Classes Without Boilerplate"
name = "attrs"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "19.3.0"
[package.extras]
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
docs = ["sphinx", "zope.interface"]
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
[[package]]
category = "dev"
description = "Modern password hashing for your software and your servers"
name = "bcrypt"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "3.1.7"
[package.dependencies]
cffi = ">=1.1"
six = ">=1.4.1"
[package.extras]
tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)"]
[[package]]
category = "dev"
description = "A decorator for caching properties in classes."
name = "cached-property"
optional = false
python-versions = "*"
version = "1.5.1"
[[package]]
category = "dev"
description = "Python package for providing Mozilla's CA Bundle."
name = "certifi"
optional = false
python-versions = "*"
version = "2020.4.5.1"
[[package]]
category = "dev"
description = "Foreign Function Interface for Python calling C code."
name = "cffi"
optional = false
python-versions = "*"
version = "1.14.0"
[package.dependencies]
pycparser = "*"
[[package]]
category = "dev"
description = "Validate configuration and produce human readable error messages."
name = "cfgv"
optional = false
python-versions = ">=3.6.1"
version = "3.1.0"
[[package]]
category = "dev"
description = "Universal encoding detector for Python 2 and 3"
name = "chardet"
optional = false
python-versions = "*"
version = "3.0.4"
[[package]]
category = "main"
description = "Cross-platform colored terminal text."
marker = "sys_platform == \"win32\""
name = "colorama"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.4.3"
[[package]]
category = "main"
description = "Log formatting with colors!"
name = "colorlog"
optional = false
python-versions = "*"
version = "4.1.0"
[package.dependencies]
colorama = "*"
[[package]]
category = "dev"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
name = "cryptography"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
version = "2.9.2"
[package.dependencies]
cffi = ">=1.8,<1.11.3 || >1.11.3"
six = ">=1.4.1"
[package.extras]
docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"]
docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
idna = ["idna (>=2.1)"]
pep8test = ["flake8", "flake8-import-order", "pep8-naming"]
test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"]
[[package]]
category = "dev"
description = "Distribution utilities"
name = "distlib"
optional = false
python-versions = "*"
version = "0.3.0"
[[package]]
category = "dev"
description = "A Python library for the Docker Engine API."
name = "docker"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "4.2.0"
[package.dependencies]
requests = ">=2.14.2,<2.18.0 || >2.18.0"
six = ">=1.4.0"
websocket-client = ">=0.32.0"
[package.dependencies.paramiko]
optional = true
version = ">=2.4.2"
[package.dependencies.pypiwin32]
python = ">=3.6"
version = "223"
[package.extras]
ssh = ["paramiko (>=2.4.2)"]
tls = ["pyOpenSSL (>=17.5.0)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"]
[[package]]
category = "dev"
description = "Multi-container orchestration for Docker"
name = "docker-compose"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.25.5"
[package.dependencies]
PyYAML = ">=3.10,<6"
cached-property = ">=1.2.0,<2"
colorama = ">=0.4,<1"
dockerpty = ">=0.4.1,<1"
docopt = ">=0.6.1,<1"
jsonschema = ">=2.5.1,<4"
requests = ">=2.20.0,<3"
six = ">=1.3.0,<2"
texttable = ">=0.9.0,<2"
websocket-client = ">=0.32.0,<1"
[package.dependencies.docker]
extras = ["ssh"]
version = ">=3.7.0,<5"
[package.extras]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2)"]
[[package]]
category = "dev"
description = "Python library to use the pseudo-tty of a docker container"
name = "dockerpty"
optional = false
python-versions = "*"
version = "0.4.1"
[package.dependencies]
six = ">=1.3.0"
[[package]]
category = "dev"
description = "Pythonic argument parser, that will make you smile"
name = "docopt"
optional = false
python-versions = "*"
version = "0.6.2"
[[package]]
category = "dev"
description = "A platform independent file lock."
name = "filelock"
optional = false
python-versions = "*"
version = "3.0.12"
[[package]]
category = "dev"
description = "File identification library for Python"
name = "identify"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "1.4.15"
[package.extras]
license = ["editdistance"]
[[package]]
category = "dev"
description = "Internationalized Domain Names in Applications (IDNA)"
name = "idna"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.9"
[[package]]
category = "dev"
description = "Read metadata from Python packages"
marker = "python_version < \"3.8\""
name = "importlib-metadata"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
version = "1.6.0"
[package.dependencies]
zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "rst.linker"]
testing = ["packaging", "importlib-resources"]
[[package]]
category = "dev"
description = "Read resources from Python packages"
marker = "python_version < \"3.7\""
name = "importlib-resources"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
version = "1.5.0"
[package.dependencies]
[package.dependencies.importlib-metadata]
python = "<3.8"
version = "*"
[package.dependencies.zipp]
python = "<3.8"
version = ">=0.4"
[package.extras]
docs = ["sphinx", "rst.linker", "jaraco.packaging"]
[[package]]
category = "main"
description = "A very fast and expressive template engine."
name = "jinja2"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.11.2"
[package.dependencies]
MarkupSafe = ">=0.23"
[package.extras]
i18n = ["Babel (>=0.8)"]
[[package]]
category = "dev"
description = "An implementation of JSON Schema validation for Python"
name = "jsonschema"
optional = false
python-versions = "*"
version = "3.2.0"
[package.dependencies]
attrs = ">=17.4.0"
pyrsistent = ">=0.14.0"
setuptools = "*"
six = ">=1.11.0"
[package.dependencies.importlib-metadata]
python = "<3.8"
version = "*"
[package.extras]
format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"]
format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"]
[[package]]
category = "main"
description = "Safely add untrusted strings to HTML/XML markup."
name = "markupsafe"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "1.1.1"
[[package]]
category = "dev"
description = "More routines for operating on iterables, beyond itertools"
name = "more-itertools"
optional = false
python-versions = ">=3.5"
version = "8.2.0"
[[package]]
category = "dev"
description = "Node.js virtual environment builder"
name = "nodeenv"
optional = false
python-versions = "*"
version = "1.3.5"
[[package]]
category = "dev"
description = "Core utilities for Python packages"
name = "packaging"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "20.3"
[package.dependencies]
pyparsing = ">=2.0.2"
six = "*"
[[package]]
category = "dev"
description = "SSH2 protocol library"
name = "paramiko"
optional = false
python-versions = "*"
version = "2.7.1"
[package.dependencies]
bcrypt = ">=3.1.3"
cryptography = ">=2.5"
pynacl = ">=1.0.1"
[package.extras]
all = ["pyasn1 (>=0.1.7)", "pynacl (>=1.0.1)", "bcrypt (>=3.1.3)", "invoke (>=1.3)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"]
ed25519 = ["pynacl (>=1.0.1)", "bcrypt (>=3.1.3)"]
gssapi = ["pyasn1 (>=0.1.7)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"]
invoke = ["invoke (>=1.3)"]
[[package]]
category = "main"
description = "File system general utilities"
name = "pathtools"
optional = false
python-versions = "*"
version = "0.1.2"
[[package]]
category = "dev"
description = "plugin and hook calling mechanisms for python"
name = "pluggy"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.13.1"
[package.dependencies]
[package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12"
[package.extras]
dev = ["pre-commit", "tox"]
[[package]]
category = "dev"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
name = "pre-commit"
optional = false
python-versions = ">=3.6.1"
version = "2.3.0"
[package.dependencies]
cfgv = ">=2.0.0"
identify = ">=1.0.0"
nodeenv = ">=0.11.1"
pyyaml = ">=5.1"
toml = "*"
virtualenv = ">=15.2"
[package.dependencies.importlib-metadata]
python = "<3.8"
version = "*"
[package.dependencies.importlib-resources]
python = "<3.7"
version = "*"
[[package]]
category = "dev"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
name = "py"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.8.1"
[[package]]
category = "dev"
description = "C parser in Python"
name = "pycparser"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.20"
[[package]]
category = "dev"
description = "Python binding to the Networking and Cryptography (NaCl) library"
name = "pynacl"
optional = false
python-versions = "*"
version = "1.3.0"
[package.dependencies]
cffi = ">=1.4.1"
six = "*"
[package.extras]
docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)", "hypothesis (>=3.27.0)"]
[[package]]
category = "dev"
description = "Python parsing module"
name = "pyparsing"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
version = "2.4.7"
[[package]]
category = "dev"
description = ""
marker = "sys_platform == \"win32\" and python_version >= \"3.6\""
name = "pypiwin32"
optional = false
python-versions = "*"
version = "223"
[package.dependencies]
pywin32 = ">=223"
[[package]]
category = "dev"
description = "Persistent/Functional/Immutable data structures"
name = "pyrsistent"
optional = false
python-versions = "*"
version = "0.16.0"
[package.dependencies]
six = "*"
[[package]]
category = "dev"
description = "pytest: simple powerful testing with Python"
name = "pytest"
optional = false
python-versions = ">=3.5"
version = "5.4.2"
[package.dependencies]
atomicwrites = ">=1.0"
attrs = ">=17.4.0"
colorama = "*"
more-itertools = ">=4.0.0"
packaging = "*"
pluggy = ">=0.12,<1.0"
py = ">=1.5.0"
wcwidth = "*"
[package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12"
[package.extras]
checkqa-mypy = ["mypy (v0.761)"]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
[[package]]
category = "dev"
description = "Thin-wrapper around the mock package for easier use with pytest"
name = "pytest-mock"
optional = false
python-versions = ">=3.5"
version = "3.1.0"
[package.dependencies]
pytest = ">=2.7"
[package.extras]
dev = ["pre-commit", "tox", "pytest-asyncio"]
[[package]]
category = "dev"
description = "Python for Window Extensions"
marker = "sys_platform == \"win32\" and python_version >= \"3.6\""
name = "pywin32"
optional = false
python-versions = "*"
version = "227"
[[package]]
category = "main"
description = "YAML parser and emitter for Python"
name = "pyyaml"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "5.3.1"
[[package]]
category = "dev"
description = "Python HTTP for Humans."
name = "requests"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.23.0"
[package.dependencies]
certifi = ">=2017.4.17"
chardet = ">=3.0.2,<4"
idna = ">=2.5,<3"
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
[package.extras]
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
[[package]]
category = "main"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.14.0"
[[package]]
category = "dev"
description = "module for creating simple ASCII tables"
name = "texttable"
optional = false
python-versions = "*"
version = "1.6.2"
[[package]]
category = "dev"
description = "Python Library for Tom's Obvious, Minimal Language"
name = "toml"
optional = false
python-versions = "*"
version = "0.10.0"
[[package]]
category = "dev"
description = "HTTP library with thread-safe connection pooling, file post, and more."
name = "urllib3"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "1.25.9"
[package.extras]
brotli = ["brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
[[package]]
category = "dev"
description = "Virtual Python Environment builder"
name = "virtualenv"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "20.0.20"
[package.dependencies]
appdirs = ">=1.4.3,<2"
distlib = ">=0.3.0,<1"
filelock = ">=3.0.0,<4"
six = ">=1.9.0,<2"
[package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12,<2"
[package.dependencies.importlib-resources]
python = "<3.7"
version = ">=1.0,<2"
[package.extras]
docs = ["sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)", "proselint (>=0.10.2)"]
testing = ["pytest (>=4)", "coverage (>=5)", "coverage-enable-subprocess (>=1)", "pytest-xdist (>=1.31.0)", "pytest-mock (>=2)", "pytest-env (>=0.6.2)", "pytest-randomly (>=1)", "pytest-timeout", "packaging (>=20.0)", "xonsh (>=0.9.16)"]
[[package]]
category = "main"
description = "Filesystem events monitoring"
name = "watchdog"
optional = false
python-versions = "*"
version = "0.10.2"
[package.dependencies]
pathtools = ">=0.1.1"
[package.extras]
watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"]
[[package]]
category = "dev"
description = "Measures number of Terminal column cells of wide-character codes"
name = "wcwidth"
optional = false
python-versions = "*"
version = "0.1.9"
[[package]]
category = "dev"
description = "WebSocket client for Python. hybi13 is supported."
name = "websocket-client"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.57.0"
[package.dependencies]
six = "*"
[[package]]
category = "dev"
description = "Backport of pathlib-compatible object wrapper for zip files"
marker = "python_version < \"3.8\""
name = "zipp"
optional = false
python-versions = ">=3.6"
version = "3.1.0"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["jaraco.itertools", "func-timeout"]
[metadata]
content-hash = "d5b4ce6c6aa76b713725b2fb9726798fffff606425e3434a1511ab75afe6dd56"
python-versions = "^3.6.1"
[metadata.files]
appdirs = [
{file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"},
{file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"},
]
atomicwrites = [
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
]
attrs = [
{file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
]
bcrypt = [
{file = "bcrypt-3.1.7-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7"},
{file = "bcrypt-3.1.7-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31"},
{file = "bcrypt-3.1.7-cp27-cp27m-win32.whl", hash = "sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161"},
{file = "bcrypt-3.1.7-cp27-cp27m-win_amd64.whl", hash = "sha256:9fe92406c857409b70a38729dbdf6578caf9228de0aef5bc44f859ffe971a39e"},
{file = "bcrypt-3.1.7-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:763669a367869786bb4c8fcf731f4175775a5b43f070f50f46f0b59da45375d0"},
{file = "bcrypt-3.1.7-cp34-abi3-macosx_10_6_intel.whl", hash = "sha256:a190f2a5dbbdbff4b74e3103cef44344bc30e61255beb27310e2aec407766052"},
{file = "bcrypt-3.1.7-cp34-abi3-manylinux1_x86_64.whl", hash = "sha256:c9457fa5c121e94a58d6505cadca8bed1c64444b83b3204928a866ca2e599105"},
{file = "bcrypt-3.1.7-cp34-cp34m-win32.whl", hash = "sha256:8b10acde4e1919d6015e1df86d4c217d3b5b01bb7744c36113ea43d529e1c3de"},
{file = "bcrypt-3.1.7-cp34-cp34m-win_amd64.whl", hash = "sha256:cb93f6b2ab0f6853550b74e051d297c27a638719753eb9ff66d1e4072be67133"},
{file = "bcrypt-3.1.7-cp35-cp35m-win32.whl", hash = "sha256:6fe49a60b25b584e2f4ef175b29d3a83ba63b3a4df1b4c0605b826668d1b6be5"},
{file = "bcrypt-3.1.7-cp35-cp35m-win_amd64.whl", hash = "sha256:a595c12c618119255c90deb4b046e1ca3bcfad64667c43d1166f2b04bc72db09"},
{file = "bcrypt-3.1.7-cp36-cp36m-win32.whl", hash = "sha256:74a015102e877d0ccd02cdeaa18b32aa7273746914a6c5d0456dd442cb65b99c"},
{file = "bcrypt-3.1.7-cp36-cp36m-win_amd64.whl", hash = "sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89"},
{file = "bcrypt-3.1.7-cp37-cp37m-win32.whl", hash = "sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294"},
{file = "bcrypt-3.1.7-cp37-cp37m-win_amd64.whl", hash = "sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc"},
{file = "bcrypt-3.1.7-cp38-cp38-win32.whl", hash = "sha256:ce4e4f0deb51d38b1611a27f330426154f2980e66582dc5f438aad38b5f24fc1"},
{file = "bcrypt-3.1.7-cp38-cp38-win_amd64.whl", hash = "sha256:6305557019906466fc42dbc53b46da004e72fd7a551c044a827e572c82191752"},
{file = "bcrypt-3.1.7.tar.gz", hash = "sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42"},
]
cached-property = [
{file = "cached-property-1.5.1.tar.gz", hash = "sha256:9217a59f14a5682da7c4b8829deadbfc194ac22e9908ccf7c8820234e80a1504"},
{file = "cached_property-1.5.1-py2.py3-none-any.whl", hash = "sha256:3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f"},
]
certifi = [
{file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"},
{file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"},
]
cffi = [
{file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"},
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"},
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"},
{file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"},
{file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"},
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"},
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"},
{file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"},
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"},
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"},
{file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"},
{file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"},
{file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"},
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"},
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"},
{file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"},
{file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"},
{file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"},
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"},
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"},
{file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"},
{file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"},
{file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"},
{file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"},
{file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"},
{file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"},
{file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"},
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"},
]
cfgv = [
{file = "cfgv-3.1.0-py2.py3-none-any.whl", hash = "sha256:1ccf53320421aeeb915275a196e23b3b8ae87dea8ac6698b1638001d4a486d53"},
{file = "cfgv-3.1.0.tar.gz", hash = "sha256:c8e8f552ffcc6194f4e18dd4f68d9aef0c0d58ae7e7be8c82bee3c5e9edfa513"},
]
chardet = [
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
]
colorama = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
]
colorlog = [
{file = "colorlog-4.1.0-py2.py3-none-any.whl", hash = "sha256:732c191ebbe9a353ec160d043d02c64ddef9028de8caae4cfa8bd49b6afed53e"},
{file = "colorlog-4.1.0.tar.gz", hash = "sha256:30aaef5ab2a1873dec5da38fd6ba568fa761c9fa10b40241027fa3edea47f3d2"},
]
cryptography = [
{file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"},
{file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"},
{file = "cryptography-2.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365"},
{file = "cryptography-2.9.2-cp27-cp27m-win32.whl", hash = "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0"},
{file = "cryptography-2.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55"},
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270"},
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf"},
{file = "cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d"},
{file = "cryptography-2.9.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785"},
{file = "cryptography-2.9.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b"},
{file = "cryptography-2.9.2-cp35-cp35m-win32.whl", hash = "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae"},
{file = "cryptography-2.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b"},
{file = "cryptography-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6"},
{file = "cryptography-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3"},
{file = "cryptography-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b"},
{file = "cryptography-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e"},
{file = "cryptography-2.9.2-cp38-cp38-win32.whl", hash = "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0"},
{file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"},
{file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"},
]
distlib = [
{file = "distlib-0.3.0.zip", hash = "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21"},
]
docker = [
{file = "docker-4.2.0-py2.py3-none-any.whl", hash = "sha256:1c2ddb7a047b2599d1faec00889561316c674f7099427b9c51e8cb804114b553"},
{file = "docker-4.2.0.tar.gz", hash = "sha256:ddae66620ab5f4bce769f64bcd7934f880c8abe6aa50986298db56735d0f722e"},
]
docker-compose = [
{file = "docker-compose-1.25.5.tar.gz", hash = "sha256:7a2eb6d8173fdf408e505e6f7d497ac0b777388719542be9e49a0efd477a50c6"},
{file = "docker_compose-1.25.5-py2.py3-none-any.whl", hash = "sha256:9d33520ae976f524968a64226516ec631dce09fba0974ce5366ad403e203eb5d"},
]
dockerpty = [
{file = "dockerpty-0.4.1.tar.gz", hash = "sha256:69a9d69d573a0daa31bcd1c0774eeed5c15c295fe719c61aca550ed1393156ce"},
]
docopt = [
{file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"},
]
filelock = [
{file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
]
identify = [
{file = "identify-1.4.15-py2.py3-none-any.whl", hash = "sha256:88ed90632023e52a6495749c6732e61e08ec9f4f04e95484a5c37b9caf40283c"},
{file = "identify-1.4.15.tar.gz", hash = "sha256:23c18d97bb50e05be1a54917ee45cc61d57cb96aedc06aabb2b02331edf0dbf0"},
]
idna = [
{file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"},
{file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"},
]
importlib-metadata = [
{file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"},
{file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"},
]
importlib-resources = [
{file = "importlib_resources-1.5.0-py2.py3-none-any.whl", hash = "sha256:85dc0b9b325ff78c8bef2e4ff42616094e16b98ebd5e3b50fe7e2f0bbcdcde49"},
{file = "importlib_resources-1.5.0.tar.gz", hash = "sha256:6f87df66833e1942667108628ec48900e02a4ab4ad850e25fbf07cb17cf734ca"},
]
jinja2 = [
{file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
{file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"},
]
jsonschema = [
{file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"},
{file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"},
]
markupsafe = [
{file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"},
{file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"},
{file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"},
{file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"},
{file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
{file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"},
{file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"},
{file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"},
{file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"},
{file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
]
more-itertools = [
{file = "more-itertools-8.2.0.tar.gz", hash = "sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507"},
{file = "more_itertools-8.2.0-py3-none-any.whl", hash = "sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c"},
]
nodeenv = [
{file = "nodeenv-1.3.5-py2.py3-none-any.whl", hash = "sha256:5b2438f2e42af54ca968dd1b374d14a1194848955187b0e5e4be1f73813a5212"},
]
packaging = [
{file = "packaging-20.3-py2.py3-none-any.whl", hash = "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"},
{file = "packaging-20.3.tar.gz", hash = "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3"},
]
paramiko = [
{file = "paramiko-2.7.1-py2.py3-none-any.whl", hash = "sha256:9c980875fa4d2cb751604664e9a2d0f69096643f5be4db1b99599fe114a97b2f"},
{file = "paramiko-2.7.1.tar.gz", hash = "sha256:920492895db8013f6cc0179293147f830b8c7b21fdfc839b6bad760c27459d9f"},
]
pathtools = [
{file = "pathtools-0.1.2.tar.gz", hash = "sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"},
]
pluggy = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
]
pre-commit = [
{file = "pre_commit-2.3.0-py2.py3-none-any.whl", hash = "sha256:979b53dab1af35063a483bfe13b0fcbbf1a2cf8c46b60e0a9a8d08e8269647a1"},
{file = "pre_commit-2.3.0.tar.gz", hash = "sha256:f3e85e68c6d1cbe7828d3471896f1b192cfcf1c4d83bf26e26beeb5941855257"},
]
py = [
{file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"},
{file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"},
]
pycparser = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
]
pynacl = [
{file = "PyNaCl-1.3.0-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:2424c8b9f41aa65bbdbd7a64e73a7450ebb4aa9ddedc6a081e7afcc4c97f7621"},
{file = "PyNaCl-1.3.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39"},
{file = "PyNaCl-1.3.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:05c26f93964373fc0abe332676cb6735f0ecad27711035b9472751faa8521255"},
{file = "PyNaCl-1.3.0-cp27-cp27m-win32.whl", hash = "sha256:a14e499c0f5955dcc3991f785f3f8e2130ed504fa3a7f44009ff458ad6bdd17f"},
{file = "PyNaCl-1.3.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f67814c38162f4deb31f68d590771a29d5ae3b1bd64b75cf232308e5c74777e0"},
{file = "PyNaCl-1.3.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:e2da3c13307eac601f3de04887624939aca8ee3c9488a0bb0eca4fb9401fc6b1"},
{file = "PyNaCl-1.3.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0d0a8171a68edf51add1e73d2159c4bc19fc0718e79dec51166e940856c2f28e"},
{file = "PyNaCl-1.3.0-cp34-abi3-macosx_10_6_intel.whl", hash = "sha256:4943decfc5b905748f0756fdd99d4f9498d7064815c4cf3643820c9028b711d1"},
{file = "PyNaCl-1.3.0-cp34-abi3-manylinux1_i686.whl", hash = "sha256:5bd61e9b44c543016ce1f6aef48606280e45f892a928ca7068fba30021e9b786"},
{file = "PyNaCl-1.3.0-cp34-abi3-manylinux1_x86_64.whl", hash = "sha256:aabb0c5232910a20eec8563503c153a8e78bbf5459490c49ab31f6adf3f3a415"},
{file = "PyNaCl-1.3.0-cp34-cp34m-win32.whl", hash = "sha256:7d3ce02c0784b7cbcc771a2da6ea51f87e8716004512493a2b69016326301c3b"},
{file = "PyNaCl-1.3.0-cp34-cp34m-win_amd64.whl", hash = "sha256:1c780712b206317a746ace34c209b8c29dbfd841dfbc02aa27f2084dd3db77ae"},
{file = "PyNaCl-1.3.0-cp35-cp35m-win32.whl", hash = "sha256:37aa336a317209f1bb099ad177fef0da45be36a2aa664507c5d72015f956c310"},
{file = "PyNaCl-1.3.0-cp35-cp35m-win_amd64.whl", hash = "sha256:57ef38a65056e7800859e5ba9e6091053cd06e1038983016effaffe0efcd594a"},
{file = "PyNaCl-1.3.0-cp36-cp36m-win32.whl", hash = "sha256:a39f54ccbcd2757d1d63b0ec00a00980c0b382c62865b61a505163943624ab20"},
{file = "PyNaCl-1.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6482d3017a0c0327a49dddc8bd1074cc730d45db2ccb09c3bac1f8f32d1eb61b"},
{file = "PyNaCl-1.3.0-cp37-cp37m-win32.whl", hash = "sha256:2d23c04e8d709444220557ae48ed01f3f1086439f12dbf11976e849a4926db56"},
{file = "PyNaCl-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bd4ecb473a96ad0f90c20acba4f0bf0df91a4e03a1f4dd6a4bdc9ca75aa3a715"},
{file = "PyNaCl-1.3.0-cp38-cp38-win32.whl", hash = "sha256:53126cd91356342dcae7e209f840212a58dcf1177ad52c1d938d428eebc9fee5"},
{file = "PyNaCl-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:bf459128feb543cfca16a95f8da31e2e65e4c5257d2f3dfa8c0c1031139c9c92"},
{file = "PyNaCl-1.3.0.tar.gz", hash = "sha256:0c6100edd16fefd1557da078c7a31e7b7d7a52ce39fdca2bec29d4f7b6e7600c"},
]
pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pypiwin32 = [
{file = "pypiwin32-223-py3-none-any.whl", hash = "sha256:67adf399debc1d5d14dffc1ab5acacb800da569754fafdc576b2a039485aa775"},
{file = "pypiwin32-223.tar.gz", hash = "sha256:71be40c1fbd28594214ecaecb58e7aa8b708eabfa0125c8a109ebd51edbd776a"},
]
pyrsistent = [
{file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"},
]
pytest = [
{file = "pytest-5.4.2-py3-none-any.whl", hash = "sha256:95c710d0a72d91c13fae35dce195633c929c3792f54125919847fdcdf7caa0d3"},
{file = "pytest-5.4.2.tar.gz", hash = "sha256:eb2b5e935f6a019317e455b6da83dd8650ac9ffd2ee73a7b657a30873d67a698"},
]
pytest-mock = [
{file = "pytest-mock-3.1.0.tar.gz", hash = "sha256:ce610831cedeff5331f4e2fc453a5dd65384303f680ab34bee2c6533855b431c"},
{file = "pytest_mock-3.1.0-py2.py3-none-any.whl", hash = "sha256:997729451dfc36b851a9accf675488c7020beccda15e11c75632ee3d1b1ccd71"},
]
pywin32 = [
{file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"},
{file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"},
{file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"},
{file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"},
{file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"},
{file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"},
{file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"},
{file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"},
{file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"},
{file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"},
{file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"},
{file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"},
]
pyyaml = [
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"},
{file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"},
{file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"},
{file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"},
{file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"},
{file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"},
{file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"},
{file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"},
{file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"},
{file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"},
{file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"},
]
requests = [
{file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"},
{file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"},
]
six = [
{file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
]
texttable = [
{file = "texttable-1.6.2-py2.py3-none-any.whl", hash = "sha256:7dc282a5b22564fe0fdc1c771382d5dd9a54742047c61558e071c8cd595add86"},
{file = "texttable-1.6.2.tar.gz", hash = "sha256:eff3703781fbc7750125f50e10f001195174f13825a92a45e9403037d539b4f4"},
]
toml = [
{file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"},
{file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"},
{file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"},
]
urllib3 = [
{file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"},
{file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"},
]
virtualenv = [
{file = "virtualenv-20.0.20-py2.py3-none-any.whl", hash = "sha256:b4c14d4d73a0c23db267095383c4276ef60e161f94fde0427f2f21a0132dde74"},
{file = "virtualenv-20.0.20.tar.gz", hash = "sha256:fd0e54dec8ac96c1c7c87daba85f0a59a7c37fe38748e154306ca21c73244637"},
]
watchdog = [
{file = "watchdog-0.10.2.tar.gz", hash = "sha256:c560efb643faed5ef28784b2245cf8874f939569717a4a12826a173ac644456b"},
]
wcwidth = [
{file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"},
{file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"},
]
websocket-client = [
{file = "websocket_client-0.57.0-py2.py3-none-any.whl", hash = "sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549"},
{file = "websocket_client-0.57.0.tar.gz", hash = "sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010"},
]
zipp = [
{file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"},
{file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"},
]

@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import unicode_literals
from .constants import *
from .docker_links import DockerLinks
from .entrypoint import Entrypoint

@ -1,6 +1,3 @@
from __future__ import absolute_import
from __future__ import unicode_literals
from sys import argv
from .entrypoint import main as m

@ -1,7 +1,4 @@
"Command object"
from __future__ import absolute_import
from __future__ import unicode_literals
import os
from fnmatch import fnmatch
@ -71,6 +68,10 @@ class Command(object):
@property
def is_handled(self):
if self.config.commands and self.args:
return [
p for p in self.config.commands if fnmatch(self.args[0], p)
]
subcom = self.config.subcommands
if not self.args or self.args[0] == self.command or \
[p for p in subcom if fnmatch(self.args[0], p)]:
@ -102,7 +103,7 @@ class Command(object):
self._exec()
if self.config.remove_dockerenv:
self._rm_dockerenv()
if os.getuid() is 0:
if os.getuid() == 0:
os.setgid(self.config.group)
os.setuid(self.config.user)
self.log.debug('Set uid {uid} and gid {gid}'.format(

@ -1,10 +1,9 @@
"""
Configuration object
"""
from __future__ import absolute_import
from __future__ import unicode_literals
import os
from distutils.util import strtobool
from fnmatch import fnmatch
from grp import getgrnam
from io import open
from pwd import getpwnam
@ -22,6 +21,10 @@ from .reloader import Reloader
__all__ = ['Config']
def envtobool(key, default):
return bool(strtobool(os.environ.get(key, str(default))))
class ConfigMeta(object):
def _return_item_lst(self, item):
@ -127,7 +130,13 @@ class Config(ConfigMeta):
@property
def has_config(self):
"Has config file provided."
return len(self._config) is not 0
return len(self._config) != 0
@property
def commands(self):
"Handled commands"
rtn = self._return_item_lst('commands')
return rtn
@property
def command(self):
@ -135,8 +144,16 @@ class Config(ConfigMeta):
if self._command:
return self._command
cmd = self._args[0] if self._args else ''
if 'commands' in self._config:
commands = self._return_item_lst('commands')
if [p for p in commands if fnmatch(self._args[0], p)]:
self._command = Command(cmd, self, self._args)
return self._command
for key in ['command', 'cmd']:
if key in self._config:
self.log.warning(
'"command" is deprecated, use "commands" instead',
)
cmd = self._config[key]
self._command = Command(cmd, self, self._args)
return self._command
@ -145,9 +162,18 @@ class Config(ConfigMeta):
def subcommands(self):
"""Subcommands to handle as arguments."""
rtn = self._return_item_lst('subcommands')
if not rtn:
if rtn:
self.log.warning(
'"subcommands" is deprecated, '
'subcommands will not be handled anymore.',
)
if self.commands:
self.log.warning(
'"subcommands" is ignored as long "commands" in present',
)
return rtn
else:
return ['-*']
return rtn
@property
def user(self):
@ -214,7 +240,7 @@ class Config(ConfigMeta):
if self._reload:
return self._reload
if (not self._config.get('reload') or
'ENTRYPOINT_DISABLE_RELOAD' in os.environ):
envtobool('ENTRYPOINT_DISABLE_RELOAD', False)):
return None
self._reload = self.get_reloader()
return self._reload
@ -236,7 +262,7 @@ class Config(ConfigMeta):
@property
def debug(self):
"""Enable debug logs."""
if 'ENTRYPOINT_DEBUG' in os.environ:
if envtobool('ENTRYPOINT_DEBUG', False):
return True
if 'debug' in self._config:
return bool(self._config['debug'])
@ -247,23 +273,23 @@ class Config(ConfigMeta):
"""Disable logging"""
if self.debug:
return False
if 'ENTRYPOINT_QUIET' in os.environ:
if envtobool('ENTRYPOINT_QUIET', False):
return True
return bool(self._config.get('quiet', False))
@property
def is_disabled(self):
"""Return if service is disabled using environment"""
return 'ENTRYPOINT_DISABLE_SERVICE' in os.environ
return envtobool('ENTRYPOINT_DISABLE_SERVICE', False)
@property
def should_config(self):
"""Check environment to tell if config should apply anyway"""
return 'ENTRYPOINT_FORCE' in os.environ
return envtobool('ENTRYPOINT_FORCE', False)
@property
def raw_output(self):
"""Check if command output should be displayed using logging or not"""
if 'ENTRYPOINT_RAW' in os.environ:
if envtobool('ENTRYPOINT_RAW', False):
return True
return bool(self._config.get('raw_output', False))

@ -1,3 +1,3 @@
from __future__ import unicode_literals
ENTRYPOINT_FILE = 'entrypoint-config.yml'

@ -1,8 +1,6 @@
"""
Container object handle a single container link
"""
from __future__ import absolute_import
from __future__ import unicode_literals
class Container(object):

@ -3,9 +3,6 @@
DockerLinks a kiss class which help to get links info in a docker
container.
"""
from __future__ import absolute_import
from __future__ import unicode_literals
import json
import os
import re
@ -118,7 +115,7 @@ class DockerLinks(object):
def _find_ports(link_name):
rtn = {}
p = re.compile('^{link}_PORT_(\d*)_(UDP|TCP)$'.format(link=link_name))
p = re.compile('^{link}_PORT_([0-9]+)_(UDP|TCP)$'.format(link=link_name))
for key in os.environ:
m = p.match(key)
if m:

@ -2,10 +2,6 @@
"""
Smart docker-entrypoint
"""
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import json
import os
from sys import argv

@ -1,9 +1,6 @@
"""
Link handle a single link to another container, determined by his port
"""
from __future__ import absolute_import
from __future__ import unicode_literals
import fnmatch
from six import viewitems
@ -57,7 +54,7 @@ class Links(object):
'required': True}
def __init__(self, config={}, links=None):
if not links or len(links.links()) is 0:
if not links or len(links.links()) == 0:
pass
self._links = []
@ -82,7 +79,7 @@ class Links(object):
links = [link for link in links
if getattr(link, "_filter_{}".format(key))(val)]
if options['required'] and len(links) is 0:
if options['required'] and len(links) == 0:
raise Exception("No links was found for {name}".format(name=name))
if options['single'] and len(links) > 1:
raise Exception("Only one link should be provided for {name}"

@ -1,9 +1,6 @@
"""
Get log object
"""
from __future__ import absolute_import
from __future__ import unicode_literals
import logging
from colorlog import ColoredFormatter

@ -1,9 +1,6 @@
"""
Send signal to pid 1 to reload service
"""
from __future__ import absolute_import
from __future__ import unicode_literals
import glob
import os
import signal
@ -38,7 +35,7 @@ class Reload(FileSystemEventHandler):
else:
self.log.debug(
'Reloader triggered but file {file} is not watched'.format(
file=file
file=event.src_path
)
)
@ -57,7 +54,7 @@ class Reloader(object):
sig_attr = getattr(signal, sig)
try:
assert int(sig_attr)
except:
except BaseException:
raise Exception('Wrong signal provided for reload')
self.observer = Observer()
rel = Reload(sig=sig_attr, reloader=self)

@ -1,8 +1,4 @@
"Run commands"
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from multiprocessing import Process
from subprocess import PIPE
from subprocess import Popen
@ -27,9 +23,9 @@ class Runner(object):
def dispout(output, cb):
enc = stdout.encoding or 'UTF-8'
output = output.decode(enc).split('\n')
l = len(output)
lenght = len(output)
for c, line in enumerate(output):
if c + 1 == l and not len(line):
if c + 1 == lenght and not len(line):
# Do not display last empty line
break
cb(line)

@ -0,0 +1,32 @@
[tool]
[tool.poetry]
name = "pyentrypoint"
version = "0.6.0"
description = "pyentrypoint manages entrypoints in Docker containers."
license = "WTFPL"
classifiers = ["Programming Language :: Python", "Development Status :: 1 - Planning", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Topic :: System :: Installation/Setup"]
homepage = "http://github.com/cmehay/pyentrypoint"
authors = ["Christophe Mehay <cmehay@nospam.student.42.fr>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.6.1"
colorlog = "^4.1"
jinja2 = "^2.11"
pyyaml = "^5.3"
six = "^1.14"
watchdog = "^0.10"
[tool.poetry.dev-dependencies]
docker-compose = "^1.25.5"
pytest = "^5.4.2"
pytest-mock = "^3.1.0"
pre-commit = "^2.3.0"
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
[tool.poetry.scripts]
pyentrypoint = "pyentrypoint.__main__:main"

@ -1 +0,0 @@
docker-compose==1.7.0

@ -1,59 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from setuptools import find_packages
from setuptools import setup
# Thanks Sam and Max
__version__ = '0.5.2'
if __name__ == '__main__':
setup(
name='pyentrypoint',
version=__version__,
packages=find_packages(),
author="Christophe Mehay",
author_email="cmehay@nospam.student.42.fr",
description="pyentrypoint manages entrypoints in Docker containers.",
long_description=open('README.md').read(),
install_requires=['Jinja2>=2.8',
'PyYAML>=3.11',
'colorlog>=2.6.1',
'six>=1.10.0',
'watchdog>=0.8.3'],
include_package_data=True,
url='http://github.com/cmehay/pyentrypoint',
classifiers=[
"Programming Language :: Python",
"Development Status :: 1 - Planning",
"License :: OSI Approved :: BSD License",
"Natural Language :: English",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.5",
"Topic :: System :: Installation/Setup",
],
entry_points={
'console_scripts': [
'pyentrypoint = pyentrypoint.__main__:main',
],
},
license="WTFPL",
)

@ -0,0 +1,4 @@
commands:
- sleep
- cat
- ba*

@ -1,7 +1,4 @@
# Tests using pytest
from __future__ import absolute_import
from __future__ import unicode_literals
import os
from multiprocessing import Process

@ -1,15 +1,12 @@
# Tests using pytest
from __future__ import absolute_import
from __future__ import unicode_literals
import fnmatch
import os
from multiprocessing import Process
import pytest
from commons import clean_env
from yaml import FullLoader
from yaml import load
from yaml import Loader
from pyentrypoint import DockerLinks
from pyentrypoint import Entrypoint
@ -119,7 +116,7 @@ def test_templates():
for _, config_file in conf.get_templates():
with open(config_file, mode='r') as r:
test = load(stream=r, Loader=Loader)
test = load(stream=r, Loader=FullLoader)
assert len(set(test['All links'])) == 4
assert len(set(test['All links 1'])) == 2
@ -311,3 +308,17 @@ def test_disabled_service():
entry.exit_if_disabled()
del os.environ['ENTRYPOINT_DISABLE_SERVICE']
def test_commands_handling():
cat = Entrypoint(conf='configs/commands.yml', args=['cat', 'hello'])
sleep = Entrypoint(conf='configs/commands.yml', args=['sleep', '1'])
bash = Entrypoint(conf='configs/commands.yml', args=['bash'])
zsh = Entrypoint(conf='configs/commands.yml', args=['zsh', '-c', 'exit'])
empty = Entrypoint(conf='configs/empty.yml', args=['zsh', '-c', 'exit'])
assert cat.is_handled
assert sleep.is_handled
assert bash.is_handled
assert not zsh.is_handled
assert empty.is_handled

@ -1,6 +1,4 @@
"Tests for reloader"
from __future__ import absolute_import
from __future__ import unicode_literals
try:

@ -1,7 +1,4 @@
"Tests for runner"
from __future__ import absolute_import
from __future__ import unicode_literals
import os
from multiprocessing import Process

Loading…
Cancel
Save