From add1bd1ff80658c80393004ac5fe37f23fc1cc58 Mon Sep 17 00:00:00 2001 From: MinRK Date: Thu, 21 Apr 2011 15:55:30 -0700 Subject: [PATCH] io.Term.cin/out/err replaced by io.stdin/out/err Behavior is now the same as sys.stdin/out/err, and defaults to those streams. --- IPython/core/debugger.py | 9 ++++---- IPython/core/displayhook.py | 17 +++++++------- IPython/core/displaypub.py | 4 ++-- IPython/core/history.py | 7 +++--- IPython/core/hooks.py | 1 - IPython/core/interactiveshell.py | 17 +++++++------- IPython/core/macro.py | 2 -- IPython/core/magic.py | 1 - IPython/core/oinspect.py | 4 ++-- IPython/core/page.py | 14 ++++++------ IPython/core/prefilter.py | 1 - IPython/core/ultratb.py | 8 +++---- IPython/lib/demo.py | 30 ++++++++++++------------ IPython/utils/io.py | 39 +++++++++++++++++++++++++------- IPython/utils/tests/test_io.py | 10 ++++++++ IPython/utils/warn.py | 8 +++---- 16 files changed, 98 insertions(+), 74 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 9f80d240fda..225e0824529 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -31,8 +31,7 @@ from IPython.utils import PyColorize from IPython.core import ipapi -from IPython.utils import coloransi -import IPython.utils.io +from IPython.utils import coloransi, io from IPython.core.excolors import exception_colors # See if we can use pydb. @@ -171,7 +170,7 @@ def __init__(self,color_scheme='NoColor',completekey=None, # Parent constructor: if has_pydb and completekey is None: - OldPdb.__init__(self,stdin=stdin,stdout=IPython.utils.io.Term.cout) + OldPdb.__init__(self,stdin=stdin,stdout=io.stdout) else: OldPdb.__init__(self,completekey,stdin,stdout) @@ -279,7 +278,7 @@ def print_stack_trace(self): def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ', context = 3): #frame, lineno = frame_lineno - print >>IPython.utils.io.Term.cout, self.format_stack_entry(frame_lineno, '', context) + print >>io.stdout, self.format_stack_entry(frame_lineno, '', context) # vds: >> frame, lineno = frame_lineno @@ -419,7 +418,7 @@ def print_list_lines(self, filename, first, last): src.append(line) self.lineno = lineno - print >>IPython.utils.io.Term.cout, ''.join(src) + print >>io.stdout, ''.join(src) except KeyboardInterrupt: pass diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index c0f38a1fd11..4af17f36ae8 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -26,8 +26,7 @@ from IPython.config.configurable import Configurable from IPython.core import prompts -import IPython.utils.generics -import IPython.utils.io +from IPython.utils import io from IPython.utils.traitlets import Instance, List from IPython.utils.warn import warn @@ -178,13 +177,13 @@ def write_output_prompt(self): """Write the output prompt. The default implementation simply writes the prompt to - ``io.Term.cout``. + ``io.stdout``. """ # Use write, not print which adds an extra space. - IPython.utils.io.Term.cout.write(self.output_sep) + io.stdout.write(self.output_sep) outprompt = str(self.prompt_out) if self.do_full_cache: - IPython.utils.io.Term.cout.write(outprompt) + io.stdout.write(outprompt) def compute_format_data(self, result): """Compute format data of the object to be displayed. @@ -219,7 +218,7 @@ def write_format_data(self, format_dict): """Write the format data dict to the frontend. This default version of this method simply writes the plain text - representation of the object to ``io.Term.cout``. Subclasses should + representation of the object to ``io.stdout``. Subclasses should override this method to send the entire `format_dict` to the frontends. @@ -244,7 +243,7 @@ def write_format_data(self, format_dict): # But avoid extraneous empty lines. result_repr = '\n' + result_repr - print >>IPython.utils.io.Term.cout, result_repr + print >>io.stdout, result_repr def update_user_ns(self, result): """Update user_ns with various things like _, __, _1, etc.""" @@ -287,8 +286,8 @@ def log_output(self, format_dict): def finish_displayhook(self): """Finish up all displayhook activities.""" - IPython.utils.io.Term.cout.write(self.output_sep2) - IPython.utils.io.Term.cout.flush() + io.stdout.write(self.output_sep2) + io.stdout.flush() def __call__(self, result=None): """Printing with history cache management. diff --git a/IPython/core/displaypub.py b/IPython/core/displaypub.py index 44b6a3e6bf9..704a99820b3 100644 --- a/IPython/core/displaypub.py +++ b/IPython/core/displaypub.py @@ -98,9 +98,9 @@ def publish(self, source, data, metadata=None): the data. """ from IPython.utils import io - # The default is to simply write the plain text data using io.Term. + # The default is to simply write the plain text data using io.stdout. if data.has_key('text/plain'): - print(data['text/plain'], file=io.Term.cout) + print(data['text/plain'], file=io.stdout) def publish_display_data(self, source, data, metadata=None): diff --git a/IPython/core/history.py b/IPython/core/history.py index e95b0b19d9d..2c1e1babd06 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -22,10 +22,9 @@ # Our own packages from IPython.config.configurable import Configurable -import IPython.utils.io from IPython.testing import decorators as testdec -from IPython.utils.io import ask_yes_no +from IPython.utils import io from IPython.utils.traitlets import Bool, Dict, Instance, Int, List, Unicode from IPython.utils.warn import warn @@ -630,12 +629,12 @@ def _format_lineno(session, line): try: outfname = opts['f'] except KeyError: - outfile = IPython.utils.io.Term.cout # default + outfile = io.stdout # default # We don't want to close stdout at the end! close_at_end = False else: if os.path.exists(outfname): - if not ask_yes_no("File %r exists. Overwrite?" % outfname): + if not io.ask_yes_no("File %r exists. Overwrite?" % outfname): print('Aborting.') return diff --git a/IPython/core/hooks.py b/IPython/core/hooks.py index 712342f7c39..cd9e46c8885 100644 --- a/IPython/core/hooks.py +++ b/IPython/core/hooks.py @@ -45,7 +45,6 @@ def calljed(self,filename, linenum): import sys from IPython.core.error import TryNext -import IPython.utils.io # List here all the default hooks. For now it's just the editor functions # but over time we'll move here all the public API for user-accessible things. diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 6de39569383..acd4cb8ac47 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -511,14 +511,13 @@ def init_inspector(self): def init_io(self): # This will just use sys.stdout and sys.stderr. If you want to # override sys.stdout and sys.stderr themselves, you need to do that - # *before* instantiating this class, because Term holds onto + # *before* instantiating this class, because io holds onto # references to the underlying streams. if sys.platform == 'win32' and self.has_readline: - Term = io.IOTerm(cout=self.readline._outputfile, - cerr=self.readline._outputfile) + io.stdout = io.stderr = io.IOStream(self.readline._outputfile) else: - Term = io.IOTerm() - io.Term = Term + io.stdout = io.IOStream(sys.stdout) + io.stderr = io.IOStream(sys.stderr) def init_prompts(self): # TODO: This is a pass for now because the prompts are managed inside @@ -1477,7 +1476,7 @@ def _showtraceback(self, etype, evalue, stb): Subclasses may override this method to put the traceback on a different place, like a side channel. """ - print >> io.Term.cout, self.InteractiveTB.stb2text(stb) + print >> io.stdout, self.InteractiveTB.stb2text(stb) def showsyntaxerror(self, filename=None): """Display the syntax error that just occurred. @@ -1931,7 +1930,7 @@ def auto_rewrite_input(self, cmd): # plain ascii works better w/ pyreadline, on some machines, so # we use it and only print uncolored rewrite if we have unicode rw = str(rw) - print >> IPython.utils.io.Term.cout, rw + print >> io.stdout, rw except UnicodeEncodeError: print "------> " + cmd @@ -2325,12 +2324,12 @@ def mktempfile(self, data=None, prefix='ipython_edit_'): # TODO: This should be removed when Term is refactored. def write(self,data): """Write a string to the default output""" - io.Term.cout.write(data) + io.stdout.write(data) # TODO: This should be removed when Term is refactored. def write_err(self,data): """Write a string to the default error output""" - io.Term.cerr.write(data) + io.stderr.write(data) def ask_yes_no(self,prompt,default=True): if self.quiet: diff --git a/IPython/core/macro.py b/IPython/core/macro.py index ed6c11fe470..e87ea78624e 100644 --- a/IPython/core/macro.py +++ b/IPython/core/macro.py @@ -10,8 +10,6 @@ import re import sys -import IPython.utils.io - coding_declaration = re.compile(r"#\s*coding[:=]\s*([-\w.]+)") class Macro(object): diff --git a/IPython/core/magic.py b/IPython/core/magic.py index f6febd45182..a298e36fa40 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -53,7 +53,6 @@ from IPython.external.Itpl import itpl, printpl from IPython.testing import decorators as testdec from IPython.utils.io import file_read, nlprint -import IPython.utils.io from IPython.utils.path import get_py_filename from IPython.utils.process import arg_split, abbrev_cwd from IPython.utils.terminal import set_term_title diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index e0affa1a5e0..1ee9f2e8f71 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -31,7 +31,7 @@ from IPython.core import page from IPython.external.Itpl import itpl from IPython.utils import PyColorize -import IPython.utils.io +from IPython.utils import io from IPython.utils.text import indent from IPython.utils.wildcard import list_namespace from IPython.utils.coloransi import * @@ -300,7 +300,7 @@ def pdef(self,obj,oname=''): if output is None: self.noinfo('definition header',oname) else: - print >>IPython.utils.io.Term.cout, header,self.format(output), + print >>io.stdout, header,self.format(output), def pdoc(self,obj,oname='',formatter = None): """Print the docstring for any object. diff --git a/IPython/core/page.py b/IPython/core/page.py index 5ee3083f633..a140d6236dc 100755 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -36,7 +36,7 @@ from IPython.core.error import TryNext from IPython.utils.cursesimport import use_curses from IPython.utils.data import chop -import IPython.utils.io +from IPython.utils import io from IPython.utils.process import system from IPython.utils.terminal import get_terminal_size @@ -56,18 +56,18 @@ def page_dumb(strng, start=0, screen_lines=25): out_ln = strng.splitlines()[start:] screens = chop(out_ln,screen_lines-1) if len(screens) == 1: - print >>IPython.utils.io.Term.cout, os.linesep.join(screens[0]) + print >>io.stdout, os.linesep.join(screens[0]) else: last_escape = "" for scr in screens[0:-1]: hunk = os.linesep.join(scr) - print >>IPython.utils.io.Term.cout, last_escape + hunk + print >>io.stdout, last_escape + hunk if not page_more(): return esc_list = esc_re.findall(hunk) if len(esc_list) > 0: last_escape = esc_list[-1] - print >>IPython.utils.io.Term.cout, last_escape + os.linesep.join(screens[-1]) + print >>io.stdout, last_escape + os.linesep.join(screens[-1]) def page(strng, start=0, screen_lines=0, pager_cmd=None): @@ -176,7 +176,7 @@ def page(strng, start=0, screen_lines=0, pager_cmd=None): #print 'numlines',numlines,'screenlines',screen_lines # dbg if numlines <= screen_lines : #print '*** normal print' # dbg - print >>IPython.utils.io.Term.cout, str_toprint + print >>io.stdout, str_toprint else: # Try to open pager and default to internal one if that fails. # All failure modes are tagged as 'retval=1', to match the return @@ -282,13 +282,13 @@ def page_more(): @return: True if need print more lines, False if quit """ - IPython.utils.io.Term.cout.write('---Return to continue, q to quit--- ') + io.stdout.write('---Return to continue, q to quit--- ') ans = msvcrt.getch() if ans in ("q", "Q"): result = False else: result = True - IPython.utils.io.Term.cout.write("\b"*37 + " "*37 + "\b"*37) + io.stdout.write("\b"*37 + " "*37 + "\b"*37) return result else: def page_more(): diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index 1370a53340a..859ccca6cb0 100755 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -37,7 +37,6 @@ from IPython.core import page from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool, Instance -import IPython.utils.io from IPython.utils.text import make_quoted_expr from IPython.utils.autoattr import auto_attr diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 3652313cef0..22928da3cb1 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -325,8 +325,8 @@ def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None): # Output stream to write to. Note that we store the original value in # a private attribute and then make the public ostream a property, so - # that we can delay accessing io.Term.cout until runtime. The way - # things are written now, the Term.cout object is dynamically managed + # that we can delay accessing io.stdout until runtime. The way + # things are written now, the io.stdout object is dynamically managed # so a reference to it should NEVER be stored statically. This # property approach confines this detail to a single location, and all # subclasses can simply access self.ostream for writing. @@ -349,12 +349,12 @@ def _get_ostream(self): Valid values are: - None: the default, which means that IPython will dynamically resolve - to io.Term.cout. This ensures compatibility with most tools, including + to io.stdout. This ensures compatibility with most tools, including Windows (where plain stdout doesn't recognize ANSI escapes). - Any object with 'write' and 'flush' attributes. """ - return io.Term.cout if self._ostream is None else self._ostream + return io.stdout if self._ostream is None else self._ostream def _set_ostream(self, val): assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush')) diff --git a/IPython/lib/demo.py b/IPython/lib/demo.py index a2e82ead3f9..e2bc7c5fb47 100644 --- a/IPython/lib/demo.py +++ b/IPython/lib/demo.py @@ -176,8 +176,8 @@ import sys from IPython.utils.PyColorize import Parser +from IPython.utils import io from IPython.utils.io import file_read, file_readlines -import IPython.utils.io from IPython.utils.text import marquee __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError'] @@ -319,7 +319,7 @@ def _get_index(self,index): if index is None: if self.finished: - print >>IPython.utils.io.Term.cout, 'Demo finished. Use .reset() if you want to rerun it.' + print >>io.stdout, 'Demo finished. Use .reset() if you want to rerun it.' return None index = self.block_index else: @@ -388,9 +388,9 @@ def show(self,index=None): if index is None: return - print >>IPython.utils.io.Term.cout, self.marquee('<%s> block # %s (%s remaining)' % + print >>io.stdout, self.marquee('<%s> block # %s (%s remaining)' % (self.title,index,self.nblocks-index-1)) - print >>IPython.utils.io.Term.cout,(self.src_blocks_colored[index]) + print >>io.stdout,(self.src_blocks_colored[index]) sys.stdout.flush() def show_all(self): @@ -403,12 +403,12 @@ def show_all(self): marquee = self.marquee for index,block in enumerate(self.src_blocks_colored): if silent[index]: - print >>IPython.utils.io.Term.cout, marquee('<%s> SILENT block # %s (%s remaining)' % + print >>io.stdout, marquee('<%s> SILENT block # %s (%s remaining)' % (title,index,nblocks-index-1)) else: - print >>IPython.utils.io.Term.cout, marquee('<%s> block # %s (%s remaining)' % + print >>io.stdout, marquee('<%s> block # %s (%s remaining)' % (title,index,nblocks-index-1)) - print >>IPython.utils.io.Term.cout, block, + print >>io.stdout, block, sys.stdout.flush() def run_cell(self,source): @@ -433,18 +433,18 @@ def __call__(self,index=None): next_block = self.src_blocks[index] self.block_index += 1 if self._silent[index]: - print >>IPython.utils.io.Term.cout, marquee('Executing silent block # %s (%s remaining)' % + print >>io.stdout, marquee('Executing silent block # %s (%s remaining)' % (index,self.nblocks-index-1)) else: self.pre_cmd() self.show(index) if self.auto_all or self._auto[index]: - print >>IPython.utils.io.Term.cout, marquee('output:') + print >>io.stdout, marquee('output:') else: - print >>IPython.utils.io.Term.cout, marquee('Press to quit, to execute...'), + print >>io.stdout, marquee('Press to quit, to execute...'), ans = raw_input().strip() if ans: - print >>IPython.utils.io.Term.cout, marquee('Block NOT executed') + print >>io.stdout, marquee('Block NOT executed') return try: save_argv = sys.argv @@ -462,10 +462,10 @@ def __call__(self,index=None): if self.block_index == self.nblocks: mq1 = self.marquee('END OF DEMO') if mq1: - # avoid spurious print >>IPython.utils.io.Term.cout,s if empty marquees are used - print >>IPython.utils.io.Term.cout - print >>IPython.utils.io.Term.cout, mq1 - print >>IPython.utils.io.Term.cout, self.marquee('Use .reset() if you want to rerun it.') + # avoid spurious print >>io.stdout,s if empty marquees are used + print >>io.stdout + print >>io.stdout, mq1 + print >>io.stdout, self.marquee('Use .reset() if you want to rerun it.') self.finished = True # These methods are meant to be overridden by subclasses who may wish to diff --git a/IPython/utils/io.py b/IPython/utils/io.py index 765d7ae3659..1775b01d660 100644 --- a/IPython/utils/io.py +++ b/IPython/utils/io.py @@ -26,13 +26,21 @@ class IOStream: - def __init__(self,stream,fallback): + def __init__(self,stream, fallback=None): if not hasattr(stream,'write') or not hasattr(stream,'flush'): - stream = fallback + if fallback is not None: + stream = fallback + else: + raise ValueError("fallback required, but not specified") self.stream = stream self._swrite = stream.write - self.flush = stream.flush - + + # clone all methods not overridden: + def clone(meth): + return not hasattr(self, meth) and not meth.startswith('_') + for meth in filter(clone, dir(stream)): + setattr(self, meth, getattr(stream, meth)) + def write(self,data): try: self._swrite(data) @@ -46,11 +54,21 @@ def write(self,data): # if we get here, something is seriously broken. print('ERROR - failed to write data to stream:', self.stream, file=sys.stderr) + + def writelines(self, lines): + if isinstance(lines, basestring): + lines = [lines] + for line in lines: + self.write(line) # This class used to have a writeln method, but regular files and streams # in Python don't have this method. We need to keep this completely # compatible so we removed it. + @property + def closed(self): + return self.stream.closed + def close(self): pass @@ -65,10 +83,15 @@ class IOTerm: # In the future, having IPython channel all its I/O operations through # this class will make it easier to embed it into other environments which # are not a normal terminal (such as a GUI-based shell) - def __init__(self, cin=None, cout=None, cerr=None): - self.cin = IOStream(cin, sys.stdin) - self.cout = IOStream(cout, sys.stdout) - self.cerr = IOStream(cerr, sys.stderr) + def __init__(self, stdin=None, stdout=None, stderr=None): + self.stdin = IOStream(stdin, sys.stdin) + self.stdout = IOStream(stdout, sys.stdout) + self.stderr = IOStream(stderr, sys.stderr) + +# setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr +stdin = IOStream(sys.stdin) +stdout = IOStream(sys.stdout) +stderr = IOStream(sys.stderr) class Tee(object): diff --git a/IPython/utils/tests/test_io.py b/IPython/utils/tests/test_io.py index c47e7889197..59fdfc503e6 100644 --- a/IPython/utils/tests/test_io.py +++ b/IPython/utils/tests/test_io.py @@ -15,6 +15,7 @@ import sys from cStringIO import StringIO +from subprocess import Popen, PIPE import nose.tools as nt @@ -59,3 +60,12 @@ def test(self): for chan in ['stdout', 'stderr']: for check in ['close', 'del']: yield self.tchan(chan, check) + +def test_io_init(): + """Test that io.stdin/out/err exist at startup""" + for name in ('stdin', 'stdout', 'stderr'): + p = Popen([sys.executable, '-c', "from IPython.utils import io;print io.%s.__class__"%name], + stdout=PIPE) + p.wait() + classname = p.stdout.read().strip() + nt.assert_equals(classname, 'IPython.utils.io.IOStream') diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index bc9edd39fbf..aabdbf7c364 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -16,7 +16,7 @@ import sys -import IPython.utils.io +from IPython.utils import io #----------------------------------------------------------------------------- # Code @@ -25,7 +25,7 @@ def warn(msg,level=2,exit_val=1): """Standard warning printer. Gives formatting consistency. - Output is sent to IPython.utils.io.Term.cerr (sys.stderr by default). + Output is sent to io.stderr (sys.stderr by default). Options: @@ -41,9 +41,9 @@ def warn(msg,level=2,exit_val=1): if level>0: header = ['','','WARNING: ','ERROR: ','FATAL ERROR: '] - print >> IPython.utils.io.Term.cerr, '%s%s' % (header[level],msg) + print >> io.stderr, '%s%s' % (header[level],msg) if level == 4: - print >> IPython.utils.io.Term.cerr,'Exiting.\n' + print >> io.stderr,'Exiting.\n' sys.exit(exit_val)