Permalink
Browse files

use Popen instead of getstatusoutput to check for libedit.

getstatusoutput uses os.popen, and is vulnerable to EINTR weirdness
in environments such as gdb or PyQt.

Exponential falloff is also used, to prevent waiting forever or firing requests too fast, though I haven't had it fire more than once
after moving to Popen.

closes gh-473
  • Loading branch information...
1 parent a353a81 commit cf26ce8a85bfacfdb42e608940e996db2725116e @minrk committed May 27, 2011
Showing with 23 additions and 14 deletions.
  1. +23 −14 IPython/utils/rlineimpl.py
View
@@ -9,9 +9,13 @@
boolean and _outputfile variable used in IPython.utils.
"""
+import re
import sys
+import time
import warnings
+from subprocess import Popen, PIPE
+
try:
from readline import *
import readline as _rl
@@ -44,24 +48,29 @@ def add_history(line):
have_readline = False
# Test to see if libedit is being used instead of GNU readline.
-# Thanks to Boyd Waters for this patch.
+# Thanks to Boyd Waters for the original patch.
uses_libedit = False
if sys.platform == 'darwin' and have_readline:
- import commands
- # Boyd's patch had a 'while True' here, I'm always a little worried about
- # infinite loops with such code, so for now I'm taking a more conservative
- # approach. See https://bugs.launchpad.net/ipython/+bug/411599.
- for i in range(10):
- try:
- (status, result) = commands.getstatusoutput( "otool -L %s | grep libedit" % _rl.__file__ )
+ # Previously this used commands.getstatusoutput, which uses os.popen.
+ # Switching to subprocess.Popen, and exponential falloff for EINTR
+ # seems to make this better behaved in environments such as PyQt and gdb
+ dt = 1e-3
+ while dt < 1:
+ p = Popen(['otool', '-L', _rl.__file__], stdout=PIPE, stderr=PIPE)
+ otool,err = p.communicate()
+
+ if p.returncode == 4:
+ # EINTR
+ time.sleep(dt)
+ dt *= 2
+ continue
+ elif p.returncode:
+ warnings.warn("libedit detection failed: %s"%err)
+ break
+ else:
break
- except IOError, (errno, strerror):
- if errno == 4:
- continue
- else:
- break
- if status == 0 and len(result) > 0:
+ if p.returncode == 0 and re.search(r'/libedit[\.\d+]*\.dylib\s', otool):
# we are bound to libedit - new in Leopard
_rl.parse_and_bind("bind ^I rl_complete")
warnings.warn("Leopard libedit detected - readline will not be well behaved "

0 comments on commit cf26ce8

Please sign in to comment.