undo some stuff

This commit is contained in:
Brad Warren 2021-07-06 12:17:57 -07:00
parent fdc19c037a
commit 8b9bc13949
6 changed files with 343 additions and 139 deletions

View file

@ -566,51 +566,6 @@ and run the command:
This would generate the HTML documentation in ``_build/html`` in your current
``docs/`` directory.
Certbot's dependencies
======================
We attempt to pin all of Certbot's dependencies whenever we can for reliability
and consistency. Some of the places we have Certbot's dependencies pinned
include our snaps, Docker images, Windows installer, CI, and our development
environments.
In most cases, the file where dependency versions are specified is
``tools/requirements.txt``. There are two exceptions to this. The first is our
"oldest" tests where ``tools/oldest_constraints.txt`` is used instead. The
purpose of the "oldest" tests is to ensure Certbot continues to work with the
oldest versions of our dependencies which we claim to support. The second
exception to using ``tools/requirements.txt`` is in our unpinned tests. As of
writing this, there is one test we run nightly in CI where we leave Certbot's
dependencies unpinned. The thinking behind this test is to help us learn about
breaking changes in our dependencies so that we can respond accordingly.
The choices of whether Certbot's dependencies are pinned and what file is used
if they are should be automatically handled for you most of the time by
Certbot's tooling. The way it works though is ``tools/pip_install.py`` (which
many of our other tools build on) checks for the presence of environment
variables. If ``CERTBOT_NO_PIN`` is set to 1, Certbot's dependencies will not
be pinned. If that variable is not set and ``CERTBOT_OLDEST`` is set to 1,
``tools/oldest_constraints.txt`` will be used as constraints for ``pip``.
Otherwise, ``tools/requirements.txt`` is used as constraints.
Updating dependency versions
----------------------------
``tools/requirements.txt`` and ``tools/oldest_constraints.txt`` can be updated
using ``tools/pinning/normal/repin.sh`` and ``tools/pinning/oldest/repin.sh``
respectively. This works by using ``poetry`` to generate pinnings based on a
dummy Poetry project defined by the ``pyproject.toml`` file in the same
directory as the script. In many cases, you can just run the script to generate
updated dependencies, however, if you need to pin back packages or unpin
packages that were previously restricted to an older version, you will need to
modify the ``pyproject.toml`` file. The syntax used by this file is described
at https://python-poetry.org/docs/pyproject/ and how dependencies are specified
in this file is further described at
https://python-poetry.org/docs/dependency-specification/.
If you want to learn more about the design used here, see
``tools/pinning/DESIGN.md`` in the Certbot repo.
.. _docker-dev:
Running the client with Docker

131
tools/dev_constraints.txt Normal file
View file

@ -0,0 +1,131 @@
# Specifies extra Python package versions during our tests with the oldest
# supported versions of our dependencies. Some dev package versions specified
# here may be overridden by higher level constraints files during tests (eg.
# tools/oldest_constraints.txt).
alabaster==0.7.10
apacheconfig==0.3.2
apipkg==1.4
appnope==0.1.0
asn1crypto==0.22.0
astroid==2.3.3
attrs==17.3.0
azure-devops==6.0.0b2
Babel==2.5.1
backcall==0.2.0
backports.functools-lru-cache==1.5
backports.shutil-get-terminal-size==1.0.0
backports.ssl-match-hostname==3.7.0.1
bcrypt==3.1.6
boto3==1.17.4
botocore==1.20.4
cached-property==1.5.1
cloudflare==2.3.1
configparser==3.7.4
contextlib2==0.6.0.post1
coverage==4.5.4
decorator==4.4.1
deprecated==1.2.10
dns-lexicon==3.3.17
dnspython==2.1.0
docker==4.3.1
docker-compose==1.26.2
docker-pycreds==0.4.0
dockerpty==0.4.1
docopt==0.6.2
docutils==0.15.2
execnet==1.5.0
functools32==3.2.3.post2
future==0.16.0
futures==3.3.0
filelock==3.0.12
google-api-python-client==1.5.5
httplib2==0.18.1
imagesize==0.7.1
importlib-metadata==0.23
ipdb==0.12.3
ipython==7.9.0
ipython-genutils==0.2.0
isodate==0.6.0
isort==4.3.21
jedi==0.17.1
Jinja2==2.9.6
jmespath==0.9.4
josepy==1.1.0
jsonpickle==2.0.0
jsonschema==2.6.0
lazy-object-proxy==1.4.3
logger==1.4
logilab-common==1.4.1
MarkupSafe==1.1.1
mccabe==0.6.1
more-itertools==5.0.0
msrest==0.6.18
mypy==0.812
mypy-extensions==0.4.3
ndg-httpsclient==0.3.2
oauth2client==4.0.0
oauthlib==3.1.0
packaging==19.2
paramiko==2.4.2
parso==0.7.0
pathlib2==2.3.5
pexpect==4.7.0
pickleshare==0.7.5
pip==20.2.4
pkginfo==1.4.2
pluggy==0.13.0
ply==3.4
prompt-toolkit==2.0.10
ptyprocess==0.6.0
py==1.8.0
pyasn1==0.1.9
pyasn1-modules==0.0.10
PyGithub==1.52
Pygments==2.2.0
pyjwt==1.7.1
pylint==2.4.3
pynacl==1.3.0
# If pynsist version is upgraded, our NSIS template windows-installer/template.nsi
# must be upgraded if necessary using the new built-in one from pynsist.
pynsist==2.7
pytest==3.2.5
pytest-cov==2.5.1
pytest-forked==0.2
pytest-xdist==1.22.5
pytest-sugar==0.9.2
pytest-rerunfailures==4.2
python-dateutil==2.8.1
python-digitalocean==1.15.0
python-dotenv==0.14.0
pywin32==300
PyYAML==5.3.1
repoze.sphinx.autointerface==0.8
requests-file==1.4.2
requests-oauthlib==1.3.0
requests-toolbelt==0.8.0
rsa==3.4.2
s3transfer==0.3.1
scandir==1.10.0
simplegeneric==0.8.1
singledispatch==3.4.0.3
snowballstemmer==1.2.1
Sphinx==1.7.5
sphinx-rtd-theme==0.2.4
sphinxcontrib-websupport==1.0.1
texttable==0.9.1
tldextract==2.2.0
toml==0.10.0
tox==3.14.0
tqdm==4.19.4
traitlets==4.3.3
twine==1.11.0
typed-ast==1.4.1
typing==3.6.4
typing-extensions==3.7.4.3
uritemplate==3.0.0
virtualenv==16.6.2
wcwidth==0.1.8
websocket-client==0.56.0
wheel==0.35.1
wrapt==1.11.2
zipp==0.6.0

92
tools/merge_requirements.py Executable file
View file

@ -0,0 +1,92 @@
#!/usr/bin/env python
"""Merges multiple Python requirements files into one file.
Requirements files specified later take precedence over earlier ones.
Only the simple formats SomeProject==1.2.3 or SomeProject<=1.2.3 are
currently supported.
"""
import sys
def process_entries(entries):
"""
Ignore empty lines, comments and editable requirements
:param list entries: List of entries
:returns: mapping from a project to its version specifier
:rtype: dict
"""
data = {}
for e in entries:
e = e.strip()
if e and not e.startswith('#') and not e.startswith('-e'):
# Support for <= was added as part of
# https://github.com/certbot/certbot/pull/8460 because we weren't
# able to pin a package to an exact version. Normally, this
# functionality shouldn't be needed so we could remove it in the
# future. If you do so, make sure to update other places in this
# file related to this behavior such as this file's docstring.
for comparison in ('==', '<=',):
parts = e.split(comparison)
if len(parts) == 2:
project_name = parts[0]
version = parts[1]
data[project_name] = comparison + version
break
else:
raise ValueError("Unexpected syntax '{0}'".format(e))
return data
def read_file(file_path):
"""Reads in a Python requirements file.
:param str file_path: path to requirements file
:returns: list of entries in the file
:rtype: list
"""
with open(file_path) as file_h:
return file_h.readlines()
def output_requirements(requirements):
"""Prepare print requirements to stdout.
:param dict requirements: mapping from a project to its version
specifier
"""
return '\n'.join('{0}{1}'.format(key, value)
for key, value in sorted(requirements.items()))
def main(*paths):
"""Merges multiple requirements files together and prints the result.
Requirement files specified later in the list take precedence over earlier
files. Files are read from file paths passed from the command line arguments.
If no command line arguments are defined, data is read from stdin instead.
:param tuple paths: paths to requirements files provided on command line
"""
data = {}
if paths:
for path in paths:
data.update(process_entries(read_file(path)))
else:
# Need to check if interactive to avoid blocking if nothing is piped
if not sys.stdin.isatty():
stdin_data = []
for line in sys.stdin:
stdin_data.append(line)
data.update(process_entries(stdin_data))
return output_requirements(data)
if __name__ == '__main__':
print(main(*sys.argv[1:])) # pylint: disable=star-args

View file

@ -1,100 +1,77 @@
# This file was generated by tools/pinning/oldest/repin.sh and can be updated using
# that script.
apacheconfig==0.3.2
asn1crypto==0.24.0
astroid==2.5.6; python_version >= "3.6" and python_version < "4.0"
atomicwrites==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.4.0"
attrs==21.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
bcrypt==3.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
boto3==1.4.7
botocore==1.7.41
cached-property==1.5.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
# This file contains the oldest versions of our dependencies we're trying to
# support. Usually these version numbers are taken from the packages of our
# dependencies available in popular LTS Linux distros. Keeping compatibility
# with those versions makes it much easier for OS maintainers to update their
# Certbot packages.
#
# When updating these dependencies, we should try to only update them to the
# oldest version of the package that is found in a non-EOL'd version of
# CentOS, Debian, or Ubuntu that has Certbot packages in their OS repositories
# using a version of Python we support. If the distro is EOL'd or using a
# version of Python we don't support, it can be ignored.
# CentOS/RHEL 7 EPEL constraints
# Some of these constraints may be stricter than necessary because they
# initially referred to the Python 2 packages in CentOS/RHEL 7 with EPEL.
cffi==1.9.1
chardet==2.2.1
cloudflare==1.5.1
colorama==0.4.4; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or python_full_version >= "3.5.0" and python_version >= "3.6" and sys_platform == "win32" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.6" and python_version < "4.0" and sys_platform == "win32" and python_full_version >= "3.5.0"
configargparse==0.10.0
configobj==5.0.6
coverage==5.5; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.6"
cryptography==2.1.4
cython==0.29.23; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0")
distro==1.0.1
dns-lexicon==3.2.1
dnspython==2.1.0; python_version >= "3.6"
docker-compose==1.24.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
docker-pycreds==0.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
docker==3.7.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
dockerpty==0.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
docopt==0.6.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
docutils==0.17.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
execnet==1.9.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
filelock==3.0.12; python_version >= "3.6"
funcsigs==0.4
future==0.18.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
google-api-python-client==1.5.5
httplib2==0.9.2
idna==2.6
importlib-metadata==4.5.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_full_version >= "3.4.0" and python_version >= "3.6" and python_version < "3.8" or python_version < "3.8" and python_version >= "3.6"
iniconfig==1.1.1; python_version >= "3.6"
ipaddress==1.0.16
isort==5.8.0; python_version >= "3.6" and python_version < "4.0"
jmespath==0.10.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
josepy==1.8.0; python_version >= "3.6"
jsonschema==2.6.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
lazy-object-proxy==1.6.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.6.0"
logger==1.4; python_version >= "3.6"
mccabe==0.6.1; python_version >= "3.6" and python_version < "4.0"
mock==1.0.1
mypy-extensions==0.4.3; python_version >= "3.6"
mypy==0.910; python_version >= "3.6"
ndg-httpsclient==0.3.2
oauth2client==4.0.0
packaging==20.9; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
paramiko==2.4.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
parsedatetime==2.4
pbr==1.8.0
pip==20.2.4; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0")
pluggy==0.13.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
ply==3.4
py==1.10.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_full_version >= "3.5.0" and python_version >= "3.6"
pyasn1-modules==0.0.10; python_version >= "3.6"
pyOpenSSL==17.3.0
pyasn1==0.1.9
pycparser==2.14
pylint==2.8.3; python_version >= "3.6" and python_version < "4.0"
pynacl==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
pyopenssl==17.3.0
pyparsing==2.2.0
pypiwin32==223; sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6")
pyrfc3339==1.0
pytest-cov==2.12.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
pytest-forked==1.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
pytest-xdist==2.3.0; python_version >= "3.6" or python_version >= "3.6"
pytest==6.2.4; python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
pyRFC3339==1.0
python-augeas==0.5.0
python-dateutil==2.8.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
python-digitalocean==1.11
pytz==2012c
pywin32==301; sys_platform == "win32" and python_version >= "3.6" or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6")
pyyaml==3.13; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6"
requests-file==1.5.1; python_version >= "3.6"
requests-toolbelt==0.9.1; python_version >= "3.6"
requests==2.14.2
rsa==4.7.2; python_version >= "3.6" and python_version < "4"
s3transfer==0.1.13; python_version >= "3.6"
setuptools==39.0.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0")
six==1.11.0
texttable==0.9.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
tldextract==3.1.0; python_version >= "3.6"
toml==0.10.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.3.0"
typed-ast==1.4.3; python_version >= "3.6" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.6"
typing-extensions==3.10.0.0; python_version >= "3.6" or python_version < "3.8" and python_version >= "3.6"
uritemplate==3.0.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
oauth2client==4.0.0
urllib3==1.10.2
websocket-client==0.59.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
wheel==0.33.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0")
wrapt==1.12.1; python_version >= "3.6" and python_version < "4.0"
zipp==3.4.1; python_version < "3.8" and python_version >= "3.6"
zope.component==4.1.0
zope.event==4.0.3
zope.hookable==4.0.4
zope.interface==4.0.5
# Debian Jessie Backports constraints
# Debian Jessie has reached end of life so these dependencies can probably be
# updated as needed or desired.
colorama==0.3.2
enum34==1.0.3
html5lib==0.999
pbr==1.8.0
pytz==2012rc0
# Debian Buster constraints
google-api-python-client==1.5.5
pyparsing==2.2.0
# Our setup.py constraints
apacheconfig==0.3.2
cloudflare==1.5.1
python-digitalocean==1.11
requests==2.6.0
# Ubuntu Xenial constraints
# Ubuntu Xenial only has versions of Python which we do not support available
# so these dependencies can probably be updated as needed or desired.
ConfigArgParse==0.10.0
funcsigs==0.4
zope.hookable==4.0.4
# Ubuntu Bionic constraints.
cryptography==2.1.4
distro==1.0.1
httplib2==0.9.2
idna==2.6
setuptools==39.0.1
six==1.11.0
# Ubuntu Focal constraints
asn1crypto==0.24.0
configobj==5.0.6
parsedatetime==2.4
# Plugin constraints
# These aren't necessarily the oldest versions we need to support
# Tracking at https://github.com/certbot/certbot/issues/6473
boto3==1.4.7
botocore==1.7.41
dns-lexicon==3.1.0

48
tools/pinning/pin.sh Executable file
View file

@ -0,0 +1,48 @@
#!/bin/bash
# This script accepts no arguments and automates the process of updating
# Certbot's dependencies. Dependencies can be pinned to older versions by
# modifying pyproject.toml in the same directory as this file.
set -euo pipefail
WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
REPO_ROOT="$(dirname "$(dirname "${WORK_DIR}")")"
RELATIVE_SCRIPT_PATH="$(realpath --relative-to "$REPO_ROOT" "$WORK_DIR")/$(basename "${BASH_SOURCE[0]}")"
REQUIREMENTS_FILE="$REPO_ROOT/tools/requirements.txt"
if ! command -v poetry >/dev/null || [ $(poetry --version | grep -oE '[0-9]+\.[0-9]+' | sed 's/\.//') -lt 12 ]; then
echo "Please install poetry 1.2+."
echo "You may need to recreate Certbot's virtual environment and activate it."
exit 1
fi
# Old eggs can cause outdated dependency information to be used by poetry so we
# delete them before generating the lock file. See
# https://github.com/python-poetry/poetry/issues/4103 for more info.
cd "${REPO_ROOT}"
rm -rf */*.egg-info
cd "${WORK_DIR}"
if [ -f poetry.lock ]; then
rm poetry.lock
fi
poetry lock
TEMP_REQUIREMENTS=$(mktemp)
trap 'rm poetry.lock; rm $TEMP_REQUIREMENTS' EXIT
poetry export -o "${TEMP_REQUIREMENTS}" --without-hashes
# We need to remove local packages from the requirements file.
sed -i '/^acme @/d; /certbot/d;' "${TEMP_REQUIREMENTS}"
cat << EOF > "$REQUIREMENTS_FILE"
# This file was generated by $RELATIVE_SCRIPT_PATH and can be updated using
# that script.
#
# It is normally used as constraints to pip, however, it has the name
# requirements.txt so that is scanned by GitHub. See
# https://docs.github.com/en/github/visualizing-repository-data-with-graphs/about-the-dependency-graph#supported-package-ecosystems
# for more info.
EOF
cat "${TEMP_REQUIREMENTS}" >> "${REQUIREMENTS_FILE}"

View file

@ -1,4 +1,4 @@
# This file was generated by tools/pinning/normal/repin.sh and can be updated using
# This file was generated by tools/pinning/pin.sh and can be updated using
# that script.
#
# It is normally used as constraints to pip, however, it has the name
@ -7,20 +7,21 @@
# for more info.
alabaster==0.7.12; python_version >= "3.6"
apacheconfig==0.3.2; python_version >= "3.6"
apipkg==1.5; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
appdirs==1.4.4; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0"
appnope==0.1.2; python_version == "3.6" and sys_platform == "darwin" or python_version >= "3.7" and sys_platform == "darwin"
astroid==2.5.6; python_version >= "3.6" and python_version < "4.0"
atomicwrites==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.4.0"
attrs==21.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
awscli==1.19.95; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.6.0")
awscli==1.19.91; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.6.0")
azure-devops==6.0.0b4; python_version >= "3.6"
babel==2.9.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
backcall==0.2.0; python_version == "3.6" or python_version >= "3.7"
bcrypt==3.2.0; python_version >= "3.6"
beautifulsoup4==4.9.3; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6"
bleach==3.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
boto3==1.17.95; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
botocore==1.20.95; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
boto3==1.17.91; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
botocore==1.20.91; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
cachecontrol==0.12.6; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0"
cached-property==1.5.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
cachetools==4.2.2; python_version >= "3.5" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6")
@ -50,11 +51,11 @@ dockerpty==0.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or p
docopt==0.6.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
docutils==0.15.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version >= "3.3.0"
entrypoints==0.3; python_version >= "3.6" and python_version < "4.0"
execnet==1.9.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
execnet==1.8.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
fabric==2.6.0; python_version >= "3.6"
filelock==3.0.12; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_version < "4.0"
google-api-core==1.30.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
google-api-python-client==2.9.0; python_version >= "3.6"
google-api-python-client==2.8.0; python_version >= "3.6"
google-auth-httplib2==0.1.0; python_version >= "3.6"
google-auth==1.31.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
googleapis-common-protos==1.53.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6"
@ -166,7 +167,7 @@ tldextract==3.1.0; python_version >= "3.6" and python_version < "4.0"
toml==0.10.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_version == "3.6" and python_full_version < "3.0.0" or python_version > "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.3.0" or python_version > "3.6" and python_full_version >= "3.3.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.3.0"
tomlkit==0.7.2; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0"
tox==3.23.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0"
tqdm==4.61.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
tqdm==4.61.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0"
traitlets==4.3.3
twine==3.3.0; python_version >= "3.6"
typed-ast==1.4.3; python_version >= "3.6" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.6"