Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45ddc221ef | ||
|
|
c3dbd05bd1 | ||
|
|
b9423d894c | ||
|
|
242c009866 | ||
|
|
0ee219dc48 | ||
|
|
76075f5de1 | ||
|
|
f8d51aab57 | ||
|
|
ac2bf10fe2 | ||
|
|
fa85371c73 | ||
|
|
d55fab3aa7 | ||
|
|
4632df37a6 | ||
|
|
ca94bda1b7 | ||
|
|
261d4189f0 | ||
|
|
f283dddf36 |
@@ -1,3 +1,21 @@
|
||||
pytest-xdist 1.26.0 (2019-01-11)
|
||||
================================
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- `#376 <https://github.com/pytest-dev/pytest-xdist/issues/376>`_: The current directory is no longer added ``sys.path`` for local workers, only for remote connections.
|
||||
|
||||
This behavior is surprising because it makes xdist runs and non-xdist runs to potentially behave differently.
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#379 <https://github.com/pytest-dev/pytest-xdist/issues/379>`_: Warning attributes are checked to make sure they can be dumped prior to
|
||||
serializing the warning for submission to the master node.
|
||||
|
||||
|
||||
pytest-xdist 1.25.0 (2018-12-12)
|
||||
================================
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
import py
|
||||
@@ -738,10 +739,12 @@ def test_sub_plugins_disabled(testdir, plugin):
|
||||
class TestWarnings:
|
||||
@pytest.mark.parametrize("n", ["-n0", "-n1"])
|
||||
@pytest.mark.parametrize("warn_type", ["pytest", "builtin"])
|
||||
def test_warnings(self, testdir, n, warn_type):
|
||||
def test_warnings(self, testdir, n, request, warn_type):
|
||||
if warn_type == "builtin":
|
||||
warn_code = """warnings.warn(UserWarning('this is a warning'))"""
|
||||
elif warn_type == "pytest":
|
||||
if not hasattr(request.config, "warn"):
|
||||
pytest.skip("config.warn has been removed in pytest 4.1")
|
||||
warn_code = """request.config.warn('', 'this is a warning',
|
||||
fslocation=py.path.local())"""
|
||||
else:
|
||||
@@ -801,6 +804,39 @@ class TestWarnings:
|
||||
result = testdir.runpytest(n)
|
||||
result.stdout.fnmatch_lines(["*UserWarning*foo.txt*", "*1 passed, 1 warnings*"])
|
||||
|
||||
@pytest.mark.parametrize("n", ["-n0", "-n1"])
|
||||
def test_unserializable_warning_details(self, testdir, n):
|
||||
"""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
|
||||
import socket
|
||||
import gc
|
||||
def abuse_socket():
|
||||
s = socket.socket()
|
||||
del s
|
||||
|
||||
# Deliberately provoke a ResourceWarning for an unclosed socket.
|
||||
# The socket itself will end up attached as a value in
|
||||
# _WARNING_DETAIL. We need to test that it is not serialized
|
||||
# (it can't be, so the test will fail if we try to).
|
||||
@pytest.mark.filterwarnings('always')
|
||||
def test_func(tmpdir):
|
||||
abuse_socket()
|
||||
gc.collect()
|
||||
"""
|
||||
)
|
||||
testdir.syspathinsert()
|
||||
result = testdir.runpytest(n)
|
||||
result.stdout.fnmatch_lines(
|
||||
["*ResourceWarning*unclosed*", "*1 passed, 1 warnings*"]
|
||||
)
|
||||
|
||||
|
||||
class TestNodeFailure:
|
||||
def test_load_single(self, testdir):
|
||||
|
||||
@@ -218,7 +218,15 @@ def serialize_warning_message(warning_message):
|
||||
for attr_name in warning_message._WARNING_DETAILS:
|
||||
if attr_name in ("message", "category"):
|
||||
continue
|
||||
result[attr_name] = getattr(warning_message, attr_name)
|
||||
attr = getattr(warning_message, attr_name)
|
||||
# Check if we can serialize the warning detail, marking `None` otherwise
|
||||
# Note that we need to define the attr (even as `None`) to allow deserializing
|
||||
try:
|
||||
dumps(attr)
|
||||
except DumpError:
|
||||
result[attr_name] = repr(attr)
|
||||
else:
|
||||
result[attr_name] = attr
|
||||
return result
|
||||
|
||||
|
||||
@@ -251,17 +259,20 @@ def remote_initconfig(option_dict, args):
|
||||
|
||||
|
||||
if __name__ == "__channelexec__":
|
||||
import py
|
||||
|
||||
channel = channel # noqa
|
||||
workerinput, args, option_dict = channel.receive()
|
||||
workerinput, args, option_dict, change_sys_path = channel.receive()
|
||||
|
||||
if change_sys_path:
|
||||
importpath = os.getcwd()
|
||||
sys.path.insert(0, importpath) # XXX only for remote situations
|
||||
sys.path.insert(0, importpath)
|
||||
os.environ["PYTHONPATH"] = (
|
||||
importpath + os.pathsep + os.environ.get("PYTHONPATH", "")
|
||||
)
|
||||
|
||||
os.environ["PYTEST_XDIST_WORKER"] = workerinput["workerid"]
|
||||
os.environ["PYTEST_XDIST_WORKER_COUNT"] = str(workerinput["workercount"])
|
||||
# os.environ['PYTHONPATH'] = importpath
|
||||
import py
|
||||
|
||||
config = remote_initconfig(option_dict, args)
|
||||
config._parser.prog = os.path.basename(workerinput["mainargv"][0])
|
||||
|
||||
@@ -245,7 +245,9 @@ class WorkerController(object):
|
||||
option_dict["basetemp"] = str(basetemp.join(name))
|
||||
self.config.hook.pytest_configure_node(node=self)
|
||||
self.channel = self.gateway.remote_exec(xdist.remote)
|
||||
self.channel.send((self.workerinput, args, option_dict))
|
||||
# change sys.path only for remote workers
|
||||
change_sys_path = not self.gateway.spec.popen
|
||||
self.channel.send((self.workerinput, args, option_dict, change_sys_path))
|
||||
if self.putevent:
|
||||
self.channel.setcallback(self.process_from_remote, endmarker=self.ENDMARK)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user