From a1312bc629abb5c09d15a20844d629b0a6ac292b 2007-09-07 07:44:16 From: fperez Date: 2007-09-07 07:44:16 Subject: [PATCH] - Fixes for doctest support. Need more testing, esp. to be sure they don't introduce any side-effects, since I'm messing with the FakeModule object which Pickle and others depend on. - Small fixes in object inspection. - Restored a number of magics that should NOT have been moved out to ipy_legacy. --- diff --git a/IPython/Extensions/ipy_legacy.py b/IPython/Extensions/ipy_legacy.py index 3a50aae..e59a5db 100644 --- a/IPython/Extensions/ipy_legacy.py +++ b/IPython/Extensions/ipy_legacy.py @@ -16,58 +16,6 @@ import os,sys from IPython.genutils import * -# use ? -def magic_pdef(self, parameter_s='', namespaces=None): - """Print the definition header for any callable object. - - If the object is a class, print the constructor information.""" - self._inspect('pdef',parameter_s, namespaces) - -ip.expose_magic("pdef", magic_pdef) - -# use ? -def magic_pdoc(self, parameter_s='', namespaces=None): - """Print the docstring for an object. - - If the given object is a class, it will print both the class and the - constructor docstrings.""" - self._inspect('pdoc',parameter_s, namespaces) - -ip.expose_magic("pdoc", magic_pdoc) - -# use ?? -def magic_psource(self, parameter_s='', namespaces=None): - """Print (or run through pager) the source code for an object.""" - self._inspect('psource',parameter_s, namespaces) - -ip.expose_magic("pdoc", magic_psource) - -# use ? -def magic_pfile(self, parameter_s=''): - """Print (or run through pager) the file where an object is defined. - - The file opens at the line where the object definition begins. IPython - will honor the environment variable PAGER if set, and otherwise will - do its best to print the file in a convenient form. - - If the given argument is not an object currently defined, IPython will - try to interpret it as a filename (automatically adding a .py extension - if needed). You can thus use %pfile as a syntax highlighting code - viewer.""" - - # first interpret argument as an object name - out = self._inspect('pfile',parameter_s) - # if not, try the input as a filename - if out == 'not found': - try: - filename = get_py_filename(parameter_s) - except IOError,msg: - print msg - return - page(self.shell.inspector.format(file(filename).read())) - -ip.expose_magic("pfile", magic_pfile) - # use rehashx def magic_rehash(self, parameter_s = ''): @@ -97,40 +45,6 @@ def magic_rehash(self, parameter_s = ''): ip.expose_magic("rehash", magic_rehash) -#use cd - -def magic_dhist(self, parameter_s=''): - """Print your history of visited directories. - - %dhist -> print full history\\ - %dhist n -> print last n entries only\\ - %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\ - - This history is automatically maintained by the %cd command, and - always available as the global list variable _dh. You can use %cd - - to go to directory number .""" - - dh = self.shell.user_ns['_dh'] - if parameter_s: - try: - args = map(int,parameter_s.split()) - except: - self.arg_err(Magic.magic_dhist) - return - if len(args) == 1: - ini,fin = max(len(dh)-(args[0]),0),len(dh) - elif len(args) == 2: - ini,fin = args - else: - self.arg_err(Magic.magic_dhist) - return - else: - ini,fin = 0,len(dh) - nlprint(dh, - header = 'Directory history (kept in _dh)', - start=ini,stop=fin) - -ip.expose_magic("dhist", magic_dhist) - # Exit def magic_Quit(self, parameter_s=''): """Exit IPython without confirmation (like %Exit).""" @@ -146,107 +60,3 @@ def magic_p(self, parameter_s=''): exec 'print ' + parameter_s in self.shell.user_ns ip.expose_magic("p", magic_p) - -# up + enter. One char magic. -def magic_r(self, parameter_s=''): - """Repeat previous input. - - If given an argument, repeats the previous command which starts with - the same string, otherwise it just repeats the previous input. - - Shell escaped commands (with ! as first character) are not recognized - by this system, only pure python code and magic commands. - """ - - start = parameter_s.strip() - esc_magic = self.shell.ESC_MAGIC - # Identify magic commands even if automagic is on (which means - # the in-memory version is different from that typed by the user). - if self.shell.rc.automagic: - start_magic = esc_magic+start - else: - start_magic = start - # Look through the input history in reverse - for n in range(len(self.shell.input_hist)-2,0,-1): - input = self.shell.input_hist[n] - # skip plain 'r' lines so we don't recurse to infinity - if input != '_ip.magic("r")\n' and \ - (input.startswith(start) or input.startswith(start_magic)): - #print 'match',`input` # dbg - print 'Executing:',input, - self.shell.runlines(input) - return - print 'No previous input matching `%s` found.' % start - -ip.expose_magic("r", magic_r) - - -# use _ip.option.automagic - -def magic_automagic(self, parameter_s = ''): - """Make magic functions callable without having to type the initial %. - - Without argumentsl toggles on/off (when off, you must call it as - %automagic, of course). With arguments it sets the value, and you can - use any of (case insensitive): - - - on,1,True: to activate - - - off,0,False: to deactivate. - - Note that magic functions have lowest priority, so if there's a - variable whose name collides with that of a magic fn, automagic won't - work for that function (you get the variable instead). However, if you - delete the variable (del var), the previously shadowed magic function - becomes visible to automagic again.""" - - rc = self.shell.rc - arg = parameter_s.lower() - if parameter_s in ('on','1','true'): - rc.automagic = True - elif parameter_s in ('off','0','false'): - rc.automagic = False - else: - rc.automagic = not rc.automagic - print '\n' + Magic.auto_status[rc.automagic] - -ip.expose_magic("automagic", magic_automagic) - -# use _ip.options.autocall -def magic_autocall(self, parameter_s = ''): - """Make functions callable without having to type parentheses. - - Usage: - - %autocall [mode] - - The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the - value is toggled on and off (remembering the previous state).""" - - rc = self.shell.rc - - if parameter_s: - arg = int(parameter_s) - else: - arg = 'toggle' - - if not arg in (0,1,2,'toggle'): - error('Valid modes: (0->Off, 1->Smart, 2->Full') - return - - if arg in (0,1,2): - rc.autocall = arg - else: # toggle - if rc.autocall: - self._magic_state.autocall_save = rc.autocall - rc.autocall = 0 - else: - try: - rc.autocall = self._magic_state.autocall_save - except AttributeError: - rc.autocall = self._magic_state.autocall_save = 1 - - print "Automatic calling is:",['OFF','Smart','Full'][rc.autocall] - -ip.expose_magic("autocall", magic_autocall) - diff --git a/IPython/FakeModule.py b/IPython/FakeModule.py index f40da06..588934c 100644 --- a/IPython/FakeModule.py +++ b/IPython/FakeModule.py @@ -5,7 +5,7 @@ Class which mimics a module. Needed to allow pickle to correctly resolve namespaces during IPython sessions. -$Id: FakeModule.py 2169 2007-03-23 06:09:43Z fperez $""" +$Id: FakeModule.py 2723 2007-09-07 07:44:16Z fperez $""" #***************************************************************************** # Copyright (C) 2002-2004 Fernando Perez. @@ -14,7 +14,9 @@ $Id: FakeModule.py 2169 2007-03-23 06:09:43Z fperez $""" # the file COPYING, distributed as part of this software. #***************************************************************************** -class FakeModule: +import types + +class FakeModule(types.ModuleType): """Simple class with attribute access to fake a module. This is not meant to replace a module, but to allow inserting a fake @@ -23,7 +25,6 @@ class FakeModule: sessions. Do NOT use this code for anything other than this IPython private hack.""" - def __init__(self,adict): # It seems pydoc (and perhaps others) needs any module instance to @@ -33,14 +34,14 @@ class FakeModule: return 1 adict['__nonzero__'] = __nonzero__ - self.__dict__ = adict + self._dict_ = adict # modules should have a __file__ attribute adict.setdefault('__file__',__file__) def __getattr__(self,key): try: - return self.__dict__[key] + return self._dict_[key] except KeyError, e: raise AttributeError("FakeModule object has no attribute %s" % e) diff --git a/IPython/Magic.py b/IPython/Magic.py index 1eebdf3..cfe4ece 100644 --- a/IPython/Magic.py +++ b/IPython/Magic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Magic functions for InteractiveShell. -$Id: Magic.py 2705 2007-09-04 15:10:37Z vivainio $""" +$Id: Magic.py 2723 2007-09-07 07:44:16Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Janko Hauser and @@ -476,6 +476,100 @@ Currently the magic system has the following functions:\n""" self.shell.set_autoindent() print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent] + + def magic_automagic(self, parameter_s = ''): + """Make magic functions callable without having to type the initial %. + + Without argumentsl toggles on/off (when off, you must call it as + %automagic, of course). With arguments it sets the value, and you can + use any of (case insensitive): + + - on,1,True: to activate + + - off,0,False: to deactivate. + + Note that magic functions have lowest priority, so if there's a + variable whose name collides with that of a magic fn, automagic won't + work for that function (you get the variable instead). However, if you + delete the variable (del var), the previously shadowed magic function + becomes visible to automagic again.""" + + rc = self.shell.rc + arg = parameter_s.lower() + if parameter_s in ('on','1','true'): + rc.automagic = True + elif parameter_s in ('off','0','false'): + rc.automagic = False + else: + rc.automagic = not rc.automagic + print '\n' + Magic.auto_status[rc.automagic] + + + def magic_autocall(self, parameter_s = ''): + """Make functions callable without having to type parentheses. + + Usage: + + %autocall [mode] + + The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the + value is toggled on and off (remembering the previous state). + + In more detail, these values mean: + + 0 -> fully disabled + + 1 -> active, but do not apply if there are no arguments on the line. + + In this mode, you get: + + In [1]: callable + Out[1]: + + In [2]: callable 'hello' + ------> callable('hello') + Out[2]: False + + 2 -> Active always. Even if no arguments are present, the callable + object is called: + + In [4]: callable + ------> callable() + + Note that even with autocall off, you can still use '/' at the start of + a line to treat the first argument on the command line as a function + and add parentheses to it: + + In [8]: /str 43 + ------> str(43) + Out[8]: '43' + """ + + rc = self.shell.rc + + if parameter_s: + arg = int(parameter_s) + else: + arg = 'toggle' + + if not arg in (0,1,2,'toggle'): + error('Valid modes: (0->Off, 1->Smart, 2->Full') + return + + if arg in (0,1,2): + rc.autocall = arg + else: # toggle + if rc.autocall: + self._magic_state.autocall_save = rc.autocall + rc.autocall = 0 + else: + try: + rc.autocall = self._magic_state.autocall_save + except AttributeError: + rc.autocall = self._magic_state.autocall_save = 1 + + print "Automatic calling is:",['OFF','Smart','Full'][rc.autocall] + def magic_system_verbose(self, parameter_s = ''): """Set verbose printing of system calls. @@ -544,7 +638,47 @@ Currently the magic system has the following functions:\n""" else: self._inspect('pinfo', oname, detail_level=detail_level, namespaces=namespaces) - + + def magic_pdef(self, parameter_s='', namespaces=None): + """Print the definition header for any callable object. + + If the object is a class, print the constructor information.""" + self._inspect('pdef',parameter_s, namespaces) + + def magic_pdoc(self, parameter_s='', namespaces=None): + """Print the docstring for an object. + + If the given object is a class, it will print both the class and the + constructor docstrings.""" + self._inspect('pdoc',parameter_s, namespaces) + + def magic_psource(self, parameter_s='', namespaces=None): + """Print (or run through pager) the source code for an object.""" + self._inspect('psource',parameter_s, namespaces) + + def magic_pfile(self, parameter_s=''): + """Print (or run through pager) the file where an object is defined. + + The file opens at the line where the object definition begins. IPython + will honor the environment variable PAGER if set, and otherwise will + do its best to print the file in a convenient form. + + If the given argument is not an object currently defined, IPython will + try to interpret it as a filename (automatically adding a .py extension + if needed). You can thus use %pfile as a syntax highlighting code + viewer.""" + + # first interpret argument as an object name + out = self._inspect('pfile',parameter_s) + # if not, try the input as a filename + if out == 'not found': + try: + filename = get_py_filename(parameter_s) + except IOError,msg: + print msg + return + page(self.shell.inspector.format(file(filename).read())) + def _inspect(self,meth,oname,namespaces=None,**kw): """Generic interface to the inspector system. @@ -2566,6 +2700,38 @@ Defaulting color scheme to 'NoColor'""" return self.shell.dir_stack[:] + def magic_dhist(self, parameter_s=''): + """Print your history of visited directories. + + %dhist -> print full history\\ + %dhist n -> print last n entries only\\ + %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\ + + This history is automatically maintained by the %cd command, and + always available as the global list variable _dh. You can use %cd - + to go to directory number .""" + + dh = self.shell.user_ns['_dh'] + if parameter_s: + try: + args = map(int,parameter_s.split()) + except: + self.arg_err(Magic.magic_dhist) + return + if len(args) == 1: + ini,fin = max(len(dh)-(args[0]),0),len(dh) + elif len(args) == 2: + ini,fin = args + else: + self.arg_err(Magic.magic_dhist) + return + else: + ini,fin = 0,len(dh) + nlprint(dh, + header = 'Directory history (kept in _dh)', + start=ini,stop=fin) + + def magic_sc(self, parameter_s=''): """Shell capture - execute a shell command and capture its output. @@ -2769,6 +2935,36 @@ Defaulting color scheme to 'NoColor'""" self.shell.jobs.new(parameter_s,self.shell.user_ns) + def magic_r(self, parameter_s=''): + """Repeat previous input. + + If given an argument, repeats the previous command which starts with + the same string, otherwise it just repeats the previous input. + + Shell escaped commands (with ! as first character) are not recognized + by this system, only pure python code and magic commands. + """ + + start = parameter_s.strip() + esc_magic = self.shell.ESC_MAGIC + # Identify magic commands even if automagic is on (which means + # the in-memory version is different from that typed by the user). + if self.shell.rc.automagic: + start_magic = esc_magic+start + else: + start_magic = start + # Look through the input history in reverse + for n in range(len(self.shell.input_hist)-2,0,-1): + input = self.shell.input_hist[n] + # skip plain 'r' lines so we don't recurse to infinity + if input != '_ip.magic("r")\n' and \ + (input.startswith(start) or input.startswith(start_magic)): + #print 'match',`input` # dbg + print 'Executing:',input, + self.shell.runlines(input) + return + print 'No previous input matching `%s` found.' % start + def magic_bookmark(self, parameter_s=''): """Manage IPython's bookmark system. diff --git a/IPython/OInspect.py b/IPython/OInspect.py index 67b0502..f41f13a 100644 --- a/IPython/OInspect.py +++ b/IPython/OInspect.py @@ -6,7 +6,7 @@ Uses syntax highlighting for presenting the various information elements. Similar in spirit to the inspect module, but all calls take a name argument to reference the name under which an object is being read. -$Id: OInspect.py 2717 2007-09-05 19:49:42Z vivainio $ +$Id: OInspect.py 2723 2007-09-07 07:44:16Z fperez $ """ #***************************************************************************** @@ -238,8 +238,7 @@ class Inspector: if inspect.isclass(obj): header = self.__head('Class constructor information:\n') obj = obj.__init__ - elif type(obj) is types.InstanceType or \ - isinstance(obj,object): + elif type(obj) is types.InstanceType: obj = obj.__call__ output = self.__getdef(obj,oname) @@ -408,8 +407,7 @@ class Inspector: fname = inspect.getabsfile(obj) if fname.endswith(''): fname = 'Dynamically generated function. No source code available.' - if (fname.endswith('.so') or fname.endswith('.dll') or - not os.path.isfile(fname)): + if (fname.endswith('.so') or fname.endswith('.dll')): binary_file = True out.writeln(header('File:\t\t')+fname) except: @@ -426,11 +424,11 @@ class Inspector: # avoid repetitions). If source fails, we add them back, see below. if ds and detail_level == 0: out.writeln(header('Docstring:\n') + indent(ds)) - # Original source code for any callable if detail_level: - # Flush the source cache because inspect can return out-of-date source + # Flush the source cache because inspect can return out-of-date + # source linecache.checkcache() source_success = False try: diff --git a/IPython/ipmaker.py b/IPython/ipmaker.py index 5db3786..1676e0e 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 2710 2007-09-04 21:10:10Z vivainio $""" +$Id: ipmaker.py 2723 2007-09-07 07:44:16Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2006 Fernando Perez. @@ -112,7 +112,7 @@ def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1, "IPython %s -- An enhanced Interactive Python." % (__version__,), """\ -? -> Introduction to IPython's features +? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object'. ?object also works, ?? prints more. diff --git a/IPython/usage.py b/IPython/usage.py index 9741db4..1d5cf35 100644 --- a/IPython/usage.py +++ b/IPython/usage.py @@ -6,7 +6,7 @@ # the file COPYING, distributed as part of this software. #***************************************************************************** -# $Id: usage.py 2710 2007-09-04 21:10:10Z vivainio $ +# $Id: usage.py 2723 2007-09-07 07:44:16Z fperez $ from IPython import Release __author__ = '%s <%s>' % Release.authors['Fernando'] @@ -602,8 +602,10 @@ quick_reference = r""" IPython -- An enhanced Interactive Python - Quick Reference Card ================================================================ -obj?, obj??, ?obj,??obj : Get help, or more help for object -?os.p* : List names in os starting with p +obj?, obj?? : Get help, or more help for object (also works as + ?obj, ??obj). +?foo.*abc* : List names in 'foo' containing 'abc' in them. +%magic : Information about IPython's 'magic' % functions. Magic functions are prefixed by %, and typically take their arguments without parentheses, quotes or even commas for convenience. diff --git a/doc/ChangeLog b/doc/ChangeLog index 3447fe3..96e2d50 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,35 @@ +2007-09-07 Fernando Perez + + * IPython/OInspect.py (Inspector.pinfo): fixed bug that was + preventing source display in certain cases. In reality I think + the problem is with Ubuntu's Python build, but this change works + around the issue in some cases (not in all, unfortunately). I'd + filed a Python bug on this with more details, but in the change of + bug trackers it seems to have been lost. + + * IPython/Magic.py (magic_dhist): restore %dhist. No, cd -TAB is + not the same, it's not self-documenting, doesn't allow range + selection, and sorts alphabetically instead of numerically. + (magic_r): restore %r. No, "up + enter. One char magic" is not + the same thing, since %r takes parameters to allow fast retrieval + of old commands. I've received emails from users who use this a + LOT, so it stays. + (magic_automagic): restore %automagic. "use _ip.option.automagic" + is not a valid replacement b/c it doesn't provide an complete + explanation (which the automagic docstring does). + (magic_autocall): restore %autocall, with improved docstring. + Same argument as for others, "use _ip.options.autocall" is not a + valid replacement. + (magic_pdef): restore %pdef & friends. Used widely, mentioned in + tutorials and online docs. + +2007-09-06 Fernando Perez + + * IPython/usage.py (quick_reference): mention magics in quickref, + modified main banner to mention %quickref. + + * IPython/FakeModule.py (FakeModule): fixes for doctest compatibility. + 2007-09-06 Ville Vainio * ipy_rehashdir.py, ipy_workdir.py, ipy_fsops.py, iplib.py: