From 9c48bb792b3f81678105f1db2d9167dc49b5e274 Mon Sep 17 00:00:00 2001 From: Ted Xiao Date: Sat, 25 Jun 2016 22:12:42 +0800 Subject: [PATCH] add --override-ini option to overrides ini values Signed-off-by: Ted Xiao --- AUTHORS | 1 + CHANGELOG.rst | 5 +++ _pytest/config.py | 32 +++++++++++---- _pytest/helpconfig.py | 4 ++ testing/test_config.py | 90 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index ac8caf905fd..e72f965e31f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -98,6 +98,7 @@ Ryan Wooden Samuele Pedroni Stephan Obermann Tareq Alayan +Ted Xiao Simon Gomizelj Stefano Taschini Stefan Farmbauer diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d95d66384ed..e42ee6e7768 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -47,6 +47,11 @@ `#1629`_. Thanks `@obestwalter`_ and `@davehunt`_ for the complete PR (`#1633`_) +* New cli flag ``--override-ini`` or ``-o`` that overrides values from the ini file. + Example '-o xfail_strict=True'. A complete ini-options can be viewed + by py.test --help. Thanks `@blueyed`_ and `@fengxx`_ for the PR + + **Changes** * Fixtures marked with ``@pytest.fixture`` can now use ``yield`` statements exactly like diff --git a/_pytest/config.py b/_pytest/config.py index a17587d9ec3..b7fdb457f67 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -1003,14 +1003,16 @@ def _getini(self, name): description, type, default = self._parser._inidict[name] except KeyError: raise ValueError("unknown configuration value: %r" %(name,)) - try: - value = self.inicfg[name] - except KeyError: - if default is not None: - return default - if type is None: - return '' - return [] + value = self._get_override_ini_value(name) + if value is None: + try: + value = self.inicfg[name] + except KeyError: + if default is not None: + return default + if type is None: + return '' + return [] if type == "pathlist": dp = py.path.local(self.inicfg.config.path).dirpath() l = [] @@ -1041,6 +1043,20 @@ def _getconftest_pathlist(self, name, path): l.append(relroot) return l + 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, + # e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2 + if self.getoption("override_ini", None): + for ini_config_list in self.option.override_ini: + for ini_config in ini_config_list: + (key, user_ini_value) = ini_config.split("=", 1) + if key == name: + value = user_ini_value + return value + def getoption(self, name, default=notset, skip=False): """ return command line option value. diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py index 15b0ada77c6..ae8daea9c6e 100644 --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -20,6 +20,10 @@ def pytest_addoption(parser): group.addoption('--debug', action="store_true", dest="debug", default=False, help="store internal tracing debug information in 'pytestdebug.log'.") + # support for "--overwrite-ini ININAME=INIVALUE" to override values from the ini file + # Example '-o xfail_strict=True'. + group._addoption('-o', '--override-ini', nargs='*', dest="override_ini", action="append", + help="overrides ini values which do not have a separate command-line flag") @pytest.hookimpl(hookwrapper=True) diff --git a/testing/test_config.py b/testing/test_config.py index 2d9ae6e0e5e..24ae546483f 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -583,3 +583,93 @@ def test_with_specific_inifile(self, tmpdir): inifile = tmpdir.ensure("pytest.ini") rootdir, inifile, inicfg = determine_setup(inifile, [tmpdir]) assert rootdir == tmpdir + +class TestOverrideIniArgs: + """ test --override-ini """ + @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) + def test_override_ini_names(self, testdir, name): + testdir.tmpdir.join(name).write(py.std.textwrap.dedent(""" + [pytest] + custom = 1.0 + """)) + testdir.makeconftest(""" + def pytest_addoption(parser): + parser.addini("custom", "") + """) + testdir.makepyfile(""" + def test_pass(pytestconfig): + ini_val = pytestconfig.getini("custom") + print('\\ncustom_option:%s\\n' % ini_val) + """) + + result = testdir.runpytest("--override-ini", "custom=2.0", "-s") + assert result.ret == 0 + result.stdout.fnmatch_lines([ + "custom_option:2.0" + ]) + + result = testdir.runpytest("--override-ini", "custom=2.0", + "--override-ini=custom=3.0", "-s") + assert result.ret == 0 + result.stdout.fnmatch_lines([ + "custom_option:3.0" + ]) + + + def test_override_ini_pathlist(self, testdir): + testdir.makeconftest(""" + def pytest_addoption(parser): + parser.addini("paths", "my new ini value", type="pathlist") + """) + testdir.makeini(""" + [pytest] + paths=blah.py + """) + testdir.makepyfile(""" + import py.path + def test_pathlist(pytestconfig): + config_paths = pytestconfig.getini("paths") + print(config_paths) + for cpf in config_paths: + print('\\nuser_path:%s' % cpf.basename) + """) + result = testdir.runpytest("--override-ini", 'paths=foo/bar1.py foo/bar2.py', "-s") + result.stdout.fnmatch_lines([ + "user_path:bar1.py", + "user_path:bar2.py" + ]) + + def test_override_multiple_and_default(self, testdir): + testdir.makeconftest(""" + def pytest_addoption(parser): + parser.addini("custom_option_1", "", default="o1") + parser.addini("custom_option_2", "", default="o2") + parser.addini("custom_option_3", "", default=False, type="bool") + parser.addini("custom_option_4", "", default=True, type="bool") + + """) + testdir.makeini(""" + [pytest] + custom_option_1=custom_option_1 + 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)) + """) + result = testdir.runpytest("--override-ini", + 'custom_option_1=fulldir=/tmp/user1', + 'custom_option_2=url=/tmp/user2?a=b&d=e', + "-o", 'custom_option_3=True', + "-o", 'custom_option_4=no', + "-s") + print result.stderr + result.stdout.fnmatch_lines([ + "ini1:fulldir=/tmp/user1", + "ini2:url=/tmp/user2?a=b&d=e", + "ini3:True", + "ini4:False" + ]) \ No newline at end of file