diff --git a/.appveyor.yml b/.appveyor.yml index 8ece168..a275120 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,7 +1,6 @@ environment: matrix: - TOXENV: "py27-pytestlatest" - - TOXENV: "py34-pytestlatest" - TOXENV: "py35-pytestlatest" - TOXENV: "py36-pytestlatest" - TOXENV: "py37-pytestlatest" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9bd71da..04d0ce3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ repos: - repo: https://github.com/ambv/black - rev: 18.6b4 + rev: 19.10b0 hooks: - id: black args: [--safe, --quiet] language_version: python3.7 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v1.3.0 + rev: v2.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer diff --git a/.travis.yml b/.travis.yml index ed01656..3b25db0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,9 +36,7 @@ jobs: env: TOXENV=py27-pytestlatest - stage: test - python: "3.4" - env: TOXENV=py34-pytestlatest - - python: "3.5" + python: "3.5" env: TOXENV=py35-pytestlatest - python: "3.6" env: TOXENV=py36-pytestlatest diff --git a/changelog/475.removal b/changelog/475.removal new file mode 100644 index 0000000..60e26e4 --- /dev/null +++ b/changelog/475.removal @@ -0,0 +1 @@ +Drop support for EOL Python 3.4. diff --git a/setup.py b/setup.py index e50898f..3eac3be 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ setup( "pytest11": ["xdist = xdist.plugin", "xdist.looponfail = xdist.looponfail"] }, zip_safe=False, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", + python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", install_requires=install_requires, setup_requires=["setuptools_scm"], classifiers=[ @@ -42,7 +42,6 @@ setup( "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", diff --git a/src/xdist/dsession.py b/src/xdist/dsession.py index 04e9f13..7ac5f57 100644 --- a/src/xdist/dsession.py +++ b/src/xdist/dsession.py @@ -169,7 +169,7 @@ class DSession(object): """ self.config.hook.pytest_testnodedown(node=node, error=None) if node.workeroutput["exitstatus"] == 2: # keyboard-interrupt - self.shouldstop = "%s received keyboard-interrupt" % (node,) + self.shouldstop = "{} received keyboard-interrupt".format(node) self.worker_errordown(node, "keyboard-interrupt") return if node in self.sched.nodes: @@ -321,7 +321,7 @@ class DSession(object): # XXX count no of failures and retry N times runner = self.config.pluginmanager.getplugin("runner") fspath = nodeid.split("::")[0] - msg = "worker %r crashed while running %r" % (worker.gateway.id, nodeid) + msg = "worker {!r} crashed while running {!r}".format(worker.gateway.id, nodeid) rep = runner.TestReport( nodeid, (fspath, None, fspath), (), "failed", msg, "???" ) @@ -351,7 +351,9 @@ class TerminalDistReporter(object): def getstatus(self): if self.config.option.verbose >= 0: - parts = ["%s %s" % (spec.id, self._status[spec.id]) for spec in self._specs] + parts = [ + "{} {}".format(spec.id, self._status[spec.id]) for spec in self._specs + ] return " / ".join(parts) else: return "bringing up nodes..." @@ -386,14 +388,16 @@ class TerminalDistReporter(object): def pytest_testnodeready(self, node): if self.config.option.verbose > 0: d = node.workerinfo - infoline = "[%s] Python %s" % (d["id"], d["version"].replace("\n", " -- ")) + infoline = "[{}] Python {}".format( + d["id"], d["version"].replace("\n", " -- ") + ) self.rewrite(infoline, newline=True) self.setstatus(node.gateway.spec, "ok") def pytest_testnodedown(self, node, error): if not error: return - self.write_line("[%s] node down: %s" % (node.gateway.id, error)) + self.write_line("[{}] node down: {}".format(node.gateway.id, error)) def get_default_max_worker_restart(config): diff --git a/src/xdist/looponfail.py b/src/xdist/looponfail.py index 65813b7..7f01ad6 100644 --- a/src/xdist/looponfail.py +++ b/src/xdist/looponfail.py @@ -136,7 +136,7 @@ def repr_pytest_looponfailinfo(failreports, rootdirs): tr.line(report, red=True) tr.sep("#", "waiting for changes", bold=True) for rootdir in rootdirs: - tr.line("### Watching: %s" % (rootdir,), bold=True) + tr.line("### Watching: {}".format(rootdir), bold=True) def init_worker_session(channel, args, option_dict): diff --git a/src/xdist/scheduler/loadscope.py b/src/xdist/scheduler/loadscope.py index 426d340..6b50a48 100644 --- a/src/xdist/scheduler/loadscope.py +++ b/src/xdist/scheduler/loadscope.py @@ -358,12 +358,12 @@ class LoadScopeScheduling(object): extra_nodes = len(self.nodes) - len(self.workqueue) if extra_nodes > 0: - self.log("Shuting down {0} nodes".format(extra_nodes)) + self.log("Shuting down {} nodes".format(extra_nodes)) for _ in range(extra_nodes): unused_node, assigned = self.assigned_work.popitem(last=True) - self.log("Shuting down unused node {0}".format(unused_node)) + self.log("Shuting down unused node {}".format(unused_node)) unused_node.shutdown() # Assign initial workload diff --git a/src/xdist/workermanage.py b/src/xdist/workermanage.py index 5f30edf..af5241f 100644 --- a/src/xdist/workermanage.py +++ b/src/xdist/workermanage.py @@ -101,7 +101,7 @@ class NodeManager(object): for root in candidates: root = py.path.local(root).realpath() if not root.check(): - raise pytest.UsageError("rsyncdir doesn't exist: %r" % (root,)) + raise pytest.UsageError("rsyncdir doesn't exist: {!r}".format(root)) if root not in roots: roots.append(root) return roots @@ -179,7 +179,7 @@ class HostRSync(execnet.RSync): if self._verbose: path = os.path.basename(self._sourcedir) + "/" + modified_rel_path remotepath = gateway.spec.chdir - print("%s:%s <= %s" % (gateway.spec, remotepath, path)) + print("{}:{} <= {}".format(gateway.spec, remotepath, path)) def make_reltoroot(roots, args): @@ -198,7 +198,7 @@ def make_reltoroot(roots, args): parts[0] = root.basename + "/" + x break else: - raise ValueError("arg %s not relative to an rsync root" % (arg,)) + raise ValueError("arg {} not relative to an rsync root".format(arg)) result.append(splitcode.join(parts)) return result @@ -233,7 +233,7 @@ class WorkerController(object): py.log.setconsumer(self.log._keywords, None) def __repr__(self): - return "<%s %s>" % (self.__class__.__name__, self.gateway.id) + return "<{} {}>".format(self.__class__.__name__, self.gateway.id) @property def shutting_down(self): @@ -293,11 +293,11 @@ class WorkerController(object): def sendcommand(self, name, **kwargs): """ send a named parametrized command to the other side. """ - self.log("sending command %s(**%s)" % (name, kwargs)) + self.log("sending command {}(**{})".format(name, kwargs)) self.channel.send((name, kwargs)) def notify_inproc(self, eventname, **kwargs): - self.log("queuing %s(**%s)" % (eventname, kwargs)) + self.log("queuing {}(**{})".format(eventname, kwargs)) self.putevent((eventname, kwargs)) def process_from_remote(self, eventcall): # noqa too complex @@ -319,7 +319,7 @@ class WorkerController(object): return eventname, kwargs = eventcall if eventname in ("collectionstart",): - self.log("ignoring %s(%s)" % (eventname, kwargs)) + self.log("ignoring {}({})".format(eventname, kwargs)) elif eventname == "workerready": self.notify_inproc(eventname, node=self, **kwargs) elif eventname == "workerfinished": @@ -359,7 +359,7 @@ class WorkerController(object): item=kwargs["item"], ) else: - raise ValueError("unknown event: %s" % (eventname,)) + raise ValueError("unknown event: {}".format(eventname)) except KeyboardInterrupt: # should not land in receiver-thread raise diff --git a/testing/test_remote.py b/testing/test_remote.py index c9c4e30..81d8153 100644 --- a/testing/test_remote.py +++ b/testing/test_remote.py @@ -25,7 +25,7 @@ class EventCall: self.name, self.kwargs = eventcall def __str__(self): - return "" % (self.name, self.kwargs) + return "".format(self.name, self.kwargs) class WorkerSetup: @@ -59,7 +59,7 @@ class WorkerSetup: ev = EventCall(data) if name is None or ev.name == name: return ev - print("skipping %s" % (ev,)) + print("skipping {}".format(ev)) def sendcommand(self, name, **kwargs): self.slp.sendcommand(name, **kwargs) diff --git a/testing/test_slavemanage.py b/testing/test_slavemanage.py index c15d70f..47d2cba 100644 --- a/testing/test_slavemanage.py +++ b/testing/test_slavemanage.py @@ -168,7 +168,7 @@ class TestNodeManager: # assert nodemanager.config.topdir == source == config.topdir nodemanager.makegateways() nodemanager.rsync_roots() - p, = nodemanager.gwmanager.multi_exec( + (p,) = nodemanager.gwmanager.multi_exec( "import os ; channel.send(os.getcwd())" ).receive_each() p = py.path.local(p) @@ -269,5 +269,5 @@ class TestNodeManager: reprec = testdir.inline_run( "-d", "--rsyncdir=%s" % testdir.tmpdir, "--tx", specssh, testdir.tmpdir ) - rep, = reprec.getreports("pytest_runtest_logreport") + (rep,) = reprec.getreports("pytest_runtest_logreport") assert rep.passed diff --git a/tox.ini b/tox.ini index 3a52a95..98e0bd1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist= linting - py{27,34,35,36,37,38}-pytestlatest + py{27,35,36,37,38}-pytestlatest py38-pytest{master,features} [testenv]