Using IPython interchangeably with code module if IPython exists
Question: In an existing code snippet, I have

    
    
    import sys
    from code import InteractiveConsole
    
    
    class FileCacher:
        "Cache the stdout text so we can analyze it before returning it"
        def __init__(self):
            self.reset()
    
        def reset(self):
            self.out = []
    
        def write(self, line):
            self.out.append(line)
    
        def flush(self):
            output = '\n'.join(self.out)
            self.reset()
            return output
    
    
    class Shell(InteractiveConsole):
        "Wrapper around Python that can filter input/output to the shell"
        def __init__(self):
            self.stdout = sys.stdout
            self.cache = FileCacher()
            InteractiveConsole.__init__(self)
            return
    
        def get_output(self):
            sys.stdout = self.cache
    
        def return_output(self):
            sys.stdout = self.stdout
    
        def push(self, line):
            self.get_output()
            # you can filter input here by doing something like
            # line = filter(line)
            InteractiveConsole.push(self, line)
            self.return_output()
            output = self.cache.flush()
            # you can filter the output here by doing something like
            # output = filter(output)
            print output  # or do something else with it
            return
    
    if __name__ == '__main__':
        sh = Shell()
        sh.interact()
    

How do I modify this to use IPython's interactive shell if IPython is
available without changing the rest of the code if possible.

I attempted swapping out line 2 `from code import InteractiveConsole` with
`from IPython.core import interactiveshell as InteractiveConsole` but
obviously, it's not a directly interchangeable class.

What's the best way to do this (with minimal change to the rest of the code
base) with a try except and using `IPython` in preference over `code` module
when `IPython` exists?


Answer: Here's my own attempt:-

    
    
    import sys
    from code import InteractiveConsole
    
    class FileCacher:
        "Cache the stdout text so we can analyze it before returning it"
        def __init__(self):
            self.reset()
    
        def reset(self):
            self.out = []
    
        def write(self, line):
            self.out.append(line)
    
        def flush(self):
            output = '\n'.join(self.out)
            self.reset()
            return output
    
    
    class Shell(InteractiveConsole):
        "Wrapper around Python that can filter input/output to the shell"
        def __init__(self):
            self.stdout = sys.stdout
            self.cache = FileCacher()
            InteractiveConsole.__init__(self)
            return
    
        def get_output(self):
            sys.stdout = self.cache
    
        def return_output(self):
            sys.stdout = self.stdout
    
        def push(self, line):
            self.get_output()
            # you can filter input here by doing something like
            # line = filter(line)
            InteractiveConsole.push(self, line)
            self.return_output()
            output = self.cache.flush()
            # you can filter the output here by doing something like
            # output = filter(output)
            print output  # or do something else with it
            return
    
    if __name__ == '__main__':
        try:
            import IPython
            IPython.embed()
        except:
            sh = Shell()
            sh.interact()
    

which seems to work fine but I probably lost the `cache` and `stdout` custom
methods/functionalities.

Any criticism, edits and improvement suggestions welcome!

