{ "info": { "author": "holger krekel and contributors", "author_email": "pytest-dev@python.org,holger@merlinux.eu", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Framework :: Pytest", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing", "Topic :: Utilities" ], "description": ".. image:: http://img.shields.io/pypi/v/pytest-xdist.svg\n :alt: PyPI version\n :target: https://pypi.python.org/pypi/pytest-xdist\n\n.. image:: https://img.shields.io/conda/vn/conda-forge/pytest-xdist.svg\n :target: https://anaconda.org/conda-forge/pytest-xdist\n\n.. image:: https://img.shields.io/pypi/pyversions/pytest-xdist.svg\n :alt: Python versions\n :target: https://pypi.python.org/pypi/pytest-xdist\n\n.. image:: https://github.com/pytest-dev/pytest-xdist/workflows/build/badge.svg\n :target: https://github.com/pytest-dev/pytest-xdist/actions\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :target: https://github.com/ambv/black\n\nxdist: pytest distributed testing plugin\n========================================\n\nThe `pytest-xdist`_ plugin extends pytest with some unique\ntest execution modes:\n\n* test run parallelization_: if you have multiple CPUs or hosts you can use\n those for a combined test run. This allows to speed up\n development or to use special resources of `remote machines`_.\n\n\n* ``--looponfail``: run your tests repeatedly in a subprocess. After each run\n pytest waits until a file in your project changes and then re-runs\n the previously failing tests. This is repeated until all tests pass\n after which again a full run is performed.\n\n* `Multi-Platform`_ coverage: you can specify different Python interpreters\n or different platforms and run tests in parallel on all of them.\n\nBefore running tests remotely, ``pytest`` efficiently \"rsyncs\" your\nprogram source code to the remote place. All test results\nare reported back and displayed to your local terminal.\nYou may specify different Python versions and interpreters.\n\nIf you would like to know how pytest-xdist works under the covers, checkout\n`OVERVIEW `_.\n\n\nInstallation\n------------\n\nInstall the plugin with::\n\n pip install pytest-xdist\n\n\nTo use ``psutil`` for detection of the number of CPUs available, install the ``psutil`` extra::\n\n pip install pytest-xdist[psutil]\n\n\n.. _parallelization:\n\nSpeed up test runs by sending tests to multiple CPUs\n----------------------------------------------------\n\nTo send tests to multiple CPUs, use the ``-n`` (or ``--numprocesses``) option::\n\n pytest -n NUMCPUS\n\nPass ``-n auto`` to use as many processes as your computer has CPU cores. This\ncan lead to considerable speed ups, especially if your test suite takes a\nnoticeable amount of time.\n\nIf a test crashes a worker, pytest-xdist will automatically restart that worker\nand report the test\u2019s failure. You can use the ``--max-worker-restart`` option\nto limit the number of worker restarts that are allowed, or disable restarting\naltogether using ``--max-worker-restart 0``.\n\nBy default, using ``--numprocesses`` will send pending tests to any worker that\nis available, without any guaranteed order. You can change the test\ndistribution algorithm this with the ``--dist`` option. It takes these values:\n\n* ``--dist no``: The default algorithm, distributing one test at a time.\n\n* ``--dist loadscope``: Tests are grouped by **module** for *test functions*\n and by **class** for *test methods*. Groups are distributed to available\n workers as whole units. This guarantees that all tests in a group run in the\n same process. This can be useful if you have expensive module-level or\n class-level fixtures. Grouping by class takes priority over grouping by\n module.\n\n* ``--dist loadfile``: Tests are grouped by their containing file. Groups are\n distributed to available workers as whole units. This guarantees that all\n tests in a file run in the same worker.\n\nMaking session-scoped fixtures execute only once\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``pytest-xdist`` is designed so that each worker process will perform its own collection and execute\na subset of all tests. This means that tests in different processes requesting a high-level\nscoped fixture (for example ``session``) will execute the fixture code more than once, which\nbreaks expectations and might be undesired in certain situations.\n\nWhile ``pytest-xdist`` does not have a builtin support for ensuring a session-scoped fixture is\nexecuted exactly once, this can be achieved by using a lock file for inter-process communication.\n\nThe example below needs to execute the fixture ``session_data`` only once (because it is\nresource intensive, or needs to execute only once to define configuration options, etc), so it makes\nuse of a `FileLock `_ to produce the fixture data only once\nwhen the first process requests the fixture, while the other processes will then read\nthe data from a file.\n\nHere is the code:\n\n.. code-block:: python\n\n import json\n\n import pytest\n from filelock import FileLock\n\n\n @pytest.fixture(scope=\"session\")\n def session_data(tmp_path_factory, worker_id):\n if worker_id == \"master\":\n # not executing in with multiple workers, just produce the data and let\n # pytest's fixture caching do its job\n return produce_expensive_data()\n\n # get the temp directory shared by all workers\n root_tmp_dir = tmp_path_factory.getbasetemp().parent\n\n fn = root_tmp_dir / \"data.json\"\n with FileLock(str(fn) + \".lock\"):\n if fn.is_file():\n data = json.loads(fn.read_text())\n else:\n data = produce_expensive_data()\n fn.write_text(json.dumps(data))\n return data\n\n\nThe example above can also be use in cases a fixture needs to execute exactly once per test session, like\ninitializing a database service and populating initial tables.\n\nThis technique might not work for every case, but should be a starting point for many situations\nwhere executing a high-scope fixture exactly once is important.\n\nRunning tests in a Python subprocess\n------------------------------------\n\nTo instantiate a python3.5 subprocess and send tests to it, you may type::\n\n pytest -d --tx popen//python=python3.5\n\nThis will start a subprocess which is run with the ``python3.5``\nPython interpreter, found in your system binary lookup path.\n\nIf you prefix the --tx option value like this::\n\n --tx 3*popen//python=python3.5\n\nthen three subprocesses would be created and tests\nwill be load-balanced across these three processes.\n\n.. _boxed:\n\nRunning tests in a boxed subprocess\n-----------------------------------\n\nThis functionality has been moved to the\n`pytest-forked `_ plugin, but the ``--boxed`` option\nis still kept for backward compatibility.\n\n.. _`remote machines`:\n\nSending tests to remote SSH accounts\n------------------------------------\n\nSuppose you have a package ``mypkg`` which contains some\ntests that you can successfully run locally. And you\nhave a ssh-reachable machine ``myhost``. Then\nyou can ad-hoc distribute your tests by typing::\n\n pytest -d --tx ssh=myhostpopen --rsyncdir mypkg mypkg\n\nThis will synchronize your :code:`mypkg` package directory\nto a remote ssh account and then locally collect tests\nand send them to remote places for execution.\n\nYou can specify multiple :code:`--rsyncdir` directories\nto be sent to the remote side.\n\n.. note::\n\n For pytest to collect and send tests correctly\n you not only need to make sure all code and tests\n directories are rsynced, but that any test (sub) directory\n also has an :code:`__init__.py` file because internally\n pytest references tests as a fully qualified python\n module path. **You will otherwise get strange errors**\n during setup of the remote side.\n\n\nYou can specify multiple :code:`--rsyncignore` glob patterns\nto be ignored when file are sent to the remote side.\nThere are also internal ignores: :code:`.*, *.pyc, *.pyo, *~`\nThose you cannot override using rsyncignore command-line or\nini-file option(s).\n\n\nSending tests to remote Socket Servers\n--------------------------------------\n\nDownload the single-module `socketserver.py`_ Python program\nand run it like this::\n\n python socketserver.py\n\nIt will tell you that it starts listening on the default\nport. You can now on your home machine specify this\nnew socket host with something like this::\n\n pytest -d --tx socket=192.168.1.102:8888 --rsyncdir mypkg mypkg\n\n\n.. _`atonce`:\n.. _`Multi-Platform`:\n\n\nRunning tests on many platforms at once\n---------------------------------------\n\nThe basic command to run tests on multiple platforms is::\n\n pytest --dist=each --tx=spec1 --tx=spec2\n\nIf you specify a windows host, an OSX host and a Linux\nenvironment this command will send each tests to all\nplatforms - and report back failures from all platforms\nat once. The specifications strings use the `xspec syntax`_.\n\n.. _`xspec syntax`: http://codespeak.net/execnet/basics.html#xspec\n\n.. _`socketserver.py`: https://raw.githubusercontent.com/pytest-dev/execnet/master/execnet/script/socketserver.py\n\n.. _`execnet`: http://codespeak.net/execnet\n\nIdentifying the worker process during a test\n--------------------------------------------\n\n*New in version 1.15.*\n\nIf you need to determine the identity of a worker process in\na test or fixture, you may use the ``worker_id`` fixture to do so:\n\n.. code-block:: python\n\n @pytest.fixture()\n def user_account(worker_id):\n \"\"\" use a different account in each xdist worker \"\"\"\n return \"account_%s\" % worker_id\n\nWhen ``xdist`` is disabled (running with ``-n0`` for example), then\n``worker_id`` will return ``\"master\"``.\n\nWorker processes also have the following environment variables\ndefined:\n\n* ``PYTEST_XDIST_WORKER``: the name of the worker, e.g., ``\"gw2\"``.\n* ``PYTEST_XDIST_WORKER_COUNT``: the total number of workers in this session,\n e.g., ``\"4\"`` when ``-n 4`` is given in the command-line.\n\nThe information about the worker_id in a test is stored in the ``TestReport`` as\nwell, under the ``worker_id`` attribute.\n\nSince version 2.0, the following functions are also available in the ``xdist`` module:\n\n.. code-block:: python\n\n def is_xdist_worker(request_or_session) -> bool:\n \"\"\"Return `True` if this is an xdist worker, `False` otherwise\n\n :param request_or_session: the `pytest` `request` or `session` object\n \"\"\"\n\n def is_xdist_master(request_or_session) -> bool:\n \"\"\"Return `True` if this is the xdist master, `False` otherwise\n\n Note: this method also returns `False` when distribution has not been\n activated at all.\n\n :param request_or_session: the `pytest` `request` or `session` object\n \"\"\"\n\n def get_xdist_worker_id(request_or_session) -> str:\n \"\"\"Return the id of the current worker ('gw0', 'gw1', etc) or 'master'\n if running on the 'master' node.\n\n If not distributing tests (for example passing `-n0` or not passing `-n` at all) also return 'master'.\n\n :param request_or_session: the `pytest` `request` or `session` object\n \"\"\"\n\n\nUniquely identifying the current test run\n-----------------------------------------\n\n*New in version 1.32.*\n\nIf you need to globally distinguish one test run from others in your\nworkers, you can use the ``testrun_uid`` fixture. For instance, let's say you\nwanted to create a separate database for each test run:\n\n.. code-block:: python\n\n import pytest\n from posix_ipc import Semaphore, O_CREAT\n\n @pytest.fixture(scope=\"session\", autouse=True)\n def create_unique_database(testrun_uid):\n \"\"\" create a unique database for this particular test run \"\"\"\n database_url = f\"psql://myapp-{testrun_uid}\"\n\n with Semaphore(f\"/{testrun_uid}-lock\", flags=O_CREAT, initial_value=1):\n if not database_exists(database_url):\n create_database(database_url)\n\n @pytest.fixture()\n def db(testrun_uid):\n \"\"\" retrieve unique database \"\"\"\n database_url = f\"psql://myapp-{testrun_uid}\"\n return database_get_instance(database_url)\n\n\nAdditionally, during a test run, the following environment variable is defined:\n\n* ``PYTEST_XDIST_TESTRUNUID``: the unique id of the test run.\n\nAccessing ``sys.argv`` from the master node in workers\n------------------------------------------------------\n\nTo access the ``sys.argv`` passed to the command-line of the master node, use\n``request.config.workerinput[\"mainargv\"]``.\n\n\nSpecifying test exec environments in an ini file\n------------------------------------------------\n\nYou can use pytest's ini file configuration to avoid typing common options.\nYou can for example make running with three subprocesses your default like this:\n\n.. code-block:: ini\n\n [pytest]\n addopts = -n3\n\nYou can also add default environments like this:\n\n.. code-block:: ini\n\n [pytest]\n addopts = --tx ssh=myhost//python=python3.5 --tx ssh=myhost//python=python3.6\n\nand then just type::\n\n pytest --dist=each\n\nto run tests in each of the environments.\n\n\nSpecifying \"rsync\" dirs in an ini-file\n--------------------------------------\n\nIn a ``tox.ini`` or ``setup.cfg`` file in your root project directory\nyou may specify directories to include or to exclude in synchronisation:\n\n.. code-block:: ini\n\n [pytest]\n rsyncdirs = . mypkg helperpkg\n rsyncignore = .hg\n\nThese directory specifications are relative to the directory\nwhere the configuration file was found.\n\n.. _`pytest-xdist`: http://pypi.python.org/pypi/pytest-xdist\n.. _`pytest-xdist repository`: https://github.com/pytest-dev/pytest-xdist\n.. _`pytest`: http://pytest.org", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/pytest-dev/pytest-xdist", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "qieman-xdist", "package_url": "https://pypi.org/project/qieman-xdist/", "platform": "linux", "project_url": "https://pypi.org/project/qieman-xdist/", "project_urls": { "Homepage": "https://github.com/pytest-dev/pytest-xdist" }, "release_url": "https://pypi.org/project/qieman-xdist/0.7/", "requires_dist": null, "requires_python": ">=3.5", "summary": "pytest xdist plugin for distributed testing and loop-on-failing modes", "version": "0.7", "yanked": false, "yanked_reason": null }, "last_serial": 9252473, "releases": { "0.3": [ { "comment_text": "", "digests": { "md5": "94556be23409c4856d530905450001f1", "sha256": "5773165f214cba0ec6078fcb627e5b2537d64b5dc279348d8fe6d782fc3b1879" }, "downloads": -1, "filename": "qieman-xdist-0.3.tar.gz", "has_sig": false, "md5_digest": "94556be23409c4856d530905450001f1", "packagetype": "sdist", "python_version": "source", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "size": 64002, "upload_time": "2019-11-22T09:08:16", "upload_time_iso_8601": "2019-11-22T09:08:16.328964Z", "url": "https://files.pythonhosted.org/packages/e2/45/d637a47d7699ba2c506232a11c86cdf5d666416dc1be9ae39705fc9d6d6b/qieman-xdist-0.3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.4": [ { "comment_text": "", "digests": { "md5": "17052ad9b93ef6fcf3b966aca1e1618d", "sha256": "7ba130fe12422f5275e1f7bf2c222d126fafc7fbab13eee7cb0028a846b4dd6e" }, "downloads": -1, "filename": "qieman-xdist-0.4.tar.gz", "has_sig": false, "md5_digest": "17052ad9b93ef6fcf3b966aca1e1618d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "size": 64022, "upload_time": "2020-01-06T03:30:27", "upload_time_iso_8601": "2020-01-06T03:30:27.458553Z", "url": "https://files.pythonhosted.org/packages/ed/29/cf622a89bc04838852a32318d7c84d58307729fe892facd10d4d5b5fbb3f/qieman-xdist-0.4.tar.gz", "yanked": false, "yanked_reason": null } ], "0.5": [ { "comment_text": "", "digests": { "md5": "1ab2bcb76c570f0e47dd9c8f32347c44", "sha256": "0e8370e95f32be871fc339a932692573eeebbe6ad2d7114fbecefff494970e6e" }, "downloads": -1, "filename": "qieman-xdist-0.5.tar.gz", "has_sig": false, "md5_digest": "1ab2bcb76c570f0e47dd9c8f32347c44", "packagetype": "sdist", "python_version": "source", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "size": 64023, "upload_time": "2020-01-06T03:34:19", "upload_time_iso_8601": "2020-01-06T03:34:19.161392Z", "url": "https://files.pythonhosted.org/packages/4d/97/611963bd6422146e50b40bcdfbabf7da8ea03b82835651e3efbfd0dcbfb6/qieman-xdist-0.5.tar.gz", "yanked": false, "yanked_reason": null } ], "0.6": [ { "comment_text": "", "digests": { "md5": "c4153c4443cb40538b0d45f446d25017", "sha256": "7b9e9c3437c3f1c22e21fae4beb0340572b081d651d6882d1c0d93c97107bff2" }, "downloads": -1, "filename": "qieman-xdist-0.6.tar.gz", "has_sig": false, "md5_digest": "c4153c4443cb40538b0d45f446d25017", "packagetype": "sdist", "python_version": "source", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "size": 64164, "upload_time": "2020-01-06T03:41:40", "upload_time_iso_8601": "2020-01-06T03:41:40.536011Z", "url": "https://files.pythonhosted.org/packages/a5/98/6e440b58543d7a61f54ed2ef5a0d267986db0fe654d8edf0f05732a40bea/qieman-xdist-0.6.tar.gz", "yanked": false, "yanked_reason": null } ], "0.7": [ { "comment_text": "", "digests": { "md5": "bccba2c4838d41911e383346d337c33e", "sha256": "e6c34a9546d851530dd447483ba917a2b0b3240c660844b7dad849ad97fbd793" }, "downloads": -1, "filename": "qieman-xdist-0.7.tar.gz", "has_sig": false, "md5_digest": "bccba2c4838d41911e383346d337c33e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 64824, "upload_time": "2021-01-28T07:27:23", "upload_time_iso_8601": "2021-01-28T07:27:23.662823Z", "url": "https://files.pythonhosted.org/packages/5a/71/6b361a1c37c4fbddb377ea38223c6fed9164950e2a24199444181aaf61eb/qieman-xdist-0.7.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "bccba2c4838d41911e383346d337c33e", "sha256": "e6c34a9546d851530dd447483ba917a2b0b3240c660844b7dad849ad97fbd793" }, "downloads": -1, "filename": "qieman-xdist-0.7.tar.gz", "has_sig": false, "md5_digest": "bccba2c4838d41911e383346d337c33e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 64824, "upload_time": "2021-01-28T07:27:23", "upload_time_iso_8601": "2021-01-28T07:27:23.662823Z", "url": "https://files.pythonhosted.org/packages/5a/71/6b361a1c37c4fbddb377ea38223c6fed9164950e2a24199444181aaf61eb/qieman-xdist-0.7.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }