From 1e10d217098b841aa2b7634c9f5a8440c4ef4740 Mon Sep 17 00:00:00 2001 From: Sylvain MARIE Date: Tue, 18 Feb 2020 16:39:34 +0100 Subject: [PATCH 1/5] New methods `is_xdist_worker`, `is_xdist_master`, `get_xdist_worker_id`. Fixes #504 --- src/xdist/__init__.py | 4 +++- src/xdist/plugin.py | 43 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/xdist/__init__.py b/src/xdist/__init__.py index 44d995da..66247a54 100644 --- a/src/xdist/__init__.py +++ b/src/xdist/__init__.py @@ -1,3 +1,5 @@ +from xdist.plugin import is_xdist_worker, is_xdist_master, get_xdist_worker_id from xdist._version import version as __version__ -__all__ = ["__version__"] +__all__ = ['__version__', + 'is_xdist_worker', 'is_xdist_master', 'get_xdist_worker_id'] diff --git a/src/xdist/plugin.py b/src/xdist/plugin.py index 4a0488e7..4a96c42c 100644 --- a/src/xdist/plugin.py +++ b/src/xdist/plugin.py @@ -201,16 +201,49 @@ def pytest_cmdline_main(config): # ------------------------------------------------------------------------- -# fixtures +# fixtures and API to easily know the role of current node # ------------------------------------------------------------------------- +def is_xdist_worker(request_or_session): + """Return `True` if this is an xdist worker, `False` otherwise -@pytest.fixture(scope="session") -def worker_id(request): + :param request_or_session: the `pytest` `request` or `session` object + :return: + """ + return hasattr(request_or_session.config, "workerinput") + + +def is_xdist_master(request_or_session): + """Return `True` if this is the xdist master, `False` otherwise + + Note: this method also returns `False` when distribution has not been + activated at all. + + :param request_or_session: the `pytest` `request` or `session` object + :return: + """ + return (not is_xdist_worker(request_or_session) + and request_or_session.config.option.dist != "no") + + +def get_xdist_worker_id(request_or_session): """Return the id of the current worker ('gw0', 'gw1', etc) or 'master' if running on the master node. + + :param request_or_session: the `pytest` `request` or `session` object + :return: """ - if hasattr(request.config, "workerinput"): - return request.config.workerinput["workerid"] + if hasattr(request_or_session.config, "workerinput"): + return request_or_session.config.workerinput["workerid"] else: + # TODO shall we raise an exception if dist is not enabled ? + # i.e. `not is_xdist_master(request_or_session)` ? return "master" + + +@pytest.fixture(scope="session") +def worker_id(request): + """Return the id of the current worker ('gw0', 'gw1', etc) or 'master' + if running on the master node. + """ + return get_xdist_worker_id(request) From 2c091be09a812dd1f88b3370ab163a23c7b16dcc Mon Sep 17 00:00:00 2001 From: Sylvain MARIE Date: Tue, 18 Feb 2020 16:45:05 +0100 Subject: [PATCH 2/5] added towncrier news --- 504.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 504.feature diff --git a/504.feature b/504.feature new file mode 100644 index 00000000..db1512b1 --- /dev/null +++ b/504.feature @@ -0,0 +1 @@ +New methods `is_xdist_worker`, `is_xdist_master`, `get_xdist_worker_id`, so as to easily grab info about current node. \ No newline at end of file From d20b0d55f95185ee5e2de8767c5ed11324cbae93 Mon Sep 17 00:00:00 2001 From: Sylvain MARIE Date: Wed, 19 Feb 2020 15:35:59 +0100 Subject: [PATCH 3/5] linter fix --- 504.feature | 2 +- src/xdist/__init__.py | 4 ++-- src/xdist/plugin.py | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/504.feature b/504.feature index db1512b1..92029a77 100644 --- a/504.feature +++ b/504.feature @@ -1 +1 @@ -New methods `is_xdist_worker`, `is_xdist_master`, `get_xdist_worker_id`, so as to easily grab info about current node. \ No newline at end of file +New methods `is_xdist_worker`, `is_xdist_master`, `get_xdist_worker_id`, so as to easily grab info about current node. diff --git a/src/xdist/__init__.py b/src/xdist/__init__.py index 66247a54..88e7dae2 100644 --- a/src/xdist/__init__.py +++ b/src/xdist/__init__.py @@ -1,5 +1,5 @@ from xdist.plugin import is_xdist_worker, is_xdist_master, get_xdist_worker_id from xdist._version import version as __version__ -__all__ = ['__version__', - 'is_xdist_worker', 'is_xdist_master', 'get_xdist_worker_id'] +__all__ = ["__version__", + "is_xdist_worker", "is_xdist_master", "get_xdist_worker_id"] diff --git a/src/xdist/plugin.py b/src/xdist/plugin.py index 4a96c42c..9660aa5a 100644 --- a/src/xdist/plugin.py +++ b/src/xdist/plugin.py @@ -204,6 +204,7 @@ def pytest_cmdline_main(config): # fixtures and API to easily know the role of current node # ------------------------------------------------------------------------- + def is_xdist_worker(request_or_session): """Return `True` if this is an xdist worker, `False` otherwise @@ -222,8 +223,10 @@ def is_xdist_master(request_or_session): :param request_or_session: the `pytest` `request` or `session` object :return: """ - return (not is_xdist_worker(request_or_session) - and request_or_session.config.option.dist != "no") + return ( + not is_xdist_worker(request_or_session) + and request_or_session.config.option.dist != "no" + ) def get_xdist_worker_id(request_or_session): From d4e54bfecb531cf6462a5c9ed3d40de277eea245 Mon Sep 17 00:00:00 2001 From: Sylvain MARIE Date: Wed, 19 Feb 2020 17:49:47 +0100 Subject: [PATCH 4/5] linter fix2 --- src/xdist/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/xdist/__init__.py b/src/xdist/__init__.py index 88e7dae2..83ef7762 100644 --- a/src/xdist/__init__.py +++ b/src/xdist/__init__.py @@ -1,5 +1,4 @@ from xdist.plugin import is_xdist_worker, is_xdist_master, get_xdist_worker_id from xdist._version import version as __version__ -__all__ = ["__version__", - "is_xdist_worker", "is_xdist_master", "get_xdist_worker_id"] +__all__ = ["__version__", "is_xdist_worker", "is_xdist_master", "get_xdist_worker_id"] From 4406042ce9a0d0bb45956b95f7adbe6875eae56f Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 5 Aug 2020 20:26:10 -0300 Subject: [PATCH 5/5] Add tests --- 504.feature | 1 - README.rst | 30 +++++++++++++++++++++++++++++- changelog/504.feature.rst | 1 + src/xdist/plugin.py | 16 +++++++--------- testing/acceptance_test.py | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 11 deletions(-) delete mode 100644 504.feature create mode 100644 changelog/504.feature.rst diff --git a/504.feature b/504.feature deleted file mode 100644 index 92029a77..00000000 --- a/504.feature +++ /dev/null @@ -1 +0,0 @@ -New methods `is_xdist_worker`, `is_xdist_master`, `get_xdist_worker_id`, so as to easily grab info about current node. diff --git a/README.rst b/README.rst index ca138196..c62dd755 100644 --- a/README.rst +++ b/README.rst @@ -268,7 +268,7 @@ a test or fixture, you may use the ``worker_id`` fixture to do so: When ``xdist`` is disabled (running with ``-n0`` for example), then ``worker_id`` will return ``"master"``. -Additionally, worker processes have the following environment variables +Worker processes also have the following environment variables defined: * ``PYTEST_XDIST_WORKER``: the name of the worker, e.g., ``"gw2"``. @@ -278,6 +278,34 @@ defined: The information about the worker_id in a test is stored in the ``TestReport`` as well, under the ``worker_id`` attribute. +Since version 2.0, the following functions are also available in the ``xdist`` module: + +.. code-block:: python + + def is_xdist_worker(request_or_session) -> bool: + """Return `True` if this is an xdist worker, `False` otherwise + + :param request_or_session: the `pytest` `request` or `session` object + """ + + def is_xdist_master(request_or_session) -> bool: + """Return `True` if this is the xdist master, `False` otherwise + + Note: this method also returns `False` when distribution has not been + activated at all. + + :param request_or_session: the `pytest` `request` or `session` object + """ + + def get_xdist_worker_id(request_or_session) -> str: + """Return the id of the current worker ('gw0', 'gw1', etc) or 'master' + if running on the 'master' node. + + If not distributing tests (for example passing `-n0` or not passing `-n` at all) also return 'master'. + + :param request_or_session: the `pytest` `request` or `session` object + """ + Uniquely identifying the current test run ----------------------------------------- diff --git a/changelog/504.feature.rst b/changelog/504.feature.rst new file mode 100644 index 00000000..2348898d --- /dev/null +++ b/changelog/504.feature.rst @@ -0,0 +1 @@ +New functions ``xdist.is_xdist_worker``, ``xdist.is_xdist_master``, ``xdist.get_xdist_worker_id``, to easily identify the current node. diff --git a/src/xdist/plugin.py b/src/xdist/plugin.py index 6a639e5b..8a09f892 100644 --- a/src/xdist/plugin.py +++ b/src/xdist/plugin.py @@ -199,23 +199,21 @@ def pytest_cmdline_main(config): # ------------------------------------------------------------------------- -def is_xdist_worker(request_or_session): +def is_xdist_worker(request_or_session) -> bool: """Return `True` if this is an xdist worker, `False` otherwise :param request_or_session: the `pytest` `request` or `session` object - :return: """ return hasattr(request_or_session.config, "workerinput") -def is_xdist_master(request_or_session): +def is_xdist_master(request_or_session) -> bool: """Return `True` if this is the xdist master, `False` otherwise Note: this method also returns `False` when distribution has not been activated at all. :param request_or_session: the `pytest` `request` or `session` object - :return: """ return ( not is_xdist_worker(request_or_session) @@ -223,18 +221,18 @@ def is_xdist_master(request_or_session): ) -def get_xdist_worker_id(request_or_session): +def get_xdist_worker_id(request_or_session) -> str: """Return the id of the current worker ('gw0', 'gw1', etc) or 'master' - if running on the master node. + if running on the 'master' node. + + If not distributing tests (for example passing `-n0` or not passing `-n` at all) + also return 'master'. :param request_or_session: the `pytest` `request` or `session` object - :return: """ if hasattr(request_or_session.config, "workerinput"): return request_or_session.config.workerinput["workerid"] else: - # TODO shall we raise an exception if dist is not enabled ? - # i.e. `not is_xdist_master(request_or_session)` ? return "master" diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 7f9a5515..c6808109 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -5,6 +5,7 @@ import py import pytest +import xdist class TestDistribution: @@ -1436,3 +1437,39 @@ def get_workers_and_test_count_by_prefix(prefix, lines, expected_status="PASSED" if expected_status == status and nodeid.startswith(prefix): result[worker] = result.get(worker, 0) + 1 return result + + +class TestAPI: + @pytest.fixture + def fake_request(self): + class FakeOption: + def __init__(self): + self.dist = "load" + + class FakeConfig: + def __init__(self): + self.workerinput = {"workerid": "gw5"} + self.option = FakeOption() + + class FakeRequest: + def __init__(self): + self.config = FakeConfig() + + return FakeRequest() + + def test_is_xdist_worker(self, fake_request): + assert xdist.is_xdist_worker(fake_request) + del fake_request.config.workerinput + assert not xdist.is_xdist_worker(fake_request) + + def test_is_xdist_master(self, fake_request): + assert not xdist.is_xdist_master(fake_request) + del fake_request.config.workerinput + assert xdist.is_xdist_master(fake_request) + fake_request.config.option.dist = "no" + assert not xdist.is_xdist_master(fake_request) + + def test_get_xdist_worker_id(self, fake_request): + assert xdist.get_xdist_worker_id(fake_request) == "gw5" + del fake_request.config.workerinput + assert xdist.get_xdist_worker_id(fake_request) == "master"