Skip to content

Commit a664fb2

Browse files
committed
Ensure Monkeypatch setenv and delenv keep bytes keys in Python 2
Fixes the bug described in: tox-dev/tox#1025 (comment) Which is more evident when using `unicode_literals`.
1 parent b1fbb2a commit a664fb2

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

changelog/4056.bugfix.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Ensure ``MonkeyPatch.setenv`` and ``MonkeyPatch.delenv`` use native strings for environment variable names.
2+
3+
In Python 2, adding ``unicode`` keys to ``os.environ`` causes problems with ``subprocess`` (and possible other modules),
4+
making this a subtle bug specially susceptible when used with ``from __future__ import unicode_literals``.

src/_pytest/monkeypatch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def setenv(self, name, value, prepend=None):
216216
value = str(value)
217217
if prepend and name in os.environ:
218218
value = value + prepend + os.environ[name]
219-
self.setitem(os.environ, name, value)
219+
self.setitem(os.environ, str(name), value)
220220

221221
def delenv(self, name, raising=True):
222222
""" Delete ``name`` from the environment. Raise KeyError if it does
@@ -225,7 +225,7 @@ def delenv(self, name, raising=True):
225225
If ``raising`` is set to False, no exception will be raised if the
226226
environment variable is missing.
227227
"""
228-
self.delitem(os.environ, name, raising=raising)
228+
self.delitem(os.environ, str(name), raising=raising)
229229

230230
def syspath_prepend(self, path):
231231
""" Prepend ``path`` to ``sys.path`` list of import locations. """

testing/test_monkeypatch.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import sys
44
import textwrap
55

6+
import six
7+
68
import pytest
79
from _pytest.monkeypatch import MonkeyPatch
810

@@ -192,6 +194,40 @@ def test_delenv():
192194
del os.environ[name]
193195

194196

197+
@pytest.mark.skipif(six.PY3, reason="python 2 only bug")
198+
class TestPython2BytesEnvironKeys(object):
199+
"""
200+
In Python 2, os.environ keys need to be bytes, otherwise this will cause problems with other modules (notably
201+
subprocess).
202+
"""
203+
204+
VAR_NAME = "PYTEST_INTERNAL_MY_VAR"
205+
206+
@pytest.fixture(autouse=True)
207+
def cleanup(self):
208+
self.check_all_environ_keys_are_bytes()
209+
yield
210+
if self.VAR_NAME in os.environ:
211+
del os.environ[self.VAR_NAME]
212+
213+
def check_all_environ_keys_are_bytes(self):
214+
for k in os.environ:
215+
assert type(k) is bytes
216+
217+
def test_setenv_unicode_key(self):
218+
monkeypatch = MonkeyPatch()
219+
monkeypatch.setenv(unicode(self.VAR_NAME), "2") # noqa
220+
self.check_all_environ_keys_are_bytes()
221+
222+
def test_delenv_unicode_key(self):
223+
os.environ[self.VAR_NAME] = "1"
224+
self.check_all_environ_keys_are_bytes()
225+
monkeypatch = MonkeyPatch()
226+
monkeypatch.delenv(unicode(self.VAR_NAME)) # noqa
227+
monkeypatch.undo()
228+
self.check_all_environ_keys_are_bytes()
229+
230+
195231
def test_setenv_prepend():
196232
import os
197233

0 commit comments

Comments
 (0)