diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c9eb227b..0be930d3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,6 +17,7 @@ jobs: - "py39-pytestlatest" - "py38-pytestmain" - "py38-psutil" + - "py38-setproctitle" os: [ubuntu-latest, windows-latest] include: @@ -32,6 +33,8 @@ jobs: python: "3.8" - tox_env: "py38-psutil" python: "3.8" + - tox_env: "py38-setproctitle" + python: "3.8" steps: - uses: actions/checkout@v1 diff --git a/README.rst b/README.rst index cb0a31b8..5394aad0 100644 --- a/README.rst +++ b/README.rst @@ -317,6 +317,26 @@ Since version 2.0, the following functions are also available in the ``xdist`` m """ +Identifying workers from the system environment +----------------------------------------------- + +*New in version UNRELEASED TBD FIXME* + +If the `setproctitle`_ package is installed, ``pytest-xdist`` will use it to +update the process title (command line) on its workers to show their current +state. The titles used are ``[pytest-xdist running] file.py/node::id`` and +``[pytest-xdist idle]``, visible in standard tools like ``ps`` and ``top`` on +Linux, Mac OS X and BSD systems. For Windows, please follow `setproctitle`_'s +pointer regarding the Process Explorer tool. + +This is intended purely as an UX enhancement, e.g. to track down issues with +long-running or CPU intensive tests. Errors in changing the title are ignored +silently. Please try not to rely on the title format or title changes in +external scripts. + +.. _`setproctitle`: https://pypi.org/project/setproctitle/ + + Uniquely identifying the current test run ----------------------------------------- diff --git a/changelog/696.feature.rst b/changelog/696.feature.rst new file mode 100644 index 00000000..8c78a141 --- /dev/null +++ b/changelog/696.feature.rst @@ -0,0 +1,3 @@ +On Linux, the process title now changes to indicate the current worker state (running/idle). + +Depends on the `setproctitle `__ package, which can be installed with ``pip install pytest-xdist[setproctitle]``. diff --git a/setup.py b/setup.py index 9a75ca52..40b1f905 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,11 @@ platforms=["linux", "osx", "win32"], packages=find_packages(where="src"), package_dir={"": "src"}, - extras_require={"testing": ["filelock"], "psutil": ["psutil>=3.0"]}, + extras_require={ + "testing": ["filelock"], + "psutil": ["psutil>=3.0"], + "setproctitle": ["setproctitle"], + }, entry_points={ "pytest11": ["xdist = xdist.plugin", "xdist.looponfail = xdist.looponfail"] }, diff --git a/src/xdist/remote.py b/src/xdist/remote.py index d79f0b38..0194ae02 100644 --- a/src/xdist/remote.py +++ b/src/xdist/remote.py @@ -16,6 +16,21 @@ from _pytest.config import _prepareconfig, Config +try: + from setproctitle import setproctitle +except ImportError: + + def setproctitle(title): + pass + + +def worker_title(title): + try: + setproctitle(title) + except Exception: + # changing the process name is very optional, no errors please + pass + class WorkerInteractor: def __init__(self, config, channel): @@ -85,9 +100,14 @@ def run_one_test(self, torun): else: nextitem = None + worker_title("[pytest-xdist running] %s" % item.nodeid) + start = time.time() self.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem) duration = time.time() - start + + worker_title("[pytest-xdist idle]") + self.sendevent( "runtest_protocol_complete", item_index=self.item_index, duration=duration ) diff --git a/tox.ini b/tox.ini index 0e4ad977..d5a263c7 100644 --- a/tox.ini +++ b/tox.ini @@ -4,6 +4,7 @@ envlist= py{36,37,38,39}-pytestlatest py38-pytestmain py38-psutil + py38-setproctitle [testenv] extras = testing @@ -21,6 +22,14 @@ deps = pytest commands = pytest {posargs:-k psutil} +[testenv:py38-setproctitle] +extras = + testing + setproctitle +deps = pytest +commands = + pytest {posargs} + [testenv:release] changedir= decription = do a release, required posarg of the version number