diff --git a/.dockerignore b/.dockerignore index bc34ac2..7218461 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,3 +3,5 @@ !setup.py !README.md !tests +!poetry.lock +!pyproject.toml diff --git a/.gitignore b/.gitignore index d543650..6d8fea2 100644 --- a/.gitignore +++ b/.gitignore @@ -90,4 +90,3 @@ ENV/ # Rope project settings .ropeproject - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8f4a2f0..c2a2265 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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 diff --git a/.travis.yml b/.travis.yml index 7d5b0e0..cc6bfde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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= diff --git a/Dockerfile-test.py3 b/Dockerfile-test.py3 index 129bb91..dca0bf7 100644 --- a/Dockerfile-test.py3 +++ b/Dockerfile-test.py3 @@ -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", "."] diff --git a/Dockerfile-test.py3.6 b/Dockerfile-test.py3.6 new file mode 100644 index 0000000..0f0b9ad --- /dev/null +++ b/Dockerfile-test.py3.6 @@ -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", "."] diff --git a/Dockerfile-test.py2 b/Dockerfile-test.py3.7 similarity index 52% rename from Dockerfile-test.py2 rename to Dockerfile-test.py3.7 index 9245497..e53ab9e 100644 --- a/Dockerfile-test.py2 +++ b/Dockerfile-test.py3.7 @@ -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", "."] diff --git a/Dockerfile-test.py3.8 b/Dockerfile-test.py3.8 new file mode 100644 index 0000000..bebe938 --- /dev/null +++ b/Dockerfile-test.py3.8 @@ -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", "."] diff --git a/Dockerfile.py2 b/Dockerfile.py2 deleted file mode 100644 index c9d17df..0000000 --- a/Dockerfile.py2 +++ /dev/null @@ -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"] diff --git a/Dockerfile.py2-alpine b/Dockerfile.py2-alpine deleted file mode 100644 index 2aa0425..0000000 --- a/Dockerfile.py2-alpine +++ /dev/null @@ -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"] diff --git a/Dockerfile.py3 b/Dockerfile.py3 index ceb19fa..229a5db 100644 --- a/Dockerfile.py3 +++ b/Dockerfile.py3 @@ -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 . diff --git a/Dockerfile.py3-alpine b/Dockerfile.py3-alpine index 8ef41fa..fd4af9e 100644 --- a/Dockerfile.py3-alpine +++ b/Dockerfile.py3-alpine @@ -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 . diff --git a/Dockerfile.py3.6 b/Dockerfile.py3.6 new file mode 100644 index 0000000..c89fc37 --- /dev/null +++ b/Dockerfile.py3.6 @@ -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"] diff --git a/Dockerfile.py3.6-alpine b/Dockerfile.py3.6-alpine new file mode 100644 index 0000000..740f94a --- /dev/null +++ b/Dockerfile.py3.6-alpine @@ -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"] diff --git a/Dockerfile.py3.7 b/Dockerfile.py3.7 new file mode 100644 index 0000000..48a34b4 --- /dev/null +++ b/Dockerfile.py3.7 @@ -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"] diff --git a/Dockerfile.py3.7-alpine b/Dockerfile.py3.7-alpine new file mode 100644 index 0000000..183e29d --- /dev/null +++ b/Dockerfile.py3.7-alpine @@ -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"] diff --git a/Dockerfile.py3.8 b/Dockerfile.py3.8 new file mode 100644 index 0000000..816eab6 --- /dev/null +++ b/Dockerfile.py3.8 @@ -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"] diff --git a/Dockerfile.py3.8-alpine b/Dockerfile.py3.8-alpine new file mode 100644 index 0000000..1b6563d --- /dev/null +++ b/Dockerfile.py3.8-alpine @@ -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"] diff --git a/MANIFEST.in b/MANIFEST.in index 1c2510d..bb3ec5f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1 @@ include README.md - diff --git a/Makefile b/Makefile index 7e1fadc..9fe631e 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.md b/README.md index 592e76e..64e48dc 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/docker-compose.yml b/docker-compose.yml index d3fcf13..0a8b8c0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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 diff --git a/docs/conf.py b/docs/conf.py index 225cd6b..3fdd0eb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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 diff --git a/docs/config.rst b/docs/config.rst index 8ab7ff3..bb8d0ba 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -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 diff --git a/entrypoint-config.yml b/entrypoint-config.yml index df9d13e..cd10572 100644 --- a/entrypoint-config.yml +++ b/entrypoint-config.yml @@ -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 diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..c565e12 --- /dev/null +++ b/poetry.lock @@ -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"}, +] diff --git a/pyentrypoint/__init__.py b/pyentrypoint/__init__.py index 877f452..1ba22d2 100644 --- a/pyentrypoint/__init__.py +++ b/pyentrypoint/__init__.py @@ -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 diff --git a/pyentrypoint/__main__.py b/pyentrypoint/__main__.py index 4fb1b2c..387c7ae 100644 --- a/pyentrypoint/__main__.py +++ b/pyentrypoint/__main__.py @@ -1,6 +1,3 @@ -from __future__ import absolute_import -from __future__ import unicode_literals - from sys import argv from .entrypoint import main as m diff --git a/pyentrypoint/command.py b/pyentrypoint/command.py index 71e43d6..f927c3e 100755 --- a/pyentrypoint/command.py +++ b/pyentrypoint/command.py @@ -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( diff --git a/pyentrypoint/config.py b/pyentrypoint/config.py index c20f285..d4f3020 100755 --- a/pyentrypoint/config.py +++ b/pyentrypoint/config.py @@ -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)) diff --git a/pyentrypoint/constants.py b/pyentrypoint/constants.py index 8fb3eb5..132393f 100644 --- a/pyentrypoint/constants.py +++ b/pyentrypoint/constants.py @@ -1,3 +1,3 @@ -from __future__ import unicode_literals + ENTRYPOINT_FILE = 'entrypoint-config.yml' diff --git a/pyentrypoint/container.py b/pyentrypoint/container.py index 670511d..84b7f19 100644 --- a/pyentrypoint/container.py +++ b/pyentrypoint/container.py @@ -1,8 +1,6 @@ """ Container object handle a single container link """ -from __future__ import absolute_import -from __future__ import unicode_literals class Container(object): diff --git a/pyentrypoint/docker_links.py b/pyentrypoint/docker_links.py index 5f2d288..a03483a 100644 --- a/pyentrypoint/docker_links.py +++ b/pyentrypoint/docker_links.py @@ -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: diff --git a/pyentrypoint/entrypoint.py b/pyentrypoint/entrypoint.py index 071b520..be2ff4b 100644 --- a/pyentrypoint/entrypoint.py +++ b/pyentrypoint/entrypoint.py @@ -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 diff --git a/pyentrypoint/links.py b/pyentrypoint/links.py index 7fcdd5f..c6b6ddb 100644 --- a/pyentrypoint/links.py +++ b/pyentrypoint/links.py @@ -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}" diff --git a/pyentrypoint/logs.py b/pyentrypoint/logs.py index 20ce84a..214c8ca 100644 --- a/pyentrypoint/logs.py +++ b/pyentrypoint/logs.py @@ -1,9 +1,6 @@ """ Get log object """ -from __future__ import absolute_import -from __future__ import unicode_literals - import logging from colorlog import ColoredFormatter diff --git a/pyentrypoint/reloader.py b/pyentrypoint/reloader.py index 41b0292..610fffe 100644 --- a/pyentrypoint/reloader.py +++ b/pyentrypoint/reloader.py @@ -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) diff --git a/pyentrypoint/runner.py b/pyentrypoint/runner.py index 298020f..89908b2 100644 --- a/pyentrypoint/runner.py +++ b/pyentrypoint/runner.py @@ -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) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..bd93153 --- /dev/null +++ b/pyproject.toml @@ -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 "] +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" diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 7590a43..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1 +0,0 @@ -docker-compose==1.7.0 diff --git a/setup.py b/setup.py deleted file mode 100644 index 920e9d5..0000000 --- a/setup.py +++ /dev/null @@ -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", - - ) diff --git a/tests/configs/commands.yml b/tests/configs/commands.yml new file mode 100644 index 0000000..eb55489 --- /dev/null +++ b/tests/configs/commands.yml @@ -0,0 +1,4 @@ +commands: + - sleep + - cat + - ba* diff --git a/tests/main_test.py b/tests/main_test.py index f6a1607..3af5946 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -1,7 +1,4 @@ # Tests using pytest -from __future__ import absolute_import -from __future__ import unicode_literals - import os from multiprocessing import Process diff --git a/tests/pyentrypoint_test.py b/tests/pyentrypoint_test.py index 9f8d974..10571c0 100644 --- a/tests/pyentrypoint_test.py +++ b/tests/pyentrypoint_test.py @@ -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 diff --git a/tests/reloader_test.py b/tests/reloader_test.py index 9ff49e1..1b4902f 100644 --- a/tests/reloader_test.py +++ b/tests/reloader_test.py @@ -1,6 +1,4 @@ "Tests for reloader" -from __future__ import absolute_import -from __future__ import unicode_literals try: diff --git a/tests/runner_test.py b/tests/runner_test.py index 113f671..6a4eb4f 100644 --- a/tests/runner_test.py +++ b/tests/runner_test.py @@ -1,7 +1,4 @@ "Tests for runner" -from __future__ import absolute_import -from __future__ import unicode_literals - import os from multiprocessing import Process