From 1a323fbd3c52db051ae32e2b27275717b891b322 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 1 Oct 2018 18:48:41 -0300 Subject: [PATCH] Show a warning when non-str is given to Monkeypatch.setenv --- src/_pytest/monkeypatch.py | 10 +++++++++- testing/acceptance_test.py | 4 ++-- testing/test_cacheprovider.py | 14 +++++++------- testing/test_junitxml.py | 2 +- testing/test_monkeypatch.py | 27 ++++++++++++++++++++------- 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/_pytest/monkeypatch.py b/src/_pytest/monkeypatch.py index 60feb0802..4bd6b607d 100644 --- a/src/_pytest/monkeypatch.py +++ b/src/_pytest/monkeypatch.py @@ -225,7 +225,15 @@ class MonkeyPatch(object): """ Set environment variable ``name`` to ``value``. If ``prepend`` is a character, read the current environment variable value and prepend the ``value`` adjoined with the ``prepend`` character.""" - value = str(value) + if not isinstance(value, str): + warnings.warn( + pytest.PytestWarning( + "Environment variable value {!r} should be str, converted to str implicitly".format( + value + ) + ) + ) + value = str(value) if prepend and name in os.environ: value = value + prepend + os.environ[name] self._warn_if_env_name_is_not_str(name) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 8a9585be2..332af27b5 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -577,7 +577,7 @@ class TestInvocationVariants(object): return what empty_package = testdir.mkpydir("empty_package") - monkeypatch.setenv("PYTHONPATH", join_pythonpath(empty_package)) + monkeypatch.setenv("PYTHONPATH", str(join_pythonpath(empty_package))) # the path which is not a package raises a warning on pypy; # no idea why only pypy and not normal python warn about it here with warnings.catch_warnings(): @@ -586,7 +586,7 @@ class TestInvocationVariants(object): assert result.ret == 0 result.stdout.fnmatch_lines(["*2 passed*"]) - monkeypatch.setenv("PYTHONPATH", join_pythonpath(testdir)) + monkeypatch.setenv("PYTHONPATH", str(join_pythonpath(testdir))) result = testdir.runpytest("--pyargs", "tpkg.test_missing", syspathinsert=True) assert result.ret != 0 result.stderr.fnmatch_lines(["*not*found*test_missing*"]) diff --git a/testing/test_cacheprovider.py b/testing/test_cacheprovider.py index 5d73dc846..2444d8bc1 100644 --- a/testing/test_cacheprovider.py +++ b/testing/test_cacheprovider.py @@ -215,7 +215,7 @@ def test_cache_show(testdir): class TestLastFailed(object): def test_lastfailed_usecase(self, testdir, monkeypatch): - monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) + monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1") p = testdir.makepyfile( """ def test_1(): @@ -301,7 +301,7 @@ class TestLastFailed(object): assert "test_a.py" not in result.stdout.str() def test_lastfailed_difference_invocations(self, testdir, monkeypatch): - monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) + monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1") testdir.makepyfile( test_a="""\ def test_a1(): @@ -335,7 +335,7 @@ class TestLastFailed(object): result.stdout.fnmatch_lines(["*1 failed*1 desel*"]) def test_lastfailed_usecase_splice(self, testdir, monkeypatch): - monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) + monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1") testdir.makepyfile( """\ def test_1(): @@ -474,8 +474,8 @@ class TestLastFailed(object): ) def rlf(fail_import, fail_run): - monkeypatch.setenv("FAILIMPORT", fail_import) - monkeypatch.setenv("FAILTEST", fail_run) + monkeypatch.setenv("FAILIMPORT", str(fail_import)) + monkeypatch.setenv("FAILTEST", str(fail_run)) testdir.runpytest("-q") config = testdir.parseconfigure() @@ -519,8 +519,8 @@ class TestLastFailed(object): ) def rlf(fail_import, fail_run, args=()): - monkeypatch.setenv("FAILIMPORT", fail_import) - monkeypatch.setenv("FAILTEST", fail_run) + monkeypatch.setenv("FAILIMPORT", str(fail_import)) + monkeypatch.setenv("FAILTEST", str(fail_run)) result = testdir.runpytest("-q", "--lf", *args) config = testdir.parseconfigure() diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 3928548a8..2304c4a50 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -850,7 +850,7 @@ def test_logxml_path_expansion(tmpdir, monkeypatch): assert xml_tilde.logfile == home_tilde # this is here for when $HOME is not set correct - monkeypatch.setenv("HOME", tmpdir) + monkeypatch.setenv("HOME", str(tmpdir)) home_var = os.path.normpath(os.path.expandvars("$HOME/test.xml")) xml_var = LogXML("$HOME%stest.xml" % tmpdir.sep, None) diff --git a/testing/test_monkeypatch.py b/testing/test_monkeypatch.py index f0f63023d..853c0192f 100644 --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -165,7 +165,8 @@ def test_delitem(): def test_setenv(): monkeypatch = MonkeyPatch() - monkeypatch.setenv("XYZ123", 2) + with pytest.warns(pytest.PytestWarning): + monkeypatch.setenv("XYZ123", 2) import os assert os.environ["XYZ123"] == "2" @@ -194,15 +195,16 @@ def test_delenv(): del os.environ[name] -@pytest.mark.skipif(six.PY3, reason="Python 2 only test") -class TestEnvironKeysWarning(object): +class TestEnvironWarnings(object): """ - os.environ needs keys to be native strings, otherwise it will cause problems with other modules (notably - subprocess). We only test this behavior on Python 2, because Python 3 raises an error right away. + os.environ keys and values should be native strings, otherwise it will cause problems with other modules (notably + subprocess). On Python 2 os.environ accepts anything without complaining, while Python 3 does the right thing + and raises an error. """ VAR_NAME = u"PYTEST_INTERNAL_MY_VAR" + @pytest.mark.skipif(six.PY3, reason="Python 2 only test") def test_setenv_unicode_key(self, monkeypatch): with pytest.warns( pytest.PytestWarning, @@ -210,6 +212,7 @@ class TestEnvironKeysWarning(object): ): monkeypatch.setenv(self.VAR_NAME, "2") + @pytest.mark.skipif(six.PY3, reason="Python 2 only test") def test_delenv_unicode_key(self, monkeypatch): with pytest.warns( pytest.PytestWarning, @@ -217,14 +220,24 @@ class TestEnvironKeysWarning(object): ): monkeypatch.delenv(self.VAR_NAME, raising=False) + def test_setenv_non_str_warning(self, monkeypatch): + value = 2 + msg = ( + "Environment variable value {!r} should be str, converted to str implicitly" + ) + with pytest.warns(pytest.PytestWarning, match=msg.format(value)): + monkeypatch.setenv(str(self.VAR_NAME), value) + def test_setenv_prepend(): import os monkeypatch = MonkeyPatch() - monkeypatch.setenv("XYZ123", 2, prepend="-") + with pytest.warns(pytest.PytestWarning): + monkeypatch.setenv("XYZ123", 2, prepend="-") assert os.environ["XYZ123"] == "2" - monkeypatch.setenv("XYZ123", 3, prepend="-") + with pytest.warns(pytest.PytestWarning): + monkeypatch.setenv("XYZ123", 3, prepend="-") assert os.environ["XYZ123"] == "3-2" monkeypatch.undo() assert "XYZ123" not in os.environ