Remove support to pre python 3.6

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
This commit is contained in:
Ulysses Souza 2021-03-10 20:43:37 -03:00
parent 31775a1532
commit c8fba210a2
19 changed files with 88 additions and 182 deletions

View File

@ -8,7 +8,7 @@ jobs:
strategy: strategy:
max-parallel: 1 max-parallel: 1
matrix: 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: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -18,8 +18,8 @@ jobs:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python3 -m pip install --upgrade pip
pip install -r test-requirements.txt -r requirements.txt pip3 install -r test-requirements.txt -r requirements.txt
- name: Test with pytest - name: Test with pytest
run: | run: |
docker logout docker logout

View File

@ -4,7 +4,7 @@ sphinx:
configuration: docs/conf.py configuration: docs/conf.py
python: python:
version: 3.5 version: 3.6
install: install:
- requirements: docs-requirements.txt - requirements: docs-requirements.txt
- requirements: requirements.txt - requirements: requirements.txt

View File

@ -1,11 +1,7 @@
ARG PYTHON_VERSION=2.7 ARG PYTHON_VERSION=3.7
FROM python:${PYTHON_VERSION} 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 RUN mkdir /src
WORKDIR /src WORKDIR /src

View File

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

5
Jenkinsfile vendored
View File

@ -1,7 +1,6 @@
#!groovy #!groovy
def imageNameBase = "dockerpinata/docker-py" def imageNameBase = "dockerpinata/docker-py"
def imageNamePy2
def imageNamePy3 def imageNamePy3
def imageDindSSH def imageDindSSH
def images = [:] def images = [:]
@ -22,12 +21,10 @@ def buildImages = { ->
stage("build image") { stage("build image") {
checkout(scm) checkout(scm)
imageNamePy2 = "${imageNameBase}:py2-${gitCommit()}"
imageNamePy3 = "${imageNameBase}:py3-${gitCommit()}" imageNamePy3 = "${imageNameBase}:py3-${gitCommit()}"
imageDindSSH = "${imageNameBase}:sshdind-${gitCommit()}" imageDindSSH = "${imageNameBase}:sshdind-${gitCommit()}"
withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') { withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
buildImage(imageDindSSH, "-f tests/Dockerfile-ssh-dind .", "") 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") 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')`") throw new Exception("Need Docker version to test, e.g.: `runTests(dockerVersion: '19.03.12')`")
} }
if (!pythonVersion) { 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')`")
} }
{ -> { ->

View File

@ -6,13 +6,9 @@ all: test
.PHONY: clean .PHONY: clean
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 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 .PHONY: build-dind-ssh
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 . 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 . docker build -t dpy-dind-certs -f tests/Dockerfile-dind-certs .
.PHONY: test .PHONY: test
test: flake8 unit-test unit-test-py3 integration-dind integration-dind-ssl test: flake8 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
.PHONY: unit-test-py3 .PHONY: unit-test-py3
unit-test-py3: build-py3 unit-test-py3: build-py3
docker run -t --rm docker-sdk-python3 py.test tests/unit 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 .PHONY: integration-test-py3
integration-test-py3: build-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} 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 docker network inspect dpy-tests || docker network create dpy-tests
.PHONY: integration-dind .PHONY: integration-dind
integration-dind: integration-dind-py2 integration-dind-py3 integration-dind: 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
.PHONY: integration-dind-py3 .PHONY: integration-dind-py3
integration-dind-py3: build-py3 setup-network 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} --network dpy-tests docker-sdk-python3 py.test tests/integration/${file}
docker rm -vf dpy-dind-py3 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 .PHONY: integration-ssh-py3
integration-ssh-py3: build-dind-ssh build-py3 setup-network 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 .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 rm -vf dpy-dind-certs dpy-dind-ssl || :
docker run -d --name dpy-dind-certs dpy-dind-certs docker run -d --name dpy-dind-certs dpy-dind-certs
docker run -d --env="DOCKER_HOST=tcp://localhost:2375" --env="DOCKER_TLS_VERIFY=1"\ 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\ docker:${TEST_ENGINE_VERSION}-dind\
dockerd --tlsverify --tlscacert=/certs/ca.pem --tlscert=/certs/server-cert.pem\ dockerd --tlsverify --tlscacert=/certs/ca.pem --tlscert=/certs/server-cert.pem\
--tlskey=/certs/server-key.pem -H tcp://0.0.0.0:2375 --experimental --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"\ 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}"\ --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} --network dpy-tests docker-sdk-python3 py.test tests/integration/${file}
docker rm -vf dpy-dind-ssl dpy-dind-certs docker rm -vf dpy-dind-ssl dpy-dind-certs
.PHONY: flake8 .PHONY: flake8
flake8: build flake8: build-py3
docker run -t --rm docker-sdk-python flake8 docker tests docker run -t --rm docker-sdk-python3 flake8 docker tests
.PHONY: docs .PHONY: docs
docs: build-docs docs: build-docs
docker run --rm -t -v `pwd`:/src docker-sdk-python-docs sphinx-build docs docs/_build docker run --rm -t -v `pwd`:/src docker-sdk-python-docs sphinx-build docs docs/_build
.PHONY: shell .PHONY: shell
shell: build shell: build-py3
docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python python docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python3 python

View File

@ -1,10 +1,10 @@
import json import json
import struct import struct
import urllib
from functools import partial from functools import partial
import requests import requests
import requests.exceptions import requests.exceptions
import six
import websocket import websocket
from .. import auth from .. import auth
@ -192,12 +192,12 @@ class APIClient(
# version detection needs to be after unix adapter mounting # version detection needs to be after unix adapter mounting
if version is None or (isinstance( if version is None or (isinstance(
version, version,
six.string_types str
) and version.lower() == 'auto'): ) and version.lower() == 'auto'):
self._version = self._retrieve_server_version() self._version = self._retrieve_server_version()
else: else:
self._version = version self._version = version
if not isinstance(self._version, six.string_types): if not isinstance(self._version, str):
raise DockerException( raise DockerException(
'Version parameter must be a string or None. Found {0}'.format( 'Version parameter must be a string or None. Found {0}'.format(
type(version).__name__ type(version).__name__
@ -246,13 +246,13 @@ class APIClient(
def _url(self, pathfmt, *args, **kwargs): def _url(self, pathfmt, *args, **kwargs):
for arg in args: for arg in args:
if not isinstance(arg, six.string_types): if not isinstance(arg, str):
raise ValueError( raise ValueError(
'Expected a string but found {0} ({1}) ' 'Expected a string but found {0} ({1}) '
'instead'.format(arg, type(arg)) '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) args = map(quote_f, args)
if kwargs.get('versioned_api', True): if kwargs.get('versioned_api', True):
@ -284,7 +284,7 @@ class APIClient(
# so we do this disgusting thing here. # so we do this disgusting thing here.
data2 = {} data2 = {}
if data is not None and isinstance(data, dict): 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: if v is not None:
data2[k] = v data2[k] = v
elif data is not None: elif data is not None:
@ -320,12 +320,10 @@ class APIClient(
sock = response.raw._fp.fp.raw.sock sock = response.raw._fp.fp.raw.sock
elif self.base_url.startswith('http+docker://ssh'): elif self.base_url.startswith('http+docker://ssh'):
sock = response.raw._fp.fp.channel sock = response.raw._fp.fp.channel
elif six.PY3: else:
sock = response.raw._fp.fp.raw sock = response.raw._fp.fp.raw
if self.base_url.startswith("https://"): if self.base_url.startswith("https://"):
sock = sock._sock sock = sock._sock
else:
sock = response.raw._fp.fp._sock
try: try:
# Keep a reference to the response to stop it being garbage # Keep a reference to the response to stop it being garbage
# collected. If the response is garbage collected, it will # collected. If the response is garbage collected, it will
@ -465,7 +463,7 @@ class APIClient(
self._result(res, binary=True) self._result(res, binary=True)
self._raise_for_status(res) self._raise_for_status(res)
sep = six.binary_type() sep = b''
if stream: if stream:
return self._multiplexed_response_stream_helper(res) return self._multiplexed_response_stream_helper(res)
else: else:

View File

@ -11,6 +11,7 @@ from docker.context.config import get_context_host
class Context: class Context:
"""A context.""" """A context."""
def __init__(self, name, orchestrator=None, host=None, endpoints=None, def __init__(self, name, orchestrator=None, host=None, endpoints=None,
tls=False): tls=False):
if not name: if not name:
@ -128,9 +129,9 @@ class Context:
key = os.path.join(tls_dir, endpoint, filename) key = os.path.join(tls_dir, endpoint, filename)
if all([ca_cert, cert, key]): if all([ca_cert, cert, key]):
verify = None verify = None
if endpoint == "docker": if endpoint == "docker" and not self.endpoints["docker"].get(
if not self.endpoints["docker"].get("SkipTLSVerify", False): "SkipTLSVerify", False):
verify = True verify = True
certs[endpoint] = TLSConfig( certs[endpoint] = TLSConfig(
client_cert=(cert, key), ca_cert=ca_cert, verify=verify) client_cert=(cert, key), ca_cert=ca_cert, verify=verify)
self.tls_cfg = certs self.tls_cfg = certs

View File

@ -53,7 +53,7 @@ class SSHSocket(socket.socket):
signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN)
preexec_func = f preexec_func = f
env = dict(os.environ) env = dict(os.environ)
# drop LD_LIBRARY_PATH and SSL_CERT_FILE # drop LD_LIBRARY_PATH and SSL_CERT_FILE
env.pop('LD_LIBRARY_PATH', None) env.pop('LD_LIBRARY_PATH', None)
@ -65,7 +65,7 @@ class SSHSocket(socket.socket):
shell=True, shell=True,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
preexec_fn=preexec_func) preexec_fn=None if constants.IS_WINDOWS_PLATFORM else preexec_func)
def _write(self, data): def _write(self, data):
if not self.proc or self.proc.stdin.closed: if not self.proc or self.proc.stdin.closed:

View File

@ -7,8 +7,6 @@ import string
from datetime import datetime from datetime import datetime
from distutils.version import StrictVersion from distutils.version import StrictVersion
import six
from .. import errors from .. import errors
from .. import tls from .. import tls
from ..constants import DEFAULT_HTTP_HOST from ..constants import DEFAULT_HTTP_HOST
@ -16,11 +14,7 @@ from ..constants import DEFAULT_UNIX_SOCKET
from ..constants import DEFAULT_NPIPE from ..constants import DEFAULT_NPIPE
from ..constants import BYTE_UNITS from ..constants import BYTE_UNITS
if six.PY2: from urllib.parse import splitnport, urlparse
from urllib import splitnport
from urlparse import urlparse
else:
from urllib.parse import splitnport, urlparse
def create_ipam_pool(*args, **kwargs): def create_ipam_pool(*args, **kwargs):
@ -39,8 +33,7 @@ def create_ipam_config(*args, **kwargs):
def decode_json_header(header): def decode_json_header(header):
data = base64.b64decode(header) data = base64.b64decode(header)
if six.PY3: data = data.decode('utf-8')
data = data.decode('utf-8')
return json.loads(data) return json.loads(data)
@ -80,7 +73,7 @@ def _convert_port_binding(binding):
if len(binding) == 2: if len(binding) == 2:
result['HostPort'] = binding[1] result['HostPort'] = binding[1]
result['HostIp'] = binding[0] result['HostIp'] = binding[0]
elif isinstance(binding[0], six.string_types): elif isinstance(binding[0], str):
result['HostIp'] = binding[0] result['HostIp'] = binding[0]
else: else:
result['HostPort'] = binding[0] result['HostPort'] = binding[0]
@ -104,7 +97,7 @@ def _convert_port_binding(binding):
def convert_port_bindings(port_bindings): def convert_port_bindings(port_bindings):
result = {} result = {}
for k, v in six.iteritems(port_bindings): for k, v in iter(port_bindings.items()):
key = str(k) key = str(k)
if '/' not in key: if '/' not in key:
key += '/tcp' key += '/tcp'
@ -121,7 +114,7 @@ def convert_volume_binds(binds):
result = [] result = []
for k, v in binds.items(): for k, v in binds.items():
if isinstance(k, six.binary_type): if isinstance(k, bytes):
k = k.decode('utf-8') k = k.decode('utf-8')
if isinstance(v, dict): if isinstance(v, dict):
@ -132,7 +125,7 @@ def convert_volume_binds(binds):
) )
bind = v['bind'] bind = v['bind']
if isinstance(bind, six.binary_type): if isinstance(bind, bytes):
bind = bind.decode('utf-8') bind = bind.decode('utf-8')
if 'ro' in v: if 'ro' in v:
@ -143,13 +136,13 @@ def convert_volume_binds(binds):
mode = 'rw' mode = 'rw'
result.append( result.append(
six.text_type('{0}:{1}:{2}').format(k, bind, mode) str('{0}:{1}:{2}').format(k, bind, mode)
) )
else: else:
if isinstance(v, six.binary_type): if isinstance(v, bytes):
v = v.decode('utf-8') v = v.decode('utf-8')
result.append( result.append(
six.text_type('{0}:{1}:rw').format(k, v) str('{0}:{1}:rw').format(k, v)
) )
return result return result
@ -166,7 +159,7 @@ def convert_tmpfs_mounts(tmpfs):
result = {} result = {}
for mount in tmpfs: for mount in tmpfs:
if isinstance(mount, six.string_types): if isinstance(mount, str):
if ":" in mount: if ":" in mount:
name, options = mount.split(":", 1) name, options = mount.split(":", 1)
else: else:
@ -191,7 +184,7 @@ def convert_service_networks(networks):
result = [] result = []
for n in networks: for n in networks:
if isinstance(n, six.string_types): if isinstance(n, str):
n = {'Target': n} n = {'Target': n}
result.append(n) result.append(n)
return result return result
@ -302,7 +295,7 @@ def parse_devices(devices):
if isinstance(device, dict): if isinstance(device, dict):
device_list.append(device) device_list.append(device)
continue continue
if not isinstance(device, six.string_types): if not isinstance(device, str):
raise errors.DockerException( raise errors.DockerException(
'Invalid device type {0}'.format(type(device)) '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): def convert_filters(filters):
result = {} result = {}
for k, v in six.iteritems(filters): for k, v in iter(filters.items()):
if isinstance(v, bool): if isinstance(v, bool):
v = 'true' if v else 'false' v = 'true' if v else 'false'
if not isinstance(v, list): if not isinstance(v, list):
v = [v, ] v = [v, ]
result[k] = [ 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 for item in v
] ]
return json.dumps(result) return json.dumps(result)
@ -391,7 +384,7 @@ def datetime_to_timestamp(dt):
def parse_bytes(s): def parse_bytes(s):
if isinstance(s, six.integer_types + (float,)): if isinstance(s, (int, float,)):
return s return s
if len(s) == 0: if len(s) == 0:
return 0 return 0
@ -433,7 +426,7 @@ def parse_bytes(s):
def normalize_links(links): def normalize_links(links):
if isinstance(links, dict): 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)] 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): def split_command(command):
if six.PY2 and not isinstance(command, six.binary_type):
command = command.encode('utf-8')
return shlex.split(command) return shlex.split(command)
@ -477,22 +468,22 @@ def format_environment(environment):
def format_env(key, value): def format_env(key, value):
if value is None: if value is None:
return key return key
if isinstance(value, six.binary_type): if isinstance(value, bytes):
value = value.decode('utf-8') value = value.decode('utf-8')
return u'{key}={value}'.format(key=key, value=value) 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): def format_extra_hosts(extra_hosts, task=False):
# Use format dictated by Swarm API if container is part of a task # Use format dictated by Swarm API if container is part of a task
if task: if task:
return [ 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 [ 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()))
] ]

View File

@ -13,6 +13,5 @@ pyOpenSSL==18.0.0
pyparsing==2.2.0 pyparsing==2.2.0
pywin32==227; sys_platform == 'win32' pywin32==227; sys_platform == 'win32'
requests==2.20.0 requests==2.20.0
six==1.10.0
urllib3==1.24.3 urllib3==1.24.3
websocket-client==0.56.0 websocket-client==0.56.0

View File

@ -11,18 +11,11 @@ ROOT_DIR = os.path.dirname(__file__)
SOURCE_DIR = os.path.join(ROOT_DIR) SOURCE_DIR = os.path.join(ROOT_DIR)
requirements = [ requirements = [
'six >= 1.4.0',
'websocket-client >= 0.32.0', 'websocket-client >= 0.32.0',
'requests >= 2.14.2, != 2.18.0', 'requests >= 2.14.2, != 2.18.0',
] ]
extras_require = { 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) # win32 APIs if on Windows (required for npipe support)
':sys_platform == "win32"': 'pywin32==227', ':sys_platform == "win32"': 'pywin32==227',
@ -69,7 +62,7 @@ setup(
install_requires=requirements, install_requires=requirements,
tests_require=test_requirements, tests_require=test_requirements,
extras_require=extras_require, 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, zip_safe=False,
test_suite='tests', test_suite='tests',
classifiers=[ classifiers=[
@ -78,10 +71,7 @@ setup(
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.8',

View File

@ -1,4 +1,4 @@
setuptools==44.0.0 # last version with python 2.7 support setuptools==54.1.1
coverage==4.5.2 coverage==4.5.2
flake8==3.6.0 flake8==3.6.0
mock==1.0.1 mock==1.0.1

View File

@ -1,4 +1,4 @@
ARG PYTHON_VERSION=2.7 ARG PYTHON_VERSION=3.6
FROM python:${PYTHON_VERSION} FROM python:${PYTHON_VERSION}
RUN mkdir /tmp/certs RUN mkdir /tmp/certs

View File

@ -7,7 +7,6 @@ from datetime import datetime
import pytest import pytest
import requests import requests
import six
import docker import docker
from .. import helpers from .. import helpers
@ -35,7 +34,7 @@ class ListContainersTest(BaseAPIIntegrationTest):
assert len(retrieved) == 1 assert len(retrieved) == 1
retrieved = retrieved[0] retrieved = retrieved[0]
assert 'Command' in retrieved assert 'Command' in retrieved
assert retrieved['Command'] == six.text_type('true') assert retrieved['Command'] == str('true')
assert 'Image' in retrieved assert 'Image' in retrieved
assert re.search(r'alpine:.*', retrieved['Image']) assert re.search(r'alpine:.*', retrieved['Image'])
assert 'Status' in retrieved assert 'Status' in retrieved
@ -104,9 +103,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(container3_id) self.client.start(container3_id)
assert self.client.wait(container3_id)['StatusCode'] == 0 assert self.client.wait(container3_id)['StatusCode'] == 0
logs = self.client.logs(container3_id) logs = self.client.logs(container3_id).decode('utf-8')
if six.PY3:
logs = logs.decode('utf-8')
assert '{0}_NAME='.format(link_env_prefix1) in logs assert '{0}_NAME='.format(link_env_prefix1) in logs
assert '{0}_ENV_FOO=1'.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 assert '{0}_NAME='.format(link_env_prefix2) in logs
@ -227,9 +224,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(container) self.client.start(container)
self.client.wait(container) self.client.wait(container)
logs = self.client.logs(container) logs = self.client.logs(container).decode('utf-8')
if six.PY3:
logs = logs.decode('utf-8')
groups = logs.strip().split(' ') groups = logs.strip().split(' ')
assert '1000' in groups assert '1000' in groups
assert '1001' in groups assert '1001' in groups
@ -244,9 +239,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(container) self.client.start(container)
self.client.wait(container) self.client.wait(container)
logs = self.client.logs(container) logs = self.client.logs(container).decode('utf-8')
if six.PY3:
logs = logs.decode('utf-8')
groups = logs.strip().split(' ') groups = logs.strip().split(' ')
assert '1000' in groups assert '1000' in groups
@ -515,10 +508,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
TEST_IMG, TEST_IMG,
['ls', self.mount_dest], ['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 assert self.filename in logs
inspect_data = self.client.inspect_container(container) inspect_data = self.client.inspect_container(container)
self.check_container_data(inspect_data, True) self.check_container_data(inspect_data, True)
@ -534,10 +524,8 @@ class VolumeBindTest(BaseAPIIntegrationTest):
TEST_IMG, TEST_IMG,
['ls', self.mount_dest], ['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 assert self.filename in logs
inspect_data = self.client.inspect_container(container) inspect_data = self.client.inspect_container(container)
@ -554,9 +542,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
host_config=host_config host_config=host_config
) )
assert container assert container
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 assert self.filename in logs
inspect_data = self.client.inspect_container(container) inspect_data = self.client.inspect_container(container)
self.check_container_data(inspect_data, True) self.check_container_data(inspect_data, True)
@ -573,9 +559,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
host_config=host_config host_config=host_config
) )
assert container assert container
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 assert self.filename in logs
inspect_data = self.client.inspect_container(container) inspect_data = self.client.inspect_container(container)
self.check_container_data(inspect_data, False) self.check_container_data(inspect_data, False)
@ -645,9 +629,8 @@ class ArchiveTest(BaseAPIIntegrationTest):
for d in strm: for d in strm:
destination.write(d) destination.write(d)
destination.seek(0) destination.seek(0)
retrieved_data = helpers.untar_file(destination, 'data.txt') retrieved_data = helpers.untar_file(destination, 'data.txt')\
if six.PY3: .decode('utf-8')
retrieved_data = retrieved_data.decode('utf-8')
assert data == retrieved_data.strip() assert data == retrieved_data.strip()
def test_get_file_stat_from_container(self): def test_get_file_stat_from_container(self):
@ -683,9 +666,6 @@ class ArchiveTest(BaseAPIIntegrationTest):
self.client.start(ctnr) self.client.start(ctnr)
self.client.wait(ctnr) self.client.wait(ctnr)
logs = self.client.logs(ctnr) logs = self.client.logs(ctnr)
if six.PY3:
logs = logs.decode('utf-8')
data = data.decode('utf-8')
assert logs.strip() == data assert logs.strip() == data
def test_copy_directory_to_container(self): def test_copy_directory_to_container(self):
@ -700,9 +680,7 @@ class ArchiveTest(BaseAPIIntegrationTest):
self.client.put_archive(ctnr, '/vol1', test_tar) self.client.put_archive(ctnr, '/vol1', test_tar)
self.client.start(ctnr) self.client.start(ctnr)
self.client.wait(ctnr) self.client.wait(ctnr)
logs = self.client.logs(ctnr) logs = self.client.logs(ctnr).decode('utf-8')
if six.PY3:
logs = logs.decode('utf-8')
results = logs.strip().split() results = logs.strip().split()
assert 'a.py' in results assert 'a.py' in results
assert 'b.py' in results assert 'b.py' in results
@ -861,7 +839,7 @@ Line2'''
id = container['Id'] id = container['Id']
self.tmp_containers.append(id) self.tmp_containers.append(id)
self.client.start(id) self.client.start(id)
logs = six.binary_type() logs = b''
for chunk in self.client.logs(id, stream=True, follow=True): for chunk in self.client.logs(id, stream=True, follow=True):
logs += chunk logs += chunk
@ -881,7 +859,7 @@ Line2'''
id = container['Id'] id = container['Id']
self.tmp_containers.append(id) self.tmp_containers.append(id)
self.client.start(id) self.client.start(id)
logs = six.binary_type() logs = b''
generator = self.client.logs(id, stream=True, follow=True) generator = self.client.logs(id, stream=True, follow=True)
threading.Timer(1, generator.close).start() threading.Timer(1, generator.close).start()

View File

@ -7,9 +7,8 @@ import tempfile
import threading import threading
import pytest import pytest
import six from http.server import SimpleHTTPRequestHandler
from six.moves import BaseHTTPServer import socketserver
from six.moves import socketserver
import docker import docker
@ -33,7 +32,7 @@ class ListImagesTest(BaseAPIIntegrationTest):
def test_images_quiet(self): def test_images_quiet(self):
res1 = self.client.images(quiet=True) res1 = self.client.images(quiet=True)
assert type(res1[0]) == six.text_type assert type(res1[0]) == str
class PullImageTest(BaseAPIIntegrationTest): class PullImageTest(BaseAPIIntegrationTest):
@ -44,7 +43,7 @@ class PullImageTest(BaseAPIIntegrationTest):
pass pass
res = self.client.pull('hello-world') res = self.client.pull('hello-world')
self.tmp_imgs.append('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 assert len(self.client.images('hello-world')) >= 1
img_info = self.client.inspect_image('hello-world') img_info = self.client.inspect_image('hello-world')
assert 'Id' in img_info assert 'Id' in img_info
@ -273,7 +272,7 @@ class ImportImageTest(BaseAPIIntegrationTest):
def temporary_http_file_server(self, stream): def temporary_http_file_server(self, stream):
'''Serve data from an IO stream over HTTP.''' '''Serve data from an IO stream over HTTP.'''
class Handler(BaseHTTPServer.BaseHTTPRequestHandler): class Handler(SimpleHTTPRequestHandler):
def do_GET(self): def do_GET(self):
self.send_response(200) self.send_response(200)
self.send_header('Content-Type', 'application/x-tar') self.send_header('Content-Type', 'application/x-tar')

View File

@ -5,7 +5,6 @@ import time
import docker import docker
import pytest import pytest
import six
from ..helpers import ( from ..helpers import (
force_leave_swarm, requires_api_version, requires_experimental force_leave_swarm, requires_api_version, requires_experimental
@ -150,7 +149,7 @@ class ServiceTest(BaseAPIIntegrationTest):
else: else:
break break
if six.PY3: if log_line is not None:
log_line = log_line.decode('utf-8') log_line = log_line.decode('utf-8')
assert 'hello\n' in log_line assert 'hello\n' in log_line

View File

@ -2,31 +2,38 @@ import unittest
import docker import docker
from docker.transport.sshconn import SSHSocket from docker.transport.sshconn import SSHSocket
class SSHAdapterTest(unittest.TestCase): class SSHAdapterTest(unittest.TestCase):
def test_ssh_hostname_prefix_trim(self): @staticmethod
conn = docker.transport.SSHHTTPAdapter(base_url="ssh://user@hostname:1234", shell_out=True) 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" 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") c = SSHSocket(host="user@hostname:1234")
assert c.host == "hostname" assert c.host == "hostname"
assert c.port == "1234" assert c.port == "1234"
assert c.user == "user" assert c.user == "user"
def test_ssh_parse_hostname_only(self): @staticmethod
def test_ssh_parse_hostname_only():
c = SSHSocket(host="hostname") c = SSHSocket(host="hostname")
assert c.host == "hostname" assert c.host == "hostname"
assert c.port == None assert c.port is None
assert c.user == 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") c = SSHSocket(host="user@hostname")
assert c.host == "hostname" assert c.host == "hostname"
assert c.port == None assert c.port is None
assert c.user == "user" 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") c = SSHSocket(host="hostname:22")
assert c.host == "hostname" assert c.host == "hostname"
assert c.port == "22" assert c.port == "22"
assert c.user == None assert c.user is None

View File

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py27, py35, py36, py37, flake8 envlist = py36, py37, flake8
skipsdist=True skipsdist=True
[testenv] [testenv]