From 932ee94045d83f9e3663f3b90f3956c62439e76f 2007-12-28 08:32:59 From: fperez Date: 2007-12-28 08:32:59 Subject: [PATCH] - New dtutils module for running doctests interactively with more convenience. Not fully fleshed yet, but already useful. Needs better support for specifying the package where doctests should be run. --- diff --git a/IPython/Magic.py b/IPython/Magic.py index 44daebe..c9747ab 100644 --- a/IPython/Magic.py +++ b/IPython/Magic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Magic functions for InteractiveShell. -$Id: Magic.py 2874 2007-11-26 06:50:42Z fperez $""" +$Id: Magic.py 2899 2007-12-28 08:32:59Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Janko Hauser and @@ -1566,8 +1566,7 @@ Currently the magic system has the following functions:\n""" stats = None try: - if self.shell.has_readline: - self.shell.savehist() + self.shell.savehist() if opts.has_key('p'): stats = self.magic_prun('',0,opts,arg_lst,prog_ns) diff --git a/IPython/Prompts.py b/IPython/Prompts.py index 214ea02..6ad6a13 100644 --- a/IPython/Prompts.py +++ b/IPython/Prompts.py @@ -2,7 +2,7 @@ """ Classes for handling input/output prompts. -$Id: Prompts.py 2855 2007-11-06 06:53:49Z vivainio $""" +$Id: Prompts.py 2899 2007-12-28 08:32:59Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez @@ -323,6 +323,13 @@ class BasePrompt(object): else: return os.sep + def __nonzero__(self): + """Implement boolean behavior. + + Checks whether the p_str attribute is non-empty""" + + return bool(self.p_template) + class Prompt1(BasePrompt): """Input interactive prompt similar to Mathematica's.""" diff --git a/IPython/dtutils.py b/IPython/dtutils.py new file mode 100644 index 0000000..37e7aa2 --- /dev/null +++ b/IPython/dtutils.py @@ -0,0 +1,137 @@ +"""Doctest-related utilities for IPython. + +For most common uses, all you should need to run is:: + + from IPython.dtutils import idoctest + +See the idoctest docstring below for usage details. +""" + +import doctest +import sys + +import IPython.ipapi +ip = IPython.ipapi.get() + +def rundoctest(text,ns=None,eraise=False): + """Run a the input source as a doctest, in the caller's namespace. + + :Parameters: + text : str + Source to execute. + + :Keywords: + ns : dict (None) + Namespace where the code should be executed. If not given, the + caller's locals and globals are used. + eraise : bool (False) + If true, immediately raise any exceptions instead of reporting them at + the end. This allows you to then do interactive debugging via + IPython's facilities (use %debug after the fact, or with %pdb for + automatic activation). + """ + + name = 'interactive doctest' + filename = '' + + if eraise: + runner = doctest.DebugRunner() + else: + runner = doctest.DocTestRunner() + + parser = doctest.DocTestParser() + if ns is None: + f = sys._getframe(1) + ns = f.f_globals.copy() + ns.update(f.f_locals) + + test = parser.get_doctest(text,ns,name,filename,0) + runner.run(test) + runner.summarize(True) + + +def idoctest(ns=None,eraise=False): + """Interactively prompt for input and run it as a doctest. + + To finish entering input, enter two blank lines or Ctrl-D (EOF). If you + use Ctrl-C, the example is aborted and all input discarded. + + :Keywords: + ns : dict (None) + Namespace where the code should be executed. If not given, the IPython + interactive namespace is used. + eraise : bool (False) + If true, immediately raise any exceptions instead of reporting them at + the end. This allows you to then do interactive debugging via + IPython's facilities (use %debug after the fact, or with %pdb for + automatic activation). + end_mark : str ('--') + String to explicitly indicate the end of input. + + """ + + inlines = [] + empty_lines = 0 # count consecutive empty lines + run_test = True + + if ns is None: + ns = ip.user_ns + + ip.IP.savehist() + try: + while True: + line = raw_input() + if not line or line.isspace(): + empty_lines += 1 + else: + empty_lines = 0 + + if empty_lines>=2: + break + + inlines.append(line) + except EOFError: + pass + except KeyboardInterrupt: + print "KeyboardInterrupt - Discarding input." + run_test = False + + ip.IP.reloadhist() + + if run_test: + # Extra blank line at the end to ensure that the final docstring has a + # closing newline + inlines.append('') + rundoctest('\n'.join(inlines),ns,eraise) + + +# For debugging of this module itself. +if __name__ == "__main__": + t = """ + >>> for i in range(10): + ... print i, + ... + 0 1 2 3 4 5 6 7 8 9 + """ + + t2 = """ + A simple example:: + + >>> for i in range(10): + ... print i, + ... + 0 1 2 3 4 5 6 7 8 9 + + Some more details:: + + >>> print "hello" + hello + """ + + t3 = """ + A failing example:: + + >>> x=1 + >>> x+1 + 3 + """ diff --git a/IPython/hooks.py b/IPython/hooks.py index a272173..a80c91e 100644 --- a/IPython/hooks.py +++ b/IPython/hooks.py @@ -32,7 +32,7 @@ ip.set_hook('editor', calljed) You can then enable the functionality by doing 'import myiphooks' somewhere in your configuration files or ipython command line. -$Id: hooks.py 1854 2006-10-30 19:54:25Z vivainio $""" +$Id: hooks.py 2899 2007-12-28 08:32:59Z fperez $""" #***************************************************************************** # Copyright (C) 2005 Fernando Perez. @@ -213,5 +213,3 @@ def generate_prompt(self, is_continuation): def generate_output_prompt(self): ip = self.api return str(ip.IP.outputcache.prompt_out) - - \ No newline at end of file diff --git a/IPython/iplib.py b/IPython/iplib.py index 58d529b..3a6bf08 100644 --- a/IPython/iplib.py +++ b/IPython/iplib.py @@ -6,7 +6,7 @@ Requires Python 2.3 or newer. This file contains all the classes and helper functions specific to IPython. -$Id: iplib.py 2894 2007-12-13 20:34:23Z vivainio $ +$Id: iplib.py 2899 2007-12-28 08:32:59Z fperez $ """ #***************************************************************************** @@ -1247,6 +1247,10 @@ want to merge them back into the new files.""" % locals() def savehist(self): """Save input history to a file (via readline library).""" + + if not self.has_readline: + return + try: self.readline.write_history_file(self.histfile) except: diff --git a/IPython/ipmaker.py b/IPython/ipmaker.py index dadac4c..4abd39d 100644 --- a/IPython/ipmaker.py +++ b/IPython/ipmaker.py @@ -6,7 +6,7 @@ Requires Python 2.1 or better. This file contains the main make_IPython() starter function. -$Id: ipmaker.py 2887 2007-12-12 08:28:43Z fperez $""" +$Id: ipmaker.py 2899 2007-12-28 08:32:59Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez. @@ -190,25 +190,26 @@ object? -> Details about 'object'. ?object also works, ?? prints more. autoindent = 0, automagic = 1, banner = 1, - cache_size = 1000, c = '', + cache_size = 1000, classic = 0, - colors = 'NoColor', color_info = 0, + colors = 'NoColor', confirm_exit = 1, debug = 0, deep_reload = 0, editor = '0', + gthread = 0, help = 0, interact = 1, ipythondir = ipythondir_def, log = 0, logfile = '', logplay = '', - multi_line_specials = 1, messages = 1, - object_info_string_level = 0, + multi_line_specials = 1, nosep = 0, + object_info_string_level = 0, pdb = 0, pprint = 0, profile = '', @@ -216,31 +217,30 @@ object? -> Details about 'object'. ?object also works, ?? prints more. prompt_in2 = ' .\\D.: ', prompt_out = 'Out[\\#]: ', prompts_pad_left = 1, + pylab = 0, pylab_import_all = 1, - quiet = 0, + q4thread = 0, + qthread = 0, quick = 0, + quiet = 0, + rcfile = 'ipythonrc' + rc_suffix, readline = 1, readline_merge_completions = 1, readline_omit__names = 0, - rcfile = 'ipythonrc' + rc_suffix, screen_length = 0, separate_in = '\n', separate_out = '\n', separate_out2 = '', system_header = 'IPython system call: ', system_verbose = 0, - gthread = 0, - qthread = 0, - q4thread = 0, - wthread = 0, - pylab = 0, term_title = 1, tk = 0, upgrade = 0, Version = 0, - xmode = 'Verbose', wildcards_case_sensitive = 1, + wthread = 0, wxversion = '0', + xmode = 'Context', magic_docstrings = 0, # undocumented, for doc generation ) diff --git a/doc/ChangeLog b/doc/ChangeLog index 02b2c22..badb01a 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,9 +1,21 @@ +2007-12-28 Fernando Perez + + * IPython/dtutils.py: Add utilities for interactively running + doctests. Still needs work to more easily handle the namespace of + the package one may be working on, but the basics are in place. + 2007-12-20 Ville Vainio * completer.py, generics.py(complete_object): Allow custom complers based on python objects via simplegeneric. See generics.py / my_demo_complete_object +2007-12-13 Fernando Perez + + * IPython/Prompts.py (BasePrompt.__nonzero__): add proper boolean + behavior to prompt objects, useful for display hooks to adjust + themselves depending on whether prompts will be there or not. + 2007-12-13 Ville Vainio * iplib.py(raw_input): unix readline does not allow unicode in