import sys # ======================================================================================================================= # BaseStdIn # ======================================================================================================================= class BaseStdIn: def __init__(self, original_stdin=sys.stdin, *args, **kwargs): try: self.encoding = sys.stdin.encoding except: # Not sure if it's available in all Python versions... pass self.original_stdin = original_stdin def readline(self, *args, **kwargs): # sys.stderr.write('Cannot readline out of the console evaluation\n') -- don't show anything # This could happen if the user had done input('enter number).<-- upon entering this, that message would appear, # which is not something we want. return '\n' def write(self, *args, **kwargs): pass # not available StdIn (but it can be expected to be in the stream interface) def flush(self, *args, **kwargs): pass # not available StdIn (but it can be expected to be in the stream interface) def read(self, *args, **kwargs): # in the interactive interpreter, a read and a readline are the same. return self.readline() def close(self, *args, **kwargs): pass # expected in StdIn def __iter__(self): # BaseStdIn would not be considered as Iterable in Python 3 without explicit `__iter__` implementation self.iter = self.original_stdin.__iter__() return self def __next__(self): return self.iter.__next__() def __getattr__(self, item): # it's called if the attribute wasn't found if hasattr(self.original_stdin, item): return getattr(self.original_stdin, item) raise AttributeError("%s has no attribute %s" % (self.original_stdin, item)) # ======================================================================================================================= # StdIn # ======================================================================================================================= class StdIn(BaseStdIn): ''' Object to be added to stdin (to emulate it as non-blocking while the next line arrives) ''' def __init__(self, interpreter, rpc_client, original_stdin=sys.stdin): BaseStdIn.__init__(self, original_stdin) self.interpreter = interpreter self.rpc_client = rpc_client def readline(self, *args, **kwargs): return self.request_input() def request_input(self): from pydev_console.pydev_protocol import KeyboardInterruptException # Ok, callback into the client to get the new input try: requested_input = self.rpc_client.requestInput() if not requested_input: return '\n' # Yes, a readline must return something (otherwise we can get an EOFError on the input() call). return requested_input except KeyboardInterrupt: raise # Let KeyboardInterrupt go through -- #PyDev-816: Interrupting infinite loop in the Interactive Console except KeyboardInterruptException: # this exception is explicitly declared in `requestInput()` method of `PythonConsoleFrontendService` Thrift service # it is thrown on the IDE side and transferred by Thrift library as the response to `requestInput()` method raise except: return '\n' def close(self, *args, **kwargs): pass # expected in StdIn def __iter__(self): return self def __next__(self): return self.request_input() #======================================================================================================================= # DebugConsoleStdIn #======================================================================================================================= class DebugConsoleStdIn(BaseStdIn): ''' Object to be added to stdin (to emulate it as non-blocking while the next line arrives) ''' def __init__(self, dbg, original_stdin): BaseStdIn.__init__(self, original_stdin) self.debugger = dbg def __pydev_run_command(self, is_started): try: cmd = self.debugger.cmd_factory.make_input_requested_message(is_started) self.debugger.writer.add_command(cmd) except Exception: import traceback traceback.print_exc() return '\n' def readline(self, *args, **kwargs): # Notify Java side about input and call original function self.__pydev_run_command(True) result = self.original_stdin.readline(*args, **kwargs) self.__pydev_run_command(False) return result def __iter__(self): self.iter = self.original_stdin.__iter__() return self def __next__(self): # Notify Java side about input and call original function self.__pydev_run_command(True) released = False if self.debugger._main_lock.is_acquired_by_current_thread(): # release main lock while waiting for input to process internal commands and handle interrupt() request self.debugger._main_lock.release() released = True try: result = self.iter.__next__() finally: self.__pydev_run_command(False) if released: self.debugger._main_lock.acquire() return result