Merge pull request #541 from pytest-dev/emancipation
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
environment:
|
||||
matrix:
|
||||
- TOXENV: "py27-pytestlatest"
|
||||
- TOXENV: "py35-pytestlatest"
|
||||
- TOXENV: "py36-pytestlatest"
|
||||
- TOXENV: "py37-pytestlatest"
|
||||
|
||||
@@ -3,7 +3,7 @@ repos:
|
||||
rev: 19.10b0
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
args: [--safe, --quiet, --target-version, py35]
|
||||
language_version: python3.7
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v2.4.0
|
||||
|
||||
@@ -32,8 +32,6 @@ jobs:
|
||||
- $HOME/.cache/pre-commit
|
||||
- python: '3.8'
|
||||
env: TOXENV=py38-pytestlatest
|
||||
- python: '2.7'
|
||||
env: TOXENV=py27-pytestlatest
|
||||
|
||||
- stage: test
|
||||
python: "3.5"
|
||||
|
||||
31
ISSUES.txt
31
ISSUES.txt
@@ -1,31 +0,0 @@
|
||||
next release critical
|
||||
-----------------------------------------------
|
||||
tag: bug
|
||||
|
||||
miserably fails: --dist=each --tx popen --tx socket=...
|
||||
|
||||
|
||||
rename / hooks
|
||||
-----------------------------------------------
|
||||
tag: bug
|
||||
|
||||
node -> slave
|
||||
transition for hooks?
|
||||
configure_node -> configure_slave
|
||||
|
||||
allow to remotely run xdist tests with xdist
|
||||
-----------------------------------------------
|
||||
tag: feature
|
||||
|
||||
allow to run xdist own tests using its own mechanism.
|
||||
currently this doesn't work because the remote side
|
||||
has no pytest plugin. How to configure/do
|
||||
register "xdist.plugin" on the remote side?
|
||||
|
||||
see to avoid any "from _pytest" internal imports
|
||||
-----------------------------------------------
|
||||
tag: feature
|
||||
|
||||
currently tests and even xdist core code imports
|
||||
names from the internal _pytest namespace.
|
||||
See to avoid it.
|
||||
1
changelog/541.removal.rst
Normal file
1
changelog/541.removal.rst
Normal file
@@ -0,0 +1 @@
|
||||
Drop backward-compatibility "slave" aliases related to worker nodes. We deliberately moved away from this terminology years ago, and it seems like the right time to finish the deprecation and removal process.
|
||||
1
changelog/541.trivial.rst
Normal file
1
changelog/541.trivial.rst
Normal file
@@ -0,0 +1 @@
|
||||
``pytest-xdist`` now requires ``pytest>=6.0``.
|
||||
1
changelog/569.removal.rst
Normal file
1
changelog/569.removal.rst
Normal file
@@ -0,0 +1 @@
|
||||
``pytest-xdist`` no longer supports Python 2.7.
|
||||
16
setup.py
16
setup.py
@@ -1,12 +1,6 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
install_requires = [
|
||||
"execnet>=1.1",
|
||||
"psutil>=3.0.0",
|
||||
"pytest>=4.4.0",
|
||||
"pytest-forked",
|
||||
"six",
|
||||
]
|
||||
install_requires = ["execnet>=1.1", "psutil>=3.0.0", "pytest>=6.0.0", "pytest-forked"]
|
||||
|
||||
|
||||
with open("README.rst") as f:
|
||||
@@ -15,8 +9,7 @@ with open("README.rst") as f:
|
||||
setup(
|
||||
name="pytest-xdist",
|
||||
use_scm_version={"write_to": "src/xdist/_version.py"},
|
||||
description="pytest xdist plugin for distributed testing"
|
||||
" and loop-on-failing modes",
|
||||
description="pytest xdist plugin for distributed testing and loop-on-failing modes",
|
||||
long_description=long_description,
|
||||
license="MIT",
|
||||
author="holger krekel and contributors",
|
||||
@@ -30,7 +23,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.*, !=3.4.*",
|
||||
python_requires=">=3.5",
|
||||
install_requires=install_requires,
|
||||
setup_requires=["setuptools_scm"],
|
||||
classifiers=[
|
||||
@@ -45,9 +38,8 @@ setup(
|
||||
"Topic :: Software Development :: Quality Assurance",
|
||||
"Topic :: Utilities",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
|
||||
@@ -10,14 +10,14 @@ from xdist.scheduler import (
|
||||
)
|
||||
|
||||
|
||||
from six.moves.queue import Empty, Queue
|
||||
from queue import Empty, Queue
|
||||
|
||||
|
||||
class Interrupted(KeyboardInterrupt):
|
||||
""" signals an immediate interruption. """
|
||||
|
||||
|
||||
class DSession(object):
|
||||
class DSession:
|
||||
"""A pytest plugin which runs a distributed test session
|
||||
|
||||
At the beginning of the test session this creates a NodeManager
|
||||
@@ -150,9 +150,6 @@ class DSession(object):
|
||||
node.workerinfo["id"] = node.gateway.id
|
||||
node.workerinfo["spec"] = node.gateway.spec
|
||||
|
||||
# TODO: (#234 task) needs this for pytest. Remove when refactor in pytest repo
|
||||
node.slaveinfo = node.workerinfo
|
||||
|
||||
self.config.hook.pytest_testnodeready(node=node)
|
||||
if self.shuttingdown:
|
||||
node.shutdown()
|
||||
@@ -336,7 +333,7 @@ class DSession(object):
|
||||
self.config.hook.pytest_runtest_logreport(report=rep)
|
||||
|
||||
|
||||
class TerminalDistReporter(object):
|
||||
class TerminalDistReporter:
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.tr = config.pluginmanager.getplugin("terminalreporter")
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
processes) otherwise changes to source code can crash
|
||||
the controlling process which should best never happen.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
import py
|
||||
import pytest
|
||||
import sys
|
||||
@@ -55,7 +54,7 @@ def looponfail_main(config):
|
||||
print()
|
||||
|
||||
|
||||
class RemoteControl(object):
|
||||
class RemoteControl:
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.failures = []
|
||||
@@ -165,7 +164,7 @@ def init_worker_session(channel, args, option_dict):
|
||||
WorkerFailSession(config, channel).main()
|
||||
|
||||
|
||||
class WorkerFailSession(object):
|
||||
class WorkerFailSession:
|
||||
def __init__(self, config, channel):
|
||||
self.config = config
|
||||
self.channel = channel
|
||||
@@ -220,7 +219,7 @@ class WorkerFailSession(object):
|
||||
self.channel.send((trails, failreports, self.collection_failed))
|
||||
|
||||
|
||||
class StatRecorder(object):
|
||||
class StatRecorder:
|
||||
def __init__(self, rootdirlist):
|
||||
self.rootdirlist = rootdirlist
|
||||
self.statcache = {}
|
||||
|
||||
@@ -43,14 +43,11 @@ def pytest_addoption(parser):
|
||||
)
|
||||
group.addoption(
|
||||
"--max-worker-restart",
|
||||
"--max-slave-restart",
|
||||
action="store",
|
||||
default=None,
|
||||
dest="maxworkerrestart",
|
||||
help="maximum number of workers that can be restarted "
|
||||
"when crashed (set to zero to disable this feature)\n"
|
||||
"'--max-slave-restart' option is deprecated and will be removed in "
|
||||
"a future release",
|
||||
"when crashed (set to zero to disable this feature)",
|
||||
)
|
||||
group.addoption(
|
||||
"--dist",
|
||||
|
||||
@@ -18,7 +18,7 @@ from execnet.gateway_base import dumps, DumpError
|
||||
from _pytest.config import _prepareconfig, Config
|
||||
|
||||
|
||||
class WorkerInteractor(object):
|
||||
class WorkerInteractor:
|
||||
def __init__(self, config, channel):
|
||||
self.config = config
|
||||
self.workerid = config.workerinput.get("workerid", "?")
|
||||
@@ -266,8 +266,5 @@ if __name__ == "__channelexec__":
|
||||
config._parser.prog = os.path.basename(workerinput["mainargv"][0])
|
||||
config.workerinput = workerinput
|
||||
config.workeroutput = {}
|
||||
# TODO: deprecated name, backward compatibility only. Remove it in future
|
||||
config.slaveinput = config.workerinput
|
||||
config.slaveoutput = config.workeroutput
|
||||
interactor = WorkerInteractor(config, channel)
|
||||
config.hook.pytest_cmdline_main(config=config)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from __future__ import print_function
|
||||
from difflib import unified_diff
|
||||
|
||||
|
||||
@@ -13,9 +12,9 @@ def report_collection_diff(from_collection, to_collection, from_id, to_id):
|
||||
|
||||
diff = unified_diff(from_collection, to_collection, fromfile=from_id, tofile=to_id)
|
||||
error_message = (
|
||||
u"Different tests were collected between {from_id} and {to_id}. "
|
||||
u"The difference is:\n"
|
||||
u"{diff}"
|
||||
"Different tests were collected between {from_id} and {to_id}. "
|
||||
"The difference is:\n"
|
||||
"{diff}"
|
||||
).format(from_id=from_id, to_id=to_id, diff="\n".join(diff))
|
||||
msg = "\n".join([x.rstrip() for x in error_message.split("\n")])
|
||||
return msg
|
||||
|
||||
@@ -4,7 +4,7 @@ from xdist.workermanage import parse_spec_config
|
||||
from xdist.report import report_collection_diff
|
||||
|
||||
|
||||
class EachScheduling(object):
|
||||
class EachScheduling:
|
||||
"""Implement scheduling of test items on all nodes
|
||||
|
||||
If a node gets added after the test run is started then it is
|
||||
|
||||
@@ -7,7 +7,7 @@ from xdist.workermanage import parse_spec_config
|
||||
from xdist.report import report_collection_diff
|
||||
|
||||
|
||||
class LoadScheduling(object):
|
||||
class LoadScheduling:
|
||||
"""Implement load scheduling across nodes.
|
||||
|
||||
This distributes the tests collected across all nodes so each test
|
||||
|
||||
@@ -21,7 +21,7 @@ class LoadFileScheduling(LoadScopeScheduling):
|
||||
"""
|
||||
|
||||
def __init__(self, config, log=None):
|
||||
super(LoadFileScheduling, self).__init__(config, log)
|
||||
super().__init__(config, log)
|
||||
if log is None:
|
||||
self.log = Producer("loadfilesched")
|
||||
else:
|
||||
|
||||
@@ -6,7 +6,7 @@ from xdist.report import report_collection_diff
|
||||
from xdist.workermanage import parse_spec_config
|
||||
|
||||
|
||||
class LoadScopeScheduling(object):
|
||||
class LoadScopeScheduling:
|
||||
"""Implement load scheduling across nodes, but grouping test by scope.
|
||||
|
||||
This distributes the tests collected across all nodes so each test is run
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from __future__ import print_function
|
||||
import fnmatch
|
||||
import os
|
||||
import re
|
||||
@@ -29,7 +28,7 @@ def parse_spec_config(config):
|
||||
return xspeclist
|
||||
|
||||
|
||||
class NodeManager(object):
|
||||
class NodeManager:
|
||||
EXIT_TIMEOUT = 10
|
||||
DEFAULT_IGNORES = [".*", "*.pyc", "*.pyo", "*~"]
|
||||
|
||||
@@ -167,7 +166,7 @@ class HostRSync(execnet.RSync):
|
||||
self._ignores = [
|
||||
re.compile(fnmatch.translate(getattr(x, "strpath", x))) for x in ignores
|
||||
]
|
||||
super(HostRSync, self).__init__(sourcedir=sourcedir, **kwargs)
|
||||
super().__init__(sourcedir=sourcedir, **kwargs)
|
||||
|
||||
def filter(self, path):
|
||||
path = py.path.local(path)
|
||||
@@ -179,9 +178,7 @@ class HostRSync(execnet.RSync):
|
||||
|
||||
def add_target_host(self, gateway, finished=None):
|
||||
remotepath = os.path.basename(self._sourcedir)
|
||||
super(HostRSync, self).add_target(
|
||||
gateway, remotepath, finishedcallback=finished, delete=True
|
||||
)
|
||||
super().add_target(gateway, remotepath, finishedcallback=finished, delete=True)
|
||||
|
||||
def _report_send_file(self, gateway, modified_rel_path):
|
||||
if self._verbose:
|
||||
@@ -211,7 +208,7 @@ def make_reltoroot(roots, args):
|
||||
return result
|
||||
|
||||
|
||||
class WorkerController(object):
|
||||
class WorkerController:
|
||||
ENDMARK = -1
|
||||
|
||||
class RemoteHook:
|
||||
@@ -228,13 +225,9 @@ class WorkerController(object):
|
||||
self.workerinput = {
|
||||
"workerid": gateway.id,
|
||||
"workercount": len(nodemanager.specs),
|
||||
"slaveid": gateway.id,
|
||||
"slavecount": len(nodemanager.specs),
|
||||
"testrunuid": nodemanager.testrunuid,
|
||||
"mainargv": sys.argv,
|
||||
}
|
||||
# TODO: deprecated name, backward compatibility only. Remove it in future
|
||||
self.slaveinput = self.workerinput
|
||||
self._down = False
|
||||
self._shutdown_sent = False
|
||||
self.log = py.log.Producer("workerctl-%s" % gateway.id)
|
||||
@@ -296,7 +289,7 @@ class WorkerController(object):
|
||||
if not self._down:
|
||||
try:
|
||||
self.sendcommand("shutdown")
|
||||
except (IOError, OSError):
|
||||
except OSError:
|
||||
pass
|
||||
self._shutdown_sent = True
|
||||
|
||||
@@ -333,7 +326,7 @@ class WorkerController(object):
|
||||
self.notify_inproc(eventname, node=self, **kwargs)
|
||||
elif eventname == "workerfinished":
|
||||
self._down = True
|
||||
self.workeroutput = self.slaveoutput = kwargs["workeroutput"]
|
||||
self.workeroutput = kwargs["workeroutput"]
|
||||
self.notify_inproc("workerfinished", node=self)
|
||||
elif eventname in ("logstart", "logfinish"):
|
||||
self.notify_inproc(eventname, node=self, **kwargs)
|
||||
|
||||
@@ -245,22 +245,6 @@ class TestDistribution:
|
||||
result.stderr.fnmatch_lines(["--foobar=123 active! *"])
|
||||
assert dest.join(subdir.basename).check(dir=1)
|
||||
|
||||
def test_backward_compatibility_worker_terminology(self, testdir):
|
||||
"""Ensure that we still support "config.slaveinput" for backward compatibility (#234).
|
||||
|
||||
Keep in mind that removing this compatibility will break a ton of plugins and user code.
|
||||
"""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test(pytestconfig):
|
||||
assert hasattr(pytestconfig, 'slaveinput')
|
||||
assert hasattr(pytestconfig, 'workerinput')
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest("-n1")
|
||||
result.stdout.fnmatch_lines("*1 passed*")
|
||||
assert result.ret == 0
|
||||
|
||||
def test_data_exchange(self, testdir):
|
||||
testdir.makeconftest(
|
||||
"""
|
||||
@@ -899,9 +883,6 @@ class TestWarnings:
|
||||
"""Check that warnings with unserializable _WARNING_DETAILS are
|
||||
handled correctly (#379).
|
||||
"""
|
||||
if sys.version_info[0] < 3:
|
||||
# The issue is only present in Python 3 warnings
|
||||
return
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import warnings, pytest
|
||||
|
||||
@@ -1,20 +1,9 @@
|
||||
import six
|
||||
import py
|
||||
import pytest
|
||||
import execnet
|
||||
|
||||
pytest_plugins = "pytester"
|
||||
|
||||
if six.PY2:
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def _ensure_imports():
|
||||
# we import some modules because pytest-2.8's testdir fixture
|
||||
# will unload all modules after each test and this cause
|
||||
# (unknown) problems with execnet.Group()
|
||||
execnet.Group
|
||||
execnet.makegateway
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _divert_atexit(request, monkeypatch):
|
||||
|
||||
@@ -203,7 +203,7 @@ class TestLoadScheduling:
|
||||
different test ids are collected by workers.
|
||||
"""
|
||||
|
||||
class CollectHook(object):
|
||||
class CollectHook:
|
||||
"""
|
||||
Dummy hook that stores collection reports.
|
||||
"""
|
||||
|
||||
@@ -8,7 +8,7 @@ from xdist.workermanage import WorkerController
|
||||
import execnet
|
||||
import marshal
|
||||
|
||||
from six.moves.queue import Queue
|
||||
from queue import Queue
|
||||
|
||||
WAIT_TIMEOUT = 10.0
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from __future__ import print_function
|
||||
import py
|
||||
import pytest
|
||||
import textwrap
|
||||
@@ -35,7 +34,7 @@ def mysetup(tmpdir):
|
||||
|
||||
@pytest.fixture
|
||||
def workercontroller(monkeypatch):
|
||||
class MockController(object):
|
||||
class MockController:
|
||||
def __init__(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user