from ctypes import windll, byref, c_int, create_unicode_buffer import io import sys import time import code kernel32 = windll.kernel32 GetStdHandle = kernel32.GetStdHandle ReadConsoleW = kernel32.ReadConsoleW WriteConsoleW = kernel32.WriteConsoleW STDIN_HANDLE = GetStdHandle(-10) STDOUT_HANDLE = GetStdHandle(-11) STDERR_HANDLE = GetStdHandle(-12) STDIN_FILENO = 0 STDOUT_FILENO = 1 STDERR_FILENO = 2 ENDLINE = "\r\n" EOF = "\x1a" CHUNK = 1024 class UnicodeConsoleIOBase(io.TextIOBase): encoding = "utf-8" errors = "strict" # input() raises (TypeError: bad argument type for built-in operation) without them defined # stdin shouldn't have stdin fileno – in that case GNU readline is called def __init__(self, name, handle): self.name = name self.handle = handle def __repr__(self): return "<{} {}>".format(self.__class__.__name__, repr(self.name)) def flush(self): pass def isatty(self): return True class UnicodeConsoleReader(UnicodeConsoleIOBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._buffer = "" def readable(self): return True @staticmethod def _read(n): characters_read = c_int() text = create_unicode_buffer(n) retval = ReadConsoleW(STDIN_HANDLE, text, n, byref(characters_read), None) if not characters_read.value: time.sleep(0.01) # wait for KeyboardInterrupt if not retval: raise OSError return text.value.replace(ENDLINE, "\n") def _read_prompt(self): # console reads whole lines # this will get the whole input so nothing lefts in console internal input buffer chunk = self._read(CHUNK) if chunk.startswith(EOF): raise EOFError else: self._buffer += chunk while not self._buffer.endswith("\n"): self._buffer += self._read(CHUNK) def read(self, n=None): if n is None: n = -1 if n < 0: try: while True: self._read_prompt() except EOFError: text = self._buffer self._buffer = "" return text else: try: while n > len(self._buffer): self._read_prompt() except EOFError: pass text, self._buffer = self._buffer[:n], self._buffer[n:] return text def readline(self, limit=None): if "\n" not in self._buffer: try: self._read_prompt() except EOFError: line = self._buffer self._buffer = "" return line buf = self._buffer index = buf.index("\n") + 1 line, self._buffer = buf[:index], buf[index:] return line class UnicodeConsoleWriter(UnicodeConsoleIOBase): def writeble(self): return True def write(self, text): text = text.replace("\n", ENDLINE) characters_written = c_int() retval = WriteConsoleW(self.handle, text, len(text), byref(characters_written), None) return characters_written.value unicode_in = UnicodeConsoleReader("stdin", STDIN_HANDLE) unicode_out = UnicodeConsoleWriter("stdout", STDOUT_HANDLE) unicode_err = UnicodeConsoleWriter("stderr", STDERR_HANDLE) class InteractiveConsole(code.InteractiveConsole): # code.InteractiveConsole without banner # exits on EOF running_console = None @classmethod def enable(cls): if cls.running_console is not None: raise RuntimeError("interactive console already running") else: import __main__ con = cls.running_console = cls(__main__.__dict__, "") con.done = False con.interact() @classmethod def disable(cls): if cls.running_console is None: raise RuntimeError("interactive console is not running") else: cls.running_console.done = True cls.running_console = None def interact(self): try: sys.ps1 except AttributeError: sys.ps1 = ">>> " try: sys.ps2 except AttributeError: sys.ps2 = "... " more = 0 while not self.done: try: if more: try: prompt = sys.ps2 except AttributeError: prompt = "" else: try: prompt = sys.ps1 except AttributeError: prompt = "" try: line = self.raw_input(prompt) except EOFError: self.on_EOF() else: more = self.push(line) except KeyboardInterrupt: self.write("\nKeyboardInterrupt\n") self.resetbuffer() more = 0 def on_EOF(self): self.write("\n") sys.exit() def disable_streams(): sys.stdin.flush() sys.stdout.flush() sys.stderr.flush() sys.stdin = sys.__stdin__ sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ def check_stream(stream, fileno): try: _fileno = stream.fileno() except io.UnsupportedOperation: return False else: if _fileno == fileno: stream.flush() return True else: return False def enable_reader(): if check_stream(sys.stdin, STDIN_FILENO) or sys.stdin is unicode_in: sys.stdin = unicode_in def enable_writer(): if check_stream(sys.stdout, STDOUT_FILENO): sys.stdout = unicode_out def enable_error_writer(): if check_stream(sys.stderr, STDERR_FILENO): sys.stderr = unicode_err def enable_streams(): enable_reader() enable_writer() enable_error_writer() # usage: # put win_unicode_console.enable_streams() to sitecustomize # put win_unicode_console.InsteractiveConsole.enable() to startup file run by PYTHONSTARTUP # to inspect a script, run "py -m i script.py" instead of "py -i script.py", first, put i.py to site-packages