remove old ways to set option defaults, relying on global setup.cfg or tox.ini files now.

revamp py.test --help-config

--HG--
branch : trunk
This commit is contained in:
holger krekel 2010-10-27 22:29:01 +02:00
parent b86b1628bb
commit c9e629c870
9 changed files with 72 additions and 123 deletions

View File

@ -3,7 +3,9 @@ Changes between 1.3.4 and 2.0.0dev0
- pytest-2.0 is now its own package and depends on pylib-2.0 - pytest-2.0 is now its own package and depends on pylib-2.0
- introduce a new way to set config options via ini-style files, - introduce a new way to set config options via ini-style files,
by default setup.cfg and tox.ini files are searched. by default setup.cfg and tox.ini files are searched. The old
ways (certain environment variables, dynamic conftest.py reading
is removed).
- fix issue126 - introduce py.test.set_trace() to trace execution via - fix issue126 - introduce py.test.set_trace() to trace execution via
PDB during the running of tests even if capturing is ongoing. PDB during the running of tests even if capturing is ongoing.
- fix issue123 - new "python -m py.test" invocation for py.test - fix issue123 - new "python -m py.test" invocation for py.test

View File

@ -8,12 +8,12 @@ basic test configuration
Command line options Command line options
--------------------------------- ---------------------------------
You can see command line options by running:: You can get help on options and configuration by running::
py.test -h py.test -h # or --help
This will display all available command line options This will display command line options, ini-settings and conftest.py
in your specific environment. settings in your specific environment.
reading test configuration from ini-files reading test configuration from ini-files
-------------------------------------------------------- --------------------------------------------------------
@ -28,12 +28,12 @@ Possible entries in a ``[pytest]`` section are:
minversion = 2.1 # will fail if we run with pytest-2.0 minversion = 2.1 # will fail if we run with pytest-2.0
.. confval:: appendargs = OPTS .. confval:: addargs = OPTS
append the specified ``OPTS`` to the command line arguments as if they add the specified ``OPTS`` to the set of command line arguments as if they
had been specified by the user. Example:: had been specified by the user. Example::
appendargs = --maxfail=2 -rf # exit after 2 failures, report fail info addargs = --maxfail=2 -rf # exit after 2 failures, report fail info
setting persistent option defaults setting persistent option defaults

View File

@ -45,7 +45,7 @@ class Parser:
self._anonymous.addoption(*opts, **attrs) self._anonymous.addoption(*opts, **attrs)
def parse(self, args): def parse(self, args):
optparser = MyOptionParser(self) self.optparser = optparser = MyOptionParser(self)
groups = self._groups + [self._anonymous] groups = self._groups + [self._anonymous]
for group in groups: for group in groups:
if group.options: if group.options:
@ -53,7 +53,7 @@ class Parser:
optgroup = py.std.optparse.OptionGroup(optparser, desc) optgroup = py.std.optparse.OptionGroup(optparser, desc)
optgroup.add_options(group.options) optgroup.add_options(group.options)
optparser.add_option_group(optgroup) optparser.add_option_group(optgroup)
return optparser.parse_args([str(x) for x in args]) return self.optparser.parse_args([str(x) for x in args])
def parse_setoption(self, args, option): def parse_setoption(self, args, option):
parsedoption, args = self.parse(args) parsedoption, args = self.parse(args)
@ -91,7 +91,8 @@ class OptionGroup:
class MyOptionParser(py.std.optparse.OptionParser): class MyOptionParser(py.std.optparse.OptionParser):
def __init__(self, parser): def __init__(self, parser):
self._parser = parser self._parser = parser
py.std.optparse.OptionParser.__init__(self, usage=parser._usage) py.std.optparse.OptionParser.__init__(self, usage=parser._usage,
add_help_option=False)
def format_epilog(self, formatter): def format_epilog(self, formatter):
hints = self._parser.hints hints = self._parser.hints
if hints: if hints:
@ -248,6 +249,12 @@ class Config(object):
self.trace("loaded conftestmodule %r" %(conftestmodule,)) self.trace("loaded conftestmodule %r" %(conftestmodule,))
self.pluginmanager.consider_conftest(conftestmodule) self.pluginmanager.consider_conftest(conftestmodule)
def _processopt(self, opt):
if hasattr(opt, 'default') and opt.dest:
if not hasattr(self.option, opt.dest):
setattr(self.option, opt.dest, opt.default)
def _getmatchingplugins(self, fspath): def _getmatchingplugins(self, fspath):
allconftests = self._conftest._conftestpath2mod.values() allconftests = self._conftest._conftestpath2mod.values()
plugins = [x for x in self.pluginmanager.getplugins() plugins = [x for x in self.pluginmanager.getplugins()
@ -259,31 +266,6 @@ class Config(object):
if getattr(self.option, 'traceconfig', None): if getattr(self.option, 'traceconfig', None):
self.hook.pytest_trace(category="config", msg=msg) self.hook.pytest_trace(category="config", msg=msg)
def _processopt(self, opt):
if hasattr(opt, 'default') and opt.dest:
val = os.environ.get("PYTEST_OPTION_" + opt.dest.upper(), None)
if val is not None:
if opt.type == "int":
val = int(val)
elif opt.type == "long":
val = long(val)
elif opt.type == "float":
val = float(val)
elif not opt.type and opt.action in ("store_true", "store_false"):
val = eval(val)
opt.default = val
else:
name = "option_" + opt.dest
try:
opt.default = self._conftest.rget(name)
except (ValueError, KeyError):
try:
opt.default = self.inicfg[opt.dest]
except KeyError:
pass
if not hasattr(self.option, opt.dest):
setattr(self.option, opt.dest, opt.default)
def _setinitialconftest(self, args): def _setinitialconftest(self, args):
# capture output during conftest init (#issue93) # capture output during conftest init (#issue93)
name = hasattr(os, 'dup') and 'StdCaptureFD' or 'StdCapture' name = hasattr(os, 'dup') and 'StdCaptureFD' or 'StdCapture'
@ -300,6 +282,10 @@ class Config(object):
def _preparse(self, args): def _preparse(self, args):
self.inicfg = getcfg(args, ["setup.cfg", "tox.ini",]) self.inicfg = getcfg(args, ["setup.cfg", "tox.ini",])
if self.inicfg:
newargs = self.inicfg.get("addargs", None)
if newargs:
args[:] = args + py.std.shlex.split(newargs)
self._checkversion() self._checkversion()
self.pluginmanager.consider_setuptools_entrypoints() self.pluginmanager.consider_setuptools_entrypoints()
self.pluginmanager.consider_env() self.pluginmanager.consider_env()
@ -325,10 +311,6 @@ class Config(object):
"can only parse cmdline args at most once per Config object") "can only parse cmdline args at most once per Config object")
self._preparse(args) self._preparse(args)
self._parser.hints.extend(self.pluginmanager._hints) self._parser.hints.extend(self.pluginmanager._hints)
if self.inicfg:
newargs = self.inicfg.get("appendargs", None)
if newargs:
args += py.std.shlex.split(newargs)
args = self._parser.parse_setoption(args, self.option) args = self._parser.parse_setoption(args, self.option)
if not args: if not args:
args.append(py.std.os.getcwd()) args.append(py.std.os.getcwd())

View File

@ -1,12 +1,15 @@
""" provide version info, conftest/environment config names. """ provide version info, conftest/environment config names.
""" """
import py import py
import pytest
import inspect, sys import inspect, sys
def pytest_addoption(parser): def pytest_addoption(parser):
group = parser.getgroup('debugconfig') group = parser.getgroup('debugconfig')
group.addoption('--version', action="store_true", group.addoption('--version', action="store_true",
help="display py lib version and import information.") help="display py lib version and import information.")
group._addoption("-h", "--help", action="store_true", dest="help",
help="show help message and configuration info")
group._addoption('-p', action="append", dest="plugins", default = [], group._addoption('-p', action="append", dest="plugins", default = [],
metavar="name", metavar="name",
help="early-load given plugin (multi-allowed).") help="early-load given plugin (multi-allowed).")
@ -19,56 +22,47 @@ def pytest_addoption(parser):
group.addoption('--debug', group.addoption('--debug',
action="store_true", dest="debug", default=False, action="store_true", dest="debug", default=False,
help="generate and show internal debugging information.") help="generate and show internal debugging information.")
group.addoption("--help-config", action="store_true", dest="helpconfig",
help="show available conftest.py and ENV-variable names.")
def pytest_cmdline_main(config): def pytest_cmdline_main(config):
if config.option.version: if config.option.version:
p = py.path.local(py.__file__).dirpath() p = py.path.local(pytest.__file__).dirpath()
sys.stderr.write("This is py.test version %s, imported from %s\n" % sys.stderr.write("This is py.test version %s, imported from %s\n" %
(py.__version__, p)) (py.__version__, p))
return 0 return 0
elif config.option.helpconfig: elif config.option.help:
config.pluginmanager.do_configure(config) config.pluginmanager.do_configure(config)
showpluginhelp(config) showhelp(config)
return 0 return 0
def showpluginhelp(config): def showhelp(config):
options = []
for group in config._parser._groups:
options.extend(group.options)
widths = [0] * 10
tw = py.io.TerminalWriter() tw = py.io.TerminalWriter()
tw.sep("-") tw.write(config._parser.optparser.format_help())
tw.line("%-13s | %-18s | %-25s | %s" %( tw.line()
"cmdline name", "conftest.py name", "ENV-variable name", "help")) tw.line()
tw.sep("-") tw.sep( "=", "ini-settings")
tw.line("the following values can be defined in [pytest] sections of")
tw.line("setup.cfg or tox.ini files:")
tw.line()
options = [opt for opt in options if opt._long_opts] for name, help in ini_settings:
options.sort(key=lambda x: x._long_opts) line = " %-15s %s" %(name, help)
for opt in options:
if not opt._long_opts or not opt.dest:
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]) tw.line(line[:tw.fullwidth])
tw.line() ; tw.line()
#tw.sep( "=", "conftest.py settings")
tw.line("the following values can be defined in conftest.py files")
tw.line()
for name, help in conftest_options: for name, help in conftest_options:
line = "%-13s | %-18s | %-25s | %s" %( line = " %-15s %s" %(name, help)
"",
name,
"",
help,
)
tw.line(line[:tw.fullwidth]) tw.line(line[:tw.fullwidth])
tw.sep("-") tw.line()
tw.sep( "=")
ini_settings = (
('addargs', 'extra command line arguments'),
('minversion', 'minimally required pytest version'),
)
conftest_options = ( conftest_options = (
('pytest_plugins', 'list of plugin names to load'), ('pytest_plugins', 'list of plugin names to load'),
@ -79,7 +73,9 @@ conftest_options = (
def pytest_report_header(config): def pytest_report_header(config):
lines = [] lines = []
if config.option.debug or config.option.traceconfig: if config.option.debug or config.option.traceconfig:
lines.append("using py lib: %s" % (py.path.local(py.__file__).dirpath())) lines.append("using: pytest-%s pylib-%s" %
(pytest.__version__,py.__version__))
if config.option.traceconfig: if config.option.traceconfig:
lines.append("active plugins:") lines.append("active plugins:")
plugins = [] plugins = []
@ -149,12 +145,11 @@ def getargs(func):
startindex = inspect.ismethod(func) and 1 or 0 startindex = inspect.ismethod(func) and 1 or 0
return args[startindex:] return args[startindex:]
def collectattr(obj, prefixes=("pytest_",)): def collectattr(obj):
methods = {} methods = {}
for apiname in dir(obj): for apiname in dir(obj):
for prefix in prefixes: if apiname.startswith("pytest_"):
if apiname.startswith(prefix): methods[apiname] = getattr(obj, apiname)
methods[apiname] = getattr(obj, apiname)
return methods return methods
def formatdef(func): def formatdef(func):

View File

@ -242,6 +242,9 @@ class TmpTestdir:
def makefile(self, ext, *args, **kwargs): def makefile(self, ext, *args, **kwargs):
return self._makefile(ext, args, kwargs) return self._makefile(ext, args, kwargs)
def makeini(self, source):
return self.makefile('cfg', setup=source)
def makeconftest(self, source): def makeconftest(self, source):
return self.makepyfile(conftest=source) return self.makepyfile(conftest=source)

View File

@ -10,11 +10,13 @@ def test_version(testdir):
'*py.test*%s*imported from*' % (py.version, ) '*py.test*%s*imported from*' % (py.version, )
]) ])
def test_helpconfig(testdir): def test_help(testdir):
result = testdir.runpytest("--help-config") result = testdir.runpytest("--help")
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines([
"*cmdline*conftest*ENV*", "*-v*verbose*",
"*ini-settings*",
"*conftest.py*",
]) ])
def test_collectattr(): def test_collectattr():

View File

@ -466,8 +466,8 @@ def test_getreportopt():
testdict.update(dict(reportchars="sfx")) testdict.update(dict(reportchars="sfx"))
assert getreportopt(config) == "sfx" assert getreportopt(config) == "sfx"
def test_terminalreporter_reportopt_conftestsetting(testdir): def test_terminalreporter_reportopt_addargs(testdir):
testdir.makeconftest("option_report = 'skipped'") testdir.makeini("[pytest]\naddargs=-rs")
p = testdir.makepyfile(""" p = testdir.makepyfile("""
def pytest_funcarg__tr(request): def pytest_funcarg__tr(request):
tr = request.config.pluginmanager.getplugin("terminalreporter") tr = request.config.pluginmanager.getplugin("terminalreporter")

View File

@ -16,19 +16,10 @@ class TestParseIni:
config._preparse([sub]) config._preparse([sub])
assert config.inicfg['name'] == 'value' assert config.inicfg['name'] == 'value'
def test_getvalue(self, tmpdir):
tmpdir.join("setup.cfg").write(py.code.Source("""
[pytest]
verbose = True
"""))
config = Config()
config._preparse([tmpdir])
assert config.option.verbose
def test_append_parse_args(self, tmpdir): def test_append_parse_args(self, tmpdir):
tmpdir.join("setup.cfg").write(py.code.Source(""" tmpdir.join("setup.cfg").write(py.code.Source("""
[pytest] [pytest]
appendargs = --verbose addargs = --verbose
""")) """))
config = Config() config = Config()
config.parse([tmpdir]) config.parse([tmpdir])
@ -46,32 +37,6 @@ class TestParseIni:
]) ])
class TestConfigCmdlineParsing: class TestConfigCmdlineParsing:
def test_parser_addoption_default_env(self, testdir, monkeypatch):
import os
config = testdir.Config()
config._preparse([testdir.tmpdir])
group = config._parser.getgroup("hello")
monkeypatch.setitem(os.environ, 'PYTEST_OPTION_OPTION1', 'True')
group.addoption("--option1", action="store_true")
assert group.options[0].default == True
monkeypatch.setitem(os.environ, 'PYTEST_OPTION_OPTION2', 'abc')
group.addoption("--option2", action="store", default="x")
assert group.options[1].default == "abc"
monkeypatch.setitem(os.environ, 'PYTEST_OPTION_OPTION3', '32')
group.addoption("--option3", action="store", type="int")
assert group.options[2].default == 32
group.addoption("--option4", action="store", type="int")
assert group.options[3].default == ("NO", "DEFAULT")
def test_parser_addoption_default_conftest(self, testdir, monkeypatch):
import os
testdir.makeconftest("option_verbose=True")
config = testdir.parseconfig()
assert config.option.verbose
def test_parsing_again_fails(self, testdir): def test_parsing_again_fails(self, testdir):
config = testdir.reparseconfig([testdir.tmpdir]) config = testdir.reparseconfig([testdir.tmpdir])

View File

@ -2,11 +2,11 @@ import py
from pytest.plugin import config as parseopt from pytest.plugin import config as parseopt
class TestParser: class TestParser:
def test_init(self, capsys): def test_no_help_by_default(self, capsys):
parser = parseopt.Parser(usage="xyz") parser = parseopt.Parser(usage="xyz")
py.test.raises(SystemExit, 'parser.parse(["-h"])') py.test.raises(SystemExit, 'parser.parse(["-h"])')
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out.find("xyz") != -1 assert err.find("no such option") != -1
def test_group_add_and_get(self): def test_group_add_and_get(self):
parser = parseopt.Parser() parser = parseopt.Parser()