Compare commits

..

52 Commits

Author SHA1 Message Date
Bruno Oliveira
3652e21f3b Prepare release 1.18.1 2017-07-05 21:25:10 -03:00
Bruno Oliveira
a84b106a3b Add issue links to changelog template 2017-07-05 21:17:16 -03:00
Bruno Oliveira
5d757f9db3 Merge pull request #178 from timyhou/locals_d_issue
Unserialize reprlocals to a ReprLocal instance
2017-07-05 12:46:41 -03:00
Bruno Oliveira
674c623ffa Merge pull request #180 from luisincrespo/patch-1
Update CHANGELOG.rst
2017-07-05 12:36:00 -03:00
Luis Crespo
1fca8ee16d Update CHANGELOG.rst 2017-07-05 11:17:54 -04:00
Luis Crespo
185595f596 Update CHANGELOG.rst 2017-07-05 11:17:36 -04:00
Luis Crespo
55bc8c49d6 Update CHANGELOG.rst
Update `1.18.0` entry in CHANGELOG to reflect that `pytest-xdist` now requires `pytest>=3.0.0`.
2017-07-05 11:14:52 -04:00
thou
530c9b234a Unserialize reprlocals to a ReprLocal instance 2017-06-30 15:00:50 -05:00
Bruno Oliveira
1ca9eff35d Fixed changelog wording to be more user friendly 2017-06-28 18:32:59 -03:00
Bruno Oliveira
5320d25e47 Merge pull request #171 from timyhou/longrepr.sections_issue
Serialization/Deserialization was dropping longrepr.sections
2017-06-28 18:31:19 -03:00
thou
96ad4d1cfd Added news fragment 2017-06-28 10:58:37 -05:00
thou
5c1a35fee4 Serialization / Deserialization was dropping longrepr.sections 2017-06-27 16:30:49 -05:00
Bruno Oliveira
665b8eda8d Merge pull request #170 from nicoddemus/release-1.18.0
release 1.18.0
2017-06-26 21:28:30 -03:00
Bruno Oliveira
cee78e9b20 CHANGELOG for 1.18.0 2017-06-26 15:16:48 -03:00
Bruno Oliveira
6e1154881d Merge pull request #164 from timyhou/master
Issue #130
2017-06-23 19:39:27 -03:00
Ronny Pfannschmidt
a96f6c9038 Merge pull request #168 from kain88-de/numprocesses-option
add '--numprocesses' as long option for '-n'
2017-06-23 09:45:46 +02:00
Bruno Oliveira
47b65716a3 Fix test for --numprocess flag 2017-06-22 21:47:34 -03:00
Max Linke
dbaf49cd69 add '--numprocesses' as long option for '-n'
This is more verbose in scripts that run pytest-xdist. It can also help
in some ci-helper scripts like to auto detect if  pytest-xdist should be
installed.
2017-06-22 21:53:16 +02:00
Bruno Oliveira
41c00ca47e Clarify PR template
Clarify that a new "file" should be added to "changelog" folder.
2017-06-22 16:41:27 -03:00
thou
f0dee10a0d Fix failing test since spawn.out does not contain "LOOPONFAILING" in pytest >= 3 2017-06-21 13:37:03 -05:00
Tim Hou
6256608669 Update tox and appveyor for CI tests to exclude pytest < 3
Update the install requires versions for pytest
2017-06-21 13:37:02 -05:00
thou
4a1f1d879b Updated serialize_report and unserialize_report to pass entire exception info using ReprExceptionInfo.
This addresses issue #130.
2017-06-21 13:36:58 -05:00
Ronny Pfannschmidt
2094157950 Merge pull request #162 from nicoddemus/let-setuptools-scm-manage-manifest
Let setuptools_scm manage the files that go into the package
2017-06-14 13:43:46 +02:00
Bruno Oliveira
7473683cdb Let setuptools_scm manage the files that go into the package
As discussed in #161, setuptools_scm will automatically
add all version controlled files to the package, so
MANIFEST.in is no longer needed

Fix #161
2017-06-14 07:58:57 -03:00
Bruno Oliveira
c48834aa69 Merge pull request #159 from nicoddemus/release-1.17.1
Release 1.17.1
2017-06-10 10:59:42 -03:00
Bruno Oliveira
6d9d6c6a34 Update HOWTORELEASE docs 2017-06-10 10:03:10 -03:00
Bruno Oliveira
1542aff326 Update CHANGELOG 2017-06-10 10:02:55 -03:00
Bruno Oliveira
cc95cf26e1 Skip uploading docs when publishing to PyPI
This should also solve the problem of not publishing wheels
2017-06-10 10:02:43 -03:00
Bruno Oliveira
eb90a7c82c Merge pull request #158 from nicoddemus/revert-pr-125
Revert PR 125 due to 1.17.0 breakage
2017-06-10 09:55:51 -03:00
Bruno Oliveira
afe8bad9ff Add news fragment
Fix #157
2017-06-10 09:44:55 -03:00
Bruno Oliveira
95a62460aa Revert "Mark test as complete at teardown."
This reverts commit 82b992a5fd.
2017-06-10 09:43:59 -03:00
Bruno Oliveira
8e2fdeee3e Revert "- Reinforce test_crashing_item to match test name instead of test"
This reverts commit 99f667380f.
2017-06-10 09:43:59 -03:00
Bruno Oliveira
fae1e02c1d Revert "Fix missing blank line."
This reverts commit 602694b817.
2017-06-10 09:43:59 -03:00
Ronny Pfannschmidt
3440f08a40 Merge pull request #156 from nicoddemus/release-howto-towncrier
Add towncrier and HOWTORELEASE docs
2017-06-10 09:00:47 +02:00
Bruno Oliveira
a9b064d992 Add HOWTORELEASE document
Fix #155
2017-06-09 19:50:54 -03:00
Bruno Oliveira
47875cbea9 Add towncrier for CHANGELOG management
Fix #154
2017-06-09 19:49:06 -03:00
Bruno Oliveira
e59c609b59 Merge pull request #153 from reginaldl/master
Fix CHANGELOG for issue #124
2017-06-09 18:52:11 -03:00
reginaldl
de257e6b83 Fix CHANGELOG for issue #124 2017-06-09 10:51:12 -07:00
Ronny Pfannschmidt
51b5a5ace4 Merge pull request #140 from xoviat/patch-1
travis: use tox-travis
2017-05-17 10:34:15 +02:00
Ronny Pfannschmidt
d86ce20d28 Merge pull request #144 from EdgeCaseLabs/master
Correcting broken URI in documentation.
2017-05-16 15:21:40 +02:00
Wes Thomas
58750f5765 Correcting broken URI in documentation. 2017-05-11 15:29:39 -05:00
xoviat
0789605d30 fixup py36 tests 2017-05-08 09:12:47 -05:00
xoviat
2b57d85550 travis: use tox-travis 2017-05-08 09:11:32 -05:00
Omer Katz
0ce4f32315 Run tests on Python 3.6 on windows. 2017-05-08 09:11:32 -05:00
Omer Katz
de7a45ef40 Test with Python 3.6 as well. 2017-05-08 09:11:32 -05:00
Ronny Pfannschmidt
e83aae6351 Merge pull request #125 from reginaldl/master
Mark test as complete at teardown.
2017-05-05 22:43:53 +02:00
Ronny Pfannschmidt
a23f572b21 Merge pull request #138 from nicoddemus/anaconda-ver
Add a badge for the anaconda package
2017-05-05 07:11:52 +02:00
Bruno Oliveira
36c0e68c23 Add a badge for the anaconda package
Also bring Travis and AppVeyor badges near each other
2017-04-24 17:04:59 -03:00
reginaldl
c79a98c624 Add note about #124 to CHANGELOG. 2017-03-07 10:15:52 -08:00
reginaldl
602694b817 Fix missing blank line. 2017-02-23 15:14:24 -08:00
reginaldl
99f667380f - Reinforce test_crashing_item to match test name instead of test
file.
- Add `test_crashing_item_teardown` to validate crash behavior at
  teardown.
2017-02-23 15:01:48 -08:00
reginaldl
82b992a5fd Mark test as complete at teardown. 2017-02-23 11:31:37 -08:00
20 changed files with 416 additions and 85 deletions

17
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,17 @@
Thanks for submitting a PR, your contribution is really appreciated!
Here's a quick checklist that should be present in PRs:
- [ ] Make sure to include reasonable tests for your change if necessary
- [ ] Add a *news* file into the `changelog` folder, following these guidelines:
* Name it `$issue_id.$type` for example `588.bug`
* If you don't have an issue_id change it to the PR id after creating it
* Ensure type is one of `removal`, `feature`, `bugfix`, `vendor`, `doc` or `trivial`
* Make sure to use full sentences with correct case and punctuation, for example:
```
Fix issue with non-ascii contents in doctest text files.
```

View File

@@ -1,30 +1,19 @@
sudo: false sudo: false
language: python language: python
python: python:
- '2.6'
- '2.7'
- '3.4'
- '3.5' - '3.5'
install: pip install -U tox setuptools_scm - '3.6'
env: install: pip install tox-travis setuptools_scm
matrix: matrix:
include:
# note: please use "tox --listenvs" to populate the build matrix # note: please use "tox --listenvs" to populate the build matrix
- TOXENV=py26-pytest27 - python: "3.5"
- TOXENV=py26-pytest28 env: TOXENV=flakes
- TOXENV=py26-pytest29 - python: "3.5"
- TOXENV=py26-pytest30 env: TOXENV=readme
- TOXENV=py27-pytest27
- TOXENV=py27-pytest28
- TOXENV=py27-pytest29
- TOXENV=py27-pytest30
- TOXENV=py34-pytest27
- TOXENV=py34-pytest28
- TOXENV=py34-pytest29
- TOXENV=py34-pytest30
- TOXENV=py35-pytest27
- TOXENV=py35-pytest28
- TOXENV=py35-pytest29
- TOXENV=py27-pytest28-pexpect
- TOXENV=py35-pytest28-pexpect
- TOXENV=flakes
- TOXENV=readme
script: tox script: tox
notifications: notifications:
@@ -39,6 +28,7 @@ notifications:
deploy: deploy:
provider: pypi provider: pypi
user: ronny user: ronny
skip_upload_docs: true
password: password:
secure: cxmSDho5d+PYKEM4ZCg8ms1P4lzhYkrw6fEOm2HtTcsuCyY6aZMSgImWAnEYbJHSkdzgcxlXK9UKJ9B0YenXmBCkAr7UjdnpNXNmkySr0sYzlH/sfqt/dDATCHFaRKxnkOSOVywaDYhT9n8YudbXI77pXwD12i/CeSSJDbHhsu0JYUfAcb+D6YjRYoA2SEGCnzSzg+gDDfwXZx4ZiODCGLVwieNp1klCg88YROUE1BaYYNuUOONvfXX8+TWowbCF6ChH1WL/bZ49OStEYQNuYxZQZr4yClIqu9VJbchrU8j860K9ott2kkGTgfB/dDrQB/XncBubyIX9ikzCQAmmBXWAI3eyvWLPDk2Jz7kW2l2RT7syct80tCq3JhvQ1qdwr5ap7siocTLgnBW0tF4tkHSTFN3510fkc43npnp6FThebESQpnI24vqpwJ9hI/kW5mYi014Og2E/cpCXnz2XO8iZPDbqAMQpDsqEQoyhfGNgPTGp4K30TxRtwZBI5hHhDKnnR16fXtRgt1gYPvz/peUQvvpOm4JzIzGXPzluuutpnCBy75v5+oiwT3YRrLL/Meims9FtDDXL3qQubAE/ezIOOpm0N5XXV8DxIom8EN71yq5ab1tqhM+tBX7owRjy4FR4If2Q8feBdmTuh26DIQt/y+qSG8VkB9Sw/JCjc7c= secure: cxmSDho5d+PYKEM4ZCg8ms1P4lzhYkrw6fEOm2HtTcsuCyY6aZMSgImWAnEYbJHSkdzgcxlXK9UKJ9B0YenXmBCkAr7UjdnpNXNmkySr0sYzlH/sfqt/dDATCHFaRKxnkOSOVywaDYhT9n8YudbXI77pXwD12i/CeSSJDbHhsu0JYUfAcb+D6YjRYoA2SEGCnzSzg+gDDfwXZx4ZiODCGLVwieNp1klCg88YROUE1BaYYNuUOONvfXX8+TWowbCF6ChH1WL/bZ49OStEYQNuYxZQZr4yClIqu9VJbchrU8j860K9ott2kkGTgfB/dDrQB/XncBubyIX9ikzCQAmmBXWAI3eyvWLPDk2Jz7kW2l2RT7syct80tCq3JhvQ1qdwr5ap7siocTLgnBW0tF4tkHSTFN3510fkc43npnp6FThebESQpnI24vqpwJ9hI/kW5mYi014Og2E/cpCXnz2XO8iZPDbqAMQpDsqEQoyhfGNgPTGp4K30TxRtwZBI5hHhDKnnR16fXtRgt1gYPvz/peUQvvpOm4JzIzGXPzluuutpnCBy75v5+oiwT3YRrLL/Meims9FtDDXL3qQubAE/ezIOOpm0N5XXV8DxIom8EN71yq5ab1tqhM+tBX7owRjy4FR4If2Q8feBdmTuh26DIQt/y+qSG8VkB9Sw/JCjc7c=
on: on:

View File

@@ -1,3 +1,70 @@
pytest-xdist 1.18.1 (2017-07-05)
================================
Bug Fixes
---------
- Fixed serialization of ``longrepr.sections`` during error reporting from
workers. (`#171 <https://github.com/pytest-dev/pytest-xdist/issues/171>`_)
- Fix ``ReprLocal`` not being unserialized breaking --showlocals usages. (`#176
<https://github.com/pytest-dev/pytest-xdist/issues/176>`_)
pytest-xdist 1.18.0 (2017-06-26)
================================
- ``pytest-xdist`` now requires ``pytest>=3.0.0``.
Features
--------
- Add long option `--numprocesses` as alternative for `-n`. (#168)
Bug Fixes
---------
- Fix serialization and deserialization dropping longrepr details. (#133)
pytest-xdist 1.17.1 (2017-06-10)
================================
Bug Fixes
---------
- Hot fix release reverting the change introduced by #124, unfortunately it
broke a number of test suites so we are reversing this change while we
investigate the problem. (#157)
Improved Documentation
----------------------
- Introduced ``towncrier`` for ``CHANGELOG`` management. (#154)
- Added ``HOWTORELEASE`` documentation. (#155)
..
You should *NOT* be adding new change log entries to this file, this
file is managed by towncrier. You *may* edit previous change logs to
fix problems like typo corrections or such.
To add a new change log entry, please see
https://pip.pypa.io/en/latest/development/#adding-a-news-entry
We named the news folder ``changelog``
.. towncrier release notes start
1.17.0
------
- fix #124: xdist would mark test as complete after 'call' step. As a result,
xdist could identify the wrong test as failing when test crashes at teardown.
To address this issue, xdist now marks test as complete at teardown.
1.16.0 1.16.0
------ ------

45
HOWTORELEASE.rst Normal file
View File

@@ -0,0 +1,45 @@
======================
Releasing pytest-xdist
======================
This document describes the steps to make a new ``pytest-xdist`` release.
Version
-------
``master`` should always be green and a potential release candidate. ``pytest-xdist`` follows
semantic versioning, so given that the current version is ``X.Y.Z``, to find the next version number
one needs to look at the ``changelog`` folder:
- If there is any file named ``*.feature``, then we must make a new **minor** release: next
release will be ``X.Y+1.0``.
- Otherwise it is just a **bug fix** release: ``X.Y.Z+1``.
Steps
-----
To publish a new release ``X.Y.Z``, the steps are as follows:
#. Create a new branch named ``release-X.Y.Z`` from the latest ``master``.
#. Install ``pytest-xdist`` and dev requirements in a virtualenv::
$ pip install -e . -r dev-requirements.txt
#. Update ``CHANGELOG.rst`` file by running::
$ towncrier --version X.Y.Z
It might ask for confirmation to remove news fragments; answer yes.
#. Commit and push the branch for review.
#. Once PR is **green** and **approved**, create and push a tag::
$ export VERSION=X.Y.Z
$ git tag v$VERSION release-$VERSION
$ git push git@github.com:pytest-dev/pytest-xdist.git v$VERSION
That will build the package and publish it on ``PyPI`` automatically.

View File

@@ -1,7 +0,0 @@
include CHANGELOG
include LICENSE
include README.txt
include setup.py
include tox.ini
graft testing
prune .git

View File

@@ -1,10 +1,14 @@
.. image:: http://img.shields.io/pypi/v/pytest-xdist.svg
:target: https://pypi.python.org/pypi/pytest-xdist
.. image:: https://anaconda.org/conda-forge/pytest-xdist/badges/version.svg
:target: https://anaconda.org/conda-forge/pytest-xdist
.. image:: https://travis-ci.org/pytest-dev/pytest-xdist.svg?branch=master .. image:: https://travis-ci.org/pytest-dev/pytest-xdist.svg?branch=master
:target: https://travis-ci.org/pytest-dev/pytest-xdist :target: https://travis-ci.org/pytest-dev/pytest-xdist
.. image:: http://img.shields.io/pypi/v/pytest-xdist.svg
:target: https://pypi.python.org/pypi/pytest-xdist
.. image:: https://ci.appveyor.com/api/projects/status/56eq1a1avd4sdd7e/branch/master?svg=true .. image:: https://ci.appveyor.com/api/projects/status/56eq1a1avd4sdd7e/branch/master?svg=true
:target: https://ci.appveyor.com/project/pytestbot/pytest-xdist :target: https://ci.appveyor.com/project/pytestbot/pytest-xdist

View File

@@ -1,23 +1,13 @@
environment: environment:
matrix: matrix:
# note: please use "tox --listenvs" to populate the build matrix # note: please use "tox --listenvs" to populate the build matrix
- TOXENV: "py26-pytest27"
- TOXENV: "py26-pytest28"
- TOXENV: "py26-pytest29"
- TOXENV: "py26-pytest30" - TOXENV: "py26-pytest30"
- TOXENV: "py27-pytest27"
- TOXENV: "py27-pytest28"
- TOXENV: "py27-pytest29"
- TOXENV: "py27-pytest30" - TOXENV: "py27-pytest30"
- TOXENV: "py34-pytest27"
- TOXENV: "py34-pytest28"
- TOXENV: "py34-pytest29"
- TOXENV: "py34-pytest30" - TOXENV: "py34-pytest30"
- TOXENV: "py35-pytest27" - TOXENV: "py35-pytest30"
- TOXENV: "py35-pytest28" - TOXENV: "py36-pytest30"
- TOXENV: "py35-pytest29" - TOXENV: "py27-pytest30-pexpect"
- TOXENV: "py27-pytest28-pexpect" - TOXENV: "py35-pytest30-pexpect"
- TOXENV: "py35-pytest28-pexpect"
- TOXENV: "flakes" - TOXENV: "flakes"
- TOXENV: "readme" - TOXENV: "readme"

39
changelog/_template.rst Normal file
View File

@@ -0,0 +1,39 @@
{% for section in sections %}
{% set underline = "-" %}
{% if section %}
{{section}}
{{ underline * section|length }}{% set underline = "~" %}
{% endif %}
{% if sections[section] %}
{% for category, val in definitions.items() if category in sections[section] %}
{{ definitions[category]['name'] }}
{{ underline * definitions[category]['name']|length }}
{% if definitions[category]['showcontent'] %}
{% for text, values in sections[section][category]|dictsort(by='value') %}
- {{ text }}{% if category != 'vendor' %} (`{{ values[0] }} <https://github.com/pytest-dev/pytest-xdist/issues/{{ values[0][1:] }}>`_){% endif %}
{% endfor %}
{% else %}
- {{ sections[section][category]['']|sort|join(', ') }}
{% endif %}
{% if sections[section][category]|length == 0 %}
No significant changes.
{% else %}
{% endif %}
{% endfor %}
{% else %}
No significant changes.
{% endif %}
{% endfor %}

1
dev-requirements.txt Normal file
View File

@@ -0,0 +1 @@
towncrier

36
pyproject.toml Normal file
View File

@@ -0,0 +1,36 @@
[tool.towncrier]
package = "xdist"
filename = "CHANGELOG.rst"
directory = "changelog/"
title_format = "pytest-xdist {version} ({project_date})"
template = "changelog/_template.rst"
[[tool.towncrier.type]]
directory = "removal"
name = "Deprecations and Removals"
showcontent = true
[[tool.towncrier.type]]
directory = "feature"
name = "Features"
showcontent = true
[[tool.towncrier.type]]
directory = "bugfix"
name = "Bug Fixes"
showcontent = true
[[tool.towncrier.type]]
directory = "vendor"
name = "Vendored Libraries"
showcontent = true
[[tool.towncrier.type]]
directory = "doc"
name = "Improved Documentation"
showcontent = true
[[tool.towncrier.type]]
directory = "trivial"
name = "Trivial Changes"
showcontent = false

View File

@@ -20,7 +20,7 @@ setup(
], ],
}, },
zip_safe=False, zip_safe=False,
install_requires=['execnet>=1.1', 'pytest>=2.7.0', 'py>=1.4.22'], install_requires=['execnet>=1.1', 'pytest>=3.0.0', 'py>=1.4.22'],
setup_requires=['setuptools_scm'], setup_requires=['setuptools_scm'],
classifiers=[ classifiers=[
'Development Status :: 5 - Production/Stable', 'Development Status :: 5 - Production/Stable',

View File

@@ -10,7 +10,9 @@ class TestDistribution:
""") """)
result = testdir.runpytest(p1, "-n1") result = testdir.runpytest(p1, "-n1")
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines(["*1 passed*", ]) result.stdout.fnmatch_lines([
"*1 passed*",
])
def test_n1_fail(self, testdir): def test_n1_fail(self, testdir):
p1 = testdir.makepyfile(""" p1 = testdir.makepyfile("""
@@ -19,7 +21,9 @@ class TestDistribution:
""") """)
result = testdir.runpytest(p1, "-n1") result = testdir.runpytest(p1, "-n1")
assert result.ret == 1 assert result.ret == 1
result.stdout.fnmatch_lines(["*1 failed*", ]) result.stdout.fnmatch_lines([
"*1 failed*",
])
def test_n1_import_error(self, testdir): def test_n1_import_error(self, testdir):
p1 = testdir.makepyfile(""" p1 = testdir.makepyfile("""
@@ -30,7 +34,7 @@ class TestDistribution:
result = testdir.runpytest(p1, "-n1") result = testdir.runpytest(p1, "-n1")
assert result.ret == 1 assert result.ret == 1
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines([
"E ImportError: *__import_of_missing_module*", "E *Error: No module named *__import_of_missing_module*",
]) ])
def test_n2_import_error(self, testdir): def test_n2_import_error(self, testdir):
@@ -53,7 +57,9 @@ class TestDistribution:
""") """)
result = testdir.runpytest(p1, "-n1") result = testdir.runpytest(p1, "-n1")
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines(["*1 skipped*", ]) result.stdout.fnmatch_lines([
"*1 skipped*",
])
def test_manytests_to_one_import_error(self, testdir): def test_manytests_to_one_import_error(self, testdir):
p1 = testdir.makepyfile(""" p1 = testdir.makepyfile("""
@@ -64,11 +70,12 @@ class TestDistribution:
result = testdir.runpytest(p1, '--tx=popen', '--tx=popen') result = testdir.runpytest(p1, '--tx=popen', '--tx=popen')
assert result.ret in (1, 2) assert result.ret in (1, 2)
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines([
"E ImportError: *__import_of_missing_module*", "E *Error: No module named *__import_of_missing_module*",
]) ])
def test_manytests_to_one_popen(self, testdir): def test_manytests_to_one_popen(self, testdir):
p1 = testdir.makepyfile(""" p1 = testdir.makepyfile(
"""
import py import py
def test_fail0(): def test_fail0():
assert 0 assert 0
@@ -108,10 +115,13 @@ class TestDistribution:
""" % str(testdir.tmpdir)) """ % str(testdir.tmpdir))
result = testdir.runpytest_subprocess(p1, "-n1") result = testdir.runpytest_subprocess(p1, "-n1")
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines(["*1 passed*", ]) result.stdout.fnmatch_lines([
"*1 passed*",
])
def test_dist_ini_specified(self, testdir): def test_dist_ini_specified(self, testdir):
p1 = testdir.makepyfile(""" p1 = testdir.makepyfile(
"""
import py import py
def test_fail0(): def test_fail0():
assert 0 assert 0
@@ -207,14 +217,14 @@ class TestDistribution:
""") """)
p1 = testdir.makepyfile("def test_func(): pass") p1 = testdir.makepyfile("def test_func(): pass")
result = testdir.runpytest("-v", p1, '-d', '--tx=popen') result = testdir.runpytest("-v", p1, '-d', '--tx=popen')
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*0*Python*", "*calculated result is 49*", "*1 passed*" ["*0*Python*", "*calculated result is 49*", "*1 passed*"])
])
assert result.ret == 0 assert result.ret == 0
def test_keyboardinterrupt_hooks_issue79(self, testdir): def test_keyboardinterrupt_hooks_issue79(self, testdir):
testdir.makepyfile(__init__="", testdir.makepyfile(
test_one=""" __init__="",
test_one="""
def test_hello(): def test_hello():
raise KeyboardInterrupt() raise KeyboardInterrupt()
""") """)
@@ -273,8 +283,9 @@ class TestDistEach:
py.test.skip("%s not found" % name) py.test.skip("%s not found" % name)
interpreters.append(interp) interpreters.append(interp)
testdir.makepyfile(__init__="", testdir.makepyfile(
test_one=""" __init__="",
test_one="""
import sys import sys
def test_hello(): def test_hello():
print("%s...%s" % sys.version_info[:2]) print("%s...%s" % sys.version_info[:2])
@@ -335,9 +346,8 @@ def test_teardownfails_one_function(testdir):
assert 0 assert 0
""") """)
result = testdir.runpytest(p, '-n1', '--tx=popen') result = testdir.runpytest(p, '-n1', '--tx=popen')
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*def teardown_function(function):*", "*1 passed*1 error*" ["*def teardown_function(function):*", "*1 passed*1 error*"])
])
@py.test.mark.xfail @py.test.mark.xfail
@@ -350,7 +360,9 @@ def test_terminate_on_hangingnode(testdir):
""") """)
result = testdir.runpytest(p, '--dist=each', '--tx=popen//id=my') result = testdir.runpytest(p, '--dist=each', '--tx=popen//id=my')
assert result.duration < 2.0 assert result.duration < 2.0
result.stdout.fnmatch_lines(["*killed*my*", ]) result.stdout.fnmatch_lines([
"*killed*my*",
])
@pytest.mark.xfail(reason="works if run outside test suite", run=False) @pytest.mark.xfail(reason="works if run outside test suite", run=False)
@@ -377,7 +389,10 @@ def test_session_hooks(testdir):
assert hasattr(sys, 'pytestsessionhooks') assert hasattr(sys, 'pytestsessionhooks')
""") """)
result = testdir.runpytest(p, "--dist=each", "--tx=popen") result = testdir.runpytest(p, "--dist=each", "--tx=popen")
result.stdout.fnmatch_lines(["*ValueError*", "*1 passed*", ]) result.stdout.fnmatch_lines([
"*ValueError*",
"*1 passed*",
])
assert not result.ret assert not result.ret
d = result.parseoutcomes() d = result.parseoutcomes()
assert d['passed'] == 1 assert d['passed'] == 1
@@ -422,7 +437,10 @@ def test_funcarg_teardown_failure(testdir):
pass pass
""") """)
result = testdir.runpytest_subprocess("--debug", p) # , "-n1") result = testdir.runpytest_subprocess("--debug", p) # , "-n1")
result.stdout.fnmatch_lines(["*ValueError*42*", "*1 passed*1 error*", ]) result.stdout.fnmatch_lines([
"*ValueError*42*",
"*1 passed*1 error*",
])
assert result.ret assert result.ret
@@ -453,7 +471,8 @@ def test_skipping(testdir):
def test_issue34_pluginloading_in_subprocess(testdir): def test_issue34_pluginloading_in_subprocess(testdir):
testdir.tmpdir.join("plugin123.py").write(py.code.Source(""" testdir.tmpdir.join("plugin123.py").write(
py.code.Source("""
def pytest_namespace(): def pytest_namespace():
return {'sample_variable': 'testing'} return {'sample_variable': 'testing'}
""")) """))
@@ -464,7 +483,9 @@ def test_issue34_pluginloading_in_subprocess(testdir):
""") """)
result = testdir.runpytest_subprocess("-n1", "-p", "plugin123") result = testdir.runpytest_subprocess("-n1", "-p", "plugin123")
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines(["*1 passed*", ]) result.stdout.fnmatch_lines([
"*1 passed*",
])
def test_fixture_scope_caching_issue503(testdir): def test_fixture_scope_caching_issue503(testdir):
@@ -486,7 +507,9 @@ def test_fixture_scope_caching_issue503(testdir):
""") """)
result = testdir.runpytest(p1, '-v', '-n1') result = testdir.runpytest(p1, '-v', '-n1')
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines(["*2 passed*", ]) result.stdout.fnmatch_lines([
"*2 passed*",
])
def test_issue_594_random_parametrize(testdir): def test_issue_594_random_parametrize(testdir):

View File

@@ -268,7 +268,7 @@ class TestFunctional:
""") """)
child = testdir.spawn_pytest("-f %s" % p) child = testdir.spawn_pytest("-f %s" % p)
child.expect("1 xpass") child.expect("1 xpass")
child.expect("### LOOPONFAILING ####") # child.expect("### LOOPONFAILING ####")
child.expect("waiting for changes") child.expect("waiting for changes")
child.kill(15) child.kill(15)

View File

@@ -20,6 +20,10 @@ def test_dist_options(testdir):
check_options(config) check_options(config)
assert config.option.dist == "load" assert config.option.dist == "load"
assert config.option.tx == ['popen'] * 2 assert config.option.tx == ['popen'] * 2
config = testdir.parseconfigure("--numprocesses", "2")
check_options(config)
assert config.option.dist == "load"
assert config.option.tx == ['popen'] * 2
config = testdir.parseconfigure("-d") config = testdir.parseconfigure("-d")
check_options(config) check_options(config)
assert config.option.dist == "load" assert config.option.dist == "load"

View File

@@ -79,6 +79,62 @@ def test_remoteinitconfig(testdir):
class TestReportSerialization: class TestReportSerialization:
def test_xdist_report_longrepr_reprcrash_130(self, testdir):
reprec = testdir.inline_runsource("""
import py
def test_fail(): assert False, 'Expected Message'
""")
reports = reprec.getreports("pytest_runtest_logreport")
assert len(reports) == 3
rep = reports[1]
added_section = ('Failure Metadata', str("metadata metadata"), "*")
rep.longrepr.sections.append(added_section)
d = serialize_report(rep)
check_marshallable(d)
a = unserialize_report("testreport", d)
# Check assembled == rep
assert a.__dict__.keys() == rep.__dict__.keys()
for key in rep.__dict__.keys():
if key != 'longrepr':
assert getattr(a, key) == getattr(rep, key)
assert rep.longrepr.reprcrash.lineno == a.longrepr.reprcrash.lineno
assert rep.longrepr.reprcrash.message == a.longrepr.reprcrash.message
assert rep.longrepr.reprcrash.path == a.longrepr.reprcrash.path
assert rep.longrepr.reprtraceback.entrysep \
== a.longrepr.reprtraceback.entrysep
assert rep.longrepr.reprtraceback.extraline \
== a.longrepr.reprtraceback.extraline
assert rep.longrepr.reprtraceback.style \
== a.longrepr.reprtraceback.style
assert rep.longrepr.sections == a.longrepr.sections
assert rep.longrepr.reprtraceback.reprentries \
== a.longrepr.reprtraceback.reprentries
# Missing section attribute PR171
assert added_section in a.longrepr.sections
def test_reprentries_serialization_170(self, testdir):
reprec = testdir.inline_runsource("""
def test_fail():
x = 0
assert x
""", '--showlocals', '-n1')
reports = reprec.getreports("pytest_runtest_logreport")
assert len(reports) == 3
rep = reports[1]
d = serialize_report(rep)
a = unserialize_report("testreport", d)
rep_entries = rep.longrepr.reprtraceback.reprentries
a_entries = a.longrepr.reprtraceback.reprentries
assert rep_entries == a_entries
for i in range(len(a_entries)):
assert rep_entries[i].lines == a_entries[i].lines
assert rep_entries[i].localssep == a_entries[i].localssep
assert rep_entries[i].reprfileloc == a_entries[i].reprfileloc
assert rep_entries[i].reprfuncargs == a_entries[i].reprfuncargs
assert rep_entries[i].reprlocals == a_entries[i].reprlocals
assert rep_entries[i].style == a_entries[i].style
def test_itemreport_outcomes(self, testdir): def test_itemreport_outcomes(self, testdir):
reprec = testdir.inline_runsource(""" reprec = testdir.inline_runsource("""
import py import py
@@ -108,7 +164,7 @@ class TestReportSerialization:
assert newrep.when == rep.when assert newrep.when == rep.when
assert newrep.keywords == rep.keywords assert newrep.keywords == rep.keywords
if rep.failed: if rep.failed:
assert newrep.longrepr == str(rep.longrepr) assert newrep.longreprtext == rep.longreprtext
def test_collectreport_passed(self, testdir): def test_collectreport_passed(self, testdir):
reprec = testdir.inline_runsource("def test_func(): pass") reprec = testdir.inline_runsource("def test_func(): pass")

11
tox.ini
View File

@@ -1,10 +1,10 @@
[tox] [tox]
# if you change the envlist, please update .travis.yml file as well # if you change the envlist, please update .travis.yml file as well
envlist= envlist=
py{26,27,34,35}-pytest{27,28,29,30} py{26,27,34,35,36}-pytest{30}
py{27,35}-pytest28-pexpect py{27,35}-pytest{30}-pexpect
flakes flakes
readme readme
[testenv] [testenv]
@@ -14,13 +14,10 @@ deps =
pycmd pycmd
# to avoid .eggs # to avoid .eggs
setuptools_scm setuptools_scm
pytest27: pytest~=2.7.2
pytest28: pytest~=2.8.7
pytest29: pytest~=2.9.2
pytest30: pytest~=3.0.5 pytest30: pytest~=3.0.5
pexpect: pexpect pexpect: pexpect
platform= platform=
pexpect: linux|darwin pexpect: linux|darwin
commands= commands=
# always clean to avoid code unmarshal mismatch on old python/pytest # always clean to avoid code unmarshal mismatch on old python/pytest
py.cleanup -aq py.cleanup -aq

View File

@@ -9,7 +9,7 @@ with the worker instance that executed the hook originally:
You can use this hooks just as you would use normal pytest hooks, but some care You can use this hooks just as you would use normal pytest hooks, but some care
must be taken in plugins in case ``xdist`` is not installed. Please see: must be taken in plugins in case ``xdist`` is not installed. Please see:
http://pytest.org/latest/writing_plugins.html#optionally-using-hooks-from-3rd-party-plugins http://pytest.org/en/latest/writing_plugins.html#optionally-using-hooks-from-3rd-party-plugins
""" """
import pytest import pytest

View File

@@ -20,7 +20,7 @@ def parse_numprocesses(s):
def pytest_addoption(parser): def pytest_addoption(parser):
group = parser.getgroup("xdist", "distributed and subprocess testing") group = parser.getgroup("xdist", "distributed and subprocess testing")
group._addoption( group._addoption(
'-n', dest="numprocesses", metavar="numprocesses", '-n', '--numprocesses', dest="numprocesses", metavar="numprocesses",
action="store", action="store",
type=parse_numprocesses, type=parse_numprocesses,
help="shortcut for '--dist=load --tx=NUM*popen', " help="shortcut for '--dist=load --tx=NUM*popen', "

View File

@@ -98,10 +98,34 @@ class SlaveInteractor:
def serialize_report(rep): def serialize_report(rep):
def disassembled_report(rep):
reprtraceback = rep.longrepr.reprtraceback.__dict__
reprcrash = rep.longrepr.reprcrash.__dict__
new_entries = []
for entry in reprtraceback['reprentries']:
new_entry = entry.__dict__
for key, value in new_entry.items():
if hasattr(value, '__dict__'):
new_entry[key] = value.__dict__
new_entries.append(new_entry)
reprtraceback['reprentries'] = new_entries
return {
'reprcrash': reprcrash,
'reprtraceback': reprtraceback,
'sections': rep.longrepr.sections
}
import py import py
d = rep.__dict__.copy() d = rep.__dict__.copy()
if hasattr(rep.longrepr, 'toterminal'): if hasattr(rep.longrepr, 'toterminal'):
d['longrepr'] = str(rep.longrepr) if hasattr(rep.longrepr, 'reprtraceback') \
and hasattr(rep.longrepr, 'reprcrash'):
d['longrepr'] = disassembled_report(rep)
else:
d['longrepr'] = str(rep.longrepr)
else: else:
d['longrepr'] = rep.longrepr d['longrepr'] = rep.longrepr
for name in d: for name in d:

View File

@@ -327,7 +327,52 @@ class SlaveController(object):
def unserialize_report(name, reportdict): def unserialize_report(name, reportdict):
def assembled_report(reportdict):
from _pytest._code.code import (
ReprEntry,
ReprExceptionInfo,
ReprFileLocation,
ReprFuncArgs,
ReprLocals,
ReprTraceback
)
if reportdict['longrepr']:
if 'reprcrash' and 'reprtraceback' in reportdict['longrepr']:
reprtraceback = reportdict['longrepr']['reprtraceback']
reprcrash = reportdict['longrepr']['reprcrash']
unserialized_entries = []
for entry in reprtraceback['reprentries']:
reprfuncargs, reprfileloc, reprlocals = None, None, None
if entry['reprfuncargs']:
reprfuncargs = ReprFuncArgs(**entry['reprfuncargs'])
if entry['reprfileloc']:
reprfileloc = ReprFileLocation(**entry['reprfileloc'])
if entry['reprlocals']:
reprlocals = ReprLocals(entry['reprlocals']['lines'])
reprentry = ReprEntry(
lines=entry['lines'],
reprfuncargs=reprfuncargs,
reprlocals=reprlocals,
filelocrepr=reprfileloc,
style=entry['style']
)
unserialized_entries.append(reprentry)
reprtraceback['reprentries'] = unserialized_entries
exception_info = ReprExceptionInfo(
reprtraceback=ReprTraceback(**reprtraceback),
reprcrash=ReprFileLocation(**reprcrash),
)
for section in reportdict['longrepr']['sections']:
exception_info.addsection(*section)
reportdict['longrepr'] = exception_info
return reportdict
if name == "testreport": if name == "testreport":
return runner.TestReport(**reportdict) return runner.TestReport(**assembled_report(reportdict))
elif name == "collectreport": elif name == "collectreport":
return runner.CollectReport(**reportdict) return runner.CollectReport(**assembled_report(reportdict))