Compare commits

...

25 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
13 changed files with 173 additions and 39 deletions

View File

@@ -4,7 +4,7 @@ Here's a quick checklist that should be present in PRs:
- [ ] Make sure to include reasonable tests for your change if necessary - [ ] Make sure to include reasonable tests for your change if necessary
- [ ] Add a new news fragment into the changelog folder, following these guidelines: - [ ] Add a *news* file into the `changelog` folder, following these guidelines:
* Name it `$issue_id.$type` for example `588.bug` * 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 * 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` * Ensure type is one of `removal`, `feature`, `bugfix`, `vendor`, `doc` or `trivial`

View File

@@ -1,3 +1,33 @@
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) pytest-xdist 1.17.1 (2017-06-10)
================================ ================================

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,28 +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-pytest28"
- TOXENV: "py35-pytest29"
- TOXENV: "py35-pytest30" - TOXENV: "py35-pytest30"
- TOXENV: "py36-pytest27"
- TOXENV: "py36-pytest28"
- TOXENV: "py36-pytest29"
- TOXENV: "py36-pytest30" - TOXENV: "py36-pytest30"
- TOXENV: "py27-pytest28-pexpect" - TOXENV: "py27-pytest30-pexpect"
- TOXENV: "py35-pytest28-pexpect" - TOXENV: "py35-pytest30-pexpect"
- TOXENV: "flakes" - TOXENV: "flakes"
- TOXENV: "readme" - TOXENV: "readme"

View File

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

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

@@ -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")

View File

@@ -1,8 +1,8 @@
[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,36}-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
@@ -14,9 +14,6 @@ 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=

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))