Fix -o behavior to no longer swallow all remaining options
The current behavior was too error-prone because a "-o" option would swallow all the following non-option parameters: pytest -o foo=bar path/to/test.py path/to/test.py would be captured by the -o option, and would fail because "path/to/test.py" is not in the format "key=value".
This commit is contained in:
parent
443275f025
commit
3f5e9ea71e
|
@ -1188,19 +1188,15 @@ class Config(object):
|
|||
|
||||
def _get_override_ini_value(self, name):
|
||||
value = None
|
||||
# override_ini is a list of list, to support both -o foo1=bar1 foo2=bar2 and
|
||||
# and -o foo1=bar1 -o foo2=bar2 options
|
||||
# always use the last item if multiple value set for same ini-name,
|
||||
# override_ini is a list of "ini=value" options
|
||||
# always use the last item if multiple values are set for same ini-name,
|
||||
# e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2
|
||||
first_override_set = False
|
||||
for ini_config_list in self._override_ini:
|
||||
for ini_config in ini_config_list:
|
||||
try:
|
||||
(key, user_ini_value) = ini_config.split("=", 1)
|
||||
first_override_set = True
|
||||
except ValueError:
|
||||
if not first_override_set:
|
||||
raise UsageError("-o/--override-ini expects option=value style.")
|
||||
for ini_config in self._override_ini:
|
||||
try:
|
||||
key, user_ini_value = ini_config.split("=", 1)
|
||||
except ValueError:
|
||||
raise UsageError("-o/--override-ini expects option=value style.")
|
||||
else:
|
||||
if key == name:
|
||||
value = user_ini_value
|
||||
return value
|
||||
|
|
|
@ -57,9 +57,9 @@ def pytest_addoption(parser):
|
|||
action="store_true", dest="debug", default=False,
|
||||
help="store internal tracing debug information in 'pytestdebug.log'.")
|
||||
group._addoption(
|
||||
'-o', '--override-ini', nargs='*', dest="override_ini",
|
||||
'-o', '--override-ini', dest="override_ini",
|
||||
action="append",
|
||||
help="override config option with option=value style, e.g. `-o xfail_strict=True`.")
|
||||
help='override ini option with "option=value" style, e.g. `-o xfail_strict=True -o cache_dir=cache`.')
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Fix ``UsageError`` being raised when specifying ``-o/--override`` command-line option followed by a test path.
|
||||
**Incompatible change**: ``-o/--override`` option no longer eats all the remaining options, which can lead to surprising behavior: for example, ``pytest -o foo=1 /path/to/test.py`` would fail because ``/path/to/test.py`` would be considered as part of the ``-o`` command-line argument. One consequence of this is that now multiple configuration overrides need multiple ``-o`` flags: ``pytest -o foo=1 -o bar=2``.
|
||||
|
|
|
@ -152,11 +152,25 @@ above will show verbose output because ``-v`` overwrites ``-q``.
|
|||
Builtin configuration file options
|
||||
----------------------------------------------
|
||||
|
||||
Here is a list of builtin configuration options that may be written in a ``pytest.ini``, ``tox.ini`` or ``setup.cfg``
|
||||
file, usually located at the root of your repository. All options must be under a ``[pytest]`` section
|
||||
(``[tool:pytest]`` for ``setup.cfg`` files).
|
||||
|
||||
Configuration file options may be overwritten in the command-line by using ``-o/--override``, which can also be
|
||||
passed multiple times. The expected format is ``name=value``. For example::
|
||||
|
||||
pytest -o console_output_style=classic -o cache_dir=/tmp/mycache
|
||||
|
||||
|
||||
.. confval:: minversion
|
||||
|
||||
Specifies a minimal pytest version required for running tests.
|
||||
|
||||
minversion = 2.1 # will fail if we run with pytest-2.0
|
||||
.. code-block:: ini
|
||||
|
||||
# content of pytest.ini
|
||||
[pytest]
|
||||
minversion = 3.0 # will fail if we run with pytest-2.8
|
||||
|
||||
.. confval:: addopts
|
||||
|
||||
|
@ -165,6 +179,7 @@ Builtin configuration file options
|
|||
|
||||
.. code-block:: ini
|
||||
|
||||
# content of pytest.ini
|
||||
[pytest]
|
||||
addopts = --maxfail=2 -rf # exit after 2 failures, report fail info
|
||||
|
||||
|
|
|
@ -781,16 +781,18 @@ class TestOverrideIniArgs(object):
|
|||
testdir.makeini("""
|
||||
[pytest]
|
||||
custom_option_1=custom_option_1
|
||||
custom_option_2=custom_option_2""")
|
||||
custom_option_2=custom_option_2
|
||||
""")
|
||||
testdir.makepyfile("""
|
||||
def test_multiple_options(pytestconfig):
|
||||
prefix = "custom_option"
|
||||
for x in range(1, 5):
|
||||
ini_value=pytestconfig.getini("%s_%d" % (prefix, x))
|
||||
print('\\nini%d:%s' % (x, ini_value))""")
|
||||
print('\\nini%d:%s' % (x, ini_value))
|
||||
""")
|
||||
result = testdir.runpytest(
|
||||
"--override-ini", 'custom_option_1=fulldir=/tmp/user1',
|
||||
'custom_option_2=url=/tmp/user2?a=b&d=e',
|
||||
'-o', 'custom_option_2=url=/tmp/user2?a=b&d=e',
|
||||
"-o", 'custom_option_3=True',
|
||||
"-o", 'custom_option_4=no', "-s")
|
||||
result.stdout.fnmatch_lines(["ini1:fulldir=/tmp/user1",
|
||||
|
@ -853,24 +855,42 @@ class TestOverrideIniArgs(object):
|
|||
assert rootdir == tmpdir
|
||||
assert inifile is None
|
||||
|
||||
def test_addopts_before_initini(self, testdir, tmpdir, monkeypatch):
|
||||
def test_addopts_before_initini(self, monkeypatch):
|
||||
cache_dir = '.custom_cache'
|
||||
monkeypatch.setenv('PYTEST_ADDOPTS', '-o cache_dir=%s' % cache_dir)
|
||||
from _pytest.config import get_config
|
||||
config = get_config()
|
||||
config._preparse([], addopts=True)
|
||||
assert config._override_ini == [['cache_dir=%s' % cache_dir]]
|
||||
assert config._override_ini == ['cache_dir=%s' % cache_dir]
|
||||
|
||||
def test_no_error_if_true_first_key_value_pair(self, testdir, request):
|
||||
def test_override_ini_does_not_contain_paths(self):
|
||||
"""Check that -o no longer swallows all options after it (#3103)"""
|
||||
from _pytest.config import get_config
|
||||
config = get_config()
|
||||
config._preparse(['-o', 'cache_dir=/cache', '/some/test/path'])
|
||||
assert config._override_ini == ['cache_dir=/cache']
|
||||
|
||||
def test_multiple_override_ini_options(self, testdir, request):
|
||||
"""Ensure a file path following a '-o' option does not generate an error (#3103)"""
|
||||
testdir.makeini("""
|
||||
[pytest]
|
||||
xdist_strict=False
|
||||
""")
|
||||
testdir.makepyfile("""
|
||||
def test():
|
||||
pass
|
||||
""")
|
||||
result = testdir.runpytest('--override-ini', 'xdist_strict=True', '{}.py'.format(request.node.name))
|
||||
testdir.makepyfile(**{
|
||||
"conftest.py": """
|
||||
def pytest_addoption(parser):
|
||||
parser.addini('foo', default=None, help='some option')
|
||||
parser.addini('bar', default=None, help='some option')
|
||||
""",
|
||||
"test_foo.py": """
|
||||
def test(pytestconfig):
|
||||
assert pytestconfig.getini('foo') == '1'
|
||||
assert pytestconfig.getini('bar') == '0'
|
||||
""",
|
||||
"test_bar.py": """
|
||||
def test():
|
||||
assert False
|
||||
""",
|
||||
})
|
||||
result = testdir.runpytest('-o', 'foo=1', '-o', 'bar=0', 'test_foo.py')
|
||||
assert 'ERROR:' not in result.stderr.str()
|
||||
result.stdout.fnmatch_lines('* 1 passed in *')
|
||||
result.stdout.fnmatch_lines([
|
||||
'collected 1 item',
|
||||
'*= 1 passed in *=',
|
||||
])
|
||||
|
|
Loading…
Reference in New Issue