diff --git a/pytest/__init__.py b/pytest/__init__.py index 4227b68d9..bac1f5f4c 100644 --- a/pytest/__init__.py +++ b/pytest/__init__.py @@ -2,14 +2,25 @@ extensible functional and unit testing with Python. (c) Holger Krekel and others, 2004-2010 """ -__version__ = "1.4.0a1" - -#__all__ = ['collect'] - -import pytest.collect +__version__ = "2.0.0dev0" import pytest.config from pytest import collect +class cmdline: # compatibility py.test.cmdline.main == pytest.cmdline.main + @staticmethod + def main(args=None): + import sys + if args is None: + args = sys.argv[1:] + config = pytest.config.Config() + config.parse(args) + try: + exitstatus = config.hook.pytest_cmdline_main(config=config) + except config.Error: + e = sys.exc_info()[1] + sys.stderr.write("ERROR: %s\n" %(e.args[0],)) + exitstatus = EXIT_INTERNALERROR + return exitstatus + def __main__(): - from pytest.session import main - raise SystemExit(main()) + raise SystemExit(cmdline.main()) diff --git a/pytest/main.py b/pytest/main.py new file mode 100644 index 000000000..e4b90065c --- /dev/null +++ b/pytest/main.py @@ -0,0 +1,18 @@ +__all__ = [] +import py, pytest + +def main(args=None): + import sys + if args is None: + args = sys.argv[1:] + config = py.test.config + config.parse(args) + try: + exitstatus = config.hook.pytest_cmdline_main(config=config) + except config.Error: + e = sys.exc_info()[1] + sys.stderr.write("ERROR: %s\n" %(e.args[0],)) + exitstatus = 3 + py.test.config = config.__class__() + return exitstatus + diff --git a/pytest/plugin/pytest_default.py b/pytest/plugin/pytest_default.py deleted file mode 100644 index f919bc585..000000000 --- a/pytest/plugin/pytest_default.py +++ /dev/null @@ -1,78 +0,0 @@ -""" default hooks and general py.test options. """ - -import sys -import py - -def pytest_cmdline_main(config): - from pytest.session import Session - return Session(config).main() - -def pytest_perform_collection(session): - collection = session.collection - assert not hasattr(collection, 'items') - hook = session.config.hook - collection.items = items = collection.perform_collect() - hook.pytest_collection_modifyitems(config=session.config, items=items) - hook.pytest_log_finishcollection(collection=collection) - return True - -def pytest_runtest_mainloop(session): - if session.config.option.collectonly: - return True - for item in session.collection.items: - item.config.hook.pytest_runtest_protocol(item=item) - if session.shouldstop: - raise session.Interrupted(session.shouldstop) - return True - -def pytest_ignore_collect(path, config): - p = path.dirpath() - ignore_paths = config.getconftest_pathlist("collect_ignore", path=p) - ignore_paths = ignore_paths or [] - excludeopt = config.getvalue("ignore") - if excludeopt: - ignore_paths.extend([py.path.local(x) for x in excludeopt]) - return path in ignore_paths - -def pytest_collect_directory(path, parent): - if not parent.recfilter(path): # by default special ".cvs", ... - # check if cmdline specified this dir or a subdir directly - for arg in parent.collection._argfspaths: - if path == arg or arg.relto(path): - break - else: - return - return parent.Directory(path, parent=parent) - -def pytest_report_iteminfo(item): - return item.reportinfo() - -def pytest_addoption(parser): - group = parser.getgroup("general", "running and selection options") - group._addoption('-x', '--exitfirst', action="store_true", default=False, - dest="exitfirst", - help="exit instantly on first error or failed test."), - group._addoption('--maxfail', metavar="num", - action="store", type="int", dest="maxfail", default=0, - help="exit after first num failures or errors.") - - group = parser.getgroup("collect", "collection") - group.addoption('--collectonly', - action="store_true", dest="collectonly", - help="only collect tests, don't execute them."), - group.addoption("--ignore", action="append", metavar="path", - help="ignore path during collection (multi-allowed).") - group.addoption('--confcutdir', dest="confcutdir", default=None, - metavar="dir", - help="only load conftest.py's relative to specified dir.") - - group = parser.getgroup("debugconfig", - "test process debugging and configuration") - group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir", - help="base temporary directory for this test run.") - -def pytest_configure(config): - # compat - if config.getvalue("exitfirst"): - config.option.maxfail = 1 - diff --git a/pytest/plugin/pytest_pytester.py b/pytest/plugin/pytest_pytester.py index 2b71b365a..939ca0dbd 100644 --- a/pytest/plugin/pytest_pytester.py +++ b/pytest/plugin/pytest_pytester.py @@ -9,6 +9,7 @@ import inspect import time from fnmatch import fnmatch from pytest.config import Config as pytestConfig +from pytest.plugin.pytest_session import Collection from py.builtin import print_ def pytest_addoption(parser): @@ -149,7 +150,6 @@ class TmpTestdir: return p def getnode(self, config, arg): - from pytest.session import Collection collection = Collection(config) return collection.getbyid(collection._normalizearg(arg))[0] @@ -161,7 +161,6 @@ class TmpTestdir: def inline_genitems(self, *args): #config = self.parseconfig(*args) - from pytest.session import Collection config = self.parseconfigure(*args) rec = self.getreportrecorder(config) items = Collection(config).perform_collect() diff --git a/pytest/plugin/pytest_python.py b/pytest/plugin/pytest_python.py index 72ed7be89..35ebe1eda 100644 --- a/pytest/plugin/pytest_python.py +++ b/pytest/plugin/pytest_python.py @@ -660,7 +660,7 @@ class FuncargRequest: raise self.LookupError(msg) def showfuncargs(config): - from pytest.session import Collection + from pytest.plugin.pytest_session import Collection collection = Collection(config) firstid = collection._normalizearg(config.args[0]) colitem = collection.getbyid(firstid)[0] diff --git a/pytest/session.py b/pytest/plugin/pytest_session.py similarity index 73% rename from pytest/session.py rename to pytest/plugin/pytest_session.py index e37a7d65d..f3c83ab0c 100644 --- a/pytest/session.py +++ b/pytest/plugin/pytest_session.py @@ -6,25 +6,81 @@ """ import py +import pytest import os, sys -import pytest.config -# -# main entry point -# +def pytest_addoption(parser): + group = parser.getgroup("general", "running and selection options") + group._addoption('-x', '--exitfirst', action="store_true", default=False, + dest="exitfirst", + help="exit instantly on first error or failed test."), + group._addoption('--maxfail', metavar="num", + action="store", type="int", dest="maxfail", default=0, + help="exit after first num failures or errors.") + + group = parser.getgroup("collect", "collection") + group.addoption('--collectonly', + action="store_true", dest="collectonly", + help="only collect tests, don't execute them."), + group.addoption("--ignore", action="append", metavar="path", + help="ignore path during collection (multi-allowed).") + group.addoption('--confcutdir', dest="confcutdir", default=None, + metavar="dir", + help="only load conftest.py's relative to specified dir.") + + group = parser.getgroup("debugconfig", + "test process debugging and configuration") + group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir", + help="base temporary directory for this test run.") + +def pytest_configure(config): + # compat + if config.getvalue("exitfirst"): + config.option.maxfail = 1 + +def pytest_cmdline_main(config): + return Session(config).main() + +def pytest_perform_collection(session): + collection = session.collection + assert not hasattr(collection, 'items') + hook = session.config.hook + collection.items = items = collection.perform_collect() + hook.pytest_collection_modifyitems(config=session.config, items=items) + hook.pytest_log_finishcollection(collection=collection) + return True + +def pytest_runtest_mainloop(session): + if session.config.option.collectonly: + return True + for item in session.collection.items: + item.config.hook.pytest_runtest_protocol(item=item) + if session.shouldstop: + raise session.Interrupted(session.shouldstop) + return True + +def pytest_ignore_collect(path, config): + p = path.dirpath() + ignore_paths = config.getconftest_pathlist("collect_ignore", path=p) + ignore_paths = ignore_paths or [] + excludeopt = config.getvalue("ignore") + if excludeopt: + ignore_paths.extend([py.path.local(x) for x in excludeopt]) + return path in ignore_paths + +def pytest_collect_directory(path, parent): + if not parent.recfilter(path): # by default special ".cvs", ... + # check if cmdline specified this dir or a subdir directly + for arg in parent.collection._argfspaths: + if path == arg or arg.relto(path): + break + else: + return + return parent.Directory(path, parent=parent) + +def pytest_report_iteminfo(item): + return item.reportinfo() -def main(args=None): - if args is None: - args = sys.argv[1:] - config = pytest.config.Config() - config.parse(args) - try: - exitstatus = config.hook.pytest_cmdline_main(config=config) - except config.Error: - e = sys.exc_info()[1] - sys.stderr.write("ERROR: %s\n" %(e.args[0],)) - exitstatus = EXIT_INTERNALERROR - return exitstatus # exitcodes for the command line EXIT_OK = 0 diff --git a/pytest/pluginmanager.py b/pytest/pluginmanager.py index adb57b871..12243a721 100644 --- a/pytest/pluginmanager.py +++ b/pytest/pluginmanager.py @@ -3,11 +3,9 @@ managing loading and interacting with pytest plugins. """ import py import sys -import inspect -from pytest.plugin import hookspec default_plugins = ( - "default terminal python runner pdb capture mark skipping tmpdir monkeypatch " + "session terminal python runner pdb capture mark skipping tmpdir monkeypatch " "recwarn pastebin unittest helpconfig nose assertion genscript " "junitxml doctest keyword").split() @@ -17,6 +15,7 @@ def check_old_use(mod, modname): class PluginManager(object): def __init__(self): + from pytest.plugin import hookspec self.registry = Registry() self._name2plugin = {} self._hints = [] @@ -275,6 +274,7 @@ class MultiCall: return kwargs def varnames(func): + import inspect if not inspect.isfunction(func) and not inspect.ismethod(func): func = getattr(func, '__call__', func) ismethod = inspect.ismethod(func) diff --git a/setup.py b/setup.py index c422dc205..a88fd2b1d 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ def main(): name='pytest', description='py.test: simple testing with Python', long_description = long_description, - version= '1.4.0a1', + version= '2.0.0.dev0', url='http://pylib.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff --git a/testing/plugin/test_pytest_default.py b/testing/plugin/test_pytest_default.py deleted file mode 100644 index ae366864b..000000000 --- a/testing/plugin/test_pytest_default.py +++ /dev/null @@ -1,46 +0,0 @@ -import py -from pytest.plugin.pytest_default import pytest_report_iteminfo - -def test_plugin_specify(testdir): - testdir.chdir() - config = py.test.raises(ImportError, """ - testdir.parseconfig("-p", "nqweotexistent") - """) - #py.test.raises(ImportError, - # "config.pluginmanager.do_configure(config)" - #) - -def test_plugin_already_exists(testdir): - config = testdir.parseconfig("-p", "default") - assert config.option.plugins == ['default'] - config.pluginmanager.do_configure(config) - -def test_exclude(testdir): - hellodir = testdir.mkdir("hello") - hellodir.join("test_hello.py").write("x y syntaxerror") - hello2dir = testdir.mkdir("hello2") - hello2dir.join("test_hello2.py").write("x y syntaxerror") - testdir.makepyfile(test_ok="def test_pass(): pass") - result = testdir.runpytest("--ignore=hello", "--ignore=hello2") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - -def test_pytest_report_iteminfo(): - class FakeItem(object): - - def reportinfo(self): - return "-reportinfo-" - - res = pytest_report_iteminfo(FakeItem()) - assert res == "-reportinfo-" - - -def test_conftest_confcutdir(testdir): - testdir.makeconftest("assert 0") - x = testdir.mkdir("x") - x.join("conftest.py").write(py.code.Source(""" - def pytest_addoption(parser): - parser.addoption("--xyz", action="store_true") - """)) - result = testdir.runpytest("-h", "--confcutdir=%s" % x, x) - result.stdout.fnmatch_lines(["*--xyz*"]) diff --git a/testing/plugin/test_pytest_resultlog.py b/testing/plugin/test_pytest_resultlog.py index a83f8c6ca..d2b88f664 100644 --- a/testing/plugin/test_pytest_resultlog.py +++ b/testing/plugin/test_pytest_resultlog.py @@ -3,9 +3,9 @@ import os from pytest.plugin.pytest_resultlog import generic_path, ResultLog, \ pytest_configure, pytest_unconfigure from pytest.collect import Node, Item, FSCollector -from pytest.session import Collection def test_generic_path(testdir): + from pytest.plugin.pytest_session import Collection config = testdir.parseconfig() collection = Collection(config) p1 = Node('a', config=config, collection=collection) diff --git a/testing/test_session.py b/testing/plugin/test_pytest_session.py similarity index 86% rename from testing/test_session.py rename to testing/plugin/test_pytest_session.py index 64d84b252..f1f39a94d 100644 --- a/testing/test_session.py +++ b/testing/plugin/test_pytest_session.py @@ -1,4 +1,5 @@ import py +from pytest.plugin.pytest_session import pytest_report_iteminfo class SessionTests: def test_basic_testitem_events(self, testdir): @@ -198,3 +199,36 @@ class TestNewSession(SessionTests): colfail = [x for x in finished if x.failed] assert len(colfail) == 1 + +def test_plugin_specify(testdir): + testdir.chdir() + config = py.test.raises(ImportError, """ + testdir.parseconfig("-p", "nqweotexistent") + """) + #py.test.raises(ImportError, + # "config.pluginmanager.do_configure(config)" + #) + +def test_plugin_already_exists(testdir): + config = testdir.parseconfig("-p", "default") + assert config.option.plugins == ['default'] + config.pluginmanager.do_configure(config) + +def test_exclude(testdir): + hellodir = testdir.mkdir("hello") + hellodir.join("test_hello.py").write("x y syntaxerror") + hello2dir = testdir.mkdir("hello2") + hello2dir.join("test_hello2.py").write("x y syntaxerror") + testdir.makepyfile(test_ok="def test_pass(): pass") + result = testdir.runpytest("--ignore=hello", "--ignore=hello2") + assert result.ret == 0 + result.stdout.fnmatch_lines(["*1 passed*"]) + +def test_pytest_report_iteminfo(): + class FakeItem(object): + + def reportinfo(self): + return "-reportinfo-" + + res = pytest_report_iteminfo(FakeItem()) + assert res == "-reportinfo-" diff --git a/testing/test_collection.py b/testing/test_collection.py index d685f80ab..4eaf7718b 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -1,6 +1,6 @@ import py -from pytest.session import Collection, gettopdir +from pytest.plugin.pytest_session import Collection, gettopdir class TestCollection: def test_parsearg(self, testdir): diff --git a/testing/test_conftest.py b/testing/test_conftest.py index 317465a64..539f9fb9c 100644 --- a/testing/test_conftest.py +++ b/testing/test_conftest.py @@ -176,3 +176,13 @@ def test_setinitial_conftest_subdirs(testdir, name): else: assert subconftest not in conftest._conftestpath2mod assert len(conftest._conftestpath2mod) == 0 + +def test_conftest_confcutdir(testdir): + testdir.makeconftest("assert 0") + x = testdir.mkdir("x") + x.join("conftest.py").write(py.code.Source(""" + def pytest_addoption(parser): + parser.addoption("--xyz", action="store_true") + """)) + result = testdir.runpytest("-h", "--confcutdir=%s" % x, x) + result.stdout.fnmatch_lines(["*--xyz*"])