Skip to content
This repository was archived by the owner on Dec 20, 2025. It is now read-only.

Commit e1cafda

Browse files
authored
Merge pull request #1 from HorlogeSkynet/master
Update ptyprocess version to v0.7.0
2 parents 9d95176 + 4b01d7f commit e1cafda

4 files changed

Lines changed: 36 additions & 18 deletions

File tree

all/ptyprocess/__init__.py

100755100644
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Run a subprocess in a pseudo terminal"""
22
from .ptyprocess import PtyProcess, PtyProcessUnicode, PtyProcessError
33

4-
__version__ = '0.5.2'
4+
__version__ = '0.7.0'

all/ptyprocess/_fork_pty.py

100755100644
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import errno
55

66
from pty import (STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, CHILD)
7+
from .util import PtyProcessError
78

89
def fork_pty():
910
'''This implements a substitute for the forkpty system call. This
@@ -63,7 +64,7 @@ def pty_make_controlling_tty(tty_fd):
6364
try:
6465
fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
6566
os.close(fd)
66-
raise ExceptionPexpect("OSError of errno.ENXIO should be raised.")
67+
raise PtyProcessError("OSError of errno.ENXIO should be raised.")
6768
except OSError as err:
6869
if err.errno != errno.ENXIO:
6970
raise
@@ -74,4 +75,4 @@ def pty_make_controlling_tty(tty_fd):
7475

7576
# Verify we now have a controlling tty.
7677
fd = os.open("/dev/tty", os.O_WRONLY)
77-
os.close(fd)
78+
os.close(fd)

all/ptyprocess/ptyprocess.py

100755100644
Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# Constants
2222
from pty import (STDIN_FILENO, CHILD)
2323

24-
from .util import which
24+
from .util import which, PtyProcessError
2525

2626
_platform = sys.platform.lower()
2727

@@ -62,11 +62,18 @@ def _make_eof_intr():
6262
# inherit EOF and INTR definitions from controlling process.
6363
try:
6464
from termios import VEOF, VINTR
65-
try:
66-
fd = sys.__stdin__.fileno()
67-
except ValueError:
68-
# ValueError: I/O operation on closed file
69-
fd = sys.__stdout__.fileno()
65+
fd = None
66+
for name in 'stdin', 'stdout':
67+
stream = getattr(sys, '__%s__' % name, None)
68+
if stream is None or not hasattr(stream, 'fileno'):
69+
continue
70+
try:
71+
fd = stream.fileno()
72+
except ValueError:
73+
continue
74+
if fd is None:
75+
# no fd, raise ValueError to fallback on CEOF, CINTR
76+
raise ValueError("No stream has a fileno")
7077
intr = ord(termios.tcgetattr(fd)[6][VINTR])
7178
eof = ord(termios.tcgetattr(fd)[6][VEOF])
7279
except (ImportError, OSError, IOError, ValueError, termios.error):
@@ -83,14 +90,11 @@ def _make_eof_intr():
8390
_INTR = _byte(intr)
8491
_EOF = _byte(eof)
8592

86-
class PtyProcessError(Exception):
87-
"""Generic error class for this package."""
88-
8993
# setecho and setwinsize are pulled out here because on some platforms, we need
9094
# to do this from the child before we exec()
9195

9296
def _setecho(fd, state):
93-
errmsg = 'setecho() may not be called on this platform'
97+
errmsg = 'setecho() may not be called on this platform (it may still be possible to enable/disable echo when spawning the child process)'
9498

9599
try:
96100
attr = termios.tcgetattr(fd)
@@ -176,7 +180,7 @@ def __init__(self, pid, fd):
176180
@classmethod
177181
def spawn(
178182
cls, argv, cwd=None, env=None, echo=True, preexec_fn=None,
179-
dimensions=(24, 80)):
183+
dimensions=(24, 80), pass_fds=()):
180184
'''Start the given command in a child process in a pseudo terminal.
181185
182186
This does all the fork/exec type of stuff for a pty, and returns an
@@ -188,6 +192,10 @@ def spawn(
188192
189193
Dimensions of the psuedoterminal used for the subprocess can be
190194
specified as a tuple (rows, cols), or the default (24, 80) will be used.
195+
196+
By default, all file descriptors except 0, 1 and 2 are closed. This
197+
behavior can be overridden with pass_fds, a list of file descriptors to
198+
keep open between the parent and the child.
191199
'''
192200
# Note that it is difficult for this method to fail.
193201
# You cannot detect if the child process cannot start.
@@ -253,9 +261,14 @@ def spawn(
253261

254262
# Do not allow child to inherit open file descriptors from parent,
255263
# with the exception of the exec_err_pipe_write of the pipe
256-
max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
257-
os.closerange(3, exec_err_pipe_write)
258-
os.closerange(exec_err_pipe_write+1, max_fd)
264+
# and pass_fds.
265+
# Impose ceiling on max_fd: AIX bugfix for users with unlimited
266+
# nofiles where resource.RLIMIT_NOFILE is 2^63-1 and os.closerange()
267+
# occasionally raises out of range error
268+
max_fd = min(1048576, resource.getrlimit(resource.RLIMIT_NOFILE)[0])
269+
spass_fds = sorted(set(pass_fds) | {exec_err_pipe_write})
270+
for pair in zip([2] + spass_fds, spass_fds + [max_fd]):
271+
os.closerange(pair[0]+1, pair[1])
259272

260273
if cwd is not None:
261274
os.chdir(cwd)

all/ptyprocess/util.py

100755100644
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,8 @@ def _access_check(fn, mode):
6464
name = os.path.join(dir, thefile)
6565
if _access_check(name, mode):
6666
return name
67-
return None
67+
return None
68+
69+
70+
class PtyProcessError(Exception):
71+
"""Generic error class for this package."""

0 commit comments

Comments
 (0)