Skip to content

Commit

Permalink
Merge pull request #2075 from pytest-dev/master
Browse files Browse the repository at this point in the history
Merge master into features after fixing flake8 errors
  • Loading branch information
nicoddemus authored Nov 22, 2016
2 parents 7574033 + a3319ff commit 5ce551e
Show file tree
Hide file tree
Showing 40 changed files with 307 additions and 8 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ Changes
Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR.

* Report teardown output on test failure (`#442`_).
Thanks `@matclab`_ or the PR.
Thanks `@matclab`_ for the PR.

* Fix teardown error message in generated xUnit XML.
Thanks `@gdyuldin`_ or the PR.
Thanks `@gdyuldin`_ for the PR.

* Properly handle exceptions in ``multiprocessing`` tasks (`#1984`_).
Thanks `@adborden`_ for the report and `@nicoddemus`_ for the PR.
Expand Down
1 change: 1 addition & 0 deletions _pytest/_argcomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def __call__(self, prefix, **kwargs):
completion.append(x[prefix_dir:])
return completion


if os.environ.get('_ARGCOMPLETE'):
try:
import argcomplete.completers
Expand Down
2 changes: 2 additions & 0 deletions _pytest/_code/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ def recursionindex(self):
l.append(entry.frame.f_locals)
return None


co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2',
'?', 'eval')

Expand Down Expand Up @@ -846,6 +847,7 @@ def getrawcode(obj, trycall=True):
return x
return obj


if sys.version_info[:2] >= (3, 5): # RecursionError introduced in 3.5
def is_recursion_error(excinfo):
return excinfo.errisinstance(RecursionError) # noqa
Expand Down
3 changes: 3 additions & 0 deletions _pytest/_code/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ def findsource(obj):
source.lines = [line.rstrip() for line in sourcelines]
return source, lineno


def getsource(obj, **kwargs):
import _pytest._code
obj = _pytest._code.getrawcode(obj)
Expand All @@ -275,6 +276,7 @@ def getsource(obj, **kwargs):
assert isinstance(strsrc, str)
return Source(strsrc, **kwargs)


def deindent(lines, offset=None):
if offset is None:
for line in lines:
Expand All @@ -288,6 +290,7 @@ def deindent(lines, offset=None):
if offset == 0:
return list(lines)
newlines = []

def readline_generator(lines):
for line in lines:
yield line + '\n'
Expand Down
2 changes: 2 additions & 0 deletions _pytest/assertion/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ def install_importhook(config):
config._assertstate.hook = hook = rewrite.AssertionRewritingHook(config)
sys.meta_path.insert(0, hook)
config._assertstate.trace('installed rewrite import hook')

def undo():
hook = config._assertstate.hook
if hook is not None and hook in sys.meta_path:
sys.meta_path.remove(hook)

config.add_cleanup(undo)
return hook

Expand Down
1 change: 1 addition & 0 deletions _pytest/assertion/rewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ def _write_pyc(state, co, source_stat, pyc):
fp.close()
return True


RN = "\r\n".encode("utf-8")
N = "\n".encode("utf-8")

Expand Down
1 change: 1 addition & 0 deletions _pytest/capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def suspendcapture_item(self, item, when, in_=False):
item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err)


error_capsysfderror = "cannot use capsys and capfd at the same time"


Expand Down
8 changes: 7 additions & 1 deletion _pytest/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ def main(args=None, plugins=None):
class cmdline: # compatibility namespace
main = staticmethod(main)


class UsageError(Exception):
""" error in pytest usage or invocation"""


_preinit = []

default_plugins = (
Expand Down Expand Up @@ -594,7 +596,7 @@ def __init__(self, *names, **attrs):
if typ == 'choice':
warnings.warn(
'type argument to addoption() is a string %r.'
' For parsearg this is optional and when supplied '
' For parsearg this is optional and when supplied'
' should be a type.'
' (options: %s)' % (typ, names),
DeprecationWarning,
Expand Down Expand Up @@ -818,9 +820,11 @@ class Notset:
def __repr__(self):
return "<NOTSET>"


notset = Notset()
FILE_OR_DIR = 'file_or_dir'


class Config(object):
""" access to configuration values, pluginmanager and plugin hooks. """

Expand All @@ -843,9 +847,11 @@ def __init__(self, pluginmanager):
self._warn = self.pluginmanager._warn
self.pluginmanager.register(self, "pytestconfig")
self._configured = False

def do_setns(dic):
import pytest
setns(pytest, dic)

self.hook.pytest_namespace.call_historic(do_setns, {})
self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser))

Expand Down
2 changes: 2 additions & 0 deletions _pytest/debugging.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ def pytest_configure(config):
config.pluginmanager.register(PdbInvoke(), 'pdbinvoke')

old = (pdb.set_trace, pytestPDB._pluginmanager)

def fin():
pdb.set_trace, pytestPDB._pluginmanager = old
pytestPDB._config = None
pytestPDB._pdb_cls = pdb.Pdb

pdb.set_trace = pytest.set_trace
pytestPDB._pluginmanager = config.pluginmanager
pytestPDB._config = config
Expand Down
2 changes: 2 additions & 0 deletions _pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ def pytest_sessionstart(session):
def scopeproperty(name=None, doc=None):
def decoratescope(func):
scopename = name or func.__name__

def provide(self):
if func.__name__ in scope2props[self.scope]:
return func(self)
raise AttributeError("%s not available in %s-scoped context" % (
scopename, self.scope))

return property(provide, None, None, func.__doc__)
return decoratescope

Expand Down
2 changes: 2 additions & 0 deletions _pytest/helpconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ def pytest_cmdline_parse():
config.trace.root.setwriter(debugfile.write)
undo_tracing = config.pluginmanager.enable_tracing()
sys.stderr.write("writing pytestdebug information to %s\n" % path)

def unset_tracing():
debugfile.close()
sys.stderr.write("wrote pytestdebug information to %s\n" %
debugfile.name)
config.trace.root.setwriter(None)
undo_tracing()

config.add_cleanup(unset_tracing)

def pytest_cmdline_main(config):
Expand Down
1 change: 1 addition & 0 deletions _pytest/junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
class Junit(py.xml.Namespace):
pass


# We need to get the subset of the invalid unicode ranges according to
# XML 1.0 which are valid in this python build. Hence we calculate
# this dynamically instead of hardcoding it. The spec range of valid
Expand Down
2 changes: 2 additions & 0 deletions _pytest/mark.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def pytest_cmdline_main(config):
tw.line()
config._ensure_unconfigure()
return 0


pytest_cmdline_main.tryfirst = True


Expand Down
6 changes: 6 additions & 0 deletions _pytest/pastebin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def pytest_addoption(parser):
choices=['failed', 'all'],
help="send failed|all info to bpaste.net pastebin service.")


@pytest.hookimpl(trylast=True)
def pytest_configure(config):
import py
Expand All @@ -23,13 +24,16 @@ def pytest_configure(config):
# pastebin file will be utf-8 encoded binary file
config._pastebinfile = tempfile.TemporaryFile('w+b')
oldwrite = tr._tw.write

def tee_write(s, **kwargs):
oldwrite(s, **kwargs)
if py.builtin._istext(s):
s = s.encode('utf-8')
config._pastebinfile.write(s)

tr._tw.write = tee_write


def pytest_unconfigure(config):
if hasattr(config, '_pastebinfile'):
# get terminal contents and delete file
Expand All @@ -45,6 +49,7 @@ def pytest_unconfigure(config):
pastebinurl = create_new_paste(sessionlog)
tr.write_line("pastebin session-log: %s\n" % pastebinurl)


def create_new_paste(contents):
"""
Creates a new paste using bpaste.net service.
Expand Down Expand Up @@ -72,6 +77,7 @@ def create_new_paste(contents):
else:
return 'bad response: ' + response


def pytest_terminal_summary(terminalreporter):
import _pytest.config
if terminalreporter.config.option.pastebin != "failed":
Expand Down
8 changes: 8 additions & 0 deletions _pytest/pytester.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,12 @@ def _makefile(self, ext, args, kwargs):
for name, value in items:
p = self.tmpdir.join(name).new(ext=ext)
source = Source(value)

def my_totext(s, encoding="utf-8"):
if py.builtin._isbytes(s):
s = py.builtin._totext(s, encoding=encoding)
return s

source_unicode = "\n".join([my_totext(line) for line in source.lines])
source = py.builtin._totext(source_unicode)
content = source.strip().encode("utf-8") # + "\n"
Expand Down Expand Up @@ -695,12 +697,15 @@ def inline_run(self, *args, **kwargs):
# warning which will trigger to say they can no longer be
# re-written, which is fine as they are already re-written.
orig_warn = AssertionRewritingHook._warn_already_imported

def revert():
AssertionRewritingHook._warn_already_imported = orig_warn

self.request.addfinalizer(revert)
AssertionRewritingHook._warn_already_imported = lambda *a: None

rec = []

class Collect:
def pytest_configure(x, config):
rec.append(self.make_hook_recorder(config.pluginmanager))
Expand Down Expand Up @@ -735,10 +740,13 @@ def runpytest_inprocess(self, *args, **kwargs):
try:
reprec = self.inline_run(*args, **kwargs)
except SystemExit as e:

class reprec:
ret = e.args[0]

except Exception:
traceback.print_exc()

class reprec:
ret = 3
finally:
Expand Down
3 changes: 3 additions & 0 deletions _pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,12 @@ def fget(self):
if obj is None:
self._obj = obj = self._getobj()
return obj

def fset(self, value):
self._obj = value

return property(fget, fset, None, "underlying python object")

obj = obj()

def _getobj(self):
Expand Down
7 changes: 7 additions & 0 deletions _pytest/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,10 @@ def exit(msg):
__tracebackhide__ = True
raise Exit(msg)


exit.Exception = Exit


def skip(msg=""):
""" skip an executing test with the given message. Note: it's usually
better to use the pytest.mark.skipif marker to declare a test to be
Expand All @@ -527,8 +529,11 @@ def skip(msg=""):
"""
__tracebackhide__ = True
raise Skipped(msg=msg)


skip.Exception = Skipped


def fail(msg="", pytrace=True):
""" explicitly fail an currently-executing test with the given Message.
Expand All @@ -537,6 +542,8 @@ def fail(msg="", pytrace=True):
"""
__tracebackhide__ = True
raise Failed(msg=msg, pytrace=pytrace)


fail.Exception = Failed


Expand Down
4 changes: 4 additions & 0 deletions _pytest/skipping.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ def pytest_configure(config):
if config.option.runxfail:
old = pytest.xfail
config._cleanup.append(lambda: setattr(pytest, "xfail", old))

def nop(*args, **kwargs):
pass

nop.Exception = XFailed
setattr(pytest, "xfail", nop)

Expand Down Expand Up @@ -65,6 +67,8 @@ def xfail(reason=""):
""" xfail an executing test or setup functions with the given reason."""
__tracebackhide__ = True
raise XFailed(reason)


xfail.Exception = XFailed


Expand Down
1 change: 1 addition & 0 deletions _pytest/tmpdir.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def get_user():
except (ImportError, KeyError):
return None


# backward compatibility
TempdirHandler = TempdirFactory

Expand Down
2 changes: 2 additions & 0 deletions _pytest/unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ def pytest_runtest_protocol(item):
ut = sys.modules['twisted.python.failure']
Failure__init__ = ut.Failure.__init__
check_testcase_implements_trial_reporter()

def excstore(self, exc_value=None, exc_type=None, exc_tb=None,
captureVars=None):
if exc_value is None:
Expand All @@ -199,6 +200,7 @@ def excstore(self, exc_value=None, exc_type=None, exc_tb=None,
captureVars=captureVars)
except TypeError:
Failure__init__(self, exc_value, exc_type, exc_tb)

ut.Failure.__init__ = excstore
yield
ut.Failure.__init__ = Failure__init__
Expand Down
5 changes: 5 additions & 0 deletions testing/code/test_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class A:
pass
pytest.raises(TypeError, "_pytest._code.Code(A)")


if True:
def x():
pass
Expand Down Expand Up @@ -68,8 +69,10 @@ def test_code_from_func():

def test_unicode_handling():
value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8')

def f():
raise Exception(value)

excinfo = pytest.raises(Exception, f)
str(excinfo)
if sys.version_info[0] < 3:
Expand All @@ -79,8 +82,10 @@ def f():
@pytest.mark.skipif(sys.version_info[0] >= 3, reason='python 2 only issue')
def test_unicode_handling_syntax_error():
value = py.builtin._totext('\xc4\x85\xc4\x87\n', 'utf-8').encode('utf8')

def f():
raise SyntaxError('invalid syntax', (None, 1, 3, value))

excinfo = pytest.raises(Exception, f)
str(excinfo)
if sys.version_info[0] < 3:
Expand Down
Loading

0 comments on commit 5ce551e

Please sign in to comment.