diff --git a/CHANGELOG b/CHANGELOG index e517b470c..c5bdf6a89 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ Changes between 1.X and 1.1.1 - install 'py.test' and `py.which` with a ``-$VERSION`` suffix to disambiguate between Python3, python2.X, Jython and PyPy installed versions. +- new "pytestconfig" funcarg allows access to test config object + - make py.test.* helpers provided by default plugins visible early - works transparently both for pydoc and for interactive sessions which will regularly see e.g. py.test.mark and py.test.importorskip. diff --git a/ISSUES.txt b/ISSUES.txt index b242e373b..2f007821c 100644 --- a/ISSUES.txt +++ b/ISSUES.txt @@ -46,14 +46,6 @@ The test-report header should optionally show information about the under-test package and versions/locations of involved packages. -install py.test with interpreter-specific prefixes --------------------------------------------------------- -tags: feature - -When installing under python3, jython or pypy-c it is -desirable to (additionally?) install py.test with -respective suffixes. - make node._checkcollectable more robust ------------------------------------------------- tags: bug 1.1.2 @@ -101,3 +93,12 @@ A local test run of a "tests" directory may work but a remote one fail because the tests directory does not contain an "__init__.py". Either give an error or make it work without the __init__.py + +deprecate ensuretemp / introduce funcargs to setup method +-------------------------------------------------------------- +tags: wish 1.1.2 + +The remaining uses of py.test.ensuretemp within the py-test base +itself are for setup methods. Also users have expressed the +wish to have funcargs available to setup functions. Experiment +with allowing funcargs there and finalizing deprecating py.test.ensuretemp. diff --git a/py/impl/test/config.py b/py/impl/test/config.py index 133b87de9..f4519086c 100644 --- a/py/impl/test/config.py +++ b/py/impl/test/config.py @@ -10,6 +10,7 @@ def ensuretemp(string, dir=1): take care to provide empty unique directories for each test call even if the test is called multiple times. """ + #py.log._apiwarn(">1.1", "use tmpdir function argument") return py.test.config.ensuretemp(string, dir=dir) class CmdOptions(object): diff --git a/py/plugin/pytest_default.py b/py/plugin/pytest_default.py index 0c3a4fd15..9257ac3fb 100644 --- a/py/plugin/pytest_default.py +++ b/py/plugin/pytest_default.py @@ -28,6 +28,9 @@ def pytest_collect_file(path, parent): if ext == ".py": return parent.Module(path, parent=parent) +def pytest_funcarg__pytestconfig(request): + return request.config + def pytest_collect_directory(path, parent): # XXX reconsider the following comment # not use parent.Directory here as we generally diff --git a/testing/cmdline/test_cmdline.py b/testing/cmdline/test_cmdline.py index 660bf2c07..3de0d5dab 100644 --- a/testing/cmdline/test_cmdline.py +++ b/testing/cmdline/test_cmdline.py @@ -1,6 +1,17 @@ +import sys, py pytest_plugins = "pytest_pytester" +@py.test.mark.multi(name=[x for x in dir(py.cmdline) if x[0] != "_"]) +def test_cmdmain(name): + main = getattr(py.cmdline, name) + assert py.builtin.callable(main) + assert name[:2] == "py" + scriptname = "py." + name[2:] + if sys.platform == "win32": + scriptname += ".exe" + assert py.path.local.sysfind(scriptname), scriptname + class TestPyLookup: def test_basic(self, testdir): p = testdir.makepyfile(hello="def x(): pass") diff --git a/testing/cmdline/test_generic.py b/testing/cmdline/test_generic.py deleted file mode 100644 index 08ae43dce..000000000 --- a/testing/cmdline/test_generic.py +++ /dev/null @@ -1,66 +0,0 @@ -import py -import sys - - -def setup_module(mod): - mod.binpath = py._impldir.dirpath('bin') - if not mod.binpath.check(): - py.test.skip("bin-source scripts not installed") - mod.binwinpath = binpath.join("win32") - mod.tmpdir = py.test.ensuretemp(__name__) - mod.iswin32 = sys.platform == "win32" - -def checkmain(name): - main = getattr(py.cmdline, name) - assert py.builtin.callable(main) - assert name[:2] == "py" - scriptname = "py." + name[2:] - assert binpath.join(scriptname).check() - assert binwinpath.join(scriptname + ".cmd").check() - -def checkprocess(script): - assert script.check() - old = tmpdir.ensure(script.basename, dir=1).chdir() - try: - if iswin32: - cmd = script.basename - else: - cmd = "%s" %(script, ) - # XXX distributed testing's rsync does not support - # syncing executable bits - script.chmod(int("777", 8)) - - if script.basename.startswith("py.lookup") or \ - script.basename.startswith("py.which"): - cmd += " sys" - py.builtin.print_("executing", script) - try: - old = script.dirpath().chdir() - try: - py.process.cmdexec(cmd) - finally: - old.chdir() - except py.process.cmdexec.Error: - e = sys.exc_info()[1] - if cmd.find("py.rest") != -1 and \ - e.out.find("module named") != -1: - return - raise - - finally: - old.chdir() - -def test_cmdline_namespace(): - for name in dir(py.cmdline): - if name[0] != "_": - yield checkmain, name - -def test_script_invocation(): - if iswin32: - scripts = binwinpath.listdir("py.*") - else: - scripts = binpath.listdir("py.*") - scripts = [x for x in scripts - if not x.basename.startswith("py.svnwcrevert")] - for script in scripts: - yield checkprocess, script diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index e4ba4da3a..29e5ac11d 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -256,16 +256,15 @@ def test_codepath_Queue_example(): assert path.check() class TestFormattedExcinfo: - def setup_method(self, method): - self.tmpdir = py.test.ensuretemp("%s_%s" %( - self.__class__.__name__, method.__name__)) - - def importasmod(self, source): - source = py.code.Source(source) - modpath = self.tmpdir.join("mod.py") - self.tmpdir.ensure("__init__.py") - modpath.write(source) - return modpath.pyimport() + def pytest_funcarg__importasmod(self, request): + def importasmod(source): + source = py.code.Source(source) + tmpdir = request.getfuncargvalue("tmpdir") + modpath = tmpdir.join("mod.py") + tmpdir.ensure("__init__.py") + modpath.write(source) + return modpath.pyimport() + return importasmod def excinfo_from_exec(self, source): source = py.code.Source(source).strip() @@ -392,8 +391,8 @@ raise ValueError() assert reprlocals.lines[2] == 'y = 5' assert reprlocals.lines[3] == 'z = 7' - def test_repr_tracebackentry_lines(self): - mod = self.importasmod(""" + def test_repr_tracebackentry_lines(self, importasmod): + mod = importasmod(""" def func1(): raise ValueError("hello\\nworld") """) @@ -423,8 +422,8 @@ raise ValueError() assert loc.lineno == 3 #assert loc.message == "ValueError: hello" - def test_repr_tracebackentry_lines(self): - mod = self.importasmod(""" + def test_repr_tracebackentry_lines(self, importasmod): + mod = importasmod(""" def func1(m, x, y, z): raise ValueError("hello\\nworld") """) @@ -447,8 +446,8 @@ raise ValueError() assert tw.lines[1] == "x = 5, y = 13" assert tw.lines[2] == "z = " + repr('z' * 120) - def test_repr_tracebackentry_short(self): - mod = self.importasmod(""" + def test_repr_tracebackentry_short(self, importasmod): + mod = importasmod(""" def func1(): raise ValueError("hello") def entry(): @@ -470,8 +469,8 @@ raise ValueError() assert lines[1] == ' raise ValueError("hello")' assert lines[2] == 'E ValueError: hello' - def test_repr_tracebackentry_no(self): - mod = self.importasmod(""" + def test_repr_tracebackentry_no(self, importasmod): + mod = importasmod(""" def func1(): raise ValueError("hello") def entry(): @@ -487,8 +486,8 @@ raise ValueError() assert lines[0] == 'E ValueError: hello' assert not lines[1:] - def test_repr_traceback_tbfilter(self): - mod = self.importasmod(""" + def test_repr_traceback_tbfilter(self, importasmod): + mod = importasmod(""" def f(x): raise ValueError(x) def entry(): @@ -502,8 +501,8 @@ raise ValueError() reprtb = p.repr_traceback(excinfo) assert len(reprtb.reprentries) == 3 - def test_repr_traceback_and_excinfo(self): - mod = self.importasmod(""" + def test_repr_traceback_and_excinfo(self, importasmod): + mod = importasmod(""" def f(x): raise ValueError(x) def entry(): @@ -523,8 +522,8 @@ raise ValueError() assert repr.reprcrash.path.endswith("mod.py") assert repr.reprcrash.message == "ValueError: 0" - def test_repr_excinfo_addouterr(self): - mod = self.importasmod(""" + def test_repr_excinfo_addouterr(self, importasmod): + mod = importasmod(""" def entry(): raise ValueError() """) @@ -536,8 +535,8 @@ raise ValueError() assert twmock.lines[-1] == "content" assert twmock.lines[-2] == ("-", "title") - def test_repr_excinfo_reprcrash(self): - mod = self.importasmod(""" + def test_repr_excinfo_reprcrash(self, importasmod): + mod = importasmod(""" def entry(): raise ValueError() """) @@ -548,8 +547,8 @@ raise ValueError() assert repr.reprcrash.message == "ValueError" assert str(repr.reprcrash).endswith("mod.py:3: ValueError") - def test_repr_traceback_recursion(self): - mod = self.importasmod(""" + def test_repr_traceback_recursion(self, importasmod): + mod = importasmod(""" def rec2(x): return rec1(x+1) def rec1(x): @@ -565,12 +564,12 @@ raise ValueError() assert reprtb.extraline == "!!! Recursion detected (same locals & position)" assert str(reprtb) - def test_tb_entry_AssertionError(self): + def test_tb_entry_AssertionError(self, importasmod): # probably this test is a bit redundant # as py/magic/testing/test_assertion.py # already tests correctness of # assertion-reinterpretation logic - mod = self.importasmod(""" + mod = importasmod(""" def somefunc(): x = 1 assert x == 2 @@ -586,8 +585,8 @@ raise ValueError() lines = reprentry.lines assert lines[-1] == "E assert 1 == 2" - def test_reprexcinfo_getrepr(self): - mod = self.importasmod(""" + def test_reprexcinfo_getrepr(self, importasmod): + mod = importasmod(""" def f(x): raise ValueError(x) def entry(): @@ -601,8 +600,8 @@ raise ValueError() assert isinstance(repr, ReprExceptionInfo) assert repr.reprtraceback.style == style - def test_toterminal_long(self): - mod = self.importasmod(""" + def test_toterminal_long(self, importasmod): + mod = importasmod(""" def g(x): raise ValueError(x) def f(): @@ -627,8 +626,8 @@ raise ValueError() assert tw.lines[9] == "" assert tw.lines[10].endswith("mod.py:3: ValueError") - def test_toterminal_long_filenames(self): - mod = self.importasmod(""" + def test_toterminal_long_filenames(self, importasmod): + mod = importasmod(""" def f(): raise ValueError() """) @@ -651,31 +650,22 @@ raise ValueError() finally: old.chdir() - def test_format_excinfo(self): - mod = self.importasmod(""" + @py.test.mark.multi(reproptions=[ + {'style': style, 'showlocals': showlocals, + 'funcargs': funcargs, 'tbfilter': tbfilter + } for style in ("long", "short", "no") + for showlocals in (True, False) + for tbfilter in (True, False) + for funcargs in (True, False)]) + def test_format_excinfo(self, importasmod, reproptions): + mod = importasmod(""" def g(x): raise ValueError(x) def f(): g(3) """) excinfo = py.test.raises(ValueError, mod.f) - def format_and_str(kw): - tw = py.io.TerminalWriter(stringio=True) - repr = excinfo.getrepr(**kw) - repr.toterminal(tw) - assert tw.stringio.getvalue() - - for combo in self.allcombos(): - yield format_and_str, combo - - def allcombos(self): - for style in ("long", "short", "no"): - for showlocals in (True, False): - for tbfilter in (True, False): - for funcargs in (True, False): - kw = {'style': style, - 'showlocals': showlocals, - 'funcargs': funcargs, - 'tbfilter': tbfilter - } - yield kw + tw = py.io.TerminalWriter(stringio=True) + repr = excinfo.getrepr(**reproptions) + repr.toterminal(tw) + assert tw.stringio.getvalue() diff --git a/testing/code/test_source.py b/testing/code/test_source.py index f7d92ddf1..c654ef1ba 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -310,10 +310,9 @@ def test_deindent(): assert lines == ['', 'def f():', ' def g():', ' pass', ' '] @py.test.mark.xfail -def test_source_of_class_at_eof_without_newline(): +def test_source_of_class_at_eof_without_newline(tmpdir): # this test fails because the implicit inspect.getsource(A) below # does not return the "x = 1" last line. - tmpdir = py.test.ensuretemp("source_write_read") source = py.code.Source(''' class A(object): def method(self): diff --git a/testing/log/test_log.py b/testing/log/test_log.py index 69d7675f9..39c32740e 100644 --- a/testing/log/test_log.py +++ b/testing/log/test_log.py @@ -6,7 +6,6 @@ from py.impl.log.log import default_keywordmapper callcapture = py.io.StdCapture.call def setup_module(mod): - mod.tempdir = py.test.ensuretemp("py.log-test") mod._oldstate = default_keywordmapper.getstate() def teardown_module(mod): @@ -116,8 +115,8 @@ class TestLogConsumer: assert not err assert out.strip() == '[xyz] hello' - def test_log_file(self): - customlog = tempdir.join('log.out') + def test_log_file(self, tmpdir): + customlog = tmpdir.join('log.out') py.log.setconsumer("default", open(str(customlog), 'w', buffering=1)) py.log.Producer("default")("hello world #1") assert customlog.readlines() == ['[default] hello world #1\n'] @@ -127,8 +126,8 @@ class TestLogConsumer: res = customlog.readlines() assert res == ['[default] hello world #2\n'] # no append by default! - def test_log_file_append_mode(self): - logfilefn = tempdir.join('log_append.out') + def test_log_file_append_mode(self, tmpdir): + logfilefn = tmpdir.join('log_append.out') # The append mode is on by default, so we don't need to specify it for File py.log.setconsumer("default", py.log.Path(logfilefn, append=True, @@ -144,8 +143,8 @@ class TestLogConsumer: assert lines == ['[default] hello world #1\n', '[default] hello world #1\n'] - def test_log_file_delayed_create(self): - logfilefn = tempdir.join('log_create.out') + def test_log_file_delayed_create(self, tmpdir): + logfilefn = tmpdir.join('log_create.out') py.log.setconsumer("default", py.log.Path(logfilefn, delayed_create=True, buffering=0)) @@ -154,11 +153,11 @@ class TestLogConsumer: lines = logfilefn.readlines() assert lines == ['[default] hello world #1\n'] - def test_keyword_based_log_files(self): + def test_keyword_based_log_files(self, tmpdir): logfiles = [] keywords = 'k1 k2 k3'.split() for key in keywords: - path = tempdir.join(key) + path = tmpdir.join(key) py.log.setconsumer(key, py.log.Path(path, buffering=0)) py.log.Producer('k1')('1') @@ -166,7 +165,7 @@ class TestLogConsumer: py.log.Producer('k3')('3') for key in keywords: - path = tempdir.join(key) + path = tmpdir.join(key) assert path.read().strip() == '[%s] %s' % (key, key[-1]) # disabled for now; the syslog log file can usually be read only by root diff --git a/testing/process/test_killproc.py b/testing/process/test_killproc.py index 88fe4dd6d..4c89eb1d9 100644 --- a/testing/process/test_killproc.py +++ b/testing/process/test_killproc.py @@ -1,10 +1,9 @@ import py, sys -def test_kill(): +def test_kill(tmpdir): subprocess = py.test.importorskip("subprocess") - tmp = py.test.ensuretemp("test_kill") - t = tmp.join("t.py") + t = tmpdir.join("t.py") t.write("import time ; time.sleep(100)") proc = py.std.subprocess.Popen([sys.executable, str(t)]) assert proc.poll() is None # no return value yet diff --git a/testing/pytest/acceptance_test.py b/testing/pytest/acceptance_test.py index c293d3a0b..9571f6a56 100644 --- a/testing/pytest/acceptance_test.py +++ b/testing/pytest/acceptance_test.py @@ -32,12 +32,12 @@ class TestGeneralUsage: mytemp = testdir.tmpdir.mkdir("mytemp") p = testdir.makepyfile(""" import py - def test_1(): - py.test.ensuretemp('xyz') + def test_1(pytestconfig): + pytestconfig.getbasetemp().ensure("hello") """) result = testdir.runpytest(p, '--basetemp=%s' %mytemp) assert result.ret == 0 - assert mytemp.join('xyz').check(dir=1) + assert mytemp.join('hello').check() def test_assertion_magic(self, testdir): p = testdir.makepyfile(""" diff --git a/testing/pytest/test_config.py b/testing/pytest/test_config.py index e98f2e580..5d6a3a693 100644 --- a/testing/pytest/test_config.py +++ b/testing/pytest/test_config.py @@ -248,8 +248,8 @@ def test_options_on_small_file_do_not_blow_up(testdir): ['--traceconfig'], ['-v'], ['-v', '-v']): runfiletest(opts + [path]) -def test_ensuretemp(): - # XXX test for deprecation +def test_ensuretemp(recwarn): + #py.test.deprecated_call(py.test.ensuretemp, 'hello') d1 = py.test.ensuretemp('hello') d2 = py.test.ensuretemp('hello') assert d1 == d2 diff --git a/testing/pytest/test_conftesthandle.py b/testing/pytest/test_conftesthandle.py index 2dbc25967..3663b1811 100644 --- a/testing/pytest/test_conftesthandle.py +++ b/testing/pytest/test_conftesthandle.py @@ -8,7 +8,7 @@ def pytest_generate_tests(metafunc): def pytest_funcarg__basedir(request): def basedirmaker(request): - basedir = d = request.config.ensuretemp(request.param) + basedir = d = request.getfuncargvalue("tmpdir") d.ensure("adir/conftest.py").write("a=1 ; Directory = 3") d.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5") if request.param == "inpackage":