diff --git a/subprocess2.py b/subprocess2.py index dea1a2d6c..9ae485d2e 100644 --- a/subprocess2.py +++ b/subprocess2.py @@ -121,6 +121,17 @@ class Popen(subprocess.Popen): env = get_english_env(kwargs.get('env')) if env: kwargs['env'] = env + if kwargs.get('env') is not None and sys.version_info.major != 2: + # Subprocess expects environment variables to be strings in Python 3. + def ensure_str(value): + if isinstance(value, bytes): + return value.decode() + return value + + kwargs['env'] = { + ensure_str(k): ensure_str(v) + for k, v in kwargs['env'].items() + } if kwargs.get('shell') is None: # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for # the executable, but shell=True makes subprocess on Linux fail when it's diff --git a/tests/subprocess2_test.py b/tests/subprocess2_test.py index 3a83ebaed..4028b866a 100755 --- a/tests/subprocess2_test.py +++ b/tests/subprocess2_test.py @@ -81,6 +81,14 @@ class DefaultsTest(unittest.TestCase): mockCommunicate.assert_called_with( ['foo'], a=True, stdin=subprocess2.VOID_INPUT, stdout=subprocess2.PIPE) + @mock.patch('subprocess.Popen.__init__') + def test_env_type(self, mockPopen): + if sys.version_info.major != 2: + subprocess2.Popen(['foo'], env={b'key': b'value'}) + mockPopen.assert_called_with(['foo'], + env={'key': 'value'}, + shell=mock.ANY) + def _run_test(with_subprocess=True): """Runs a tests in 12 combinations: