Skip to content

Commit 789e467

Browse files
authored
Merge pull request #1813 from nicoddemus/pytest-setup.cfg
Support [tool:pytest] in setup.cfg files
2 parents c8ab794 + ab86dea commit 789e467

10 files changed

+85
-33
lines changed

CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ time or change existing behaviors in order to make them less surprising/more use
225225
* ``yield``-based tests are considered deprecated and will be removed in pytest-4.0.
226226
Thanks `@nicoddemus`_ for the PR.
227227

228+
* ``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]``
229+
to avoid conflicts with other distutils commands (see `#567`_). ``[pytest]`` sections in
230+
``pytest.ini`` or ``tox.ini`` files are supported and unchanged.
231+
Thanks `@nicoddemus`_ for the PR.
232+
228233
* Using ``pytest_funcarg__`` prefix to declare fixtures is considered deprecated and will be
229234
removed in pytest-4.0 (`#1684`_).
230235
Thanks `@nicoddemus`_ for the PR.
@@ -375,6 +380,7 @@ time or change existing behaviors in order to make them less surprising/more use
375380
.. _#372: https://github.com/pytest-dev/pytest/issues/372
376381
.. _#457: https://github.com/pytest-dev/pytest/issues/457
377382
.. _#460: https://github.com/pytest-dev/pytest/pull/460
383+
.. _#567: https://github.com/pytest-dev/pytest/pull/567
378384
.. _#607: https://github.com/pytest-dev/pytest/issues/607
379385
.. _#634: https://github.com/pytest-dev/pytest/issues/634
380386
.. _#717: https://github.com/pytest-dev/pytest/issues/717

_pytest/config.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ def pytest_load_initial_conftests(self, early_config):
927927

928928
def _initini(self, args):
929929
ns, unknown_args = self._parser.parse_known_and_unknown_args(args, namespace=self.option.copy())
930-
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args)
930+
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args, warnfunc=self.warn)
931931
self.rootdir, self.inifile, self.inicfg = r
932932
self._parser.extra_info['rootdir'] = self.rootdir
933933
self._parser.extra_info['inifile'] = self.inifile
@@ -1154,7 +1154,18 @@ def exists(path, ignore=EnvironmentError):
11541154
except ignore:
11551155
return False
11561156

1157-
def getcfg(args, inibasenames):
1157+
def getcfg(args, warnfunc=None):
1158+
"""
1159+
Search the list of arguments for a valid ini-file for pytest,
1160+
and return a tuple of (rootdir, inifile, cfg-dict).
1161+
1162+
note: warnfunc is an optional function used to warn
1163+
about ini-files that use deprecated features.
1164+
This parameter should be removed when pytest
1165+
adopts standard deprecation warnings (#1804).
1166+
"""
1167+
from _pytest.deprecated import SETUP_CFG_PYTEST
1168+
inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
11581169
args = [x for x in args if not str(x).startswith("-")]
11591170
if not args:
11601171
args = [py.path.local()]
@@ -1166,7 +1177,11 @@ def getcfg(args, inibasenames):
11661177
if exists(p):
11671178
iniconfig = py.iniconfig.IniConfig(p)
11681179
if 'pytest' in iniconfig.sections:
1180+
if inibasename == 'setup.cfg' and warnfunc:
1181+
warnfunc('C1', SETUP_CFG_PYTEST)
11691182
return base, p, iniconfig['pytest']
1183+
if inibasename == 'setup.cfg' and 'tool:pytest' in iniconfig.sections:
1184+
return base, p, iniconfig['tool:pytest']
11701185
elif inibasename == "pytest.ini":
11711186
# allowed to be empty
11721187
return base, p, {}
@@ -1207,7 +1222,7 @@ def get_dirs_from_args(args):
12071222
if d.exists()]
12081223

12091224

1210-
def determine_setup(inifile, args):
1225+
def determine_setup(inifile, args, warnfunc=None):
12111226
dirs = get_dirs_from_args(args)
12121227
if inifile:
12131228
iniconfig = py.iniconfig.IniConfig(inifile)
@@ -1218,15 +1233,13 @@ def determine_setup(inifile, args):
12181233
rootdir = get_common_ancestor(dirs)
12191234
else:
12201235
ancestor = get_common_ancestor(dirs)
1221-
rootdir, inifile, inicfg = getcfg(
1222-
[ancestor], ["pytest.ini", "tox.ini", "setup.cfg"])
1236+
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
12231237
if rootdir is None:
12241238
for rootdir in ancestor.parts(reverse=True):
12251239
if rootdir.join("setup.py").exists():
12261240
break
12271241
else:
1228-
rootdir, inifile, inicfg = getcfg(
1229-
dirs, ["pytest.ini", "tox.ini", "setup.cfg"])
1242+
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
12301243
if rootdir is None:
12311244
rootdir = get_common_ancestor([py.path.local(), ancestor])
12321245
is_fs_root = os.path.splitdrive(str(rootdir))[1] == os.sep

_pytest/deprecated.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
'and scheduled to be removed in pytest 4.0. '
1818
'Please remove the prefix and use the @pytest.fixture decorator instead.')
1919

20+
SETUP_CFG_PYTEST = '[pytest] section in setup.cfg files is deprecated, use [tool:pytest] instead.'
21+
2022
GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue"
2123

2224
RESULT_LOG = '--result-log is deprecated and scheduled for removal in pytest 4.0'

_pytest/helpconfig.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ def showhelp(config):
7171
tw.write(config._parser.optparser.format_help())
7272
tw.line()
7373
tw.line()
74-
#tw.sep( "=", "config file settings")
7574
tw.line("[pytest] ini-options in the next "
7675
"pytest.ini|tox.ini|setup.cfg file:")
7776
tw.line()

doc/en/customize.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Here is the algorithm which finds the rootdir from ``args``:
5050

5151
Note that an existing ``pytest.ini`` file will always be considered a match,
5252
whereas ``tox.ini`` and ``setup.cfg`` will only match if they contain a
53-
``[pytest]`` section. Options from multiple ini-files candidates are never
53+
``[pytest]`` or ``[tool:pytest]`` section, respectively. Options from multiple ini-files candidates are never
5454
merged - the first one wins (``pytest.ini`` always wins, even if it does not
5555
contain a ``[pytest]`` section).
5656

@@ -73,7 +73,7 @@ check for ini-files as follows::
7373

7474
# first look for pytest.ini files
7575
path/pytest.ini
76-
path/setup.cfg # must also contain [pytest] section to match
76+
path/setup.cfg # must also contain [tool:pytest] section to match
7777
path/tox.ini # must also contain [pytest] section to match
7878
pytest.ini
7979
... # all the way down to the root
@@ -154,7 +154,7 @@ Builtin configuration file options
154154

155155
.. code-block:: ini
156156
157-
# content of setup.cfg
157+
# content of pytest.ini
158158
[pytest]
159159
norecursedirs = .svn _build tmp*
160160

doc/en/example/pythoncollection.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ Example::
7777
Changing directory recursion
7878
-----------------------------------------------------
7979

80-
You can set the :confval:`norecursedirs` option in an ini-file, for example your ``setup.cfg`` in the project root directory::
80+
You can set the :confval:`norecursedirs` option in an ini-file, for example your ``pytest.ini`` in the project root directory::
8181

82-
# content of setup.cfg
82+
# content of pytest.ini
8383
[pytest]
8484
norecursedirs = .svn _build tmp*
8585

@@ -94,8 +94,9 @@ You can configure different naming conventions by setting
9494
the :confval:`python_files`, :confval:`python_classes` and
9595
:confval:`python_functions` configuration options. Example::
9696

97-
# content of setup.cfg
98-
# can also be defined in in tox.ini or pytest.ini file
97+
# content of pytest.ini
98+
# can also be defined in in tox.ini or setup.cfg file, although the section
99+
# name in setup.cfg files should be "tool:pytest"
99100
[pytest]
100101
python_files=check_*.py
101102
python_classes=Check

doc/en/goodpractices.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,24 @@ required for calling the test command. You can also pass additional
196196
arguments to pytest such as your test directory or other
197197
options using ``--addopts``.
198198

199+
You can also specify other pytest-ini options in your ``setup.cfg`` file
200+
by putting them into a ``[tool:pytest]`` section:
201+
202+
.. code-block:: ini
203+
204+
[tool:pytest]
205+
addopts = --verbose
206+
python_files = testing/*/*.py
207+
208+
209+
.. note::
210+
Prior to 3.0, the supported section name was ``[pytest]``. Due to how
211+
this may collide with some distutils commands, the recommended
212+
section name for ``setup.cfg`` files is now ``[tool:pytest]``.
213+
214+
Note that for ``pytest.ini`` and ``tox.ini`` files the section
215+
name is ``[pytest]``.
216+
199217

200218
Manual Integration
201219
^^^^^^^^^^^^^^^^^^

doc/en/xdist.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ and ``pytest`` will run your tests. Assuming you have failures it will then
9090
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
9191
can change it in your project by setting a configuration option::
9292

93-
# content of a pytest.ini, setup.cfg or tox.ini file
93+
# content of a pytest.ini or tox.ini file
9494
[pytest]
9595
looponfailroots = mypkg testdir
9696

@@ -181,7 +181,7 @@ to run tests in each of the environments.
181181
Specifying "rsync" dirs in an ini-file
182182
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
183183

184-
In a ``tox.ini`` or ``setup.cfg`` file in your root project directory
184+
In a ``pytest.ini`` or ``tox.ini`` file in your root project directory
185185
you may specify directories to include or to exclude in synchronisation::
186186

187187
[pytest]

testing/deprecated_test.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ def test_funcarg_prefix(value):
3434
])
3535

3636

37+
def test_pytest_setup_cfg_deprecated(testdir):
38+
testdir.makefile('.cfg', setup='''
39+
[pytest]
40+
addopts = --verbose
41+
''')
42+
result = testdir.runpytest()
43+
result.stdout.fnmatch_lines(['*pytest*section in setup.cfg files is deprecated*use*tool:pytest*instead*'])
44+
45+
3746
def test_str_args_deprecated(tmpdir, testdir):
3847
"""Deprecate passing strings to pytest.main(). Scheduled for removal in pytest-4.0."""
3948
from _pytest.main import EXIT_NOTESTSCOLLECTED

testing/test_config.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,28 @@
55
from _pytest.main import EXIT_NOTESTSCOLLECTED
66

77
class TestParseIni:
8-
def test_getcfg_and_config(self, testdir, tmpdir):
8+
9+
@pytest.mark.parametrize('section, filename',
10+
[('pytest', 'pytest.ini'), ('tool:pytest', 'setup.cfg')])
11+
def test_getcfg_and_config(self, testdir, tmpdir, section, filename):
912
sub = tmpdir.mkdir("sub")
1013
sub.chdir()
11-
tmpdir.join("setup.cfg").write(_pytest._code.Source("""
12-
[pytest]
14+
tmpdir.join(filename).write(_pytest._code.Source("""
15+
[{section}]
1316
name = value
14-
"""))
15-
rootdir, inifile, cfg = getcfg([sub], ["setup.cfg"])
17+
""".format(section=section)))
18+
rootdir, inifile, cfg = getcfg([sub])
1619
assert cfg['name'] == "value"
1720
config = testdir.parseconfigure(sub)
1821
assert config.inicfg['name'] == 'value'
1922

20-
def test_getcfg_empty_path(self, tmpdir):
21-
getcfg([''], ['setup.cfg']) #happens on pytest ""
23+
def test_getcfg_empty_path(self):
24+
"""correctly handle zero length arguments (a la pytest '')"""
25+
getcfg([''])
2226

2327
def test_append_parse_args(self, testdir, tmpdir, monkeypatch):
2428
monkeypatch.setenv('PYTEST_ADDOPTS', '--color no -rs --tb="short"')
25-
tmpdir.join("setup.cfg").write(_pytest._code.Source("""
29+
tmpdir.join("pytest.ini").write(_pytest._code.Source("""
2630
[pytest]
2731
addopts = --verbose
2832
"""))
@@ -31,10 +35,6 @@ def test_append_parse_args(self, testdir, tmpdir, monkeypatch):
3135
assert config.option.reportchars == 's'
3236
assert config.option.tbstyle == 'short'
3337
assert config.option.verbose
34-
#config = testdir.Config()
35-
#args = [tmpdir,]
36-
#config._preparse(args, addopts=False)
37-
#assert len(args) == 1
3838

3939
def test_tox_ini_wrong_version(self, testdir):
4040
testdir.makefile('.ini', tox="""
@@ -47,12 +47,16 @@ def test_tox_ini_wrong_version(self, testdir):
4747
"*tox.ini:2*requires*9.0*actual*"
4848
])
4949

50-
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
51-
def test_ini_names(self, testdir, name):
50+
@pytest.mark.parametrize("section, name", [
51+
('tool:pytest', 'setup.cfg'),
52+
('pytest', 'tox.ini'),
53+
('pytest', 'pytest.ini')],
54+
)
55+
def test_ini_names(self, testdir, name, section):
5256
testdir.tmpdir.join(name).write(py.std.textwrap.dedent("""
53-
[pytest]
57+
[{section}]
5458
minversion = 1.0
55-
"""))
59+
""".format(section=section)))
5660
config = testdir.parseconfig()
5761
assert config.getini("minversion") == "1.0"
5862

0 commit comments

Comments
 (0)