mirror of https://github.com/docker/docker-py.git
Merge pull request #2788 from docker/set-minimal-python-to-3_6
Make python 3.6 the minimum version
This commit is contained in:
commit
30d482d359
|
@ -8,7 +8,7 @@ jobs:
|
|||
strategy:
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9]
|
||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -18,8 +18,8 @@ jobs:
|
|||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r test-requirements.txt -r requirements.txt
|
||||
python3 -m pip install --upgrade pip
|
||||
pip3 install -r test-requirements.txt -r requirements.txt
|
||||
- name: Test with pytest
|
||||
run: |
|
||||
docker logout
|
||||
|
|
|
@ -4,7 +4,7 @@ sphinx:
|
|||
configuration: docs/conf.py
|
||||
|
||||
python:
|
||||
version: 3.5
|
||||
version: 3.6
|
||||
install:
|
||||
- requirements: docs-requirements.txt
|
||||
- requirements: requirements.txt
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
ARG PYTHON_VERSION=2.7
|
||||
ARG PYTHON_VERSION=3.7
|
||||
|
||||
FROM python:${PYTHON_VERSION}
|
||||
|
||||
# Add SSH keys and set permissions
|
||||
COPY tests/ssh-keys /root/.ssh
|
||||
RUN chmod -R 600 /root/.ssh
|
||||
|
||||
RUN mkdir /src
|
||||
WORKDIR /src
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
ARG PYTHON_VERSION=3.7
|
||||
|
||||
FROM python:${PYTHON_VERSION}
|
||||
|
||||
RUN mkdir /src
|
||||
WORKDIR /src
|
||||
|
||||
COPY requirements.txt /src/requirements.txt
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY test-requirements.txt /src/test-requirements.txt
|
||||
RUN pip install -r test-requirements.txt
|
||||
|
||||
COPY . /src
|
||||
RUN pip install .
|
|
@ -1,7 +1,6 @@
|
|||
#!groovy
|
||||
|
||||
def imageNameBase = "dockerpinata/docker-py"
|
||||
def imageNamePy2
|
||||
def imageNamePy3
|
||||
def imageDindSSH
|
||||
def images = [:]
|
||||
|
@ -22,12 +21,10 @@ def buildImages = { ->
|
|||
stage("build image") {
|
||||
checkout(scm)
|
||||
|
||||
imageNamePy2 = "${imageNameBase}:py2-${gitCommit()}"
|
||||
imageNamePy3 = "${imageNameBase}:py3-${gitCommit()}"
|
||||
imageDindSSH = "${imageNameBase}:sshdind-${gitCommit()}"
|
||||
withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
|
||||
buildImage(imageDindSSH, "-f tests/Dockerfile-ssh-dind .", "")
|
||||
buildImage(imageNamePy2, "-f tests/Dockerfile --build-arg PYTHON_VERSION=2.7 .", "py2.7")
|
||||
buildImage(imageNamePy3, "-f tests/Dockerfile --build-arg PYTHON_VERSION=3.7 .", "py3.7")
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +70,7 @@ def runTests = { Map settings ->
|
|||
throw new Exception("Need Docker version to test, e.g.: `runTests(dockerVersion: '19.03.12')`")
|
||||
}
|
||||
if (!pythonVersion) {
|
||||
throw new Exception("Need Python version being tested, e.g.: `runTests(pythonVersion: 'py2.7')`")
|
||||
throw new Exception("Need Python version being tested, e.g.: `runTests(pythonVersion: 'py3.7')`")
|
||||
}
|
||||
|
||||
{ ->
|
||||
|
|
50
Makefile
50
Makefile
|
@ -6,13 +6,9 @@ all: test
|
|||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-docker rm -f dpy-dind-py2 dpy-dind-py3 dpy-dind-certs dpy-dind-ssl
|
||||
-docker rm -f dpy-dind-py3 dpy-dind-certs dpy-dind-ssl
|
||||
find -name "__pycache__" | xargs rm -rf
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
docker build -t docker-sdk-python -f tests/Dockerfile --build-arg PYTHON_VERSION=2.7 --build-arg APT_MIRROR .
|
||||
|
||||
.PHONY: build-dind-ssh
|
||||
build-dind-ssh:
|
||||
docker build -t docker-dind-ssh -f tests/Dockerfile-ssh-dind --build-arg ENGINE_VERSION=${TEST_ENGINE_VERSION} --build-arg API_VERSION=${TEST_API_VERSION} --build-arg APT_MIRROR .
|
||||
|
@ -30,20 +26,12 @@ build-dind-certs:
|
|||
docker build -t dpy-dind-certs -f tests/Dockerfile-dind-certs .
|
||||
|
||||
.PHONY: test
|
||||
test: flake8 unit-test unit-test-py3 integration-dind integration-dind-ssl
|
||||
|
||||
.PHONY: unit-test
|
||||
unit-test: build
|
||||
docker run -t --rm docker-sdk-python py.test tests/unit
|
||||
test: flake8 unit-test-py3 integration-dind integration-dind-ssl
|
||||
|
||||
.PHONY: unit-test-py3
|
||||
unit-test-py3: build-py3
|
||||
docker run -t --rm docker-sdk-python3 py.test tests/unit
|
||||
|
||||
.PHONY: integration-test
|
||||
integration-test: build
|
||||
docker run -t --rm -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python py.test -v tests/integration/${file}
|
||||
|
||||
.PHONY: integration-test-py3
|
||||
integration-test-py3: build-py3
|
||||
docker run -t --rm -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python3 py.test -v tests/integration/${file}
|
||||
|
@ -53,16 +41,7 @@ setup-network:
|
|||
docker network inspect dpy-tests || docker network create dpy-tests
|
||||
|
||||
.PHONY: integration-dind
|
||||
integration-dind: integration-dind-py2 integration-dind-py3
|
||||
|
||||
.PHONY: integration-dind-py2
|
||||
integration-dind-py2: build setup-network
|
||||
docker rm -vf dpy-dind-py2 || :
|
||||
docker run -d --network dpy-tests --name dpy-dind-py2 --privileged\
|
||||
docker:${TEST_ENGINE_VERSION}-dind dockerd -H tcp://0.0.0.0:2375 --experimental
|
||||
docker run -t --rm --env="DOCKER_HOST=tcp://dpy-dind-py2:2375" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\
|
||||
--network dpy-tests docker-sdk-python py.test tests/integration/${file}
|
||||
docker rm -vf dpy-dind-py2
|
||||
integration-dind: integration-dind-py3
|
||||
|
||||
.PHONY: integration-dind-py3
|
||||
integration-dind-py3: build-py3 setup-network
|
||||
|
@ -73,16 +52,6 @@ integration-dind-py3: build-py3 setup-network
|
|||
--network dpy-tests docker-sdk-python3 py.test tests/integration/${file}
|
||||
docker rm -vf dpy-dind-py3
|
||||
|
||||
.PHONY: integration-ssh-py2
|
||||
integration-ssh-py2: build-dind-ssh build setup-network
|
||||
docker rm -vf dpy-dind-py2 || :
|
||||
docker run -d --network dpy-tests --name dpy-dind-py2 --privileged\
|
||||
docker-dind-ssh dockerd --experimental
|
||||
# start SSH daemon
|
||||
docker exec dpy-dind-py2 sh -c "/usr/sbin/sshd"
|
||||
docker run -t --rm --env="DOCKER_HOST=ssh://dpy-dind-py2" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\
|
||||
--network dpy-tests docker-sdk-python py.test tests/ssh/${file}
|
||||
docker rm -vf dpy-dind-py2
|
||||
|
||||
.PHONY: integration-ssh-py3
|
||||
integration-ssh-py3: build-dind-ssh build-py3 setup-network
|
||||
|
@ -97,7 +66,7 @@ integration-ssh-py3: build-dind-ssh build-py3 setup-network
|
|||
|
||||
|
||||
.PHONY: integration-dind-ssl
|
||||
integration-dind-ssl: build-dind-certs build build-py3
|
||||
integration-dind-ssl: build-dind-certs build-py3
|
||||
docker rm -vf dpy-dind-certs dpy-dind-ssl || :
|
||||
docker run -d --name dpy-dind-certs dpy-dind-certs
|
||||
docker run -d --env="DOCKER_HOST=tcp://localhost:2375" --env="DOCKER_TLS_VERIFY=1"\
|
||||
|
@ -106,22 +75,19 @@ integration-dind-ssl: build-dind-certs build build-py3
|
|||
docker:${TEST_ENGINE_VERSION}-dind\
|
||||
dockerd --tlsverify --tlscacert=/certs/ca.pem --tlscert=/certs/server-cert.pem\
|
||||
--tlskey=/certs/server-key.pem -H tcp://0.0.0.0:2375 --experimental
|
||||
docker run -t --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\
|
||||
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\
|
||||
--network dpy-tests docker-sdk-python py.test tests/integration/${file}
|
||||
docker run -t --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\
|
||||
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\
|
||||
--network dpy-tests docker-sdk-python3 py.test tests/integration/${file}
|
||||
docker rm -vf dpy-dind-ssl dpy-dind-certs
|
||||
|
||||
.PHONY: flake8
|
||||
flake8: build
|
||||
docker run -t --rm docker-sdk-python flake8 docker tests
|
||||
flake8: build-py3
|
||||
docker run -t --rm docker-sdk-python3 flake8 docker tests
|
||||
|
||||
.PHONY: docs
|
||||
docs: build-docs
|
||||
docker run --rm -t -v `pwd`:/src docker-sdk-python-docs sphinx-build docs docs/_build
|
||||
|
||||
.PHONY: shell
|
||||
shell: build
|
||||
docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python python
|
||||
shell: build-py3
|
||||
docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python3 python
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import json
|
||||
import struct
|
||||
import urllib
|
||||
from functools import partial
|
||||
|
||||
import requests
|
||||
import requests.exceptions
|
||||
import six
|
||||
import websocket
|
||||
|
||||
from .. import auth
|
||||
|
@ -192,12 +192,12 @@ class APIClient(
|
|||
# version detection needs to be after unix adapter mounting
|
||||
if version is None or (isinstance(
|
||||
version,
|
||||
six.string_types
|
||||
str
|
||||
) and version.lower() == 'auto'):
|
||||
self._version = self._retrieve_server_version()
|
||||
else:
|
||||
self._version = version
|
||||
if not isinstance(self._version, six.string_types):
|
||||
if not isinstance(self._version, str):
|
||||
raise DockerException(
|
||||
'Version parameter must be a string or None. Found {0}'.format(
|
||||
type(version).__name__
|
||||
|
@ -246,13 +246,13 @@ class APIClient(
|
|||
|
||||
def _url(self, pathfmt, *args, **kwargs):
|
||||
for arg in args:
|
||||
if not isinstance(arg, six.string_types):
|
||||
if not isinstance(arg, str):
|
||||
raise ValueError(
|
||||
'Expected a string but found {0} ({1}) '
|
||||
'instead'.format(arg, type(arg))
|
||||
)
|
||||
|
||||
quote_f = partial(six.moves.urllib.parse.quote, safe="/:")
|
||||
quote_f = partial(urllib.parse.quote, safe="/:")
|
||||
args = map(quote_f, args)
|
||||
|
||||
if kwargs.get('versioned_api', True):
|
||||
|
@ -284,7 +284,7 @@ class APIClient(
|
|||
# so we do this disgusting thing here.
|
||||
data2 = {}
|
||||
if data is not None and isinstance(data, dict):
|
||||
for k, v in six.iteritems(data):
|
||||
for k, v in iter(data.items()):
|
||||
if v is not None:
|
||||
data2[k] = v
|
||||
elif data is not None:
|
||||
|
@ -320,12 +320,10 @@ class APIClient(
|
|||
sock = response.raw._fp.fp.raw.sock
|
||||
elif self.base_url.startswith('http+docker://ssh'):
|
||||
sock = response.raw._fp.fp.channel
|
||||
elif six.PY3:
|
||||
else:
|
||||
sock = response.raw._fp.fp.raw
|
||||
if self.base_url.startswith("https://"):
|
||||
sock = sock._sock
|
||||
else:
|
||||
sock = response.raw._fp.fp._sock
|
||||
try:
|
||||
# Keep a reference to the response to stop it being garbage
|
||||
# collected. If the response is garbage collected, it will
|
||||
|
@ -465,7 +463,7 @@ class APIClient(
|
|||
self._result(res, binary=True)
|
||||
|
||||
self._raise_for_status(res)
|
||||
sep = six.binary_type()
|
||||
sep = b''
|
||||
if stream:
|
||||
return self._multiplexed_response_stream_helper(res)
|
||||
else:
|
||||
|
|
|
@ -11,6 +11,7 @@ from docker.context.config import get_context_host
|
|||
|
||||
class Context:
|
||||
"""A context."""
|
||||
|
||||
def __init__(self, name, orchestrator=None, host=None, endpoints=None,
|
||||
tls=False):
|
||||
if not name:
|
||||
|
@ -128,9 +129,9 @@ class Context:
|
|||
key = os.path.join(tls_dir, endpoint, filename)
|
||||
if all([ca_cert, cert, key]):
|
||||
verify = None
|
||||
if endpoint == "docker":
|
||||
if not self.endpoints["docker"].get("SkipTLSVerify", False):
|
||||
verify = True
|
||||
if endpoint == "docker" and not self.endpoints["docker"].get(
|
||||
"SkipTLSVerify", False):
|
||||
verify = True
|
||||
certs[endpoint] = TLSConfig(
|
||||
client_cert=(cert, key), ca_cert=ca_cert, verify=verify)
|
||||
self.tls_cfg = certs
|
||||
|
|
|
@ -53,7 +53,7 @@ class SSHSocket(socket.socket):
|
|||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
preexec_func = f
|
||||
|
||||
env = dict(os.environ)
|
||||
env = dict(os.environ)
|
||||
|
||||
# drop LD_LIBRARY_PATH and SSL_CERT_FILE
|
||||
env.pop('LD_LIBRARY_PATH', None)
|
||||
|
@ -65,7 +65,7 @@ class SSHSocket(socket.socket):
|
|||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE,
|
||||
preexec_fn=preexec_func)
|
||||
preexec_fn=None if constants.IS_WINDOWS_PLATFORM else preexec_func)
|
||||
|
||||
def _write(self, data):
|
||||
if not self.proc or self.proc.stdin.closed:
|
||||
|
|
|
@ -7,8 +7,6 @@ import string
|
|||
from datetime import datetime
|
||||
from distutils.version import StrictVersion
|
||||
|
||||
import six
|
||||
|
||||
from .. import errors
|
||||
from .. import tls
|
||||
from ..constants import DEFAULT_HTTP_HOST
|
||||
|
@ -16,11 +14,7 @@ from ..constants import DEFAULT_UNIX_SOCKET
|
|||
from ..constants import DEFAULT_NPIPE
|
||||
from ..constants import BYTE_UNITS
|
||||
|
||||
if six.PY2:
|
||||
from urllib import splitnport
|
||||
from urlparse import urlparse
|
||||
else:
|
||||
from urllib.parse import splitnport, urlparse
|
||||
from urllib.parse import splitnport, urlparse
|
||||
|
||||
|
||||
def create_ipam_pool(*args, **kwargs):
|
||||
|
@ -39,8 +33,7 @@ def create_ipam_config(*args, **kwargs):
|
|||
|
||||
def decode_json_header(header):
|
||||
data = base64.b64decode(header)
|
||||
if six.PY3:
|
||||
data = data.decode('utf-8')
|
||||
data = data.decode('utf-8')
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
|
@ -80,7 +73,7 @@ def _convert_port_binding(binding):
|
|||
if len(binding) == 2:
|
||||
result['HostPort'] = binding[1]
|
||||
result['HostIp'] = binding[0]
|
||||
elif isinstance(binding[0], six.string_types):
|
||||
elif isinstance(binding[0], str):
|
||||
result['HostIp'] = binding[0]
|
||||
else:
|
||||
result['HostPort'] = binding[0]
|
||||
|
@ -104,7 +97,7 @@ def _convert_port_binding(binding):
|
|||
|
||||
def convert_port_bindings(port_bindings):
|
||||
result = {}
|
||||
for k, v in six.iteritems(port_bindings):
|
||||
for k, v in iter(port_bindings.items()):
|
||||
key = str(k)
|
||||
if '/' not in key:
|
||||
key += '/tcp'
|
||||
|
@ -121,7 +114,7 @@ def convert_volume_binds(binds):
|
|||
|
||||
result = []
|
||||
for k, v in binds.items():
|
||||
if isinstance(k, six.binary_type):
|
||||
if isinstance(k, bytes):
|
||||
k = k.decode('utf-8')
|
||||
|
||||
if isinstance(v, dict):
|
||||
|
@ -132,7 +125,7 @@ def convert_volume_binds(binds):
|
|||
)
|
||||
|
||||
bind = v['bind']
|
||||
if isinstance(bind, six.binary_type):
|
||||
if isinstance(bind, bytes):
|
||||
bind = bind.decode('utf-8')
|
||||
|
||||
if 'ro' in v:
|
||||
|
@ -143,13 +136,13 @@ def convert_volume_binds(binds):
|
|||
mode = 'rw'
|
||||
|
||||
result.append(
|
||||
six.text_type('{0}:{1}:{2}').format(k, bind, mode)
|
||||
str('{0}:{1}:{2}').format(k, bind, mode)
|
||||
)
|
||||
else:
|
||||
if isinstance(v, six.binary_type):
|
||||
if isinstance(v, bytes):
|
||||
v = v.decode('utf-8')
|
||||
result.append(
|
||||
six.text_type('{0}:{1}:rw').format(k, v)
|
||||
str('{0}:{1}:rw').format(k, v)
|
||||
)
|
||||
return result
|
||||
|
||||
|
@ -166,7 +159,7 @@ def convert_tmpfs_mounts(tmpfs):
|
|||
|
||||
result = {}
|
||||
for mount in tmpfs:
|
||||
if isinstance(mount, six.string_types):
|
||||
if isinstance(mount, str):
|
||||
if ":" in mount:
|
||||
name, options = mount.split(":", 1)
|
||||
else:
|
||||
|
@ -191,7 +184,7 @@ def convert_service_networks(networks):
|
|||
|
||||
result = []
|
||||
for n in networks:
|
||||
if isinstance(n, six.string_types):
|
||||
if isinstance(n, str):
|
||||
n = {'Target': n}
|
||||
result.append(n)
|
||||
return result
|
||||
|
@ -302,7 +295,7 @@ def parse_devices(devices):
|
|||
if isinstance(device, dict):
|
||||
device_list.append(device)
|
||||
continue
|
||||
if not isinstance(device, six.string_types):
|
||||
if not isinstance(device, str):
|
||||
raise errors.DockerException(
|
||||
'Invalid device type {0}'.format(type(device))
|
||||
)
|
||||
|
@ -372,13 +365,13 @@ def kwargs_from_env(ssl_version=None, assert_hostname=None, environment=None):
|
|||
|
||||
def convert_filters(filters):
|
||||
result = {}
|
||||
for k, v in six.iteritems(filters):
|
||||
for k, v in iter(filters.items()):
|
||||
if isinstance(v, bool):
|
||||
v = 'true' if v else 'false'
|
||||
if not isinstance(v, list):
|
||||
v = [v, ]
|
||||
result[k] = [
|
||||
str(item) if not isinstance(item, six.string_types) else item
|
||||
str(item) if not isinstance(item, str) else item
|
||||
for item in v
|
||||
]
|
||||
return json.dumps(result)
|
||||
|
@ -391,7 +384,7 @@ def datetime_to_timestamp(dt):
|
|||
|
||||
|
||||
def parse_bytes(s):
|
||||
if isinstance(s, six.integer_types + (float,)):
|
||||
if isinstance(s, (int, float,)):
|
||||
return s
|
||||
if len(s) == 0:
|
||||
return 0
|
||||
|
@ -433,7 +426,7 @@ def parse_bytes(s):
|
|||
|
||||
def normalize_links(links):
|
||||
if isinstance(links, dict):
|
||||
links = six.iteritems(links)
|
||||
links = iter(links.items())
|
||||
|
||||
return ['{0}:{1}'.format(k, v) if v else k for k, v in sorted(links)]
|
||||
|
||||
|
@ -468,8 +461,6 @@ def parse_env_file(env_file):
|
|||
|
||||
|
||||
def split_command(command):
|
||||
if six.PY2 and not isinstance(command, six.binary_type):
|
||||
command = command.encode('utf-8')
|
||||
return shlex.split(command)
|
||||
|
||||
|
||||
|
@ -477,22 +468,22 @@ def format_environment(environment):
|
|||
def format_env(key, value):
|
||||
if value is None:
|
||||
return key
|
||||
if isinstance(value, six.binary_type):
|
||||
if isinstance(value, bytes):
|
||||
value = value.decode('utf-8')
|
||||
|
||||
return u'{key}={value}'.format(key=key, value=value)
|
||||
return [format_env(*var) for var in six.iteritems(environment)]
|
||||
return [format_env(*var) for var in iter(environment.items())]
|
||||
|
||||
|
||||
def format_extra_hosts(extra_hosts, task=False):
|
||||
# Use format dictated by Swarm API if container is part of a task
|
||||
if task:
|
||||
return [
|
||||
'{} {}'.format(v, k) for k, v in sorted(six.iteritems(extra_hosts))
|
||||
'{} {}'.format(v, k) for k, v in sorted(iter(extra_hosts.items()))
|
||||
]
|
||||
|
||||
return [
|
||||
'{}:{}'.format(k, v) for k, v in sorted(six.iteritems(extra_hosts))
|
||||
'{}:{}'.format(k, v) for k, v in sorted(iter(extra_hosts.items()))
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,5 @@ pyOpenSSL==18.0.0
|
|||
pyparsing==2.2.0
|
||||
pywin32==227; sys_platform == 'win32'
|
||||
requests==2.20.0
|
||||
six==1.10.0
|
||||
urllib3==1.24.3
|
||||
websocket-client==0.56.0
|
||||
|
|
12
setup.py
12
setup.py
|
@ -11,18 +11,11 @@ ROOT_DIR = os.path.dirname(__file__)
|
|||
SOURCE_DIR = os.path.join(ROOT_DIR)
|
||||
|
||||
requirements = [
|
||||
'six >= 1.4.0',
|
||||
'websocket-client >= 0.32.0',
|
||||
'requests >= 2.14.2, != 2.18.0',
|
||||
]
|
||||
|
||||
extras_require = {
|
||||
':python_version < "3.5"': 'backports.ssl_match_hostname >= 3.5',
|
||||
# While not imported explicitly, the ipaddress module is required for
|
||||
# ssl_match_hostname to verify hosts match with certificates via
|
||||
# ServerAltname: https://pypi.python.org/pypi/backports.ssl_match_hostname
|
||||
':python_version < "3.3"': 'ipaddress >= 1.0.16',
|
||||
|
||||
# win32 APIs if on Windows (required for npipe support)
|
||||
':sys_platform == "win32"': 'pywin32==227',
|
||||
|
||||
|
@ -69,7 +62,7 @@ setup(
|
|||
install_requires=requirements,
|
||||
tests_require=test_requirements,
|
||||
extras_require=extras_require,
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
|
||||
python_requires='>=3.6',
|
||||
zip_safe=False,
|
||||
test_suite='tests',
|
||||
classifiers=[
|
||||
|
@ -78,10 +71,7 @@ setup(
|
|||
'Intended Audience :: Developers',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
setuptools==44.0.0 # last version with python 2.7 support
|
||||
setuptools==54.1.1
|
||||
coverage==4.5.2
|
||||
flake8==3.6.0
|
||||
mock==1.0.1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARG PYTHON_VERSION=2.7
|
||||
ARG PYTHON_VERSION=3.6
|
||||
|
||||
FROM python:${PYTHON_VERSION}
|
||||
RUN mkdir /tmp/certs
|
||||
|
|
|
@ -7,7 +7,6 @@ from datetime import datetime
|
|||
|
||||
import pytest
|
||||
import requests
|
||||
import six
|
||||
|
||||
import docker
|
||||
from .. import helpers
|
||||
|
@ -35,7 +34,7 @@ class ListContainersTest(BaseAPIIntegrationTest):
|
|||
assert len(retrieved) == 1
|
||||
retrieved = retrieved[0]
|
||||
assert 'Command' in retrieved
|
||||
assert retrieved['Command'] == six.text_type('true')
|
||||
assert retrieved['Command'] == str('true')
|
||||
assert 'Image' in retrieved
|
||||
assert re.search(r'alpine:.*', retrieved['Image'])
|
||||
assert 'Status' in retrieved
|
||||
|
@ -104,9 +103,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
|
|||
self.client.start(container3_id)
|
||||
assert self.client.wait(container3_id)['StatusCode'] == 0
|
||||
|
||||
logs = self.client.logs(container3_id)
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
logs = self.client.logs(container3_id).decode('utf-8')
|
||||
assert '{0}_NAME='.format(link_env_prefix1) in logs
|
||||
assert '{0}_ENV_FOO=1'.format(link_env_prefix1) in logs
|
||||
assert '{0}_NAME='.format(link_env_prefix2) in logs
|
||||
|
@ -227,9 +224,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
|
|||
self.client.start(container)
|
||||
self.client.wait(container)
|
||||
|
||||
logs = self.client.logs(container)
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
logs = self.client.logs(container).decode('utf-8')
|
||||
groups = logs.strip().split(' ')
|
||||
assert '1000' in groups
|
||||
assert '1001' in groups
|
||||
|
@ -244,9 +239,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
|
|||
self.client.start(container)
|
||||
self.client.wait(container)
|
||||
|
||||
logs = self.client.logs(container)
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
logs = self.client.logs(container).decode('utf-8')
|
||||
|
||||
groups = logs.strip().split(' ')
|
||||
assert '1000' in groups
|
||||
|
@ -515,10 +508,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
|
|||
TEST_IMG,
|
||||
['ls', self.mount_dest],
|
||||
)
|
||||
logs = self.client.logs(container)
|
||||
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
logs = self.client.logs(container).decode('utf-8')
|
||||
assert self.filename in logs
|
||||
inspect_data = self.client.inspect_container(container)
|
||||
self.check_container_data(inspect_data, True)
|
||||
|
@ -534,10 +524,8 @@ class VolumeBindTest(BaseAPIIntegrationTest):
|
|||
TEST_IMG,
|
||||
['ls', self.mount_dest],
|
||||
)
|
||||
logs = self.client.logs(container)
|
||||
logs = self.client.logs(container).decode('utf-8')
|
||||
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
assert self.filename in logs
|
||||
|
||||
inspect_data = self.client.inspect_container(container)
|
||||
|
@ -554,9 +542,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
|
|||
host_config=host_config
|
||||
)
|
||||
assert container
|
||||
logs = self.client.logs(container)
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
logs = self.client.logs(container).decode('utf-8')
|
||||
assert self.filename in logs
|
||||
inspect_data = self.client.inspect_container(container)
|
||||
self.check_container_data(inspect_data, True)
|
||||
|
@ -573,9 +559,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
|
|||
host_config=host_config
|
||||
)
|
||||
assert container
|
||||
logs = self.client.logs(container)
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
logs = self.client.logs(container).decode('utf-8')
|
||||
assert self.filename in logs
|
||||
inspect_data = self.client.inspect_container(container)
|
||||
self.check_container_data(inspect_data, False)
|
||||
|
@ -645,9 +629,8 @@ class ArchiveTest(BaseAPIIntegrationTest):
|
|||
for d in strm:
|
||||
destination.write(d)
|
||||
destination.seek(0)
|
||||
retrieved_data = helpers.untar_file(destination, 'data.txt')
|
||||
if six.PY3:
|
||||
retrieved_data = retrieved_data.decode('utf-8')
|
||||
retrieved_data = helpers.untar_file(destination, 'data.txt')\
|
||||
.decode('utf-8')
|
||||
assert data == retrieved_data.strip()
|
||||
|
||||
def test_get_file_stat_from_container(self):
|
||||
|
@ -683,9 +666,6 @@ class ArchiveTest(BaseAPIIntegrationTest):
|
|||
self.client.start(ctnr)
|
||||
self.client.wait(ctnr)
|
||||
logs = self.client.logs(ctnr)
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
data = data.decode('utf-8')
|
||||
assert logs.strip() == data
|
||||
|
||||
def test_copy_directory_to_container(self):
|
||||
|
@ -700,9 +680,7 @@ class ArchiveTest(BaseAPIIntegrationTest):
|
|||
self.client.put_archive(ctnr, '/vol1', test_tar)
|
||||
self.client.start(ctnr)
|
||||
self.client.wait(ctnr)
|
||||
logs = self.client.logs(ctnr)
|
||||
if six.PY3:
|
||||
logs = logs.decode('utf-8')
|
||||
logs = self.client.logs(ctnr).decode('utf-8')
|
||||
results = logs.strip().split()
|
||||
assert 'a.py' in results
|
||||
assert 'b.py' in results
|
||||
|
@ -861,7 +839,7 @@ Line2'''
|
|||
id = container['Id']
|
||||
self.tmp_containers.append(id)
|
||||
self.client.start(id)
|
||||
logs = six.binary_type()
|
||||
logs = b''
|
||||
for chunk in self.client.logs(id, stream=True, follow=True):
|
||||
logs += chunk
|
||||
|
||||
|
@ -881,7 +859,7 @@ Line2'''
|
|||
id = container['Id']
|
||||
self.tmp_containers.append(id)
|
||||
self.client.start(id)
|
||||
logs = six.binary_type()
|
||||
logs = b''
|
||||
|
||||
generator = self.client.logs(id, stream=True, follow=True)
|
||||
threading.Timer(1, generator.close).start()
|
||||
|
|
|
@ -7,9 +7,8 @@ import tempfile
|
|||
import threading
|
||||
|
||||
import pytest
|
||||
import six
|
||||
from six.moves import BaseHTTPServer
|
||||
from six.moves import socketserver
|
||||
from http.server import SimpleHTTPRequestHandler
|
||||
import socketserver
|
||||
|
||||
|
||||
import docker
|
||||
|
@ -33,7 +32,7 @@ class ListImagesTest(BaseAPIIntegrationTest):
|
|||
|
||||
def test_images_quiet(self):
|
||||
res1 = self.client.images(quiet=True)
|
||||
assert type(res1[0]) == six.text_type
|
||||
assert type(res1[0]) == str
|
||||
|
||||
|
||||
class PullImageTest(BaseAPIIntegrationTest):
|
||||
|
@ -44,7 +43,7 @@ class PullImageTest(BaseAPIIntegrationTest):
|
|||
pass
|
||||
res = self.client.pull('hello-world')
|
||||
self.tmp_imgs.append('hello-world')
|
||||
assert type(res) == six.text_type
|
||||
assert type(res) == str
|
||||
assert len(self.client.images('hello-world')) >= 1
|
||||
img_info = self.client.inspect_image('hello-world')
|
||||
assert 'Id' in img_info
|
||||
|
@ -273,7 +272,7 @@ class ImportImageTest(BaseAPIIntegrationTest):
|
|||
def temporary_http_file_server(self, stream):
|
||||
'''Serve data from an IO stream over HTTP.'''
|
||||
|
||||
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
class Handler(SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/x-tar')
|
||||
|
|
|
@ -5,7 +5,6 @@ import time
|
|||
|
||||
import docker
|
||||
import pytest
|
||||
import six
|
||||
|
||||
from ..helpers import (
|
||||
force_leave_swarm, requires_api_version, requires_experimental
|
||||
|
@ -150,7 +149,7 @@ class ServiceTest(BaseAPIIntegrationTest):
|
|||
else:
|
||||
break
|
||||
|
||||
if six.PY3:
|
||||
if log_line is not None:
|
||||
log_line = log_line.decode('utf-8')
|
||||
assert 'hello\n' in log_line
|
||||
|
||||
|
|
|
@ -2,31 +2,38 @@ import unittest
|
|||
import docker
|
||||
from docker.transport.sshconn import SSHSocket
|
||||
|
||||
|
||||
class SSHAdapterTest(unittest.TestCase):
|
||||
def test_ssh_hostname_prefix_trim(self):
|
||||
conn = docker.transport.SSHHTTPAdapter(base_url="ssh://user@hostname:1234", shell_out=True)
|
||||
@staticmethod
|
||||
def test_ssh_hostname_prefix_trim():
|
||||
conn = docker.transport.SSHHTTPAdapter(
|
||||
base_url="ssh://user@hostname:1234", shell_out=True)
|
||||
assert conn.ssh_host == "user@hostname:1234"
|
||||
|
||||
def test_ssh_parse_url(self):
|
||||
@staticmethod
|
||||
def test_ssh_parse_url():
|
||||
c = SSHSocket(host="user@hostname:1234")
|
||||
assert c.host == "hostname"
|
||||
assert c.port == "1234"
|
||||
assert c.user == "user"
|
||||
|
||||
def test_ssh_parse_hostname_only(self):
|
||||
@staticmethod
|
||||
def test_ssh_parse_hostname_only():
|
||||
c = SSHSocket(host="hostname")
|
||||
assert c.host == "hostname"
|
||||
assert c.port == None
|
||||
assert c.user == None
|
||||
assert c.port is None
|
||||
assert c.user is None
|
||||
|
||||
def test_ssh_parse_user_and_hostname(self):
|
||||
@staticmethod
|
||||
def test_ssh_parse_user_and_hostname():
|
||||
c = SSHSocket(host="user@hostname")
|
||||
assert c.host == "hostname"
|
||||
assert c.port == None
|
||||
assert c.port is None
|
||||
assert c.user == "user"
|
||||
|
||||
def test_ssh_parse_hostname_and_port(self):
|
||||
@staticmethod
|
||||
def test_ssh_parse_hostname_and_port():
|
||||
c = SSHSocket(host="hostname:22")
|
||||
assert c.host == "hostname"
|
||||
assert c.port == "22"
|
||||
assert c.user == None
|
||||
assert c.user is None
|
||||
|
|
Loading…
Reference in New Issue