mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	Issue #9290: In IDLE the sys.std* streams now implement io.TextIOBase
interface and support all mandatory methods and properties.
This commit is contained in:
		
							parent
							
								
									3e6e2ac31d
								
							
						
					
					
						commit
						39e70a4e83
					
				
					 3 changed files with 83 additions and 73 deletions
				
			
		|  | @ -417,10 +417,8 @@ def start_subprocess(self): | |||
|         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 @@ def __init__(self, flist=None): | |||
|         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 @@ def rmenu_check_paste(self): | |||
|             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 | ||||
| 
 | ||||
|     def write(self, s): | ||||
|         if not isinstance(s, str): | ||||
|             raise TypeError('must be str, not ' + type(s).__name__) | ||||
|         return self.shell.write(s, self.tags) | ||||
|     @property | ||||
|     def encoding(self): | ||||
|         return self._encoding | ||||
| 
 | ||||
|     def writelines(self, lines): | ||||
|         for line in lines: | ||||
|             self.write(line) | ||||
| 
 | ||||
|     def flush(self): | ||||
|         pass | ||||
|     @property | ||||
|     def name(self): | ||||
|         return '<%s>' % self.tags | ||||
| 
 | ||||
|     def isatty(self): | ||||
|         return True | ||||
| 
 | ||||
| class PseudoInputFile(object): | ||||
|     def __init__(self, shell): | ||||
|         self.readline = shell.readline | ||||
|         self.isatty = shell.isatty | ||||
| 
 | ||||
| class PseudoOutputFile(PseudoFile): | ||||
| 
 | ||||
|     def writable(self): | ||||
|         return True | ||||
| 
 | ||||
|     def write(self, s): | ||||
|         raise io.UnsupportedOperation("not writable") | ||||
|     writelines = write | ||||
|         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) | ||||
| 
 | ||||
| 
 | ||||
| class PseudoInputFile(PseudoFile): | ||||
| 
 | ||||
|     def __init__(self, shell, tags, encoding=None): | ||||
|         PseudoFile.__init__(self, shell, tags, encoding) | ||||
|         self._line_buffer = '' | ||||
| 
 | ||||
|     def readable(self): | ||||
|         return True | ||||
| 
 | ||||
|     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 = """\ | ||||
|  |  | |||
|  | @ -15,6 +15,8 @@ | |||
| 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 @@ def handle_error(self, request, client_address): | |||
|             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) | ||||
| 
 | ||||
|  |  | |||
|  | @ -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. | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Serhiy Storchaka
						Serhiy Storchaka