diff --git a/CHANGELOG b/CHANGELOG index 06140d513..bc4c0d6ae 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,7 @@ Changes between 2.1.3 and [next version] ---------------------------------------- -- fix pytest's own test suite to not leak FDs +- fix and cleanup pytest's own test suite to not leak FDs - fix issue83: link to generated funcarg list - fix issue74: pyarg module names are now checked against imp.find_module false positives diff --git a/_pytest/__init__.py b/_pytest/__init__.py index d2dc3e496..9a7071550 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.1.4.dev2' +__version__ = '2.1.4.dev3' diff --git a/_pytest/capture.py b/_pytest/capture.py index f26e31731..37e5611cc 100644 --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -11,20 +11,23 @@ def pytest_addoption(parser): group._addoption('-s', action="store_const", const="no", dest="capture", help="shortcut for --capture=no.") +@pytest.mark.tryfirst +def pytest_cmdline_parse(pluginmanager, args): + # we want to perform capturing already for plugin/conftest loading + if '-s' in args or "--capture=no" in args: + method = "no" + elif hasattr(os, 'dup') and '--capture=sys' not in args: + method = "fd" + else: + method = "sys" + capman = CaptureManager(method) + pluginmanager.register(capman, "capturemanager") + def addouterr(rep, outerr): for secname, content in zip(["out", "err"], outerr): if content: rep.sections.append(("Captured std%s" % secname, content)) -def pytest_unconfigure(config): - # registered in config.py during early conftest.py loading - capman = config.pluginmanager.getplugin('capturemanager') - while capman._method2capture: - name, cap = capman._method2capture.popitem() - # XXX logging module may wants to close it itself on process exit - # otherwise we could do finalization here and call "reset()". - cap.suspend() - class NoCapture: def startall(self): pass @@ -36,8 +39,9 @@ class NoCapture: return "", "" class CaptureManager: - def __init__(self): + def __init__(self, defaultmethod=None): self._method2capture = {} + self._defaultmethod = defaultmethod def _maketempfile(self): f = py.std.tempfile.TemporaryFile() @@ -62,14 +66,6 @@ class CaptureManager: else: raise ValueError("unknown capturing method: %r" % method) - def _getmethod_preoptionparse(self, args): - if '-s' in args or "--capture=no" in args: - return "no" - elif hasattr(os, 'dup') and '--capture=sys' not in args: - return "fd" - else: - return "sys" - def _getmethod(self, config, fspath): if config.option.capture: method = config.option.capture @@ -82,16 +78,22 @@ class CaptureManager: method = "sys" return method + def reset_capturings(self): + for name, cap in self._method2capture.items(): + cap.reset() + def resumecapture_item(self, item): method = self._getmethod(item.config, item.fspath) if not hasattr(item, 'outerr'): item.outerr = ('', '') # we accumulate outerr on the item return self.resumecapture(method) - def resumecapture(self, method): + def resumecapture(self, method=None): if hasattr(self, '_capturing'): raise ValueError("cannot resume, already capturing with %r" % (self._capturing,)) + if method is None: + method = self._defaultmethod cap = self._method2capture.get(method) self._capturing = method if cap is None: diff --git a/_pytest/config.py b/_pytest/config.py index 19a9d35f9..29b3c3bbd 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -11,8 +11,12 @@ def pytest_cmdline_parse(pluginmanager, args): return config def pytest_unconfigure(config): - for func in config._cleanup: - func() + while 1: + try: + fin = config._cleanup.pop() + except IndexError: + break + fin() class Parser: """ Parser for command line arguments. """ @@ -254,11 +258,14 @@ class Config(object): self.hook = self.pluginmanager.hook self._inicache = {} self._cleanup = [] - + @classmethod def fromdictargs(cls, option_dict, args): """ constructor useable for subprocesses. """ config = cls() + # XXX slightly crude way to initialize capturing + import _pytest.capture + _pytest.capture.pytest_cmdline_parse(config.pluginmanager, args) config._preparse(args, addopts=False) config.option.__dict__.update(option_dict) for x in config.option.plugins: @@ -283,11 +290,10 @@ class Config(object): def _setinitialconftest(self, args): # capture output during conftest init (#issue93) - from _pytest.capture import CaptureManager - capman = CaptureManager() - self.pluginmanager.register(capman, 'capturemanager') - # will be unregistered in capture.py's unconfigure() - capman.resumecapture(capman._getmethod_preoptionparse(args)) + # XXX introduce load_conftest hook to avoid needing to know + # about capturing plugin here + capman = self.pluginmanager.getplugin("capturemanager") + capman.resumecapture() try: try: self._conftest.setinitial(args) diff --git a/_pytest/core.py b/_pytest/core.py index b50b5f6b4..8ccae40c8 100644 --- a/_pytest/core.py +++ b/_pytest/core.py @@ -431,10 +431,7 @@ _preinit = [] def _preloadplugins(): _preinit.append(PluginManager(load=True)) -def main(args=None, plugins=None): - """ returned exit code integer, after an in-process testing run - with the given command line arguments, preloading an optional list - of passed in plugin objects. """ +def _prepareconfig(args=None, plugins=None): if args is None: args = sys.argv[1:] elif isinstance(args, py.path.local): @@ -448,13 +445,19 @@ def main(args=None, plugins=None): else: # subsequent calls to main will create a fresh instance _pluginmanager = PluginManager(load=True) hook = _pluginmanager.hook + if plugins: + for plugin in plugins: + _pluginmanager.register(plugin) + return hook.pytest_cmdline_parse( + pluginmanager=_pluginmanager, args=args) + +def main(args=None, plugins=None): + """ returned exit code integer, after an in-process testing run + with the given command line arguments, preloading an optional list + of passed in plugin objects. """ try: - if plugins: - for plugin in plugins: - _pluginmanager.register(plugin) - config = hook.pytest_cmdline_parse( - pluginmanager=_pluginmanager, args=args) - exitstatus = hook.pytest_cmdline_main(config=config) + config = _prepareconfig(args, plugins) + exitstatus = config.hook.pytest_cmdline_main(config=config) except UsageError: e = sys.exc_info()[1] sys.stderr.write("ERROR: %s\n" %(e.args[0],)) diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py index ce4fbf133..29a3f5b2e 100644 --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -56,6 +56,7 @@ def pytest_cmdline_main(config): elif config.option.help: config.pluginmanager.do_configure(config) showhelp(config) + config.pluginmanager.do_unconfigure(config) return 0 def showhelp(config): @@ -113,7 +114,7 @@ def pytest_report_header(config): verinfo = getpluginversioninfo(config) if verinfo: lines.extend(verinfo) - + if config.option.traceconfig: lines.append("active plugins:") plugins = [] diff --git a/_pytest/main.py b/_pytest/main.py index 76da59e86..4d4852105 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -50,7 +50,7 @@ def pytest_addoption(parser): def pytest_namespace(): collect = dict(Item=Item, Collector=Collector, File=File, Session=Session) return dict(collect=collect) - + def pytest_configure(config): py.test.config = config # compatibiltiy if config.option.exitfirst: @@ -134,7 +134,7 @@ def compatproperty(name): return getattr(pytest, name) return property(fget, None, None, "deprecated attribute %r, use pytest.%s" % (name,name)) - + class Node(object): """ base class for all Nodes in the collection tree. Collector subclasses have children, Items are terminal nodes.""" @@ -145,13 +145,13 @@ class Node(object): #: the parent collector node. self.parent = parent - + #: the test config object self.config = config or parent.config #: the collection this node is part of self.session = session or parent.session - + #: filesystem path where this node was collected from self.fspath = getattr(parent, 'fspath', None) self.ihook = self.session.gethookproxy(self.fspath) @@ -488,7 +488,7 @@ class Session(FSCollector): else: if fd is not None: fd.close() - + if type_[2] != imp.PKG_DIRECTORY: path = [os.path.dirname(mod)] else: @@ -511,7 +511,7 @@ class Session(FSCollector): raise pytest.UsageError(msg + arg) parts[0] = path return parts - + def matchnodes(self, matching, names): self.trace("matchnodes", matching, names) self.trace.root.indent += 1 diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 9966bb7f9..54dd8a2be 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -314,16 +314,6 @@ class TmpTestdir: result.extend(session.genitems(colitem)) return result - def inline_genitems(self, *args): - #config = self.parseconfig(*args) - config = self.parseconfigure(*args) - rec = self.getreportrecorder(config) - session = Session(config) - config.hook.pytest_sessionstart(session=session) - session.perform_collect() - config.hook.pytest_sessionfinish(session=session, exitstatus=EXIT_OK) - return session.items, rec - def runitem(self, source): # used from runner functional tests item = self.getitem(source) @@ -347,70 +337,52 @@ class TmpTestdir: assert len(reports) == 1, reports return reports[0] - def inline_run(self, *args): - args = ("-s", ) + args # otherwise FD leakage - config = self.parseconfig(*args) - reprec = self.getreportrecorder(config) - #config.pluginmanager.do_configure(config) - config.hook.pytest_cmdline_main(config=config) - #config.pluginmanager.do_unconfigure(config) - return reprec + def inline_genitems(self, *args): + return self.inprocess_run(list(args) + ['--collectonly']) - def config_preparse(self): - config = self.Config() - for plugin in self.plugins: - if isinstance(plugin, str): - config.pluginmanager.import_plugin(plugin) - else: - if isinstance(plugin, dict): - plugin = PseudoPlugin(plugin) - if not config.pluginmanager.isregistered(plugin): - config.pluginmanager.register(plugin) - return config + def inline_run(self, *args): + items, rec = self.inprocess_run(args) + return rec + + def inprocess_run(self, args, plugins=None): + rec = [] + items = [] + class Collect: + def pytest_configure(x, config): + rec.append(self.getreportrecorder(config)) + def pytest_itemcollected(self, item): + items.append(item) + if not plugins: + plugins = [] + plugins.append(Collect()) + self.pytestmain(list(args), plugins=[Collect()]) + assert len(rec) == 1 + return items, rec[0] def parseconfig(self, *args): - if not args: - args = (self.tmpdir,) - config = self.config_preparse() - args = list(args) + args = map(str, args) for x in args: if str(x).startswith('--basetemp'): break else: args.append("--basetemp=%s" % self.tmpdir.dirpath('basetemp')) - config.parse(args) + import _pytest.core + config = _pytest.core._prepareconfig(args, self.plugins) + # the in-process pytest invocation needs to avoid leaking FDs + # so we register a "reset_capturings" callmon the capturing manager + # and make sure it gets called + config._cleanup.append( + config.pluginmanager.getplugin("capturemanager").reset_capturings) + import _pytest.config + self.request.addfinalizer( + lambda: _pytest.config.pytest_unconfigure(config)) return config - def reparseconfig(self, args=None): - """ this is used from tests that want to re-invoke parse(). """ - if not args: - args = [self.tmpdir] - oldconfig = getattr(py.test, 'config', None) - try: - c = py.test.config = self.Config() - c.basetemp = py.path.local.make_numbered_dir(prefix="reparse", - keep=0, rootdir=self.tmpdir, lock_timeout=None) - c.parse(args) - c.pluginmanager.do_configure(c) - self.request.addfinalizer(lambda: c.pluginmanager.do_unconfigure(c)) - return c - finally: - py.test.config = oldconfig - def parseconfigure(self, *args): config = self.parseconfig(*args) config.pluginmanager.do_configure(config) self.request.addfinalizer(lambda: - config.pluginmanager.do_unconfigure(config)) - # XXX we need to additionally reset FDs to prevent pen FDs - # during our test suite. see also capture.py's unconfigure XXX - # comment about logging - def finalize_capman(): - capman = config.pluginmanager.getplugin('capturemanager') - while capman._method2capture: - name, cap = capman._method2capture.popitem() - cap.reset() - self.request.addfinalizer(finalize_capman) + config.pluginmanager.do_unconfigure(config)) return config def getitem(self, source, funcname="test_func"): @@ -430,7 +402,6 @@ class TmpTestdir: self.makepyfile(__init__ = "#") self.config = config = self.parseconfigure(path, *configargs) node = self.getnode(config, path) - #config.pluginmanager.do_unconfigure(config) return node def collect_by_name(self, modcol, name): @@ -447,9 +418,16 @@ class TmpTestdir: return py.std.subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw) def pytestmain(self, *args, **kwargs): - ret = pytest.main(*args, **kwargs) - if ret == 2: - raise KeyboardInterrupt() + class ResetCapturing: + @pytest.mark.trylast + def pytest_unconfigure(self, config): + capman = config.pluginmanager.getplugin("capturemanager") + capman.reset_capturings() + plugins = kwargs.setdefault("plugins", []) + rc = ResetCapturing() + plugins.append(rc) + return pytest.main(*args, **kwargs) + def run(self, *cmdargs): return self._run(*cmdargs) @@ -550,10 +528,6 @@ def getdecoded(out): return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % ( py.io.saferepr(out),) -class PseudoPlugin: - def __init__(self, vars): - self.__dict__.update(vars) - class ReportRecorder(object): def __init__(self, hook): self.hook = hook diff --git a/_pytest/terminal.py b/_pytest/terminal.py index 8f1061b22..3b3e39e05 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -43,7 +43,8 @@ def pytest_configure(config): pass else: stdout = os.fdopen(newfd, stdout.mode, 1) - config._toclose = stdout + config._cleanup.append(lambda: stdout.close()) + reporter = TerminalReporter(config, stdout) config.pluginmanager.register(reporter, 'terminalreporter') if config.option.debug or config.option.traceconfig: @@ -52,11 +53,6 @@ def pytest_configure(config): reporter.write_line("[traceconfig] " + msg) config.trace.root.setprocessor("pytest:config", mywriter) -def pytest_unconfigure(config): - if hasattr(config, '_toclose'): - #print "closing", config._toclose, config._toclose.fileno() - config._toclose.close() - def getreportopt(config): reportopts = "" optvalue = config.option.report diff --git a/setup.py b/setup.py index 22e0a07e1..09f1b0ff4 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ def main(): name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.1.4.dev2', + version='2.1.4.dev3', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 4bbf6b28f..218a87529 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -13,6 +13,12 @@ class TestGeneralUsage: '*ERROR: hello' ]) + def test_root_conftest_syntax_error(self, testdir): + p = testdir.makepyfile(conftest="raise SyntaxError\n") + result = testdir.runpytest() + result.stderr.fnmatch_lines(["*raise SyntaxError*"]) + assert result.ret != 0 + def test_early_hook_error_issue38_1(self, testdir): testdir.makeconftest(""" def pytest_sessionstart(): @@ -354,24 +360,24 @@ class TestInvocationVariants: def test_equivalence_pytest_pytest(self): assert pytest.main == py.test.cmdline.main - def test_invoke_with_string(self, capsys): - retcode = pytest.main("-h") + def test_invoke_with_string(self, testdir, capsys): + retcode = testdir.pytestmain("-h") assert not retcode out, err = capsys.readouterr() assert "--help" in out - pytest.raises(ValueError, lambda: pytest.main(retcode)) + pytest.raises(ValueError, lambda: pytest.main(0)) def test_invoke_with_path(self, testdir, capsys): retcode = testdir.pytestmain(testdir.tmpdir) assert not retcode out, err = capsys.readouterr() - def test_invoke_plugin_api(self, capsys): + def test_invoke_plugin_api(self, testdir, capsys): class MyPlugin: def pytest_addoption(self, parser): parser.addoption("--myopt") - pytest.main(["-h"], plugins=[MyPlugin()]) + testdir.pytestmain(["-h"], plugins=[MyPlugin()]) out, err = capsys.readouterr() assert "--myopt" in out diff --git a/testing/conftest.py b/testing/conftest.py index 6d20b9a4d..e020264a7 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -18,7 +18,7 @@ def pytest_configure(config): except py.process.cmdexec.Error: pass else: - config._numfiles = getopenfiles(out) + config._numfiles = len(getopenfiles(out)) #def pytest_report_header(): # return "pid: %s" % os.getpid() @@ -26,23 +26,31 @@ def pytest_configure(config): def getopenfiles(out): def isopen(line): return ("REG" in line or "CHR" in line) and ( - "deleted" not in line and 'mem' not in line) - return len([x for x in out.split("\n") if isopen(x)]) + "deleted" not in line and 'mem' not in line and "txt" not in line) + return [x for x in out.split("\n") if isopen(x)] -def pytest_unconfigure(config, __multicall__): - if not hasattr(config, '_numfiles'): - return - __multicall__.execute() +def check_open_files(config): out2 = py.process.cmdexec("lsof -p %d" % pid) - len2 = getopenfiles(out2) - assert len2 < config._numfiles + 15, out2 - + lines2 = getopenfiles(out2) + if len(lines2) > config._numfiles + 1: + error = [] + error.append("***** %s FD leackage detected" % + (len(lines2)-config._numfiles)) + error.extend(lines2) + error.append(error[0]) + # update numfile so that the overall test run continuess + config._numfiles = len(lines2) + raise AssertionError("\n".join(error)) def pytest_runtest_setup(item): item._oldir = py.path.local() -def pytest_runtest_teardown(item): +def pytest_runtest_teardown(item, __multicall__): item._oldir.chdir() + if hasattr(item.config, '_numfiles'): + x = __multicall__.execute() + check_open_files(item.config) + return x def pytest_generate_tests(metafunc): multi = getattr(metafunc.function, 'multi', None) diff --git a/testing/test_capture.py b/testing/test_capture.py index c22069d2f..b5c1744c9 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -16,7 +16,6 @@ class TestCaptureManager: def test_configure_per_fspath(self, testdir): config = testdir.parseconfig(testdir.tmpdir) - assert config.getvalue("capture") is None capman = CaptureManager() hasfd = hasattr(os, 'dup') if hasfd: @@ -53,6 +52,7 @@ class TestCaptureManager: capman.resumecapture(method) out, err = capman.suspendcapture() assert not out and not err + capman.reset_capturings() finally: capouter.reset() @@ -60,20 +60,23 @@ class TestCaptureManager: def test_juggle_capturings(self, testdir): capouter = py.io.StdCaptureFD() try: - config = testdir.parseconfig(testdir.tmpdir) + #config = testdir.parseconfig(testdir.tmpdir) capman = CaptureManager() - capman.resumecapture("fd") - pytest.raises(ValueError, 'capman.resumecapture("fd")') - pytest.raises(ValueError, 'capman.resumecapture("sys")') - os.write(1, "hello\n".encode('ascii')) - out, err = capman.suspendcapture() - assert out == "hello\n" - capman.resumecapture("sys") - os.write(1, "hello\n".encode('ascii')) - py.builtin.print_("world", file=sys.stderr) - out, err = capman.suspendcapture() - assert not out - assert err == "world\n" + try: + capman.resumecapture("fd") + pytest.raises(ValueError, 'capman.resumecapture("fd")') + pytest.raises(ValueError, 'capman.resumecapture("sys")') + os.write(1, "hello\n".encode('ascii')) + out, err = capman.suspendcapture() + assert out == "hello\n" + capman.resumecapture("sys") + os.write(1, "hello\n".encode('ascii')) + py.builtin.print_("world", file=sys.stderr) + out, err = capman.suspendcapture() + assert not out + assert err == "world\n" + finally: + capman.reset_capturings() finally: capouter.reset() diff --git a/testing/test_collection.py b/testing/test_collection.py index 1b6b3bded..45877fc5b 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -313,7 +313,8 @@ class TestSession: def test_collect_topdir(self, testdir): p = testdir.makepyfile("def test_func(): pass") id = "::".join([p.basename, "test_func"]) - config = testdir.parseconfigure(id) + # XXX migrate to inline_genitems? (see below) + config = testdir.parseconfig(id) topdir = testdir.tmpdir rcol = Session(config) assert topdir == rcol.fspath @@ -328,15 +329,9 @@ class TestSession: def test_collect_protocol_single_function(self, testdir): p = testdir.makepyfile("def test_func(): pass") id = "::".join([p.basename, "test_func"]) - config = testdir.parseconfigure(id) topdir = testdir.tmpdir - rcol = Session(config) - assert topdir == rcol.fspath - hookrec = testdir.getreportrecorder(config) - rcol.perform_collect() - items = rcol.items - assert len(items) == 1 - item = items[0] + items, hookrec = testdir.inline_genitems(id) + item, = items assert item.name == "test_func" newid = item.nodeid assert newid == id @@ -363,10 +358,7 @@ class TestSession: p.basename + "::TestClass::()", normid, ]: - config = testdir.parseconfigure(id) - rcol = Session(config=config) - rcol.perform_collect() - items = rcol.items + items, hookrec = testdir.inline_genitems(id) assert len(items) == 1 assert items[0].name == "test_method" newid = items[0].nodeid @@ -388,11 +380,7 @@ class TestSession: """ % p.basename) id = p.basename - config = testdir.parseconfigure(id) - rcol = Session(config) - hookrec = testdir.getreportrecorder(config) - rcol.perform_collect() - items = rcol.items + items, hookrec = testdir.inline_genitems(id) py.std.pprint.pprint(hookrec.hookrecorder.calls) assert len(items) == 2 hookrec.hookrecorder.contains([ @@ -413,11 +401,8 @@ class TestSession: aaa = testdir.mkpydir("aaa") test_aaa = aaa.join("test_aaa.py") p.move(test_aaa) - config = testdir.parseconfigure() - rcol = Session(config) - hookrec = testdir.getreportrecorder(config) - rcol.perform_collect() - items = rcol.items + + items, hookrec = testdir.inline_genitems() assert len(items) == 1 py.std.pprint.pprint(hookrec.hookrecorder.calls) hookrec.hookrecorder.contains([ @@ -437,11 +422,8 @@ class TestSession: p.move(test_bbb) id = "." - config = testdir.parseconfigure(id) - rcol = Session(config) - hookrec = testdir.getreportrecorder(config) - rcol.perform_collect() - items = rcol.items + + items, hookrec = testdir.inline_genitems(id) assert len(items) == 2 py.std.pprint.pprint(hookrec.hookrecorder.calls) hookrec.hookrecorder.contains([ @@ -455,19 +437,13 @@ class TestSession: def test_serialization_byid(self, testdir): p = testdir.makepyfile("def test_func(): pass") - config = testdir.parseconfigure() - rcol = Session(config) - rcol.perform_collect() - items = rcol.items + items, hookrec = testdir.inline_genitems() assert len(items) == 1 item, = items - rcol.config.pluginmanager.unregister(name="session") - newcol = Session(config) - item2, = newcol.perform_collect([item.nodeid], genitems=False) + items2, hookrec = testdir.inline_genitems(item.nodeid) + item2, = items2 assert item2.name == item.name assert item2.fspath == item.fspath - item2b, = newcol.perform_collect([item.nodeid], genitems=False) - assert item2b == item2 def test_find_byid_without_instance_parents(self, testdir): p = testdir.makepyfile(""" @@ -476,10 +452,7 @@ class TestSession: pass """) arg = p.basename + ("::TestClass::test_method") - config = testdir.parseconfigure(arg) - rcol = Session(config) - rcol.perform_collect() - items = rcol.items + items, hookrec = testdir.inline_genitems(arg) assert len(items) == 1 item, = items assert item.nodeid.endswith("TestClass::()::test_method") @@ -487,7 +460,7 @@ class TestSession: class Test_getinitialnodes: def test_global_file(self, testdir, tmpdir): x = tmpdir.ensure("x.py") - config = testdir.reparseconfig([x]) + config = testdir.parseconfigure(x) col = testdir.getnode(config, x) assert isinstance(col, pytest.Module) assert col.name == 'x.py' @@ -502,7 +475,7 @@ class Test_getinitialnodes: subdir = tmpdir.join("subdir") x = subdir.ensure("x.py") subdir.ensure("__init__.py") - config = testdir.reparseconfig([x]) + config = testdir.parseconfigure(x) col = testdir.getnode(config, x) assert isinstance(col, pytest.Module) assert col.name == 'subdir/x.py' @@ -528,12 +501,6 @@ class Test_genitems: assert hash(i) != hash(j) assert i != j - def test_root_conftest_syntax_error(self, testdir): - # do we want to unify behaviour with - # test_subdir_conftest_error? - p = testdir.makepyfile(conftest="raise SyntaxError\n") - pytest.raises(SyntaxError, testdir.inline_genitems, p.dirpath()) - def test_example_items1(self, testdir): p = testdir.makepyfile(''' def testone(): @@ -597,6 +564,6 @@ def test_matchnodes_two_collections_same_file(testdir): res.stdout.fnmatch_lines([ "*1 passed*", ]) - + diff --git a/testing/test_config.py b/testing/test_config.py index 0a83c3c48..b54bd83a7 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1,9 +1,9 @@ import py, pytest -from _pytest.config import getcfg, Config +from _pytest.config import getcfg class TestParseIni: - def test_getcfg_and_config(self, tmpdir): + def test_getcfg_and_config(self, testdir, tmpdir): sub = tmpdir.mkdir("sub") sub.chdir() tmpdir.join("setup.cfg").write(py.code.Source(""" @@ -12,25 +12,23 @@ class TestParseIni: """)) cfg = getcfg([sub], ["setup.cfg"]) assert cfg['name'] == "value" - config = Config() - config._preparse([sub]) + config = testdir.parseconfigure(sub) assert config.inicfg['name'] == 'value' def test_getcfg_empty_path(self, tmpdir): cfg = getcfg([''], ['setup.cfg']) #happens on py.test "" - def test_append_parse_args(self, tmpdir): + def test_append_parse_args(self, testdir, tmpdir): tmpdir.join("setup.cfg").write(py.code.Source(""" [pytest] addopts = --verbose """)) - config = Config() - config.parse([tmpdir]) + config = testdir.parseconfig(tmpdir) assert config.option.verbose - config = Config() - args = [tmpdir,] - config._preparse(args, addopts=False) - assert len(args) == 1 + #config = testdir.Config() + #args = [tmpdir,] + #config._preparse(args, addopts=False) + #assert len(args) == 1 def test_tox_ini_wrong_version(self, testdir): p = testdir.makefile('.ini', tox=""" @@ -49,8 +47,7 @@ class TestParseIni: [pytest] minversion = 1.0 """)) - config = Config() - config.parse([testdir.tmpdir]) + config = testdir.parseconfig() assert config.getini("minversion") == "1.0" def test_toxini_before_lower_pytestini(self, testdir): @@ -63,8 +60,7 @@ class TestParseIni: [pytest] minversion = 1.5 """)) - config = Config() - config.parse([sub]) + config = testdir.parseconfigure(sub) assert config.getini("minversion") == "2.0" @pytest.mark.xfail(reason="probably not needed") @@ -77,10 +73,10 @@ class TestParseIni: """) result = testdir.runpytest("--confcutdir=.") assert result.ret == 0 - + class TestConfigCmdlineParsing: def test_parsing_again_fails(self, testdir): - config = testdir.reparseconfig([testdir.tmpdir]) + config = testdir.parseconfig() pytest.raises(AssertionError, "config.parse([])") @@ -101,7 +97,7 @@ class TestConfigAPI: assert config.getvalue("x") == 1 assert config.getvalue("x", o.join('sub')) == 2 pytest.raises(KeyError, "config.getvalue('y')") - config = testdir.reparseconfig([str(o.join('sub'))]) + config = testdir.parseconfigure(str(o.join('sub'))) assert config.getvalue("x") == 2 assert config.getvalue("y") == 3 assert config.getvalue("x", o) == 1 @@ -127,18 +123,18 @@ class TestConfigAPI: def test_config_overwrite(self, testdir): o = testdir.tmpdir o.ensure("conftest.py").write("x=1") - config = testdir.reparseconfig([str(o)]) + config = testdir.parseconfig(str(o)) assert config.getvalue('x') == 1 config.option.x = 2 assert config.getvalue('x') == 2 - config = testdir.reparseconfig([str(o)]) + config = testdir.parseconfig([str(o)]) assert config.getvalue('x') == 1 def test_getconftest_pathlist(self, testdir, tmpdir): somepath = tmpdir.join("x", "y", "z") p = tmpdir.join("conftest.py") p.write("pathlist = ['.', %r]" % str(somepath)) - config = testdir.reparseconfig([p]) + config = testdir.parseconfigure(p) assert config._getconftest_pathlist('notexist') is None pl = config._getconftest_pathlist('pathlist') print(pl) diff --git a/testing/test_core.py b/testing/test_core.py index b289f3d41..b122cf689 100644 --- a/testing/test_core.py +++ b/testing/test_core.py @@ -332,17 +332,6 @@ class TestPytestPluginInteractions: "*did not find*sys*" ]) - def test_do_option_conftestplugin(self, testdir): - p = testdir.makepyfile(""" - def pytest_addoption(parser): - parser.addoption('--test123', action="store_true") - """) - config = testdir.Config() - config._conftest.importconftest(p) - print(config.pluginmanager.getplugins()) - config.parse([]) - assert not config.option.test123 - def test_namespace_early_from_import(self, testdir): p = testdir.makepyfile(""" from pytest import Item @@ -370,9 +359,7 @@ class TestPytestPluginInteractions: ]) def test_do_option_postinitialize(self, testdir): - config = testdir.Config() - config.parse([]) - config.pluginmanager.do_configure(config=config) + config = testdir.parseconfigure() assert not hasattr(config.option, 'test123') p = testdir.makepyfile(""" def pytest_addoption(parser): @@ -640,7 +627,7 @@ class TestTracer: log2("seen") tags, args = l2[0] assert args == ("seen",) - + def test_setmyprocessor(self): from _pytest.core import TagTracer diff --git a/testing/test_mark.py b/testing/test_mark.py index 495f491ba..d26132675 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -189,58 +189,6 @@ class TestFunctional: ]) -class Test_genitems: - def test_check_collect_hashes(self, testdir): - p = testdir.makepyfile(""" - def test_1(): - pass - - def test_2(): - pass - """) - p.copy(p.dirpath(p.purebasename + "2" + ".py")) - items, reprec = testdir.inline_genitems(p.dirpath()) - assert len(items) == 4 - for numi, i in enumerate(items): - for numj, j in enumerate(items): - if numj != numi: - assert hash(i) != hash(j) - assert i != j - - def test_root_conftest_syntax_error(self, testdir): - # do we want to unify behaviour with - # test_subdir_conftest_error? - p = testdir.makepyfile(conftest="raise SyntaxError\n") - pytest.raises(SyntaxError, testdir.inline_genitems, p.dirpath()) - - def test_example_items1(self, testdir): - p = testdir.makepyfile(''' - def testone(): - pass - - class TestX: - def testmethod_one(self): - pass - - class TestY(TestX): - pass - ''') - items, reprec = testdir.inline_genitems(p) - assert len(items) == 3 - assert items[0].name == 'testone' - assert items[1].name == 'testmethod_one' - assert items[2].name == 'testmethod_one' - - # let's also test getmodpath here - assert items[0].getmodpath() == "testone" - assert items[1].getmodpath() == "TestX.testmethod_one" - assert items[2].getmodpath() == "TestY.testmethod_one" - - s = items[0].getmodpath(stopatmodule=False) - assert s.endswith("test_example_items1.testone") - print(s) - - class TestKeywordSelection: def test_select_simple(self, testdir): file_test = testdir.makepyfile(""" diff --git a/testing/test_python.py b/testing/test_python.py index f5f0faae0..bbef18e5b 100644 --- a/testing/test_python.py +++ b/testing/test_python.py @@ -257,7 +257,7 @@ class TestFunction: assert hasattr(modcol.obj, 'test_func') def test_function_equality(self, testdir, tmpdir): - config = testdir.reparseconfig() + config = testdir.parseconfigure() session = testdir.Session(config) f1 = pytest.Function(name="name", config=config, args=(1,), callobj=isinstance, session=session) @@ -279,7 +279,7 @@ class TestFunction: assert not f1 != f1_b def test_function_equality_with_callspec(self, testdir, tmpdir): - config = testdir.reparseconfig() + config = testdir.parseconfigure() class callspec1: param = 1 funcargs = {} @@ -783,7 +783,7 @@ class TestRequestCachedSetup: req2 = funcargs.FuncargRequest(item2) ret2 = req2.cached_setup(setup, scope="class") assert ret2 == "hello" - + req3 = funcargs.FuncargRequest(item3) ret3a = req3.cached_setup(setup, scope="class") ret3b = req3.cached_setup(setup, scope="class") @@ -1320,7 +1320,7 @@ def test_customized_python_discovery(testdir): "*CheckMyApp*", "*check_meth*", ]) - + result = testdir.runpytest() assert result.ret == 0 result.stdout.fnmatch_lines([ @@ -1354,7 +1354,7 @@ def test_customize_through_attributes(testdir): Function = MyFunction class MyClass(pytest.Class): Instance = MyInstance - + def pytest_pycollect_makeitem(collector, name, obj): if name.startswith("MyTestClass"): return MyClass(name, parent=collector) diff --git a/testing/test_tmpdir.py b/testing/test_tmpdir.py index 79eb9e836..985b9045b 100644 --- a/testing/test_tmpdir.py +++ b/testing/test_tmpdir.py @@ -54,17 +54,6 @@ class TestConfigTmpdir: assert b2.check() assert not h.check() - def test_reparse(self, testdir): - config2 = testdir.reparseconfig([]) - config3 = testdir.reparseconfig([]) - assert config2.basetemp != config3.basetemp - assert not config2.basetemp.relto(config3.basetemp) - assert not config3.basetemp.relto(config2.basetemp) - - def test_reparse_filename_too_long(self, testdir): - config = testdir.reparseconfig(["--basetemp=%s" % ("123"*300)]) - - def test_basetemp(testdir): mytemp = testdir.tmpdir.mkdir("mytemp") p = testdir.makepyfile("""