Skip to content

Commit f4b341b

Browse files
committed
merge 3.2
2 parents f3923e9 + c882b7c commit f4b341b

File tree

3 files changed

+38
-5
lines changed

3 files changed

+38
-5
lines changed

Lib/idlelib/NEWS.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
What's New in IDLE 3.3.0?
22
=========================
33

4+
- Issue #15318: Prevent writing to sys.stdin.
5+
46
- Issue #4832: Modify IDLE to save files with .py extension by
57
default on Windows and OS X (Tk 8.5) as it already does with X11 Tk.
68

Lib/idlelib/PyShell.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import tokenize
1313
import traceback
1414
import types
15+
import io
1516

1617
import linecache
1718
from code import InteractiveInterpreter
@@ -410,6 +411,9 @@ def start_subprocess(self):
410411
except socket.timeout as err:
411412
self.display_no_subprocess_error()
412413
return None
414+
# Can't regiter self.tkconsole.stdin, since run.py wants to
415+
# call non-TextIO methods on it (such as getvar)
416+
# XXX should be renamed to "console"
413417
self.rpcclt.register("stdin", self.tkconsole)
414418
self.rpcclt.register("stdout", self.tkconsole.stdout)
415419
self.rpcclt.register("stderr", self.tkconsole.stderr)
@@ -854,13 +858,14 @@ def __init__(self, flist=None):
854858
self.save_stderr = sys.stderr
855859
self.save_stdin = sys.stdin
856860
from idlelib import IOBinding
861+
self.stdin = PseudoInputFile(self)
857862
self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
858863
self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
859864
self.console = PseudoFile(self, "console", IOBinding.encoding)
860865
if not use_subprocess:
861866
sys.stdout = self.stdout
862867
sys.stderr = self.stderr
863-
sys.stdin = self
868+
sys.stdin = self.stdin
864869
try:
865870
# page help() text to shell.
866871
import pydoc # import must be done here to capture i/o rebinding.
@@ -1272,6 +1277,15 @@ def flush(self):
12721277
def isatty(self):
12731278
return True
12741279

1280+
class PseudoInputFile(object):
1281+
def __init__(self, shell):
1282+
self.readline = shell.readline
1283+
self.isatty = shell.isatty
1284+
1285+
def write(self, s):
1286+
raise io.UnsupportedOperation("not writable")
1287+
writelines = write
1288+
12751289

12761290
usage_msg = """\
12771291

Lib/idlelib/run.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,28 +269,45 @@ def __init__(self, rpc):
269269

270270
def __getattribute__(self, name):
271271
# When accessing the 'rpc' attribute, or 'write', use ours
272-
if name in ('rpc', 'write'):
272+
if name in ('rpc', 'write', 'writelines'):
273273
return io.TextIOBase.__getattribute__(self, name)
274274
# Else only look into the remote object only
275275
return getattr(self.rpc, name)
276276

277277
def __setattr__(self, name, value):
278278
return setattr(self.rpc, name, value)
279279

280+
@staticmethod
281+
def _ensure_string(func):
282+
def f(self, s):
283+
if not isinstance(s, str):
284+
raise TypeError('must be str, not ' + type(s).__name__)
285+
return func(self, s)
286+
return f
287+
288+
class _RPCOutputFile(_RPCFile):
289+
@_RPCFile._ensure_string
280290
def write(self, s):
281291
if not isinstance(s, str):
282292
raise TypeError('must be str, not ' + type(s).__name__)
283293
return self.rpc.write(s)
284294

295+
class _RPCInputFile(_RPCFile):
296+
@_RPCFile._ensure_string
297+
def write(self, s):
298+
raise io.UnsupportedOperation("not writable")
299+
writelines = write
300+
285301
class MyHandler(rpc.RPCHandler):
286302

287303
def handle(self):
288304
"""Override base method"""
289305
executive = Executive(self)
290306
self.register("exec", executive)
291-
sys.stdin = self.console = self.get_remote_proxy("stdin")
292-
sys.stdout = _RPCFile(self.get_remote_proxy("stdout"))
293-
sys.stderr = _RPCFile(self.get_remote_proxy("stderr"))
307+
self.console = self.get_remote_proxy("stdin")
308+
sys.stdin = _RPCInputFile(self.console)
309+
sys.stdout = _RPCOutputFile(self.get_remote_proxy("stdout"))
310+
sys.stderr = _RPCOutputFile(self.get_remote_proxy("stderr"))
294311
sys.displayhook = rpc.displayhook
295312
# page help() text to shell.
296313
import pydoc # import must be done here to capture i/o binding

0 commit comments

Comments
 (0)