summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralexrecuenco <alejandrogonzalezrecuenco@gmail.com>2020-02-24 13:24:57 +0100
committerUlysses Souza <ulyssessouza@gmail.com>2020-08-21 18:32:29 +0200
commit1285960d3c7a04b501af31b027c343b0281d193e (patch)
tree9fbafb69c7f22d30b13f50959199f218cc7f7666
parent53965e65b701997915455b5c01fc59a9fca2c0ce (diff)
Removed Python2 support
Closes: #6890 Some remarks, - `# coding ... utf-8` statements are not needed - isdigit on strings instead of a try-catch. - Default opening mode is read, so we can do `open()` without the `'r'` everywhere - Removed inheritinng from `object` class, it isn't necessary in python3. - `super(ClassName, self)` can now be replaced with `super()` - Use of itertools and `chain` on a couple places dealing with sets. - Used the operator module instead of lambdas when warranted `itemgetter(0)` instead of `lambda x: x[0]` `attrgetter('name')` instead of `lambda x: x.name` - `sorted` returns a list, so no need to use `list(sorted(...))` - Removed `dict()` using dictionary comprehensions whenever possible - Attempted to remove python3.2 support Signed-off-by: alexrecuenco <alejandrogonzalezrecuenco@gmail.com>
-rw-r--r--.pre-commit-config.yaml6
-rw-r--r--compose/__init__.py1
-rw-r--r--compose/cli/colors.py8
-rw-r--r--compose/cli/command.py13
-rw-r--r--compose/cli/docopt_command.py4
-rw-r--r--compose/cli/errors.py4
-rw-r--r--compose/cli/formatter.py17
-rw-r--r--compose/cli/log_printer.py11
-rw-r--r--compose/cli/main.py13
-rw-r--r--compose/cli/utils.py13
-rw-r--r--compose/cli/verbose_proxy.py8
-rw-r--r--compose/config/config.py51
-rw-r--r--compose/config/environment.py16
-rw-r--r--compose/config/errors.py6
-rw-r--r--compose/config/interpolation.py26
-rw-r--r--compose/config/serialize.py2
-rw-r--r--compose/config/sort_services.py2
-rw-r--r--compose/config/types.py25
-rw-r--r--compose/config/validation.py8
-rw-r--r--compose/container.py14
-rw-r--r--compose/errors.py6
-rw-r--r--compose/network.py21
-rw-r--r--compose/parallel.py8
-rw-r--r--compose/progress_stream.py10
-rw-r--r--compose/project.py34
-rw-r--r--compose/service.py72
-rw-r--r--compose/timeparse.py19
-rw-r--r--compose/utils.py6
-rw-r--r--compose/volume.py21
-rwxr-xr-xcontrib/migration/migrate-compose-file-v1-to-v2.py2
-rw-r--r--docker-compose_darwin.spec2
-rw-r--r--requirements.txt2
-rw-r--r--script/release/utils.py4
-rw-r--r--setup.py4
-rw-r--r--tests/acceptance/cli_test.py23
-rw-r--r--tests/acceptance/context_test.py1
-rw-r--r--tests/helpers.py2
-rw-r--r--tests/integration/environment_test.py4
-rw-r--r--tests/integration/project_test.py60
-rw-r--r--tests/integration/resilience_test.py2
-rw-r--r--tests/integration/service_test.py28
-rw-r--r--tests/integration/state_test.py46
-rw-r--r--tests/integration/volume_test.py2
-rw-r--r--tests/unit/cli/command_test.py3
-rw-r--r--tests/unit/cli/docker_client_test.py16
-rw-r--r--tests/unit/cli/errors_test.py6
-rw-r--r--tests/unit/cli/formatter_test.py4
-rw-r--r--tests/unit/cli/log_printer_test.py10
-rw-r--r--tests/unit/cli/main_test.py10
-rw-r--r--tests/unit/cli_test.py1
-rw-r--r--tests/unit/config/config_test.py13
-rw-r--r--tests/unit/config/environment_test.py1
-rw-r--r--tests/unit/config/interpolation_test.py3
-rw-r--r--tests/unit/config/sort_services_test.py2
-rw-r--r--tests/unit/config/types_test.py6
-rw-r--r--tests/unit/progress_stream_test.py4
-rw-r--r--tests/unit/project_test.py3
-rw-r--r--tests/unit/service_test.py6
-rw-r--r--tests/unit/split_buffer_test.py2
-rw-r--r--tests/unit/utils_test.py13
-rw-r--r--tests/unit/volume_test.py2
61 files changed, 350 insertions, 382 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index a2aeb014..05cd5202 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -20,3 +20,9 @@
language_version: 'python3.7'
args:
- --py3-plus
+- repo: https://github.com/asottile/pyupgrade
+ rev: v2.1.0
+ hooks:
+ - id: pyupgrade
+ args:
+ - --py3-plus
diff --git a/compose/__init__.py b/compose/__init__.py
index 00afb07c..76e27d25 100644
--- a/compose/__init__.py
+++ b/compose/__init__.py
@@ -1,2 +1 @@
-
__version__ = '1.27.0dev'
diff --git a/compose/cli/colors.py b/compose/cli/colors.py
index c6a869bf..a4983a9f 100644
--- a/compose/cli/colors.py
+++ b/compose/cli/colors.py
@@ -14,16 +14,16 @@ NAMES = [
def get_pairs():
for i, name in enumerate(NAMES):
- yield(name, str(30 + i))
- yield('intense_' + name, str(30 + i) + ';1')
+ yield (name, str(30 + i))
+ yield ('intense_' + name, str(30 + i) + ';1')
def ansi(code):
- return '\033[{0}m'.format(code)
+ return '\033[{}m'.format(code)
def ansi_color(code, s):
- return '{0}{1}{2}'.format(ansi(code), s, ansi(0))
+ return '{}{}{}'.format(ansi(code), s, ansi(0))
def make_color_fn(code):
diff --git a/compose/cli/command.py b/compose/cli/command.py
index e907a05c..8882727b 100644
--- a/compose/cli/command.py
+++ b/compose/cli/command.py
@@ -147,15 +147,17 @@ def get_project(project_dir, config_path=None, project_name=None, verbose=False,
def execution_context_labels(config_details, environment_file):
extra_labels = [
- '{0}={1}'.format(LABEL_WORKING_DIR, os.path.abspath(config_details.working_dir))
+ '{}={}'.format(LABEL_WORKING_DIR, os.path.abspath(config_details.working_dir))
]
if not use_config_from_stdin(config_details):
- extra_labels.append('{0}={1}'.format(LABEL_CONFIG_FILES, config_files_label(config_details)))
+ extra_labels.append('{}={}'.format(LABEL_CONFIG_FILES, config_files_label(config_details)))
if environment_file is not None:
- extra_labels.append('{0}={1}'.format(LABEL_ENVIRONMENT_FILE,
- os.path.normpath(environment_file)))
+ extra_labels.append('{}={}'.format(
+ LABEL_ENVIRONMENT_FILE,
+ os.path.normpath(environment_file))
+ )
return extra_labels
@@ -168,7 +170,8 @@ def use_config_from_stdin(config_details):
def config_files_label(config_details):
return ",".join(
- map(str, (os.path.normpath(c.filename) for c in config_details.config_files)))
+ os.path.normpath(c.filename) for c in config_details.config_files
+ )
def get_project_name(working_dir, project_name=None, environment=None):
diff --git a/compose/cli/docopt_command.py b/compose/cli/docopt_command.py
index 856c9234..d0ba7f67 100644
--- a/compose/cli/docopt_command.py
+++ b/compose/cli/docopt_command.py
@@ -11,7 +11,7 @@ def docopt_full_help(docstring, *args, **kwargs):
raise SystemExit(docstring)
-class DocoptDispatcher(object):
+class DocoptDispatcher:
def __init__(self, command_class, options):
self.command_class = command_class
@@ -50,7 +50,7 @@ def get_handler(command_class, command):
class NoSuchCommand(Exception):
def __init__(self, command, supercommand):
- super(NoSuchCommand, self).__init__("No such command: %s" % command)
+ super().__init__("No such command: %s" % command)
self.command = command
self.supercommand = supercommand
diff --git a/compose/cli/errors.py b/compose/cli/errors.py
index d1a47f07..a807c7d1 100644
--- a/compose/cli/errors.py
+++ b/compose/cli/errors.py
@@ -26,11 +26,9 @@ class UserError(Exception):
def __init__(self, msg):
self.msg = dedent(msg).strip()
- def __unicode__(self):
+ def __str__(self):
return self.msg
- __str__ = __unicode__
-
class ConnectionError(Exception):
pass
diff --git a/compose/cli/formatter.py b/compose/cli/formatter.py
index a59f0742..ff81ee65 100644
--- a/compose/cli/formatter.py
+++ b/compose/cli/formatter.py
@@ -1,15 +1,10 @@
import logging
-import shutil
+from shutil import get_terminal_size
import texttable
from compose.cli import colors
-if hasattr(shutil, "get_terminal_size"):
- from shutil import get_terminal_size
-else:
- from backports.shutil_get_terminal_size import get_terminal_size
-
def get_tty_width():
try:
@@ -45,15 +40,15 @@ class ConsoleWarningFormatter(logging.Formatter):
def get_level_message(self, record):
separator = ': '
- if record.levelno == logging.WARNING:
- return colors.yellow(record.levelname) + separator
- if record.levelno == logging.ERROR:
+ if record.levelno >= logging.ERROR:
return colors.red(record.levelname) + separator
+ if record.levelno >= logging.WARNING:
+ return colors.yellow(record.levelname) + separator
return ''
def format(self, record):
if isinstance(record.msg, bytes):
record.msg = record.msg.decode('utf-8')
- message = super(ConsoleWarningFormatter, self).format(record)
- return '{0}{1}'.format(self.get_level_message(record), message)
+ message = super().format(record)
+ return '{}{}'.format(self.get_level_message(record), message)
diff --git a/compose/cli/log_printer.py b/compose/cli/log_printer.py
index 100f3a82..cd9f73c2 100644
--- a/compose/cli/log_printer.py
+++ b/compose/cli/log_printer.py
@@ -2,6 +2,7 @@ import _thread as thread
import sys
from collections import namedtuple
from itertools import cycle
+from operator import attrgetter
from queue import Empty
from queue import Queue
from threading import Thread
@@ -13,7 +14,7 @@ from compose.cli.signals import ShutdownException
from compose.utils import split_buffer
-class LogPresenter(object):
+class LogPresenter:
def __init__(self, prefix_width, color_func):
self.prefix_width = prefix_width
@@ -50,7 +51,7 @@ def max_name_width(service_names, max_index_width=3):
return max(len(name) for name in service_names) + max_index_width
-class LogPrinter(object):
+class LogPrinter:
"""Print logs from many containers to a single output stream."""
def __init__(self,
@@ -133,7 +134,7 @@ def build_thread_map(initial_containers, presenters, thread_args):
# Container order is unspecified, so they are sorted by name in order to make
# container:presenter (log color) assignment deterministic when given a list of containers
# with the same names.
- for container in sorted(initial_containers, key=lambda c: c.name)
+ for container in sorted(initial_containers, key=attrgetter('name'))
}
@@ -194,9 +195,9 @@ def build_log_generator(container, log_args):
def wait_on_exit(container):
try:
exit_code = container.wait()
- return "%s exited with code %s\n" % (container.name, exit_code)
+ return "{} exited with code {}\n".format(container.name, exit_code)
except APIError as e:
- return "Unexpected API error for %s (HTTP code %s)\nResponse body:\n%s\n" % (
+ return "Unexpected API error for {} (HTTP code {})\nResponse body:\n{}\n".format(
container.name, e.response.status_code,
e.response.text or '[empty]'
)
diff --git a/compose/cli/main.py b/compose/cli/main.py
index 1de8a774..8809318f 100644
--- a/compose/cli/main.py
+++ b/compose/cli/main.py
@@ -73,7 +73,7 @@ def main():
log.error(e.msg)
sys.exit(1)
except BuildError as e:
- log.error("Service '%s' failed to build: %s" % (e.service.name, e.reason))
+ log.error("Service '{}' failed to build: {}".format(e.service.name, e.reason))
sys.exit(1)
except StreamOutputError as e:
log.error(e)
@@ -175,7 +175,7 @@ def parse_doc_section(name, source):
return [s.strip() for s in pattern.findall(source)]
-class TopLevelCommand(object):
+class TopLevelCommand:
"""Define and run multi-container applications with Docker.
Usage:
@@ -546,7 +546,7 @@ class TopLevelCommand(object):
key=attrgetter('name'))
if options['--quiet']:
- for image in set(c.image for c in containers):
+ for image in {c.image for c in containers}:
print(image.split(':')[1])
return
@@ -1130,7 +1130,7 @@ def compute_service_exit_code(exit_value_from, attached_containers):
attached_containers))
if not candidates:
log.error(
- 'No containers matching the spec "{0}" '
+ 'No containers matching the spec "{}" '
'were run.'.format(exit_value_from)
)
return 2
@@ -1453,10 +1453,7 @@ def call_docker(args, dockeropts, environment):
args = [executable_path] + tls_options + args
log.debug(" ".join(map(pipes.quote, args)))
- filtered_env = {}
- for k, v in environment.items():
- if v is not None:
- filtered_env[k] = environment[k]
+ filtered_env = {k: v for k, v in environment.items() if v is not None}
return subprocess.call(args, env=filtered_env)
diff --git a/compose/cli/utils.py b/compose/cli/utils.py
index b91ab6a1..6a4615a9 100644
--- a/compose/cli/utils.py
+++ b/compose/cli/utils.py
@@ -11,13 +11,6 @@ import docker
import compose
from ..const import IS_WINDOWS_PLATFORM
-# WindowsError is not defined on non-win32 platforms. Avoid runtime errors by
-# defining it as OSError (its parent class) if missing.
-try:
- WindowsError
-except NameError:
- WindowsError = OSError
-
def yesno(prompt, default=None):
"""
@@ -58,7 +51,7 @@ def call_silently(*args, **kwargs):
with open(os.devnull, 'w') as shutup:
try:
return subprocess.call(*args, stdout=shutup, stderr=shutup, **kwargs)
- except WindowsError:
+ except OSError:
# On Windows, subprocess.call() can still raise exceptions. Normalize
# to POSIXy behaviour by returning a nonzero exit code.
return 1
@@ -120,7 +113,7 @@ def generate_user_agent():
try:
p_system = platform.system()
p_release = platform.release()
- except IOError:
+ except OSError:
pass
else:
parts.append("{}/{}".format(p_system, p_release))
@@ -133,7 +126,7 @@ def human_readable_file_size(size):
if order >= len(suffixes):
order = len(suffixes) - 1
- return '{0:.4g} {1}'.format(
+ return '{:.4g} {}'.format(
size / pow(10, order * 3),
suffixes[order]
)
diff --git a/compose/cli/verbose_proxy.py b/compose/cli/verbose_proxy.py
index 1d2f28b5..c9340c4e 100644
--- a/compose/cli/verbose_proxy.py
+++ b/compose/cli/verbose_proxy.py
@@ -6,13 +6,13 @@ from itertools import chain
def format_call(args, kwargs):
args = (repr(a) for a in args)
- kwargs = ("{0!s}={1!r}".format(*item) for item in kwargs.items())
- return "({0})".format(", ".join(chain(args, kwargs)))
+ kwargs = ("{!s}={!r}".format(*item) for item in kwargs.items())
+ return "({})".format(", ".join(chain(args, kwargs)))
def format_return(result, max_lines):
if isinstance(result, (list, tuple, set)):
- return "({0} with {1} items)".format(type(result).__name__, len(result))
+ return "({} with {} items)".format(type(result).__name__, len(result))
if result:
lines = pprint.pformat(result).split('\n')
@@ -22,7 +22,7 @@ def format_return(result, max_lines):
return result
-class VerboseProxy(object):
+class VerboseProxy:
"""Proxy all function calls to another class and log method name, arguments
and return values for each call.
"""
diff --git a/compose/config/config.py b/compose/config/config.py
index c7cc7240..8f579021 100644
--- a/compose/config/config.py
+++ b/compose/config/config.py
@@ -1,12 +1,13 @@
import functools
-import io
import logging
import os
import re
import string
import sys
from collections import namedtuple
+from itertools import chain
from operator import attrgetter
+from operator import itemgetter
import yaml
from cached_property import cached_property
@@ -166,7 +167,7 @@ class ConfigDetails(namedtuple('_ConfigDetails', 'working_dir config_files envir
def __new__(cls, working_dir, config_files, environment=None):
if environment is None:
environment = Environment.from_env_file(working_dir)
- return super(ConfigDetails, cls).__new__(
+ return super().__new__(
cls, working_dir, config_files, environment
)
@@ -315,8 +316,8 @@ def validate_config_version(config_files):
if main_file.version != next_file.version:
raise ConfigurationError(
- "Version mismatch: file {0} specifies version {1} but "
- "extension file {2} uses version {3}".format(
+ "Version mismatch: file {} specifies version {} but "
+ "extension file {} uses version {}".format(
main_file.filename,
main_file.version,
next_file.filename,
@@ -595,7 +596,7 @@ def process_config_file(config_file, environment, service_name=None, interpolate
return config_file
-class ServiceExtendsResolver(object):
+class ServiceExtendsResolver:
def __init__(self, service_config, config_file, environment, already_seen=None):
self.service_config = service_config
self.working_dir = service_config.working_dir
@@ -703,7 +704,7 @@ def resolve_build_args(buildargs, environment):
def validate_extended_service_dict(service_dict, filename, service):
- error_prefix = "Cannot extend service '%s' in %s:" % (service, filename)
+ error_prefix = "Cannot extend service '{}' in {}:".format(service, filename)
if 'links' in service_dict:
raise ConfigurationError(
@@ -826,9 +827,9 @@ def process_ports(service_dict):
def process_depends_on(service_dict):
if 'depends_on' in service_dict and not isinstance(service_dict['depends_on'], dict):
- service_dict['depends_on'] = dict([
- (svc, {'condition': 'service_started'}) for svc in service_dict['depends_on']
- ])
+ service_dict['depends_on'] = {
+ svc: {'condition': 'service_started'} for svc in service_dict['depends_on']
+ }
return service_dict
@@ -1071,9 +1072,9 @@ def merge_service_dicts(base, override, version):
def merge_unique_items_lists(base, override):
- override = [str(o) for o in override]
- base = [str(b) for b in base]
- return sorted(set().union(base, override))
+ override = (str(o) for o in override)
+ base = (str(b) for b in base)
+ return sorted(set(chain(base, override)))
def merge_healthchecks(base, override):
@@ -1086,9 +1087,7 @@ def merge_healthchecks(base, override):
def merge_ports(md, base, override):
def parse_sequence_func(seq):
- acc = []
- for item in seq:
- acc.extend(ServicePort.parse(item))
+ acc = [s for item in seq for s in ServicePort.parse(item)]
return to_mapping(acc, 'merge_field')
field = 'ports'
@@ -1098,7 +1097,7 @@ def merge_ports(md, base, override):
merged = parse_sequence_func(md.base.get(field, []))
merged.update(parse_sequence_func(md.override.get(field, [])))
- md[field] = [item for item in sorted(merged.values(), key=lambda x: x.target)]
+ md[field] = [item for item in sorted(merged.values(), key=attrgetter("target"))]
def merge_build(output, base, override):
@@ -1170,8 +1169,8 @@ def merge_reservations(base, override):
def merge_unique_objects_lists(base, override):
- result = dict((json_hash(i), i) for i in base + override)
- return [i[1] for i in sorted([(k, v) for k, v in result.items()], key=lambda x: x[0])]
+ result = {json_hash(i): i for i in base + override}
+ return [i[1] for i in sorted(((k, v) for k, v in result.items()), key=itemgetter(0))]
def merge_blkio_config(base, override):
@@ -1179,11 +1178,11 @@ def merge_blkio_config(base, override):
md.merge_scalar('weight')
def merge_blkio_limits(base, override):
- index = dict((b['path'], b) for b in base)
- for o in override:
- index[o['path']] = o
+ get_path = itemgetter('path')
+ index = {get_path(b): b for b in base}
+ index.update((get_path(o), o) for o in override)
- return sorted(list(index.values()), key=lambda x: x['path'])
+ return sorted(index.values(), key=get_path)
for field in [
"device_read_bps", "device_read_iops", "device_write_bps",
@@ -1304,7 +1303,7 @@ def resolve_volume_path(working_dir, volume):
if host_path.startswith('.'):
host_path = expand_path(working_dir, host_path)
host_path = os.path.expanduser(host_path)
- return u"{}:{}{}".format(host_path, container_path, (':' + mode if mode else ''))
+ return "{}:{}{}".format(host_path, container_path, (':' + mode if mode else ''))
return container_path
@@ -1447,13 +1446,13 @@ def has_uppercase(name):
def load_yaml(filename, encoding=None, binary=True):
try:
- with io.open(filename, 'rb' if binary else 'r', encoding=encoding) as fh:
+ with open(filename, 'rb' if binary else 'r', encoding=encoding) as fh:
return yaml.safe_load(fh)
- except (IOError, yaml.YAMLError, UnicodeDecodeError) as e:
+ except (OSError, yaml.YAMLError, UnicodeDecodeError) as e:
if encoding is None:
# Sometimes the user's locale sets an encoding that doesn't match
# the YAML files. Im such cases, retry once with the "default"
# UTF-8 encoding
return load_yaml(filename, encoding='utf-8-sig', binary=False)
error_name = getattr(e, '__module__', '') + '.' + e.__class__.__name__
- raise ConfigurationError(u"{}: {}".format(error_name, e))
+ raise ConfigurationError("{}: {}".format(error_name, e))
diff --git a/compose/config/environment.py b/compose/config/environment.py
index 4526d0b3..1780851f 100644
--- a/compose/config/environment.py
+++ b/compose/config/environment.py
@@ -43,7 +43,7 @@ def env_vars_from_file(filename, interpolate=True):
class Environment(dict):
def __init__(self, *args, **kwargs):
- super(Environment, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self.missing_keys = []
self.silent = False
@@ -81,11 +81,11 @@ class Environment(dict):
def __getitem__(self, key):
try:
- return super(Environment, self).__getitem__(key)
+ return super().__getitem__(key)
except KeyError:
if IS_WINDOWS_PLATFORM:
try:
- return super(Environment, self).__getitem__(key.upper())
+ return super().__getitem__(key.upper())
except KeyError:
pass
if not self.silent and key not in self.missing_keys:
@@ -98,20 +98,20 @@ class Environment(dict):
return ""
def __contains__(self, key):
- result = super(Environment, self).__contains__(key)
+ result = super().__contains__(key)
if IS_WINDOWS_PLATFORM:
return (
- result or super(Environment, self).__contains__(key.upper())
+ result or super().__contains__(key.upper())
)
return result
def get(self, key, *args, **kwargs):
if IS_WINDOWS_PLATFORM:
- return super(Environment, self).get(
+ return super().get(
key,
- super(Environment, self).get(key.upper(), *args, **kwargs)
+ super().get(key.upper(), *args, **kwargs)
)
- return super(Environment, self).get(key, *args, **kwargs)
+ return super().get(key, *args, **kwargs)
def get_boolean(self, key):
# Convert a value to a boolean using "common sense" rules.
diff --git a/compose/config/errors.py b/compose/config/errors.py
index 7db079e9..b66433a7 100644
--- a/compose/config/errors.py
+++ b/compose/config/errors.py
@@ -1,5 +1,3 @@
-
-
VERSION_EXPLANATION = (
'You might be seeing this error because you\'re using the wrong Compose file version. '
'Either specify a supported version (e.g "2.2" or "3.3") and place '
@@ -40,7 +38,7 @@ class CircularReference(ConfigurationError):
class ComposeFileNotFound(ConfigurationError):
def __init__(self, supported_filenames):
- super(ComposeFileNotFound, self).__init__("""
+ super().__init__("""
Can't find a suitable configuration file in this directory or any
parent. Are you in the right directory?
@@ -51,7 +49,7 @@ class ComposeFileNotFound(ConfigurationError):
class DuplicateOverrideFileFound(ConfigurationError):
def __init__(self, override_filenames):
self.override_filenames = override_filenames
- super(DuplicateOverrideFileFound, self).__init__(
+ super().__init__(
"Multiple override files found: {}. You may only use a single "
"override file.".format(", ".join(override_filenames))
)
diff --git a/compose/config/interpolation.py b/compose/config/interpolation.py
index bfa6a56c..71e78bba 100644
--- a/compose/config/interpolation.py
+++ b/compose/config/interpolation.py
@@ -11,7 +11,7 @@ from compose.utils import parse_nanoseconds_int
log = logging.getLogger(__name__)
-class Interpolator(object):
+class Interpolator:
def __init__(self, templater, mapping):
self.templater = templater
@@ -31,15 +31,15 @@ def interpolate_environment_variables(version, config, section, environment):
interpolator = Interpolator(TemplateWithDefaults, environment)
def process_item(name, config_dict):
- return dict(
- (key, interpolate_value(name, key, val, section, interpolator))
+ return {
+ key: interpolate_value(name, key, val, section, interpolator)
for key, val in (config_dict or {}).items()
- )
+ }
- return dict(
- (name, process_item(name, config_dict or {}))
+ return {
+ name: process_item(name, config_dict or {})
for name, config_dict in config.items()
- )
+ }
def get_config_path(config_key, section, name):
@@ -75,10 +75,10 @@ def recursive_interpolate(obj, interpolator, config_path):
if isinstance(obj, str):
return converter.convert(config_path, interpolator.interpolate(obj))
if isinstance(obj, dict):
- return dict(
- (key, recursive_interpolate(val, interpolator, append(config_path, key)))
- for (key, val) in obj.items()
- )
+ return {
+ key: recursive_interpolate(val, interpolator, append(config_path, key))
+ for key, val in obj.items()
+ }
if isinstance(obj, list):
return [recursive_interpolate(val, interpolator, config_path) for val in obj]
return converter.convert(config_path, obj)
@@ -135,7 +135,7 @@ class TemplateWithDefaults(Template):
val = mapping[named]
if isinstance(val, bytes):
val = val.decode('utf-8')
- return '%s' % (val,)
+ return '{}'.format(val)
if mo.group('escaped') is not None:
return self.delimiter
if mo.group('invalid') is not None:
@@ -224,7 +224,7 @@ def to_microseconds(v):
return int(parse_nanoseconds_int(v) / 1000)
-class ConversionMap(object):
+class ConversionMap:
map = {
service_path('blkio_config', 'weight'): to_int,
service_path('blkio_config', 'weight_device', 'weight'): to_int,
diff --git a/compose/config/serialize.py b/compose/config/serialize.py
index e41e1ba4..2dd2c47f 100644
--- a/compose/config/serialize.py
+++ b/compose/config/serialize.py
@@ -104,7 +104,7 @@ def serialize_ns_time_value(value):
result = (int(value), stage[1])
else:
break
- return '{0}{1}'.format(*result)
+ return '{}{}'.format(*result)
def denormalize_service_dict(service_dict, version, image_digest=None):
diff --git a/compose/config/sort_services.py b/compose/config/sort_services.py
index 65953891..0a7eb2b4 100644
--- a/compose/config/sort_services.py
+++ b/compose/config/sort_services.py
@@ -21,7 +21,7 @@ def get_source_name_from_network_mode(network_mode, source_type):
def get_service_names(links):
- return [link.split(':')[0] for link in links]
+ return [link.split(':', 1)[0] for link in links]
def get_service_names_from_volumes_from(volumes_from):
diff --git a/compose/config/types.py b/compose/config/types.py
index 0c654fa6..f52b5654 100644
--- a/compose/config/types.py
+++ b/compose/config/types.py
@@ -146,7 +146,7 @@ def normpath(path, win_host=False):
return path
-class MountSpec(object):
+class MountSpec:
options_map = {
'volume': {
'nocopy': 'no_copy'
@@ -338,9 +338,9 @@ class ServiceConfigBase(namedtuple('_ServiceConfigBase', 'source target uid gid
return self.source
def repr(self):
- return dict(
- [(k, v) for k, v in zip(self._fields, self) if v is not None]
- )
+ return {
+ k: v for k, v in zip(self._fields, self) if v is not None
+ }
class ServiceSecret(ServiceConfigBase):
@@ -362,10 +362,7 @@ class ServicePort(namedtuple('_ServicePort', 'target published protocol mode ext
if published:
if isinstance(published, str) and '-' in published: # "x-y:z" format
a, b = published.split('-', 1)
- try:
- int(a)
- int(b)
- except ValueError:
+ if not a.isdigit() or not b.isdigit():
raise ConfigurationError('Invalid published port: {}'.format(published))
else:
try:
@@ -373,7 +370,7 @@ class ServicePort(namedtuple('_ServicePort', 'target published protocol mode ext
except ValueError:
raise ConfigurationError('Invalid published port: {}'.format(published))
- return super(ServicePort, cls).__new__(
+ return super().__new__(
cls, target, published, *args, **kwargs
)
@@ -422,9 +419,9 @@ class ServicePort(namedtuple('_ServicePort', 'target published protocol mode ext
return (self.target, self.published, self.external_ip, self.protocol)
def repr(self):
- return dict(
- [(k, v) for k, v in zip(self._fields, self) if v is not None]
- )
+ return {
+ k: v for k, v in zip(self._fields, self) if v is not None
+ }
def legacy_repr(self):
return normalize_port_dict(self.repr())
@@ -484,9 +481,9 @@ class SecurityOpt(namedtuple('_SecurityOpt', 'value src_file')):
if con[0] == 'seccomp' and con[1] != 'unconfined':
try:
- with open(unquote_path(con[1]), 'r') as f:
+ with open(unquote_path(con[1])) as f:
seccomp_data = json.load(f)
- except (IOError, ValueError) as e:
+ except (OSError, ValueError) as e:
raise ConfigurationError('Error reading seccomp profile: {}'.format(e))
return cls(
'seccomp={}'.format(json.dumps(seccomp_data)), con[1]
diff --git a/compose/config/validation.py b/compose/config/validation.py
index 61a3370d..2b46cafe 100644
--- a/compose/config/validation.py
+++ b/compose/config/validation.py
@@ -100,7 +100,7 @@ def match_named_volumes(service_dict, project_volumes):
for volume_spec in service_volumes:
if volume_spec.is_named_volume and volume_spec.external not in project_volumes:
raise ConfigurationError(
- 'Named volume "{0}" is used in service "{1}" but no'
+ 'Named volume "{}" is used in service "{}" but no'
' declaration was found in the volumes section.'.format(
volume_spec.repr(), service_dict.get('name')
)
@@ -508,13 +508,13 @@ def load_jsonschema(version):
filename = os.path.join(
get_schema_path(),
- "config_schema_{0}.json".format(suffix))
+ "config_schema_{}.json".format(suffix))
if not os.path.exists(filename):
raise ConfigurationError(
'Version in "{}" is unsupported. {}'
.format(filename, VERSION_EXPLANATION))
- with open(filename, "r") as fh:
+ with open(filename) as fh:
return json.load(fh)
@@ -534,7 +534,7 @@ def handle_errors(errors, format_error_func, filename):
gone wrong. Process each error and pull out relevant information and re-write
helpful error messages that are relevant.
"""
- errors = list(sorted(errors, key=str))
+ errors = sorted(errors, key=str)
if not errors:
return
diff --git a/compose/container.py b/compose/container.py
index 7160a982..00626b61 100644
--- a/compose/container.py
+++ b/compose/container.py
@@ -12,7 +12,7 @@ from .utils import truncate_id
from .version import ComposeVersion
-class Container(object):
+class Container:
"""
Represents a Docker container, constructed from the output of
GET /containers/:id:/json.
@@ -78,8 +78,8 @@ class Container(object):
@property
def name_without_project(self):
- if self.name.startswith('{0}_{1}'.format(self.project, self.service)):
- return '{0}_{1}'.format(self.service, self.number if self.number is not None else self.slug)
+ if self.name.startswith('{}_{}'.format(self.project, self.service)):
+ return '{}_{}'.format(self.service, self.number if self.number is not None else self.slug)
else:
return self.name
@@ -91,7 +91,7 @@ class Container(object):
number = self.labels.get(LABEL_CONTAINER_NUMBER)
if not number:
- raise ValueError("Container {0} does not have a {1} label".format(
+ raise ValueError("Container {} does not have a {} label".format(
self.short_id, LABEL_CONTAINER_NUMBER))
return int(number)
@@ -224,7 +224,7 @@ class Container(object):
return reduce(get_value, key.split('.'), self.dictionary)
def get_local_port(self, port, protocol='tcp'):
- port = self.ports.get("%s/%s" % (port, protocol))
+ port = self.ports.get("{}/{}".format(port, protocol))
return "{HostIp}:{HostPort}".format(**port[0]) if port else None
def get_mount(self, mount_dest):
@@ -266,7 +266,7 @@ class Container(object):
"""
if not self.name.startswith(self.short_id):
self.client.rename(
- self.id, '{0}_{1}'.format(self.short_id, self.name)
+ self.id, '{}_{}'.format(self.short_id, self.name)
)
def inspect_if_not_inspected(self):
@@ -309,7 +309,7 @@ class Container(object):
)
def __repr__(self):
- return '<Container: %s (%s)>' % (self.name, self.id[:6])
+ return '<Container: {} ({})>'.format(self.name, self.id[:6])
def __eq__(self, other):
if type(self) != type(other):
diff --git a/compose/errors.py b/compose/errors.py
index 53065617..d4fead25 100644
--- a/compose/errors.py
+++ b/compose/errors.py
@@ -1,5 +1,3 @@
-
-
class OperationFailedError(Exception):
def __init__(self, reason):
self.msg = reason
@@ -17,14 +15,14 @@ class HealthCheckException(Exception):
class HealthCheckFailed(HealthCheckException):
def __init__(self, container_id):
- super(HealthCheckFailed, self).__init__(
+ super().__init__(
'Container "{}" is unhealthy.'.format(container_id)
)
class NoHealthCheckConfigured(HealthCheckException):
def __init__(self, service_name):
- super(NoHealthCheckConfigured, self).__init__(
+ super().__init__(
'Service "{}" is missing a healthcheck configuration'.format(
service_name
)
diff --git a/compose/network.py b/compose/network.py
index bc3ade16..a67c703c 100644
--- a/compose/network.py
+++ b/compose/network.py
@@ -1,6 +1,7 @@
import logging
import re
from collections import OrderedDict
+from operator import itemgetter
from docker.errors import NotFound
from docker.types import IPAMConfig
@@ -24,7 +25,7 @@ OPTS_EXCEPTIONS = [
]
-class Network(object):
+class Network:
def __init__(self, client, project, name, driver=None, driver_opts=None,
ipam=None, external=False, internal=False, enable_ipv6=False,
labels=None, custom_name=False):
@@ -51,7 +52,7 @@ class Network(object):
try:
self.inspect()
log.debug(
- 'Network {0} declared as external. No new '
+ 'Network {} declared as external. No new '
'network will be created.'.format(self.name)
)
except NotFound:
@@ -107,7 +108,7 @@ class Network(object):
def legacy_full_name(self):
if self.custom_name:
return self.name
- return '{0}_{1}'.format(
+ return '{}_{}'.format(
re.sub(r'[_-]', '', self.project), self.name
)
@@ -115,7 +116,7 @@ class Network(object):
def full_name(self):
if self.custom_name:
return self.name
- return '{0}_{1}'.format(self.project, self.name)
+ return '{}_{}'.format(self.project, self.name)
@property
def true_name(self):
@@ -167,7 +168,7 @@ def create_ipam_config_from_dict(ipam_dict):
class NetworkConfigChangedError(ConfigurationError):
def __init__(self, net_name, property_name):
- super(NetworkConfigChangedError, self).__init__(
+ super().__init__(
'Network "{}" needs to be recreated - {} has changed'.format(
net_name, property_name
)
@@ -258,7 +259,7 @@ def build_networks(name, config_data, client):
return networks
-class ProjectNetworks(object):
+class ProjectNetworks:
def __init__(self, networks, use_networking):
self.networks = networks or {}
@@ -299,10 +300,10 @@ def get_network_defs_for_service(service_dict):
if 'network_mode' in service_dict:
return {}
networks = service_dict.get('networks', {'default': None})
- return dict(
- (net, (config or {}))
+ return {
+ net: (config or {})
for net, config in networks.items()
- )
+ }
def get_network_names_for_service(service_dict):
@@ -328,4 +329,4 @@ def get_networks(service_dict, network_definitions):
else:
# Ensure Compose will pick a consistent primary network if no
# priority is set
- return OrderedDict(sorted(networks.items(), key=lambda t: t[0]))
+ return OrderedDict(sorted(networks.items(), key=itemgetter(0)))
diff --git a/compose/parallel.py b/compose/parallel.py
index 15c3ad57..acf9e4a8 100644
--- a/compose/parallel.py
+++ b/compose/parallel.py
@@ -25,7 +25,7 @@ log = logging.getLogger(__name__)
STOP = object()
-class GlobalLimit(object):
+class GlobalLimit:
"""Simple class to hold a global semaphore limiter for a project. This class
should be treated as a singleton that is instantiated when the project is.
"""
@@ -114,7 +114,7 @@ def _no_deps(x):
return []
-class State(object):
+class State:
"""
Holds the state of a partially-complete parallel operation.
@@ -136,7 +136,7 @@ class State(object):
return set(self.objects) - self.started - self.finished - self.failed
-class NoLimit(object):
+class NoLimit:
def __enter__(self):
pass
@@ -252,7 +252,7 @@ class UpstreamError(Exception):
pass
-class ParallelStreamWriter(object):
+class ParallelStreamWriter:
"""Write out messages for operations happening in parallel.
Each operation has its own line, and ANSI code characters are used
diff --git a/compose/progress_stream.py b/compose/progress_stream.py
index 8792ff28..3c03cc4b 100644
--- a/compose/progress_stream.py
+++ b/compose/progress_stream.py
@@ -79,19 +79,19 @@ def print_output_event(event, stream, is_terminal):
status = event.get('status', '')
if 'progress' in event:
- write_to_stream("%s %s%s" % (status, event['progress'], terminator), stream)
+ write_to_stream("{} {}{}".format(status, event['progress'], terminator), stream)
elif 'progressDetail' in event:
detail = event['progressDetail']
total = detail.get('total')
if 'current' in detail and total:
percentage = float(detail['current']) / float(total) * 100
- write_to_stream('%s (%.1f%%)%s' % (status, percentage, terminator), stream)
+ write_to_stream('{} ({:.1f}%){}'.format(status, percentage, terminator), stream)
else:
- write_to_stream('%s%s' % (status, terminator), stream)
+ write_to_stream('{}{}'.format(status, terminator), stream)
elif 'stream' in event:
- write_to_stream("%s%s" % (event['stream'], terminator), stream)
+ write_to_stream("{}{}".format(event['stream'], terminator), stream)
else:
- write_to_stream("%s%s\n" % (status, terminator), stream)
+ write_to_stream("{}{}\n".format(status, terminator), stream)
def get_digest_from_pull(events):
diff --git a/compose/project.py b/compose/project.py
index 5a03b30c..0ae5721b 100644
--- a/compose/project.py
+++ b/compose/project.py
@@ -55,16 +55,16 @@ class OneOffFilter(enum.Enum):
@classmethod
def update_labels(cls, value, labels):
if value == cls.only:
- labels.append('{0}={1}'.format(LABEL_ONE_OFF, "True"))
+ labels.append('{}={}'.format(LABEL_ONE_OFF, "True"))
elif value == cls.exclude:
- labels.append('{0}={1}'.format(LABEL_ONE_OFF, "False"))
+ labels.append('{}={}'.format(LABEL_ONE_OFF, "False"))
elif value == cls.include:
pass
else:
raise ValueError("Invalid value for one_off: {}".format(repr(value)))
-class Project(object):
+class Project:
"""
A collection of services.
"""
@@ -80,7 +80,7 @@ class Project(object):
name = self.name
if legacy:
name = re.sub(r'[_-]', '', name)
- labels = ['{0}={1}'.format(LABEL_PROJECT, name)]
+ labels = ['{}={}'.format(LABEL_PROJECT, name)]
OneOffFilter.update_labels(one_off, labels)
return labels
@@ -549,10 +549,10 @@ class Project(object):
'action': event['status'],
'id': event['Actor']['ID'],
'service': container_attrs.get(LABEL_SERVICE),
- 'attributes': dict([
- (k, v) for k, v in container_attrs.items()
+ 'attributes': {
+ k: v for k, v in container_attrs.items()
if not k.startswith('com.docker.compose.')
- ]),
+ },
'container': container,
}
@@ -812,7 +812,7 @@ class Project(object):
return
if remove_orphans:
for ctnr in orphans:
- log.info('Removing orphan container "{0}"'.format(ctnr.name))
+ log.info('Removing orphan container "{}"'.format(ctnr.name))
try:
ctnr.kill()
except APIError:
@@ -820,7 +820,7 @@ class Project(object):
ctnr.remove(force=True)
else:
log.warning(
- 'Found orphan containers ({0}) for this project. If '
+ 'Found orphan containers ({}) for this project. If '
'you removed or renamed this service in your compose '
'file, you can run this command with the '
'--remove-orphans flag to clean it up.'.format(
@@ -966,16 +966,16 @@ def get_secrets(service, service_secrets, secret_defs):
.format(service=service, secret=secret.source))
if secret_def.get('external'):
- log.warning("Service \"{service}\" uses secret \"{secret}\" which is external. "
- "External secrets are not available to containers created by "
- "docker-compose.".format(service=service, secret=secret.source))
+ log.warning('Service "{service}" uses secret "{secret}" which is external. '
+ 'External secrets are not available to containers created by '
+ 'docker-compose.'.format(service=service, secret=secret.source))
continue
if secret.uid or secret.gid or secret.mode:
log.warning(
- "Service \"{service}\" uses secret \"{secret}\" with uid, "
- "gid, or mode. These fields are not supported by this "
- "implementation of the Compose file".format(
+ 'Service "{service}" uses secret "{secret}" with uid, '
+ 'gid, or mode. These fields are not supported by this '
+ 'implementation of the Compose file'.format(
service=service, secret=secret.source
)
)
@@ -983,8 +983,8 @@ def get_secrets(service, service_secrets, secret_defs):
secret_file = secret_def.get('file')
if not path.isfile(str(secret_file)):
log.warning(
- "Service \"{service}\" uses an undefined secret file \"{secret_file}\", "
- "the following file should be created \"{secret_file}\"".format(
+ 'Service "{service}" uses an undefined secret file "{secret_file}", '
+ 'the following file should be created "{secret_file}"'.format(
service=service, secret_file=secret_file
)
)
diff --git a/compose/service.py b/compose/service.py
index f52bd6ff..5980310b 100644
--- a/compose/service.py
+++ b/compose/service.py
@@ -163,7 +163,7 @@ class BuildAction(enum.Enum):
skip = 2
-class Service(object):
+class Service:
def __init__(
self,
name,
@@ -230,10 +230,10 @@ class Service(object):
"""Return a :class:`compose.container.Container` for this service. The
container must be active, and match `number`.
"""
- for container in self.containers(labels=['{0}={1}'.format(LABEL_CONTAINER_NUMBER, number)]):
+ for container in self.containers(labels=['{}={}'.format(LABEL_CONTAINER_NUMBER, number)]):
return container
- raise ValueError("No container found for %s_%s" % (self.name, number))
+ raise ValueError("No container found for {}_{}".format(self.name, number))
def start(self, **options):
containers = self.containers(stopped=True)
@@ -642,7 +642,7 @@ class Service(object):
expl = binarystr_to_unicode(ex.explanation)
if "driver failed programming external connectivity" in expl:
log.warn("Host is already in use by another container")
- raise OperationFailedError("Cannot start service %s: %s" % (self.name, expl))
+ raise OperationFailedError("Cannot start service {}: {}".format(self.name, expl))
return container
@property
@@ -736,12 +736,12 @@ class Service(object):
pid_namespace = self.pid_mode.service_name
ipc_namespace = self.ipc_mode.service_name
- configs = dict(
- [(name, None) for name in self.get_linked_service_names()]
+ configs = {
+ name: None for name in self.get_linked_service_names()
+ }
+ configs.update(
+ (name, None) for name in self.get_volumes_from_names()
)
- configs.update(dict(
- [(name, None) for name in self.get_volumes_from_names()]
- ))
configs.update({net_name: None} if net_name else {})
configs.update({pid_namespace: None} if pid_namespace else {})
configs.update({ipc_namespace: None} if ipc_namespace else {})
@@ -863,9 +863,9 @@ class Service(object):
add_config_hash = (not one_off and not override_options)
slug = generate_random_id() if one_off else None
- container_options = dict(
- (k, self.options[k])
- for k in DOCKER_CONFIG_KEYS if k in self.options)
+ container_options = {
+ k: self.options[k]
+ for k in DOCKER_CONFIG_KEYS if k in self.options}
override_volumes = override_options.pop('volumes', [])
container_options.update(override_options)
@@ -957,7 +957,7 @@ class Service(object):
)
container_options['environment'].update(affinity)
- container_options['volumes'] = dict((v.internal, {}) for v in container_volumes or {})
+ container_options['volumes'] = {v.internal: {} for v in container_volumes or {}}
if version_gte(self.client.api_version, '1.30'):
override_options['mounts'] = [build_mount(v) for v in container_mounts] or None
else:
@@ -1159,9 +1159,9 @@ class Service(object):
def labels(self, one_off=False, legacy=False):
proj_name = self.project if not legacy else re.sub(r'[_-]', '', self.project)
return [
- '{0}={1}'.format(LABEL_PROJECT, proj_name),
- '{0}={1}'.format(LABEL_SERVICE, self.name),
- '{0}={1}'.format(LABEL_ONE_OFF, "True" if one_off else "False"),
+ '{}={}'.format(LABEL_PROJECT, proj_name),
+ '{}={}'.format(LABEL_SERVICE, self.name),
+ '{}={}'.format(LABEL_ONE_OFF, "True" if one_off else "False"),
]
@property
@@ -1178,7 +1178,7 @@ class Service(object):
ext_links_origins = [link.split(':')[0] for link in self.options.get('external_links', [])]
if container_name in ext_links_origins:
raise DependencyError(
- 'Service {0} has a self-referential external link: {1}'.format(
+ 'Service {} has a self-referential external link: {}'.format(
self.name, container_name
)
)
@@ -1233,11 +1233,9 @@ class Service(object):
output = self.client.pull(repo, **pull_kwargs)
if silent:
with open(os.devnull, 'w') as devnull:
- for event in stream_output(output, devnull):
- yield event
+ yield from stream_output(output, devnull)
else:
- for event in stream_output(output, sys.stdout):
- yield event
+ yield from stream_output(output, sys.stdout)
except (StreamOutputError, NotFound) as e:
if not ignore_pull_failures:
raise
@@ -1255,7 +1253,7 @@ class Service(object):
'platform': self.platform,
}
if not silent:
- log.info('Pulling %s (%s%s%s)...' % (self.name, repo, separator, tag))
+ log.info('Pulling {} ({}{}{})...'.format(self.name, repo, separator, tag))
if kwargs['platform'] and version_lt(self.client.api_version, '1.35'):
raise OperationFailedError(
@@ -1273,7 +1271,7 @@ class Service(object):
repo, tag, separator = parse_repository_tag(self.options['image'])
tag = tag or 'latest'
- log.info('Pushing %s (%s%s%s)...' % (self.name, repo, separator, tag))
+ log.info('Pushing {} ({}{}{})...'.format(self.name, repo, separator, tag))
output = self.client.push(repo, tag=tag, stream=True)
try:
@@ -1335,7 +1333,7 @@ def short_id_alias_exists(container, network):
return container.short_id in aliases
-class IpcMode(object):
+class IpcMode:
def __init__(self, mode):
self._mode = mode
@@ -1375,7 +1373,7 @@ class ContainerIpcMode(IpcMode):
self._mode = 'container:{}'.format(container.id)
-class PidMode(object):
+class PidMode:
def __init__(self, mode):
self._mode = mode
@@ -1415,7 +1413,7 @@ class ContainerPidMode(PidMode):
self._mode = 'container:{}'.format(container.id)
-class NetworkMode(object):
+class NetworkMode:
"""A `standard` network mode (ex: host, bridge)"""
service_name = None
@@ -1430,7 +1428,7 @@ class NetworkMode(object):
mode = id
-class ContainerNetworkMode(object):
+class ContainerNetworkMode:
"""A network mode that uses a container's network stack."""
service_name = None
@@ -1447,7 +1445,7 @@ class ContainerNetworkMode(object):
return 'container:' + self.container.id
-class ServiceNetworkMode(object):
+class ServiceNetworkMode:
"""A network mode that uses a service's network stack."""
def __init__(self, service):
@@ -1552,10 +1550,10 @@ def get_container_data_volumes(container, volumes_option, tmpfs_option, mounts_o
volumes = []
volumes_option = volumes_option or []
- container_mounts = dict(
- (mount['Destination'], mount)
+ container_mounts = {
+ mount['Destination']: mount
for mount in container.get('Mounts') or {}
- )
+ }
image_volumes = [
VolumeSpec.parse(volume)
@@ -1607,9 +1605,9 @@ def get_container_data_volumes(container, volumes_option, tmpfs_option, mounts_o
def warn_on_masked_volume(volumes_option, container_volumes, service):
- container_volumes = dict(
- (volume.internal, volume.external)
- for volume in container_volumes)
+ container_volumes = {
+ volume.internal: volume.external
+ for volume in container_volumes}
for volume in volumes_option:
if (
@@ -1759,7 +1757,7 @@ def convert_blkio_config(blkio_config):
continue
arr = []
for item in blkio_config[field]:
- arr.append(dict([(k.capitalize(), v) for k, v in item.items()]))
+ arr.append({k.capitalize(): v for k, v in item.items()})
result[field] = arr
return result
@@ -1771,7 +1769,7 @@ def rewrite_build_path(path):
return path
-class _CLIBuilder(object):
+class _CLIBuilder:
def __init__(self, progress):
self._progress = progress
@@ -1879,7 +1877,7 @@ class _CLIBuilder(object):
yield json.dumps({"stream": "{}{}\n".format(magic_word, image_id)})
-class _CommandBuilder(object):
+class _CommandBuilder:
def __init__(self):
self._args = ["docker", "build"]
diff --git a/compose/timeparse.py b/compose/timeparse.py
index bdd9f611..47744562 100644
--- a/compose/timeparse.py
+++ b/compose/timeparse.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
'''
timeparse.py
(c) Will Roberts <wildwilhelm@gmail.com> 1 February, 2014
@@ -54,14 +53,14 @@ TIMEFORMAT = r'{HOURS}{MINS}{SECS}{MILLI}{MICRO}{NANO}'.format(
NANO=opt(NANO),
)
-MULTIPLIERS = dict([
- ('hours', 60 * 60),
- ('mins', 60),
- ('secs', 1),
- ('milli', 1.0 / 1000),
- ('micro', 1.0 / 1000.0 / 1000),
- ('nano', 1.0 / 1000.0 / 1000.0 / 1000.0),
-])
+MULTIPLIERS = {
+ 'hours': 60 * 60,
+ 'mins': 60,
+ 'secs': 1,
+ 'milli': 1.0 / 1000,
+ 'micro': 1.0 / 1000.0 / 1000,
+ 'nano': 1.0 / 1000.0 / 1000.0 / 1000.0,
+}
def timeparse(sval):
@@ -90,4 +89,4 @@ def timeparse(sval):
def cast(value):
- return int(value, 10) if value.isdigit() else float(value)
+ return int(value) if value.isdigit() else float(value)
diff --git a/compose/utils.py b/compose/utils.py
index 8b5ab38d..060ba50c 100644
--- a/compose/utils.py
+++ b/compose/utils.py
@@ -29,7 +29,7 @@ def stream_as_text(stream):
yield data
-def line_splitter(buffer, separator=u'\n'):
+def line_splitter(buffer, separator='\n'):
index = buffer.find(str(separator))
if index == -1:
return None
@@ -45,7 +45,7 @@ def split_buffer(stream, splitter=None, decoder=lambda a: a):
of the input.
"""
splitter = splitter or line_splitter
- buffered = str('')
+ buffered = ''
for data in stream_as_text(stream):
buffered += data
@@ -116,7 +116,7 @@ def parse_nanoseconds_int(value):
def build_string_dict(source_dict):
- return dict((k, str(v if v is not None else '')) for k, v in source_dict.items())
+ return {k: str(v if v is not None else '') for k, v in source_dict.items()}
def splitdrive(path):
diff --git a/compose/volume.py b/compose/volume.py
index d31417a5..5f36e432 100644
--- a/compose/volume.py
+++ b/compose/volume.py
@@ -1,5 +1,6 @@
import logging
import re
+from itertools import chain
from docker.errors import NotFound
from docker.utils import version_lt
@@ -15,7 +16,7 @@ from .const import LABEL_VOLUME
log = logging.getLogger(__name__)
-class Volume(object):
+class Volume:
def __init__(self, client, project, name, driver=None, driver_opts=None,
external=False, labels=None, custom_name=False):
self.client = client
@@ -57,13 +58,13 @@ class Volume(object):
def full_name(self):
if self.custom_name:
return self.name
- return '{0}_{1}'.format(self.project.lstrip('-_'), self.name)
+ return '{}_{}'.format(self.project.lstrip('-_'), self.name)
@property
def legacy_full_name(self):
if self.custom_name:
return self.name
- return '{0}_{1}'.format(
+ return '{}_{}'.format(
re.sub(r'[_-]', '', self.project), self.name
)
@@ -96,7 +97,7 @@ class Volume(object):
self.legacy = False
-class ProjectVolumes(object):
+class ProjectVolumes:
def __init__(self, volumes):
self.volumes = volumes
@@ -132,7 +133,7 @@ class ProjectVolumes(object):
volume_exists = volume.exists()
if volume.external:
log.debug(
- 'Volume {0} declared as external. No new '
+ 'Volume {} declared as external. No new '
'volume will be created.'.format(volume.name)
)
if not volume_exists:
@@ -148,7 +149,7 @@ class ProjectVolumes(object):
if not volume_exists:
log.info(
- 'Creating volume "{0}" with {1} driver'.format(
+ 'Creating volume "{}" with {} driver'.format(
volume.full_name, volume.driver or 'default'
)
)
@@ -157,7 +158,7 @@ class ProjectVolumes(object):
check_remote_volume_config(volume.inspect(legacy=volume.legacy), volume)
except NotFound:
raise ConfigurationError(
- 'Volume %s specifies nonexistent driver %s' % (volume.name, volume.driver)
+ 'Volume {} specifies nonexistent driver {}'.format(volume.name, volume.driver)
)
def namespace_spec(self, volume_spec):
@@ -174,7 +175,7 @@ class ProjectVolumes(object):
class VolumeConfigChangedError(ConfigurationError):
def __init__(self, local, property_name, local_value, remote_value):
- super(VolumeConfigChangedError, self).__init__(
+ super().__init__(
'Configuration for volume {vol_name} specifies {property_name} '
'{local_value}, but a volume with the same name uses a different '
'{property_name} ({remote_value}). If you wish to use the new '
@@ -192,7 +193,7 @@ def check_remote_volume_config(remote, local):
raise VolumeConfigChangedError(local, 'driver', local.driver, remote.get('Driver'))
local_opts = local.driver_opts or {}
remote_opts = remote.get('Options') or {}
- for k in set.union(set(remote_opts.keys()), set(local_opts.keys())):
+ for k in set(chain(remote_opts, local_opts)):
if k.startswith('com.docker.'): # These options are set internally
continue
if remote_opts.get(k) != local_opts.get(k):
@@ -202,7 +203,7 @@ def check_remote_volume_config(remote, local):
local_labels = local.labels or {}
remote_labels = remote.get('Labels') or {}
- for k in set.union(set(remote_labels.keys()), set(local_labels.keys())):
+ for k in set(chain(remote_labels, local_labels)):
if k.startswith('com.docker.'): # We are only interested in user-specified labels
continue
if remote_labels.get(k) != local_labels.get(k):
diff --git a/contrib/migration/migrate-compose-file-v1-to-v2.py b/contrib/migration/migrate-compose-file-v1-to-v2.py
index e217b707..26511206 100755
--- a/contrib/migration/migrate-compose-file-v1-to-v2.py
+++ b/contrib/migration/migrate-compose-file-v1-to-v2.py
@@ -156,7 +156,7 @@ def main(args):
opts = parse_opts(args)
- with open(opts.filename, 'r') as fh:
+ with open(opts.filename) as fh:
new_format = migrate(fh.read())
if opts.in_place:
diff --git a/docker-compose_darwin.spec b/docker-compose_darwin.spec
index 6f96b29a..3228884f 100644
--- a/docker-compose_darwin.spec
+++ b/docker-compose_darwin.spec
@@ -1,4 +1,4 @@
-# -*- mode: python ; coding: utf-8 -*-
+# -*- mode: python -*-
block_cipher = None
diff --git a/requirements.txt b/requirements.txt
index d0a38664..59317bdf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,8 +8,6 @@ docker==4.3.0
docker-pycreds==0.4.0
dockerpty==0.4.1
docopt==0.6.2
-enum34==1.1.6; python_version < '3.4'
-functools32==3.2.3.post2; python_version < '3.2'
idna==2.10
ipaddress==1.0.23
jsonschema==3.2.0
diff --git a/script/release/utils.py b/script/release/utils.py
index 25b39ca7..5ed53ec8 100644
--- a/script/release/utils.py
+++ b/script/release/utils.py
@@ -6,7 +6,7 @@ from const import REPO_ROOT
def update_init_py_version(version):
path = os.path.join(REPO_ROOT, 'compose', '__init__.py')
- with open(path, 'r') as f:
+ with open(path) as f:
contents = f.read()
contents = re.sub(r"__version__ = '[0-9a-z.-]+'", "__version__ = '{}'".format(version), contents)
with open(path, 'w') as f:
@@ -15,7 +15,7 @@ def update_init_py_version(version):
def update_run_sh_version(version):
path = os.path.join(REPO_ROOT, 'script', 'run', 'run.sh')
- with open(path, 'r') as f:
+ with open(path) as f:
contents = f.read()
contents = re.sub(r'VERSION="[0-9a-z.-]+"', 'VERSION="{}"'.format(version), contents)
with open(path, 'w') as f:
diff --git a/setup.py b/setup.py
index a2e946b3..6041fce1 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
import codecs
import os
import re
@@ -50,7 +49,6 @@ if sys.version_info[:2] < (3, 4):
tests_require.append('mock >= 1.0.1, < 4')
extras_require = {
- ':python_version < "3.2"': ['subprocess32 >= 3.5.4, < 4'],
':python_version < "3.4"': ['enum34 >= 1.0.4, < 2'],
':python_version < "3.5"': ['backports.ssl_match_hostname >= 3.5, < 4'],
':python_version < "3.3"': ['backports.shutil_get_terminal_size == 1.0.0',
@@ -94,7 +92,7 @@ setup(
install_requires=install_requires,
extras_require=extras_require,
tests_require=tests_require,
- python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
+ python_requires='>=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
entry_points={
'console_scripts': ['docker-compose=compose.cli.main:main'],
},
diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py
index 92168e93..4dd93521 100644
--- a/tests/acceptance/cli_test.py
+++ b/tests/acceptance/cli_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import datetime
import json
import os.path
@@ -99,7 +98,7 @@ def kill_service(service):
container.kill()
-class ContainerCountCondition(object):
+class ContainerCountCondition:
def __init__(self, project, expected):
self.project = project
@@ -112,7 +111,7 @@ class ContainerCountCondition(object):
return "waiting for counter count == %s" % self.expected
-class ContainerStateCondition(object):
+class ContainerStateCondition:
def __init__(self, client, name, status):
self.client = client
@@ -140,7 +139,7 @@ class ContainerStateCondition(object):
class CLITestCase(DockerClientTestCase):
def setUp(self):
- super(CLITestCase, self).setUp()
+ super().setUp()
self.base_dir = 'tests/fixtures/simple-composefile'
self.override_dir = None
@@ -162,7 +161,7 @@ class CLITestCase(DockerClientTestCase):
if hasattr(self, '_project'):
del self._project
- super(CLITestCase, self).tearDown()
+ super().tearDown()
@property
def project(self):
@@ -206,14 +205,14 @@ class CLITestCase(DockerClientTestCase):
def test_shorthand_host_opt(self):
self.dispatch(
- ['-H={0}'.format(os.environ.get('DOCKER_HOST', 'unix://')),
+ ['-H={}'.format(os.environ.get('DOCKER_HOST', 'unix://')),
'up', '-d'],
returncode=0
)
def test_shorthand_host_opt_interactive(self):
self.dispatch(
- ['-H={0}'.format(os.environ.get('DOCKER_HOST', 'unix://')),
+ ['-H={}'.format(os.environ.get('DOCKER_HOST', 'unix://')),
'run', 'another', 'ls'],
returncode=0
)
@@ -1453,7 +1452,7 @@ services:
if v['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
]
- assert set([v['Name'].split('/')[-1] for v in volumes]) == {volume_with_label}
+ assert {v['Name'].split('/')[-1] for v in volumes} == {volume_with_label}
assert 'label_key' in volumes[0]['Labels']
assert volumes[0]['Labels']['label_key'] == 'label_val'
@@ -1866,12 +1865,12 @@ services:
self.dispatch(['run', 'implicit'])
service = self.project.get_service('implicit')
containers = service.containers(stopped=True, one_off=OneOffFilter.only)
- assert [c.human_readable_command for c in containers] == [u'/bin/sh -c echo "success"']
+ assert [c.human_readable_command for c in containers] == ['/bin/sh -c echo "success"']
self.dispatch(['run', 'explicit'])
service = self.project.get_service('explicit')
containers = service.containers(stopped=True, one_off=OneOffFilter.only)
- assert [c.human_readable_command for c in containers] == [u'/bin/true']
+ assert [c.human_readable_command for c in containers] == ['/bin/true']
@pytest.mark.skipif(SWARM_SKIP_RM_VOLUMES, reason='Swarm DELETE /containers/<id> bug')
def test_run_rm(self):
@@ -2701,7 +2700,7 @@ services:
str_iso_date, str_iso_time, container_info = string.split(' ', 2)
try:
return isinstance(datetime.datetime.strptime(
- '%s %s' % (str_iso_date, str_iso_time),
+ '{} {}'.format(str_iso_date, str_iso_time),
'%Y-%m-%d %H:%M:%S.%f'),
datetime.datetime)
except ValueError:
@@ -2790,7 +2789,7 @@ services:
self.base_dir = 'tests/fixtures/extends'
self.dispatch(['up', '-d'], None)
- assert set([s.name for s in self.project.services]) == {'mydb', 'myweb'}
+ assert {s.name for s in self.project.services} == {'mydb', 'myweb'}
# Sort by name so we get [db, web]
containers = sorted(
diff --git a/tests/acceptance/context_test.py b/tests/acceptance/context_test.py
index e17e7171..a5d0c147 100644
--- a/tests/acceptance/context_test.py
+++ b/tests/acceptance/context_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import os
import shutil
import unittest
diff --git a/tests/helpers.py b/tests/helpers.py
index d1786848..3642e6eb 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -49,7 +49,7 @@ def create_custom_host_file(client, filename, content):
def create_host_file(client, filename):
- with open(filename, 'r') as fh:
+ with open(filename) as fh:
content = fh.read()
return create_custom_host_file(client, filename, content)
diff --git a/tests/integration/environment_test.py b/tests/integration/environment_test.py
index 43df2c52..12a969c9 100644
--- a/tests/integration/environment_test.py
+++ b/tests/integration/environment_test.py
@@ -15,7 +15,7 @@ from tests.integration.testcases import DockerClientTestCase
class EnvironmentTest(DockerClientTestCase):
@classmethod
def setUpClass(cls):
- super(EnvironmentTest, cls).setUpClass()
+ super().setUpClass()
cls.compose_file = tempfile.NamedTemporaryFile(mode='w+b')
cls.compose_file.write(bytes("""version: '3.2'
services:
@@ -27,7 +27,7 @@ services:
@classmethod
def tearDownClass(cls):
- super(EnvironmentTest, cls).tearDownClass()
+ super().tearDownClass()
cls.compose_file.close()
@data('events',
diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py
index 4848c53e..87970107 100644
--- a/tests/integration/project_test.py
+++ b/tests/integration/project_test.py
@@ -289,19 +289,19 @@ class ProjectTest(DockerClientTestCase):
db_container = db.create_container()
project.start(service_names=['web'])
- assert set(c.name for c in project.containers() if c.is_running) == {
+ assert {c.name for c in project.containers() if c.is_running} == {
web_container_1.name, web_container_2.name}
project.start()
- assert set(c.name for c in project.containers() if c.is_running) == {
+ assert {c.name for c in project.containers() if c.is_running} == {
web_container_1.name, web_container_2.name, db_container.name}
project.pause(service_names=['web'])
- assert set([c.name for c in project.containers() if c.is_paused]) == {
+ assert {c.name for c in project.containers() if c.is_paused} == {
web_container_1.name, web_container_2.name}
project.pause()
- assert set([c.name for c in project.containers() if c.is_paused]) == {
+ assert {c.name for c in project.containers() if c.is_paused} == {
web_container_1.name, web_container_2.name, db_container.name}
project.unpause(service_names=['db'])
@@ -311,7 +311,7 @@ class ProjectTest(DockerClientTestCase):
assert len([c.name for c in project.containers() if c.is_paused]) == 0
project.stop(service_names=['web'], timeout=1)
- assert set(c.name for c in project.containers() if c.is_running) == {db_container.name}
+ assert {c.name for c in project.containers() if c.is_running} == {db_container.name}
project.kill(service_names=['db'])
assert len([c for c in project.containers() if c.is_running]) == 0
@@ -1177,8 +1177,8 @@ class ProjectTest(DockerClientTestCase):
assert networks[0]['Labels']['label_key'] == 'label_val'
def test_project_up_volumes(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
- full_vol_name = 'composetest_{0}'.format(vol_name)
+ vol_name = '{:x}'.format(random.getrandbits(32))
+ full_vol_name = 'composetest_{}'.format(vol_name)
config_data = build_config(
services=[{
'name': 'web',
@@ -1232,9 +1232,9 @@ class ProjectTest(DockerClientTestCase):
if v['Name'].split('/')[-1].startswith('composetest_')
]
- assert set([v['Name'].split('/')[-1] for v in volumes]) == set(
- ['composetest_{}'.format(volume_name)]
- )
+ assert {v['Name'].split('/')[-1] for v in volumes} == {
+ 'composetest_{}'.format(volume_name)
+ }
assert 'label_key' in volumes[0]['Labels']
assert volumes[0]['Labels']['label_key'] == 'label_val'
@@ -1348,8 +1348,8 @@ class ProjectTest(DockerClientTestCase):
assert len(project.containers()) == 3
def test_initialize_volumes(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
- full_vol_name = 'composetest_{0}'.format(vol_name)
+ vol_name = '{:x}'.format(random.getrandbits(32))
+ full_vol_name = 'composetest_{}'.format(vol_name)
config_data = build_config(
services=[{
'name': 'web',
@@ -1370,8 +1370,8 @@ class ProjectTest(DockerClientTestCase):
assert volume_data['Driver'] == 'local'
def test_project_up_implicit_volume_driver(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
- full_vol_name = 'composetest_{0}'.format(vol_name)
+ vol_name = '{:x}'.format(random.getrandbits(32))
+ full_vol_name = 'composetest_{}'.format(vol_name)
config_data = build_config(
services=[{
'name': 'web',
@@ -1479,7 +1479,7 @@ class ProjectTest(DockerClientTestCase):
assert output == b"This is the secret\n"
def test_initialize_volumes_invalid_volume_driver(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
+ vol_name = '{:x}'.format(random.getrandbits(32))
config_data = build_config(
version=VERSION,
@@ -1500,8 +1500,8 @@ class ProjectTest(DockerClientTestCase):
@no_cluster('inspect volume by name defect on Swarm Classic')
def test_initialize_volumes_updated_driver(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
- full_vol_name = 'composetest_{0}'.format(vol_name)
+ vol_name = '{:x}'.format(random.getrandbits(32))
+ full_vol_name = 'composetest_{}'.format(vol_name)
config_data = build_config(
services=[{
@@ -1531,14 +1531,14 @@ class ProjectTest(DockerClientTestCase):
)
with pytest.raises(config.ConfigurationError) as e:
project.volumes.initialize()
- assert 'Configuration for volume {0} specifies driver smb'.format(
+ assert 'Configuration for volume {} specifies driver smb'.format(
vol_name
) in str(e.value)
@no_cluster('inspect volume by name defect on Swarm Classic')
def test_initialize_volumes_updated_driver_opts(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
- full_vol_name = 'composetest_{0}'.format(vol_name)
+ vol_name = '{:x}'.format(random.getrandbits(32))
+ full_vol_name = 'composetest_{}'.format(vol_name)
tmpdir = tempfile.mkdtemp(prefix='compose_test_')
self.addCleanup(shutil.rmtree, tmpdir)
driver_opts = {'o': 'bind', 'device': tmpdir, 'type': 'none'}
@@ -1575,13 +1575,13 @@ class ProjectTest(DockerClientTestCase):
)
with pytest.raises(config.ConfigurationError) as e:
project.volumes.initialize()
- assert 'Configuration for volume {0} specifies "device" driver_opt {1}'.format(
+ assert 'Configuration for volume {} specifies "device" driver_opt {}'.format(
vol_name, driver_opts['device']
) in str(e.value)
def test_initialize_volumes_updated_blank_driver(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
- full_vol_name = 'composetest_{0}'.format(vol_name)
+ vol_name = '{:x}'.format(random.getrandbits(32))
+ full_vol_name = 'composetest_{}'.format(vol_name)
config_data = build_config(
services=[{
@@ -1617,8 +1617,8 @@ class ProjectTest(DockerClientTestCase):
@no_cluster('inspect volume by name defect on Swarm Classic')
def test_initialize_volumes_external_volumes(self):
# Use composetest_ prefix so it gets garbage-collected in tearDown()
- vol_name = 'composetest_{0:x}'.format(random.getrandbits(32))
- full_vol_name = 'composetest_{0}'.format(vol_name)
+ vol_name = 'composetest_{:x}'.format(random.getrandbits(32))
+ full_vol_name = 'composetest_{}'.format(vol_name)
self.client.create_volume(vol_name)
config_data = build_config(
services=[{
@@ -1640,7 +1640,7 @@ class ProjectTest(DockerClientTestCase):
self.client.inspect_volume(full_vol_name)
def test_initialize_volumes_inexistent_external_volume(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
+ vol_name = '{:x}'.format(random.getrandbits(32))
config_data = build_config(
services=[{
@@ -1658,13 +1658,13 @@ class ProjectTest(DockerClientTestCase):
)
with pytest.raises(config.ConfigurationError) as e:
project.volumes.initialize()
- assert 'Volume {0} declared as external'.format(
+ assert 'Volume {} declared as external'.format(
vol_name
) in str(e.value)
def test_project_up_named_volumes_in_binds(self):
- vol_name = '{0:x}'.format(random.getrandbits(32))
- full_vol_name = 'composetest_{0}'.format(vol_name)
+ vol_name = '{:x}'.format(random.getrandbits(32))
+ full_vol_name = 'composetest_{}'.format(vol_name)
base_file = config.ConfigFile(
'base.yml',
@@ -1673,7 +1673,7 @@ class ProjectTest(DockerClientTestCase):
'simple': {
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'top',
- 'volumes': ['{0}:/data'.format(vol_name)]
+ 'volumes': ['{}:/data'.format(vol_name)]
},
},
'volumes': {
diff --git a/tests/integration/resilience_test.py b/tests/integration/resilience_test.py
index 81cb2382..2fbaafb2 100644
--- a/tests/integration/resilience_test.py
+++ b/tests/integration/resilience_test.py
@@ -22,7 +22,7 @@ class ResilienceTest(DockerClientTestCase):
def tearDown(self):
del self.project
del self.db
- super(ResilienceTest, self).tearDown()
+ super().tearDown()
def test_successful_recreate(self):
self.project.up(strategy=ConvergenceStrategy.always)
diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py
index 76efba44..985c4d77 100644
--- a/tests/integration/service_test.py
+++ b/tests/integration/service_test.py
@@ -248,7 +248,7 @@ class ServiceTest(DockerClientTestCase):
service = self.create_service('db', security_opt=security_opt)
container = service.create_container()
service.start_container(container)
- assert set(container.get('HostConfig.SecurityOpt')) == set([o.repr() for o in security_opt])
+ assert set(container.get('HostConfig.SecurityOpt')) == {o.repr() for o in security_opt}
@pytest.mark.xfail(True, reason='Not supported on most drivers')
def test_create_container_with_storage_opt(self):
@@ -290,7 +290,7 @@ class ServiceTest(DockerClientTestCase):
actual_host_path = container.get_mount(container_path)['Source']
assert path.basename(actual_host_path) == path.basename(host_path), (
- "Last component differs: %s, %s" % (actual_host_path, host_path)
+ "Last component differs: {}, {}".format(actual_host_path, host_path)
)
def test_create_container_with_host_mount(self):
@@ -844,11 +844,11 @@ class ServiceTest(DockerClientTestCase):
db2 = create_and_start_container(db)
create_and_start_container(web)
- assert set(get_links(web.containers()[0])) == set([
+ assert set(get_links(web.containers()[0])) == {
db1.name, db1.name_without_project,
db2.name, db2.name_without_project,
'db'
- ])
+ }
@no_cluster('No legacy links support in Swarm')
def test_start_container_creates_links_with_names(self):
@@ -859,11 +859,11 @@ class ServiceTest(DockerClientTestCase):
db2 = create_and_start_container(db)
create_and_start_container(web)
- assert set(get_links(web.containers()[0])) == set([
+ assert set(get_links(web.containers()[0])) == {
db1.name, db1.name_without_project,
db2.name, db2.name_without_project,
'custom_link_name'
- ])
+ }
@no_cluster('No legacy links support in Swarm')
def test_start_container_with_external_links(self):
@@ -879,11 +879,11 @@ class ServiceTest(DockerClientTestCase):
create_and_start_container(web)
- assert set(get_links(web.containers()[0])) == set([
+ assert set(get_links(web.containers()[0])) == {
db_ctnrs[0].name,
db_ctnrs[1].name,
'db_3'
- ])
+ }
@no_cluster('No legacy links support in Swarm')
def test_start_normal_container_does_not_create_links_to_its_own_service(self):
@@ -893,7 +893,7 @@ class ServiceTest(DockerClientTestCase):
create_and_start_container(db)
c = create_and_start_container(db)
- assert set(get_links(c)) == set([])
+ assert set(get_links(c)) == set()
@no_cluster('No legacy links support in Swarm')
def test_start_one_off_container_creates_links_to_its_own_service(self):
@@ -904,11 +904,11 @@ class ServiceTest(DockerClientTestCase):
c = create_and_start_container(db, one_off=OneOffFilter.only)
- assert set(get_links(c)) == set([
+ assert set(get_links(c)) == {
db1.name, db1.name_without_project,
db2.name, db2.name_without_project,
'db'
- ])
+ }
def test_start_container_builds_images(self):
service = Service(
@@ -1719,14 +1719,14 @@ class ServiceTest(DockerClientTestCase):
options = service._get_container_create_options({}, service._next_container_number())
original = Container.create(service.client, **options)
- assert set(service.containers(stopped=True)) == set([original])
+ assert set(service.containers(stopped=True)) == {original}
assert set(service.duplicate_containers()) == set()
options['name'] = 'temporary_container_name'
duplicate = Container.create(service.client, **options)
- assert set(service.containers(stopped=True)) == set([original, duplicate])
- assert set(service.duplicate_containers()) == set([duplicate])
+ assert set(service.containers(stopped=True)) == {original, duplicate}
+ assert set(service.duplicate_containers()) == {duplicate}
def converge(service, strategy=ConvergenceStrategy.changed):
diff --git a/tests/integration/state_test.py b/tests/integration/state_test.py
index 611d0cc9..5258e310 100644
--- a/tests/integration/state_test.py
+++ b/tests/integration/state_test.py
@@ -39,7 +39,7 @@ class ProjectTestCase(DockerClientTestCase):
class BasicProjectTest(ProjectTestCase):
def setUp(self):
- super(BasicProjectTest, self).setUp()
+ super().setUp()
self.cfg = {
'db': {'image': BUSYBOX_IMAGE_WITH_TAG, 'command': 'top'},
@@ -95,7 +95,7 @@ class BasicProjectTest(ProjectTestCase):
class ProjectWithDependenciesTest(ProjectTestCase):
def setUp(self):
- super(ProjectWithDependenciesTest, self).setUp()
+ super().setUp()
self.cfg = {
'db': {
@@ -116,7 +116,7 @@ class ProjectWithDependenciesTest(ProjectTestCase):
def test_up(self):
containers = self.run_up(self.cfg)
- assert set(c.service for c in containers) == set(['db', 'web', 'nginx'])
+ assert {c.service for c in containers} == {'db', 'web', 'nginx'}
def test_change_leaf(self):
old_containers = self.run_up(self.cfg)
@@ -124,7 +124,7 @@ class ProjectWithDependenciesTest(ProjectTestCase):
self.cfg['nginx']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(self.cfg)
- assert set(c.service for c in new_containers - old_containers) == set(['nginx'])
+ assert {c.service for c in new_containers - old_containers} == {'nginx'}
def test_change_middle(self):
old_containers = self.run_up(self.cfg)
@@ -132,7 +132,7 @@ class ProjectWithDependenciesTest(ProjectTestCase):
self.cfg['web']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(self.cfg)
- assert set(c.service for c in new_containers - old_containers) == set(['web'])
+ assert {c.service for c in new_containers - old_containers} == {'web'}
def test_change_middle_always_recreate_deps(self):
old_containers = self.run_up(self.cfg, always_recreate_deps=True)
@@ -140,7 +140,7 @@ class ProjectWithDependenciesTest(ProjectTestCase):
self.cfg['web']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(self.cfg, always_recreate_deps=True)
- assert set(c.service for c in new_containers - old_containers) == {'web', 'nginx'}
+ assert {c.service for c in new_containers - old_containers} == {'web', 'nginx'}
def test_change_root(self):
old_containers = self.run_up(self.cfg)
@@ -148,7 +148,7 @@ class ProjectWithDependenciesTest(ProjectTestCase):
self.cfg['db']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(self.cfg)
- assert set(c.service for c in new_containers - old_containers) == set(['db'])
+ assert {c.service for c in new_containers - old_containers} == {'db'}
def test_change_root_always_recreate_deps(self):
old_containers = self.run_up(self.cfg, always_recreate_deps=True)
@@ -156,7 +156,7 @@ class ProjectWithDependenciesTest(ProjectTestCase):
self.cfg['db']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(self.cfg, always_recreate_deps=True)
- assert set(c.service for c in new_containers - old_containers) == {
+ assert {c.service for c in new_containers - old_containers} == {
'db', 'web', 'nginx'
}
@@ -213,7 +213,7 @@ class ProjectWithDependenciesTest(ProjectTestCase):
class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
def setUp(self):
- super(ProjectWithDependsOnDependenciesTest, self).setUp()
+ super().setUp()
self.cfg = {
'version': '2',
@@ -238,7 +238,7 @@ class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
def test_up(self):
local_cfg = copy.deepcopy(self.cfg)
containers = self.run_up(local_cfg)
- assert set(c.service for c in containers) == set(['db', 'web', 'nginx'])
+ assert {c.service for c in containers} == {'db', 'web', 'nginx'}
def test_change_leaf(self):
local_cfg = copy.deepcopy(self.cfg)
@@ -247,7 +247,7 @@ class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
local_cfg['services']['nginx']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(local_cfg)
- assert set(c.service for c in new_containers - old_containers) == set(['nginx'])
+ assert {c.service for c in new_containers - old_containers} == {'nginx'}
def test_change_middle(self):
local_cfg = copy.deepcopy(self.cfg)
@@ -256,7 +256,7 @@ class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
local_cfg['services']['web']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(local_cfg)
- assert set(c.service for c in new_containers - old_containers) == set(['web'])
+ assert {c.service for c in new_containers - old_containers} == {'web'}
def test_change_middle_always_recreate_deps(self):
local_cfg = copy.deepcopy(self.cfg)
@@ -265,7 +265,7 @@ class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
local_cfg['services']['web']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(local_cfg, always_recreate_deps=True)
- assert set(c.service for c in new_containers - old_containers) == set(['web', 'nginx'])
+ assert {c.service for c in new_containers - old_containers} == {'web', 'nginx'}
def test_change_root(self):
local_cfg = copy.deepcopy(self.cfg)
@@ -274,7 +274,7 @@ class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
local_cfg['services']['db']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(local_cfg)
- assert set(c.service for c in new_containers - old_containers) == set(['db'])
+ assert {c.service for c in new_containers - old_containers} == {'db'}
def test_change_root_always_recreate_deps(self):
local_cfg = copy.deepcopy(self.cfg)
@@ -283,7 +283,7 @@ class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
local_cfg['services']['db']['environment'] = {'NEW_VAR': '1'}
new_containers = self.run_up(local_cfg, always_recreate_deps=True)
- assert set(c.service for c in new_containers - old_containers) == set(['db', 'web', 'nginx'])
+ assert {c.service for c in new_containers - old_containers} == {'db', 'web', 'nginx'}
def test_change_root_no_recreate(self):
local_cfg = copy.deepcopy(self.cfg)
@@ -303,24 +303,24 @@ class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
del next_cfg['services']['web']['depends_on']
containers = self.run_up(local_cfg)
- assert set(c.service for c in containers) == set(['db', 'web', 'nginx'])
+ assert {c.service for c in containers} == {'db', 'web', 'nginx'}
project = self.make_project(local_cfg)
project.stop(timeout=1)
next_containers = self.run_up(next_cfg)
- assert set(c.service for c in next_containers) == set(['web', 'nginx'])
+ assert {c.service for c in next_containers} == {'web', 'nginx'}
def test_service_removed_while_up(self):
local_cfg = copy.deepcopy(self.cfg)
containers = self.run_up(local_cfg)
- assert set(c.service for c in containers) == set(['db', 'web', 'nginx'])
+ assert {c.service for c in containers} == {'db', 'web', 'nginx'}
del local_cfg['services']['db']
del local_cfg['services']['web']['depends_on']
containers = self.run_up(local_cfg)
- assert set(c.service for c in containers) == set(['web', 'nginx'])
+ assert {c.service for c in containers} == {'web', 'nginx'}
def test_dependency_removed(self):
local_cfg = copy.deepcopy(self.cfg)
@@ -328,24 +328,24 @@ class ProjectWithDependsOnDependenciesTest(ProjectTestCase):
del next_cfg['services']['nginx']['depends_on']
containers = self.run_up(local_cfg, service_names=['nginx'])
- assert set(c.service for c in containers) == set(['db', 'web', 'nginx'])
+ assert {c.service for c in containers} == {'db', 'web', 'nginx'}
project = self.make_project(local_cfg)
project.stop(timeout=1)
next_containers = self.run_up(next_cfg, service_names=['nginx'])
- assert set(c.service for c in next_containers if c.is_running) == set(['nginx'])
+ assert {c.service for c in next_containers if c.is_running} == {'nginx'}
def test_dependency_added(self):
local_cfg = copy.deepcopy(self.cfg)
del local_cfg['services']['nginx']['depends_on']
containers = self.run_up(local_cfg, service_names=['nginx'])
- assert set(c.service for c in containers) == set(['nginx'])
+ assert {c.service for c in containers} == {'nginx'}
local_cfg['services']['nginx']['depends_on'] = ['db']
containers = self.run_up(local_cfg, service_names=['nginx'])
- assert set(c.service for c in containers) == set(['nginx', 'db'])
+ assert {c.service for c in containers} == {'nginx', 'db'}
class ServiceStateTest(DockerClientTestCase):
diff --git a/tests/integration/volume_test.py b/tests/integration/volume_test.py
index 2ede7bf2..0e7c78bc 100644
--- a/tests/integration/volume_test.py
+++ b/tests/integration/volume_test.py
@@ -18,7 +18,7 @@ class VolumeTest(DockerClientTestCase):
except DockerException:
pass
del self.tmp_volumes
- super(VolumeTest, self).tearDown()
+ super().tearDown()
def create_volume(self, name, driver=None, opts=None, external=None, custom_name=False):
if external:
diff --git a/tests/unit/cli/command_test.py b/tests/unit/cli/command_test.py
index 20702d97..9d4db5b5 100644
--- a/tests/unit/cli/command_test.py
+++ b/tests/unit/cli/command_test.py
@@ -1,4 +1,3 @@
-# ~*~ encoding: utf-8 ~*~
import os
import pytest
@@ -9,7 +8,7 @@ from compose.const import IS_WINDOWS_PLATFORM
from tests import mock
-class TestGetConfigPathFromOptions(object):
+class TestGetConfigPathFromOptions:
def test_path_from_options(self):
paths = ['one.yml', 'two.yml']
diff --git a/tests/unit/cli/docker_client_test.py b/tests/unit/cli/docker_client_test.py
index 873c1ff3..941aed4f 100644
--- a/tests/unit/cli/docker_client_test.py
+++ b/tests/unit/cli/docker_client_test.py
@@ -55,7 +55,7 @@ class DockerClientTestCase(unittest.TestCase):
def test_user_agent(self):
client = docker_client(os.environ)
- expected = "docker-compose/{0} docker-py/{1} {2}/{3}".format(
+ expected = "docker-compose/{} docker-py/{} {}/{}".format(
compose.__version__,
docker.__version__,
platform.system(),
@@ -151,9 +151,9 @@ class TLSConfigTestCase(unittest.TestCase):
def test_tls_client_and_ca_quoted_paths(self):
options = {
- '--tlscacert': '"{0}"'.format(self.ca_cert),
- '--tlscert': '"{0}"'.format(self.client_cert),
- '--tlskey': '"{0}"'.format(self.key),
+ '--tlscacert': '"{}"'.format(self.ca_cert),
+ '--tlscert': '"{}"'.format(self.client_cert),
+ '--tlskey': '"{}"'.format(self.key),
'--tlsverify': True
}
result = tls_config_from_options(options)
@@ -185,9 +185,9 @@ class TLSConfigTestCase(unittest.TestCase):
'DOCKER_TLS_VERIFY': 'false'
})
options = {
- '--tlscacert': '"{0}"'.format(self.ca_cert),
- '--tlscert': '"{0}"'.format(self.client_cert),
- '--tlskey': '"{0}"'.format(self.key),
+ '--tlscacert': '"{}"'.format(self.ca_cert),
+ '--tlscert': '"{}"'.format(self.client_cert),
+ '--tlskey': '"{}"'.format(self.key),
'--tlsverify': True
}
@@ -230,7 +230,7 @@ class TLSConfigTestCase(unittest.TestCase):
assert result.cert == (self.client_cert, self.key)
-class TestGetTlsVersion(object):
+class TestGetTlsVersion:
def test_get_tls_version_default(self):
environment = {}
assert get_tls_version(environment) is None
diff --git a/tests/unit/cli/errors_test.py b/tests/unit/cli/errors_test.py
index f7359a48..3b70ffe7 100644
--- a/tests/unit/cli/errors_test.py
+++ b/tests/unit/cli/errors_test.py
@@ -21,7 +21,7 @@ def patch_find_executable(side_effect):
side_effect=side_effect)
-class TestHandleConnectionErrors(object):
+class TestHandleConnectionErrors:
def test_generic_connection_error(self, mock_logging):
with pytest.raises(errors.ConnectionError):
@@ -43,7 +43,7 @@ class TestHandleConnectionErrors(object):
def test_api_error_version_mismatch_unicode_explanation(self, mock_logging):
with pytest.raises(errors.ConnectionError):
with handle_connection_errors(mock.Mock(api_version='1.38')):
- raise APIError(None, None, u"client is newer than server")
+ raise APIError(None, None, "client is newer than server")
_, args, _ = mock_logging.error.mock_calls[0]
assert "Docker Engine of version 18.06.0 or greater" in args[0]
@@ -57,7 +57,7 @@ class TestHandleConnectionErrors(object):
mock_logging.error.assert_called_once_with(msg.decode('utf-8'))
def test_api_error_version_other_unicode_explanation(self, mock_logging):
- msg = u"Something broke!"
+ msg = "Something broke!"
with pytest.raises(errors.ConnectionError):
with handle_connection_errors(mock.Mock(api_version='1.22')):
raise APIError(None, None, msg)
diff --git a/tests/unit/cli/formatter_test.py b/tests/unit/cli/formatter_test.py
index 07f5a8f5..08752a62 100644
--- a/tests/unit/cli/formatter_test.py
+++ b/tests/unit/cli/formatter_test.py
@@ -40,10 +40,10 @@ class ConsoleWarningFormatterTestCase(unittest.TestCase):
message = b'\xec\xa0\x95\xec\x88\x98\xec\xa0\x95'
output = self.formatter.format(make_log_record(logging.WARN, message))
expected = colors.yellow('WARNING') + ': '
- assert output == '{0}{1}'.format(expected, message.decode('utf-8'))
+ assert output == '{}{}'.format(expected, message.decode('utf-8'))
def test_format_unicode_error(self):
message = b'\xec\xa0\x95\xec\x88\x98\xec\xa0\x95'
output = self.formatter.format(make_log_record(logging.ERROR, message))
expected = colors.red('ERROR') + ': '
- assert output == '{0}{1}'.format(expected, message.decode('utf-8'))
+ assert output == '{}{}'.format(expected, message.decode('utf-8'))
diff --git a/tests/unit/cli/log_printer_test.py b/tests/unit/cli/log_printer_test.py
index 38dd56c7..aeeed31f 100644
--- a/tests/unit/cli/log_printer_test.py
+++ b/tests/unit/cli/log_printer_test.py
@@ -29,7 +29,7 @@ def mock_container():
return mock.Mock(spec=Container, name_without_project='web_1')
-class TestLogPresenter(object):
+class TestLogPresenter:
def test_monochrome(self, mock_container):
presenters = build_log_presenters(['foo', 'bar'], True)
@@ -83,7 +83,7 @@ def test_build_no_log_generator(mock_container):
assert "exited with code" not in output
-class TestBuildLogGenerator(object):
+class TestBuildLogGenerator:
def test_no_log_stream(self, mock_container):
mock_container.log_stream = None
@@ -108,7 +108,7 @@ class TestBuildLogGenerator(object):
assert next(generator) == "world"
def test_unicode(self, output_stream):
- glyph = u'\u2022\n'
+ glyph = '\u2022\n'
mock_container.log_stream = iter([glyph.encode('utf-8')])
generator = build_log_generator(mock_container, {})
@@ -125,7 +125,7 @@ def mock_presenters():
return itertools.cycle([mock.Mock()])
-class TestWatchEvents(object):
+class TestWatchEvents:
def test_stop_event(self, thread_map, mock_presenters):
event_stream = [{'action': 'stop', 'id': 'cid'}]
@@ -167,7 +167,7 @@ class TestWatchEvents(object):
assert container_id not in thread_map
-class TestConsumeQueue(object):
+class TestConsumeQueue:
def test_item_is_an_exception(self):
diff --git a/tests/unit/cli/main_test.py b/tests/unit/cli/main_test.py
index ac3df292..d75b6bd4 100644
--- a/tests/unit/cli/main_test.py
+++ b/tests/unit/cli/main_test.py
@@ -22,7 +22,7 @@ def mock_container(service, number):
container.Container,
service=service,
number=number,
- name_without_project='{0}_{1}'.format(service, number))
+ name_without_project='{}_{}'.format(service, number))
@pytest.fixture
@@ -32,7 +32,7 @@ def logging_handler():
return logging.StreamHandler(stream=stream)
-class TestCLIMainTestCase(object):
+class TestCLIMainTestCase:
def test_filter_attached_containers(self):
containers = [
@@ -135,7 +135,7 @@ class TestCLIMainTestCase(object):
assert expected_docker_start_call == docker_start_call
-class TestSetupConsoleHandlerTestCase(object):
+class TestSetupConsoleHandlerTestCase:
def test_with_tty_verbose(self, logging_handler):
setup_console_handler(logging_handler, True)
@@ -155,7 +155,7 @@ class TestSetupConsoleHandlerTestCase(object):
assert type(logging_handler.formatter) == logging.Formatter
-class TestConvergeStrategyFromOptsTestCase(object):
+class TestConvergeStrategyFromOptsTestCase:
def test_invalid_opts(self):
options = {'--force-recreate': True, '--no-recreate': True}
@@ -189,7 +189,7 @@ def mock_find_executable(exe):
@mock.patch('compose.cli.main.find_executable', mock_find_executable)
-class TestCallDocker(object):
+class TestCallDocker:
def test_simple_no_options(self):
with mock.patch('subprocess.call') as fake_call:
call_docker(['ps'], {}, {})
diff --git a/tests/unit/cli_test.py b/tests/unit/cli_test.py
index 2c53e00a..f1a3e270 100644
--- a/tests/unit/cli_test.py
+++ b/tests/unit/cli_test.py
@@ -1,4 +1,3 @@
-# encoding: utf-8
import os
import shutil
import tempfile
diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py
index f562141d..03e95f77 100644
--- a/tests/unit/config/config_test.py
+++ b/tests/unit/config/config_test.py
@@ -1,4 +1,3 @@
-# encoding: utf-8
import codecs
import os
import shutil
@@ -3885,12 +3884,12 @@ class VolumeConfigTest(unittest.TestCase):
assert d['volumes'] == ['~:/data']
def test_volume_path_with_non_ascii_directory(self):
- volume = u'/Füü/data:/data'
+ volume = '/Füü/data:/data'
container_path = config.resolve_volume_path(".", volume)
assert container_path == volume
-class MergePathMappingTest(object):
+class MergePathMappingTest:
config_name = ""
def test_empty(self):
@@ -3963,7 +3962,7 @@ class BuildOrImageMergeTest(unittest.TestCase):
assert config.merge_service_dicts({'image': 'redis'}, {'build': '.'}, V1) == {'build': '.'}
-class MergeListsTest(object):
+class MergeListsTest:
config_name = ""
base_config = []
override_config = []
@@ -4396,7 +4395,7 @@ class EnvTest(unittest.TestCase):
{'env_file': ['tests/fixtures/env/resolve.env']},
Environment.from_env_file(None)
) == {
- 'FILE_DEF': u'bär',
+ 'FILE_DEF': 'bär',
'FILE_DEF_EMPTY': '',
'ENV_DEF': 'E3',
'NO_DEF': None
@@ -5042,14 +5041,14 @@ class VolumePathTest(unittest.TestCase):
container_path = 'c:\\scarletdevil\\data'
expected_mapping = (container_path, (host_path, None))
- mapping = config.split_path_mapping('{0}:{1}'.format(host_path, container_path))
+ mapping = config.split_path_mapping('{}:{}'.format(host_path, container_path))
assert mapping == expected_mapping
def test_split_path_mapping_with_root_mount(self):
host_path = '/'
container_path = '/var/hostroot'
expected_mapping = (container_path, (host_path, None))
- mapping = config.split_path_mapping('{0}:{1}'.format(host_path, container_path))
+ mapping = config.split_path_mapping('{}:{}'.format(host_path, container_path))
assert mapping == expected_mapping
diff --git a/tests/unit/config/environment_test.py b/tests/unit/config/environment_test.py
index 50738546..6a80ff12 100644
--- a/tests/unit/config/environment_test.py
+++ b/tests/unit/config/environment_test.py
@@ -1,4 +1,3 @@
-# encoding: utf-8
import codecs
import os
import shutil
diff --git a/tests/unit/config/interpolation_test.py b/tests/unit/config/interpolation_test.py
index f8ff8c66..6f3533d0 100644
--- a/tests/unit/config/interpolation_test.py
+++ b/tests/unit/config/interpolation_test.py
@@ -1,4 +1,3 @@
-# encoding: utf-8
import pytest
from compose.config.environment import Environment
@@ -439,7 +438,7 @@ def test_unbraced_separators(defaults_interpolator):
def test_interpolate_unicode_values():
variable_mapping = {
- 'FOO': '十六夜 咲夜'.encode('utf-8'),
+ 'FOO': '十六夜 咲夜'.encode(),
'BAR': '十六夜 咲夜'
}
interpol = Interpolator(TemplateWithDefaults, variable_mapping).interpolate
diff --git a/tests/unit/config/sort_services_test.py b/tests/unit/config/sort_services_test.py
index 430fed6a..508c4bba 100644
--- a/tests/unit/config/sort_services_test.py
+++ b/tests/unit/config/sort_services_test.py
@@ -5,7 +5,7 @@ from compose.config.sort_services import sort_service_dicts
from compose.config.types import VolumeFromSpec
-class TestSortService(object):
+class TestSortService:
def test_sort_service_dicts_1(self):
services = [
{
diff --git a/tests/unit/config/types_test.py b/tests/unit/config/types_test.py
index 23b9b676..e5fcde1a 100644
--- a/tests/unit/config/types_test.py
+++ b/tests/unit/config/types_test.py
@@ -39,7 +39,7 @@ def test_parse_extra_hosts_dict():
}
-class TestServicePort(object):
+class TestServicePort:
def test_parse_dict(self):
data = {
'target': 8000,
@@ -129,7 +129,7 @@ class TestServicePort(object):
ServicePort.parse(port_def)
-class TestVolumeSpec(object):
+class TestVolumeSpec:
def test_parse_volume_spec_only_one_path(self):
spec = VolumeSpec.parse('/the/volume')
@@ -216,7 +216,7 @@ class TestVolumeSpec(object):
)
-class TestVolumesFromSpec(object):
+class TestVolumesFromSpec:
services = ['servicea', 'serviceb']
diff --git a/tests/unit/progress_stream_test.py b/tests/unit/progress_stream_test.py
index b885b239..288c9b6e 100644
--- a/tests/unit/progress_stream_test.py
+++ b/tests/unit/progress_stream_test.py
@@ -1,5 +1,3 @@
-# ~*~ encoding: utf-8 ~*~
-import io
import os
import random
import shutil
@@ -75,7 +73,7 @@ class ProgressStreamTestCase(unittest.TestCase):
def mktempfile(encoding):
fname = os.path.join(tmpdir, hex(random.getrandbits(128))[2:-1])
- return io.open(fname, mode='w+', encoding=encoding)
+ return open(fname, mode='w+', encoding=encoding)
text = '就吃饭'
with mktempfile(encoding='utf-8') as tf:
diff --git a/tests/unit/project_test.py b/tests/unit/project_test.py
index b889e5e2..01f0b11e 100644
--- a/tests/unit/project_test.py
+++ b/tests/unit/project_test.py
@@ -1,4 +1,3 @@
-# encoding: utf-8
import datetime
import os
import tempfile
@@ -739,7 +738,7 @@ class ProjectTest(unittest.TestCase):
assert fake_log.warn.call_count == 0
def test_no_such_service_unicode(self):
- assert NoSuchService('十六夜 咲夜'.encode('utf-8')).msg == 'No such service: 十六夜 咲夜'
+ assert NoSuchService('十六夜 咲夜'.encode()).msg == 'No such service: 十六夜 咲夜'
assert NoSuchService('十六夜 咲夜').msg == 'No such service: 十六夜 咲夜'
def test_project_platform_value(self):
diff --git a/tests/unit/service_test.py b/tests/unit/service_test.py
index d4e7f3c5..72cb1d7f 100644
--- a/tests/unit/service_test.py
+++ b/tests/unit/service_test.py
@@ -63,9 +63,9 @@ class ServiceTest(unittest.TestCase):
assert [c.id for c in service.containers()] == list(range(3))
expected_labels = [
- '{0}=myproject'.format(LABEL_PROJECT),
- '{0}=db'.format(LABEL_SERVICE),
- '{0}=False'.format(LABEL_ONE_OFF),
+ '{}=myproject'.format(LABEL_PROJECT),
+ '{}=db'.format(LABEL_SERVICE),
+ '{}=False'.format(LABEL_ONE_OFF),
]
self.mock_client.containers.assert_called_once_with(
diff --git a/tests/unit/split_buffer_test.py b/tests/unit/split_buffer_test.py
index f1974c83..d6b5b884 100644
--- a/tests/unit/split_buffer_test.py
+++ b/tests/unit/split_buffer_test.py
@@ -36,7 +36,7 @@ class SplitBufferTest(unittest.TestCase):
self.assert_produces(reader, ['abc\n', 'd'])
def test_preserves_unicode_sequences_within_lines(self):
- string = u"a\u2022c\n"
+ string = "a\u2022c\n"
def reader():
yield string.encode('utf-8')
diff --git a/tests/unit/utils_test.py b/tests/unit/utils_test.py
index f1febc13..3052e4d8 100644
--- a/tests/unit/utils_test.py
+++ b/tests/unit/utils_test.py
@@ -1,8 +1,7 @@
-# encoding: utf-8
from compose import utils
-class TestJsonSplitter(object):
+class TestJsonSplitter:
def test_json_splitter_no_object(self):
data = '{"foo": "bar'
@@ -17,7 +16,7 @@ class TestJsonSplitter(object):
assert utils.json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}')
-class TestStreamAsText(object):
+class TestStreamAsText:
def test_stream_with_non_utf_unicode_character(self):
stream = [b'\xed\xf3\xf3']
@@ -25,12 +24,12 @@ class TestStreamAsText(object):
assert output == '���'
def test_stream_with_utf_character(self):
- stream = ['ěĝ'.encode('utf-8')]
+ stream = ['ěĝ'.encode()]
output, = utils.stream_as_text(stream)
assert output == 'ěĝ'
-class TestJsonStream(object):
+class TestJsonStream:
def test_with_falsy_entries(self):
stream = [
@@ -59,7 +58,7 @@ class TestJsonStream(object):
]
-class TestParseBytes(object):
+class TestParseBytes:
def test_parse_bytes(self):
assert utils.parse_bytes('123kb') == 123 * 1024
assert utils.parse_bytes(123) == 123
@@ -67,7 +66,7 @@ class TestParseBytes(object):
assert utils.parse_bytes('123') == 123
-class TestMoreItertools(object):
+class TestMoreItertools:
def test_unique_everseen(self):
unique = utils.unique_everseen
assert list(unique([2, 1, 2, 1])) == [2, 1]
diff --git a/tests/unit/volume_test.py b/tests/unit/volume_test.py
index 8b2f6cfe..0dfbfcd4 100644
--- a/tests/unit/volume_test.py
+++ b/tests/unit/volume_test.py
@@ -10,7 +10,7 @@ def mock_client():
return mock.create_autospec(docker.APIClient)
-class TestVolume(object):
+class TestVolume:
def test_remove_local_volume(self, mock_client):
vol = volume.Volume(mock_client, 'foo', 'project')