[Python-checkins] cpython (3.2): Issue #15318: Prevent writing to sys.stdin.

martin.v.loewis python-checkins at python.org
Wed Jul 25 10:49:52 CEST 2012


http://hg.python.org/cpython/rev/a82fd35e28be
changeset:   78273:a82fd35e28be
branch:      3.2
parent:      78269:0caff799e4bf
user:        Martin v. Löwis <martin at v.loewis.de>
date:        Wed Jul 25 10:47:20 2012 +0200
summary:
  Issue #15318: Prevent writing to sys.stdin.
Patch by Roger Serwy and myself.

files:
  Lib/idlelib/NEWS.txt   |   2 ++
  Lib/idlelib/PyShell.py |  16 +++++++++++++++-
  Lib/idlelib/run.py     |  25 +++++++++++++++++++++----
  3 files changed, 38 insertions(+), 5 deletions(-)


diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -1,6 +1,8 @@
 What's New in IDLE 3.2.4?
 =========================
 
+- Issue #15318: Prevent writing to sys.stdin.
+
 - Issue #13532, #15319: Check that arguments to sys.stdout.write are strings.
 
 - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE.
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -12,6 +12,7 @@
 import tokenize
 import traceback
 import types
+import io
 
 import linecache
 from code import InteractiveInterpreter
@@ -410,6 +411,9 @@
         except socket.timeout as err:
             self.display_no_subprocess_error()
             return None
+        # Can't regiter self.tkconsole.stdin, since run.py wants to
+        # call non-TextIO methods on it (such as getvar)
+        # XXX should be renamed to "console"
         self.rpcclt.register("stdin", self.tkconsole)
         self.rpcclt.register("stdout", self.tkconsole.stdout)
         self.rpcclt.register("stderr", self.tkconsole.stderr)
@@ -850,13 +854,14 @@
         self.save_stderr = sys.stderr
         self.save_stdin = sys.stdin
         from idlelib import IOBinding
+        self.stdin = PseudoInputFile(self)
         self.stdout = PseudoFile(self, "stdout", IOBinding.encoding)
         self.stderr = PseudoFile(self, "stderr", IOBinding.encoding)
         self.console = PseudoFile(self, "console", IOBinding.encoding)
         if not use_subprocess:
             sys.stdout = self.stdout
             sys.stderr = self.stderr
-            sys.stdin = self
+            sys.stdin = self.stdin
         try:
             # page help() text to shell.
             import pydoc # import must be done here to capture i/o rebinding.
@@ -1256,6 +1261,15 @@
     def isatty(self):
         return True
 
+class PseudoInputFile(object):
+    def __init__(self, shell):
+        self.readline = shell.readline
+        self.isatty = shell.isatty
+
+    def write(self, s):
+        raise io.UnsupportedOperation("not writable")
+    writelines = write
+
 
 usage_msg = """\
 
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -256,7 +256,7 @@
 
     def __getattribute__(self, name):
         # When accessing the 'rpc' attribute, or 'write', use ours
-        if name in ('rpc', 'write'):
+        if name in ('rpc', 'write', 'writelines'):
             return io.TextIOBase.__getattribute__(self, name)
         # Else only look into the remote object only
         return getattr(self.rpc, name)
@@ -264,20 +264,37 @@
     def __setattr__(self, name, value):
         return setattr(self.rpc, name, value)
 
+    @staticmethod
+    def _ensure_string(func):
+        def f(self, s):
+            if not isinstance(s, str):
+                raise TypeError('must be str, not ' + type(s).__name__)
+            return func(self, s)
+        return f
+
+class _RPCOutputFile(_RPCFile):
+    @_RPCFile._ensure_string
     def write(self, s):
         if not isinstance(s, str):
             raise TypeError('must be str, not ' + type(s).__name__)
         return self.rpc.write(s)
 
+class _RPCInputFile(_RPCFile):
+    @_RPCFile._ensure_string
+    def write(self, s):
+        raise io.UnsupportedOperation("not writable")
+    writelines = write
+
 class MyHandler(rpc.RPCHandler):
 
     def handle(self):
         """Override base method"""
         executive = Executive(self)
         self.register("exec", executive)
-        sys.stdin = self.console = self.get_remote_proxy("stdin")
-        sys.stdout = _RPCFile(self.get_remote_proxy("stdout"))
-        sys.stderr = _RPCFile(self.get_remote_proxy("stderr"))
+        self.console = self.get_remote_proxy("stdin")
+        sys.stdin = _RPCInputFile(self.console)
+        sys.stdout = _RPCOutputFile(self.get_remote_proxy("stdout"))
+        sys.stderr = _RPCOutputFile(self.get_remote_proxy("stderr"))
         # page help() text to shell.
         import pydoc # import must be done here to capture i/o binding
         pydoc.pager = pydoc.plainpager

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list