Reputation: 36556
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?
Upvotes: 3
Views: 656
Reputation: 36556
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!
Upvotes: 1
Reputation: 26951
I'm not a big expert (so plese don't downvote if I'm wrong), but I think you can go with something like
try: from IPython.core import interactiveshell as InteractiveConsole #facade code here, if needed except ImportError: from code import InteractiveConsole #fallback case
This way you'll get your code.InteractiveConsole
if it's present and IPython.core.interactiveshell
otherwise remapped as InteractiveConsole
. You'll have to change method names and signatures anyway, or try build some kind of facade or adapter.
One possible way is to alias all required function calls into your namespace and use this aliases. Than in 'facade' code you'll just have to define functions with same signatures (names and parameter lists) and make them call interactiveshell
functions:
try:
from IPython.core import interactiveshell as InteractiveConsole
def func1(a,b,c):
InteractiveConsole.some_other_func(a,b,c)
except ImportError:
from code import InteractiveConsole #fallback case
func1 = InteractiveConsole.func1
...
func1(a,b,c)
Upvotes: 0