Hello community,
here is the log from the commit of package python-pytest-xdist for
openSUSE:Factory checked in at 2019-02-24 17:04:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pytest-xdist (Old)
and /work/SRC/openSUSE:Factory/.python-pytest-xdist.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pytest-xdist"
Sun Feb 24 17:04:27 2019 rev:8 rq:674153 version:1.26.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pytest-xdist/python-pytest-xdist.changes
2018-11-08 09:39:23.725736040 +0100
+++
/work/SRC/openSUSE:Factory/.python-pytest-xdist.new.28833/python-pytest-xdist.changes
2019-02-24 17:04:34.976646573 +0100
@@ -1,0 +2,13 @@
+Tue Feb 12 12:57:15 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 1.26.1:
+ * #406: Do not implement deprecated pytest_logwarning hook in pytest
versions where it is deprecated.
+ * #376: The current directory is no longer added sys.path for local workers,
only for remote connections.
+ * #379: Warning attributes are checked to make sure they can be dumped prior
to serializing the warning for submission to the master node.
+ * #372: Pytest versions older than 3.6 are no longer supported.
+ * #373: Node setup information is hidden when pytest is run in quiet mode to
reduce noise on many-core machines.
+ * #388: mainargv is made available in workerinput from the host's sys.argv.
+ * #384: pytest 4.1 support: ExceptionInfo API changes.
+ * #390: pytest 4.1 support: pytest_logwarning hook removed.
+
+-------------------------------------------------------------------
Old:
----
pytest-xdist-1.23.2.tar.gz
New:
----
pytest-xdist-1.26.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pytest-xdist.spec ++++++
--- /var/tmp/diff_new_pack.m7q3p1/_old 2019-02-24 17:04:35.768646196 +0100
+++ /var/tmp/diff_new_pack.m7q3p1/_new 2019-02-24 17:04:35.768646196 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-pytest-xdist
#
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,18 +18,23 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-pytest-xdist
-Version: 1.23.2
+Version: 1.26.1
Release: 0
Summary: Distributed testing and loop-on-failing for py.test
License: MIT
Group: Development/Languages/Python
-Url: https://bitbucket.org/pytest-dev/pytest-xdist
+Url: https://github.com/pytest-dev/pytest-xdist
Source0:
https://files.pythonhosted.org/packages/source/p/pytest-xdist/pytest-xdist-%{version}.tar.gz
+BuildRequires: %{python_module execnet >= 1.1}
+BuildRequires: %{python_module filelock}
+BuildRequires: %{python_module pytest >= 3.6.0}
+BuildRequires: %{python_module pytest-forked}
BuildRequires: %{python_module setuptools_scm}
+BuildRequires: %{python_module six}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires: python-execnet >= 1.1
-Requires: python-pytest >= 3.0.0
+Requires: python-pytest >= 3.6.0
Requires: python-pytest-forked
Requires: python-six
BuildArch: noarch
@@ -70,6 +75,9 @@
%python_install
%python_expand %fdupes -s %{buildroot}%{$python_sitelib}
+%check
+%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib}
py.test-%{$python_bin_suffix} -v
+
%files %{python_files}
%doc CHANGELOG.rst ISSUES.txt README.rst
%license LICENSE
++++++ pytest-xdist-1.23.2.tar.gz -> pytest-xdist-1.26.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/.travis.yml
new/pytest-xdist-1.26.1/.travis.yml
--- old/pytest-xdist-1.23.2/.travis.yml 2018-09-28 12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/.travis.yml 2019-01-28 21:48:04.000000000 +0100
@@ -11,36 +11,36 @@
email:
- [email protected]
-python:
-- '2.7'
-- '3.4'
-- '3.5'
-- '3.6'
-env:
-- TOXENV=py-pytest30
-- TOXENV=py-pytest31
-- TOXENV=py-pytest32
-- TOXENV=py-pytest33
-- TOXENV=py-pytest36
-- TOXENV=py-pytest38
-
-install: pip install tox setuptools_scm
+install:
+ - pip install -U pip
+ - pip install tox setuptools_scm
script: tox
stages:
-- linting
+- baseline
- test
- name: deploy
if: repo = pytest-dev/pytest-xdist AND tag IS present
jobs:
include:
- - stage: linting
+ - stage: baseline
python: '3.6'
- script:
- - tox -e linting
+ env: TOXENV=linting
+ - python: '3.6'
+ env: TOXENV=py36-pytestlatest
+ - python: '2.7'
+ env: TOXENV=py27-pytestlatest
+
- stage: test
- # python x env above are already included into this stage
+ python: "3.4"
+ env: TOXENV=py34-pytestlatest
+ - python: "3.5"
+ env: TOXENV=py35-pytestlatest
+ - python: "3.7"
+ env: TOXENV=py37-pytestlatest
+ sudo: required
+ dist: xenial
- python: "2.7"
env: TOXENV=py27-pytestmaster
- python: "2.7"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/CHANGELOG.rst
new/pytest-xdist-1.26.1/CHANGELOG.rst
--- old/pytest-xdist-1.23.2/CHANGELOG.rst 2018-09-28 12:28:58.000000000
+0200
+++ new/pytest-xdist-1.26.1/CHANGELOG.rst 2019-01-28 21:48:04.000000000
+0100
@@ -1,3 +1,85 @@
+pytest-xdist 1.26.1 (2019-01-28)
+================================
+
+Bug Fixes
+---------
+
+- `#406 <https://github.com/pytest-dev/pytest-xdist/issues/406>`_: Do not
implement deprecated ``pytest_logwarning`` hook in pytest versions where it is
deprecated.
+
+
+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)
+================================
+
+Deprecations and Removals
+-------------------------
+
+- `#372 <https://github.com/pytest-dev/pytest-xdist/issues/372>`_: Pytest
versions older than 3.6 are no longer supported.
+
+
+Features
+--------
+
+- `#373 <https://github.com/pytest-dev/pytest-xdist/issues/373>`_: Node setup
information is hidden when pytest is run in quiet mode to reduce noise on
many-core machines.
+
+- `#388 <https://github.com/pytest-dev/pytest-xdist/issues/388>`_:
``mainargv`` is made available in ``workerinput`` from the host's ``sys.argv``.
+
+ This can be used via ``request.config.workerinput["mainargv"]``.
+
+
+Bug Fixes
+---------
+
+- `#332 <https://github.com/pytest-dev/pytest-xdist/issues/332>`_: Fix report
of module-level skips (``pytest.skip(reason, allow_module_level=True)``).
+
+- `#378 <https://github.com/pytest-dev/pytest-xdist/issues/378>`_: Fix support
for gevent monkeypatching
+
+- `#384 <https://github.com/pytest-dev/pytest-xdist/issues/384>`_: pytest 4.1
support: ``ExceptionInfo`` API changes.
+
+- `#390 <https://github.com/pytest-dev/pytest-xdist/issues/390>`_: pytest 4.1
support: ``pytest_logwarning`` hook removed.
+
+
+pytest-xdist 1.24.1 (2018-11-09)
+================================
+
+Bug Fixes
+---------
+
+- `#349 <https://github.com/pytest-dev/pytest-xdist/issues/349>`_: Correctly
handle warnings created with arguments that can't be serialized during the
transfer from workers to master node.
+
+
+pytest-xdist 1.24.0 (2018-10-18)
+================================
+
+Features
+--------
+
+- `#337 <https://github.com/pytest-dev/pytest-xdist/issues/337>`_: New
``--maxprocesses`` command-line option that limits the maximum number of
workers when using ``--numprocesses=auto``.
+
+
+Bug Fixes
+---------
+
+- `#351 <https://github.com/pytest-dev/pytest-xdist/issues/351>`_: Fix
scheduling deadlock in case of inter-test locking.
+
+
pytest-xdist 1.23.2 (2018-09-28)
================================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/PKG-INFO
new/pytest-xdist-1.26.1/PKG-INFO
--- old/pytest-xdist-1.23.2/PKG-INFO 2018-09-28 12:29:23.000000000 +0200
+++ new/pytest-xdist-1.26.1/PKG-INFO 2019-01-28 21:48:22.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: pytest-xdist
-Version: 1.23.2
+Version: 1.26.1
Summary: pytest xdist plugin for distributed testing and loop-on-failing modes
Home-page: https://github.com/pytest-dev/pytest-xdist
Author: holger krekel and contributors
@@ -231,6 +231,12 @@
The information about the worker_id in a test is stored in the
``TestReport`` as
well, under the ``worker_id`` attribute.
+ Acessing ``sys.argv`` from the master node in workers
+ -----------------------------------------------------
+
+ To access the ``sys.argv`` passed to the command-line of the master
node, use
+ ``request.config.workerinput["mainargv"]``.
+
Specifying test exec environments in an ini file
------------------------------------------------
@@ -296,4 +302,5 @@
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/README.rst
new/pytest-xdist-1.26.1/README.rst
--- old/pytest-xdist-1.23.2/README.rst 2018-09-28 12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/README.rst 2019-01-28 21:48:04.000000000 +0100
@@ -223,6 +223,12 @@
The information about the worker_id in a test is stored in the ``TestReport``
as
well, under the ``worker_id`` attribute.
+Acessing ``sys.argv`` from the master node in workers
+-----------------------------------------------------
+
+To access the ``sys.argv`` passed to the command-line of the master node, use
+``request.config.workerinput["mainargv"]``.
+
Specifying test exec environments in an ini file
------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/appveyor.yml
new/pytest-xdist-1.26.1/appveyor.yml
--- old/pytest-xdist-1.23.2/appveyor.yml 2018-09-28 12:28:58.000000000
+0200
+++ new/pytest-xdist-1.26.1/appveyor.yml 2019-01-28 21:48:04.000000000
+0100
@@ -1,22 +1,23 @@
environment:
matrix:
- # note: please use "tox --listenvs" to populate the build matrix
- - TOXENV: "py27-pytest33"
- - TOXENV: "py34-pytest33"
- - TOXENV: "py35-pytest33"
- - TOXENV: "py36-pytest33"
- - TOXENV: "py36-pytest36"
- - TOXENV: "py36-pytest38"
- - TOXENV: "py27-pytest33-pexpect"
- - TOXENV: "py36-pytest33-pexpect"
+ - TOXENV: "py27-pytestlatest"
+ - TOXENV: "py34-pytestlatest"
+ - TOXENV: "py35-pytestlatest"
+ - TOXENV: "py36-pytestlatest"
+ - TOXENV: "py37-pytestlatest"
+ - TOXENV: "py27-pytestmaster"
+ - TOXENV: "py36-pytestmaster"
+ - TOXENV: "py27-pytestfeatures"
+ - TOXENV: "py36-pytestfeatures"
install:
- - C:\Python36\python -m pip install -U tox setuptools_scm pip
+ - C:\Python37\python -m pip install -U pip
+ - C:\Python37\python -m pip install -U tox setuptools_scm
build: false # Not a C# project, build stuff at the test step instead.
test_script:
- - C:\Python36\python -m tox
+ - C:\Python37\python -m tox
# We don't deploy anything on tags with AppVeyor, we use Travis instead, so we
# might as well save resources
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/pytest_xdist.egg-info/PKG-INFO
new/pytest-xdist-1.26.1/pytest_xdist.egg-info/PKG-INFO
--- old/pytest-xdist-1.23.2/pytest_xdist.egg-info/PKG-INFO 2018-09-28
12:29:22.000000000 +0200
+++ new/pytest-xdist-1.26.1/pytest_xdist.egg-info/PKG-INFO 2019-01-28
21:48:22.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: pytest-xdist
-Version: 1.23.2
+Version: 1.26.1
Summary: pytest xdist plugin for distributed testing and loop-on-failing modes
Home-page: https://github.com/pytest-dev/pytest-xdist
Author: holger krekel and contributors
@@ -231,6 +231,12 @@
The information about the worker_id in a test is stored in the
``TestReport`` as
well, under the ``worker_id`` attribute.
+ Acessing ``sys.argv`` from the master node in workers
+ -----------------------------------------------------
+
+ To access the ``sys.argv`` passed to the command-line of the master
node, use
+ ``request.config.workerinput["mainargv"]``.
+
Specifying test exec environments in an ini file
------------------------------------------------
@@ -296,4 +302,5 @@
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest-xdist-1.23.2/pytest_xdist.egg-info/SOURCES.txt
new/pytest-xdist-1.26.1/pytest_xdist.egg-info/SOURCES.txt
--- old/pytest-xdist-1.23.2/pytest_xdist.egg-info/SOURCES.txt 2018-09-28
12:29:22.000000000 +0200
+++ new/pytest-xdist-1.26.1/pytest_xdist.egg-info/SOURCES.txt 2019-01-28
21:48:22.000000000 +0100
@@ -48,6 +48,6 @@
xdist/workermanage.py
xdist/scheduler/__init__.py
xdist/scheduler/each.py
-xdist/scheduler/filescope.py
xdist/scheduler/load.py
+xdist/scheduler/loadfile.py
xdist/scheduler/loadscope.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest-xdist-1.23.2/pytest_xdist.egg-info/requires.txt
new/pytest-xdist-1.26.1/pytest_xdist.egg-info/requires.txt
--- old/pytest-xdist-1.23.2/pytest_xdist.egg-info/requires.txt 2018-09-28
12:29:22.000000000 +0200
+++ new/pytest-xdist-1.26.1/pytest_xdist.egg-info/requires.txt 2019-01-28
21:48:22.000000000 +0100
@@ -1,4 +1,4 @@
execnet>=1.1
-pytest>=3.0.0
+pytest>=3.6.0
pytest-forked
six
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/setup.py
new/pytest-xdist-1.26.1/setup.py
--- old/pytest-xdist-1.23.2/setup.py 2018-09-28 12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/setup.py 2019-01-28 21:48:04.000000000 +0100
@@ -1,14 +1,17 @@
from setuptools import setup, find_packages
-install_requires = ["execnet>=1.1", "pytest>=3.0.0", "pytest-forked", "six"]
+install_requires = ["execnet>=1.1", "pytest>=3.6.0", "pytest-forked", "six"]
+with open("README.rst") as f:
+ long_description = f.read()
+
setup(
name="pytest-xdist",
use_scm_version={"write_to": "xdist/_version.py"},
description="pytest xdist plugin for distributed testing"
" and loop-on-failing modes",
- long_description=open("README.rst").read(),
+ long_description=long_description,
license="MIT",
author="holger krekel and contributors",
author_email="[email protected],[email protected]",
@@ -40,5 +43,6 @@
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
],
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/testing/acceptance_test.py
new/pytest-xdist-1.26.1/testing/acceptance_test.py
--- old/pytest-xdist-1.23.2/testing/acceptance_test.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/testing/acceptance_test.py 2019-01-28
21:48:04.000000000 +0100
@@ -1,5 +1,6 @@
import os
import re
+import sys
import textwrap
import py
@@ -358,6 +359,30 @@
class TestTerminalReporting:
+ @pytest.mark.parametrize("verbosity", ["", "-q", "-v"])
+ def test_output_verbosity(self, testdir, verbosity):
+ testdir.makepyfile(
+ """
+ def test_ok():
+ pass
+ """
+ )
+ args = ["-n1"]
+ if verbosity:
+ args.append(verbosity)
+ result = testdir.runpytest(*args)
+ out = result.stdout.str()
+ if verbosity == "-v":
+ assert "scheduling tests" in out
+ assert "gw" in out
+ elif verbosity == "-q":
+ assert "scheduling tests" not in out
+ assert "gw" not in out
+ assert "bringing up nodes..." in out
+ else:
+ assert "scheduling tests" not in out
+ assert "gw" in out
+
def test_pass_skip_fail(self, testdir):
testdir.makepyfile(
"""
@@ -400,64 +425,6 @@
]
)
- @pytest.mark.parametrize("n", ["-n0", "-n1"])
- @pytest.mark.parametrize("warn_type", ["pytest", "builtin"])
- def test_warnings(self, testdir, n, warn_type):
- from pkg_resources import parse_version
-
- if parse_version(pytest.__version__) < parse_version("3.1"):
- pytest.skip("pytest warnings requires >= 3.1")
-
- if warn_type == "builtin":
- warn_code = """warnings.warn(UserWarning('this is a warning'))"""
- elif warn_type == "pytest":
- warn_code = """request.config.warn('', 'this is a warning',
- fslocation=py.path.local())"""
- else:
- assert False
- testdir.makepyfile(
- """
- import warnings, py, pytest
-
- @pytest.mark.filterwarnings('ignore:config.warn has been
deprecated')
- def test_func(request):
- {warn_code}
- """.format(
- warn_code=warn_code
- )
- )
- result = testdir.runpytest(n)
- result.stdout.fnmatch_lines(["*this is a warning*", "*1 passed, 1
warnings*"])
-
- @pytest.mark.parametrize("n", ["-n0", "-n1"])
- def test_custom_subclass(self, testdir, n):
- """Check that warning subclasses that don't honor the args attribute
don't break
- pytest-xdist (#344)
- """
- from pkg_resources import parse_version
-
- if parse_version(pytest.__version__) < parse_version("3.1"):
- pytest.skip("pytest warnings requires >= 3.1")
-
- testdir.makepyfile(
- """
- import warnings, py, pytest
-
- class MyWarning(UserWarning):
-
- def __init__(self, p1, p2):
- self.p1 = p1
- self.p2 = p2
- self.args = ()
-
- def test_func(request):
- warnings.warn(MyWarning("foo", 1))
- """
- )
- testdir.syspathinsert()
- result = testdir.runpytest(n)
- result.stdout.fnmatch_lines(["*MyWarning*", "*1 passed, 1 warnings*"])
-
def test_logfinish_hook(self, testdir):
"""Ensure the pytest_runtest_logfinish hook is being properly
handled"""
from _pytest import hookspec
@@ -523,9 +490,8 @@
name = "worker"
else:
name = "master"
- f = open(name, "w")
- f.write("xy")
- f.close()
+ with open(name, "w") as f:
+ f.write("xy")
# let's fail on the worker
if name == "worker":
raise ValueError(42)
@@ -575,16 +541,15 @@
assert collected_file.read() == "collected = 3"
-def test_funcarg_teardown_failure(testdir):
+def test_fixture_teardown_failure(testdir):
p = testdir.makepyfile(
"""
import pytest
- @pytest.fixture
+ @pytest.fixture(scope="module")
def myarg(request):
- def teardown(val):
- raise ValueError(val)
- return request.cached_setup(setup=lambda: 42, teardown=teardown,
- scope="module")
+ yield 42
+ raise ValueError(42)
+
def test_hello(myarg):
pass
"""
@@ -670,6 +635,11 @@
def test_issue34_pluginloading_in_subprocess(testdir):
+ import _pytest.hookspec
+
+ if not hasattr(_pytest.hookspec, "pytest_namespace"):
+ pytest.skip("this pytest version no longer supports
pytest_namespace()")
+
testdir.tmpdir.join("plugin123.py").write(
textwrap.dedent(
"""
@@ -765,6 +735,108 @@
result.stdout.fnmatch_lines("*1 passed*")
+class TestWarnings:
+ @pytest.mark.parametrize("n", ["-n0", "-n1"])
+ @pytest.mark.parametrize("warn_type", ["pytest", "builtin"])
+ 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:
+ assert False
+ testdir.makepyfile(
+ """
+ import warnings, py, pytest
+
+ @pytest.mark.filterwarnings('ignore:config.warn has been
deprecated')
+ def test_func(request):
+ {warn_code}
+ """.format(
+ warn_code=warn_code
+ )
+ )
+ result = testdir.runpytest(n)
+ result.stdout.fnmatch_lines(["*this is a warning*", "*1 passed, 1
warnings*"])
+
+ @pytest.mark.parametrize("n", ["-n0", "-n1"])
+ def test_custom_subclass(self, testdir, n):
+ """Check that warning subclasses that don't honor the args attribute
don't break
+ pytest-xdist (#344)
+ """
+ testdir.makepyfile(
+ """
+ import warnings, py, pytest
+
+ class MyWarning(UserWarning):
+
+ def __init__(self, p1, p2):
+ self.p1 = p1
+ self.p2 = p2
+ self.args = ()
+
+ def test_func(request):
+ warnings.warn(MyWarning("foo", 1))
+ """
+ )
+ testdir.syspathinsert()
+ result = testdir.runpytest(n)
+ result.stdout.fnmatch_lines(["*MyWarning*", "*1 passed, 1 warnings*"])
+
+ @pytest.mark.parametrize("n", ["-n0", "-n1"])
+ def test_unserializable_arguments(self, testdir, n):
+ """Check that warnings with unserializable arguments are handled
correctly (#349)."""
+ testdir.makepyfile(
+ """
+ import warnings, pytest
+
+ def test_func(tmpdir):
+ fn = (tmpdir / 'foo.txt').ensure(file=1)
+ with fn.open('r') as f:
+ warnings.warn(UserWarning("foo", f))
+ """
+ )
+ testdir.syspathinsert()
+ 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):
f = testdir.makepyfile(
@@ -1132,6 +1204,56 @@
assert c1 == c2
+class TestLocking:
+ _test_content = """
+ class TestClassName%s(object):
+
+ @classmethod
+ def setup_class(cls):
+ FILE_LOCK.acquire()
+
+ @classmethod
+ def teardown_class(cls):
+ FILE_LOCK.release()
+
+ def test_a(self):
+ pass
+
+ def test_b(self):
+ pass
+
+ def test_c(self):
+ pass
+
+ """
+
+ test_file1 = """
+ import filelock
+
+ FILE_LOCK = filelock.FileLock("test.lock")
+
+ """ + (
+ (_test_content * 4) % ("A", "B", "C", "D")
+ )
+
+ @pytest.mark.parametrize("scope", ["each", "load", "loadscope",
"loadfile", "no"])
+ def test_single_file(self, testdir, scope):
+ testdir.makepyfile(test_a=self.test_file1)
+ result = testdir.runpytest("-n2", "--dist=%s" % scope, "-v")
+ result.assert_outcomes(passed=(12 if scope != "each" else 12 * 2))
+
+ @pytest.mark.parametrize("scope", ["each", "load", "loadscope",
"loadfile", "no"])
+ def test_multi_file(self, testdir, scope):
+ testdir.makepyfile(
+ test_a=self.test_file1,
+ test_b=self.test_file1,
+ test_c=self.test_file1,
+ test_d=self.test_file1,
+ )
+ result = testdir.runpytest("-n2", "--dist=%s" % scope, "-v")
+ result.assert_outcomes(passed=(48 if scope != "each" else 48 * 2))
+
+
def parse_tests_and_workers_from_output(lines):
result = []
for line in lines:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/testing/test_looponfail.py
new/pytest-xdist-1.26.1/testing/test_looponfail.py
--- old/pytest-xdist-1.23.2/testing/test_looponfail.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/testing/test_looponfail.py 2019-01-28
21:48:04.000000000 +0100
@@ -1,4 +1,7 @@
import py
+import pytest
+from pkg_resources import parse_version
+
from xdist.looponfail import RemoteControl
from xdist.looponfail import StatRecorder
@@ -214,7 +217,11 @@
assert "test_one" not in remotecontrol.failures[0]
assert "test_two" in remotecontrol.failures[0]
- @py.test.mark.xfail(py.test.__version__ >= "3.1", reason="broken by pytest
3.1+")
+ @pytest.mark.xfail(
+ parse_version(pytest.__version__) >= parse_version("3.1"),
+ reason="broken by pytest 3.1+",
+ strict=True,
+ )
def test_looponfail_removed_test(self, testdir):
modcol = testdir.getmodulecol(
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/testing/test_plugin.py
new/pytest-xdist-1.26.1/testing/test_plugin.py
--- old/pytest-xdist-1.23.2/testing/test_plugin.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/testing/test_plugin.py 2019-01-28
21:48:04.000000000 +0100
@@ -25,6 +25,10 @@
check_options(config)
assert config.option.dist == "load"
assert config.option.tx == ["popen"] * 2
+ config = testdir.parseconfigure("--numprocesses", "3", "--maxprocesses",
"2")
+ check_options(config)
+ assert config.option.dist == "load"
+ assert config.option.tx == ["popen"] * 2
config = testdir.parseconfigure("-d")
check_options(config)
assert config.option.dist == "load"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/testing/test_remote.py
new/pytest-xdist-1.26.1/testing/test_remote.py
--- old/pytest-xdist-1.23.2/testing/test_remote.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/testing/test_remote.py 2019-01-28
21:48:04.000000000 +0100
@@ -1,6 +1,8 @@
import py
import pprint
import pytest
+import sys
+
from xdist.workermanage import WorkerController, unserialize_report
from xdist.remote import serialize_report
import execnet
@@ -151,7 +153,6 @@
for i in range(len(a_entries)):
assert isinstance(rep_entries[i], ReprEntry)
assert rep_entries[i].lines == a_entries[i].lines
- assert rep_entries[i].localssep == a_entries[i].localssep
assert rep_entries[i].reprfileloc.lineno ==
a_entries[i].reprfileloc.lineno
assert (
rep_entries[i].reprfileloc.message ==
a_entries[i].reprfileloc.message
@@ -292,14 +293,11 @@
ev = worker.popevent("workerfinished")
assert "workeroutput" in ev.kwargs
- @pytest.mark.skipif(
- pytest.__version__ >= "3.0", reason="skip at module level illegal in
pytest 3.0"
- )
def test_remote_collect_skip(self, worker):
worker.testdir.makepyfile(
"""
- import py
- py.test.skip("hello")
+ import pytest
+ pytest.skip("hello", allow_module_level=True)
"""
)
worker.setup()
@@ -307,10 +305,9 @@
assert not ev.kwargs
ev = worker.popevent()
assert ev.name == "collectreport"
- ev = worker.popevent()
- assert ev.name == "collectreport"
rep = unserialize_report(ev.name, ev.kwargs["data"])
assert rep.skipped
+ assert rep.longrepr[2] == "Skipped: hello"
ev = worker.popevent("collectionfinish")
assert not ev.kwargs["ids"]
@@ -400,3 +397,66 @@
)
result = testdir.runpytest("-n2", "--max-worker-restart=0")
assert result.ret == 0
+
+
+def test_remote_inner_argv(testdir):
+ """Test/document the behavior due to execnet using `python -c`."""
+ testdir.makepyfile(
+ """
+ import sys
+
+ def test_argv():
+ assert sys.argv == ["-c"]
+ """
+ )
+ result = testdir.runpytest("-n1")
+ assert result.ret == 0
+
+
+def test_remote_mainargv(testdir):
+ outer_argv = sys.argv
+
+ testdir.makepyfile(
+ """
+ def test_mainargv(request):
+ assert request.config.workerinput["mainargv"] == {!r}
+ """.format(
+ outer_argv
+ )
+ )
+ result = testdir.runpytest("-n1")
+ assert result.ret == 0
+
+
+def test_remote_usage_prog(testdir, request):
+ if not hasattr(request.config._parser, "prog"):
+ pytest.skip("prog not available in config parser")
+ testdir.makeconftest(
+ """
+ import pytest
+
+ config_parser = None
+
+ @pytest.fixture
+ def get_config_parser():
+ return config_parser
+
+ def pytest_configure(config):
+ global config_parser
+ config_parser = config._parser
+ """
+ )
+ testdir.makepyfile(
+ """
+ import sys
+
+ def test(get_config_parser, request):
+ get_config_parser._getparser().error("my_usage_error")
+ """
+ )
+
+ result = testdir.runpytest_subprocess("-n1")
+ assert result.ret == 1
+ result.stdout.fnmatch_lines(
+ ["usage: pytest.py *", "pytest.py: error: my_usage_error"]
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/tox.ini
new/pytest-xdist-1.26.1/tox.ini
--- old/pytest-xdist-1.23.2/tox.ini 2018-09-28 12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/tox.ini 2019-01-28 21:48:04.000000000 +0100
@@ -1,33 +1,18 @@
[tox]
-# if you change the envlist, please update .travis.yml file as well
envlist=
linting
- py{27,34,35,36}-pytest{30,31,32,33,36,38}
- py{27,36}-pytest36-pexpect
+ py{27,34,35,36,37}-pytestlatest
py{27,36}-pytest{master,features}
-
[testenv]
changedir=testing
passenv = USER USERNAME
deps =
- pycmd
- # to avoid .eggs
- setuptools_scm
- pytest30: pytest~=3.0.5
- pytest31: pytest~=3.1.0
- pytest32: pytest~=3.2.0
- pytest33: pytest~=3.3.0
- pytest36: pytest~=3.6.0
- pytest38: pytest~=3.8.0
+ pytestlatest: pytest
pytestmaster: git+https://github.com/pytest-dev/pytest.git@master
pytestfeatures: git+https://github.com/pytest-dev/pytest.git@features
- pexpect: pexpect
-platform=
- pexpect: linux|darwin
+ filelock
commands=
- # always clean to avoid code unmarshal mismatch on old python/pytest
- py.cleanup -aq
pytest {posargs}
[testenv:linting]
@@ -50,7 +35,7 @@
towncrier --version {posargs} --yes
[pytest]
-addopts = -rsfxX
+addopts = -ra
[flake8]
max-line-length = 120
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/_version.py
new/pytest-xdist-1.26.1/xdist/_version.py
--- old/pytest-xdist-1.23.2/xdist/_version.py 2018-09-28 12:29:22.000000000
+0200
+++ new/pytest-xdist-1.26.1/xdist/_version.py 2019-01-28 21:48:22.000000000
+0100
@@ -1,4 +1,4 @@
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
-version = '1.23.2'
+version = '1.26.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/dsession.py
new/pytest-xdist-1.26.1/xdist/dsession.py
--- old/pytest-xdist-1.23.2/xdist/dsession.py 2018-09-28 12:28:58.000000000
+0200
+++ new/pytest-xdist-1.26.1/xdist/dsession.py 2019-01-28 21:48:04.000000000
+0100
@@ -229,9 +229,10 @@
if self.terminal and not self.sched.has_pending:
self.trdist.ensure_show_status()
self.terminal.write_line("")
- self.terminal.write_line(
- "scheduling tests via %s" % (self.sched.__class__.__name__)
- )
+ if self.config.option.verbose > 0:
+ self.terminal.write_line(
+ "scheduling tests via %s" %
(self.sched.__class__.__name__)
+ )
self.sched.schedule()
def worker_logstart(self, node, nodeid, location):
@@ -259,10 +260,10 @@
def worker_collectreport(self, node, rep):
"""Emitted when a node calls the pytest_collectreport hook.
- Because we only need the report when there's a failure, as optimization
- we only expect to receive failed reports from workers (#330).
+ Because we only need the report when there's a failure/skip, as
optimization
+ we only expect to receive failed/skipped reports from workers (#330).
"""
- assert rep.failed
+ assert not rep.passed
self._failed_worker_collectreport(node, rep)
def worker_logwarning(self, message, code, nodeid, fslocation):
@@ -344,8 +345,11 @@
self.rewrite(self.getstatus())
def getstatus(self):
- parts = ["%s %s" % (spec.id, self._status[spec.id]) for spec in
self._specs]
- return " / ".join(parts)
+ if self.config.option.verbose >= 0:
+ parts = ["%s %s" % (spec.id, self._status[spec.id]) for spec in
self._specs]
+ return " / ".join(parts)
+ else:
+ return "bringing up nodes..."
def rewrite(self, line, newline=False):
pline = line + " " * max(self._lastlen - len(line), 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/looponfail.py
new/pytest-xdist-1.26.1/xdist/looponfail.py
--- old/pytest-xdist-1.23.2/xdist/looponfail.py 2018-09-28 12:28:58.000000000
+0200
+++ new/pytest-xdist-1.26.1/xdist/looponfail.py 2019-01-28 21:48:04.000000000
+0100
@@ -32,7 +32,7 @@
if config.getoption("looponfail"):
usepdb = config.getoption("usepdb") # a core option
if usepdb:
- raise pytest.UsageError("--pdb incompatible with --looponfail.")
+ raise pytest.UsageError("--pdb is incompatible with --looponfail.")
looponfail_main(config)
return 2 # looponfail only can get stop with ctrl-C anyway
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/plugin.py
new/pytest-xdist-1.26.1/xdist/plugin.py
--- old/pytest-xdist-1.23.2/xdist/plugin.py 2018-09-28 12:28:58.000000000
+0200
+++ new/pytest-xdist-1.26.1/xdist/plugin.py 2019-01-28 21:48:04.000000000
+0100
@@ -48,6 +48,14 @@
"host system",
)
group.addoption(
+ "--maxprocesses",
+ dest="maxprocesses",
+ metavar="maxprocesses",
+ action="store",
+ type=int,
+ help="limit the maximum number of workers to process the tests when
using --numprocesses=auto",
+ )
+ group.addoption(
"--max-worker-restart",
"--max-slave-restart",
action="store",
@@ -118,12 +126,12 @@
)
parser.addini(
"rsyncdirs",
- "list of (relative) paths to be rsynced for" " remote distributed
testing.",
+ "list of (relative) paths to be rsynced for remote distributed
testing.",
type="pathlist",
)
parser.addini(
"rsyncignore",
- "list of (relative) glob-style paths to be ignored " "for rsyncing.",
+ "list of (relative) glob-style paths to be ignored for rsyncing.",
type="pathlist",
)
parser.addini(
@@ -172,7 +180,10 @@
if config.option.numprocesses:
if config.option.dist == "no":
config.option.dist = "load"
- config.option.tx = ["popen"] * config.option.numprocesses
+ numprocesses = config.option.numprocesses
+ if config.option.maxprocesses:
+ numprocesses = min(numprocesses, config.option.maxprocesses)
+ config.option.tx = ["popen"] * numprocesses
if config.option.distload:
config.option.dist = "load"
val = config.getvalue
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/remote.py
new/pytest-xdist-1.26.1/xdist/remote.py
--- old/pytest-xdist-1.23.2/xdist/remote.py 2018-09-28 12:28:58.000000000
+0200
+++ new/pytest-xdist-1.26.1/xdist/remote.py 2019-01-28 21:48:04.000000000
+0100
@@ -12,6 +12,7 @@
import _pytest.hookspec
import pytest
+from execnet.gateway_base import dumps, DumpError
class WorkerInteractor(object):
@@ -109,19 +110,24 @@
self.sendevent("testreport", data=data)
def pytest_collectreport(self, report):
- # master only needs reports that failed, as optimization send only
them instead (#330)
- if report.failed:
+ # send only reports that have not passed to master as optimization
(#330)
+ if not report.passed:
data = serialize_report(report)
self.sendevent("collectreport", data=data)
- def pytest_logwarning(self, message, code, nodeid, fslocation):
- self.sendevent(
- "logwarning",
- message=message,
- code=code,
- nodeid=nodeid,
- fslocation=str(fslocation),
- )
+ # the pytest_logwarning hook was deprecated since pytest 4.0
+ if hasattr(
+ _pytest.hookspec, "pytest_logwarning"
+ ) and not
_pytest.hookspec.pytest_logwarning.pytest_spec.get("warn_on_impl"):
+
+ def pytest_logwarning(self, message, code, nodeid, fslocation):
+ self.sendevent(
+ "logwarning",
+ message=message,
+ code=code,
+ nodeid=nodeid,
+ fslocation=str(fslocation),
+ )
# the pytest_warning_captured hook was introduced in pytest 3.8
if hasattr(_pytest.hookspec, "pytest_warning_captured"):
@@ -181,8 +187,15 @@
if isinstance(warning_message.message, Warning):
message_module = type(warning_message.message).__module__
message_class_name = type(warning_message.message).__name__
- message_args = warning_message.message.args
message_str = str(warning_message.message)
+ # check now if we can serialize the warning arguments (#349)
+ # if not, we will just use the exception message on the master node
+ try:
+ dumps(warning_message.message.args)
+ except DumpError:
+ message_args = None
+ else:
+ message_args = warning_message.message.args
else:
message_str = warning_message.message
message_module = None
@@ -207,7 +220,15 @@
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
@@ -234,24 +255,29 @@
config.option.dist = "no"
config.option.distload = False
config.option.numprocesses = None
+ config.option.maxprocesses = None
config.args = args
return config
if __name__ == "__channelexec__":
+ import py
+
channel = channel # noqa
- workerinput, args, option_dict = channel.receive()
- importpath = os.getcwd()
- sys.path.insert(0, importpath) # XXX only for remote situations
- os.environ["PYTHONPATH"] = (
- importpath + os.pathsep + os.environ.get("PYTHONPATH", "")
- )
+ workerinput, args, option_dict, change_sys_path = channel.receive()
+
+ if change_sys_path:
+ importpath = os.getcwd()
+ 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])
config.workerinput = workerinput
config.workeroutput = {}
# TODO: deprecated name, backward compatibility only. Remove it in future
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/scheduler/__init__.py
new/pytest-xdist-1.26.1/xdist/scheduler/__init__.py
--- old/pytest-xdist-1.23.2/xdist/scheduler/__init__.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/xdist/scheduler/__init__.py 2019-01-28
21:48:04.000000000 +0100
@@ -1,4 +1,4 @@
from xdist.scheduler.each import EachScheduling # noqa
from xdist.scheduler.load import LoadScheduling # noqa
+from xdist.scheduler.loadfile import LoadFileScheduling # noqa
from xdist.scheduler.loadscope import LoadScopeScheduling # noqa
-from xdist.scheduler.filescope import LoadFileScheduling # noqa
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/scheduler/each.py
new/pytest-xdist-1.26.1/xdist/scheduler/each.py
--- old/pytest-xdist-1.23.2/xdist/scheduler/each.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/xdist/scheduler/each.py 2019-01-28
21:48:04.000000000 +0100
@@ -126,6 +126,7 @@
if not pending:
pending[:] = range(len(self.node2collection[node]))
node.send_runtest_all()
+ node.shutdown()
else:
node.send_runtest_some(pending)
self._started.append(node)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/scheduler/filescope.py
new/pytest-xdist-1.26.1/xdist/scheduler/filescope.py
--- old/pytest-xdist-1.23.2/xdist/scheduler/filescope.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/xdist/scheduler/filescope.py 1970-01-01
01:00:00.000000000 +0100
@@ -1,52 +0,0 @@
-from . import LoadScopeScheduling
-from py.log import Producer
-
-
-class LoadFileScheduling(LoadScopeScheduling):
- """Implement load scheduling across nodes, but grouping test test file.
-
- This distributes the tests collected across all nodes so each test is run
- just once. All nodes collect and submit the list of tests and when all
- collections are received it is verified they are identical collections.
- Then the collection gets divided up in work units, grouped by test file,
- and those work units get submitted to nodes. Whenever a node finishes an
- item, it calls ``.mark_test_complete()`` which will trigger the scheduler
- to assign more work units if the number of pending tests for the node falls
- below a low-watermark.
-
- When created, ``numnodes`` defines how many nodes are expected to submit a
- collection. This is used to know when all nodes have finished collection.
-
- This class behaves very much like LoadScopeScheduling, but with a
file-level scope.
- """
-
- def __init__(self, config, log=None):
- super(LoadFileScheduling, self).__init__(config, log)
- if log is None:
- self.log = Producer("loadfilesched")
- else:
- self.log = log.loadfilesched
-
- def _split_scope(self, nodeid):
- """Determine the scope (grouping) of a nodeid.
-
- There are usually 3 cases for a nodeid::
-
- example/loadsuite/test/test_beta.py::test_beta0
- example/loadsuite/test/test_delta.py::Delta1::test_delta0
- example/loadsuite/epsilon/__init__.py::epsilon.epsilon
-
- #. Function in a test module.
- #. Method of a class in a test module.
- #. Doctest in a function in a package.
-
- This function will group tests with the scope determined by splitting
- the first ``::`` from the left. That is, test will be grouped in a
- single work unit when they reside in the same file.
- In the above example, scopes will be::
-
- example/loadsuite/test/test_beta.py
- example/loadsuite/test/test_delta.py
- example/loadsuite/epsilon/__init__.py
- """
- return nodeid.split("::", 1)[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/scheduler/load.py
new/pytest-xdist-1.26.1/xdist/scheduler/load.py
--- old/pytest-xdist-1.23.2/xdist/scheduler/load.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/xdist/scheduler/load.py 2019-01-28
21:48:04.000000000 +0100
@@ -178,6 +178,9 @@
return
num_send = items_per_node_max - len(node_pending)
self._send_tests(node, num_send)
+ else:
+ node.shutdown()
+
self.log("num items waiting for node:", len(self.pending))
def remove_node(self, node):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/scheduler/loadfile.py
new/pytest-xdist-1.26.1/xdist/scheduler/loadfile.py
--- old/pytest-xdist-1.23.2/xdist/scheduler/loadfile.py 1970-01-01
01:00:00.000000000 +0100
+++ new/pytest-xdist-1.26.1/xdist/scheduler/loadfile.py 2019-01-28
21:48:04.000000000 +0100
@@ -0,0 +1,52 @@
+from .loadscope import LoadScopeScheduling
+from py.log import Producer
+
+
+class LoadFileScheduling(LoadScopeScheduling):
+ """Implement load scheduling across nodes, but grouping test test file.
+
+ This distributes the tests collected across all nodes so each test is run
+ just once. All nodes collect and submit the list of tests and when all
+ collections are received it is verified they are identical collections.
+ Then the collection gets divided up in work units, grouped by test file,
+ and those work units get submitted to nodes. Whenever a node finishes an
+ item, it calls ``.mark_test_complete()`` which will trigger the scheduler
+ to assign more work units if the number of pending tests for the node falls
+ below a low-watermark.
+
+ When created, ``numnodes`` defines how many nodes are expected to submit a
+ collection. This is used to know when all nodes have finished collection.
+
+ This class behaves very much like LoadScopeScheduling, but with a
file-level scope.
+ """
+
+ def __init__(self, config, log=None):
+ super(LoadFileScheduling, self).__init__(config, log)
+ if log is None:
+ self.log = Producer("loadfilesched")
+ else:
+ self.log = log.loadfilesched
+
+ def _split_scope(self, nodeid):
+ """Determine the scope (grouping) of a nodeid.
+
+ There are usually 3 cases for a nodeid::
+
+ example/loadsuite/test/test_beta.py::test_beta0
+ example/loadsuite/test/test_delta.py::Delta1::test_delta0
+ example/loadsuite/epsilon/__init__.py::epsilon.epsilon
+
+ #. Function in a test module.
+ #. Method of a class in a test module.
+ #. Doctest in a function in a package.
+
+ This function will group tests with the scope determined by splitting
+ the first ``::`` from the left. That is, test will be grouped in a
+ single work unit when they reside in the same file.
+ In the above example, scopes will be::
+
+ example/loadsuite/test/test_beta.py
+ example/loadsuite/test/test_delta.py
+ example/loadsuite/epsilon/__init__.py
+ """
+ return nodeid.split("::", 1)[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/scheduler/loadscope.py
new/pytest-xdist-1.26.1/xdist/scheduler/loadscope.py
--- old/pytest-xdist-1.23.2/xdist/scheduler/loadscope.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/xdist/scheduler/loadscope.py 2019-01-28
21:48:04.000000000 +0100
@@ -187,7 +187,7 @@
break
else:
raise RuntimeError(
- "Unable to identify crashitem on a workload with " "pending
items"
+ "Unable to identify crashitem on a workload with pending items"
)
# Made uncompleted work unit available again
@@ -306,6 +306,7 @@
# Check that more work is available
if not self.workqueue:
+ node.shutdown()
return
self.log("Number of units waiting for node:", len(self.workqueue))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest-xdist-1.23.2/xdist/workermanage.py
new/pytest-xdist-1.26.1/xdist/workermanage.py
--- old/pytest-xdist-1.23.2/xdist/workermanage.py 2018-09-28
12:28:58.000000000 +0200
+++ new/pytest-xdist-1.26.1/xdist/workermanage.py 2019-01-28
21:48:04.000000000 +0100
@@ -2,6 +2,7 @@
import fnmatch
import os
import re
+import sys
import threading
import py
@@ -213,6 +214,7 @@
"workercount": len(nodemanager.specs),
"slaveid": gateway.id,
"slavecount": len(nodemanager.specs),
+ "mainargv": sys.argv,
}
# TODO: deprecated name, backward compatibility only. Remove it in
future
self.slaveinput = self.workerinput
@@ -243,7 +245,9 @@
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)
@@ -268,7 +272,7 @@
if not self._down:
try:
self.sendcommand("shutdown")
- except IOError:
+ except (IOError, OSError):
pass
self._shutdown_sent = True
@@ -345,7 +349,11 @@
except: # noqa
from _pytest._code import ExceptionInfo
- excinfo = ExceptionInfo()
+ # ExceptionInfo API changed in pytest 4.1
+ if hasattr(ExceptionInfo, "from_current"):
+ excinfo = ExceptionInfo.from_current()
+ else:
+ excinfo = ExceptionInfo()
print("!" * 20, excinfo)
self.config.notify_exception(excinfo)
self.shutdown()
@@ -426,9 +434,16 @@
if data["message_module"]:
mod = importlib.import_module(data["message_module"])
cls = getattr(mod, data["message_class_name"])
- try:
- message = cls(*data["message_args"])
- except TypeError:
+ message = None
+ if data["message_args"] is not None:
+ try:
+ message = cls(*data["message_args"])
+ except TypeError:
+ pass
+ if message is None:
+ # could not recreate the original warning instance;
+ # create a generic Warning instance with the original
+ # message at least
message_text = "{mod}.{cls}: {msg}".format(
mod=data["message_module"],
cls=data["message_class_name"],