Backward-compatible Port to Python 3

- Keeps Python 2.7 and 2.6 compatibility
  - Is not compatible with Python 2.5, as the original code never was.
    This is due to two problems:
     1. Use of the `Thread.is_alive()` method. Python 2.5 only
        provides `Thread.isAlive()`.
     2. Use of the `Popen.terminate()` and `Popen.kill()` methods,
        which only exist in Python >= 2.6
This commit is contained in:
Brice Fernandes
2012-06-07 16:30:41 +01:00
parent 160816428e
commit d9b70c8a9b
4 changed files with 41 additions and 35 deletions
+2 -2
View File
@@ -1,3 +1,3 @@
from core import *
from .core import *
from core import __version__
from .core import __version__
+10 -4
View File
@@ -8,6 +8,7 @@ This module provides envoy awesomeness.
"""
import os
import sys
import shlex
import subprocess
import threading
@@ -43,8 +44,13 @@ class Command(object):
stderr=subprocess.PIPE,
bufsize=0,
)
self.out, self.err = self.process.communicate(self.data)
if sys.version_info[0] >= 3:
self.out, self.err = self.process.communicate(
input = bytes(self.data, "UTF-8") if self.data else None
)
else:
self.out, self.err = self.process.communicate(self.data)
thread = threading.Thread(target=target)
thread.start()
@@ -139,7 +145,7 @@ def expand_args(command):
"""Parses command strings and returns a Popen-ready list."""
# Prepare arguments.
if isinstance(command, basestring):
if isinstance(command, str):
splitter = shlex.shlex(command)
splitter.whitespace = '|'
splitter.whitespace_split = True
@@ -152,7 +158,7 @@ def expand_args(command):
else:
break
command = map(shlex.split, command)
command = list(map(shlex.split, command))
return command
+26 -26
View File
@@ -80,7 +80,7 @@ try:
import errno
import traceback
import signal
except ImportError, e:
except ImportError as e:
raise ImportError (str(e) + """
A critical module was not found. Probably this operating system does not
@@ -217,8 +217,8 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
else:
child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile, cwd=cwd, env=env)
if events is not None:
patterns = events.keys()
responses = events.values()
patterns = list(events.keys())
responses = list(events.values())
else:
patterns=None # We assume that EOF or TIMEOUT will save us.
responses=None
@@ -227,16 +227,16 @@ def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None
while 1:
try:
index = child.expect (patterns)
if type(child.after) in types.StringTypes:
if type(child.after) in str:
child_result_list.append(child.before + child.after)
else: # child.after may have been a TIMEOUT or EOF, so don't cat those.
child_result_list.append(child.before)
if type(responses[index]) in types.StringTypes:
if type(responses[index]) in str:
child.send(responses[index])
elif type(responses[index]) is types.FunctionType:
callback_result = responses[index](locals())
sys.stdout.flush()
if type(callback_result) in types.StringTypes:
if type(callback_result) in str:
child.send(callback_result)
elif callback_result:
break
@@ -519,7 +519,7 @@ class spawn (object):
if self.use_native_pty_fork:
try:
self.pid, self.child_fd = pty.fork()
except OSError, e:
except OSError as e:
raise ExceptionPexpect('Error! pty.fork() failed: ' + str(e))
else: # Use internal __fork_pty
self.pid, self.child_fd = self.__fork_pty()
@@ -574,11 +574,11 @@ class spawn (object):
parent_fd, child_fd = os.openpty()
if parent_fd < 0 or child_fd < 0:
raise ExceptionPexpect, "Error! Could not open pty with os.openpty()."
raise ExceptionPexpect("Error! Could not open pty with os.openpty().")
pid = os.fork()
if pid < 0:
raise ExceptionPexpect, "Error! Failed os.fork()."
raise ExceptionPexpect("Error! Failed os.fork().")
elif pid == 0:
# Child.
os.close(parent_fd)
@@ -615,7 +615,7 @@ class spawn (object):
fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY);
if fd >= 0:
os.close(fd)
raise ExceptionPexpect, "Error! We are not disconnected from a controlling tty."
raise ExceptionPexpect("Error! We are not disconnected from a controlling tty.")
except:
# Good! We are disconnected from a controlling tty.
pass
@@ -623,14 +623,14 @@ class spawn (object):
# Verify we can open child pty.
fd = os.open(child_name, os.O_RDWR);
if fd < 0:
raise ExceptionPexpect, "Error! Could not open child pty, " + child_name
raise ExceptionPexpect("Error! Could not open child pty, " + child_name)
else:
os.close(fd)
# Verify we now have a controlling tty.
fd = os.open("/dev/tty", os.O_WRONLY)
if fd < 0:
raise ExceptionPexpect, "Error! Could not open controlling tty, /dev/tty"
raise ExceptionPexpect("Error! Could not open controlling tty, /dev/tty")
else:
os.close(fd)
@@ -878,7 +878,7 @@ class spawn (object):
return self
def next (self): # File-like object.
def __next__ (self): # File-like object.
"""This is to support iterators over a file-like object.
"""
@@ -1098,7 +1098,7 @@ class spawn (object):
try:
pid, status = os.waitpid(self.pid, waitpid_options)
except OSError, e: # No child processes
except OSError as e: # No child processes
if e[0] == errno.ECHILD:
raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?')
else:
@@ -1110,7 +1110,7 @@ class spawn (object):
if pid == 0:
try:
pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris!
except OSError, e: # This should never happen...
except OSError as e: # This should never happen...
if e[0] == errno.ECHILD:
raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?')
else:
@@ -1175,7 +1175,7 @@ class spawn (object):
if patterns is None:
return []
if type(patterns) is not types.ListType:
if type(patterns) is not list:
patterns = [patterns]
compile_flags = re.DOTALL # Allow dot to match \n
@@ -1183,7 +1183,7 @@ class spawn (object):
compile_flags = compile_flags | re.IGNORECASE
compiled_pattern_list = []
for p in patterns:
if type(p) in types.StringTypes:
if type(p) in str:
compiled_pattern_list.append(re.compile(p, compile_flags))
elif p is EOF:
compiled_pattern_list.append(EOF)
@@ -1301,7 +1301,7 @@ class spawn (object):
This method is also useful when you don't want to have to worry about
escaping regular expression characters that you want to match."""
if type(pattern_list) in types.StringTypes or pattern_list in (TIMEOUT, EOF):
if type(pattern_list) in str or pattern_list in (TIMEOUT, EOF):
pattern_list = [pattern_list]
return self.expect_loop(searcher_string(pattern_list), timeout, searchwindowsize)
@@ -1343,7 +1343,7 @@ class spawn (object):
incoming = incoming + c
if timeout is not None:
timeout = end_time - time.time()
except EOF, e:
except EOF as e:
self.buffer = ''
self.before = incoming
self.after = EOF
@@ -1356,7 +1356,7 @@ class spawn (object):
self.match = None
self.match_index = None
raise EOF (str(e) + '\n' + str(self))
except TIMEOUT, e:
except TIMEOUT as e:
self.buffer = incoming
self.before = incoming
self.after = TIMEOUT
@@ -1380,7 +1380,7 @@ class spawn (object):
"""This returns the terminal window size of the child tty. The return
value is a tuple of (rows, cols). """
TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912L)
TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912)
s = struct.pack('HHHH', 0, 0, 0, 0)
x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s)
return struct.unpack('HHHH', x)[0:2]
@@ -1401,7 +1401,7 @@ class spawn (object):
# Newer versions of Linux have totally different values for TIOCSWINSZ.
# Note that this fix is a hack.
TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2.
if TIOCSWINSZ == 2148037735: # L is not required in Python >= 2.2.
TIOCSWINSZ = -2146929561 # Same bits, but with sign.
# Note, assume ws_xpixel and ws_ypixel are zero.
s = struct.pack('HHHH', r, c, 0, 0)
@@ -1502,7 +1502,7 @@ class spawn (object):
while True:
try:
return select.select (iwtd, owtd, ewtd, timeout)
except select.error, e:
except select.error as e:
if e[0] == errno.EINTR:
# if we loop back we have to subtract the amount of time we already waited.
if timeout is not None:
@@ -1554,7 +1554,7 @@ class searcher_string (object):
self.eof_index = -1
self.timeout_index = -1
self._strings = []
for n, s in zip(range(len(strings)), strings):
for n, s in zip(list(range(len(strings))), strings):
if s is EOF:
self.eof_index = n
continue
@@ -1648,7 +1648,7 @@ class searcher_re (object):
self.eof_index = -1
self.timeout_index = -1
self._searches = []
for n, s in zip(range(len(patterns)), patterns):
for n, s in zip(list(range(len(patterns))), patterns):
if s is EOF:
self.eof_index = n
continue
@@ -1715,7 +1715,7 @@ def which(filename):
if os.access (filename, os.X_OK):
return filename
if not os.environ.has_key('PATH') or os.environ['PATH'] == '':
if 'PATH' not in os.environ or os.environ['PATH'] == '':
p = os.defpath
else:
p = os.environ['PATH']
+3 -3
View File
@@ -35,10 +35,10 @@ setup(
'Natural Language :: English',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.5',
# 'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
# 'Programming Language :: Python :: 3.0',
# 'Programming Language :: Python :: 3.1',
'Programming Language :: Python :: 3.0',
'Programming Language :: Python :: 3.1',
),
)