Merge pull request #2788 from docker/set-minimal-python-to-3_6

Make python 3.6 the minimum version
This commit is contained in:
Anca Iordache 2021-03-25 09:59:41 +01:00 committed by GitHub
commit 30d482d359
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 88 additions and 182 deletions

View File

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

View File

@ -4,7 +4,7 @@ sphinx:
configuration: docs/conf.py
python:
version: 3.5
version: 3.6
install:
- requirements: docs-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}
# Add SSH keys and set permissions
COPY tests/ssh-keys /root/.ssh
RUN chmod -R 600 /root/.ssh
RUN mkdir /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
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')`")
}
{ ->

View File

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

View File

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

View File

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

View File

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

View File

@ -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()))
]

View File

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

View File

@ -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',

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
flake8==3.6.0
mock==1.0.1

View File

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

View File

@ -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()

View File

@ -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')

View File

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

View File

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

View File

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