Skip to content

Commit 4642f16

Browse files
authored
Merge pull request #448 from nicoddemus/config-init-test
Use Config.invocation_params for consistent worker initialization
2 parents a19d74d + 953a3f0 commit 4642f16

File tree

4 files changed

+55
-8
lines changed

4 files changed

+55
-8
lines changed

changelog/448.feature.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Initialization between workers and master nodes is now more consistent, which fixes a number of
2+
long-standing issues related to startup with the ``-c`` option.
3+
4+
Issues:
5+
6+
* `#6 <https://github.com/pytest-dev/pytest-xdist/issues/6>`__: Poor interaction between ``-n#`` and ``-c X.cfg``
7+
* `#445 <https://github.com/pytest-dev/pytest-xdist/issues/445>`__: pytest-xdist is not reporting the same nodeid as pytest does
8+
9+
This however only works with **pytest 5.1 or later**, as it required changes in pytest itself.

src/xdist/remote.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import pytest
1616
from execnet.gateway_base import dumps, DumpError
1717

18+
from _pytest.config import _prepareconfig, Config
19+
1820

1921
class WorkerInteractor(object):
2022
def __init__(self, config, channel):
@@ -211,18 +213,18 @@ def getinfodict():
211213

212214

213215
def remote_initconfig(option_dict, args):
214-
from _pytest.config import Config
215-
216216
option_dict["plugins"].append("no:terminal")
217-
config = Config.fromdictargs(option_dict, args)
217+
return Config.fromdictargs(option_dict, args)
218+
219+
220+
def setup_config(config, basetemp):
218221
config.option.looponfail = False
219222
config.option.usepdb = False
220223
config.option.dist = "no"
221224
config.option.distload = False
222225
config.option.numprocesses = None
223226
config.option.maxprocesses = None
224-
config.args = args
225-
return config
227+
config.option.basetemp = basetemp
226228

227229

228230
if __name__ == "__channelexec__":
@@ -239,7 +241,13 @@ def remote_initconfig(option_dict, args):
239241
os.environ["PYTEST_XDIST_WORKER"] = workerinput["workerid"]
240242
os.environ["PYTEST_XDIST_WORKER_COUNT"] = str(workerinput["workercount"])
241243

242-
config = remote_initconfig(option_dict, args)
244+
if hasattr(Config, "InvocationParams"):
245+
config = _prepareconfig(args, None)
246+
else:
247+
config = remote_initconfig(option_dict, args)
248+
config.args = args
249+
250+
setup_config(config, option_dict.get("basetemp"))
243251
config._parser.prog = os.path.basename(workerinput["mainargv"][0])
244252
config.workerinput = workerinput
245253
config.workeroutput = {}

src/xdist/workermanage.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ def make_reltoroot(roots, args):
186186
for arg in args:
187187
parts = arg.split(splitcode)
188188
fspath = py.path.local(parts[0])
189+
if not fspath.exists():
190+
continue
189191
for root in roots:
190192
x = fspath.relto(root)
191193
if x or fspath == root:
@@ -236,10 +238,14 @@ def shutting_down(self):
236238
def setup(self):
237239
self.log("setting up worker session")
238240
spec = self.gateway.spec
239-
args = self.config.args
241+
if hasattr(self.config, "invocation_params"):
242+
args = [str(x) for x in self.config.invocation_params.args or ()]
243+
option_dict = {}
244+
else:
245+
args = self.config.args
246+
option_dict = vars(self.config.option)
240247
if not spec.popen or spec.chdir:
241248
args = make_reltoroot(self.nodemanager.roots, args)
242-
option_dict = vars(self.config.option)
243249
if spec.popen:
244250
name = "popen-%s" % self.gateway.id
245251
if hasattr(self.config, "_tmpdirhandler"):

testing/acceptance_test.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,30 @@ def test_hello(myarg):
559559
assert result.ret
560560

561561

562+
def test_config_initialization(testdir, pytestconfig):
563+
"""Ensure workers and master are initialized consistently. Integration test for #445"""
564+
if not hasattr(pytestconfig, "invocation_params"):
565+
pytest.skip(
566+
"requires pytest >=5.1 (config has no attribute 'invocation_params')"
567+
)
568+
testdir.makepyfile(
569+
**{
570+
"dir_a/test_foo.py": """
571+
def test_1(): pass
572+
"""
573+
}
574+
)
575+
testdir.makefile(
576+
".ini",
577+
myconfig="""
578+
[pytest]
579+
testpaths=dir_a
580+
""",
581+
)
582+
result = testdir.runpytest("-n2", "-c", "myconfig.ini", "-v")
583+
result.stdout.fnmatch_lines(["dir_a/test_foo.py::test_1*"])
584+
585+
562586
@pytest.mark.parametrize("when", ["setup", "call", "teardown"])
563587
def test_crashing_item(testdir, when):
564588
"""Ensure crashing item is correctly reported during all testing stages"""

0 commit comments

Comments
 (0)