Merge pull request #1813 from nicoddemus/pytest-setup.cfg
Support [tool:pytest] in setup.cfg files
This commit is contained in:
commit
789e4670e7
|
@ -225,6 +225,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.
|
* ``yield``-based tests are considered deprecated and will be removed in pytest-4.0.
|
||||||
Thanks `@nicoddemus`_ for the PR.
|
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
|
* Using ``pytest_funcarg__`` prefix to declare fixtures is considered deprecated and will be
|
||||||
removed in pytest-4.0 (`#1684`_).
|
removed in pytest-4.0 (`#1684`_).
|
||||||
Thanks `@nicoddemus`_ for the PR.
|
Thanks `@nicoddemus`_ for the PR.
|
||||||
|
@ -375,6 +380,7 @@ time or change existing behaviors in order to make them less surprising/more use
|
||||||
.. _#372: https://github.com/pytest-dev/pytest/issues/372
|
.. _#372: https://github.com/pytest-dev/pytest/issues/372
|
||||||
.. _#457: https://github.com/pytest-dev/pytest/issues/457
|
.. _#457: https://github.com/pytest-dev/pytest/issues/457
|
||||||
.. _#460: https://github.com/pytest-dev/pytest/pull/460
|
.. _#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
|
.. _#607: https://github.com/pytest-dev/pytest/issues/607
|
||||||
.. _#634: https://github.com/pytest-dev/pytest/issues/634
|
.. _#634: https://github.com/pytest-dev/pytest/issues/634
|
||||||
.. _#717: https://github.com/pytest-dev/pytest/issues/717
|
.. _#717: https://github.com/pytest-dev/pytest/issues/717
|
||||||
|
|
|
@ -927,7 +927,7 @@ class Config(object):
|
||||||
|
|
||||||
def _initini(self, args):
|
def _initini(self, args):
|
||||||
ns, unknown_args = self._parser.parse_known_and_unknown_args(args, namespace=self.option.copy())
|
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.rootdir, self.inifile, self.inicfg = r
|
||||||
self._parser.extra_info['rootdir'] = self.rootdir
|
self._parser.extra_info['rootdir'] = self.rootdir
|
||||||
self._parser.extra_info['inifile'] = self.inifile
|
self._parser.extra_info['inifile'] = self.inifile
|
||||||
|
@ -1154,7 +1154,18 @@ def exists(path, ignore=EnvironmentError):
|
||||||
except ignore:
|
except ignore:
|
||||||
return False
|
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("-")]
|
args = [x for x in args if not str(x).startswith("-")]
|
||||||
if not args:
|
if not args:
|
||||||
args = [py.path.local()]
|
args = [py.path.local()]
|
||||||
|
@ -1166,7 +1177,11 @@ def getcfg(args, inibasenames):
|
||||||
if exists(p):
|
if exists(p):
|
||||||
iniconfig = py.iniconfig.IniConfig(p)
|
iniconfig = py.iniconfig.IniConfig(p)
|
||||||
if 'pytest' in iniconfig.sections:
|
if 'pytest' in iniconfig.sections:
|
||||||
|
if inibasename == 'setup.cfg' and warnfunc:
|
||||||
|
warnfunc('C1', SETUP_CFG_PYTEST)
|
||||||
return base, p, iniconfig['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":
|
elif inibasename == "pytest.ini":
|
||||||
# allowed to be empty
|
# allowed to be empty
|
||||||
return base, p, {}
|
return base, p, {}
|
||||||
|
@ -1207,7 +1222,7 @@ def get_dirs_from_args(args):
|
||||||
if d.exists()]
|
if d.exists()]
|
||||||
|
|
||||||
|
|
||||||
def determine_setup(inifile, args):
|
def determine_setup(inifile, args, warnfunc=None):
|
||||||
dirs = get_dirs_from_args(args)
|
dirs = get_dirs_from_args(args)
|
||||||
if inifile:
|
if inifile:
|
||||||
iniconfig = py.iniconfig.IniConfig(inifile)
|
iniconfig = py.iniconfig.IniConfig(inifile)
|
||||||
|
@ -1218,15 +1233,13 @@ def determine_setup(inifile, args):
|
||||||
rootdir = get_common_ancestor(dirs)
|
rootdir = get_common_ancestor(dirs)
|
||||||
else:
|
else:
|
||||||
ancestor = get_common_ancestor(dirs)
|
ancestor = get_common_ancestor(dirs)
|
||||||
rootdir, inifile, inicfg = getcfg(
|
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
|
||||||
[ancestor], ["pytest.ini", "tox.ini", "setup.cfg"])
|
|
||||||
if rootdir is None:
|
if rootdir is None:
|
||||||
for rootdir in ancestor.parts(reverse=True):
|
for rootdir in ancestor.parts(reverse=True):
|
||||||
if rootdir.join("setup.py").exists():
|
if rootdir.join("setup.py").exists():
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
rootdir, inifile, inicfg = getcfg(
|
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
|
||||||
dirs, ["pytest.ini", "tox.ini", "setup.cfg"])
|
|
||||||
if rootdir is None:
|
if rootdir is None:
|
||||||
rootdir = get_common_ancestor([py.path.local(), ancestor])
|
rootdir = get_common_ancestor([py.path.local(), ancestor])
|
||||||
is_fs_root = os.path.splitdrive(str(rootdir))[1] == os.sep
|
is_fs_root = os.path.splitdrive(str(rootdir))[1] == os.sep
|
||||||
|
|
|
@ -17,6 +17,8 @@ FUNCARG_PREFIX = (
|
||||||
'and scheduled to be removed in pytest 4.0. '
|
'and scheduled to be removed in pytest 4.0. '
|
||||||
'Please remove the prefix and use the @pytest.fixture decorator instead.')
|
'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"
|
GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue"
|
||||||
|
|
||||||
RESULT_LOG = '--result-log is deprecated and scheduled for removal in pytest 4.0'
|
RESULT_LOG = '--result-log is deprecated and scheduled for removal in pytest 4.0'
|
||||||
|
|
|
@ -71,7 +71,6 @@ def showhelp(config):
|
||||||
tw.write(config._parser.optparser.format_help())
|
tw.write(config._parser.optparser.format_help())
|
||||||
tw.line()
|
tw.line()
|
||||||
tw.line()
|
tw.line()
|
||||||
#tw.sep( "=", "config file settings")
|
|
||||||
tw.line("[pytest] ini-options in the next "
|
tw.line("[pytest] ini-options in the next "
|
||||||
"pytest.ini|tox.ini|setup.cfg file:")
|
"pytest.ini|tox.ini|setup.cfg file:")
|
||||||
tw.line()
|
tw.line()
|
||||||
|
|
|
@ -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,
|
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
|
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
|
merged - the first one wins (``pytest.ini`` always wins, even if it does not
|
||||||
contain a ``[pytest]`` section).
|
contain a ``[pytest]`` section).
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ check for ini-files as follows::
|
||||||
|
|
||||||
# first look for pytest.ini files
|
# first look for pytest.ini files
|
||||||
path/pytest.ini
|
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
|
path/tox.ini # must also contain [pytest] section to match
|
||||||
pytest.ini
|
pytest.ini
|
||||||
... # all the way down to the root
|
... # all the way down to the root
|
||||||
|
@ -154,7 +154,7 @@ Builtin configuration file options
|
||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
|
|
||||||
# content of setup.cfg
|
# content of pytest.ini
|
||||||
[pytest]
|
[pytest]
|
||||||
norecursedirs = .svn _build tmp*
|
norecursedirs = .svn _build tmp*
|
||||||
|
|
||||||
|
|
|
@ -77,9 +77,9 @@ Example::
|
||||||
Changing directory recursion
|
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]
|
[pytest]
|
||||||
norecursedirs = .svn _build tmp*
|
norecursedirs = .svn _build tmp*
|
||||||
|
|
||||||
|
@ -94,8 +94,9 @@ You can configure different naming conventions by setting
|
||||||
the :confval:`python_files`, :confval:`python_classes` and
|
the :confval:`python_files`, :confval:`python_classes` and
|
||||||
:confval:`python_functions` configuration options. Example::
|
:confval:`python_functions` configuration options. Example::
|
||||||
|
|
||||||
# content of setup.cfg
|
# content of pytest.ini
|
||||||
# can also be defined in in tox.ini or pytest.ini file
|
# 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]
|
[pytest]
|
||||||
python_files=check_*.py
|
python_files=check_*.py
|
||||||
python_classes=Check
|
python_classes=Check
|
||||||
|
|
|
@ -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
|
arguments to pytest such as your test directory or other
|
||||||
options using ``--addopts``.
|
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
|
Manual Integration
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -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
|
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::
|
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]
|
[pytest]
|
||||||
looponfailroots = mypkg testdir
|
looponfailroots = mypkg testdir
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ to run tests in each of the environments.
|
||||||
Specifying "rsync" dirs in an ini-file
|
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::
|
you may specify directories to include or to exclude in synchronisation::
|
||||||
|
|
||||||
[pytest]
|
[pytest]
|
||||||
|
|
|
@ -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):
|
def test_str_args_deprecated(tmpdir, testdir):
|
||||||
"""Deprecate passing strings to pytest.main(). Scheduled for removal in pytest-4.0."""
|
"""Deprecate passing strings to pytest.main(). Scheduled for removal in pytest-4.0."""
|
||||||
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
||||||
|
|
|
@ -5,24 +5,28 @@ from _pytest.config import getcfg, get_common_ancestor, determine_setup
|
||||||
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
||||||
|
|
||||||
class TestParseIni:
|
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 = tmpdir.mkdir("sub")
|
||||||
sub.chdir()
|
sub.chdir()
|
||||||
tmpdir.join("setup.cfg").write(_pytest._code.Source("""
|
tmpdir.join(filename).write(_pytest._code.Source("""
|
||||||
[pytest]
|
[{section}]
|
||||||
name = value
|
name = value
|
||||||
"""))
|
""".format(section=section)))
|
||||||
rootdir, inifile, cfg = getcfg([sub], ["setup.cfg"])
|
rootdir, inifile, cfg = getcfg([sub])
|
||||||
assert cfg['name'] == "value"
|
assert cfg['name'] == "value"
|
||||||
config = testdir.parseconfigure(sub)
|
config = testdir.parseconfigure(sub)
|
||||||
assert config.inicfg['name'] == 'value'
|
assert config.inicfg['name'] == 'value'
|
||||||
|
|
||||||
def test_getcfg_empty_path(self, tmpdir):
|
def test_getcfg_empty_path(self):
|
||||||
getcfg([''], ['setup.cfg']) #happens on pytest ""
|
"""correctly handle zero length arguments (a la pytest '')"""
|
||||||
|
getcfg([''])
|
||||||
|
|
||||||
def test_append_parse_args(self, testdir, tmpdir, monkeypatch):
|
def test_append_parse_args(self, testdir, tmpdir, monkeypatch):
|
||||||
monkeypatch.setenv('PYTEST_ADDOPTS', '--color no -rs --tb="short"')
|
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]
|
[pytest]
|
||||||
addopts = --verbose
|
addopts = --verbose
|
||||||
"""))
|
"""))
|
||||||
|
@ -31,10 +35,6 @@ class TestParseIni:
|
||||||
assert config.option.reportchars == 's'
|
assert config.option.reportchars == 's'
|
||||||
assert config.option.tbstyle == 'short'
|
assert config.option.tbstyle == 'short'
|
||||||
assert config.option.verbose
|
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):
|
def test_tox_ini_wrong_version(self, testdir):
|
||||||
testdir.makefile('.ini', tox="""
|
testdir.makefile('.ini', tox="""
|
||||||
|
@ -47,12 +47,16 @@ class TestParseIni:
|
||||||
"*tox.ini:2*requires*9.0*actual*"
|
"*tox.ini:2*requires*9.0*actual*"
|
||||||
])
|
])
|
||||||
|
|
||||||
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
|
@pytest.mark.parametrize("section, name", [
|
||||||
def test_ini_names(self, testdir, 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("""
|
testdir.tmpdir.join(name).write(py.std.textwrap.dedent("""
|
||||||
[pytest]
|
[{section}]
|
||||||
minversion = 1.0
|
minversion = 1.0
|
||||||
"""))
|
""".format(section=section)))
|
||||||
config = testdir.parseconfig()
|
config = testdir.parseconfig()
|
||||||
assert config.getini("minversion") == "1.0"
|
assert config.getini("minversion") == "1.0"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue