diff options
author | Ondřej Čertík <ondrej.certik@gmail.com> | 2013-03-24 09:45:29 -0700 |
---|---|---|
committer | Ondřej Čertík <ondrej.certik@gmail.com> | 2013-03-24 09:45:29 -0700 |
commit | c96c69bf2c133c9c68480e3cb532693fb942c051 (patch) | |
tree | 989e00edee5034842ab80788d872ae6bab62b3ad /numpy | |
parent | bd7104cef45be9a4250cb67af9225c9606498a51 (diff) | |
parent | 5099683c351929e938985fd770b0a03cf7285ecb (diff) | |
download | numpy-c96c69bf2c133c9c68480e3cb532693fb942c051.tar.gz |
Merge pull request #3128 from certik/pull-request-3127
BUG: fix issue with distutils.exec_command introduced in 1.7.0.
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/distutils/exec_command.py | 51 | ||||
-rw-r--r-- | numpy/distutils/tests/test_exec_command.py | 81 |
2 files changed, 118 insertions, 14 deletions
diff --git a/numpy/distutils/exec_command.py b/numpy/distutils/exec_command.py index f05b56429..a469fc5e0 100644 --- a/numpy/distutils/exec_command.py +++ b/numpy/distutils/exec_command.py @@ -141,6 +141,19 @@ def _update_environment( **env ): for name,value in env.items(): os.environ[name] = value or '' +def _supports_fileno(stream): + """ + Returns True if 'stream' supports the file descriptor and allows fileno(). + """ + if hasattr(stream, 'fileno'): + try: + r = stream.fileno() + return True + except IOError: + return False + else: + return False + def exec_command( command, execute_in='', use_shell=None, use_tee = None, _with_python = 1, @@ -195,7 +208,8 @@ def exec_command( command, # _exec_command_posix uses os.system and is faster # but not on all platforms os.system will return # a correct status. - if _with_python and sys.stdout.fileno() == -1: + if (_with_python and _supports_fileno(sys.stdout) and + sys.stdout.fileno() == -1): st = _exec_command_python(command, exec_command_dir = exec_dir, **env) @@ -349,12 +363,16 @@ def _exec_command( command, use_shell=None, use_tee = None, **env ): argv = [os.environ['COMSPEC'],'/C'] + argv using_command = 1 - so_fileno = sys.stdout.fileno() - se_fileno = sys.stderr.fileno() + _so_has_fileno = _supports_fileno(sys.stdout) + _se_has_fileno = _supports_fileno(sys.stderr) so_flush = sys.stdout.flush se_flush = sys.stderr.flush - so_dup = os.dup(so_fileno) - se_dup = os.dup(se_fileno) + if _so_has_fileno: + so_fileno = sys.stdout.fileno() + so_dup = os.dup(so_fileno) + if _se_has_fileno: + se_fileno = sys.stderr.fileno() + se_dup = os.dup(se_fileno) outfile = temp_file_name() fout = open(outfile,'w') @@ -371,13 +389,16 @@ def _exec_command( command, use_shell=None, use_tee = None, **env ): so_flush() se_flush() - os.dup2(fout.fileno(),so_fileno) - if using_command: - #XXX: disabled for now as it does not work from cmd under win32. - # Tests fail on msys - os.dup2(ferr.fileno(),se_fileno) - else: - os.dup2(fout.fileno(),se_fileno) + if _so_has_fileno: + os.dup2(fout.fileno(),so_fileno) + + if _se_has_fileno: + if using_command: + #XXX: disabled for now as it does not work from cmd under win32. + # Tests fail on msys + os.dup2(ferr.fileno(),se_fileno) + else: + os.dup2(fout.fileno(),se_fileno) try: status = spawn_command(os.P_WAIT,argv0,argv,os.environ) except OSError: @@ -387,8 +408,10 @@ def _exec_command( command, use_shell=None, use_tee = None, **env ): so_flush() se_flush() - os.dup2(so_dup,so_fileno) - os.dup2(se_dup,se_fileno) + if _so_has_fileno: + os.dup2(so_dup,so_fileno) + if _se_has_fileno: + os.dup2(se_dup,se_fileno) fout.close() fout = open_latin1(outfile,'r') diff --git a/numpy/distutils/tests/test_exec_command.py b/numpy/distutils/tests/test_exec_command.py new file mode 100644 index 000000000..d23a4485a --- /dev/null +++ b/numpy/distutils/tests/test_exec_command.py @@ -0,0 +1,81 @@ +import os +import sys +import StringIO +from tempfile import TemporaryFile + +from numpy.distutils import exec_command + + +class redirect_stdout(object): + """Context manager to redirect stdout for exec_command test.""" + def __init__(self, stdout=None): + self._stdout = stdout or sys.stdout + + def __enter__(self): + self.old_stdout = sys.stdout + sys.stdout = self._stdout + + def __exit__(self, exc_type, exc_value, traceback): + self._stdout.flush() + sys.stdout = self.old_stdout + +class redirect_stderr(object): + """Context manager to redirect stderr for exec_command test.""" + def __init__(self, stderr=None): + self._stderr = stderr or sys.stderr + + def __enter__(self): + self.old_stderr = sys.stderr + sys.stderr = self._stderr + + def __exit__(self, exc_type, exc_value, traceback): + self._stderr.flush() + sys.stderr = self.old_stderr + +class emulate_nonposix(object): + """Context manager to emulate os.name != 'posix' """ + def __init__(self, osname='non-posix'): + self._new_name = osname + + def __enter__(self): + self._old_name = os.name + os.name = self._new_name + + def __exit__(self, exc_type, exc_value, traceback): + os.name = self._old_name + + +def test_exec_command_stdout(): + # Regression test for gh-2999 and gh-2915. + # There are several packages (nose, scipy.weave.inline, Sage inline + # Fortran) that replace stdout, in which case it doesn't have a fileno + # method. This is tested here, with a do-nothing command that fails if the + # presence of fileno() is assumed in exec_command. + + # The code has a special case for posix systems, so if we are on posix test + # both that the special case works and that the generic code works. + + # Test posix version: + with redirect_stdout(StringIO.StringIO()): + with redirect_stderr(TemporaryFile()): + exec_command.exec_command("cd '.'") + + if os.name == 'posix': + # Test general (non-posix) version: + with emulate_nonposix(): + with redirect_stdout(StringIO.StringIO()): + with redirect_stderr(TemporaryFile()): + exec_command.exec_command("cd '.'") + +def test_exec_command_stderr(): + # Test posix version: + with redirect_stdout(TemporaryFile()): + with redirect_stderr(StringIO.StringIO()): + exec_command.exec_command("cd '.'") + + if os.name == 'posix': + # Test general (non-posix) version: + with emulate_nonposix(): + with redirect_stdout(TemporaryFile()): + with redirect_stderr(StringIO.StringIO()): + exec_command.exec_command("cd '.'") |