Support [tool:pytest] in setup.cfg files

Also deprecate [pytest] usage in setup.cfg files

Fix #567
This commit is contained in:
Bruno Oliveira 2016-08-16 21:30:07 -03:00
parent d3b855104c
commit ab86dea529
10 changed files with 85 additions and 33 deletions

View File

@ -232,6 +232,11 @@ time or change existing behaviors in order to make them less surprising/more use
* ``yield``-based tests are considered deprecated and will be removed in pytest-4.0.
Thanks `@nicoddemus`_ for the PR.
* ``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]``
to avoid conflicts with other distutils commands (see `#567`_). ``[pytest]`` sections in
``pytest.ini`` or ``tox.ini`` files are supported and unchanged.
Thanks `@nicoddemus`_ for the PR.
* Using ``pytest_funcarg__`` prefix to declare fixtures is considered deprecated and will be
removed in pytest-4.0 (`#1684`_).
Thanks `@nicoddemus`_ for the PR.
@ -374,6 +379,7 @@ time or change existing behaviors in order to make them less surprising/more use
.. _#372: https://github.com/pytest-dev/pytest/issues/372
.. _#457: https://github.com/pytest-dev/pytest/issues/457
.. _#460: https://github.com/pytest-dev/pytest/pull/460
.. _#567: https://github.com/pytest-dev/pytest/pull/567
.. _#607: https://github.com/pytest-dev/pytest/issues/607
.. _#634: https://github.com/pytest-dev/pytest/issues/634
.. _#717: https://github.com/pytest-dev/pytest/issues/717

View File

@ -927,7 +927,7 @@ class Config(object):
def _initini(self, args):
ns, unknown_args = self._parser.parse_known_and_unknown_args(args, namespace=self.option.copy())
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args)
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args, warnfunc=self.warn)
self.rootdir, self.inifile, self.inicfg = r
self._parser.extra_info['rootdir'] = self.rootdir
self._parser.extra_info['inifile'] = self.inifile
@ -1154,7 +1154,18 @@ def exists(path, ignore=EnvironmentError):
except ignore:
return False
def getcfg(args, inibasenames):
def getcfg(args, warnfunc=None):
"""
Search the list of arguments for a valid ini-file for pytest,
and return a tuple of (rootdir, inifile, cfg-dict).
note: warnfunc is an optional function used to warn
about ini-files that use deprecated features.
This parameter should be removed when pytest
adopts standard deprecation warnings (#1804).
"""
from _pytest.deprecated import SETUP_CFG_PYTEST
inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
args = [x for x in args if not str(x).startswith("-")]
if not args:
args = [py.path.local()]
@ -1166,7 +1177,11 @@ def getcfg(args, inibasenames):
if exists(p):
iniconfig = py.iniconfig.IniConfig(p)
if 'pytest' in iniconfig.sections:
if inibasename == 'setup.cfg' and warnfunc:
warnfunc('C1', SETUP_CFG_PYTEST)
return base, p, iniconfig['pytest']
if inibasename == 'setup.cfg' and 'tool:pytest' in iniconfig.sections:
return base, p, iniconfig['tool:pytest']
elif inibasename == "pytest.ini":
# allowed to be empty
return base, p, {}
@ -1207,7 +1222,7 @@ def get_dirs_from_args(args):
if d.exists()]
def determine_setup(inifile, args):
def determine_setup(inifile, args, warnfunc=None):
dirs = get_dirs_from_args(args)
if inifile:
iniconfig = py.iniconfig.IniConfig(inifile)
@ -1218,15 +1233,13 @@ def determine_setup(inifile, args):
rootdir = get_common_ancestor(dirs)
else:
ancestor = get_common_ancestor(dirs)
rootdir, inifile, inicfg = getcfg(
[ancestor], ["pytest.ini", "tox.ini", "setup.cfg"])
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
if rootdir is None:
for rootdir in ancestor.parts(reverse=True):
if rootdir.join("setup.py").exists():
break
else:
rootdir, inifile, inicfg = getcfg(
dirs, ["pytest.ini", "tox.ini", "setup.cfg"])
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
if rootdir is None:
rootdir = get_common_ancestor([py.path.local(), ancestor])
is_fs_root = os.path.splitdrive(str(rootdir))[1] == os.sep

View File

@ -17,5 +17,7 @@ FUNCARG_PREFIX = (
'and scheduled to be removed in pytest 4.0. '
'Please remove the prefix and use the @pytest.fixture decorator instead.')
SETUP_CFG_PYTEST = '[pytest] section in setup.cfg files is deprecated, use [tool:pytest] instead.'
GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue"

View File

@ -71,7 +71,6 @@ def showhelp(config):
tw.write(config._parser.optparser.format_help())
tw.line()
tw.line()
#tw.sep( "=", "config file settings")
tw.line("[pytest] ini-options in the next "
"pytest.ini|tox.ini|setup.cfg file:")
tw.line()

View File

@ -50,7 +50,7 @@ Here is the algorithm which finds the rootdir from ``args``:
Note that an existing ``pytest.ini`` file will always be considered a match,
whereas ``tox.ini`` and ``setup.cfg`` will only match if they contain a
``[pytest]`` section. Options from multiple ini-files candidates are never
``[pytest]`` or ``[tool:pytest]`` section, respectively. Options from multiple ini-files candidates are never
merged - the first one wins (``pytest.ini`` always wins, even if it does not
contain a ``[pytest]`` section).
@ -73,7 +73,7 @@ check for ini-files as follows::
# first look for pytest.ini files
path/pytest.ini
path/setup.cfg # must also contain [pytest] section to match
path/setup.cfg # must also contain [tool:pytest] section to match
path/tox.ini # must also contain [pytest] section to match
pytest.ini
... # all the way down to the root
@ -154,7 +154,7 @@ Builtin configuration file options
.. code-block:: ini
# content of setup.cfg
# content of pytest.ini
[pytest]
norecursedirs = .svn _build tmp*

View File

@ -77,9 +77,9 @@ Example::
Changing directory recursion
-----------------------------------------------------
You can set the :confval:`norecursedirs` option in an ini-file, for example your ``setup.cfg`` in the project root directory::
You can set the :confval:`norecursedirs` option in an ini-file, for example your ``pytest.ini`` in the project root directory::
# content of setup.cfg
# content of pytest.ini
[pytest]
norecursedirs = .svn _build tmp*
@ -94,8 +94,9 @@ You can configure different naming conventions by setting
the :confval:`python_files`, :confval:`python_classes` and
:confval:`python_functions` configuration options. Example::
# content of setup.cfg
# can also be defined in in tox.ini or pytest.ini file
# content of pytest.ini
# can also be defined in in tox.ini or setup.cfg file, although the section
# name in setup.cfg files should be "tool:pytest"
[pytest]
python_files=check_*.py
python_classes=Check

View File

@ -196,6 +196,24 @@ required for calling the test command. You can also pass additional
arguments to pytest such as your test directory or other
options using ``--addopts``.
You can also specify other pytest-ini options in your ``setup.cfg`` file
by putting them into a ``[tool:pytest]`` section:
.. code-block:: ini
[tool:pytest]
addopts = --verbose
python_files = testing/*/*.py
.. note::
Prior to 3.0, the supported section name was ``[pytest]``. Due to how
this may collide with some distutils commands, the recommended
section name for ``setup.cfg`` files is now ``[tool:pytest]``.
Note that for ``pytest.ini`` and ``tox.ini`` files the section
name is ``[pytest]``.
Manual Integration
^^^^^^^^^^^^^^^^^^

View File

@ -90,7 +90,7 @@ and ``pytest`` will run your tests. Assuming you have failures it will then
wait for file changes and re-run the failing test set. File changes are detected by looking at ``looponfailingroots`` root directories and all of their contents (recursively). If the default for this value does not work for you you
can change it in your project by setting a configuration option::
# content of a pytest.ini, setup.cfg or tox.ini file
# content of a pytest.ini or tox.ini file
[pytest]
looponfailroots = mypkg testdir
@ -181,7 +181,7 @@ to run tests in each of the environments.
Specifying "rsync" dirs in an ini-file
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
In a ``tox.ini`` or ``setup.cfg`` file in your root project directory
In a ``pytest.ini`` or ``tox.ini`` file in your root project directory
you may specify directories to include or to exclude in synchronisation::
[pytest]

View File

@ -34,6 +34,15 @@ def test_funcarg_prefix_deprecation(testdir):
])
def test_pytest_setup_cfg_deprecated(testdir):
testdir.makefile('.cfg', setup='''
[pytest]
addopts = --verbose
''')
result = testdir.runpytest()
result.stdout.fnmatch_lines(['*pytest*section in setup.cfg files is deprecated*use*tool:pytest*instead*'])
def test_str_args_deprecated(tmpdir, testdir):
"""Deprecate passing strings to pytest.main(). Scheduled for removal in pytest-4.0."""
from _pytest.main import EXIT_NOTESTSCOLLECTED

View File

@ -5,24 +5,28 @@ from _pytest.config import getcfg, get_common_ancestor, determine_setup
from _pytest.main import EXIT_NOTESTSCOLLECTED
class TestParseIni:
def test_getcfg_and_config(self, testdir, tmpdir):
@pytest.mark.parametrize('section, filename',
[('pytest', 'pytest.ini'), ('tool:pytest', 'setup.cfg')])
def test_getcfg_and_config(self, testdir, tmpdir, section, filename):
sub = tmpdir.mkdir("sub")
sub.chdir()
tmpdir.join("setup.cfg").write(_pytest._code.Source("""
[pytest]
tmpdir.join(filename).write(_pytest._code.Source("""
[{section}]
name = value
"""))
rootdir, inifile, cfg = getcfg([sub], ["setup.cfg"])
""".format(section=section)))
rootdir, inifile, cfg = getcfg([sub])
assert cfg['name'] == "value"
config = testdir.parseconfigure(sub)
assert config.inicfg['name'] == 'value'
def test_getcfg_empty_path(self, tmpdir):
getcfg([''], ['setup.cfg']) #happens on pytest ""
def test_getcfg_empty_path(self):
"""correctly handle zero length arguments (a la pytest '')"""
getcfg([''])
def test_append_parse_args(self, testdir, tmpdir, monkeypatch):
monkeypatch.setenv('PYTEST_ADDOPTS', '--color no -rs --tb="short"')
tmpdir.join("setup.cfg").write(_pytest._code.Source("""
tmpdir.join("pytest.ini").write(_pytest._code.Source("""
[pytest]
addopts = --verbose
"""))
@ -31,10 +35,6 @@ class TestParseIni:
assert config.option.reportchars == 's'
assert config.option.tbstyle == 'short'
assert config.option.verbose
#config = testdir.Config()
#args = [tmpdir,]
#config._preparse(args, addopts=False)
#assert len(args) == 1
def test_tox_ini_wrong_version(self, testdir):
testdir.makefile('.ini', tox="""
@ -47,12 +47,16 @@ class TestParseIni:
"*tox.ini:2*requires*9.0*actual*"
])
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
def test_ini_names(self, testdir, name):
@pytest.mark.parametrize("section, name", [
('tool:pytest', 'setup.cfg'),
('pytest', 'tox.ini'),
('pytest', 'pytest.ini')],
)
def test_ini_names(self, testdir, name, section):
testdir.tmpdir.join(name).write(py.std.textwrap.dedent("""
[pytest]
[{section}]
minversion = 1.0
"""))
""".format(section=section)))
config = testdir.parseconfig()
assert config.getini("minversion") == "1.0"