diff --git a/CHANGELOG b/CHANGELOG index 0c4794fd1..e135eb644 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,10 @@ Changes between 1.0.0 and 1.0.1 * improved documentation layout and content a lot +* added a "--help-config" option to show conftest.py / ENV-var names for + all longopt cmdline options, and some special conftest.py variables. + renamed 'conf_capture' conftest setting to 'option_capture' accordingly. + * fix issue #27: better reporting on non-collectable items given on commandline (e.g. pyc files) diff --git a/MANIFEST b/MANIFEST index f32c63e68..712cc2266 100644 --- a/MANIFEST +++ b/MANIFEST @@ -36,6 +36,7 @@ doc/test/mission.txt doc/test/plugin/capture.txt doc/test/plugin/doctest.txt doc/test/plugin/figleaf.txt +doc/test/plugin/helpconfig.txt doc/test/plugin/hooklog.txt doc/test/plugin/hookspec.txt doc/test/plugin/index.txt @@ -349,6 +350,7 @@ py/test/plugin/pytest_default.py py/test/plugin/pytest_doctest.py py/test/plugin/pytest_execnetcleanup.py py/test/plugin/pytest_figleaf.py +py/test/plugin/pytest_helpconfig.py py/test/plugin/pytest_hooklog.py py/test/plugin/pytest_keyword.py py/test/plugin/pytest_monkeypatch.py @@ -366,6 +368,7 @@ py/test/plugin/pytest_tmpdir.py py/test/plugin/pytest_unittest.py py/test/plugin/pytest_xfail.py py/test/plugin/test_pytest_capture.py +py/test/plugin/test_pytest_helpconfig.py py/test/plugin/test_pytest_nose.py py/test/plugin/test_pytest_runner.py py/test/plugin/test_pytest_runner_xunit.py diff --git a/doc/announce/release-1.0.1.txt b/doc/announce/release-1.0.1.txt index 593e45873..96860024e 100644 --- a/doc/announce/release-1.0.1.txt +++ b/doc/announce/release-1.0.1.txt @@ -1,17 +1,12 @@ -1.0.1: bug fixes, nose/unittest.py support, improved reporting --------------------------------------------------------------------- +1.0.1: improved reporting, nose/unittest.py support, bug fixes +----------------------------------------------------------------------- -The py.test/pylib 1.0.1 release is a bugfix release for 1.0.1, coming -with improved documentation and more support for running existing -nose/unittest.py style test suites. Checkout: +The py.test/pylib 1.0.1 release is a bugfix release, coming +with improved documentation and many test reporting improvements. +It also allows to run more existing nose and unittest.py style test suites. +For a testing quickstart and general documentation: - quickstart: http://codespeak.net/py/current/test/quickstart.html - - pytest: http://pytest.org - - pylib: http://pylib.org - -or read on for the changelog. + http://pytest.org and http://pylib.org Changes 1.0.0 to 1.0.1 ------------------------ @@ -20,7 +15,11 @@ Changes 1.0.0 to 1.0.1 nose-style function/method/generator setup/teardown and tries to report functions correctly. -* much improved documentation layout: see http://pytest.org +* improved documentation, better navigation: see http://pytest.org + +* added a "--help-config" option to show conftest.py / ENV-var names for + all longopt cmdline options, and some special conftest.py variables. + renamed 'conf_capture' conftest setting to 'option_capture' accordingly. * unicode fixes: capturing and unicode writes to sys.stdout (through e.g a print statement) now work within tests, diff --git a/doc/test/customize.txt b/doc/test/customize.txt index 4e69ad89d..d0f82d3f6 100644 --- a/doc/test/customize.txt +++ b/doc/test/customize.txt @@ -17,85 +17,80 @@ You can see command line options by running:: py.test -h This will display all available command line options -including the ones added by plugins `loaded at tool startup`_. - +in your specific environment. .. _`project-specific test configuration`: .. _`collect_ignore`: -conftest.py: project specific test configuration +conftest.py: project specific hooks and configuration -------------------------------------------------------- A unique feature of py.test are its ``conftest.py`` files which -allow to `set option defaults`_, `implement hooks`_, `specify funcargs`_ +allow to: + +* `set option defaults`_ + +* `implement hooks`_ + +* `specify funcargs`_ + or set particular variables to influence the testing process: * ``pytest_plugins``: list of named plugins to load -* ``collect_ignore``: list of paths to ignore during test collection (relative to the containing - ``conftest.py`` file) +* ``collect_ignore``: list of paths to ignore during test collection, relative to the containing ``conftest.py`` file * ``rsyncdirs``: list of to-be-rsynced directories for distributed - testing + testing, relative to the containing ``conftest.py`` file. You may put a conftest.py files in your project root directory or into your package directory if you want to add project-specific test options. ``py.test`` loads all ``conftest.py`` files upwards from the command -line specified test files. It will lookup configuration values +line file arguments. It usually looks up configuration values right-to-left, i.e. the closer conftest files will be checked first. -You may have a ``conftest.py`` in your very home directory to have some -global configuration values. - -There is a flag that may help you debugging your conftest.py -configuration:: - - py.test --traceconfig +This means you can have a ``conftest.py`` in your very home directory to +have some global configuration values. .. _`specify funcargs`: funcargs.html#application-setup-tutorial-example .. _`set option defaults`: -setting option defaults -------------------------------- +setting persistent option defaults +------------------------------------ -py.test will lookup values of options in this order: +py.test will lookup option values in this order: -* option value supplied at command line -* content of environment variable ``PYTEST_OPTION_NAME=...`` -* ``name = ...`` setting in the nearest ``conftest.py`` file. +* command line +* conftest.py files +* environment variables -The name of an option usually is the one you find -in the longform of the option, i.e. the name -behind the ``--`` double-dash that you get with ``py.test -h``. +To find out about the particular switches and type:: -IOW, you can set default values for options per project, per -home-directoray, per shell session or per test-run. + py.test --help-config + +This will print information about all options in your +environment, including your local plugins. .. _`basetemp`: Temporary directories ------------------------------------------- -``py.test`` runs provide means to create per-test session -temporary (sub) directories through the config object. -You can create directories by calling a method +You can create directories by calling one of two methods on the config object: -- ``config.mktemp(basename)``: create and returns a new tempdir +- ``config.mktemp(basename)``: create and return a new tempdir - ``config.ensuretemp(basename)``: create or return a new tempdir -tempdirs are created as sub directories of a per-session testdir -and will keep around the directories of the last three -test runs. You can also set the base temporary directory -with the `--basetemp`` option. When distributing -tests on the same machine, ``py.test`` takes care to -pass around the basetemp directory such that all temporary -files land below the same basetemp directory. - -The config object is available when implementing `function arguments`_ -or `extensions`_ and can otherwise be globally accessed as ``py.test.config``. +temporary directories are created as sub directories of a per-session +testdir and will keep around the directories of the last three test +runs. You can set the base temporary directory through the command line +`--basetemp`` option. When distributing tests on the same machine, +``py.test`` takes care to configure a basetemp directory for the sub +processes such that all temporary data lands below below a single +per-test run basetemp directory. .. _`function arguments`: funcargs.html .. _`extensions`: diff --git a/doc/test/plugin/capture.txt b/doc/test/plugin/capture.txt index d333c4bc9..3c1a45be9 100644 --- a/doc/test/plugin/capture.txt +++ b/doc/test/plugin/capture.txt @@ -38,7 +38,7 @@ You can influence output capturing mechanisms from the command line:: If you set capturing values in a conftest file like this:: # conftest.py - conf_capture = 'fd' + option_capture = 'fd' then all tests in that directory will execute with "fd" style capturing. diff --git a/doc/test/plugin/helpconfig.txt b/doc/test/plugin/helpconfig.txt new file mode 100644 index 000000000..1805d1708 --- /dev/null +++ b/doc/test/plugin/helpconfig.txt @@ -0,0 +1,31 @@ + +pytest_helpconfig plugin +======================== + +provide version info, conftest/environment config names. + +.. contents:: + :local: + + + +command line options +-------------------- + + +``--help-config`` + show available conftest.py and ENV-variable names. +``--version`` + display py lib version and import information. + +Start improving this plugin in 30 seconds +========================================= + + +1. Download `pytest_helpconfig.py`_ plugin source code +2. put it somewhere as ``pytest_helpconfig.py`` into your import path +3. a subsequent ``py.test`` run will use your local version + +Checkout customize_, other plugins_ or `get in contact`_. + +.. include:: links.txt diff --git a/doc/test/plugin/index.txt b/doc/test/plugin/index.txt index 22a0e5944..338819ca7 100644 --- a/doc/test/plugin/index.txt +++ b/doc/test/plugin/index.txt @@ -1,6 +1,6 @@ -Plugins related to Python test functions and programs -===================================================== +plugins for Python test functions +================================= xfail_ mark python test functions as expected-to-fail and report them separately. @@ -13,7 +13,7 @@ capture_ configurable per-test stdout/stderr capturing mechanisms. recwarn_ helpers for asserting deprecation and other warnings. -Plugins for other testing styles and languages +plugins for other testing styles and languages ============================================== oejskit_ run javascript tests in real life browsers @@ -27,7 +27,7 @@ doctest_ collect and execute doctests from modules and test files. restdoc_ perform ReST syntax, local and remote reference tests on .rst/.txt files. -Plugins for generic reporting and failure logging +plugins for generic reporting and failure logging ================================================= pastebin_ submit failure or test session information to a pastebin service. @@ -37,8 +37,20 @@ resultlog_ resultlog plugin for machine-readable logging of test results. terminal_ Implements terminal reporting of the full testing process. -internal plugins / core functionality -===================================== +plugins for generic reporting and failure logging +================================================= + +pastebin_ submit failure or test session information to a pastebin service. + +resultlog_ resultlog plugin for machine-readable logging of test results. + +terminal_ Implements terminal reporting of the full testing process. + + +misc plugins / core functionality +================================= + +helpconfig_ provide version info, conftest/environment config names. pdb_ interactive debugging with the Python Debugger. diff --git a/doc/test/plugin/links.txt b/doc/test/plugin/links.txt index b2e560406..9d9325062 100644 --- a/doc/test/plugin/links.txt +++ b/doc/test/plugin/links.txt @@ -1,3 +1,4 @@ +.. _`helpconfig`: helpconfig.html .. _`terminal`: terminal.html .. _`pytest_recwarn.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_recwarn.py .. _`unittest`: unittest.html @@ -15,6 +16,7 @@ .. _`pytest_figleaf.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_figleaf.py .. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_hooklog.py .. _`checkout the py.test development version`: ../../download.html#checkout +.. _`pytest_helpconfig.py`: http://bitbucket.org/hpk42/py-trunk/raw/1.0.1/py/test/plugin/pytest_helpconfig.py .. _`oejskit`: oejskit.html .. _`doctest`: doctest.html .. _`get in contact`: ../../contact.html diff --git a/makepluginlist.py b/makepluginlist.py index dbd707f6d..baacc9e0a 100644 --- a/makepluginlist.py +++ b/makepluginlist.py @@ -4,14 +4,16 @@ import sys WIDTH = 75 plugins = [ - ('Plugins related to Python test functions and programs', + ('plugins for Python test functions', 'xfail figleaf monkeypatch capture recwarn',), - ('Plugins for other testing styles and languages', + ('plugins for other testing styles and languages', 'oejskit unittest nose doctest restdoc'), - ('Plugins for generic reporting and failure logging', + ('plugins for generic reporting and failure logging', 'pastebin resultlog terminal',), - ('internal plugins / core functionality', - 'pdb keyword hooklog') + ('plugins for generic reporting and failure logging', + 'pastebin resultlog terminal',), + ('misc plugins / core functionality', + 'helpconfig pdb keyword hooklog') #('internal plugins / core functionality', # #'pdb keyword hooklog runner execnetcleanup # pytester', # 'pdb keyword hooklog runner execnetcleanup' # pytester', diff --git a/py/test/config.py b/py/test/config.py index 2ef394ba9..3d25fa45f 100644 --- a/py/test/config.py +++ b/py/test/config.py @@ -64,7 +64,7 @@ class Config(object): val = eval(val) opt.default = val else: - name = "pytest_option_" + opt.dest + name = "option_" + opt.dest try: opt.default = self._conftest.rget(name) except (ValueError, KeyError): diff --git a/py/test/defaultconftest.py b/py/test/defaultconftest.py index 506935541..7fac4f3cc 100644 --- a/py/test/defaultconftest.py +++ b/py/test/defaultconftest.py @@ -10,6 +10,5 @@ Generator = py.test.collect.Generator Function = py.test.collect.Function Instance = py.test.collect.Instance -pytest_plugins = "default runner capture terminal keyword xfail tmpdir execnetcleanup monkeypatch recwarn pdb pastebin unittest".split() +pytest_plugins = "default runner capture terminal keyword xfail tmpdir execnetcleanup monkeypatch recwarn pdb pastebin unittest helpconfig".split() -conf_capture = "fd" diff --git a/py/test/dist/testing/acceptance_test.py b/py/test/dist/testing/acceptance_test.py index 3e609dc75..ecd855d81 100644 --- a/py/test/dist/testing/acceptance_test.py +++ b/py/test/dist/testing/acceptance_test.py @@ -65,7 +65,7 @@ class TestDistribution: """, ) testdir.makeconftest(""" - pytest_option_tx = 'popen popen popen'.split() + option_tx = 'popen popen popen'.split() """) result = testdir.runpytest(p1, '-d') result.stdout.fnmatch_lines([ diff --git a/py/test/plugin/pytest_capture.py b/py/test/plugin/pytest_capture.py index a391ba828..e43aa8559 100644 --- a/py/test/plugin/pytest_capture.py +++ b/py/test/plugin/pytest_capture.py @@ -32,7 +32,7 @@ You can influence output capturing mechanisms from the command line:: If you set capturing values in a conftest file like this:: # conftest.py - conf_capture = 'fd' + option_capture = 'fd' then all tests in that directory will execute with "fd" style capturing. @@ -131,7 +131,10 @@ class CaptureManager: def _getmethod(self, config, fspath): if config.option.capture: return config.option.capture - return config._conftest.rget("conf_capture", path=fspath) + try: + return config._conftest.rget("option_capture", path=fspath) + except KeyError: + return "fd" def resumecapture_item(self, item): method = self._getmethod(item.config, item.fspath) diff --git a/py/test/plugin/pytest_default.py b/py/test/plugin/pytest_default.py index bc7d6cb8d..85cc78562 100644 --- a/py/test/plugin/pytest_default.py +++ b/py/test/plugin/pytest_default.py @@ -61,13 +61,13 @@ def pytest_addoption(parser): action="store", dest="tbstyle", default='long', type="choice", choices=['long', 'short', 'no'], help="traceback verboseness (long/short/no).") - group._addoption('-p', action="append", dest="plugin", default = [], + group._addoption('-p', action="append", dest="plugins", default = [], help=("load the specified plugin after command line parsing. ")) group._addoption('-f', '--looponfail', action="store_true", dest="looponfail", default=False, help="run tests, re-run failing test set until all pass.") - group = parser.addgroup("test process debugging") + group = parser.addgroup("debugconfig", "test process debugging and configuration") group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir", help="base temporary directory for this test run.") @@ -91,17 +91,10 @@ def pytest_addoption(parser): help="shortcut for '--dist=load --tx=NUM*popen'") group.addoption('--rsyncdir', action="append", default=[], metavar="dir1", help="add directory for rsyncing to remote tx nodes.") - group.addoption('--version', action="store_true", - help="display version information") def pytest_configure(config): fixoptions(config) setsession(config) - if config.option.version: - p = py.path.local(py.__file__).dirpath() - sys.stderr.write("This is py.test version %s, imported from %s\n" % - (py.__version__, p)) - sys.exit(0) #xxxloadplugins(config) def fixoptions(config): @@ -154,7 +147,7 @@ def test_plugin_specify(testdir): def test_plugin_already_exists(testdir): config = testdir.parseconfig("-p", "default") - assert config.option.plugin == ['default'] + assert config.option.plugins == ['default'] config.pluginmanager.do_configure(config) diff --git a/py/test/plugin/pytest_helpconfig.py b/py/test/plugin/pytest_helpconfig.py new file mode 100644 index 000000000..49109442f --- /dev/null +++ b/py/test/plugin/pytest_helpconfig.py @@ -0,0 +1,63 @@ +""" provide version info, conftest/environment config names. +""" +import py +import sys + +def pytest_addoption(parser): + group = parser.getgroup('debugconfig') + group.addoption("--help-config", action="store_true", dest="helpconfig", + help="show available conftest.py and ENV-variable names.") + group.addoption('--version', action="store_true", + help="display py lib version and import information.") + +def pytest_configure(__multicall__, config): + if config.option.version: + p = py.path.local(py.__file__).dirpath() + sys.stderr.write("This is py.test version %s, imported from %s\n" % + (py.__version__, p)) + sys.exit(0) + if not config.option.helpconfig: + return + __multicall__.execute() + options = [] + for group in config._parser._groups: + options.extend(group.options) + widths = [0] * 10 + tw = py.io.TerminalWriter() + tw.sep("-") + tw.line("%-13s | %-18s | %-25s | %s" %( + "cmdline name", "conftest.py name", "ENV-variable name", "help")) + tw.sep("-") + + options = [opt for opt in options if opt._long_opts] + options.sort(lambda x, y: cmp(x._long_opts, y._long_opts)) + for opt in options: + if not opt._long_opts: + continue + optstrings = list(opt._long_opts) # + list(opt._short_opts) + optstrings = filter(None, optstrings) + optstring = "|".join(optstrings) + line = "%-13s | %-18s | %-25s | %s" %( + optstring, + "option_%s" % opt.dest, + "PYTEST_OPTION_%s" % opt.dest.upper(), + opt.help and opt.help or "", + ) + tw.line(line[:tw.fullwidth]) + for name, help in conftest_options: + line = "%-13s | %-18s | %-25s | %s" %( + "", + name, + "", + help, + ) + tw.line(line[:tw.fullwidth]) + + tw.sep("-") + sys.exit(0) + +conftest_options = ( + ('pytest_plugins', 'list of plugin names to load'), + ('collect_ignore', '(relative) paths ignored during collection'), + ('rsyncdirs', 'to-be-rsynced directories for dist-testing'), +) diff --git a/py/test/plugin/pytest_terminal.py b/py/test/plugin/pytest_terminal.py index 203353174..7eee7ace3 100644 --- a/py/test/plugin/pytest_terminal.py +++ b/py/test/plugin/pytest_terminal.py @@ -7,7 +7,7 @@ import py import sys def pytest_addoption(parser): - group = parser.getgroup("test process debugging") + group = parser.getgroup("debugconfig") group.addoption('--collectonly', action="store_true", dest="collectonly", help="only collect tests, don't execute them."), diff --git a/py/test/plugin/test_pytest_capture.py b/py/test/plugin/test_pytest_capture.py index 8980e6d39..298764963 100644 --- a/py/test/plugin/test_pytest_capture.py +++ b/py/test/plugin/test_pytest_capture.py @@ -12,7 +12,7 @@ class TestCaptureManager: for name in ('no', 'fd', 'sys'): sub = testdir.tmpdir.mkdir("dir" + name) sub.ensure("__init__.py") - sub.join("conftest.py").write('conf_capture = %r' % name) + sub.join("conftest.py").write('option_capture = %r' % name) assert capman._getmethod(config, sub.join("test_hello.py")) == name @py.test.mark.multi(method=['no', 'fd', 'sys']) diff --git a/py/test/plugin/test_pytest_helpconfig.py b/py/test/plugin/test_pytest_helpconfig.py new file mode 100644 index 000000000..0ddbe53ea --- /dev/null +++ b/py/test/plugin/test_pytest_helpconfig.py @@ -0,0 +1,18 @@ +import py, os + +def test_version(testdir): + assert py.version == py.__version__ + result = testdir.runpytest("--version") + assert result.ret == 0 + p = py.path.local(py.__file__).dirpath() + assert result.stderr.fnmatch_lines([ + '*py.test*%s*imported from*%s*' % (py.version, p) + ]) + +def test_helpconfig(testdir): + result = testdir.runpytest("--help-config") + assert result.ret == 0 + assert result.stdout.fnmatch_lines([ + "*cmdline*conftest*ENV*", + ]) + diff --git a/py/test/pluginmanager.py b/py/test/pluginmanager.py index c8868c552..7a5ac305d 100644 --- a/py/test/pluginmanager.py +++ b/py/test/pluginmanager.py @@ -233,8 +233,7 @@ def importplugin(importspec): def isgenerichook(name): return name == "pytest_plugins" or \ - name.startswith("pytest_funcarg__") or \ - name.startswith("pytest_option_") + name.startswith("pytest_funcarg__") def getargs(func): args = py.std.inspect.getargs(func.func_code)[0] diff --git a/py/test/testing/acceptance_test.py b/py/test/testing/acceptance_test.py index 127f2682b..faf7fa690 100644 --- a/py/test/testing/acceptance_test.py +++ b/py/test/testing/acceptance_test.py @@ -1,14 +1,6 @@ import py class TestGeneralUsage: - def test_version(self, testdir): - assert py.version == py.__version__ - result = testdir.runpytest("--version") - assert result.ret == 0 - p = py.path.local(py.__file__).dirpath() - assert result.stderr.fnmatch_lines([ - '*py.test*%s*imported from*%s*' % (py.version, p) - ]) def test_config_error(self, testdir): testdir.makeconftest(""" def pytest_configure(config): diff --git a/py/test/testing/test_config.py b/py/test/testing/test_config.py index 8299aa6e3..5e9dc22dc 100644 --- a/py/test/testing/test_config.py +++ b/py/test/testing/test_config.py @@ -42,7 +42,7 @@ class TestConfigCmdlineParsing: def test_parser_addoption_default_conftest(self, testdir, monkeypatch): import os - testdir.makeconftest("pytest_option_verbose=True") + testdir.makeconftest("option_verbose=True") config = testdir.parseconfig() assert config.option.verbose