summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2013-01-25 13:30:58 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2013-01-25 13:30:58 (GMT)
commit39e70a4e837a4ebfae009bc202ac274aa9005fb6 (patch)
tree9327ac4ae34b55d631f7d22cc26c90029985c2a4
parent3e6e2ac31d8b847f65240f333e54322880adc914 (diff)
downloadcpython-39e70a4e837a4ebfae009bc202ac274aa9005fb6.zip
cpython-39e70a4e837a4ebfae009bc202ac274aa9005fb6.tar.gz
cpython-39e70a4e837a4ebfae009bc202ac274aa9005fb6.tar.bz2
Issue #9290: In IDLE the sys.std* streams now implement io.TextIOBase
interface and support all mandatory methods and properties.
-rw-r--r--Lib/idlelib/PyShell.py92
-rw-r--r--Lib/idlelib/run.py57
-rw-r--r--Misc/NEWS3
3 files changed, 81 insertions, 71 deletions
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index fb47b99..865472e 100644
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -417,10 +417,8 @@ class ModifiedInterpreter(InteractiveInterpreter):
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("console", self.tkconsole)
+ self.rpcclt.register("stdin", self.tkconsole.stdin)
self.rpcclt.register("stdout", self.tkconsole.stdout)
self.rpcclt.register("stderr", self.tkconsole.stderr)
self.rpcclt.register("flist", self.tkconsole.flist)
@@ -860,10 +858,10 @@ class PyShell(OutputWindow):
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)
+ self.stdin = PseudoInputFile(self, "stdin", IOBinding.encoding)
+ self.stdout = PseudoOutputFile(self, "stdout", IOBinding.encoding)
+ self.stderr = PseudoOutputFile(self, "stderr", IOBinding.encoding)
+ self.console = PseudoOutputFile(self, "console", IOBinding.encoding)
if not use_subprocess:
sys.stdout = self.stdout
sys.stderr = self.stderr
@@ -1259,36 +1257,82 @@ class PyShell(OutputWindow):
return 'disabled'
return super().rmenu_check_paste()
-class PseudoFile(object):
+class PseudoFile(io.TextIOBase):
def __init__(self, shell, tags, encoding=None):
self.shell = shell
self.tags = tags
- self.encoding = encoding
+ self._encoding = encoding
+
+ @property
+ def encoding(self):
+ return self._encoding
+
+ @property
+ def name(self):
+ return '<%s>' % self.tags
+
+ def isatty(self):
+ return True
+
+
+class PseudoOutputFile(PseudoFile):
+
+ def writable(self):
+ return True
def write(self, s):
+ if self.closed:
+ raise ValueError("write to closed file")
if not isinstance(s, str):
raise TypeError('must be str, not ' + type(s).__name__)
return self.shell.write(s, self.tags)
- def writelines(self, lines):
- for line in lines:
- self.write(line)
- def flush(self):
- pass
+class PseudoInputFile(PseudoFile):
- def isatty(self):
- return True
+ def __init__(self, shell, tags, encoding=None):
+ PseudoFile.__init__(self, shell, tags, encoding)
+ self._line_buffer = ''
-class PseudoInputFile(object):
- def __init__(self, shell):
- self.readline = shell.readline
- self.isatty = shell.isatty
+ def readable(self):
+ return True
- def write(self, s):
- raise io.UnsupportedOperation("not writable")
- writelines = write
+ def read(self, size=-1):
+ if self.closed:
+ raise ValueError("read from closed file")
+ if size is None:
+ size = -1
+ elif not isinstance(size, int):
+ raise TypeError('must be int, not ' + type(size).__name__)
+ result = self._line_buffer
+ self._line_buffer = ''
+ if size < 0:
+ while True:
+ line = self.shell.readline()
+ if not line: break
+ result += line
+ else:
+ while len(result) < size:
+ line = self.shell.readline()
+ if not line: break
+ result += line
+ self._line_buffer = result[size:]
+ result = result[:size]
+ return result
+
+ def readline(self, size=-1):
+ if self.closed:
+ raise ValueError("read from closed file")
+ if size is None:
+ size = -1
+ elif not isinstance(size, int):
+ raise TypeError('must be int, not ' + type(size).__name__)
+ line = self._line_buffer or self.shell.readline()
+ if size < 0:
+ size = len(line)
+ self._line_buffer = line[size:]
+ return line[:size]
usage_msg = """\
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index b0a4794..7d0941e 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -15,6 +15,8 @@ from idlelib import RemoteDebugger
from idlelib import RemoteObjectBrowser
from idlelib import StackViewer
from idlelib import rpc
+from idlelib import PyShell
+from idlelib import IOBinding
import __main__
@@ -262,62 +264,23 @@ class MyRPCServer(rpc.RPCServer):
quitting = True
thread.interrupt_main()
-class _RPCFile(io.TextIOBase):
- """Wrapper class for the RPC proxy to typecheck arguments
- that may not support pickling. The base class is there only
- to support type tests; all implementations come from the remote
- object."""
-
- def __init__(self, rpc):
- super.__setattr__(self, 'rpc', rpc)
-
- def __getattribute__(self, name):
- # When accessing the 'rpc' attribute, or 'write', use ours
- 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)
-
- 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)
- 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"))
+ self.console = self.get_remote_proxy("console")
+ sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
+ IOBinding.encoding)
+ sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
+ IOBinding.encoding)
+ sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
+ IOBinding.encoding)
+
# page help() text to shell.
import pydoc # import must be done here to capture i/o binding
pydoc.pager = pydoc.plainpager
- from idlelib import IOBinding
- sys.stdin.encoding = sys.stdout.encoding = \
- sys.stderr.encoding = IOBinding.encoding
self.interp = self.get_remote_proxy("interp")
rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
diff --git a/Misc/NEWS b/Misc/NEWS
index 43864ae..ff40c2c 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -202,6 +202,9 @@ Core and Builtins
Library
-------
+- Issue #9290: In IDLE the sys.std* streams now implement io.TextIOBase
+ interface and support all mandatory methods and properties.
+
- Issue #13454: Fix a crash when deleting an iterator created by itertools.tee()
if all other iterators were very advanced before.