From 2f7d0f8bd932ce2447386cdabb8fcdedf4cb7111 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 18 Jul 2015 16:39:55 -0300 Subject: [PATCH 1/6] Consider --color option in more places which deal with TerminalWriters --- CHANGELOG | 3 +++ _pytest/config.py | 13 +++++++++++++ _pytest/genscript.py | 3 ++- _pytest/helpconfig.py | 3 ++- _pytest/mark.py | 3 ++- _pytest/pdb.py | 6 +++++- _pytest/python.py | 3 ++- _pytest/terminal.py | 8 +++----- testing/python/fixture.py | 5 +++++ 9 files changed, 37 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 03c804514..1af7b2ef1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ 2.7.3 (compared to 2.7.2) ----------------------------- +- fix issue856: consider --color parameter in all outputs (for example + --fixtures). Thanks Barney Gale for the report and Bruno Oliveira for the PR. + - fix issue744: fix for ast.Call changes in Python 3.5+. Thanks Guido van Rossum, Matthias Bussonnier, Stefan Zimmermann and Thomas Kluyver. diff --git a/_pytest/config.py b/_pytest/config.py index c6a6403f6..a954a6222 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -933,3 +933,16 @@ def setns(obj, dic): #if obj != pytest: # pytest.__all__.append(name) setattr(pytest, name, value) + + +def create_terminal_writer(config, *args, **kwargs): + """Create a TerminalWriter instance configured according to the options + in the config object. Every code which requires a TerminalWriter object + and has access to a config object should use this function. + """ + tw = py.io.TerminalWriter(*args, **kwargs) + if config.option.color == 'yes': + tw.hasmarkup = True + if config.option.color == 'no': + tw.hasmarkup = False + return tw diff --git a/_pytest/genscript.py b/_pytest/genscript.py index 22f3fdeae..ed1f3b5c2 100755 --- a/_pytest/genscript.py +++ b/_pytest/genscript.py @@ -66,9 +66,10 @@ def pytest_addoption(parser): help="create standalone pytest script at given target path.") def pytest_cmdline_main(config): + import _pytest.config genscript = config.getvalue("genscript") if genscript: - tw = py.io.TerminalWriter() + tw = _pytest.config.create_terminal_writer(config) deps = ['py', '_pytest', 'pytest'] if sys.version_info < (2,7): deps.append("argparse") diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py index d79fc671a..9b9286910 100644 --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -64,7 +64,8 @@ def pytest_cmdline_main(config): return 0 def showhelp(config): - tw = py.io.TerminalWriter() + import _pytest.config + tw = _pytest.config.create_terminal_writer(config) tw.write(config._parser.optparser.format_help()) tw.line() tw.line() diff --git a/_pytest/mark.py b/_pytest/mark.py index 791f6ef55..9d2b70958 100644 --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -44,9 +44,10 @@ def pytest_addoption(parser): def pytest_cmdline_main(config): + import _pytest.config if config.option.markers: config.do_configure() - tw = py.io.TerminalWriter() + tw = _pytest.config.create_terminal_writer(config) for line in config.getini("markers"): name, rest = line.split(":", 1) tw.write("@pytest.mark.%s:" % name, bold=True) diff --git a/_pytest/pdb.py b/_pytest/pdb.py index d0f7509f9..904504ffe 100644 --- a/_pytest/pdb.py +++ b/_pytest/pdb.py @@ -23,23 +23,27 @@ def pytest_configure(config): old = (pdb.set_trace, pytestPDB._pluginmanager) def fin(): pdb.set_trace, pytestPDB._pluginmanager = old + pytestPDB._config = None pdb.set_trace = pytest.set_trace pytestPDB._pluginmanager = config.pluginmanager + pytestPDB._config = config config._cleanup.append(fin) class pytestPDB: """ Pseudo PDB that defers to the real pdb. """ _pluginmanager = None + _config = None def set_trace(self): """ invoke PDB set_trace debugging, dropping any IO capturing. """ + import _pytest.config frame = sys._getframe().f_back capman = None if self._pluginmanager is not None: capman = self._pluginmanager.getplugin("capturemanager") if capman: capman.suspendcapture(in_=True) - tw = py.io.TerminalWriter() + tw = _pytest.config.create_terminal_writer(self._config) tw.line() tw.sep(">", "PDB set_trace (IO-capturing turned off)") self._pluginmanager.hook.pytest_enter_pdb() diff --git a/_pytest/python.py b/_pytest/python.py index 76a6c4ed4..3faf85d51 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -947,9 +947,10 @@ def showfixtures(config): return wrap_session(config, _showfixtures_main) def _showfixtures_main(config, session): + import _pytest.config session.perform_collect() curdir = py.path.local() - tw = py.io.TerminalWriter() + tw = _pytest.config.create_terminal_writer(config) verbose = config.getvalue("verbose") fm = session._fixturemanager diff --git a/_pytest/terminal.py b/_pytest/terminal.py index 538bf3d8e..deff75b1c 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -87,6 +87,7 @@ class WarningReport: class TerminalReporter: def __init__(self, config, file=None): + import _pytest.config self.config = config self.verbosity = self.config.option.verbose self.showheader = self.verbosity >= 0 @@ -98,11 +99,8 @@ class TerminalReporter: self.startdir = py.path.local() if file is None: file = sys.stdout - self._tw = self.writer = py.io.TerminalWriter(file) - if self.config.option.color == 'yes': - self._tw.hasmarkup = True - if self.config.option.color == 'no': - self._tw.hasmarkup = False + self._tw = self.writer = _pytest.config.create_terminal_writer(config, + file) self.currentfspath = None self.reportchars = getreportopt(config) self.hasmarkup = self._tw.hasmarkup diff --git a/testing/python/fixture.py b/testing/python/fixture.py index 69c140f8d..90986173a 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -623,6 +623,11 @@ class TestRequestBasic: *arg1* """) + def test_show_fixtures_color_yes(self, testdir): + testdir.makepyfile("def test_this(): assert 1") + result = testdir.runpytest('--color=yes', '--fixtures') + assert '\x1b[32mtmpdir' in result.stdout.str() + def test_newstyle_with_request(self, testdir): testdir.makepyfile(""" import pytest From de65737cb1e2be6762cafb0884a04a13aa9b0ec0 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 18 Jul 2015 18:23:17 -0300 Subject: [PATCH 2/6] Fix flakes --- _pytest/mark.py | 1 - _pytest/pdb.py | 1 - 2 files changed, 2 deletions(-) diff --git a/_pytest/mark.py b/_pytest/mark.py index 9d2b70958..5f6372397 100644 --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -1,6 +1,5 @@ """ generic mechanism for marking and selecting python functions. """ import inspect -import py class MarkerError(Exception): diff --git a/_pytest/pdb.py b/_pytest/pdb.py index 904504ffe..78fedd373 100644 --- a/_pytest/pdb.py +++ b/_pytest/pdb.py @@ -4,7 +4,6 @@ import pdb import sys import pytest -import py def pytest_addoption(parser): From 31cfbac1f4c0f8748210a0b8c7707c79fda2b32b Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 20 Jul 2015 19:25:01 -0300 Subject: [PATCH 3/6] Fix autouse fixtures defined in a TestCase subclass --- CHANGELOG | 4 ++++ _pytest/python.py | 20 ++++++++++++-------- testing/test_unittest.py | 15 ++++++++++----- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 03c804514..d0571f095 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,10 @@ - preserve warning functions after call to pytest.deprecated_call. Thanks Pieter Mulder for PR. +- fix issue854: autouse yield_fixtures defined as class members of + unittest.TestCase subclasses now work as expected. + Thannks xmo-odoo for the report and Bruno Oliveira for the PR. + - fix issue833: --fixtures now shows all fixtures of collected test files, instead of just the fixtures declared on the first one. Thanks Florian Bruhin for reporting and Bruno Oliveira for the PR. diff --git a/_pytest/python.py b/_pytest/python.py index 76a6c4ed4..90bd8b99b 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1900,10 +1900,13 @@ class FixtureDef: self.finish() assert not hasattr(self, "cached_result") + fixturefunc = self.func + if self.unittest: - result = self.func(request.instance, **kwargs) + if request.instance is not None: + # bind the unbound method to the TestCase instance + fixturefunc = self.func.__get__(request.instance) else: - fixturefunc = self.func # the fixture function needs to be bound to the actual # request.instance so that code working with "self" behaves # as expected. @@ -1911,12 +1914,13 @@ class FixtureDef: fixturefunc = getimfunc(self.func) if fixturefunc != self.func: fixturefunc = fixturefunc.__get__(request.instance) - try: - result = call_fixture_func(fixturefunc, request, kwargs, - self.yieldctx) - except Exception: - self.cached_result = (None, my_cache_key, sys.exc_info()) - raise + + try: + result = call_fixture_func(fixturefunc, request, kwargs, + self.yieldctx) + except Exception: + self.cached_result = (None, my_cache_key, sys.exc_info()) + raise self.cached_result = (result, my_cache_key, None) return result diff --git a/testing/test_unittest.py b/testing/test_unittest.py index 1ab016a5a..9e3962aad 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -607,18 +607,23 @@ def test_unittest_unexpected_failure(testdir): ]) - -def test_unittest_setup_interaction(testdir): +@pytest.mark.parametrize('fix_type, stmt', [ + ('fixture', 'return'), + ('yield_fixture', 'yield'), +]) +def test_unittest_setup_interaction(testdir, fix_type, stmt): testdir.makepyfile(""" import unittest import pytest class MyTestCase(unittest.TestCase): - @pytest.fixture(scope="class", autouse=True) + @pytest.{fix_type}(scope="class", autouse=True) def perclass(self, request): request.cls.hello = "world" - @pytest.fixture(scope="function", autouse=True) + {stmt} + @pytest.{fix_type}(scope="function", autouse=True) def perfunction(self, request): request.instance.funcname = request.function.__name__ + {stmt} def test_method1(self): assert self.funcname == "test_method1" @@ -629,7 +634,7 @@ def test_unittest_setup_interaction(testdir): def test_classattr(self): assert self.__class__.hello == "world" - """) + """.format(fix_type=fix_type, stmt=stmt)) result = testdir.runpytest() result.stdout.fnmatch_lines("*3 passed*") From 0769bb48980379ee9b05785b1e9fcf32687d8170 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 21 Jul 2015 12:55:18 -0300 Subject: [PATCH 4/6] Make pastebin use _pytest.config.create_terminal_writer --- _pytest/pastebin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_pytest/pastebin.py b/_pytest/pastebin.py index 4d0badbf2..6ac9d50c6 100644 --- a/_pytest/pastebin.py +++ b/_pytest/pastebin.py @@ -69,6 +69,7 @@ def create_new_paste(contents): return 'bad response: ' + response def pytest_terminal_summary(terminalreporter): + import _pytest.config if terminalreporter.config.option.pastebin != "failed": return tr = terminalreporter @@ -79,7 +80,7 @@ def pytest_terminal_summary(terminalreporter): msg = rep.longrepr.reprtraceback.reprentries[-1].reprfileloc except AttributeError: msg = tr._getfailureheadline(rep) - tw = py.io.TerminalWriter(stringio=True) + tw = _pytest.config.create_terminal_writer(terminalreporter.config, stringio=True) rep.toterminal(tw) s = tw.stringio.getvalue() assert len(s) From 81f18f8a0fd29fddef12b4817c7a8f60678ac013 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 21 Jul 2015 19:55:01 -0300 Subject: [PATCH 5/6] Fix flakes --- _pytest/pastebin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_pytest/pastebin.py b/_pytest/pastebin.py index 6ac9d50c6..9f615e4aa 100644 --- a/_pytest/pastebin.py +++ b/_pytest/pastebin.py @@ -1,6 +1,6 @@ """ submit failure or test session information to a pastebin service. """ import pytest -import py, sys +import sys import tempfile From 5a17e797c7cd084e5b65cc03e834f37b9db5a3a5 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 23 Jul 2015 21:15:45 -0300 Subject: [PATCH 6/6] Fix basepython for tox envs "doctesting" and "coveralls" Because we are currently using "nighly" python for travis, which uses python 3.6 as the default interpreter. This breaks the environments listed above because "inspect.getargspec" has been removed in py36. --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 0b262e562..be2d9baa0 100644 --- a/tox.ini +++ b/tox.ini @@ -89,6 +89,7 @@ commands= make html [testenv:doctesting] +basepython = python3.4 changedir=doc/en deps=PyYAML commands= py.test -rfsxX {posargs} @@ -117,6 +118,7 @@ commands= [testenv:coveralls] +basepython = python3.4 changedir=testing deps = {[testenv]deps}