introduce reading of setup.cfg / ini-style configuration files
rename internal config.Error to pytest.UsageError --HG-- branch : trunk
This commit is contained in:
parent
f7b4f70a16
commit
b86b1628bb
|
@ -1,7 +1,9 @@
|
|||
Changes between 1.3.4 and 2.0.0dev0
|
||||
----------------------------------------------
|
||||
|
||||
- pytest-2.0 is now its own package and depends on pylib
|
||||
- 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,
|
||||
by default setup.cfg and tox.ini files are searched.
|
||||
- fix issue126 - introduce py.test.set_trace() to trace execution via
|
||||
PDB during the running of tests even if capturing is ongoing.
|
||||
- fix issue123 - new "python -m py.test" invocation for py.test
|
||||
|
|
|
@ -258,3 +258,9 @@ epub_copyright = u'2010, holger krekel et aliter'
|
|||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'http://docs.python.org/': None}
|
||||
def setup(app):
|
||||
#from sphinx.ext.autodoc import cut_lines
|
||||
#app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
|
||||
app.add_description_unit('confval', 'confval',
|
||||
objname='configuration value',
|
||||
indextemplate='pair: %s; configuration value')
|
||||
|
|
|
@ -15,6 +15,26 @@ You can see command line options by running::
|
|||
This will display all available command line options
|
||||
in your specific environment.
|
||||
|
||||
reading test configuration from ini-files
|
||||
--------------------------------------------------------
|
||||
|
||||
py.test tries to find a configuration INI format file, trying
|
||||
to find a section ``[pytest]`` in a ``tox.ini`` (or XXX ``pytest.ini`` file).
|
||||
Possible entries in a ``[pytest]`` section are:
|
||||
|
||||
.. confval:: minversion = VERSTRING
|
||||
|
||||
specifies the minimal pytest version that is needed for this test suite.
|
||||
|
||||
minversion = 2.1 # will fail if we run with pytest-2.0
|
||||
|
||||
.. confval:: appendargs = OPTS
|
||||
|
||||
append the specified ``OPTS`` to the command line arguments as if they
|
||||
had been specified by the user. Example::
|
||||
|
||||
appendargs = --maxfail=2 -rf # exit after 2 failures, report fail info
|
||||
|
||||
|
||||
setting persistent option defaults
|
||||
------------------------------------
|
||||
|
@ -22,6 +42,7 @@ setting persistent option defaults
|
|||
py.test will lookup option values in this order:
|
||||
|
||||
* command line
|
||||
* ``[pytest]`` section in upwards ``setup.cfg`` or ``tox.ini`` files.
|
||||
* conftest.py files
|
||||
* environment variables
|
||||
|
||||
|
@ -86,6 +107,7 @@ in your home directory to provide global configuration values.
|
|||
|
||||
.. _`named plugins`: plugin/index.html
|
||||
|
||||
|
||||
Plugin discovery at tool startup
|
||||
--------------------------------------------
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ __version__ = '2.0.0.dev10'
|
|||
__all__ = ['config', 'cmdline']
|
||||
|
||||
from pytest import _core as cmdline
|
||||
UsageError = cmdline.UsageError
|
||||
|
||||
def __main__():
|
||||
raise SystemExit(cmdline.main())
|
||||
raise SystemExit(cmdline.main())
|
||||
|
|
|
@ -345,13 +345,16 @@ def main(args=None):
|
|||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
hook = pluginmanager.hook
|
||||
config = hook.pytest_cmdline_parse(pluginmanager=pluginmanager, args=args)
|
||||
try:
|
||||
config = hook.pytest_cmdline_parse(
|
||||
pluginmanager=pluginmanager, args=args)
|
||||
exitstatus = hook.pytest_cmdline_main(config=config)
|
||||
except config.Error:
|
||||
except UsageError:
|
||||
e = sys.exc_info()[1]
|
||||
sys.stderr.write("ERROR: %s\n" %(e.args[0],))
|
||||
exitstatus = 3
|
||||
pluginmanager = PluginManager(load=True)
|
||||
return exitstatus
|
||||
|
||||
class UsageError(Exception):
|
||||
""" error in py.test usage or invocation"""
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import py
|
||||
import sys, os
|
||||
from pytest._core import PluginManager
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_cmdline_parse(pluginmanager, args):
|
||||
|
@ -226,13 +227,9 @@ class CmdOptions(object):
|
|||
def __repr__(self):
|
||||
return "<CmdOptions %r>" %(self.__dict__,)
|
||||
|
||||
class Error(Exception):
|
||||
""" Test Configuration Error. """
|
||||
|
||||
class Config(object):
|
||||
""" access to configuration values, pluginmanager and plugin hooks. """
|
||||
Option = py.std.optparse.Option
|
||||
Error = Error
|
||||
basetemp = None
|
||||
|
||||
def __init__(self, pluginmanager=None):
|
||||
|
@ -280,7 +277,10 @@ class Config(object):
|
|||
try:
|
||||
opt.default = self._conftest.rget(name)
|
||||
except (ValueError, KeyError):
|
||||
pass
|
||||
try:
|
||||
opt.default = self.inicfg[opt.dest]
|
||||
except KeyError:
|
||||
pass
|
||||
if not hasattr(self.option, opt.dest):
|
||||
setattr(self.option, opt.dest, opt.default)
|
||||
|
||||
|
@ -299,12 +299,25 @@ class Config(object):
|
|||
raise
|
||||
|
||||
def _preparse(self, args):
|
||||
self.inicfg = getcfg(args, ["setup.cfg", "tox.ini",])
|
||||
self._checkversion()
|
||||
self.pluginmanager.consider_setuptools_entrypoints()
|
||||
self.pluginmanager.consider_env()
|
||||
self.pluginmanager.consider_preparse(args)
|
||||
self._setinitialconftest(args)
|
||||
self.pluginmanager.do_addoption(self._parser)
|
||||
|
||||
def _checkversion(self):
|
||||
minver = self.inicfg.get('minversion', None)
|
||||
if minver:
|
||||
ver = minver.split(".")
|
||||
myver = pytest.__version__.split(".")
|
||||
if myver < ver:
|
||||
raise pytest.UsageError(
|
||||
"%s:%d: requires pytest-%s, actual pytest-%s'" %(
|
||||
self.inicfg.config.path, self.inicfg.lineof('minversion'),
|
||||
minver, pytest.__version__))
|
||||
|
||||
def parse(self, args):
|
||||
# cmdline arguments into this config object.
|
||||
# Note that this can only be called once per testing process.
|
||||
|
@ -312,6 +325,10 @@ class Config(object):
|
|||
"can only parse cmdline args at most once per Config object")
|
||||
self._preparse(args)
|
||||
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)
|
||||
if not args:
|
||||
args.append(py.std.os.getcwd())
|
||||
|
@ -381,3 +398,26 @@ class Config(object):
|
|||
except AttributeError:
|
||||
return self._conftest.rget(name, path)
|
||||
|
||||
def getcfg(args, inibasenames):
|
||||
if not args:
|
||||
args = [py.path.local()]
|
||||
for inibasename in inibasenames:
|
||||
for p in args:
|
||||
x = findupwards(p, inibasename)
|
||||
if x is not None:
|
||||
iniconfig = py.iniconfig.IniConfig(x)
|
||||
if 'pytest' in iniconfig.sections:
|
||||
return iniconfig['pytest']
|
||||
return {}
|
||||
|
||||
def findupwards(current, basename):
|
||||
current = py.path.local(current)
|
||||
while 1:
|
||||
p = current.join(basename)
|
||||
if p.check():
|
||||
return p
|
||||
p = current.dirpath()
|
||||
if p == current:
|
||||
return
|
||||
current = p
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ class Session(object):
|
|||
config.hook.pytest_sessionstart(session=self)
|
||||
config.hook.pytest_perform_collection(session=self)
|
||||
config.hook.pytest_runtest_mainloop(session=self)
|
||||
except self.config.Error:
|
||||
except pytest.UsageError:
|
||||
raise
|
||||
except KeyboardInterrupt:
|
||||
excinfo = py.code.ExceptionInfo()
|
||||
|
@ -173,10 +173,10 @@ class Collection:
|
|||
parts = str(arg).split("::")
|
||||
path = base.join(parts[0], abs=True)
|
||||
if not path.check():
|
||||
raise self.config.Error("file not found: %s" %(path,))
|
||||
raise pytest.UsageError("file not found: %s" %(path,))
|
||||
topdir = self.topdir
|
||||
if path != topdir and not path.relto(topdir):
|
||||
raise self.config.Error("path %r is not relative to %r" %
|
||||
raise pytest.UsageError("path %r is not relative to %r" %
|
||||
(str(path), str(topdir)))
|
||||
topparts = path.relto(topdir).split(path.sep)
|
||||
return topparts + parts[1:]
|
||||
|
@ -213,7 +213,7 @@ class Collection:
|
|||
for node in self.matchnodes([self._topcollector], names):
|
||||
items.extend(self.genitems(node))
|
||||
except NoMatch:
|
||||
raise self.config.Error("can't collect: %s" % (arg,))
|
||||
raise pytest.UsageError("can't collect: %s" % (arg,))
|
||||
return items
|
||||
|
||||
def matchnodes(self, matching, names):
|
||||
|
|
|
@ -4,7 +4,8 @@ class TestGeneralUsage:
|
|||
def test_config_error(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
def pytest_configure(config):
|
||||
raise config.Error("hello")
|
||||
import pytest
|
||||
raise pytest.UsageError("hello")
|
||||
""")
|
||||
result = testdir.runpytest(testdir.tmpdir)
|
||||
assert result.ret != 0
|
||||
|
|
|
@ -41,6 +41,12 @@ def pytest_unconfigure(config, __multicall__):
|
|||
assert len2 < config._numfiles + 7, out2
|
||||
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
item._oldir = py.path.local()
|
||||
|
||||
def pytest_runtest_teardown(item):
|
||||
item._oldir.chdir()
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
multi = getattr(metafunc.function, 'multi', None)
|
||||
if multi is not None:
|
||||
|
|
|
@ -1,9 +1,55 @@
|
|||
import py
|
||||
|
||||
from pytest.plugin.config import getcfg, Config
|
||||
|
||||
class TestParseIni:
|
||||
def test_getcfg_and_config(self, tmpdir):
|
||||
sub = tmpdir.mkdir("sub")
|
||||
sub.chdir()
|
||||
tmpdir.join("setup.cfg").write(py.code.Source("""
|
||||
[pytest]
|
||||
name = value
|
||||
"""))
|
||||
cfg = getcfg([sub], ["setup.cfg"])
|
||||
assert cfg['name'] == "value"
|
||||
config = Config()
|
||||
config._preparse([sub])
|
||||
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):
|
||||
tmpdir.join("setup.cfg").write(py.code.Source("""
|
||||
[pytest]
|
||||
appendargs = --verbose
|
||||
"""))
|
||||
config = Config()
|
||||
config.parse([tmpdir])
|
||||
assert config.option.verbose
|
||||
|
||||
def test_tox_ini_wrong_version(self, testdir):
|
||||
p = testdir.makefile('.ini', tox="""
|
||||
[pytest]
|
||||
minversion=9.0
|
||||
""")
|
||||
result = testdir.runpytest()
|
||||
assert result.ret != 0
|
||||
result.stderr.fnmatch_lines([
|
||||
"*tox.ini:2*requires*9.0*actual*"
|
||||
])
|
||||
|
||||
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')
|
||||
|
|
Loading…
Reference in New Issue