utilities needed to emulate python s interactive interpreter inspired by similar code by jeff epler and fredrik lundh base class for interactiveconsole this class deals with parsing and interpreter state the user s namespace it doesn t deal with input buffering or prompting or input file naming the filename is always passed in explicitly constructor the optional locals argument specifies the dictionary in which code will be executed it defaults to a newly created dictionary with key name set to console and key doc set to none compile and run some source in the interpreter arguments are as for compilecommand one of several things can happen 1 the input is incorrect compilecommand raised an exception syntaxerror or overflowerror a syntax traceback will be printed by calling the showsyntaxerror method 2 the input is incomplete and more input is required compilecommand returned none nothing happens 3 the input is complete compilecommand returned a code object the code is executed by calling self runcode which also handles runtime exceptions except for systemexit the return value is true in case 2 false in the other cases unless an exception is raised the return value can be used to decide whether to use sys ps1 or sys ps2 to prompt the next line case 1 case 2 case 3 execute a code object when an exception occurs self showtraceback is called to display a traceback all exceptions are caught except systemexit which is reraised a note about keyboardinterrupt this exception may occur elsewhere in this code and may not always be caught the caller should be prepared to deal with it display the syntax error that just occurred this doesn t display a stack trace because there isn t one if a filename is given it is stuffed in the exception instead of what was there before because python s parser always uses string when reading from a string the output is written by self write below work hard to stuff the correct filename in the exception not the format we expect leave it alone stuff in the right filename if someone has set sys excepthook we let that take precedence over self write display the exception that just occurred we remove the first stack item because it is our own code the output is written by self write below if someone has set sys excepthook we let that take precedence over self write write a string the base implementation writes to sys stderr a subclass may replace this with a different implementation closely emulate the behavior of the interactive python interpreter this class builds on interactiveinterpreter and adds prompting using the familiar sys ps1 and sys ps2 and input buffering constructor the optional locals argument will be passed to the interactiveinterpreter base class the optional filename argument should specify the filename of the input stream it will show up in tracebacks reset the input buffer self buffer def interactself bannernone exitmsgnone try sys ps1 except attributeerror sys ps1 try sys ps2 except attributeerror sys ps2 cprt type help credits or license for more information if banner is none self writepython s on snsnsn sys version sys platform cprt self class name elif banner self writesn strbanner more 0 when the user uses exit or quit in their interactive shell they probably just want to exit the created shell not the whole process exit and quit in builtins closes sys stdin which makes it super difficult to restore when self localexit is true we overwrite the builtins so exit and quit only raises systemexit and we can catch that to only exit the interactive shell exit none quit none if self localexit if hasattrbuiltins exit exit builtins exit builtins exit quitterexit if hasattrbuiltins quit quit builtins quit builtins quit quitterquit try while true try if more prompt sys ps2 else prompt sys ps1 try line self rawinputprompt except eoferror self writen break else more self pushline except keyboardinterrupt self writenkeyboardinterruptn self resetbuffer more 0 except systemexit as e if self localexit self writen break else raise e finally restore exit and quit in builtins if they were modified if exit is not none builtins exit exit if quit is not none builtins quit quit if exitmsg is none self write now exiting s n self class name elif exitmsg self write sn exitmsg def pushself line self buffer appendline source n joinself buffer more self runsourcesource self filename if not more self resetbuffer return more def rawinputself prompt return inputprompt class quitter def initself name self name name if sys platform win32 self eof ctrlz plus return else self eof ctrld i e eof def reprself return f use self name or self eof to exit def callself codenone raise systemexitcode def interactbannernone readfuncnone localnone exitmsgnone localexitfalse console interactiveconsolelocal localexitlocalexit if readfunc is not none console rawinput readfunc else try import readline except importerror pass console interactbanner exitmsg if name main import argparse parser argparse argumentparser parser addargument q action storetrue helpdon t print version and messages args parser parseargs if args q or sys flags quiet banner else banner none interactbanner inspired by similar code by jeff epler and fredrik lundh base class for interactiveconsole this class deals with parsing and interpreter state the user s namespace it doesn t deal with input buffering or prompting or input file naming the filename is always passed in explicitly constructor the optional locals argument specifies the dictionary in which code will be executed it defaults to a newly created dictionary with key __name__ set to __console__ and key __doc__ set to none compile and run some source in the interpreter arguments are as for compile_command one of several things can happen 1 the input is incorrect compile_command raised an exception syntaxerror or overflowerror a syntax traceback will be printed by calling the showsyntaxerror method 2 the input is incomplete and more input is required compile_command returned none nothing happens 3 the input is complete compile_command returned a code object the code is executed by calling self runcode which also handles run time exceptions except for systemexit the return value is true in case 2 false in the other cases unless an exception is raised the return value can be used to decide whether to use sys ps1 or sys ps2 to prompt the next line case 1 case 2 case 3 execute a code object when an exception occurs self showtraceback is called to display a traceback all exceptions are caught except systemexit which is reraised a note about keyboardinterrupt this exception may occur elsewhere in this code and may not always be caught the caller should be prepared to deal with it display the syntax error that just occurred this doesn t display a stack trace because there isn t one if a filename is given it is stuffed in the exception instead of what was there before because python s parser always uses string when reading from a string the output is written by self write below work hard to stuff the correct filename in the exception not the format we expect leave it alone stuff in the right filename if someone has set sys excepthook we let that take precedence over self write display the exception that just occurred we remove the first stack item because it is our own code the output is written by self write below if someone has set sys excepthook we let that take precedence over self write write a string the base implementation writes to sys stderr a subclass may replace this with a different implementation closely emulate the behavior of the interactive python interpreter this class builds on interactiveinterpreter and adds prompting using the familiar sys ps1 and sys ps2 and input buffering constructor the optional locals argument will be passed to the interactiveinterpreter base class the optional filename argument should specify the file name of the input stream it will show up in tracebacks reset the input buffer closely emulate the interactive python console the optional banner argument specifies the banner to print before the first interaction by default it prints a banner similar to the one printed by the real python interpreter followed by the current class name in parentheses so as not to confuse this with the real interpreter since it s so close the optional exitmsg argument specifies the exit message printed when exiting pass the empty string to suppress printing an exit message if exitmsg is not given or none a default message is printed when the user uses exit or quit in their interactive shell they probably just want to exit the created shell not the whole process exit and quit in builtins closes sys stdin which makes it super difficult to restore when self local_exit is true we overwrite the builtins so exit and quit only raises systemexit and we can catch that to only exit the interactive shell restore exit and quit in builtins if they were modified push a line to the interpreter the line should not have a trailing newline it may have internal newlines the line is appended to a buffer and the interpreter s runsource method is called with the concatenated contents of the buffer as source if this indicates that the command was executed or invalid the buffer is reset otherwise the command is incomplete and the buffer is left as it was after the line was appended the return value is 1 if more input is required 0 if the line was dealt with in some way this is the same as runsource write a prompt and read a line the returned line does not include the trailing newline when the user enters the eof key sequence eoferror is raised the base implementation uses the built in function input a subclass may replace this with a different implementation closely emulate the interactive python interpreter this is a backwards compatible interface to the interactiveconsole class when readfunc is not specified it attempts to import the readline module to enable gnu readline if it is available arguments all optional all default to none banner passed to interactiveconsole interact readfunc if not none replaces interactiveconsole raw_input local passed to interactiveinterpreter __init__ exitmsg passed to interactiveconsole interact local_exit passed to interactiveconsole __init__
import builtins
import sys
import traceback
from codeop import CommandCompiler, compile_command

__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
           "compile_command"]

class InteractiveInterpreter:
    

    def __init__(self, locals=None):
        
        if locals is None:
            locals = {"__name__": "__console__", "__doc__": None}
        self.locals = locals
        self.compile = CommandCompiler()

    def runsource(self, source, filename="<input>", symbol="single"):
        
        try:
            code = self.compile(source, filename, symbol)
        except (OverflowError, SyntaxError, ValueError):
            
            self.showsyntaxerror(filename)
            return False

        if code is None:
            
            return True

        
        self.runcode(code)
        return False

    def runcode(self, code):
        
        try:
            exec(code, self.locals)
        except SystemExit:
            raise
        except:
            self.showtraceback()

    def showsyntaxerror(self, filename=None):
        
        type, value, tb = sys.exc_info()
        sys.last_exc = value
        sys.last_type = type
        sys.last_value = value
        sys.last_traceback = tb
        if filename and type is SyntaxError:
            
            try:
                msg, (dummy_filename, lineno, offset, line) = value.args
            except ValueError:
                
                pass
            else:
                
                value = SyntaxError(msg, (filename, lineno, offset, line))
                sys.last_exc = sys.last_value = value
        if sys.excepthook is sys.__excepthook__:
            lines = traceback.format_exception_only(type, value)
            self.write(''.join(lines))
        else:
            
            
            sys.excepthook(type, value, tb)

    def showtraceback(self):
        
        sys.last_type, sys.last_value, last_tb = ei = sys.exc_info()
        sys.last_traceback = last_tb
        sys.last_exc = ei[1]
        try:
            lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next)
            if sys.excepthook is sys.__excepthook__:
                self.write(''.join(lines))
            else:
                
                
                sys.excepthook(ei[0], ei[1], last_tb)
        finally:
            last_tb = ei = None

    def write(self, data):
        
        sys.stderr.write(data)


class InteractiveConsole(InteractiveInterpreter):
    

    def __init__(self, locals=None, filename="<console>", local_exit=False):
        
        InteractiveInterpreter.__init__(self, locals)
        self.filename = filename
        self.local_exit = local_exit
        self.resetbuffer()

    def resetbuffer(self):
        
        self.buffer = []

    def interact(self, banner=None, exitmsg=None):
        
        try:
            sys.ps1
        except AttributeError:
            sys.ps1 = ">>> "
        try:
            sys.ps2
        except AttributeError:
            sys.ps2 = "... "
        cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
        if banner is None:
            self.write("Python %s on %s\n%s\n(%s)\n" %
                       (sys.version, sys.platform, cprt,
                        self.__class__.__name__))
        elif banner:
            self.write("%s\n" % str(banner))
        more = 0

        
        
        
        
        
        
        
        

        _exit = None
        _quit = None

        if self.local_exit:
            if hasattr(builtins, "exit"):
                _exit = builtins.exit
                builtins.exit = Quitter("exit")

            if hasattr(builtins, "quit"):
                _quit = builtins.quit
                builtins.quit = Quitter("quit")

        try:
            while True:
                try:
                    if more:
                        prompt = sys.ps2
                    else:
                        prompt = sys.ps1
                    try:
                        line = self.raw_input(prompt)
                    except EOFError:
                        self.write("\n")
                        break
                    else:
                        more = self.push(line)
                except KeyboardInterrupt:
                    self.write("\nKeyboardInterrupt\n")
                    self.resetbuffer()
                    more = 0
                except SystemExit as e:
                    if self.local_exit:
                        self.write("\n")
                        break
                    else:
                        raise e
        finally:
            
            if _exit is not None:
                builtins.exit = _exit

            if _quit is not None:
                builtins.quit = _quit

            if exitmsg is None:
                self.write('now exiting %s...\n' % self.__class__.__name__)
            elif exitmsg != '':
                self.write('%s\n' % exitmsg)

    def push(self, line):
        
        self.buffer.append(line)
        source = "\n".join(self.buffer)
        more = self.runsource(source, self.filename)
        if not more:
            self.resetbuffer()
        return more

    def raw_input(self, prompt=""):
        
        return input(prompt)


class Quitter:
    def __init__(self, name):
        self.name = name
        if sys.platform == "win32":
            self.eof = 'Ctrl-Z plus Return'
        else:
            self.eof = 'Ctrl-D (i.e. EOF)'

    def __repr__(self):
        return f'Use {self.name} or {self.eof} to exit'

    def __call__(self, code=None):
        raise SystemExit(code)


def interact(banner=None, readfunc=None, local=None, exitmsg=None, local_exit=False):
    
    console = InteractiveConsole(local, local_exit=local_exit)
    if readfunc is not None:
        console.raw_input = readfunc
    else:
        try:
            import readline
        except ImportError:
            pass
    console.interact(banner, exitmsg)


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-q', action='store_true',
                       help="don't print version and copyright messages")
    args = parser.parse_args()
    if args.q or sys.flags.quiet:
        banner = ''
    else:
        banner = None
    interact(banner)