diff --git a/IPython/core/completer.py b/IPython/core/completer.py index dd236614af6..52fa2168c31 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -53,15 +53,14 @@ # proper procedure is to maintain its copyright as belonging to the Python # Software Foundation (in addition to my own, for all new code). # -# Copyright (C) 2008-2011 IPython Development Team -# Copyright (C) 2001-2007 Fernando Perez. +# Copyright (C) 2008 IPython Development Team +# Copyright (C) 2001 Fernando Perez. # Copyright (C) 2001 Python Software Foundation, www.python.org # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. # #***************************************************************************** -from __future__ import print_function #----------------------------------------------------------------------------- # Imports @@ -178,11 +177,14 @@ def compress_user(path, tilde_expand, tilde_val): else: return path + class Bunch(object): pass + DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' GREEDY_DELIMS = ' \r\n' + class CompletionSplitter(object): """An object to split an input line in a manner similar to readline. @@ -194,7 +196,7 @@ class CompletionSplitter(object): What characters are used as splitting delimiters can be controlled by setting the `delims` attribute (this is a property that internally - automatically builds the necessary """ + automatically builds the necessary regular expression)""" # Private interface @@ -212,19 +214,21 @@ class CompletionSplitter(object): def __init__(self, delims=None): delims = CompletionSplitter._delims if delims is None else delims - self.set_delims(delims) + self.delims = delims + + @property + def delims(self): + """Return the string of delimiter characters.""" + return self._delims - def set_delims(self, delims): + @delims.setter + def delims(self, delims): """Set the delimiters for line splitting.""" expr = '[' + ''.join('\\'+ c for c in delims) + ']' self._delim_re = re.compile(expr) self._delims = delims self._delim_expr = expr - def get_delims(self): - """Return the string of delimiter characters.""" - return self._delims - def split_line(self, line, cursor_pos=None): """Split a line of text with a cursor at the given position. """ @@ -377,7 +381,7 @@ def attr_matches(self, text): def get__all__entries(obj): """returns the strings in the __all__ attribute""" try: - words = getattr(obj,'__all__') + words = getattr(obj, '__all__') except: return [] @@ -390,12 +394,12 @@ class IPCompleter(Completer): def _greedy_changed(self, name, old, new): """update the splitter and readline delims when greedy is changed""" if new: - self.splitter.set_delims(GREEDY_DELIMS) + self.splitter.delims = GREEDY_DELIMS else: - self.splitter.set_delims(DELIMS) + self.splitter.delims = DELIMS if self.readline: - self.readline.set_completer_delims(self.splitter.get_delims()) + self.readline.set_completer_delims(self.splitter.delims) merge_completions = CBool(True, config=True, help="""Whether to merge completion results into a single list @@ -472,7 +476,7 @@ def __init__(self, shell=None, namespace=None, global_namespace=None, # List where completion matches will be stored self.matches = [] - self.shell = shell.shell + self.shell = shell if alias_table is None: alias_table = {} self.alias_table = alias_table @@ -601,11 +605,23 @@ def magic_matches(self, text): """Match magics""" #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg # Get all shell magics now rather than statically, so magics loaded at - # runtime show up too - magics = self.shell.lsmagic() + # runtime show up too. + lsm = self.shell.magics_manager.lsmagic() + line_magics = lsm['line'] + cell_magics = lsm['cell'] pre = self.magic_escape - baretext = text.lstrip(pre) - return [ pre+m for m in magics if m.startswith(baretext)] + pre2 = pre+pre + + # Completion logic: + # - user gives %%: only do cell magics + # - user gives %: do both line and cell magics + # - no prefix: do both + # In other words, line magics are skipped if the user gives %% explicitly + bare_text = text.lstrip(pre) + comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)] + if not text.startswith(pre2): + comp += [ pre+m for m in line_magics if m.startswith(bare_text)] + return comp def alias_matches(self, text): """Match internal system aliases""" @@ -820,7 +836,7 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): self.line_buffer = line_buffer self.text_until_cursor = self.line_buffer[:cursor_pos] - #io.rprint('\nCOMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg + #io.rprint('COMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg # Start with a clean slate of completions self.matches[:] = [] diff --git a/IPython/core/history.py b/IPython/core/history.py index 6c51f73299b..317f76c1c51 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -15,7 +15,6 @@ # Stdlib imports import atexit import datetime -from io import open as io_open import os import re try: @@ -25,11 +24,8 @@ import threading # Our own packages -from IPython.core.error import StdinNotImplementedError from IPython.config.configurable import Configurable from IPython.external.decorator import decorator -from IPython.testing.skipdoctest import skip_doctest -from IPython.utils import io from IPython.utils.path import locate_profile from IPython.utils.traitlets import Bool, Dict, Instance, Integer, List, Unicode from IPython.utils.warn import warn @@ -53,7 +49,8 @@ def __enter__(self, *args, **kwargs): def __exit__(self, *args, **kwargs): pass - + + @decorator def needs_sqlite(f,*a,**kw): """return an empty list in the absence of sqlite""" @@ -62,6 +59,7 @@ def needs_sqlite(f,*a,**kw): else: return f(*a,**kw) + class HistoryAccessor(Configurable): """Access the history database without adding to it. @@ -72,19 +70,18 @@ class HistoryAccessor(Configurable): hist_file = Unicode(config=True, help="""Path to file to use for SQLite history database. - By default, IPython will put the history database in the IPython profile - directory. If you would rather share one history among profiles, - you ca set this value in each, so that they are consistent. + By default, IPython will put the history database in the IPython + profile directory. If you would rather share one history among + profiles, you can set this value in each, so that they are consistent. - Due to an issue with fcntl, SQLite is known to misbehave on some NFS mounts. - If you see IPython hanging, try setting this to something on a local disk, - e.g:: + Due to an issue with fcntl, SQLite is known to misbehave on some NFS + mounts. If you see IPython hanging, try setting this to something on a + local disk, e.g:: ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite """) - # The SQLite database if sqlite3: db = Instance(sqlite3.Connection) @@ -152,7 +149,8 @@ def _get_hist_file_name(self, profile='default'): def init_db(self): """Connect to the database, and create tables if necessary.""" # use detect_types so that timestamps return datetime objects - self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES) + self.db = sqlite3.connect(self.hist_file, + detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES) self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer primary key autoincrement, start timestamp, end timestamp, num_cmds integer, remark text)""") @@ -215,7 +213,8 @@ def get_session_info(self, session=0): Returns ------- - (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode]) + (session_id [int], start [datetime], end [datetime], num_cmds [int], + remark [unicode]) Sessions that are running or did not exit cleanly will have `end=None` and `num_cmds=None`. @@ -511,7 +510,8 @@ def get_range(self, session=0, start=1, stop=None, raw=True,output=False): session += self.session_number if session==self.session_number: # Current session return self._get_range_session(start, stop, raw, output) - return super(HistoryManager, self).get_range(session, start, stop, raw, output) + return super(HistoryManager, self).get_range(session, start, stop, raw, + output) ## ---------------------------- ## Methods for storing history: @@ -610,7 +610,9 @@ def writeout_cache(self, conn=None): print("ERROR! Session/line number was not unique in", "database. History logging moved to new session", self.session_number) - try: # Try writing to the new session. If this fails, don't recurse + try: + # Try writing to the new session. If this fails, don't + # recurse self._writeout_input_cache(conn) except sqlite3.IntegrityError: pass @@ -676,6 +678,7 @@ def stop(self): (?P\d+))? $""", re.VERBOSE) + def extract_hist_ranges(ranges_str): """Turn a string of history ranges into 3-tuples of (session, start, stop). @@ -708,270 +711,11 @@ def extract_hist_ranges(ranges_str): yield (sess, 1, None) yield (endsess, 1, end) + def _format_lineno(session, line): """Helper function to format line numbers properly.""" if session == 0: return str(line) return "%s#%s" % (session, line) -@skip_doctest -def magic_history(self, parameter_s = ''): - """Print input history (_i variables), with most recent last. - - %history [-o -p -t -n] [-f filename] [range | -g pattern | -l number] - - By default, input history is printed without line numbers so it can be - directly pasted into an editor. Use -n to show them. - - By default, all input history from the current session is displayed. - Ranges of history can be indicated using the syntax: - 4 : Line 4, current session - 4-6 : Lines 4-6, current session - 243/1-5: Lines 1-5, session 243 - ~2/7 : Line 7, session 2 before current - ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line - of 6 sessions ago. - Multiple ranges can be entered, separated by spaces - - The same syntax is used by %macro, %save, %edit, %rerun - - Options: - - -n: print line numbers for each input. - This feature is only available if numbered prompts are in use. - - -o: also print outputs for each input. - - -p: print classic '>>>' python prompts before each input. This is useful - for making documentation, and in conjunction with -o, for producing - doctest-ready output. - - -r: (default) print the 'raw' history, i.e. the actual commands you typed. - - -t: print the 'translated' history, as IPython understands it. IPython - filters your input and converts it all into valid Python source before - executing it (things like magics or aliases are turned into function - calls, for example). With this option, you'll see the native history - instead of the user-entered version: '%cd /' will be seen as - 'get_ipython().magic("%cd /")' instead of '%cd /'. - - -g: treat the arg as a pattern to grep for in (full) history. - This includes the saved history (almost all commands ever written). - Use '%hist -g' to show full saved history (may be very long). - - -l: get the last n lines from all sessions. Specify n as a single arg, or - the default is the last 10 lines. - - -f FILENAME: instead of printing the output to the screen, redirect it to - the given file. The file is always overwritten, though *when it can*, - IPython asks for confirmation first. In particular, running the command - "history -f FILENAME" from the IPython Notebook interface will replace - FILENAME even if it already exists *without* confirmation. - - Examples - -------- - :: - - In [6]: %hist -n 4-6 - 4:a = 12 - 5:print a**2 - 6:%hist -n 4-6 - - """ - - if not self.shell.displayhook.do_full_cache: - print('This feature is only available if numbered prompts are in use.') - return - opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string') - - # For brevity - history_manager = self.shell.history_manager - - def _format_lineno(session, line): - """Helper function to format line numbers properly.""" - if session in (0, history_manager.session_number): - return str(line) - return "%s/%s" % (session, line) - - # Check if output to specific file was requested. - try: - outfname = opts['f'] - except KeyError: - outfile = io.stdout # default - # We don't want to close stdout at the end! - close_at_end = False - else: - if os.path.exists(outfname): - try: - ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname) - except StdinNotImplementedError: - ans = True - if not ans: - print('Aborting.') - return - print("Overwriting file.") - outfile = io_open(outfname, 'w', encoding='utf-8') - close_at_end = True - - print_nums = 'n' in opts - get_output = 'o' in opts - pyprompts = 'p' in opts - # Raw history is the default - raw = not('t' in opts) - - default_length = 40 - pattern = None - - if 'g' in opts: # Glob search - pattern = "*" + args + "*" if args else "*" - hist = history_manager.search(pattern, raw=raw, output=get_output) - print_nums = True - elif 'l' in opts: # Get 'tail' - try: - n = int(args) - except ValueError, IndexError: - n = 10 - hist = history_manager.get_tail(n, raw=raw, output=get_output) - else: - if args: # Get history by ranges - hist = history_manager.get_range_by_str(args, raw, get_output) - else: # Just get history for the current session - hist = history_manager.get_range(raw=raw, output=get_output) - - # We could be displaying the entire history, so let's not try to pull it - # into a list in memory. Anything that needs more space will just misalign. - width = 4 - - for session, lineno, inline in hist: - # Print user history with tabs expanded to 4 spaces. The GUI clients - # use hard tabs for easier usability in auto-indented code, but we want - # to produce PEP-8 compliant history for safe pasting into an editor. - if get_output: - inline, output = inline - inline = inline.expandtabs(4).rstrip() - - multiline = "\n" in inline - line_sep = '\n' if multiline else ' ' - if print_nums: - print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width), - line_sep), file=outfile, end=u'') - if pyprompts: - print(u">>> ", end=u"", file=outfile) - if multiline: - inline = "\n... ".join(inline.splitlines()) + "\n..." - print(inline, file=outfile) - if get_output and output: - print(output, file=outfile) - - if close_at_end: - outfile.close() - - -def magic_rep(self, arg): - r"""Repeat a command, or get command to input line for editing. - - %recall and %rep are equivalent. - - - %recall (no arguments): - - Place a string version of last computation result (stored in the special '_' - variable) to the next input prompt. Allows you to create elaborate command - lines without using copy-paste:: - - In[1]: l = ["hei", "vaan"] - In[2]: "".join(l) - Out[2]: heivaan - In[3]: %rep - In[4]: heivaan_ <== cursor blinking - - %recall 45 - - Place history line 45 on the next input prompt. Use %hist to find - out the number. - - %recall 1-4 - Combine the specified lines into one cell, and place it on the next - input prompt. See %history for the slice syntax. - - %recall foo+bar - - If foo+bar can be evaluated in the user namespace, the result is - placed at the next input prompt. Otherwise, the history is searched - for lines which contain that substring, and the most recent one is - placed at the next input prompt. - """ - if not arg: # Last output - self.set_next_input(str(self.shell.user_ns["_"])) - return - # Get history range - histlines = self.history_manager.get_range_by_str(arg) - cmd = "\n".join(x[2] for x in histlines) - if cmd: - self.set_next_input(cmd.rstrip()) - return - - try: # Variable in user namespace - cmd = str(eval(arg, self.shell.user_ns)) - except Exception: # Search for term in history - histlines = self.history_manager.search("*"+arg+"*") - for h in reversed([x[2] for x in histlines]): - if 'rep' in h: - continue - self.set_next_input(h.rstrip()) - return - else: - self.set_next_input(cmd.rstrip()) - print("Couldn't evaluate or find in history:", arg) - -def magic_rerun(self, parameter_s=''): - """Re-run previous input - - By default, you can specify ranges of input history to be repeated - (as with %history). With no arguments, it will repeat the last line. - - Options: - - -l : Repeat the last n lines of input, not including the - current command. - - -g foo : Repeat the most recent line which contains foo - """ - opts, args = self.parse_options(parameter_s, 'l:g:', mode='string') - if "l" in opts: # Last n lines - n = int(opts['l']) - hist = self.history_manager.get_tail(n) - elif "g" in opts: # Search - p = "*"+opts['g']+"*" - hist = list(self.history_manager.search(p)) - for l in reversed(hist): - if "rerun" not in l[2]: - hist = [l] # The last match which isn't a %rerun - break - else: - hist = [] # No matches except %rerun - elif args: # Specify history ranges - hist = self.history_manager.get_range_by_str(args) - else: # Last line - hist = self.history_manager.get_tail(1) - hist = [x[2] for x in hist] - if not hist: - print("No lines in history match specification") - return - histlines = "\n".join(hist) - print("=== Executing: ===") - print(histlines) - print("=== Output: ===") - self.run_cell("\n".join(hist), store_history=False) - - -def init_ipython(ip): - ip.define_magic("rep", magic_rep) - ip.define_magic("recall", magic_rep) - ip.define_magic("rerun", magic_rerun) - ip.define_magic("hist",magic_history) # Alternative name - ip.define_magic("history",magic_history) - - # XXX - ipy_completers are in quarantine, need to be updated to new apis - #import ipy_completers - #ipy_completers.quick_completer('%hist' ,'-g -t -r -n') diff --git a/IPython/core/hooks.py b/IPython/core/hooks.py index 29028d7b5ec..81340d2b492 100644 --- a/IPython/core/hooks.py +++ b/IPython/core/hooks.py @@ -128,9 +128,9 @@ def __init__(self,commands=None): def __call__(self,*args, **kw): """ Command chain is called just like normal func. - This will call all funcs in chain with the same args as were given to this - function, and return the result of first func that didn't raise - TryNext """ + This will call all funcs in chain with the same args as were given to + this function, and return the result of first func that didn't raise + TryNext""" for prio,cmd in self.chain: #print "prio",prio,"cmd",cmd #dbg diff --git a/IPython/core/inputsplitter.py b/IPython/core/inputsplitter.py index f2e148a0189..c0183d1b95a 100644 --- a/IPython/core/inputsplitter.py +++ b/IPython/core/inputsplitter.py @@ -55,12 +55,11 @@ * Brian Granger """ #----------------------------------------------------------------------------- -# Copyright (C) 2010-2011 The IPython Development Team +# Copyright (C) 2010 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #----------------------------------------------------------------------------- -from __future__ import print_function #----------------------------------------------------------------------------- # Imports @@ -141,6 +140,46 @@ def num_ini_spaces(s): else: return 0 +def last_blank(src): + """Determine if the input source ends in a blank. + + A blank is either a newline or a line consisting of whitespace. + + Parameters + ---------- + src : string + A single or multiline string. + """ + if not src: return False + ll = src.splitlines()[-1] + return (ll == '') or ll.isspace() + + +last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE) +last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE) + +def last_two_blanks(src): + """Determine if the input source ends in two blanks. + + A blank is either a newline or a line consisting of whitespace. + + Parameters + ---------- + src : string + A single or multiline string. + """ + if not src: return False + # The logic here is tricky: I couldn't get a regexp to work and pass all + # the tests, so I took a different approach: split the source by lines, + # grab the last two and prepend '###\n' as a stand-in for whatever was in + # the body before the last two lines. Then, with that structure, it's + # possible to analyze with two regexps. Not the most elegant solution, but + # it works. If anyone tries to change this logic, make sure to validate + # the whole test suite first! + new_src = '\n'.join(['###\n'] + src.splitlines()[-2:]) + return (bool(last_two_blanks_re.match(new_src)) or + bool(last_two_blanks_re2.match(new_src)) ) + def remove_comments(src): """Remove all comments from input source. @@ -558,20 +597,23 @@ def _make_help_call(target, esc, lspace, next_input=None): else 'psearch' if '*' in target \ else 'pinfo' arg = " ".join([method, target]) - - if next_input: - tpl = '%sget_ipython().magic(%r, next_input=%r)' - return tpl % (lspace, arg, next_input) - else: + if next_input is None: return '%sget_ipython().magic(%r)' % (lspace, arg) + else: + return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \ + (lspace, next_input, arg) + _initial_space_re = re.compile(r'\s*') -_help_end_re = re.compile(r"""(%? + +_help_end_re = re.compile(r"""(%{0,2} [a-zA-Z_*][\w*]* # Variable name (\.[a-zA-Z_*][\w*]*)* # .etc.etc ) (\?\??)$ # ? or ??""", re.VERBOSE) + + def transform_help_end(line): """Translate lines with ?/?? at the end""" m = _help_end_re.search(line) @@ -681,20 +723,31 @@ class IPythonInputSplitter(InputSplitter): # String with raw, untransformed input. source_raw = '' + # Flag to track when we're in the middle of processing a cell magic, since + # the logic has to change. In that case, we apply no transformations at + # all. + processing_cell_magic = False + + # Storage for all blocks of input that make up a cell magic + cell_magic_parts = [] + # Private attributes - + # List with lines of raw input accumulated so far. _buffer_raw = None def __init__(self, input_mode=None): - InputSplitter.__init__(self, input_mode) + super(IPythonInputSplitter, self).__init__(input_mode) self._buffer_raw = [] + self._validate = True def reset(self): """Reset the input buffer and associated state.""" - InputSplitter.reset(self) + super(IPythonInputSplitter, self).reset() self._buffer_raw[:] = [] self.source_raw = '' + self.cell_magic_parts = [] + self.processing_cell_magic = False def source_raw_reset(self): """Return input and raw source and perform a full reset. @@ -704,8 +757,79 @@ def source_raw_reset(self): self.reset() return out, out_r + def push_accepts_more(self): + if self.processing_cell_magic: + return not self._is_complete + else: + return super(IPythonInputSplitter, self).push_accepts_more() + + def _handle_cell_magic(self, lines): + """Process lines when they start with %%, which marks cell magics. + """ + self.processing_cell_magic = True + first, _, body = lines.partition('\n') + magic_name, _, line = first.partition(' ') + magic_name = magic_name.lstrip(ESC_MAGIC) + # We store the body of the cell and create a call to a method that + # will use this stored value. This is ugly, but it's a first cut to + # get it all working, as right now changing the return API of our + # methods would require major refactoring. + self.cell_magic_parts = [body] + tpl = 'get_ipython()._run_cached_cell_magic(%r, %r)' + tlines = tpl % (magic_name, line) + self._store(tlines) + self._store(lines, self._buffer_raw, 'source_raw') + # We can actually choose whether to allow for single blank lines here + # during input for clients that use cell mode to decide when to stop + # pushing input (currently only the Qt console). + # My first implementation did that, and then I realized it wasn't + # consistent with the terminal behavior, so I've reverted it to one + # line. But I'm leaving it here so we can easily test both behaviors, + # I kind of liked having full blank lines allowed in the cell magics... + #self._is_complete = last_two_blanks(lines) + self._is_complete = last_blank(lines) + return self._is_complete + + def _line_mode_cell_append(self, lines): + """Append new content for a cell magic in line mode. + """ + # Only store the raw input. Lines beyond the first one are only only + # stored for history purposes; for execution the caller will grab the + # magic pieces from cell_magic_parts and will assemble the cell body + self._store(lines, self._buffer_raw, 'source_raw') + self.cell_magic_parts.append(lines) + # Find out if the last stored block has a whitespace line as its + # last line and also this line is whitespace, case in which we're + # done (two contiguous blank lines signal termination). Note that + # the storage logic *enforces* that every stored block is + # newline-terminated, so we grab everything but the last character + # so we can have the body of the block alone. + last_block = self.cell_magic_parts[-1] + self._is_complete = last_blank(last_block) and lines.isspace() + return self._is_complete + def push(self, lines): """Push one or more lines of IPython input. + + This stores the given lines and returns a status code indicating + whether the code forms a complete Python block or not, after processing + all input lines for special IPython syntax. + + Any exceptions generated in compilation are swallowed, but if an + exception was produced, the method returns True. + + Parameters + ---------- + lines : string + One or more lines of Python input. + + Returns + ------- + is_complete : boolean + True if the current input source (the result of the current input + plus prior inputs) forms a complete Python execution block. Note that + this value is also stored as a private attribute (_is_complete), so it + can be queried at any time. """ if not lines: return super(IPythonInputSplitter, self).push(lines) @@ -713,6 +837,18 @@ def push(self, lines): # We must ensure all input is pure unicode lines = cast_unicode(lines, self.encoding) + # If the entire input block is a cell magic, return after handling it + # as the rest of the transformation logic should be skipped. + if lines.startswith('%%') and not \ + (len(lines.splitlines()) == 1 and lines.strip().endswith('?')): + return self._handle_cell_magic(lines) + + # In line mode, a cell magic can arrive in separate pieces + if self.input_mode == 'line' and self.processing_cell_magic: + return self._line_mode_cell_append(lines) + + # The rest of the processing is for 'normal' content, i.e. IPython + # source that we process through our transformations pipeline. lines_list = lines.splitlines() transforms = [transform_ipy_prompt, transform_classic_prompt, @@ -755,8 +891,7 @@ def push(self, lines): buf = self._buffer for line in lines_list: if self._is_complete or not buf or \ - (buf and (buf[-1].rstrip().endswith(':') or - buf[-1].rstrip().endswith(',')) ): + (buf and buf[-1].rstrip().endswith((':', ','))): for f in transforms: line = f(line) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index a2ccbe81323..d062b75f299 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -28,11 +28,18 @@ import sys import tempfile import types -import urllib -from io import open as io_open + +# We need to use nested to support python 2.6, once we move to >=2.7, we can +# use the with keyword's new builtin support for nested managers +try: + from contextlib import nested +except: + from IPython.utils.nested_context import nested from IPython.config.configurable import SingletonConfigurable from IPython.core import debugger, oinspect +from IPython.core import history as ipcorehist +from IPython.core import magic from IPython.core import page from IPython.core import prefilter from IPython.core import shadowns @@ -52,7 +59,6 @@ from IPython.core.inputsplitter import IPythonInputSplitter from IPython.core.logger import Logger from IPython.core.macro import Macro -from IPython.core.magic import Magic from IPython.core.payload import PayloadManager from IPython.core.plugin import PluginManager from IPython.core.prefilter import PrefilterManager, ESC_MAGIC @@ -187,7 +193,7 @@ def get_readline_tail(self, n=10): # Main IPython class #----------------------------------------------------------------------------- -class InteractiveShell(SingletonConfigurable, Magic): +class InteractiveShell(SingletonConfigurable): """An enhanced, interactive shell for Python.""" _instance = None @@ -380,6 +386,7 @@ def _prompt_trait_changed(self, name, old, new): plugin_manager = Instance('IPython.core.plugin.PluginManager') payload_manager = Instance('IPython.core.payload.PayloadManager') history_manager = Instance('IPython.core.history.HistoryManager') + magics_manager = Instance('IPython.core.magic.MagicsManager') profile_dir = Instance('IPython.core.application.ProfileDir') @property @@ -430,8 +437,6 @@ def __init__(self, config=None, ipython_dir=None, profile_dir=None, self.init_encoding() self.init_prefilter() - Magic.__init__(self, self) - self.init_syntax_highlighting() self.init_hooks() self.init_pushd_popd_magic() @@ -588,11 +593,11 @@ def init_logstart(self): """Initialize logging in case it was requested at the command line. """ if self.logappend: - self.magic_logstart(self.logappend + ' append') + self.magic('logstart %s append' % self.logappend) elif self.logfile: - self.magic_logstart(self.logfile) + self.magic('logstart %' % self.logfile) elif self.logstart: - self.magic_logstart() + self.magic('logstart') def init_builtins(self): # A single, static flag that we set to True. Its presence indicates @@ -1396,8 +1401,10 @@ def _ofind(self, oname, namespaces=None): # Try to see if it's magic if not found: if oname.startswith(ESC_MAGIC): - oname = oname[1:] - obj = getattr(self,'magic_'+oname,None) + oname = oname.lstrip(ESC_MAGIC) + obj = self.find_line_magic(oname) + if obj is None: + obj = self.find_cell_magic(oname) if obj is not None: found = True ospace = 'IPython internal' @@ -1993,16 +2000,113 @@ def set_completer_frame(self, frame=None): #------------------------------------------------------------------------- def init_magics(self): + from IPython.core import magics as m + self.magics_manager = magic.MagicsManager(shell=self, + confg=self.config, + user_magics=m.UserMagics(self)) + self.configurables.append(self.magics_manager) + + # Expose as public API from the magics manager + self.register_magics = self.magics_manager.register + self.register_magic_function = self.magics_manager.register_function + self.define_magic = self.magics_manager.define_magic + + self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics, + m.ConfigMagics, m.DeprecatedMagics, m.ExecutionMagics, + m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics, + m.NamespaceMagics, m.OSMagics, m.PylabMagics ) + # FIXME: Move the color initialization to the DisplayHook, which # should be split into a prompt manager and displayhook. We probably # even need a centralize colors management object. - self.magic_colors(self.colors) - # History was moved to a separate module - from IPython.core import history - history.init_ipython(self) + self.magic('colors %s' % self.colors) + + def run_line_magic(self, magic_name, line): + """Execute the given line magic. + + Parameters + ---------- + magic_name : str + Name of the desired magic function, without '%' prefix. + + line : str + The rest of the input line as a single string. + """ + fn = self.find_line_magic(magic_name) + if fn is None: + cm = self.find_cell_magic(magic_name) + etpl = "Line magic function `%%%s` not found%s." + extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, ' + 'did you mean that instead?)' % magic_name ) + error(etpl % (magic_name, extra)) + else: + # Note: this is the distance in the stack to the user's frame. + # This will need to be updated if the internal calling logic gets + # refactored, or else we'll be expanding the wrong variables. + stack_depth = 2 + magic_arg_s = self.var_expand(line, stack_depth) + # Put magic args in a list so we can call with f(*a) syntax + args = [magic_arg_s] + # Grab local namespace if we need it: + if getattr(fn, "needs_local_scope", False): + args.append(sys._getframe(stack_depth).f_locals) + with self.builtin_trap: + result = fn(*args) + return result + + def run_cell_magic(self, magic_name, line, cell): + """Execute the given cell magic. + + Parameters + ---------- + magic_name : str + Name of the desired magic function, without '%' prefix. + + line : str + The rest of the first input line as a single string. + + cell : str + The body of the cell as a (possibly multiline) string. + """ + fn = self.find_cell_magic(magic_name) + if fn is None: + lm = self.find_line_magic(magic_name) + etpl = "Cell magic function `%%%%%s` not found%s." + extra = '' if lm is None else (' (But line magic `%%%s` exists, ' + 'did you mean that instead?)' % magic_name ) + error(etpl % (magic_name, extra)) + else: + # Note: this is the distance in the stack to the user's frame. + # This will need to be updated if the internal calling logic gets + # refactored, or else we'll be expanding the wrong variables. + stack_depth = 2 + magic_arg_s = self.var_expand(line, stack_depth) + with self.builtin_trap: + result = fn(line, cell) + return result + + def find_line_magic(self, magic_name): + """Find and return a line magic by name. + + Returns None if the magic isn't found.""" + return self.magics_manager.magics['line'].get(magic_name) + + def find_cell_magic(self, magic_name): + """Find and return a cell magic by name. - def magic(self, arg_s, next_input=None): - """Call a magic function by name. + Returns None if the magic isn't found.""" + return self.magics_manager.magics['cell'].get(magic_name) + + def find_magic(self, magic_name, magic_kind='line'): + """Find and return a magic of the given type by name. + + Returns None if the magic isn't found.""" + return self.magics_manager.magics[magic_kind].get(magic_name) + + def magic(self, arg_s): + """DEPRECATED. Use run_line_magic() instead. + + Call a magic function by name. Input: a string containing the name of the magic function to call and any additional arguments to be passed to the magic. @@ -2018,45 +2122,10 @@ def magic(self, arg_s, next_input=None): valid Python code you can type at the interpreter, including loops and compound statements. """ - # Allow setting the next input - this is used if the user does `a=abs?`. - # We do this first so that magic functions can override it. - if next_input: - self.set_next_input(next_input) - - magic_name, _, magic_args = arg_s.partition(' ') + # TODO: should we issue a loud deprecation warning here? + magic_name, _, magic_arg_s = arg_s.partition(' ') magic_name = magic_name.lstrip(prefilter.ESC_MAGIC) - - fn = getattr(self,'magic_'+magic_name,None) - if fn is None: - error("Magic function `%s` not found." % magic_name) - else: - magic_args = self.var_expand(magic_args,1) - # Grab local namespace if we need it: - if getattr(fn, "needs_local_scope", False): - self._magic_locals = sys._getframe(1).f_locals - with self.builtin_trap: - result = fn(magic_args) - # Ensure we're not keeping object references around: - self._magic_locals = {} - return result - - def define_magic(self, magicname, func): - """Expose own function as magic function for ipython - - Example:: - - def foo_impl(self,parameter_s=''): - 'My very own magic!. (Use docstrings, IPython reads them).' - print 'Magic function. Passed parameter is between < >:' - print '<%s>' % parameter_s - print 'The self object is:', self - - ip.define_magic('foo',foo_impl) - """ - im = types.MethodType(func,self) - old = getattr(self, "magic_" + magicname, None) - setattr(self, "magic_" + magicname, im) - return old + return self.run_line_magic(magic_name, magic_arg_s) #------------------------------------------------------------------------- # Things related to macros @@ -2426,6 +2495,13 @@ def safe_run_module(self, mod_name, where): self.showtraceback() warn('Unknown failure executing module: <%s>' % mod_name) + def _run_cached_cell_magic(self, magic_name, line): + """Special method to call a cell magic with the data stored in self. + """ + cell = self._current_cell_magic_body + self._current_cell_magic_body = None + return self.run_cell_magic(magic_name, line, cell) + def run_cell(self, raw_cell, store_history=False, silent=False): """Run a complete IPython cell. @@ -2447,8 +2523,15 @@ def run_cell(self, raw_cell, store_history=False, silent=False): if silent: store_history = False - for line in raw_cell.splitlines(): - self.input_splitter.push(line) + self.input_splitter.push(raw_cell) + + # Check for cell magics, which leave state behind. This interface is + # ugly, we need to do something cleaner later... Now the logic is + # simply that the input_splitter remembers if there was a cell magic, + # and in that case we grab the cell body. + if self.input_splitter.cell_magic_parts: + self._current_cell_magic_body = \ + ''.join(self.input_splitter.cell_magic_parts) cell = self.input_splitter.source_reset() with self.builtin_trap: @@ -2479,7 +2562,8 @@ def run_cell(self, raw_cell, store_history=False, silent=False): with self.display_trap: try: - code_ast = self.compile.ast_parse(cell, filename=cell_name) + code_ast = self.compile.ast_parse(cell, + filename=cell_name) except IndentationError: self.showindentationerror() if store_history: @@ -2669,7 +2753,7 @@ def enable_pylab(self, gui=None, import_all=True): make sense in all contexts, for example a terminal ipython can't display figures inline. """ - + from IPython.core.pylabtools import mpl_runner # We want to prevent the loading of pylab to pollute the user's # namespace as shown by the %who* magics, so we execute the activation # code in an empty namespace, and we update *both* user_ns and @@ -2685,7 +2769,8 @@ def enable_pylab(self, gui=None, import_all=True): # Now we must activate the gui pylab wants to use, and fix %run to take # plot updates into account self.enable_gui(gui) - self.magic_run = self._pylab_magic_run + self.magics_manager.registry['ExecutionMagics'].default_runner = \ + mpl_runner(self.safe_execfile) #------------------------------------------------------------------------- # Utilities @@ -2749,6 +2834,29 @@ def show_usage(self): """Show a usage message""" page.page(IPython.core.usage.interactive_usage) + def extract_input_lines(self, range_str, raw=False): + """Return as a string a set of input history slices. + + Parameters + ---------- + range_str : string + The set of slices is given as a string, like "~5/6-~4/2 4:8 9", + since this function is for use by magic functions which get their + arguments as strings. The number before the / is the session + number: ~n goes n back from the current session. + + Optional Parameters: + - raw(False): by default, the processed input is used. If this is + true, the raw input history is used instead. + + Note that slices can be called with two notations: + + N:M -> standard python form, means including items N...(M-1). + + N-M -> include items N..M (closed endpoint).""" + lines = self.history_manager.get_range_by_str(range_str, raw=raw) + return "\n".join(x for _, _, x in lines) + def find_user_code(self, target, raw=True, py_only=False): """Get a code string from history, file, url, or a string or macro. diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 6980f0da9f4..803b343220a 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -4,8 +4,8 @@ #----------------------------------------------------------------------------- # Copyright (C) 2001 Janko Hauser and -# Copyright (C) 2001-2007 Fernando Perez -# Copyright (C) 2008-2011 The IPython Development Team +# Copyright (C) 2001 Fernando Perez +# Copyright (C) 2008 The IPython Development Team # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. @@ -14,67 +14,58 @@ #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- - -import __builtin__ as builtin_mod -import __future__ -import bdb -import inspect -import io -import json +# Stdlib import os -import sys import re -import time -import gc -from StringIO import StringIO -from getopt import getopt,GetoptError -from pprint import pformat -from urllib2 import urlopen - -# cProfile was added in Python2.5 -try: - import cProfile as profile - import pstats -except ImportError: - # profile isn't bundled by default in Debian for license reasons - try: - import profile,pstats - except ImportError: - profile = pstats = None - -from IPython.core import debugger, oinspect -from IPython.core.error import TryNext +import sys +import types +from getopt import getopt, GetoptError + +# Our own +from IPython.config.configurable import Configurable +from IPython.core import oinspect from IPython.core.error import UsageError -from IPython.core.error import StdinNotImplementedError -from IPython.core.macro import Macro -from IPython.core import magic_arguments, page from IPython.core.prefilter import ESC_MAGIC -from IPython.core.pylabtools import mpl_runner -from IPython.testing.skipdoctest import skip_doctest -from IPython.utils import py3compat -from IPython.utils.encoding import DEFAULT_ENCODING -from IPython.utils.io import file_read, nlprint -from IPython.utils.module_paths import find_mod -from IPython.utils.path import get_py_filename, unquote_filename -from IPython.utils.process import arg_split, abbrev_cwd -from IPython.utils.terminal import set_term_title -from IPython.utils.text import format_screen -from IPython.utils.timing import clock, clock2 -from IPython.utils.warn import warn, error +from IPython.external.decorator import decorator from IPython.utils.ipstruct import Struct -from IPython.config.application import Application +from IPython.utils.process import arg_split +from IPython.utils.text import dedent +from IPython.utils.traitlets import Bool, Dict, Instance +from IPython.utils.warn import error, warn + +#----------------------------------------------------------------------------- +# Globals +#----------------------------------------------------------------------------- + +# A dict we'll use for each class that has magics, used as temporary storage to +# pass information between the @line/cell_magic method decorators and the +# @magics_class class decorator, because the method decorators have no +# access to the class when they run. See for more details: +# http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class + +magics = dict(line={}, cell={}) + +magic_kinds = ('line', 'cell') +magic_spec = ('line', 'cell', 'line_cell') #----------------------------------------------------------------------------- -# Utility functions +# Utility classes and functions #----------------------------------------------------------------------------- +class Bunch: pass + + def on_off(tag): """Return an ON/OFF string for a 1/0 input. Simple utility function.""" return ['OFF','ON'][tag] -class Bunch: pass def compress_dhist(dh): + """Compress a directory history into a new one with at most 20 entries. + + Return a new list made from the first and last 10 elements of dhist after + removal of duplicates. + """ head, tail = dh[:-10], dh[-10:] newhead = [] @@ -87,127 +78,400 @@ def compress_dhist(dh): return newhead + tail + def needs_local_scope(func): """Decorator to mark magic functions which need to local scope to run.""" func.needs_local_scope = True return func +#----------------------------------------------------------------------------- +# Class and method decorators for registering magics +#----------------------------------------------------------------------------- + +def magics_class(cls): + """Class decorator for all subclasses of the main Magics class. + + Any class that subclasses Magics *must* also apply this decorator, to + ensure that all the methods that have been decorated as line/cell magics + get correctly registered in the class instance. This is necessary because + when method decorators run, the class does not exist yet, so they + temporarily store their information into a module global. Application of + this class decorator copies that global data to the class instance and + clears the global. + + Obviously, this mechanism is not thread-safe, which means that the + *creation* of subclasses of Magic should only be done in a single-thread + context. Instantiation of the classes has no restrictions. Given that + these classes are typically created at IPython startup time and before user + application code becomes active, in practice this should not pose any + problems. + """ + cls.registered = True + cls.magics = dict(line = magics['line'], + cell = magics['cell']) + magics['line'] = {} + magics['cell'] = {} + return cls + + +def record_magic(dct, magic_kind, magic_name, func): + """Utility function to store a function as a magic of a specific kind. + + Parameters + ---------- + dct : dict + A dictionary with 'line' and 'cell' subdicts. + + magic_kind : str + Kind of magic to be stored. + + magic_name : str + Key to store the magic as. + + func : function + Callable object to store. + """ + if magic_kind == 'line_cell': + dct['line'][magic_name] = dct['cell'][magic_name] = func + else: + dct[magic_kind][magic_name] = func + + +def validate_type(magic_kind): + """Ensure that the given magic_kind is valid. + + Check that the given magic_kind is one of the accepted spec types (stored + in the global `magic_spec`), raise ValueError otherwise. + """ + if magic_kind not in magic_spec: + raise ValueError('magic_kind must be one of %s, %s given' % + magic_kinds, magic_kind) + + +# The docstrings for the decorator below will be fairly similar for the two +# types (method and function), so we generate them here once and reuse the +# templates below. +_docstring_template = \ +"""Decorate the given {0} as {1} magic. + +The decorator can be used with or without arguments, as follows. + +i) without arguments: it will create a {1} magic named as the {0} being +decorated:: + + @deco + def foo(...) + +will create a {1} magic named `foo`. + +ii) with one string argument: which will be used as the actual name of the +resulting magic:: + + @deco('bar') + def foo(...) + +will create a {1} magic named `bar`. +""" + +# These two are decorator factories. While they are conceptually very similar, +# there are enough differences in the details that it's simpler to have them +# written as completely standalone functions rather than trying to share code +# and make a single one with convoluted logic. + +def _method_magic_marker(magic_kind): + """Decorator factory for methods in Magics subclasses. + """ + + validate_type(magic_kind) + + # This is a closure to capture the magic_kind. We could also use a class, + # but it's overkill for just that one bit of state. + def magic_deco(arg): + call = lambda f, *a, **k: f(*a, **k) + + if callable(arg): + # "Naked" decorator call (just @foo, no args) + func = arg + name = func.func_name + retval = decorator(call, func) + record_magic(magics, magic_kind, name, name) + elif isinstance(arg, basestring): + # Decorator called with arguments (@foo('bar')) + name = arg + def mark(func, *a, **kw): + record_magic(magics, magic_kind, name, func.func_name) + return decorator(call, func) + retval = mark + else: + raise ValueError("Decorator can only be called with " + "string or function") + return retval + + # Ensure the resulting decorator has a usable docstring + magic_deco.__doc__ = _docstring_template.format('method', magic_kind) + return magic_deco + + +def _function_magic_marker(magic_kind): + """Decorator factory for standalone functions. + """ + validate_type(magic_kind) + + # This is a closure to capture the magic_kind. We could also use a class, + # but it's overkill for just that one bit of state. + def magic_deco(arg): + call = lambda f, *a, **k: f(*a, **k) + + # Find get_ipython() in the caller's namespace + caller = sys._getframe(1) + for ns in ['f_locals', 'f_globals', 'f_builtins']: + get_ipython = getattr(caller, ns).get('get_ipython') + if get_ipython is not None: + break + else: + raise('Decorator can only run in context where `get_ipython` exists') + + ip = get_ipython() + + if callable(arg): + # "Naked" decorator call (just @foo, no args) + func = arg + name = func.func_name + ip.register_magic_function(func, magic_kind, name) + retval = decorator(call, func) + elif isinstance(arg, basestring): + # Decorator called with arguments (@foo('bar')) + name = arg + def mark(func, *a, **kw): + ip.register_magic_function(func, magic_kind, name) + return decorator(call, func) + retval = mark + else: + raise ValueError("Decorator can only be called with " + "string or function") + return retval + + # Ensure the resulting decorator has a usable docstring + ds = _docstring_template.format('function', magic_kind) + + ds += dedent(""" + Note: this decorator can only be used in a context where IPython is already + active, so that the `get_ipython()` call succeeds. You can therefore use + it in your startup files loaded after IPython initializes, but *not* in the + IPython configuration file itself, which is executed before IPython is + fully up and running. Any file located in the `startup` subdirectory of + your configuration profile will be OK in this sense. + """) -# Used for exception handling in magic_edit -class MacroToEdit(ValueError): pass + magic_deco.__doc__ = ds + return magic_deco -#*************************************************************************** -# Main class implementing Magic functionality -# XXX - for some odd reason, if Magic is made a new-style class, we get errors -# on construction of the main InteractiveShell object. Something odd is going -# on with super() calls, Configurable and the MRO... For now leave it as-is, but -# eventually this needs to be clarified. -# BG: This is because InteractiveShell inherits from this, but is itself a -# Configurable. This messes up the MRO in some way. The fix is that we need to -# make Magic a configurable that InteractiveShell does not subclass. +# Create the actual decorators for public use -class Magic: - """Magic functions for InteractiveShell. +# These three are used to decorate methods in class definitions +line_magic = _method_magic_marker('line') +cell_magic = _method_magic_marker('cell') +line_cell_magic = _method_magic_marker('line_cell') - Shell functions which can be reached as %function_name. All magic - functions should accept a string, which they can parse for their own - needs. This can make some functions easier to type, eg `%cd ../` - vs. `%cd("../")` +# These three decorate standalone functions and perform the decoration +# immediately. They can only run where get_ipython() works +register_line_magic = _function_magic_marker('line') +register_cell_magic = _function_magic_marker('cell') +register_line_cell_magic = _function_magic_marker('line_cell') - ALL definitions MUST begin with the prefix magic_. The user won't need it - at the command line, but it is is needed in the definition. """ +#----------------------------------------------------------------------------- +# Core Magic classes +#----------------------------------------------------------------------------- - # class globals - auto_status = ['Automagic is OFF, % prefix IS needed for magic functions.', - 'Automagic is ON, % prefix NOT needed for magic functions.'] +class MagicsManager(Configurable): + """Object that handles all magic-related functionality for IPython. + """ + # Non-configurable class attributes + # A two-level dict, first keyed by magic type, then by magic function, and + # holding the actual callable object as value. This is the dict used for + # magic function dispatch + magics = Dict - configurables = None - #...................................................................... - # some utility functions + # A registry of the original objects that we've been given holding magics. + registry = Dict - def __init__(self,shell): + shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') - self.options_table = {} - if profile is None: - self.magic_prun = self.profile_missing_notice - self.shell = shell - if self.configurables is None: - self.configurables = [] + auto_magic = Bool(True, config=True, help= + "Automatically call line magics without requiring explicit % prefix") + + _auto_status = [ + 'Automagic is OFF, % prefix IS needed for line magics.', + 'Automagic is ON, % prefix IS NOT needed for line magics.'] - # namespace for holding state we may need - self._magic_state = Bunch() + user_magics = Instance('IPython.core.magics.UserMagics') - def profile_missing_notice(self, *args, **kwargs): - error("""\ -The profile module could not be found. It has been removed from the standard -python packages because of its non-free license. To use profiling, install the -python-profiler package from non-free.""") + def __init__(self, shell=None, config=None, user_magics=None, **traits): - def default_option(self,fn,optstr): - """Make an entry in the options_table for fn, with value optstr""" + super(MagicsManager, self).__init__(shell=shell, config=config, + user_magics=user_magics, **traits) + self.magics = dict(line={}, cell={}) + # Let's add the user_magics to the registry for uniformity, so *all* + # registered magic containers can be found there. + self.registry[user_magics.__class__.__name__] = user_magics - if fn not in self.lsmagic(): - error("%s is not a magic function" % fn) - self.options_table[fn] = optstr + def auto_status(self): + """Return descriptive string with automagic status.""" + return self._auto_status[self.auto_magic] def lsmagic(self): - """Return a list of currently available magic functions. - - Gives a list of the bare names after mangling (['ls','cd', ...], not - ['magic_ls','magic_cd',...]""" - - # FIXME. This needs a cleanup, in the way the magics list is built. - - # magics in class definition - class_magic = lambda fn: fn.startswith('magic_') and \ - callable(Magic.__dict__[fn]) - # in instance namespace (run-time user additions) - inst_magic = lambda fn: fn.startswith('magic_') and \ - callable(self.__dict__[fn]) - # and bound magics by user (so they can access self): - inst_bound_magic = lambda fn: fn.startswith('magic_') and \ - callable(self.__class__.__dict__[fn]) - magics = filter(class_magic,Magic.__dict__.keys()) + \ - filter(inst_magic,self.__dict__.keys()) + \ - filter(inst_bound_magic,self.__class__.__dict__.keys()) - out = [] - for fn in set(magics): - out.append(fn.replace('magic_','',1)) - out.sort() - return out - - def extract_input_lines(self, range_str, raw=False): - """Return as a string a set of input history slices. + """Return a dict of currently available magic functions. + + The return dict has the keys 'line' and 'cell', corresponding to the + two types of magics we support. Each value is a list of names. + """ + return self.magics + + def register(self, *magic_objects): + """Register one or more instances of Magics. + + Take one or more classes or instances of classes that subclass the main + `core.Magic` class, and register them with IPython to use the magic + functions they provide. The registration process will then ensure that + any methods that have decorated to provide line and/or cell magics will + be recognized with the `%x`/`%%x` syntax as a line/cell magic + respectively. + + If classes are given, they will be instantiated with the default + constructor. If your classes need a custom constructor, you should + instanitate them first and pass the instance. + + The provided arguments can be an arbitrary mix of classes and instances. + + Parameters + ---------- + magic_objects : one or more classes or instances + """ + # Start by validating them to ensure they have all had their magic + # methods registered at the instance level + for m in magic_objects: + if not m.registered: + raise ValueError("Class of magics %r was constructed without " + "the @register_macics class decorator") + if type(m) is type: + # If we're given an uninstantiated class + m = m(self.shell) + + # Now that we have an instance, we can register it and update the + # table of callables + self.registry[m.__class__.__name__] = m + for mtype in magic_kinds: + self.magics[mtype].update(m.magics[mtype]) + + def register_function(self, func, magic_kind='line', magic_name=None): + """Expose a standalone function as magic function for IPython. + + This will create an IPython magic (line, cell or both) from a + standalone function. The functions should have the following + signatures: + + * For line magics: `def f(line)` + * For cell magics: `def f(line, cell)` + * For a function that does both: `def f(line, cell=None)` + + In the latter case, the function will be called with `cell==None` when + invoked as `%f`, and with cell as a string when invoked as `%%f`. Parameters ---------- - range_str : string - The set of slices is given as a string, like "~5/6-~4/2 4:8 9", - since this function is for use by magic functions which get their - arguments as strings. The number before the / is the session - number: ~n goes n back from the current session. + func : callable + Function to be registered as a magic. - Optional Parameters: - - raw(False): by default, the processed input is used. If this is - true, the raw input history is used instead. + magic_kind : str + Kind of magic, one of 'line', 'cell' or 'line_cell' - Note that slices can be called with two notations: + magic_name : optional str + If given, the name the magic will have in the IPython namespace. By + default, the name of the function itself is used. + """ + + # Create the new method in the user_magics and register it in the + # global table + validate_type(magic_kind) + magic_name = func.func_name if magic_name is None else magic_name + setattr(self.user_magics, magic_name, func) + record_magic(self.magics, magic_kind, magic_name, func) + + def define_magic(self, name, func): + """[Deprecated] Expose own function as magic function for IPython. + + Example:: + + def foo_impl(self, parameter_s=''): + 'My very own magic!. (Use docstrings, IPython reads them).' + print 'Magic function. Passed parameter is between < >:' + print '<%s>' % parameter_s + print 'The self object is:', self + + ip.define_magic('foo',foo_impl) + """ + meth = types.MethodType(func, self.user_magics) + setattr(self.user_magics, name, meth) + record_magic(self.magics, 'line', name, meth) + +# Key base class that provides the central functionality for magics. - N:M -> standard python form, means including items N...(M-1). +class Magics(object): + """Base class for implementing magic functions. - N-M -> include items N..M (closed endpoint).""" - lines = self.shell.history_manager.\ - get_range_by_str(range_str, raw=raw) - return "\n".join(x for _, _, x in lines) + Shell functions which can be reached as %function_name. All magic + functions should accept a string, which they can parse for their own + needs. This can make some functions easier to type, eg `%cd ../` + vs. `%cd("../")` + + Classes providing magic functions need to subclass this class, and they + MUST: + + - Use the method decorators `@line_magic` and `@cell_magic` to decorate + individual methods as magic functions, AND + + - Use the class decorator `@magics_class` to ensure that the magic + methods are properly registered at the instance level upon instance + initialization. + + See :mod:`magic_functions` for examples of actual implementation classes. + """ + # Dict holding all command-line options for each magic. + options_table = None + # Dict for the mapping of magic names to methods, set by class decorator + magics = None + # Flag to check that the class decorator was properly applied + registered = False + # Instance of IPython shell + shell = None + + def __init__(self, shell): + if not(self.__class__.registered): + raise ValueError('Magics subclass without registration - ' + 'did you forget to apply @magics_class?') + self.shell = shell + self.options_table = {} + # The method decorators are run when the instance doesn't exist yet, so + # they can only record the names of the methods they are supposed to + # grab. Only now, that the instance exists, can we create the proper + # mapping to bound methods. So we read the info off the original names + # table and replace each method name by the actual bound method. + for mtype in magic_kinds: + tab = self.magics[mtype] + # must explicitly use keys, as we're mutating this puppy + for magic_name in tab.keys(): + meth_name = tab[magic_name] + if isinstance(meth_name, basestring): + tab[magic_name] = getattr(self, meth_name) def arg_err(self,func): """Print docstring if incorrect arguments were passed""" print 'Error in arguments:' print oinspect.getdoc(func) - def format_latex(self,strng): + def format_latex(self, strng): """Format a string for latex inclusion.""" # Characters that need to be escaped for latex: @@ -234,7 +498,7 @@ def format_latex(self,strng): strng = newline_re.sub(r'\\textbackslash{}n',strng) return strng - def parse_options(self,arg_str,opt_str,*long_opts,**kw): + def parse_options(self, arg_str, opt_str, *long_opts, **kw): """Parse options passed to an argument string. The interface is similar to that of getopt(), but it returns back a @@ -257,7 +521,7 @@ def parse_options(self,arg_str,opt_str,*long_opts,**kw): standard library.""" # inject default options at the beginning of the input line - caller = sys._getframe(1).f_code.co_name.replace('magic_','') + caller = sys._getframe(1).f_code.co_name arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str) mode = kw.get('mode','string') @@ -303,3550 +567,9 @@ def parse_options(self,arg_str,opt_str,*long_opts,**kw): return opts,args - #...................................................................... - # And now the actual magic functions - - # Functions for IPython shell work (vars,funcs, config, etc) - def magic_lsmagic(self, parameter_s = ''): - """List currently available magic functions.""" - mesc = ESC_MAGIC - print 'Available magic functions:\n'+mesc+\ - (' '+mesc).join(self.lsmagic()) - print '\n' + Magic.auto_status[self.shell.automagic] - return None - - def magic_magic(self, parameter_s = ''): - """Print information about the magic function system. - - Supported formats: -latex, -brief, -rest - """ - - mode = '' - try: - if parameter_s.split()[0] == '-latex': - mode = 'latex' - if parameter_s.split()[0] == '-brief': - mode = 'brief' - if parameter_s.split()[0] == '-rest': - mode = 'rest' - rest_docs = [] - except: - pass - - magic_docs = [] - for fname in self.lsmagic(): - mname = 'magic_' + fname - for space in (Magic,self,self.__class__): - try: - fn = space.__dict__[mname] - except KeyError: - pass - else: - break - if mode == 'brief': - # only first line - if fn.__doc__: - fndoc = fn.__doc__.split('\n',1)[0] - else: - fndoc = 'No documentation' - else: - if fn.__doc__: - fndoc = fn.__doc__.rstrip() - else: - fndoc = 'No documentation' - - - if mode == 'rest': - rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(ESC_MAGIC, - fname,fndoc)) - - else: - magic_docs.append('%s%s:\n\t%s\n' %(ESC_MAGIC, - fname,fndoc)) - - magic_docs = ''.join(magic_docs) - - if mode == 'rest': - return "".join(rest_docs) - - if mode == 'latex': - print self.format_latex(magic_docs) - return - else: - magic_docs = format_screen(magic_docs) - if mode == 'brief': - return magic_docs - - outmsg = """ -IPython's 'magic' functions -=========================== - -The magic function system provides a series of functions which allow you to -control the behavior of IPython itself, plus a lot of system-type -features. All these functions are prefixed with a % character, but parameters -are given without parentheses or quotes. - -NOTE: If you have 'automagic' enabled (via the command line option or with the -%automagic function), you don't need to type in the % explicitly. By default, -IPython ships with automagic on, so you should only rarely need the % escape. - -Example: typing '%cd mydir' (without the quotes) changes you working directory -to 'mydir', if it exists. - -For a list of the available magic functions, use %lsmagic. For a description -of any of them, type %magic_name?, e.g. '%cd?'. - -Currently the magic system has the following functions:\n""" - - mesc = ESC_MAGIC - outmsg = ("%s\n%s\n\nSummary of magic functions (from %slsmagic):" - "\n\n%s%s\n\n%s" % (outmsg, - magic_docs,mesc,mesc, - (' '+mesc).join(self.lsmagic()), - Magic.auto_status[self.shell.automagic] ) ) - page.page(outmsg) - - 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.""" - - arg = parameter_s.lower() - if parameter_s in ('on','1','true'): - self.shell.automagic = True - elif parameter_s in ('off','0','false'): - self.shell.automagic = False - else: - self.shell.automagic = not self.shell.automagic - print '\n' + Magic.auto_status[self.shell.automagic] - - @skip_doctest - 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 [2]: float - ------> float() - Out[2]: 0.0 - - 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' - - # all-random (note for auto-testing) - """ - - 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): - self.shell.autocall = arg - else: # toggle - if self.shell.autocall: - self._magic_state.autocall_save = self.shell.autocall - self.shell.autocall = 0 - else: - try: - self.shell.autocall = self._magic_state.autocall_save - except AttributeError: - self.shell.autocall = self._magic_state.autocall_save = 1 - - print "Automatic calling is:",['OFF','Smart','Full'][self.shell.autocall] - - - def magic_page(self, parameter_s=''): - """Pretty print the object and display it through a pager. - - %page [options] OBJECT - - If no object is given, use _ (last output). - - Options: - - -r: page str(object), don't pretty-print it.""" - - # After a function contributed by Olivier Aubert, slightly modified. - - # Process options/args - opts,args = self.parse_options(parameter_s,'r') - raw = 'r' in opts - - oname = args and args or '_' - info = self._ofind(oname) - if info['found']: - txt = (raw and str or pformat)( info['obj'] ) - page.page(txt) - else: - print 'Object `%s` not found' % oname - - def magic_profile(self, parameter_s=''): - """Print your currently active IPython profile.""" - from IPython.core.application import BaseIPythonApplication - if BaseIPythonApplication.initialized(): - print BaseIPythonApplication.instance().profile - else: - error("profile is an application-level value, but you don't appear to be in an IPython application") - - def magic_pinfo(self, parameter_s='', namespaces=None): - """Provide detailed information about an object. - - '%pinfo object' is just a synonym for object? or ?object.""" - - #print 'pinfo par: <%s>' % parameter_s # dbg - - - # detail_level: 0 -> obj? , 1 -> obj?? - detail_level = 0 - # We need to detect if we got called as 'pinfo pinfo foo', which can - # happen if the user types 'pinfo foo?' at the cmd line. - pinfo,qmark1,oname,qmark2 = \ - re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups() - if pinfo or qmark1 or qmark2: - detail_level = 1 - if "*" in oname: - self.magic_psearch(oname) - else: - self.shell._inspect('pinfo', oname, detail_level=detail_level, - namespaces=namespaces) - - def magic_pinfo2(self, parameter_s='', namespaces=None): - """Provide extra detailed information about an object. - - '%pinfo2 object' is just a synonym for object?? or ??object.""" - self.shell._inspect('pinfo', parameter_s, detail_level=1, - namespaces=namespaces) - - @skip_doctest - 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. - - Examples - -------- - :: - - In [3]: %pdef urllib.urlopen - urllib.urlopen(url, data=None, proxies=None) - """ - 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.page(self.shell.inspector.format(open(filename).read())) - - def magic_psearch(self, parameter_s=''): - """Search for object in namespaces by wildcard. - - %psearch [options] PATTERN [OBJECT TYPE] - - Note: ? can be used as a synonym for %psearch, at the beginning or at - the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the - rest of the command line must be unchanged (options come first), so - for example the following forms are equivalent - - %psearch -i a* function - -i a* function? - ?-i a* function - - Arguments: - - PATTERN - - where PATTERN is a string containing * as a wildcard similar to its - use in a shell. The pattern is matched in all namespaces on the - search path. By default objects starting with a single _ are not - matched, many IPython generated objects have a single - underscore. The default is case insensitive matching. Matching is - also done on the attributes of objects and not only on the objects - in a module. - - [OBJECT TYPE] - - Is the name of a python type from the types module. The name is - given in lowercase without the ending type, ex. StringType is - written string. By adding a type here only objects matching the - given type are matched. Using all here makes the pattern match all - types (this is the default). - - Options: - - -a: makes the pattern match even objects whose names start with a - single underscore. These names are normally omitted from the - search. - - -i/-c: make the pattern case insensitive/sensitive. If neither of - these options are given, the default is read from your configuration - file, with the option ``InteractiveShell.wildcards_case_sensitive``. - If this option is not specified in your configuration file, IPython's - internal default is to do a case sensitive search. - - -e/-s NAMESPACE: exclude/search a given namespace. The pattern you - specify can be searched in any of the following namespaces: - 'builtin', 'user', 'user_global','internal', 'alias', where - 'builtin' and 'user' are the search defaults. Note that you should - not use quotes when specifying namespaces. - - 'Builtin' contains the python module builtin, 'user' contains all - user data, 'alias' only contain the shell aliases and no python - objects, 'internal' contains objects used by IPython. The - 'user_global' namespace is only used by embedded IPython instances, - and it contains module-level globals. You can add namespaces to the - search with -s or exclude them with -e (these options can be given - more than once). - - Examples - -------- - :: - - %psearch a* -> objects beginning with an a - %psearch -e builtin a* -> objects NOT in the builtin space starting in a - %psearch a* function -> all functions beginning with an a - %psearch re.e* -> objects beginning with an e in module re - %psearch r*.e* -> objects that start with e in modules starting in r - %psearch r*.* string -> all strings in modules beginning with r - - Case sensitive search:: - - %psearch -c a* list all object beginning with lower case a - - Show objects beginning with a single _:: - - %psearch -a _* list objects beginning with a single underscore""" - try: - parameter_s.encode('ascii') - except UnicodeEncodeError: - print 'Python identifiers can only contain ascii characters.' - return - - # default namespaces to be searched - def_search = ['user_local', 'user_global', 'builtin'] - - # Process options/args - opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True) - opt = opts.get - shell = self.shell - psearch = shell.inspector.psearch - - # select case options - if opts.has_key('i'): - ignore_case = True - elif opts.has_key('c'): - ignore_case = False - else: - ignore_case = not shell.wildcards_case_sensitive - - # Build list of namespaces to search from user options - def_search.extend(opt('s',[])) - ns_exclude = ns_exclude=opt('e',[]) - ns_search = [nm for nm in def_search if nm not in ns_exclude] - - # Call the actual search - try: - psearch(args,shell.ns_table,ns_search, - show_all=opt('a'),ignore_case=ignore_case) - except: - shell.showtraceback() - - @skip_doctest - def magic_who_ls(self, parameter_s=''): - """Return a sorted list of all interactive variables. - - If arguments are given, only variables of types matching these - arguments are returned. - - Examples - -------- - - Define two variables and list them with who_ls:: - - In [1]: alpha = 123 - - In [2]: beta = 'test' - - In [3]: %who_ls - Out[3]: ['alpha', 'beta'] - - In [4]: %who_ls int - Out[4]: ['alpha'] - - In [5]: %who_ls str - Out[5]: ['beta'] - """ - - user_ns = self.shell.user_ns - user_ns_hidden = self.shell.user_ns_hidden - out = [ i for i in user_ns - if not i.startswith('_') \ - and not i in user_ns_hidden ] - - typelist = parameter_s.split() - if typelist: - typeset = set(typelist) - out = [i for i in out if type(user_ns[i]).__name__ in typeset] - - out.sort() - return out - - @skip_doctest - def magic_who(self, parameter_s=''): - """Print all interactive variables, with some minimal formatting. - - If any arguments are given, only variables whose type matches one of - these are printed. For example:: - - %who function str - - will only list functions and strings, excluding all other types of - variables. To find the proper type names, simply use type(var) at a - command line to see how python prints type names. For example: - - :: - - In [1]: type('hello')\\ - Out[1]: - - indicates that the type name for strings is 'str'. - - ``%who`` always excludes executed names loaded through your configuration - file and things which are internal to IPython. - - This is deliberate, as typically you may load many modules and the - purpose of %who is to show you only what you've manually defined. - - Examples - -------- - - Define two variables and list them with who:: - - In [1]: alpha = 123 - - In [2]: beta = 'test' - - In [3]: %who - alpha beta - - In [4]: %who int - alpha - - In [5]: %who str - beta - """ - - varlist = self.magic_who_ls(parameter_s) - if not varlist: - if parameter_s: - print 'No variables match your requested type.' - else: - print 'Interactive namespace is empty.' - return - - # if we have variables, move on... - count = 0 - for i in varlist: - print i+'\t', - count += 1 - if count > 8: - count = 0 - print - print - - @skip_doctest - def magic_whos(self, parameter_s=''): - """Like %who, but gives some extra information about each variable. - - The same type filtering of %who can be applied here. - - For all variables, the type is printed. Additionally it prints: - - - For {},[],(): their length. - - - For numpy arrays, a summary with shape, number of - elements, typecode and size in memory. - - - Everything else: a string representation, snipping their middle if - too long. - - Examples - -------- - - Define two variables and list them with whos:: - - In [1]: alpha = 123 - - In [2]: beta = 'test' - - In [3]: %whos - Variable Type Data/Info - -------------------------------- - alpha int 123 - beta str test - """ - - varnames = self.magic_who_ls(parameter_s) - if not varnames: - if parameter_s: - print 'No variables match your requested type.' - else: - print 'Interactive namespace is empty.' - return - - # if we have variables, move on... - - # for these types, show len() instead of data: - seq_types = ['dict', 'list', 'tuple'] - - # for numpy arrays, display summary info - ndarray_type = None - if 'numpy' in sys.modules: - try: - from numpy import ndarray - except ImportError: - pass - else: - ndarray_type = ndarray.__name__ - - # Find all variable names and types so we can figure out column sizes - def get_vars(i): - return self.shell.user_ns[i] - - # some types are well known and can be shorter - abbrevs = {'IPython.core.macro.Macro' : 'Macro'} - def type_name(v): - tn = type(v).__name__ - return abbrevs.get(tn,tn) - - varlist = map(get_vars,varnames) - - typelist = [] - for vv in varlist: - tt = type_name(vv) - - if tt=='instance': - typelist.append( abbrevs.get(str(vv.__class__), - str(vv.__class__))) - else: - typelist.append(tt) - - # column labels and # of spaces as separator - varlabel = 'Variable' - typelabel = 'Type' - datalabel = 'Data/Info' - colsep = 3 - # variable format strings - vformat = "{0:<{varwidth}}{1:<{typewidth}}" - aformat = "%s: %s elems, type `%s`, %s bytes" - # find the size of the columns to format the output nicely - varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep - typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep - # table header - print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \ - ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1) - # and the table itself - kb = 1024 - Mb = 1048576 # kb**2 - for vname,var,vtype in zip(varnames,varlist,typelist): - print vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), - if vtype in seq_types: - print "n="+str(len(var)) - elif vtype == ndarray_type: - vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1] - if vtype==ndarray_type: - # numpy - vsize = var.size - vbytes = vsize*var.itemsize - vdtype = var.dtype - - if vbytes < 100000: - print aformat % (vshape,vsize,vdtype,vbytes) - else: - print aformat % (vshape,vsize,vdtype,vbytes), - if vbytes < Mb: - print '(%s kb)' % (vbytes/kb,) - else: - print '(%s Mb)' % (vbytes/Mb,) - else: - try: - vstr = str(var) - except UnicodeEncodeError: - vstr = unicode(var).encode(DEFAULT_ENCODING, - 'backslashreplace') - except: - vstr = "" % id(var) - vstr = vstr.replace('\n','\\n') - if len(vstr) < 50: - print vstr - else: - print vstr[:25] + "<...>" + vstr[-25:] - - def magic_reset(self, parameter_s=''): - """Resets the namespace by removing all names defined by the user, if - called without arguments, or by removing some types of objects, such - as everything currently in IPython's In[] and Out[] containers (see - the parameters for details). - - Parameters - ---------- - -f : force reset without asking for confirmation. - - -s : 'Soft' reset: Only clears your namespace, leaving history intact. - References to objects may be kept. By default (without this option), - we do a 'hard' reset, giving you a new session and removing all - references to objects from the current session. - - in : reset input history - - out : reset output history - - dhist : reset directory history - - array : reset only variables that are NumPy arrays - - See Also - -------- - magic_reset_selective : invoked as ``%reset_selective`` - - Examples - -------- - :: - - In [6]: a = 1 - - In [7]: a - Out[7]: 1 - - In [8]: 'a' in _ip.user_ns - Out[8]: True - - In [9]: %reset -f - - In [1]: 'a' in _ip.user_ns - Out[1]: False - - In [2]: %reset -f in - Flushing input history - - In [3]: %reset -f dhist in - Flushing directory history - Flushing input history - - Notes - ----- - Calling this magic from clients that do not implement standard input, - such as the ipython notebook interface, will reset the namespace - without confirmation. - """ - opts, args = self.parse_options(parameter_s,'sf', mode='list') - if 'f' in opts: - ans = True - else: - try: - ans = self.shell.ask_yes_no( - "Once deleted, variables cannot be recovered. Proceed (y/[n])? ", default='n') - except StdinNotImplementedError: - ans = True - if not ans: - print 'Nothing done.' - return - - if 's' in opts: # Soft reset - user_ns = self.shell.user_ns - for i in self.magic_who_ls(): - del(user_ns[i]) - elif len(args) == 0: # Hard reset - self.shell.reset(new_session = False) - - # reset in/out/dhist/array: previously extensinions/clearcmd.py - ip = self.shell - user_ns = self.user_ns # local lookup, heavily used - - for target in args: - target = target.lower() # make matches case insensitive - if target == 'out': - print "Flushing output cache (%d entries)" % len(user_ns['_oh']) - self.displayhook.flush() - - elif target == 'in': - print "Flushing input history" - pc = self.displayhook.prompt_count + 1 - for n in range(1, pc): - key = '_i'+repr(n) - user_ns.pop(key,None) - user_ns.update(dict(_i=u'',_ii=u'',_iii=u'')) - hm = ip.history_manager - # don't delete these, as %save and %macro depending on the length - # of these lists to be preserved - hm.input_hist_parsed[:] = [''] * pc - hm.input_hist_raw[:] = [''] * pc - # hm has internal machinery for _i,_ii,_iii, clear it out - hm._i = hm._ii = hm._iii = hm._i00 = u'' - - elif target == 'array': - # Support cleaning up numpy arrays - try: - from numpy import ndarray - # This must be done with items and not iteritems because we're - # going to modify the dict in-place. - for x,val in user_ns.items(): - if isinstance(val,ndarray): - del user_ns[x] - except ImportError: - print "reset array only works if Numpy is available." - - elif target == 'dhist': - print "Flushing directory history" - del user_ns['_dh'][:] - - else: - print "Don't know how to reset ", - print target + ", please run `%reset?` for details" + def default_option(self, fn, optstr): + """Make an entry in the options_table for fn, with value optstr""" - gc.collect() - - def magic_reset_selective(self, parameter_s=''): - """Resets the namespace by removing names defined by the user. - - Input/Output history are left around in case you need them. - - %reset_selective [-f] regex - - No action is taken if regex is not included - - Options - -f : force reset without asking for confirmation. - - See Also - -------- - magic_reset : invoked as ``%reset`` - - Examples - -------- - - We first fully reset the namespace so your output looks identical to - this example for pedagogical reasons; in practice you do not need a - full reset:: - - In [1]: %reset -f - - Now, with a clean namespace we can make a few variables and use - ``%reset_selective`` to only delete names that match our regexp:: - - In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8 - - In [3]: who_ls - Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c'] - - In [4]: %reset_selective -f b[2-3]m - - In [5]: who_ls - Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c'] - - In [6]: %reset_selective -f d - - In [7]: who_ls - Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c'] - - In [8]: %reset_selective -f c - - In [9]: who_ls - Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m'] - - In [10]: %reset_selective -f b - - In [11]: who_ls - Out[11]: ['a'] - - Notes - ----- - Calling this magic from clients that do not implement standard input, - such as the ipython notebook interface, will reset the namespace - without confirmation. - """ - - opts, regex = self.parse_options(parameter_s,'f') - - if opts.has_key('f'): - ans = True - else: - try: - ans = self.shell.ask_yes_no( - "Once deleted, variables cannot be recovered. Proceed (y/[n])? ", - default='n') - except StdinNotImplementedError: - ans = True - if not ans: - print 'Nothing done.' - return - user_ns = self.shell.user_ns - if not regex: - print 'No regex pattern specified. Nothing done.' - return - else: - try: - m = re.compile(regex) - except TypeError: - raise TypeError('regex must be a string or compiled pattern') - for i in self.magic_who_ls(): - if m.search(i): - del(user_ns[i]) - - def magic_xdel(self, parameter_s=''): - """Delete a variable, trying to clear it from anywhere that - IPython's machinery has references to it. By default, this uses - the identity of the named object in the user namespace to remove - references held under other names. The object is also removed - from the output history. - - Options - -n : Delete the specified name from all namespaces, without - checking their identity. - """ - opts, varname = self.parse_options(parameter_s,'n') - try: - self.shell.del_var(varname, ('n' in opts)) - except (NameError, ValueError) as e: - print type(e).__name__ +": "+ str(e) - - def magic_logstart(self,parameter_s=''): - """Start logging anywhere in a session. - - %logstart [-o|-r|-t] [log_name [log_mode]] - - If no name is given, it defaults to a file named 'ipython_log.py' in your - current directory, in 'rotate' mode (see below). - - '%logstart name' saves to file 'name' in 'backup' mode. It saves your - history up to that point and then continues logging. - - %logstart takes a second optional parameter: logging mode. This can be one - of (note that the modes are given unquoted):\\ - append: well, that says it.\\ - backup: rename (if exists) to name~ and start name.\\ - global: single logfile in your home dir, appended to.\\ - over : overwrite existing log.\\ - rotate: create rotating logs name.1~, name.2~, etc. - - Options: - - -o: log also IPython's output. In this mode, all commands which - generate an Out[NN] prompt are recorded to the logfile, right after - their corresponding input line. The output lines are always - prepended with a '#[Out]# ' marker, so that the log remains valid - Python code. - - Since this marker is always the same, filtering only the output from - a log is very easy, using for example a simple awk call:: - - awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py - - -r: log 'raw' input. Normally, IPython's logs contain the processed - input, so that user lines are logged in their final form, converted - into valid Python. For example, %Exit is logged as - _ip.magic("Exit"). If the -r flag is given, all input is logged - exactly as typed, with no transformations applied. - - -t: put timestamps before each input line logged (these are put in - comments).""" - - opts,par = self.parse_options(parameter_s,'ort') - log_output = 'o' in opts - log_raw_input = 'r' in opts - timestamp = 't' in opts - - logger = self.shell.logger - - # if no args are given, the defaults set in the logger constructor by - # ipython remain valid - if par: - try: - logfname,logmode = par.split() - except: - logfname = par - logmode = 'backup' - else: - logfname = logger.logfname - logmode = logger.logmode - # put logfname into rc struct as if it had been called on the command - # line, so it ends up saved in the log header Save it in case we need - # to restore it... - old_logfile = self.shell.logfile - if logfname: - logfname = os.path.expanduser(logfname) - self.shell.logfile = logfname - - loghead = '# IPython log file\n\n' - try: - started = logger.logstart(logfname,loghead,logmode, - log_output,timestamp,log_raw_input) - except: - self.shell.logfile = old_logfile - warn("Couldn't start log: %s" % sys.exc_info()[1]) - else: - # log input history up to this point, optionally interleaving - # output if requested - - if timestamp: - # disable timestamping for the previous history, since we've - # lost those already (no time machine here). - logger.timestamp = False - - if log_raw_input: - input_hist = self.shell.history_manager.input_hist_raw - else: - input_hist = self.shell.history_manager.input_hist_parsed - - if log_output: - log_write = logger.log_write - output_hist = self.shell.history_manager.output_hist - for n in range(1,len(input_hist)-1): - log_write(input_hist[n].rstrip() + '\n') - if n in output_hist: - log_write(repr(output_hist[n]),'output') - else: - logger.log_write('\n'.join(input_hist[1:])) - logger.log_write('\n') - if timestamp: - # re-enable timestamping - logger.timestamp = True - - print ('Activating auto-logging. ' - 'Current session state plus future input saved.') - logger.logstate() - - def magic_logstop(self,parameter_s=''): - """Fully stop logging and close log file. - - In order to start logging again, a new %logstart call needs to be made, - possibly (though not necessarily) with a new filename, mode and other - options.""" - self.logger.logstop() - - def magic_logoff(self,parameter_s=''): - """Temporarily stop logging. - - You must have previously started logging.""" - self.shell.logger.switch_log(0) - - def magic_logon(self,parameter_s=''): - """Restart logging. - - This function is for restarting logging which you've temporarily - stopped with %logoff. For starting logging for the first time, you - must use the %logstart function, which allows you to specify an - optional log filename.""" - - self.shell.logger.switch_log(1) - - def magic_logstate(self,parameter_s=''): - """Print the status of the logging system.""" - - self.shell.logger.logstate() - - def magic_pdb(self, parameter_s=''): - """Control the automatic calling of the pdb interactive debugger. - - Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without - argument it works as a toggle. - - When an exception is triggered, IPython can optionally call the - interactive pdb debugger after the traceback printout. %pdb toggles - this feature on and off. - - The initial state of this feature is set in your configuration - file (the option is ``InteractiveShell.pdb``). - - If you want to just activate the debugger AFTER an exception has fired, - without having to type '%pdb on' and rerunning your code, you can use - the %debug magic.""" - - par = parameter_s.strip().lower() - - if par: - try: - new_pdb = {'off':0,'0':0,'on':1,'1':1}[par] - except KeyError: - print ('Incorrect argument. Use on/1, off/0, ' - 'or nothing for a toggle.') - return - else: - # toggle - new_pdb = not self.shell.call_pdb - - # set on the shell - self.shell.call_pdb = new_pdb - print 'Automatic pdb calling has been turned',on_off(new_pdb) - - def magic_debug(self, parameter_s=''): - """Activate the interactive debugger in post-mortem mode. - - If an exception has just occurred, this lets you inspect its stack - frames interactively. Note that this will always work only on the last - traceback that occurred, so you must call this quickly after an - exception that you wish to inspect has fired, because if another one - occurs, it clobbers the previous one. - - If you want IPython to automatically do this on every exception, see - the %pdb magic for more details. - """ - self.shell.debugger(force=True) - - @skip_doctest - def magic_prun(self, parameter_s ='',user_mode=1, - opts=None,arg_lst=None,prog_ns=None): - - """Run a statement through the python code profiler. - - Usage: - %prun [options] statement - - The given statement (which doesn't require quote marks) is run via the - python profiler in a manner similar to the profile.run() function. - Namespaces are internally managed to work correctly; profile.run - cannot be used in IPython because it makes certain assumptions about - namespaces which do not hold under IPython. - - Options: - - -l : you can place restrictions on what or how much of the - profile gets printed. The limit value can be: - - * A string: only information for function names containing this string - is printed. - - * An integer: only these many lines are printed. - - * A float (between 0 and 1): this fraction of the report is printed - (for example, use a limit of 0.4 to see the topmost 40% only). - - You can combine several limits with repeated use of the option. For - example, '-l __init__ -l 5' will print only the topmost 5 lines of - information about class constructors. - - -r: return the pstats.Stats object generated by the profiling. This - object has all the information about the profile in it, and you can - later use it for further analysis or in other functions. - - -s : sort profile by given key. You can provide more than one key - by using the option several times: '-s key1 -s key2 -s key3...'. The - default sorting key is 'time'. - - The following is copied verbatim from the profile documentation - referenced below: - - When more than one key is provided, additional keys are used as - secondary criteria when the there is equality in all keys selected - before them. - - Abbreviations can be used for any key names, as long as the - abbreviation is unambiguous. The following are the keys currently - defined: - - Valid Arg Meaning - "calls" call count - "cumulative" cumulative time - "file" file name - "module" file name - "pcalls" primitive call count - "line" line number - "name" function name - "nfl" name/file/line - "stdname" standard name - "time" internal time - - Note that all sorts on statistics are in descending order (placing - most time consuming items first), where as name, file, and line number - searches are in ascending order (i.e., alphabetical). The subtle - distinction between "nfl" and "stdname" is that the standard name is a - sort of the name as printed, which means that the embedded line - numbers get compared in an odd way. For example, lines 3, 20, and 40 - would (if the file names were the same) appear in the string order - "20" "3" and "40". In contrast, "nfl" does a numeric compare of the - line numbers. In fact, sort_stats("nfl") is the same as - sort_stats("name", "file", "line"). - - -T : save profile results as shown on screen to a text - file. The profile is still shown on screen. - - -D : save (via dump_stats) profile statistics to given - filename. This data is in a format understood by the pstats module, and - is generated by a call to the dump_stats() method of profile - objects. The profile is still shown on screen. - - -q: suppress output to the pager. Best used with -T and/or -D above. - - If you want to run complete programs under the profiler's control, use - '%run -p [prof_opts] filename.py [args to program]' where prof_opts - contains profiler specific options as described here. - - You can read the complete documentation for the profile module with:: - - In [1]: import profile; profile.help() - """ - - opts_def = Struct(D=[''],l=[],s=['time'],T=['']) - - if user_mode: # regular user call - opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:q', - list_all=1, posix=False) - namespace = self.shell.user_ns - else: # called to run a program by %run -p - try: - filename = get_py_filename(arg_lst[0]) - except IOError as e: - try: - msg = str(e) - except UnicodeError: - msg = e.message - error(msg) - return - - arg_str = 'execfile(filename,prog_ns)' - namespace = { - 'execfile': self.shell.safe_execfile, - 'prog_ns': prog_ns, - 'filename': filename - } - - opts.merge(opts_def) - - prof = profile.Profile() - try: - prof = prof.runctx(arg_str,namespace,namespace) - sys_exit = '' - except SystemExit: - sys_exit = """*** SystemExit exception caught in code being profiled.""" - - stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s) - - lims = opts.l - if lims: - lims = [] # rebuild lims with ints/floats/strings - for lim in opts.l: - try: - lims.append(int(lim)) - except ValueError: - try: - lims.append(float(lim)) - except ValueError: - lims.append(lim) - - # Trap output. - stdout_trap = StringIO() - - if hasattr(stats,'stream'): - # In newer versions of python, the stats object has a 'stream' - # attribute to write into. - stats.stream = stdout_trap - stats.print_stats(*lims) - else: - # For older versions, we manually redirect stdout during printing - sys_stdout = sys.stdout - try: - sys.stdout = stdout_trap - stats.print_stats(*lims) - finally: - sys.stdout = sys_stdout - - output = stdout_trap.getvalue() - output = output.rstrip() - - if 'q' not in opts: - page.page(output) - print sys_exit, - - dump_file = opts.D[0] - text_file = opts.T[0] - if dump_file: - dump_file = unquote_filename(dump_file) - prof.dump_stats(dump_file) - print '\n*** Profile stats marshalled to file',\ - `dump_file`+'.',sys_exit - if text_file: - text_file = unquote_filename(text_file) - pfile = open(text_file,'w') - pfile.write(output) - pfile.close() - print '\n*** Profile printout saved to text file',\ - `text_file`+'.',sys_exit - - if opts.has_key('r'): - return stats - else: - return None - - @skip_doctest - def magic_run(self, parameter_s ='', runner=None, - file_finder=get_py_filename): - """Run the named file inside IPython as a program. - - Usage:\\ - %run [-n -i -t [-N] -d [-b] -p [profile options]] file [args] - - Parameters after the filename are passed as command-line arguments to - the program (put in sys.argv). Then, control returns to IPython's - prompt. - - This is similar to running at a system prompt:\\ - $ python file args\\ - but with the advantage of giving you IPython's tracebacks, and of - loading all variables into your interactive namespace for further use - (unless -p is used, see below). - - The file is executed in a namespace initially consisting only of - __name__=='__main__' and sys.argv constructed as indicated. It thus - sees its environment as if it were being run as a stand-alone program - (except for sharing global objects such as previously imported - modules). But after execution, the IPython interactive namespace gets - updated with all variables defined in the program (except for __name__ - and sys.argv). This allows for very convenient loading of code for - interactive work, while giving each program a 'clean sheet' to run in. - - Options: - - -n: __name__ is NOT set to '__main__', but to the running file's name - without extension (as python does under import). This allows running - scripts and reloading the definitions in them without calling code - protected by an ' if __name__ == "__main__" ' clause. - - -i: run the file in IPython's namespace instead of an empty one. This - is useful if you are experimenting with code written in a text editor - which depends on variables defined interactively. - - -e: ignore sys.exit() calls or SystemExit exceptions in the script - being run. This is particularly useful if IPython is being used to - run unittests, which always exit with a sys.exit() call. In such - cases you are interested in the output of the test results, not in - seeing a traceback of the unittest module. - - -t: print timing information at the end of the run. IPython will give - you an estimated CPU time consumption for your script, which under - Unix uses the resource module to avoid the wraparound problems of - time.clock(). Under Unix, an estimate of time spent on system tasks - is also given (for Windows platforms this is reported as 0.0). - - If -t is given, an additional -N option can be given, where - must be an integer indicating how many times you want the script to - run. The final timing report will include total and per run results. - - For example (testing the script uniq_stable.py):: - - In [1]: run -t uniq_stable - - IPython CPU timings (estimated):\\ - User : 0.19597 s.\\ - System: 0.0 s.\\ - - In [2]: run -t -N5 uniq_stable - - IPython CPU timings (estimated):\\ - Total runs performed: 5\\ - Times : Total Per run\\ - User : 0.910862 s, 0.1821724 s.\\ - System: 0.0 s, 0.0 s. - - -d: run your program under the control of pdb, the Python debugger. - This allows you to execute your program step by step, watch variables, - etc. Internally, what IPython does is similar to calling: - - pdb.run('execfile("YOURFILENAME")') - - with a breakpoint set on line 1 of your file. You can change the line - number for this automatic breakpoint to be by using the -bN option - (where N must be an integer). For example:: - - %run -d -b40 myscript - - will set the first breakpoint at line 40 in myscript.py. Note that - the first breakpoint must be set on a line which actually does - something (not a comment or docstring) for it to stop execution. - - When the pdb debugger starts, you will see a (Pdb) prompt. You must - first enter 'c' (without quotes) to start execution up to the first - breakpoint. - - Entering 'help' gives information about the use of the debugger. You - can easily see pdb's full documentation with "import pdb;pdb.help()" - at a prompt. - - -p: run program under the control of the Python profiler module (which - prints a detailed report of execution times, function calls, etc). - - You can pass other options after -p which affect the behavior of the - profiler itself. See the docs for %prun for details. - - In this mode, the program's variables do NOT propagate back to the - IPython interactive namespace (because they remain in the namespace - where the profiler executes them). - - Internally this triggers a call to %prun, see its documentation for - details on the options available specifically for profiling. - - There is one special usage for which the text above doesn't apply: - if the filename ends with .ipy, the file is run as ipython script, - just as if the commands were written on IPython prompt. - - -m: specify module name to load instead of script path. Similar to - the -m option for the python interpreter. Use this option last if you - want to combine with other %run options. Unlike the python interpreter - only source modules are allowed no .pyc or .pyo files. - For example:: - - %run -m example - - will run the example module. - - """ - - # get arguments and set sys.argv for program to be run. - opts, arg_lst = self.parse_options(parameter_s, 'nidtN:b:pD:l:rs:T:em:', - mode='list', list_all=1) - if "m" in opts: - modulename = opts["m"][0] - modpath = find_mod(modulename) - if modpath is None: - warn('%r is not a valid modulename on sys.path'%modulename) - return - arg_lst = [modpath] + arg_lst - try: - filename = file_finder(arg_lst[0]) - except IndexError: - warn('you must provide at least a filename.') - print '\n%run:\n', oinspect.getdoc(self.magic_run) - return - except IOError as e: - try: - msg = str(e) - except UnicodeError: - msg = e.message - error(msg) - return - - if filename.lower().endswith('.ipy'): - self.shell.safe_execfile_ipy(filename) - return - - # Control the response to exit() calls made by the script being run - exit_ignore = 'e' in opts - - # Make sure that the running script gets a proper sys.argv as if it - # were run from a system shell. - save_argv = sys.argv # save it for later restoring - - # simulate shell expansion on arguments, at least tilde expansion - args = [ os.path.expanduser(a) for a in arg_lst[1:] ] - - sys.argv = [filename] + args # put in the proper filename - # protect sys.argv from potential unicode strings on Python 2: - if not py3compat.PY3: - sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ] - - if 'i' in opts: - # Run in user's interactive namespace - prog_ns = self.shell.user_ns - __name__save = self.shell.user_ns['__name__'] - prog_ns['__name__'] = '__main__' - main_mod = self.shell.new_main_mod(prog_ns) - else: - # Run in a fresh, empty namespace - if 'n' in opts: - name = os.path.splitext(os.path.basename(filename))[0] - else: - name = '__main__' - - main_mod = self.shell.new_main_mod() - prog_ns = main_mod.__dict__ - prog_ns['__name__'] = name - - # Since '%run foo' emulates 'python foo.py' at the cmd line, we must - # set the __file__ global in the script's namespace - prog_ns['__file__'] = filename - - # pickle fix. See interactiveshell for an explanation. But we need to make sure - # that, if we overwrite __main__, we replace it at the end - main_mod_name = prog_ns['__name__'] - - if main_mod_name == '__main__': - restore_main = sys.modules['__main__'] - else: - restore_main = False - - # This needs to be undone at the end to prevent holding references to - # every single object ever created. - sys.modules[main_mod_name] = main_mod - - try: - stats = None - with self.readline_no_record: - if 'p' in opts: - stats = self.magic_prun('', 0, opts, arg_lst, prog_ns) - else: - if 'd' in opts: - deb = debugger.Pdb(self.shell.colors) - # reset Breakpoint state, which is moronically kept - # in a class - bdb.Breakpoint.next = 1 - bdb.Breakpoint.bplist = {} - bdb.Breakpoint.bpbynumber = [None] - # Set an initial breakpoint to stop execution - maxtries = 10 - bp = int(opts.get('b', [1])[0]) - checkline = deb.checkline(filename, bp) - if not checkline: - for bp in range(bp + 1, bp + maxtries + 1): - if deb.checkline(filename, bp): - break - else: - msg = ("\nI failed to find a valid line to set " - "a breakpoint\n" - "after trying up to line: %s.\n" - "Please set a valid breakpoint manually " - "with the -b option." % bp) - error(msg) - return - # if we find a good linenumber, set the breakpoint - deb.do_break('%s:%s' % (filename, bp)) - # Start file run - print "NOTE: Enter 'c' at the", - print "%s prompt to start your script." % deb.prompt - ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns} - try: - deb.run('execfile("%s", prog_ns)' % filename, ns) - - except: - etype, value, tb = sys.exc_info() - # Skip three frames in the traceback: the %run one, - # one inside bdb.py, and the command-line typed by the - # user (run by exec in pdb itself). - self.shell.InteractiveTB(etype, value, tb, tb_offset=3) - else: - if runner is None: - runner = self.shell.safe_execfile - if 't' in opts: - # timed execution - try: - nruns = int(opts['N'][0]) - if nruns < 1: - error('Number of runs must be >=1') - return - except (KeyError): - nruns = 1 - twall0 = time.time() - if nruns == 1: - t0 = clock2() - runner(filename, prog_ns, prog_ns, - exit_ignore=exit_ignore) - t1 = clock2() - t_usr = t1[0] - t0[0] - t_sys = t1[1] - t0[1] - print "\nIPython CPU timings (estimated):" - print " User : %10.2f s." % t_usr - print " System : %10.2f s." % t_sys - else: - runs = range(nruns) - t0 = clock2() - for nr in runs: - runner(filename, prog_ns, prog_ns, - exit_ignore=exit_ignore) - t1 = clock2() - t_usr = t1[0] - t0[0] - t_sys = t1[1] - t0[1] - print "\nIPython CPU timings (estimated):" - print "Total runs performed:", nruns - print " Times : %10.2f %10.2f" % ('Total', 'Per run') - print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns) - print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns) - twall1 = time.time() - print "Wall time: %10.2f s." % (twall1 - twall0) - - else: - # regular execution - runner(filename, prog_ns, prog_ns, exit_ignore=exit_ignore) - - if 'i' in opts: - self.shell.user_ns['__name__'] = __name__save - else: - # The shell MUST hold a reference to prog_ns so after %run - # exits, the python deletion mechanism doesn't zero it out - # (leaving dangling references). - self.shell.cache_main_mod(prog_ns, filename) - # update IPython interactive namespace - - # Some forms of read errors on the file may mean the - # __name__ key was never set; using pop we don't have to - # worry about a possible KeyError. - prog_ns.pop('__name__', None) - - self.shell.user_ns.update(prog_ns) - finally: - # It's a bit of a mystery why, but __builtins__ can change from - # being a module to becoming a dict missing some key data after - # %run. As best I can see, this is NOT something IPython is doing - # at all, and similar problems have been reported before: - # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html - # Since this seems to be done by the interpreter itself, the best - # we can do is to at least restore __builtins__ for the user on - # exit. - self.shell.user_ns['__builtins__'] = builtin_mod - - # Ensure key global structures are restored - sys.argv = save_argv - if restore_main: - sys.modules['__main__'] = restore_main - else: - # Remove from sys.modules the reference to main_mod we'd - # added. Otherwise it will trap references to objects - # contained therein. - del sys.modules[main_mod_name] - - return stats - - @skip_doctest - def magic_timeit(self, parameter_s =''): - """Time execution of a Python statement or expression - - Usage:\\ - %timeit [-n -r [-t|-c]] statement - - Time execution of a Python statement or expression using the timeit - module. - - Options: - -n: execute the given statement times in a loop. If this value - is not given, a fitting value is chosen. - - -r: repeat the loop iteration times and take the best result. - Default: 3 - - -t: use time.time to measure the time, which is the default on Unix. - This function measures wall time. - - -c: use time.clock to measure the time, which is the default on - Windows and measures wall time. On Unix, resource.getrusage is used - instead and returns the CPU user time. - - -p

: use a precision of

digits to display the timing result. - Default: 3 - - - Examples - -------- - :: - - In [1]: %timeit pass - 10000000 loops, best of 3: 53.3 ns per loop - - In [2]: u = None - - In [3]: %timeit u is None - 10000000 loops, best of 3: 184 ns per loop - - In [4]: %timeit -r 4 u == None - 1000000 loops, best of 4: 242 ns per loop - - In [5]: import time - - In [6]: %timeit -n1 time.sleep(2) - 1 loops, best of 3: 2 s per loop - - - The times reported by %timeit will be slightly higher than those - reported by the timeit.py script when variables are accessed. This is - due to the fact that %timeit executes the statement in the namespace - of the shell, compared with timeit.py, which uses a single setup - statement to import function or create variables. Generally, the bias - does not matter as long as results from timeit.py are not mixed with - those from %timeit.""" - - import timeit - import math - - # XXX: Unfortunately the unicode 'micro' symbol can cause problems in - # certain terminals. Until we figure out a robust way of - # auto-detecting if the terminal can deal with it, use plain 'us' for - # microseconds. I am really NOT happy about disabling the proper - # 'micro' prefix, but crashing is worse... If anyone knows what the - # right solution for this is, I'm all ears... - # - # Note: using - # - # s = u'\xb5' - # s.encode(sys.getdefaultencoding()) - # - # is not sufficient, as I've seen terminals where that fails but - # print s - # - # succeeds - # - # See bug: https://bugs.launchpad.net/ipython/+bug/348466 - - #units = [u"s", u"ms",u'\xb5',"ns"] - units = [u"s", u"ms",u'us',"ns"] - - scaling = [1, 1e3, 1e6, 1e9] - - opts, stmt = self.parse_options(parameter_s,'n:r:tcp:', - posix=False, strict=False) - if stmt == "": - return - timefunc = timeit.default_timer - number = int(getattr(opts, "n", 0)) - repeat = int(getattr(opts, "r", timeit.default_repeat)) - precision = int(getattr(opts, "p", 3)) - if hasattr(opts, "t"): - timefunc = time.time - if hasattr(opts, "c"): - timefunc = clock - - timer = timeit.Timer(timer=timefunc) - # this code has tight coupling to the inner workings of timeit.Timer, - # but is there a better way to achieve that the code stmt has access - # to the shell namespace? - - src = timeit.template % {'stmt': timeit.reindent(stmt, 8), - 'setup': "pass"} - # Track compilation time so it can be reported if too long - # Minimum time above which compilation time will be reported - tc_min = 0.1 - - t0 = clock() - code = compile(src, "", "exec") - tc = clock()-t0 - - ns = {} - exec code in self.shell.user_ns, ns - timer.inner = ns["inner"] - - if number == 0: - # determine number so that 0.2 <= total time < 2.0 - number = 1 - for i in range(1, 10): - if timer.timeit(number) >= 0.2: - break - number *= 10 - - best = min(timer.repeat(repeat, number)) / number - - if best > 0.0 and best < 1000.0: - order = min(-int(math.floor(math.log10(best)) // 3), 3) - elif best >= 1000.0: - order = 0 - else: - order = 3 - print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat, - precision, - best * scaling[order], - units[order]) - if tc > tc_min: - print "Compiler time: %.2f s" % tc - - @skip_doctest - @needs_local_scope - def magic_time(self,parameter_s = ''): - """Time execution of a Python statement or expression. - - The CPU and wall clock times are printed, and the value of the - expression (if any) is returned. Note that under Win32, system time - is always reported as 0, since it can not be measured. - - This function provides very basic timing functionality. In Python - 2.3, the timeit module offers more control and sophistication, so this - could be rewritten to use it (patches welcome). - - Examples - -------- - :: - - In [1]: time 2**128 - CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s - Wall time: 0.00 - Out[1]: 340282366920938463463374607431768211456L - - In [2]: n = 1000000 - - In [3]: time sum(range(n)) - CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s - Wall time: 1.37 - Out[3]: 499999500000L - - In [4]: time print 'hello world' - hello world - CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s - Wall time: 0.00 - - Note that the time needed by Python to compile the given expression - will be reported if it is more than 0.1s. In this example, the - actual exponentiation is done by Python at compilation time, so while - the expression can take a noticeable amount of time to compute, that - time is purely due to the compilation: - - In [5]: time 3**9999; - CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s - Wall time: 0.00 s - - In [6]: time 3**999999; - CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s - Wall time: 0.00 s - Compiler : 0.78 s - """ - - # fail immediately if the given expression can't be compiled - - expr = self.shell.prefilter(parameter_s,False) - - # Minimum time above which compilation time will be reported - tc_min = 0.1 - - try: - mode = 'eval' - t0 = clock() - code = compile(expr,'',mode) - tc = clock()-t0 - except SyntaxError: - mode = 'exec' - t0 = clock() - code = compile(expr,'',mode) - tc = clock()-t0 - # skew measurement as little as possible - glob = self.shell.user_ns - locs = self._magic_locals - clk = clock2 - wtime = time.time - # time execution - wall_st = wtime() - if mode=='eval': - st = clk() - out = eval(code, glob, locs) - end = clk() - else: - st = clk() - exec code in glob, locs - end = clk() - out = None - wall_end = wtime() - # Compute actual times and report - wall_time = wall_end-wall_st - cpu_user = end[0]-st[0] - cpu_sys = end[1]-st[1] - cpu_tot = cpu_user+cpu_sys - print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \ - (cpu_user,cpu_sys,cpu_tot) - print "Wall time: %.2f s" % wall_time - if tc > tc_min: - print "Compiler : %.2f s" % tc - return out - - @skip_doctest - def magic_macro(self,parameter_s = ''): - """Define a macro for future re-execution. It accepts ranges of history, - filenames or string objects. - - Usage:\\ - %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ... - - Options: - - -r: use 'raw' input. By default, the 'processed' history is used, - so that magics are loaded in their transformed version to valid - Python. If this option is given, the raw input as typed as the - command line is used instead. - - This will define a global variable called `name` which is a string - made of joining the slices and lines you specify (n1,n2,... numbers - above) from your input history into a single string. This variable - acts like an automatic function which re-executes those lines as if - you had typed them. You just type 'name' at the prompt and the code - executes. - - The syntax for indicating input ranges is described in %history. - - Note: as a 'hidden' feature, you can also use traditional python slice - notation, where N:M means numbers N through M-1. - - For example, if your history contains (%hist prints it):: - - 44: x=1 - 45: y=3 - 46: z=x+y - 47: print x - 48: a=5 - 49: print 'x',x,'y',y - - you can create a macro with lines 44 through 47 (included) and line 49 - called my_macro with:: - - In [55]: %macro my_macro 44-47 49 - - Now, typing `my_macro` (without quotes) will re-execute all this code - in one pass. - - You don't need to give the line-numbers in order, and any given line - number can appear multiple times. You can assemble macros with any - lines from your input history in any order. - - The macro is a simple object which holds its value in an attribute, - but IPython's display system checks for macros and executes them as - code instead of printing them when you type their name. - - You can view a macro's contents by explicitly printing it with:: - - print macro_name - - """ - opts,args = self.parse_options(parameter_s,'r',mode='list') - if not args: # List existing macros - return sorted(k for k,v in self.shell.user_ns.iteritems() if\ - isinstance(v, Macro)) - if len(args) == 1: - raise UsageError( - "%macro insufficient args; usage '%macro name n1-n2 n3-4...") - name, codefrom = args[0], " ".join(args[1:]) - - #print 'rng',ranges # dbg - try: - lines = self.shell.find_user_code(codefrom, 'r' in opts) - except (ValueError, TypeError) as e: - print e.args[0] - return - macro = Macro(lines) - self.shell.define_macro(name, macro) - print 'Macro `%s` created. To execute, type its name (without quotes).' % name - print '=== Macro contents: ===' - print macro, - - def magic_save(self,parameter_s = ''): - """Save a set of lines or a macro to a given filename. - - Usage:\\ - %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ... - - Options: - - -r: use 'raw' input. By default, the 'processed' history is used, - so that magics are loaded in their transformed version to valid - Python. If this option is given, the raw input as typed as the - command line is used instead. - - This function uses the same syntax as %history for input ranges, - then saves the lines to the filename you specify. - - It adds a '.py' extension to the file if you don't do so yourself, and - it asks for confirmation before overwriting existing files.""" - - opts,args = self.parse_options(parameter_s,'r',mode='list') - fname, codefrom = unquote_filename(args[0]), " ".join(args[1:]) - if not fname.endswith('.py'): - fname += '.py' - if os.path.isfile(fname): - overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n') - if not overwrite : - print 'Operation cancelled.' - return - try: - cmds = self.shell.find_user_code(codefrom, 'r' in opts) - except (TypeError, ValueError) as e: - print e.args[0] - return - with io.open(fname,'w', encoding="utf-8") as f: - f.write(u"# coding: utf-8\n") - f.write(py3compat.cast_unicode(cmds)) - print 'The following commands were written to file `%s`:' % fname - print cmds - - def magic_pastebin(self, parameter_s = ''): - """Upload code to Github's Gist paste bin, returning the URL. - - Usage:\\ - %pastebin [-d "Custom description"] 1-7 - - The argument can be an input history range, a filename, or the name of a - string or macro. - - Options: - - -d: Pass a custom description for the gist. The default will say - "Pasted from IPython". - """ - opts, args = self.parse_options(parameter_s, 'd:') - - try: - code = self.shell.find_user_code(args) - except (ValueError, TypeError) as e: - print e.args[0] - return - - post_data = json.dumps({ - "description": opts.get('d', "Pasted from IPython"), - "public": True, - "files": { - "file1.py": { - "content": code - } - } - }).encode('utf-8') - - response = urlopen("https://api.github.com/gists", post_data) - response_data = json.loads(response.read().decode('utf-8')) - return response_data['html_url'] - - def magic_loadpy(self, arg_s): - """Alias of `%load` - - `%loadpy` has gained some flexibility and droped the requirement of a `.py` - extension. So it has been renamed simply into %load. You can look at - `%load`'s docstring for more info. - """ - self.magic_load(arg_s) - - def magic_load(self, arg_s): - """Load code into the current frontend. - - Usage:\\ - %load [options] source - - where source can be a filename, URL, input history range or macro - - Options: - -------- - -y : Don't ask confirmation for loading source above 200 000 characters. - - This magic command can either take a local filename, a URL, an history - range (see %history) or a macro as argument, it will prompt for - confirmation before loading source with more than 200 000 characters, unless - -y flag is passed or if the frontend does not support raw_input:: - - %load myscript.py - %load 7-27 - %load myMacro - %load http://www.example.com/myscript.py - """ - opts,args = self.parse_options(arg_s,'y') - - contents = self.shell.find_user_code(args) - l = len(contents) - - # 200 000 is ~ 2500 full 80 caracter lines - # so in average, more than 5000 lines - if l > 200000 and 'y' not in opts: - try: - ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\ - " (%d characters). Continue (y/[N]) ?" % l), default='n' ) - except StdinNotImplementedError: - #asume yes if raw input not implemented - ans = True - - if ans is False : - print 'Operation cancelled.' - return - - self.set_next_input(contents) - - def _find_edit_target(self, args, opts, last_call): - """Utility method used by magic_edit to find what to edit.""" - - def make_filename(arg): - "Make a filename from the given args" - arg = unquote_filename(arg) - try: - filename = get_py_filename(arg) - except IOError: - # If it ends with .py but doesn't already exist, assume we want - # a new file. - if arg.endswith('.py'): - filename = arg - else: - filename = None - return filename - - # Set a few locals from the options for convenience: - opts_prev = 'p' in opts - opts_raw = 'r' in opts - - # custom exceptions - class DataIsObject(Exception): pass - - # Default line number value - lineno = opts.get('n',None) - - if opts_prev: - args = '_%s' % last_call[0] - if not self.shell.user_ns.has_key(args): - args = last_call[1] - - # use last_call to remember the state of the previous call, but don't - # let it be clobbered by successive '-p' calls. - try: - last_call[0] = self.shell.displayhook.prompt_count - if not opts_prev: - last_call[1] = args - except: - pass - - # by default this is done with temp files, except when the given - # arg is a filename - use_temp = True - - data = '' - - # First, see if the arguments should be a filename. - filename = make_filename(args) - if filename: - use_temp = False - elif args: - # Mode where user specifies ranges of lines, like in %macro. - data = self.extract_input_lines(args, opts_raw) - if not data: - try: - # Load the parameter given as a variable. If not a string, - # process it as an object instead (below) - - #print '*** args',args,'type',type(args) # dbg - data = eval(args, self.shell.user_ns) - if not isinstance(data, basestring): - raise DataIsObject - - except (NameError,SyntaxError): - # given argument is not a variable, try as a filename - filename = make_filename(args) - if filename is None: - warn("Argument given (%s) can't be found as a variable " - "or as a filename." % args) - return - use_temp = False - - except DataIsObject: - # macros have a special edit function - if isinstance(data, Macro): - raise MacroToEdit(data) - - # For objects, try to edit the file where they are defined - try: - filename = inspect.getabsfile(data) - if 'fakemodule' in filename.lower() and inspect.isclass(data): - # class created by %edit? Try to find source - # by looking for method definitions instead, the - # __module__ in those classes is FakeModule. - attrs = [getattr(data, aname) for aname in dir(data)] - for attr in attrs: - if not inspect.ismethod(attr): - continue - filename = inspect.getabsfile(attr) - if filename and 'fakemodule' not in filename.lower(): - # change the attribute to be the edit target instead - data = attr - break - - datafile = 1 - except TypeError: - filename = make_filename(args) - datafile = 1 - warn('Could not find file where `%s` is defined.\n' - 'Opening a file named `%s`' % (args,filename)) - # Now, make sure we can actually read the source (if it was in - # a temp file it's gone by now). - if datafile: - try: - if lineno is None: - lineno = inspect.getsourcelines(data)[1] - except IOError: - filename = make_filename(args) - if filename is None: - warn('The file `%s` where `%s` was defined cannot ' - 'be read.' % (filename,data)) - return - use_temp = False - - if use_temp: - filename = self.shell.mktempfile(data) - print 'IPython will make a temporary file named:',filename - - return filename, lineno, use_temp - - def _edit_macro(self,mname,macro): - """open an editor with the macro data in a file""" - filename = self.shell.mktempfile(macro.value) - self.shell.hooks.editor(filename) - - # and make a new macro object, to replace the old one - mfile = open(filename) - mvalue = mfile.read() - mfile.close() - self.shell.user_ns[mname] = Macro(mvalue) - - def magic_ed(self,parameter_s=''): - """Alias to %edit.""" - return self.magic_edit(parameter_s) - - @skip_doctest - def magic_edit(self,parameter_s='',last_call=['','']): - """Bring up an editor and execute the resulting code. - - Usage: - %edit [options] [args] - - %edit runs IPython's editor hook. The default version of this hook is - set to call the editor specified by your $EDITOR environment variable. - If this isn't found, it will default to vi under Linux/Unix and to - notepad under Windows. See the end of this docstring for how to change - the editor hook. - - You can also set the value of this editor via the - ``TerminalInteractiveShell.editor`` option in your configuration file. - This is useful if you wish to use a different editor from your typical - default with IPython (and for Windows users who typically don't set - environment variables). - - This command allows you to conveniently edit multi-line code right in - your IPython session. - - If called without arguments, %edit opens up an empty editor with a - temporary file and will execute the contents of this file when you - close it (don't forget to save it!). - - - Options: - - -n : open the editor at a specified line number. By default, - the IPython editor hook uses the unix syntax 'editor +N filename', but - you can configure this by providing your own modified hook if your - favorite editor supports line-number specifications with a different - syntax. - - -p: this will call the editor with the same data as the previous time - it was used, regardless of how long ago (in your current session) it - was. - - -r: use 'raw' input. This option only applies to input taken from the - user's history. By default, the 'processed' history is used, so that - magics are loaded in their transformed version to valid Python. If - this option is given, the raw input as typed as the command line is - used instead. When you exit the editor, it will be executed by - IPython's own processor. - - -x: do not execute the edited code immediately upon exit. This is - mainly useful if you are editing programs which need to be called with - command line arguments, which you can then do using %run. - - - Arguments: - - If arguments are given, the following possibilities exist: - - - If the argument is a filename, IPython will load that into the - editor. It will execute its contents with execfile() when you exit, - loading any code in the file into your interactive namespace. - - - The arguments are ranges of input history, e.g. "7 ~1/4-6". - The syntax is the same as in the %history magic. - - - If the argument is a string variable, its contents are loaded - into the editor. You can thus edit any string which contains - python code (including the result of previous edits). - - - If the argument is the name of an object (other than a string), - IPython will try to locate the file where it was defined and open the - editor at the point where it is defined. You can use `%edit function` - to load an editor exactly at the point where 'function' is defined, - edit it and have the file be executed automatically. - - - If the object is a macro (see %macro for details), this opens up your - specified editor with a temporary file containing the macro's data. - Upon exit, the macro is reloaded with the contents of the file. - - Note: opening at an exact line is only supported under Unix, and some - editors (like kedit and gedit up to Gnome 2.8) do not understand the - '+NUMBER' parameter necessary for this feature. Good editors like - (X)Emacs, vi, jed, pico and joe all do. - - After executing your code, %edit will return as output the code you - typed in the editor (except when it was an existing file). This way - you can reload the code in further invocations of %edit as a variable, - via _ or Out[], where is the prompt number of - the output. - - Note that %edit is also available through the alias %ed. - - This is an example of creating a simple function inside the editor and - then modifying it. First, start up the editor:: - - In [1]: ed - Editing... done. Executing edited code... - Out[1]: 'def foo():\\n print "foo() was defined in an editing - session"\\n' - - We can then call the function foo():: - - In [2]: foo() - foo() was defined in an editing session - - Now we edit foo. IPython automatically loads the editor with the - (temporary) file where foo() was previously defined:: - - In [3]: ed foo - Editing... done. Executing edited code... - - And if we call foo() again we get the modified version:: - - In [4]: foo() - foo() has now been changed! - - Here is an example of how to edit a code snippet successive - times. First we call the editor:: - - In [5]: ed - Editing... done. Executing edited code... - hello - Out[5]: "print 'hello'\\n" - - Now we call it again with the previous output (stored in _):: - - In [6]: ed _ - Editing... done. Executing edited code... - hello world - Out[6]: "print 'hello world'\\n" - - Now we call it with the output #8 (stored in _8, also as Out[8]):: - - In [7]: ed _8 - Editing... done. Executing edited code... - hello again - Out[7]: "print 'hello again'\\n" - - - Changing the default editor hook: - - If you wish to write your own editor hook, you can put it in a - configuration file which you load at startup time. The default hook - is defined in the IPython.core.hooks module, and you can use that as a - starting example for further modifications. That file also has - general instructions on how to set a new hook for use once you've - defined it.""" - opts,args = self.parse_options(parameter_s,'prxn:') - - try: - filename, lineno, is_temp = self._find_edit_target(args, opts, last_call) - except MacroToEdit as e: - self._edit_macro(args, e.args[0]) - return - - # do actual editing here - print 'Editing...', - sys.stdout.flush() - try: - # Quote filenames that may have spaces in them - if ' ' in filename: - filename = "'%s'" % filename - self.shell.hooks.editor(filename,lineno) - except TryNext: - warn('Could not open editor') - return - - # XXX TODO: should this be generalized for all string vars? - # For now, this is special-cased to blocks created by cpaste - if args.strip() == 'pasted_block': - self.shell.user_ns['pasted_block'] = file_read(filename) - - if 'x' in opts: # -x prevents actual execution - print - else: - print 'done. Executing edited code...' - if 'r' in opts: # Untranslated IPython code - self.shell.run_cell(file_read(filename), - store_history=False) - else: - self.shell.safe_execfile(filename,self.shell.user_ns, - self.shell.user_ns) - - if is_temp: - try: - return open(filename).read() - except IOError,msg: - if msg.filename == filename: - warn('File not found. Did you forget to save?') - return - else: - self.shell.showtraceback() - - def magic_xmode(self,parameter_s = ''): - """Switch modes for the exception handlers. - - Valid modes: Plain, Context and Verbose. - - If called without arguments, acts as a toggle.""" - - def xmode_switch_err(name): - warn('Error changing %s exception modes.\n%s' % - (name,sys.exc_info()[1])) - - shell = self.shell - new_mode = parameter_s.strip().capitalize() - try: - shell.InteractiveTB.set_mode(mode=new_mode) - print 'Exception reporting mode:',shell.InteractiveTB.mode - except: - xmode_switch_err('user') - - def magic_colors(self,parameter_s = ''): - """Switch color scheme for prompts, info system and exception handlers. - - Currently implemented schemes: NoColor, Linux, LightBG. - - Color scheme names are not case-sensitive. - - Examples - -------- - To get a plain black and white terminal:: - - %colors nocolor - """ - - def color_switch_err(name): - warn('Error changing %s color schemes.\n%s' % - (name,sys.exc_info()[1])) - - - new_scheme = parameter_s.strip() - if not new_scheme: - raise UsageError( - "%colors: you must specify a color scheme. See '%colors?'") - return - # local shortcut - shell = self.shell - - import IPython.utils.rlineimpl as readline - - if not shell.colors_force and \ - not readline.have_readline and sys.platform == "win32": - msg = """\ -Proper color support under MS Windows requires the pyreadline library. -You can find it at: -http://ipython.org/pyreadline.html -Gary's readline needs the ctypes module, from: -http://starship.python.net/crew/theller/ctypes -(Note that ctypes is already part of Python versions 2.5 and newer). - -Defaulting color scheme to 'NoColor'""" - new_scheme = 'NoColor' - warn(msg) - - # readline option is 0 - if not shell.colors_force and not shell.has_readline: - new_scheme = 'NoColor' - - # Set prompt colors - try: - shell.prompt_manager.color_scheme = new_scheme - except: - color_switch_err('prompt') - else: - shell.colors = \ - shell.prompt_manager.color_scheme_table.active_scheme_name - # Set exception colors - try: - shell.InteractiveTB.set_colors(scheme = new_scheme) - shell.SyntaxTB.set_colors(scheme = new_scheme) - except: - color_switch_err('exception') - - # Set info (for 'object?') colors - if shell.color_info: - try: - shell.inspector.set_active_scheme(new_scheme) - except: - color_switch_err('object inspector') - else: - shell.inspector.set_active_scheme('NoColor') - - def magic_pprint(self, parameter_s=''): - """Toggle pretty printing on/off.""" - ptformatter = self.shell.display_formatter.formatters['text/plain'] - ptformatter.pprint = bool(1 - ptformatter.pprint) - print 'Pretty printing has been turned', \ - ['OFF','ON'][ptformatter.pprint] - - #...................................................................... - # Functions to implement unix shell-type things - - @skip_doctest - def magic_alias(self, parameter_s = ''): - """Define an alias for a system command. - - '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd' - - Then, typing 'alias_name params' will execute the system command 'cmd - params' (from your underlying operating system). - - Aliases have lower precedence than magic functions and Python normal - variables, so if 'foo' is both a Python variable and an alias, the - alias can not be executed until 'del foo' removes the Python variable. - - You can use the %l specifier in an alias definition to represent the - whole line when the alias is called. For example:: - - In [2]: alias bracket echo "Input in brackets: <%l>" - In [3]: bracket hello world - Input in brackets: - - You can also define aliases with parameters using %s specifiers (one - per parameter):: - - In [1]: alias parts echo first %s second %s - In [2]: %parts A B - first A second B - In [3]: %parts A - Incorrect number of arguments: 2 expected. - parts is an alias to: 'echo first %s second %s' - - Note that %l and %s are mutually exclusive. You can only use one or - the other in your aliases. - - Aliases expand Python variables just like system calls using ! or !! - do: all expressions prefixed with '$' get expanded. For details of - the semantic rules, see PEP-215: - http://www.python.org/peps/pep-0215.html. This is the library used by - IPython for variable expansion. If you want to access a true shell - variable, an extra $ is necessary to prevent its expansion by - IPython:: - - In [6]: alias show echo - In [7]: PATH='A Python string' - In [8]: show $PATH - A Python string - In [9]: show $$PATH - /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... - - You can use the alias facility to acess all of $PATH. See the %rehash - and %rehashx functions, which automatically create aliases for the - contents of your $PATH. - - If called with no parameters, %alias prints the current alias table.""" - - par = parameter_s.strip() - if not par: - stored = self.db.get('stored_aliases', {} ) - aliases = sorted(self.shell.alias_manager.aliases) - # for k, v in stored: - # atab.append(k, v[0]) - - print "Total number of aliases:", len(aliases) - sys.stdout.flush() - return aliases - - # Now try to define a new one - try: - alias,cmd = par.split(None, 1) - except: - print oinspect.getdoc(self.magic_alias) - else: - self.shell.alias_manager.soft_define_alias(alias, cmd) - # end magic_alias - - def magic_unalias(self, parameter_s = ''): - """Remove an alias""" - - aname = parameter_s.strip() - self.shell.alias_manager.undefine_alias(aname) - stored = self.db.get('stored_aliases', {} ) - if aname in stored: - print "Removing %stored alias",aname - del stored[aname] - self.db['stored_aliases'] = stored - - def magic_rehashx(self, parameter_s = ''): - """Update the alias table with all executable files in $PATH. - - This version explicitly checks that every entry in $PATH is a file - with execute access (os.X_OK), so it is much slower than %rehash. - - Under Windows, it checks executability as a match against a - '|'-separated string of extensions, stored in the IPython config - variable win_exec_ext. This defaults to 'exe|com|bat'. - - This function also resets the root module cache of module completer, - used on slow filesystems. - """ - from IPython.core.alias import InvalidAliasError - - # for the benefit of module completer in ipy_completers.py - del self.shell.db['rootmodules'] - - path = [os.path.abspath(os.path.expanduser(p)) for p in - os.environ.get('PATH','').split(os.pathsep)] - path = filter(os.path.isdir,path) - - syscmdlist = [] - # Now define isexec in a cross platform manner. - if os.name == 'posix': - isexec = lambda fname:os.path.isfile(fname) and \ - os.access(fname,os.X_OK) - else: - try: - winext = os.environ['pathext'].replace(';','|').replace('.','') - except KeyError: - winext = 'exe|com|bat|py' - if 'py' not in winext: - winext += '|py' - execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) - isexec = lambda fname:os.path.isfile(fname) and execre.match(fname) - savedir = os.getcwdu() - - # Now walk the paths looking for executables to alias. - try: - # write the whole loop for posix/Windows so we don't have an if in - # the innermost part - if os.name == 'posix': - for pdir in path: - os.chdir(pdir) - for ff in os.listdir(pdir): - if isexec(ff): - try: - # Removes dots from the name since ipython - # will assume names with dots to be python. - self.shell.alias_manager.define_alias( - ff.replace('.',''), ff) - except InvalidAliasError: - pass - else: - syscmdlist.append(ff) - else: - no_alias = self.shell.alias_manager.no_alias - for pdir in path: - os.chdir(pdir) - for ff in os.listdir(pdir): - base, ext = os.path.splitext(ff) - if isexec(ff) and base.lower() not in no_alias: - if ext.lower() == '.exe': - ff = base - try: - # Removes dots from the name since ipython - # will assume names with dots to be python. - self.shell.alias_manager.define_alias( - base.lower().replace('.',''), ff) - except InvalidAliasError: - pass - syscmdlist.append(ff) - self.shell.db['syscmdlist'] = syscmdlist - finally: - os.chdir(savedir) - - @skip_doctest - def magic_pwd(self, parameter_s = ''): - """Return the current working directory path. - - Examples - -------- - :: - - In [9]: pwd - Out[9]: '/home/tsuser/sprint/ipython' - """ - return os.getcwdu() - - @skip_doctest - def magic_cd(self, parameter_s=''): - """Change the current working directory. - - This command automatically maintains an internal list of directories - you visit during your IPython session, in the variable _dh. The - command %dhist shows this history nicely formatted. You can also - do 'cd -' to see directory history conveniently. - - Usage: - - cd 'dir': changes to directory 'dir'. - - cd -: changes to the last visited directory. - - cd -: changes to the n-th directory in the directory history. - - cd --foo: change to directory that matches 'foo' in history - - cd -b : jump to a bookmark set by %bookmark - (note: cd is enough if there is no - directory , but a bookmark with the name exists.) - 'cd -b ' allows you to tab-complete bookmark names. - - Options: - - -q: quiet. Do not print the working directory after the cd command is - executed. By default IPython's cd command does print this directory, - since the default prompts do not display path information. - - Note that !cd doesn't work for this purpose because the shell where - !command runs is immediately discarded after executing 'command'. - - Examples - -------- - :: - - In [10]: cd parent/child - /home/tsuser/parent/child - """ - - parameter_s = parameter_s.strip() - #bkms = self.shell.persist.get("bookmarks",{}) - - oldcwd = os.getcwdu() - numcd = re.match(r'(-)(\d+)$',parameter_s) - # jump in directory history by number - if numcd: - nn = int(numcd.group(2)) - try: - ps = self.shell.user_ns['_dh'][nn] - except IndexError: - print 'The requested directory does not exist in history.' - return - else: - opts = {} - elif parameter_s.startswith('--'): - ps = None - fallback = None - pat = parameter_s[2:] - dh = self.shell.user_ns['_dh'] - # first search only by basename (last component) - for ent in reversed(dh): - if pat in os.path.basename(ent) and os.path.isdir(ent): - ps = ent - break - - if fallback is None and pat in ent and os.path.isdir(ent): - fallback = ent - - # if we have no last part match, pick the first full path match - if ps is None: - ps = fallback - - if ps is None: - print "No matching entry in directory history" - return - else: - opts = {} - - - else: - #turn all non-space-escaping backslashes to slashes, - # for c:\windows\directory\names\ - parameter_s = re.sub(r'\\(?! )','/', parameter_s) - opts,ps = self.parse_options(parameter_s,'qb',mode='string') - # jump to previous - if ps == '-': - try: - ps = self.shell.user_ns['_dh'][-2] - except IndexError: - raise UsageError('%cd -: No previous directory to change to.') - # jump to bookmark if needed - else: - if not os.path.isdir(ps) or opts.has_key('b'): - bkms = self.db.get('bookmarks', {}) - - if bkms.has_key(ps): - target = bkms[ps] - print '(bookmark:%s) -> %s' % (ps,target) - ps = target - else: - if opts.has_key('b'): - raise UsageError("Bookmark '%s' not found. " - "Use '%%bookmark -l' to see your bookmarks." % ps) - - # strip extra quotes on Windows, because os.chdir doesn't like them - ps = unquote_filename(ps) - # at this point ps should point to the target dir - if ps: - try: - os.chdir(os.path.expanduser(ps)) - if hasattr(self.shell, 'term_title') and self.shell.term_title: - set_term_title('IPython: ' + abbrev_cwd()) - except OSError: - print sys.exc_info()[1] - else: - cwd = os.getcwdu() - dhist = self.shell.user_ns['_dh'] - if oldcwd != cwd: - dhist.append(cwd) - self.db['dhist'] = compress_dhist(dhist)[-100:] - - else: - os.chdir(self.shell.home_dir) - if hasattr(self.shell, 'term_title') and self.shell.term_title: - set_term_title('IPython: ' + '~') - cwd = os.getcwdu() - dhist = self.shell.user_ns['_dh'] - - if oldcwd != cwd: - dhist.append(cwd) - self.db['dhist'] = compress_dhist(dhist)[-100:] - if not 'q' in opts and self.shell.user_ns['_dh']: - print self.shell.user_ns['_dh'][-1] - - - def magic_env(self, parameter_s=''): - """List environment variables.""" - - return dict(os.environ) - - def magic_pushd(self, parameter_s=''): - """Place the current dir on stack and change directory. - - Usage:\\ - %pushd ['dirname'] - """ - - dir_s = self.shell.dir_stack - tgt = os.path.expanduser(unquote_filename(parameter_s)) - cwd = os.getcwdu().replace(self.home_dir,'~') - if tgt: - self.magic_cd(parameter_s) - dir_s.insert(0,cwd) - return self.magic_dirs() - - def magic_popd(self, parameter_s=''): - """Change to directory popped off the top of the stack. - """ - if not self.shell.dir_stack: - raise UsageError("%popd on empty stack") - top = self.shell.dir_stack.pop(0) - self.magic_cd(top) - print "popd ->",top - - def magic_dirs(self, parameter_s=''): - """Return the current directory stack.""" - - 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 . - - Note that most of time, you should view directory history by entering - cd -. - - """ - - 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) - - @skip_doctest - def magic_sc(self, parameter_s=''): - """Shell capture - execute a shell command and capture its output. - - DEPRECATED. Suboptimal, retained for backwards compatibility. - - You should use the form 'var = !command' instead. Example: - - "%sc -l myfiles = ls ~" should now be written as - - "myfiles = !ls ~" - - myfiles.s, myfiles.l and myfiles.n still apply as documented - below. - - -- - %sc [options] varname=command - - IPython will run the given command using commands.getoutput(), and - will then update the user's interactive namespace with a variable - called varname, containing the value of the call. Your command can - contain shell wildcards, pipes, etc. - - The '=' sign in the syntax is mandatory, and the variable name you - supply must follow Python's standard conventions for valid names. - - (A special format without variable name exists for internal use) - - Options: - - -l: list output. Split the output on newlines into a list before - assigning it to the given variable. By default the output is stored - as a single string. - - -v: verbose. Print the contents of the variable. - - In most cases you should not need to split as a list, because the - returned value is a special type of string which can automatically - provide its contents either as a list (split on newlines) or as a - space-separated string. These are convenient, respectively, either - for sequential processing or to be passed to a shell command. - - For example:: - - # Capture into variable a - In [1]: sc a=ls *py - - # a is a string with embedded newlines - In [2]: a - Out[2]: 'setup.py\\nwin32_manual_post_install.py' - - # which can be seen as a list: - In [3]: a.l - Out[3]: ['setup.py', 'win32_manual_post_install.py'] - - # or as a whitespace-separated string: - In [4]: a.s - Out[4]: 'setup.py win32_manual_post_install.py' - - # a.s is useful to pass as a single command line: - In [5]: !wc -l $a.s - 146 setup.py - 130 win32_manual_post_install.py - 276 total - - # while the list form is useful to loop over: - In [6]: for f in a.l: - ...: !wc -l $f - ...: - 146 setup.py - 130 win32_manual_post_install.py - - Similarly, the lists returned by the -l option are also special, in - the sense that you can equally invoke the .s attribute on them to - automatically get a whitespace-separated string from their contents:: - - In [7]: sc -l b=ls *py - - In [8]: b - Out[8]: ['setup.py', 'win32_manual_post_install.py'] - - In [9]: b.s - Out[9]: 'setup.py win32_manual_post_install.py' - - In summary, both the lists and strings used for output capture have - the following special attributes:: - - .l (or .list) : value as list. - .n (or .nlstr): value as newline-separated string. - .s (or .spstr): value as space-separated string. - """ - - opts,args = self.parse_options(parameter_s,'lv') - # Try to get a variable name and command to run - try: - # the variable name must be obtained from the parse_options - # output, which uses shlex.split to strip options out. - var,_ = args.split('=',1) - var = var.strip() - # But the command has to be extracted from the original input - # parameter_s, not on what parse_options returns, to avoid the - # quote stripping which shlex.split performs on it. - _,cmd = parameter_s.split('=',1) - except ValueError: - var,cmd = '','' - # If all looks ok, proceed - split = 'l' in opts - out = self.shell.getoutput(cmd, split=split) - if opts.has_key('v'): - print '%s ==\n%s' % (var,pformat(out)) - if var: - self.shell.user_ns.update({var:out}) - else: - return out - - def magic_sx(self, parameter_s=''): - """Shell execute - run a shell command and capture its output. - - %sx command - - IPython will run the given command using commands.getoutput(), and - return the result formatted as a list (split on '\\n'). Since the - output is _returned_, it will be stored in ipython's regular output - cache Out[N] and in the '_N' automatic variables. - - Notes: - - 1) If an input line begins with '!!', then %sx is automatically - invoked. That is, while:: - - !ls - - causes ipython to simply issue system('ls'), typing:: - - !!ls - - is a shorthand equivalent to:: - - %sx ls - - 2) %sx differs from %sc in that %sx automatically splits into a list, - like '%sc -l'. The reason for this is to make it as easy as possible - to process line-oriented shell output via further python commands. - %sc is meant to provide much finer control, but requires more - typing. - - 3) Just like %sc -l, this is a list with special attributes: - :: - - .l (or .list) : value as list. - .n (or .nlstr): value as newline-separated string. - .s (or .spstr): value as whitespace-separated string. - - This is very useful when trying to use such lists as arguments to - system commands.""" - - if parameter_s: - return self.shell.getoutput(parameter_s) - - - def magic_bookmark(self, parameter_s=''): - """Manage IPython's bookmark system. - - %bookmark - set bookmark to current dir - %bookmark

- set bookmark to - %bookmark -l - list all bookmarks - %bookmark -d - remove bookmark - %bookmark -r - remove all bookmarks - - You can later on access a bookmarked folder with:: - - %cd -b - - or simply '%cd ' if there is no directory called AND - there is such a bookmark defined. - - Your bookmarks persist through IPython sessions, but they are - associated with each profile.""" - - opts,args = self.parse_options(parameter_s,'drl',mode='list') - if len(args) > 2: - raise UsageError("%bookmark: too many arguments") - - bkms = self.db.get('bookmarks',{}) - - if opts.has_key('d'): - try: - todel = args[0] - except IndexError: - raise UsageError( - "%bookmark -d: must provide a bookmark to delete") - else: - try: - del bkms[todel] - except KeyError: - raise UsageError( - "%%bookmark -d: Can't delete bookmark '%s'" % todel) - - elif opts.has_key('r'): - bkms = {} - elif opts.has_key('l'): - bks = bkms.keys() - bks.sort() - if bks: - size = max(map(len,bks)) - else: - size = 0 - fmt = '%-'+str(size)+'s -> %s' - print 'Current bookmarks:' - for bk in bks: - print fmt % (bk,bkms[bk]) - else: - if not args: - raise UsageError("%bookmark: You must specify the bookmark name") - elif len(args)==1: - bkms[args[0]] = os.getcwdu() - elif len(args)==2: - bkms[args[0]] = args[1] - self.db['bookmarks'] = bkms - - - def magic_pycat(self, parameter_s=''): - """Show a syntax-highlighted file through a pager. - - This magic is similar to the cat utility, but it will assume the file - to be Python source and will show it with syntax highlighting. - - This magic command can either take a local filename, an url, - an history range (see %history) or a macro as argument :: - - %pycat myscript.py - %pycat 7-27 - %pycat myMacro - %pycat http://www.example.com/myscript.py - """ - - try : - cont = self.shell.find_user_code(parameter_s) - except ValueError, IOError: - print "Error: no such file, variable, URL, history range or macro" - return - - page.page(self.shell.pycolorize(cont)) - - def magic_quickref(self,arg): - """ Show a quick reference sheet """ - import IPython.core.usage - qr = IPython.core.usage.quick_reference + self.magic_magic('-brief') - - page.page(qr) - - def magic_doctest_mode(self,parameter_s=''): - """Toggle doctest mode on and off. - - This mode is intended to make IPython behave as much as possible like a - plain Python shell, from the perspective of how its prompts, exceptions - and output look. This makes it easy to copy and paste parts of a - session into doctests. It does so by: - - - Changing the prompts to the classic ``>>>`` ones. - - Changing the exception reporting mode to 'Plain'. - - Disabling pretty-printing of output. - - Note that IPython also supports the pasting of code snippets that have - leading '>>>' and '...' prompts in them. This means that you can paste - doctests from files or docstrings (even if they have leading - whitespace), and the code will execute correctly. You can then use - '%history -t' to see the translated history; this will give you the - input after removal of all the leading prompts and whitespace, which - can be pasted back into an editor. - - With these features, you can switch into this mode easily whenever you - need to do testing and changes to doctests, without having to leave - your existing IPython session. - """ - - from IPython.utils.ipstruct import Struct - - # Shorthands - shell = self.shell - pm = shell.prompt_manager - meta = shell.meta - disp_formatter = self.shell.display_formatter - ptformatter = disp_formatter.formatters['text/plain'] - # dstore is a data store kept in the instance metadata bag to track any - # changes we make, so we can undo them later. - dstore = meta.setdefault('doctest_mode',Struct()) - save_dstore = dstore.setdefault - - # save a few values we'll need to recover later - mode = save_dstore('mode',False) - save_dstore('rc_pprint',ptformatter.pprint) - save_dstore('xmode',shell.InteractiveTB.mode) - save_dstore('rc_separate_out',shell.separate_out) - save_dstore('rc_separate_out2',shell.separate_out2) - save_dstore('rc_prompts_pad_left',pm.justify) - save_dstore('rc_separate_in',shell.separate_in) - save_dstore('rc_plain_text_only',disp_formatter.plain_text_only) - save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template)) - - if mode == False: - # turn on - pm.in_template = '>>> ' - pm.in2_template = '... ' - pm.out_template = '' - - # Prompt separators like plain python - shell.separate_in = '' - shell.separate_out = '' - shell.separate_out2 = '' - - pm.justify = False - - ptformatter.pprint = False - disp_formatter.plain_text_only = True - - shell.magic_xmode('Plain') - else: - # turn off - pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates - - shell.separate_in = dstore.rc_separate_in - - shell.separate_out = dstore.rc_separate_out - shell.separate_out2 = dstore.rc_separate_out2 - - pm.justify = dstore.rc_prompts_pad_left - - ptformatter.pprint = dstore.rc_pprint - disp_formatter.plain_text_only = dstore.rc_plain_text_only - - shell.magic_xmode(dstore.xmode) - - # Store new mode and inform - dstore.mode = bool(1-int(mode)) - mode_label = ['OFF','ON'][dstore.mode] - print 'Doctest mode is:', mode_label - - def magic_gui(self, parameter_s=''): - """Enable or disable IPython GUI event loop integration. - - %gui [GUINAME] - - This magic replaces IPython's threaded shells that were activated - using the (pylab/wthread/etc.) command line flags. GUI toolkits - can now be enabled at runtime and keyboard - interrupts should work without any problems. The following toolkits - are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX):: - - %gui wx # enable wxPython event loop integration - %gui qt4|qt # enable PyQt4 event loop integration - %gui gtk # enable PyGTK event loop integration - %gui gtk3 # enable Gtk3 event loop integration - %gui tk # enable Tk event loop integration - %gui OSX # enable Cocoa event loop integration - # (requires %matplotlib 1.1) - %gui # disable all event loop integration - - WARNING: after any of these has been called you can simply create - an application object, but DO NOT start the event loop yourself, as - we have already handled that. - """ - opts, arg = self.parse_options(parameter_s, '') - if arg=='': arg = None - try: - return self.enable_gui(arg) - except Exception as e: - # print simple error message, rather than traceback if we can't - # hook up the GUI - error(str(e)) - - def magic_install_ext(self, parameter_s): - """Download and install an extension from a URL, e.g.:: - - %install_ext https://bitbucket.org/birkenfeld/ipython-physics/raw/d1310a2ab15d/physics.py - - The URL should point to an importable Python module - either a .py file - or a .zip file. - - Parameters: - - -n filename : Specify a name for the file, rather than taking it from - the URL. - """ - opts, args = self.parse_options(parameter_s, 'n:') - try: - filename = self.extension_manager.install_extension(args, opts.get('n')) - except ValueError as e: - print e - return - - filename = os.path.basename(filename) - print "Installed %s. To use it, type:" % filename - print " %%load_ext %s" % os.path.splitext(filename)[0] - - - def magic_load_ext(self, module_str): - """Load an IPython extension by its module name.""" - return self.extension_manager.load_extension(module_str) - - def magic_unload_ext(self, module_str): - """Unload an IPython extension by its module name.""" - self.extension_manager.unload_extension(module_str) - - def magic_reload_ext(self, module_str): - """Reload an IPython extension by its module name.""" - self.extension_manager.reload_extension(module_str) - - def magic_install_profiles(self, s): - """%install_profiles has been deprecated.""" - print '\n'.join([ - "%install_profiles has been deprecated.", - "Use `ipython profile list` to view available profiles.", - "Requesting a profile with `ipython profile create `", - "or `ipython --profile=` will start with the bundled", - "profile of that name if it exists." - ]) - - def magic_install_default_config(self, s): - """%install_default_config has been deprecated.""" - print '\n'.join([ - "%install_default_config has been deprecated.", - "Use `ipython profile create ` to initialize a profile", - "with the default config files.", - "Add `--reset` to overwrite already existing config files with defaults." - ]) - - # Pylab support: simple wrappers that activate pylab, load gui input - # handling and modify slightly %run - - @skip_doctest - def _pylab_magic_run(self, parameter_s=''): - Magic.magic_run(self, parameter_s, - runner=mpl_runner(self.shell.safe_execfile)) - - _pylab_magic_run.__doc__ = magic_run.__doc__ - - @skip_doctest - def magic_pylab(self, s): - """Load numpy and matplotlib to work interactively. - - %pylab [GUINAME] - - This function lets you activate pylab (matplotlib, numpy and - interactive support) at any point during an IPython session. - - It will import at the top level numpy as np, pyplot as plt, matplotlib, - pylab and mlab, as well as all names from numpy and pylab. - - If you are using the inline matplotlib backend for embedded figures, - you can adjust its behavior via the %config magic:: - - # enable SVG figures, necessary for SVG+XHTML export in the qtconsole - In [1]: %config InlineBackend.figure_format = 'svg' - - # change the behavior of closing all figures at the end of each - # execution (cell), or allowing reuse of active figures across - # cells: - In [2]: %config InlineBackend.close_figures = False - - Parameters - ---------- - guiname : optional - One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk', - 'osx' or 'tk'). If given, the corresponding Matplotlib backend is - used, otherwise matplotlib's default (which you can override in your - matplotlib config file) is used. - - Examples - -------- - In this case, where the MPL default is TkAgg:: - - In [2]: %pylab - - Welcome to pylab, a matplotlib-based Python environment. - Backend in use: TkAgg - For more information, type 'help(pylab)'. - - But you can explicitly request a different backend:: - - In [3]: %pylab qt - - Welcome to pylab, a matplotlib-based Python environment. - Backend in use: Qt4Agg - For more information, type 'help(pylab)'. - """ - - if Application.initialized(): - app = Application.instance() - try: - import_all_status = app.pylab_import_all - except AttributeError: - import_all_status = True - else: - import_all_status = True - - self.shell.enable_pylab(s, import_all=import_all_status) - - def magic_tb(self, s): - """Print the last traceback with the currently active exception mode. - - See %xmode for changing exception reporting modes.""" - self.shell.showtraceback() - - @skip_doctest - def magic_precision(self, s=''): - """Set floating point precision for pretty printing. - - Can set either integer precision or a format string. - - If numpy has been imported and precision is an int, - numpy display precision will also be set, via ``numpy.set_printoptions``. - - If no argument is given, defaults will be restored. - - Examples - -------- - :: - - In [1]: from math import pi - - In [2]: %precision 3 - Out[2]: u'%.3f' - - In [3]: pi - Out[3]: 3.142 - - In [4]: %precision %i - Out[4]: u'%i' - - In [5]: pi - Out[5]: 3 - - In [6]: %precision %e - Out[6]: u'%e' - - In [7]: pi**10 - Out[7]: 9.364805e+04 - - In [8]: %precision - Out[8]: u'%r' - - In [9]: pi**10 - Out[9]: 93648.047476082982 - - """ - - ptformatter = self.shell.display_formatter.formatters['text/plain'] - ptformatter.float_precision = s - return ptformatter.float_format - - - @magic_arguments.magic_arguments() - @magic_arguments.argument( - '-e', '--export', action='store_true', default=False, - help='Export IPython history as a notebook. The filename argument ' - 'is used to specify the notebook name and format. For example ' - 'a filename of notebook.ipynb will result in a notebook name ' - 'of "notebook" and a format of "xml". Likewise using a ".json" ' - 'or ".py" file extension will write the notebook in the json ' - 'or py formats.' - ) - @magic_arguments.argument( - '-f', '--format', - help='Convert an existing IPython notebook to a new format. This option ' - 'specifies the new format and can have the values: xml, json, py. ' - 'The target filename is chosen automatically based on the new ' - 'format. The filename argument gives the name of the source file.' - ) - @magic_arguments.argument( - 'filename', type=unicode, - help='Notebook name or filename' - ) - def magic_notebook(self, s): - """Export and convert IPython notebooks. - - This function can export the current IPython history to a notebook file - or can convert an existing notebook file into a different format. For - example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb". - To export the history to "foo.py" do "%notebook -e foo.py". To convert - "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible - formats include (json/ipynb, py). - """ - args = magic_arguments.parse_argstring(self.magic_notebook, s) - - from IPython.nbformat import current - args.filename = unquote_filename(args.filename) - if args.export: - fname, name, format = current.parse_filename(args.filename) - cells = [] - hist = list(self.history_manager.get_range()) - for session, prompt_number, input in hist[:-1]: - cells.append(current.new_code_cell(prompt_number=prompt_number, input=input)) - worksheet = current.new_worksheet(cells=cells) - nb = current.new_notebook(name=name,worksheets=[worksheet]) - with io.open(fname, 'w', encoding='utf-8') as f: - current.write(nb, f, format); - elif args.format is not None: - old_fname, old_name, old_format = current.parse_filename(args.filename) - new_format = args.format - if new_format == u'xml': - raise ValueError('Notebooks cannot be written as xml.') - elif new_format == u'ipynb' or new_format == u'json': - new_fname = old_name + u'.ipynb' - new_format = u'json' - elif new_format == u'py': - new_fname = old_name + u'.py' - else: - raise ValueError('Invalid notebook format: %s' % new_format) - with io.open(old_fname, 'r', encoding='utf-8') as f: - nb = current.read(f, old_format) - with io.open(new_fname, 'w', encoding='utf-8') as f: - current.write(nb, f, new_format) - - def magic_config(self, s): - """configure IPython - - %config Class[.trait=value] - - This magic exposes most of the IPython config system. Any - Configurable class should be able to be configured with the simple - line:: - - %config Class.trait=value - - Where `value` will be resolved in the user's namespace, if it is an - expression or variable name. - - Examples - -------- - - To see what classes are available for config, pass no arguments:: - - In [1]: %config - Available objects for config: - TerminalInteractiveShell - HistoryManager - PrefilterManager - AliasManager - IPCompleter - PromptManager - DisplayFormatter - - To view what is configurable on a given class, just pass the class - name:: - - In [2]: %config IPCompleter - IPCompleter options - ----------------- - IPCompleter.omit__names= - Current: 2 - Choices: (0, 1, 2) - Instruct the completer to omit private method names - Specifically, when completing on ``object.``. - When 2 [default]: all names that start with '_' will be excluded. - When 1: all 'magic' names (``__foo__``) will be excluded. - When 0: nothing will be excluded. - IPCompleter.merge_completions= - Current: True - Whether to merge completion results into a single list - If False, only the completion results from the first non-empty completer - will be returned. - IPCompleter.limit_to__all__= - Current: False - Instruct the completer to use __all__ for the completion - Specifically, when completing on ``object.``. - When True: only those names in obj.__all__ will be included. - When False [default]: the __all__ attribute is ignored - IPCompleter.greedy= - Current: False - Activate greedy completion - This will enable completion on elements of lists, results of function calls, - etc., but can be unsafe because the code is actually evaluated on TAB. - - but the real use is in setting values:: - - In [3]: %config IPCompleter.greedy = True - - and these values are read from the user_ns if they are variables:: - - In [4]: feeling_greedy=False - - In [5]: %config IPCompleter.greedy = feeling_greedy - - """ - from IPython.config.loader import Config - # some IPython objects are Configurable, but do not yet have - # any configurable traits. Exclude them from the effects of - # this magic, as their presence is just noise: - configurables = [ c for c in self.configurables if c.__class__.class_traits(config=True) ] - classnames = [ c.__class__.__name__ for c in configurables ] - - line = s.strip() - if not line: - # print available configurable names - print "Available objects for config:" - for name in classnames: - print " ", name - return - elif line in classnames: - # `%config TerminalInteractiveShell` will print trait info for - # TerminalInteractiveShell - c = configurables[classnames.index(line)] - cls = c.__class__ - help = cls.class_get_help(c) - # strip leading '--' from cl-args: - help = re.sub(re.compile(r'^--', re.MULTILINE), '', help) - print help - return - elif '=' not in line: - raise UsageError("Invalid config statement: %r, should be Class.trait = value" % line) - - - # otherwise, assume we are setting configurables. - # leave quotes on args when splitting, because we want - # unquoted args to eval in user_ns - cfg = Config() - exec "cfg."+line in locals(), self.user_ns - - for configurable in configurables: - try: - configurable.update_config(cfg) - except Exception as e: - error(e) - -# end Magic + if fn not in self.lsmagic(): + error("%s is not a magic function" % fn) + self.options_table[fn] = optstr diff --git a/IPython/core/magics/__init__.py b/IPython/core/magics/__init__.py new file mode 100644 index 00000000000..23479b5f3e1 --- /dev/null +++ b/IPython/core/magics/__init__.py @@ -0,0 +1,40 @@ +"""Implementation of all the magic functions built into IPython. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +from ..magic import Magics, magics_class +from .auto import AutoMagics +from .basic import BasicMagics +from .code import CodeMagics, MacroToEdit +from .config import ConfigMagics +from .deprecated import DeprecatedMagics +from .execution import ExecutionMagics +from .extension import ExtensionMagics +from .history import HistoryMagics +from .logging import LoggingMagics +from .namespace import NamespaceMagics +from .osm import OSMagics +from .pylab import PylabMagics + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class UserMagics(Magics): + """Placeholder for user-defined magics to be added at runtime. + + All magics are eventually merged into a single namespace at runtime, but we + use this class to isolate the magics defined dynamically by the user into + their own class. + """ diff --git a/IPython/core/magics/auto.py b/IPython/core/magics/auto.py new file mode 100644 index 00000000000..04aff30dd8a --- /dev/null +++ b/IPython/core/magics/auto.py @@ -0,0 +1,128 @@ +"""Implementation of magic functions that control various automatic behaviors. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Our own packages +from IPython.core.magic import Bunch, Magics, magics_class, line_magic +from IPython.testing.skipdoctest import skip_doctest +from IPython.utils.warn import error + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class AutoMagics(Magics): + """Magics that control various autoX behaviors.""" + + def __init__(self, shell): + super(AutoMagics, self).__init__(shell) + # namespace for holding state we may need + self._magic_state = Bunch() + + @line_magic + def 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.""" + + arg = parameter_s.lower() + mman = self.shell.magics_manager + if arg in ('on', '1', 'true'): + val = True + elif arg in ('off', '0', 'false'): + val = False + else: + val = not mman.auto_magic + mman.auto_magic = val + print '\n' + self.shell.magics_manager.auto_status() + + @skip_doctest + @line_magic + def 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 [2]: float + ------> float() + Out[2]: 0.0 + + 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' + + # all-random (note for auto-testing) + """ + + 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): + self.shell.autocall = arg + else: # toggle + if self.shell.autocall: + self._magic_state.autocall_save = self.shell.autocall + self.shell.autocall = 0 + else: + try: + self.shell.autocall = self._magic_state.autocall_save + except AttributeError: + self.shell.autocall = self._magic_state.autocall_save = 1 + + print "Automatic calling is:",['OFF','Smart','Full'][self.shell.autocall] diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py new file mode 100644 index 00000000000..d1702535d87 --- /dev/null +++ b/IPython/core/magics/basic.py @@ -0,0 +1,538 @@ +"""Implementation of basic magic functions. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +from __future__ import print_function + +# Stdlib +import io +import sys +from pprint import pformat + +# Our own packages +from IPython.core.error import UsageError +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.core.prefilter import ESC_MAGIC +from IPython.utils.text import format_screen +from IPython.core import magic_arguments, page +from IPython.testing.skipdoctest import skip_doctest +from IPython.utils.ipstruct import Struct +from IPython.utils.path import unquote_filename +from IPython.utils.warn import warn, error + +#----------------------------------------------------------------------------- +# Magics class implementation +#----------------------------------------------------------------------------- + +@magics_class +class BasicMagics(Magics): + """Magics that provide central IPython functionality. + + These are various magics that don't fit into specific categories but that + are all part of the base 'IPython experience'.""" + + def _lsmagic(self): + mesc = ESC_MAGIC + cesc = mesc*2 + mman = self.shell.magics_manager + magics = mman.lsmagic() + out = ['Available line magics:', + mesc + (' '+mesc).join(magics['line']), + '', + 'Available cell magics:', + cesc + (' '+cesc).join(magics['cell']), + '', + mman.auto_status()] + return '\n'.join(out) + + @line_magic + def lsmagic(self, parameter_s=''): + """List currently available magic functions.""" + print(self._lsmagic()) + + @line_magic + def magic(self, parameter_s=''): + """Print information about the magic function system. + + Supported formats: -latex, -brief, -rest + """ + + mode = '' + try: + mode = parameter_s.split()[0][1:] + if mode == 'rest': + rest_docs = [] + except IndexError: + pass + + magic_docs = [] + escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC*2) + magics = self.shell.magics_manager.magics + + for mtype in ('line', 'cell'): + escape = escapes[mtype] + for fname, fn in magics[mtype].iteritems(): + + if mode == 'brief': + # only first line + if fn.__doc__: + fndoc = fn.__doc__.split('\n',1)[0] + else: + fndoc = 'No documentation' + else: + if fn.__doc__: + fndoc = fn.__doc__.rstrip() + else: + fndoc = 'No documentation' + + if mode == 'rest': + rest_docs.append('**%s%s**::\n\n\t%s\n\n' % + (escape, fname, fndoc)) + else: + magic_docs.append('%s%s:\n\t%s\n' % + (escape, fname, fndoc)) + + magic_docs = ''.join(magic_docs) + + if mode == 'rest': + return "".join(rest_docs) + + if mode == 'latex': + print(self.format_latex(magic_docs)) + return + else: + magic_docs = format_screen(magic_docs) + if mode == 'brief': + return magic_docs + + out = [""" +IPython's 'magic' functions +=========================== + +The magic function system provides a series of functions which allow you to +control the behavior of IPython itself, plus a lot of system-type +features. There are two kinds of magics, line-oriented and cell-oriented. + +Line magics are prefixed with the % character and work much like OS +command-line calls: they get as an argument the rest of the line, where +arguments are passed without parentheses or quotes. For example, this will +time the given statement:: + + %timeit range(1000) + +Cell magics are prefixed with a double %%, and they are functions that get as +an argument not only the rest of the line, but also the lines below it in a +separate argument. These magics are called with two arguments: the rest of the +call line and the body of the cell, consisting of the lines below the first. +For example:: + + %%timeit x = numpy.random.randn((100, 100)) + numpy.linalg.svd(x) + +will time the execution of the numpy svd routine, running the assignment of x +as part of the setup phase, which is not timed. + +In a line-oriented client (the terminal or Qt console IPython), starting a new +input with %% will automatically enter cell mode, and IPython will continue +reading input until a blank line is given. In the notebook, simply type the +whole cell as one entity, but keep in mind that the %% escape can only be at +the very start of the cell. + +NOTE: If you have 'automagic' enabled (via the command line option or with the +%automagic function), you don't need to type in the % explicitly for line +magics; cell magics always require an explicit '%%' escape. By default, +IPython ships with automagic on, so you should only rarely need the % escape. + +Example: typing '%cd mydir' (without the quotes) changes you working directory +to 'mydir', if it exists. + +For a list of the available magic functions, use %lsmagic. For a description +of any of them, type %magic_name?, e.g. '%cd?'. + +Currently the magic system has the following functions:""", + magic_docs, + "Summary of magic functions (from %slsmagic):", + self._lsmagic(), + ] + page.page('\n'.join(out)) + + + @line_magic + def page(self, parameter_s=''): + """Pretty print the object and display it through a pager. + + %page [options] OBJECT + + If no object is given, use _ (last output). + + Options: + + -r: page str(object), don't pretty-print it.""" + + # After a function contributed by Olivier Aubert, slightly modified. + + # Process options/args + opts, args = self.parse_options(parameter_s, 'r') + raw = 'r' in opts + + oname = args and args or '_' + info = self._ofind(oname) + if info['found']: + txt = (raw and str or pformat)( info['obj'] ) + page.page(txt) + else: + print('Object `%s` not found' % oname) + + @line_magic + def profile(self, parameter_s=''): + """Print your currently active IPython profile.""" + from IPython.core.application import BaseIPythonApplication + if BaseIPythonApplication.initialized(): + print(BaseIPythonApplication.instance().profile) + else: + error("profile is an application-level value, but you don't appear to be in an IPython application") + + @line_magic + def pprint(self, parameter_s=''): + """Toggle pretty printing on/off.""" + ptformatter = self.shell.display_formatter.formatters['text/plain'] + ptformatter.pprint = bool(1 - ptformatter.pprint) + print('Pretty printing has been turned', + ['OFF','ON'][ptformatter.pprint]) + + @line_magic + def colors(self, parameter_s=''): + """Switch color scheme for prompts, info system and exception handlers. + + Currently implemented schemes: NoColor, Linux, LightBG. + + Color scheme names are not case-sensitive. + + Examples + -------- + To get a plain black and white terminal:: + + %colors nocolor + """ + def color_switch_err(name): + warn('Error changing %s color schemes.\n%s' % + (name, sys.exc_info()[1])) + + + new_scheme = parameter_s.strip() + if not new_scheme: + raise UsageError( + "%colors: you must specify a color scheme. See '%colors?'") + return + # local shortcut + shell = self.shell + + import IPython.utils.rlineimpl as readline + + if not shell.colors_force and \ + not readline.have_readline and sys.platform == "win32": + msg = """\ +Proper color support under MS Windows requires the pyreadline library. +You can find it at: +http://ipython.org/pyreadline.html +Gary's readline needs the ctypes module, from: +http://starship.python.net/crew/theller/ctypes +(Note that ctypes is already part of Python versions 2.5 and newer). + +Defaulting color scheme to 'NoColor'""" + new_scheme = 'NoColor' + warn(msg) + + # readline option is 0 + if not shell.colors_force and not shell.has_readline: + new_scheme = 'NoColor' + + # Set prompt colors + try: + shell.prompt_manager.color_scheme = new_scheme + except: + color_switch_err('prompt') + else: + shell.colors = \ + shell.prompt_manager.color_scheme_table.active_scheme_name + # Set exception colors + try: + shell.InteractiveTB.set_colors(scheme = new_scheme) + shell.SyntaxTB.set_colors(scheme = new_scheme) + except: + color_switch_err('exception') + + # Set info (for 'object?') colors + if shell.color_info: + try: + shell.inspector.set_active_scheme(new_scheme) + except: + color_switch_err('object inspector') + else: + shell.inspector.set_active_scheme('NoColor') + + @line_magic + def xmode(self, parameter_s=''): + """Switch modes for the exception handlers. + + Valid modes: Plain, Context and Verbose. + + If called without arguments, acts as a toggle.""" + + def xmode_switch_err(name): + warn('Error changing %s exception modes.\n%s' % + (name,sys.exc_info()[1])) + + shell = self.shell + new_mode = parameter_s.strip().capitalize() + try: + shell.InteractiveTB.set_mode(mode=new_mode) + print('Exception reporting mode:',shell.InteractiveTB.mode) + except: + xmode_switch_err('user') + + @line_magic + def quickref(self,arg): + """ Show a quick reference sheet """ + from IPython.core.usage import quick_reference + qr = quick_reference + self.magic('-brief') + page.page(qr) + + @line_magic + def doctest_mode(self, parameter_s=''): + """Toggle doctest mode on and off. + + This mode is intended to make IPython behave as much as possible like a + plain Python shell, from the perspective of how its prompts, exceptions + and output look. This makes it easy to copy and paste parts of a + session into doctests. It does so by: + + - Changing the prompts to the classic ``>>>`` ones. + - Changing the exception reporting mode to 'Plain'. + - Disabling pretty-printing of output. + + Note that IPython also supports the pasting of code snippets that have + leading '>>>' and '...' prompts in them. This means that you can paste + doctests from files or docstrings (even if they have leading + whitespace), and the code will execute correctly. You can then use + '%history -t' to see the translated history; this will give you the + input after removal of all the leading prompts and whitespace, which + can be pasted back into an editor. + + With these features, you can switch into this mode easily whenever you + need to do testing and changes to doctests, without having to leave + your existing IPython session. + """ + + # Shorthands + shell = self.shell + pm = shell.prompt_manager + meta = shell.meta + disp_formatter = self.shell.display_formatter + ptformatter = disp_formatter.formatters['text/plain'] + # dstore is a data store kept in the instance metadata bag to track any + # changes we make, so we can undo them later. + dstore = meta.setdefault('doctest_mode',Struct()) + save_dstore = dstore.setdefault + + # save a few values we'll need to recover later + mode = save_dstore('mode',False) + save_dstore('rc_pprint',ptformatter.pprint) + save_dstore('xmode',shell.InteractiveTB.mode) + save_dstore('rc_separate_out',shell.separate_out) + save_dstore('rc_separate_out2',shell.separate_out2) + save_dstore('rc_prompts_pad_left',pm.justify) + save_dstore('rc_separate_in',shell.separate_in) + save_dstore('rc_plain_text_only',disp_formatter.plain_text_only) + save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template)) + + if mode == False: + # turn on + pm.in_template = '>>> ' + pm.in2_template = '... ' + pm.out_template = '' + + # Prompt separators like plain python + shell.separate_in = '' + shell.separate_out = '' + shell.separate_out2 = '' + + pm.justify = False + + ptformatter.pprint = False + disp_formatter.plain_text_only = True + + shell.magic('xmode Plain') + else: + # turn off + pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates + + shell.separate_in = dstore.rc_separate_in + + shell.separate_out = dstore.rc_separate_out + shell.separate_out2 = dstore.rc_separate_out2 + + pm.justify = dstore.rc_prompts_pad_left + + ptformatter.pprint = dstore.rc_pprint + disp_formatter.plain_text_only = dstore.rc_plain_text_only + + shell.magic('xmode ' + dstore.xmode) + + # Store new mode and inform + dstore.mode = bool(1-int(mode)) + mode_label = ['OFF','ON'][dstore.mode] + print('Doctest mode is:', mode_label) + + @line_magic + def gui(self, parameter_s=''): + """Enable or disable IPython GUI event loop integration. + + %gui [GUINAME] + + This magic replaces IPython's threaded shells that were activated + using the (pylab/wthread/etc.) command line flags. GUI toolkits + can now be enabled at runtime and keyboard + interrupts should work without any problems. The following toolkits + are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX):: + + %gui wx # enable wxPython event loop integration + %gui qt4|qt # enable PyQt4 event loop integration + %gui gtk # enable PyGTK event loop integration + %gui gtk3 # enable Gtk3 event loop integration + %gui tk # enable Tk event loop integration + %gui OSX # enable Cocoa event loop integration + # (requires %matplotlib 1.1) + %gui # disable all event loop integration + + WARNING: after any of these has been called you can simply create + an application object, but DO NOT start the event loop yourself, as + we have already handled that. + """ + opts, arg = self.parse_options(parameter_s, '') + if arg=='': arg = None + try: + return self.enable_gui(arg) + except Exception as e: + # print simple error message, rather than traceback if we can't + # hook up the GUI + error(str(e)) + + @skip_doctest + @line_magic + def precision(self, s=''): + """Set floating point precision for pretty printing. + + Can set either integer precision or a format string. + + If numpy has been imported and precision is an int, + numpy display precision will also be set, via ``numpy.set_printoptions``. + + If no argument is given, defaults will be restored. + + Examples + -------- + :: + + In [1]: from math import pi + + In [2]: %precision 3 + Out[2]: u'%.3f' + + In [3]: pi + Out[3]: 3.142 + + In [4]: %precision %i + Out[4]: u'%i' + + In [5]: pi + Out[5]: 3 + + In [6]: %precision %e + Out[6]: u'%e' + + In [7]: pi**10 + Out[7]: 9.364805e+04 + + In [8]: %precision + Out[8]: u'%r' + + In [9]: pi**10 + Out[9]: 93648.047476082982 + """ + ptformatter = self.shell.display_formatter.formatters['text/plain'] + ptformatter.float_precision = s + return ptformatter.float_format + + @magic_arguments.magic_arguments() + @magic_arguments.argument( + '-e', '--export', action='store_true', default=False, + help='Export IPython history as a notebook. The filename argument ' + 'is used to specify the notebook name and format. For example ' + 'a filename of notebook.ipynb will result in a notebook name ' + 'of "notebook" and a format of "xml". Likewise using a ".json" ' + 'or ".py" file extension will write the notebook in the json ' + 'or py formats.' + ) + @magic_arguments.argument( + '-f', '--format', + help='Convert an existing IPython notebook to a new format. This option ' + 'specifies the new format and can have the values: xml, json, py. ' + 'The target filename is chosen automatically based on the new ' + 'format. The filename argument gives the name of the source file.' + ) + @magic_arguments.argument( + 'filename', type=unicode, + help='Notebook name or filename' + ) + @line_magic + def notebook(self, s): + """Export and convert IPython notebooks. + + This function can export the current IPython history to a notebook file + or can convert an existing notebook file into a different format. For + example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb". + To export the history to "foo.py" do "%notebook -e foo.py". To convert + "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible + formats include (json/ipynb, py). + """ + args = magic_arguments.parse_argstring(self.notebook, s) + + from IPython.nbformat import current + args.filename = unquote_filename(args.filename) + if args.export: + fname, name, format = current.parse_filename(args.filename) + cells = [] + hist = list(self.shell.history_manager.get_range()) + for session, prompt_number, input in hist[:-1]: + cells.append(current.new_code_cell(prompt_number=prompt_number, + input=input)) + worksheet = current.new_worksheet(cells=cells) + nb = current.new_notebook(name=name,worksheets=[worksheet]) + with io.open(fname, 'w', encoding='utf-8') as f: + current.write(nb, f, format); + elif args.format is not None: + old_fname, old_name, old_format = current.parse_filename(args.filename) + new_format = args.format + if new_format == u'xml': + raise ValueError('Notebooks cannot be written as xml.') + elif new_format == u'ipynb' or new_format == u'json': + new_fname = old_name + u'.ipynb' + new_format = u'json' + elif new_format == u'py': + new_fname = old_name + u'.py' + else: + raise ValueError('Invalid notebook format: %s' % new_format) + with io.open(old_fname, 'r', encoding='utf-8') as f: + nb = current.read(f, old_format) + with io.open(new_fname, 'w', encoding='utf-8') as f: + current.write(nb, f, new_format) diff --git a/IPython/core/magics/code.py b/IPython/core/magics/code.py new file mode 100644 index 00000000000..faad35337ec --- /dev/null +++ b/IPython/core/magics/code.py @@ -0,0 +1,478 @@ +"""Implementation of code management magic functions. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import inspect +import io +import json +import os +import sys +from urllib2 import urlopen + +# Our own packages +from IPython.core.error import TryNext +from IPython.core.macro import Macro +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.testing.skipdoctest import skip_doctest +from IPython.utils import openpy +from IPython.utils import py3compat +from IPython.utils.io import file_read +from IPython.utils.path import get_py_filename, unquote_filename +from IPython.utils.warn import warn + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +# Used for exception handling in magic_edit +class MacroToEdit(ValueError): pass + + +@magics_class +class CodeMagics(Magics): + """Magics related to code management (loading, saving, editing, ...).""" + + @line_magic + def save(self, parameter_s=''): + """Save a set of lines or a macro to a given filename. + + Usage:\\ + %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ... + + Options: + + -r: use 'raw' input. By default, the 'processed' history is used, + so that magics are loaded in their transformed version to valid + Python. If this option is given, the raw input as typed as the + command line is used instead. + + This function uses the same syntax as %history for input ranges, + then saves the lines to the filename you specify. + + It adds a '.py' extension to the file if you don't do so yourself, and + it asks for confirmation before overwriting existing files.""" + + opts,args = self.parse_options(parameter_s,'r',mode='list') + fname, codefrom = unquote_filename(args[0]), " ".join(args[1:]) + if not fname.endswith('.py'): + fname += '.py' + if os.path.isfile(fname): + ans = raw_input('File `%s` exists. Overwrite (y/[N])? ' % fname) + if ans.lower() not in ['y','yes']: + print 'Operation cancelled.' + return + try: + cmds = self.shell.find_user_code(codefrom, 'r' in opts) + except (TypeError, ValueError) as e: + print e.args[0] + return + with io.open(fname,'w', encoding="utf-8") as f: + f.write(u"# coding: utf-8\n") + f.write(py3compat.cast_unicode(cmds)) + print 'The following commands were written to file `%s`:' % fname + print cmds + + @line_magic + def pastebin(self, parameter_s=''): + """Upload code to Github's Gist paste bin, returning the URL. + + Usage:\\ + %pastebin [-d "Custom description"] 1-7 + + The argument can be an input history range, a filename, or the name of a + string or macro. + + Options: + + -d: Pass a custom description for the gist. The default will say + "Pasted from IPython". + """ + opts, args = self.parse_options(parameter_s, 'd:') + + try: + code = self.shell.find_user_code(args) + except (ValueError, TypeError) as e: + print e.args[0] + return + + post_data = json.dumps({ + "description": opts.get('d', "Pasted from IPython"), + "public": True, + "files": { + "file1.py": { + "content": code + } + } + }).encode('utf-8') + + response = urlopen("https://api.github.com/gists", post_data) + response_data = json.loads(response.read().decode('utf-8')) + return response_data['html_url'] + + @line_magic + def loadpy(self, arg_s): + """Load a .py python script into the GUI console. + + This magic command can either take a local filename or a url:: + + %loadpy myscript.py + %loadpy http://www.example.com/myscript.py + """ + arg_s = unquote_filename(arg_s) + remote_url = arg_s.startswith(('http://', 'https://')) + local_url = not remote_url + if local_url and not arg_s.endswith('.py'): + # Local files must be .py; for remote URLs it's possible that the + # fetch URL doesn't have a .py in it (many servers have an opaque + # URL, such as scipy-central.org). + raise ValueError('%%loadpy only works with .py files: %s' % arg_s) + + # openpy takes care of finding the source encoding (per PEP 263) + if remote_url: + contents = openpy.read_py_url(arg_s, skip_encoding_cookie=True) + else: + contents = openpy.read_py_file(arg_s, skip_encoding_cookie=True) + + self.shell.set_next_input(contents) + + def _find_edit_target(self, args, opts, last_call): + """Utility method used by magic_edit to find what to edit.""" + + def make_filename(arg): + "Make a filename from the given args" + arg = unquote_filename(arg) + try: + filename = get_py_filename(arg) + except IOError: + # If it ends with .py but doesn't already exist, assume we want + # a new file. + if arg.endswith('.py'): + filename = arg + else: + filename = None + return filename + + # Set a few locals from the options for convenience: + opts_prev = 'p' in opts + opts_raw = 'r' in opts + + # custom exceptions + class DataIsObject(Exception): pass + + # Default line number value + lineno = opts.get('n',None) + + if opts_prev: + args = '_%s' % last_call[0] + if not self.shell.user_ns.has_key(args): + args = last_call[1] + + # use last_call to remember the state of the previous call, but don't + # let it be clobbered by successive '-p' calls. + try: + last_call[0] = self.shell.displayhook.prompt_count + if not opts_prev: + last_call[1] = args + except: + pass + + # by default this is done with temp files, except when the given + # arg is a filename + use_temp = True + + data = '' + + # First, see if the arguments should be a filename. + filename = make_filename(args) + if filename: + use_temp = False + elif args: + # Mode where user specifies ranges of lines, like in %macro. + data = self.shell.extract_input_lines(args, opts_raw) + if not data: + try: + # Load the parameter given as a variable. If not a string, + # process it as an object instead (below) + + #print '*** args',args,'type',type(args) # dbg + data = eval(args, self.shell.user_ns) + if not isinstance(data, basestring): + raise DataIsObject + + except (NameError,SyntaxError): + # given argument is not a variable, try as a filename + filename = make_filename(args) + if filename is None: + warn("Argument given (%s) can't be found as a variable " + "or as a filename." % args) + return + use_temp = False + + except DataIsObject: + # macros have a special edit function + if isinstance(data, Macro): + raise MacroToEdit(data) + + # For objects, try to edit the file where they are defined + try: + filename = inspect.getabsfile(data) + if 'fakemodule' in filename.lower() and \ + inspect.isclass(data): + # class created by %edit? Try to find source + # by looking for method definitions instead, the + # __module__ in those classes is FakeModule. + attrs = [getattr(data, aname) for aname in dir(data)] + for attr in attrs: + if not inspect.ismethod(attr): + continue + filename = inspect.getabsfile(attr) + if filename and \ + 'fakemodule' not in filename.lower(): + # change the attribute to be the edit + # target instead + data = attr + break + + datafile = 1 + except TypeError: + filename = make_filename(args) + datafile = 1 + warn('Could not find file where `%s` is defined.\n' + 'Opening a file named `%s`' % (args, filename)) + # Now, make sure we can actually read the source (if it was + # in a temp file it's gone by now). + if datafile: + try: + if lineno is None: + lineno = inspect.getsourcelines(data)[1] + except IOError: + filename = make_filename(args) + if filename is None: + warn('The file `%s` where `%s` was defined ' + 'cannot be read.' % (filename, data)) + return + use_temp = False + + if use_temp: + filename = self.shell.mktempfile(data) + print 'IPython will make a temporary file named:',filename + + return filename, lineno, use_temp + + def _edit_macro(self,mname,macro): + """open an editor with the macro data in a file""" + filename = self.shell.mktempfile(macro.value) + self.shell.hooks.editor(filename) + + # and make a new macro object, to replace the old one + mfile = open(filename) + mvalue = mfile.read() + mfile.close() + self.shell.user_ns[mname] = Macro(mvalue) + + @line_magic + def ed(self, parameter_s=''): + """Alias to %edit.""" + return self.edit(parameter_s) + + @skip_doctest + @line_magic + def edit(self, parameter_s='',last_call=['','']): + """Bring up an editor and execute the resulting code. + + Usage: + %edit [options] [args] + + %edit runs IPython's editor hook. The default version of this hook is + set to call the editor specified by your $EDITOR environment variable. + If this isn't found, it will default to vi under Linux/Unix and to + notepad under Windows. See the end of this docstring for how to change + the editor hook. + + You can also set the value of this editor via the + ``TerminalInteractiveShell.editor`` option in your configuration file. + This is useful if you wish to use a different editor from your typical + default with IPython (and for Windows users who typically don't set + environment variables). + + This command allows you to conveniently edit multi-line code right in + your IPython session. + + If called without arguments, %edit opens up an empty editor with a + temporary file and will execute the contents of this file when you + close it (don't forget to save it!). + + + Options: + + -n : open the editor at a specified line number. By default, + the IPython editor hook uses the unix syntax 'editor +N filename', but + you can configure this by providing your own modified hook if your + favorite editor supports line-number specifications with a different + syntax. + + -p: this will call the editor with the same data as the previous time + it was used, regardless of how long ago (in your current session) it + was. + + -r: use 'raw' input. This option only applies to input taken from the + user's history. By default, the 'processed' history is used, so that + magics are loaded in their transformed version to valid Python. If + this option is given, the raw input as typed as the command line is + used instead. When you exit the editor, it will be executed by + IPython's own processor. + + -x: do not execute the edited code immediately upon exit. This is + mainly useful if you are editing programs which need to be called with + command line arguments, which you can then do using %run. + + + Arguments: + + If arguments are given, the following possibilities exist: + + - If the argument is a filename, IPython will load that into the + editor. It will execute its contents with execfile() when you exit, + loading any code in the file into your interactive namespace. + + - The arguments are ranges of input history, e.g. "7 ~1/4-6". + The syntax is the same as in the %history magic. + + - If the argument is a string variable, its contents are loaded + into the editor. You can thus edit any string which contains + python code (including the result of previous edits). + + - If the argument is the name of an object (other than a string), + IPython will try to locate the file where it was defined and open the + editor at the point where it is defined. You can use `%edit function` + to load an editor exactly at the point where 'function' is defined, + edit it and have the file be executed automatically. + + - If the object is a macro (see %macro for details), this opens up your + specified editor with a temporary file containing the macro's data. + Upon exit, the macro is reloaded with the contents of the file. + + Note: opening at an exact line is only supported under Unix, and some + editors (like kedit and gedit up to Gnome 2.8) do not understand the + '+NUMBER' parameter necessary for this feature. Good editors like + (X)Emacs, vi, jed, pico and joe all do. + + After executing your code, %edit will return as output the code you + typed in the editor (except when it was an existing file). This way + you can reload the code in further invocations of %edit as a variable, + via _ or Out[], where is the prompt number of + the output. + + Note that %edit is also available through the alias %ed. + + This is an example of creating a simple function inside the editor and + then modifying it. First, start up the editor:: + + In [1]: ed + Editing... done. Executing edited code... + Out[1]: 'def foo():\\n print "foo() was defined in an editing + session"\\n' + + We can then call the function foo():: + + In [2]: foo() + foo() was defined in an editing session + + Now we edit foo. IPython automatically loads the editor with the + (temporary) file where foo() was previously defined:: + + In [3]: ed foo + Editing... done. Executing edited code... + + And if we call foo() again we get the modified version:: + + In [4]: foo() + foo() has now been changed! + + Here is an example of how to edit a code snippet successive + times. First we call the editor:: + + In [5]: ed + Editing... done. Executing edited code... + hello + Out[5]: "print 'hello'\\n" + + Now we call it again with the previous output (stored in _):: + + In [6]: ed _ + Editing... done. Executing edited code... + hello world + Out[6]: "print 'hello world'\\n" + + Now we call it with the output #8 (stored in _8, also as Out[8]):: + + In [7]: ed _8 + Editing... done. Executing edited code... + hello again + Out[7]: "print 'hello again'\\n" + + + Changing the default editor hook: + + If you wish to write your own editor hook, you can put it in a + configuration file which you load at startup time. The default hook + is defined in the IPython.core.hooks module, and you can use that as a + starting example for further modifications. That file also has + general instructions on how to set a new hook for use once you've + defined it.""" + opts,args = self.parse_options(parameter_s,'prxn:') + + try: + filename, lineno, is_temp = self._find_edit_target(args, opts, last_call) + except MacroToEdit as e: + self._edit_macro(args, e.args[0]) + return + + # do actual editing here + print 'Editing...', + sys.stdout.flush() + try: + # Quote filenames that may have spaces in them + if ' ' in filename: + filename = "'%s'" % filename + self.shell.hooks.editor(filename,lineno) + except TryNext: + warn('Could not open editor') + return + + # XXX TODO: should this be generalized for all string vars? + # For now, this is special-cased to blocks created by cpaste + if args.strip() == 'pasted_block': + self.shell.user_ns['pasted_block'] = file_read(filename) + + if 'x' in opts: # -x prevents actual execution + print + else: + print 'done. Executing edited code...' + if 'r' in opts: # Untranslated IPython code + self.shell.run_cell(file_read(filename), + store_history=False) + else: + self.shell.safe_execfile(filename, self.shell.user_ns, + self.shell.user_ns) + + if is_temp: + try: + return open(filename).read() + except IOError,msg: + if msg.filename == filename: + warn('File not found. Did you forget to save?') + return + else: + self.shell.showtraceback() diff --git a/IPython/core/magics/config.py b/IPython/core/magics/config.py new file mode 100644 index 00000000000..5480d129016 --- /dev/null +++ b/IPython/core/magics/config.py @@ -0,0 +1,146 @@ +"""Implementation of configuration-related magic functions. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import re + +# Our own packages +from IPython.core.error import UsageError +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.utils.warn import error + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class ConfigMagics(Magics): + + def __init__(self, shell): + super(ConfigMagics, self).__init__(shell) + self.configurables = [] + + @line_magic + def config(self, s): + """configure IPython + + %config Class[.trait=value] + + This magic exposes most of the IPython config system. Any + Configurable class should be able to be configured with the simple + line:: + + %config Class.trait=value + + Where `value` will be resolved in the user's namespace, if it is an + expression or variable name. + + Examples + -------- + + To see what classes are available for config, pass no arguments:: + + In [1]: %config + Available objects for config: + TerminalInteractiveShell + HistoryManager + PrefilterManager + AliasManager + IPCompleter + PromptManager + DisplayFormatter + + To view what is configurable on a given class, just pass the class + name:: + + In [2]: %config IPCompleter + IPCompleter options + ----------------- + IPCompleter.omit__names= + Current: 2 + Choices: (0, 1, 2) + Instruct the completer to omit private method names + Specifically, when completing on ``object.``. + When 2 [default]: all names that start with '_' will be excluded. + When 1: all 'magic' names (``__foo__``) will be excluded. + When 0: nothing will be excluded. + IPCompleter.merge_completions= + Current: True + Whether to merge completion results into a single list + If False, only the completion results from the first non-empty + completer will be returned. + IPCompleter.limit_to__all__= + Current: False + Instruct the completer to use __all__ for the completion + Specifically, when completing on ``object.``. + When True: only those names in obj.__all__ will be included. + When False [default]: the __all__ attribute is ignored + IPCompleter.greedy= + Current: False + Activate greedy completion + This will enable completion on elements of lists, results of + function calls, etc., but can be unsafe because the code is + actually evaluated on TAB. + + but the real use is in setting values:: + + In [3]: %config IPCompleter.greedy = True + + and these values are read from the user_ns if they are variables:: + + In [4]: feeling_greedy=False + + In [5]: %config IPCompleter.greedy = feeling_greedy + + """ + from IPython.config.loader import Config + # some IPython objects are Configurable, but do not yet have + # any configurable traits. Exclude them from the effects of + # this magic, as their presence is just noise: + configurables = [ c for c in self.shell.configurables + if c.__class__.class_traits(config=True) ] + classnames = [ c.__class__.__name__ for c in configurables ] + + line = s.strip() + if not line: + # print available configurable names + print "Available objects for config:" + for name in classnames: + print " ", name + return + elif line in classnames: + # `%config TerminalInteractiveShell` will print trait info for + # TerminalInteractiveShell + c = configurables[classnames.index(line)] + cls = c.__class__ + help = cls.class_get_help(c) + # strip leading '--' from cl-args: + help = re.sub(re.compile(r'^--', re.MULTILINE), '', help) + print help + return + elif '=' not in line: + raise UsageError("Invalid config statement: %r, " + "should be Class.trait = value" % line) + + # otherwise, assume we are setting configurables. + # leave quotes on args when splitting, because we want + # unquoted args to eval in user_ns + cfg = Config() + exec "cfg."+line in locals(), self.shell.user_ns + + for configurable in configurables: + try: + configurable.update_config(cfg) + except Exception as e: + error(e) diff --git a/IPython/core/magics/deprecated.py b/IPython/core/magics/deprecated.py new file mode 100644 index 00000000000..254b101c934 --- /dev/null +++ b/IPython/core/magics/deprecated.py @@ -0,0 +1,45 @@ +"""Deprecated Magic functions. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Our own packages +from IPython.core.magic import Magics, magics_class, line_magic + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class DeprecatedMagics(Magics): + """Magics slated for later removal.""" + + @line_magic + def install_profiles(self, parameter_s=''): + """%install_profiles has been deprecated.""" + print '\n'.join([ + "%install_profiles has been deprecated.", + "Use `ipython profile list` to view available profiles.", + "Requesting a profile with `ipython profile create `", + "or `ipython --profile=` will start with the bundled", + "profile of that name if it exists." + ]) + + @line_magic + def install_default_config(self, parameter_s=''): + """%install_default_config has been deprecated.""" + print '\n'.join([ + "%install_default_config has been deprecated.", + "Use `ipython profile create ` to initialize a profile", + "with the default config files.", + "Add `--reset` to overwrite already existing config files with defaults." + ]) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py new file mode 100644 index 00000000000..3dab02bffc3 --- /dev/null +++ b/IPython/core/magics/execution.py @@ -0,0 +1,985 @@ +"""Implementation of execution-related magic functions. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import __builtin__ as builtin_mod +import bdb +import os +import sys +import time +from StringIO import StringIO + +# cProfile was added in Python2.5 +try: + import cProfile as profile + import pstats +except ImportError: + # profile isn't bundled by default in Debian for license reasons + try: + import profile, pstats + except ImportError: + profile = pstats = None + +# Our own packages +from IPython.core import debugger, oinspect +from IPython.core import page +from IPython.core.error import UsageError +from IPython.core.macro import Macro +from IPython.core.magic import (Magics, magics_class, line_magic, + line_cell_magic, on_off, needs_local_scope) +from IPython.testing.skipdoctest import skip_doctest +from IPython.utils import py3compat +from IPython.utils.ipstruct import Struct +from IPython.utils.module_paths import find_mod +from IPython.utils.path import get_py_filename, unquote_filename +from IPython.utils.timing import clock, clock2 +from IPython.utils.warn import warn, error + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class ExecutionMagics(Magics): + """Magics related to code execution, debugging, profiling, etc. + + """ + + def __init__(self, shell): + super(ExecutionMagics, self).__init__(shell) + if profile is None: + self.prun = self.profile_missing_notice + # Default execution function used to actually run user code. + self.default_runner = None + + def profile_missing_notice(self, *args, **kwargs): + error("""\ +The profile module could not be found. It has been removed from the standard +python packages because of its non-free license. To use profiling, install the +python-profiler package from non-free.""") + + @skip_doctest + @line_cell_magic + def prun(self, parameter_s='', cell=None, user_mode=True, + opts=None,arg_lst=None,prog_ns=None): + + """Run a statement through the python code profiler. + + Usage, in line mode: + %prun [options] statement + + Usage, in cell mode: + %%prun [options] [statement] + code... + code... + + In cell mode, the additional code lines are appended to the (possibly + empty) statement in the first line. Cell mode allows you to easily + profile multiline blocks without having to put them in a separate + function. + + The given statement (which doesn't require quote marks) is run via the + python profiler in a manner similar to the profile.run() function. + Namespaces are internally managed to work correctly; profile.run + cannot be used in IPython because it makes certain assumptions about + namespaces which do not hold under IPython. + + Options: + + -l : you can place restrictions on what or how much of the + profile gets printed. The limit value can be: + + * A string: only information for function names containing this string + is printed. + + * An integer: only these many lines are printed. + + * A float (between 0 and 1): this fraction of the report is printed + (for example, use a limit of 0.4 to see the topmost 40% only). + + You can combine several limits with repeated use of the option. For + example, '-l __init__ -l 5' will print only the topmost 5 lines of + information about class constructors. + + -r: return the pstats.Stats object generated by the profiling. This + object has all the information about the profile in it, and you can + later use it for further analysis or in other functions. + + -s : sort profile by given key. You can provide more than one key + by using the option several times: '-s key1 -s key2 -s key3...'. The + default sorting key is 'time'. + + The following is copied verbatim from the profile documentation + referenced below: + + When more than one key is provided, additional keys are used as + secondary criteria when the there is equality in all keys selected + before them. + + Abbreviations can be used for any key names, as long as the + abbreviation is unambiguous. The following are the keys currently + defined: + + Valid Arg Meaning + "calls" call count + "cumulative" cumulative time + "file" file name + "module" file name + "pcalls" primitive call count + "line" line number + "name" function name + "nfl" name/file/line + "stdname" standard name + "time" internal time + + Note that all sorts on statistics are in descending order (placing + most time consuming items first), where as name, file, and line number + searches are in ascending order (i.e., alphabetical). The subtle + distinction between "nfl" and "stdname" is that the standard name is a + sort of the name as printed, which means that the embedded line + numbers get compared in an odd way. For example, lines 3, 20, and 40 + would (if the file names were the same) appear in the string order + "20" "3" and "40". In contrast, "nfl" does a numeric compare of the + line numbers. In fact, sort_stats("nfl") is the same as + sort_stats("name", "file", "line"). + + -T : save profile results as shown on screen to a text + file. The profile is still shown on screen. + + -D : save (via dump_stats) profile statistics to given + filename. This data is in a format understood by the pstats module, and + is generated by a call to the dump_stats() method of profile + objects. The profile is still shown on screen. + + -q: suppress output to the pager. Best used with -T and/or -D above. + + If you want to run complete programs under the profiler's control, use + '%run -p [prof_opts] filename.py [args to program]' where prof_opts + contains profiler specific options as described here. + + You can read the complete documentation for the profile module with:: + + In [1]: import profile; profile.help() + """ + + opts_def = Struct(D=[''],l=[],s=['time'],T=['']) + + if user_mode: # regular user call + opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:q', + list_all=True, posix=False) + namespace = self.shell.user_ns + if cell is not None: + arg_str += '\n' + cell + else: # called to run a program by %run -p + try: + filename = get_py_filename(arg_lst[0]) + except IOError as e: + try: + msg = str(e) + except UnicodeError: + msg = e.message + error(msg) + return + + arg_str = 'execfile(filename,prog_ns)' + namespace = { + 'execfile': self.shell.safe_execfile, + 'prog_ns': prog_ns, + 'filename': filename + } + + opts.merge(opts_def) + + prof = profile.Profile() + try: + prof = prof.runctx(arg_str,namespace,namespace) + sys_exit = '' + except SystemExit: + sys_exit = """*** SystemExit exception caught in code being profiled.""" + + stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s) + + lims = opts.l + if lims: + lims = [] # rebuild lims with ints/floats/strings + for lim in opts.l: + try: + lims.append(int(lim)) + except ValueError: + try: + lims.append(float(lim)) + except ValueError: + lims.append(lim) + + # Trap output. + stdout_trap = StringIO() + + if hasattr(stats,'stream'): + # In newer versions of python, the stats object has a 'stream' + # attribute to write into. + stats.stream = stdout_trap + stats.print_stats(*lims) + else: + # For older versions, we manually redirect stdout during printing + sys_stdout = sys.stdout + try: + sys.stdout = stdout_trap + stats.print_stats(*lims) + finally: + sys.stdout = sys_stdout + + output = stdout_trap.getvalue() + output = output.rstrip() + + if 'q' not in opts: + page.page(output) + print sys_exit, + + dump_file = opts.D[0] + text_file = opts.T[0] + if dump_file: + dump_file = unquote_filename(dump_file) + prof.dump_stats(dump_file) + print '\n*** Profile stats marshalled to file',\ + `dump_file`+'.',sys_exit + if text_file: + text_file = unquote_filename(text_file) + pfile = open(text_file,'w') + pfile.write(output) + pfile.close() + print '\n*** Profile printout saved to text file',\ + `text_file`+'.',sys_exit + + if opts.has_key('r'): + return stats + else: + return None + + @line_magic + def pdb(self, parameter_s=''): + """Control the automatic calling of the pdb interactive debugger. + + Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without + argument it works as a toggle. + + When an exception is triggered, IPython can optionally call the + interactive pdb debugger after the traceback printout. %pdb toggles + this feature on and off. + + The initial state of this feature is set in your configuration + file (the option is ``InteractiveShell.pdb``). + + If you want to just activate the debugger AFTER an exception has fired, + without having to type '%pdb on' and rerunning your code, you can use + the %debug magic.""" + + par = parameter_s.strip().lower() + + if par: + try: + new_pdb = {'off':0,'0':0,'on':1,'1':1}[par] + except KeyError: + print ('Incorrect argument. Use on/1, off/0, ' + 'or nothing for a toggle.') + return + else: + # toggle + new_pdb = not self.shell.call_pdb + + # set on the shell + self.shell.call_pdb = new_pdb + print 'Automatic pdb calling has been turned',on_off(new_pdb) + + @line_magic + def debug(self, parameter_s=''): + """Activate the interactive debugger in post-mortem mode. + + If an exception has just occurred, this lets you inspect its stack + frames interactively. Note that this will always work only on the last + traceback that occurred, so you must call this quickly after an + exception that you wish to inspect has fired, because if another one + occurs, it clobbers the previous one. + + If you want IPython to automatically do this on every exception, see + the %pdb magic for more details. + """ + self.shell.debugger(force=True) + + @line_magic + def tb(self, s): + """Print the last traceback with the currently active exception mode. + + See %xmode for changing exception reporting modes.""" + self.shell.showtraceback() + + @skip_doctest + @line_magic + def run(self, parameter_s='', runner=None, + file_finder=get_py_filename): + """Run the named file inside IPython as a program. + + Usage:\\ + %run [-n -i -t [-N] -d [-b] -p [profile options]] file [args] + + Parameters after the filename are passed as command-line arguments to + the program (put in sys.argv). Then, control returns to IPython's + prompt. + + This is similar to running at a system prompt:\\ + $ python file args\\ + but with the advantage of giving you IPython's tracebacks, and of + loading all variables into your interactive namespace for further use + (unless -p is used, see below). + + The file is executed in a namespace initially consisting only of + __name__=='__main__' and sys.argv constructed as indicated. It thus + sees its environment as if it were being run as a stand-alone program + (except for sharing global objects such as previously imported + modules). But after execution, the IPython interactive namespace gets + updated with all variables defined in the program (except for __name__ + and sys.argv). This allows for very convenient loading of code for + interactive work, while giving each program a 'clean sheet' to run in. + + Options: + + -n: __name__ is NOT set to '__main__', but to the running file's name + without extension (as python does under import). This allows running + scripts and reloading the definitions in them without calling code + protected by an ' if __name__ == "__main__" ' clause. + + -i: run the file in IPython's namespace instead of an empty one. This + is useful if you are experimenting with code written in a text editor + which depends on variables defined interactively. + + -e: ignore sys.exit() calls or SystemExit exceptions in the script + being run. This is particularly useful if IPython is being used to + run unittests, which always exit with a sys.exit() call. In such + cases you are interested in the output of the test results, not in + seeing a traceback of the unittest module. + + -t: print timing information at the end of the run. IPython will give + you an estimated CPU time consumption for your script, which under + Unix uses the resource module to avoid the wraparound problems of + time.clock(). Under Unix, an estimate of time spent on system tasks + is also given (for Windows platforms this is reported as 0.0). + + If -t is given, an additional -N option can be given, where + must be an integer indicating how many times you want the script to + run. The final timing report will include total and per run results. + + For example (testing the script uniq_stable.py):: + + In [1]: run -t uniq_stable + + IPython CPU timings (estimated):\\ + User : 0.19597 s.\\ + System: 0.0 s.\\ + + In [2]: run -t -N5 uniq_stable + + IPython CPU timings (estimated):\\ + Total runs performed: 5\\ + Times : Total Per run\\ + User : 0.910862 s, 0.1821724 s.\\ + System: 0.0 s, 0.0 s. + + -d: run your program under the control of pdb, the Python debugger. + This allows you to execute your program step by step, watch variables, + etc. Internally, what IPython does is similar to calling: + + pdb.run('execfile("YOURFILENAME")') + + with a breakpoint set on line 1 of your file. You can change the line + number for this automatic breakpoint to be by using the -bN option + (where N must be an integer). For example:: + + %run -d -b40 myscript + + will set the first breakpoint at line 40 in myscript.py. Note that + the first breakpoint must be set on a line which actually does + something (not a comment or docstring) for it to stop execution. + + When the pdb debugger starts, you will see a (Pdb) prompt. You must + first enter 'c' (without quotes) to start execution up to the first + breakpoint. + + Entering 'help' gives information about the use of the debugger. You + can easily see pdb's full documentation with "import pdb;pdb.help()" + at a prompt. + + -p: run program under the control of the Python profiler module (which + prints a detailed report of execution times, function calls, etc). + + You can pass other options after -p which affect the behavior of the + profiler itself. See the docs for %prun for details. + + In this mode, the program's variables do NOT propagate back to the + IPython interactive namespace (because they remain in the namespace + where the profiler executes them). + + Internally this triggers a call to %prun, see its documentation for + details on the options available specifically for profiling. + + There is one special usage for which the text above doesn't apply: + if the filename ends with .ipy, the file is run as ipython script, + just as if the commands were written on IPython prompt. + + -m: specify module name to load instead of script path. Similar to + the -m option for the python interpreter. Use this option last if you + want to combine with other %run options. Unlike the python interpreter + only source modules are allowed no .pyc or .pyo files. + For example:: + + %run -m example + + will run the example module. + + """ + + # get arguments and set sys.argv for program to be run. + opts, arg_lst = self.parse_options(parameter_s, 'nidtN:b:pD:l:rs:T:em:', + mode='list', list_all=1) + if "m" in opts: + modulename = opts["m"][0] + modpath = find_mod(modulename) + if modpath is None: + warn('%r is not a valid modulename on sys.path'%modulename) + return + arg_lst = [modpath] + arg_lst + try: + filename = file_finder(arg_lst[0]) + except IndexError: + warn('you must provide at least a filename.') + print '\n%run:\n', oinspect.getdoc(self.run) + return + except IOError as e: + try: + msg = str(e) + except UnicodeError: + msg = e.message + error(msg) + return + + if filename.lower().endswith('.ipy'): + self.shell.safe_execfile_ipy(filename) + return + + # Control the response to exit() calls made by the script being run + exit_ignore = 'e' in opts + + # Make sure that the running script gets a proper sys.argv as if it + # were run from a system shell. + save_argv = sys.argv # save it for later restoring + + # simulate shell expansion on arguments, at least tilde expansion + args = [ os.path.expanduser(a) for a in arg_lst[1:] ] + + sys.argv = [filename] + args # put in the proper filename + # protect sys.argv from potential unicode strings on Python 2: + if not py3compat.PY3: + sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ] + + if 'i' in opts: + # Run in user's interactive namespace + prog_ns = self.shell.user_ns + __name__save = self.shell.user_ns['__name__'] + prog_ns['__name__'] = '__main__' + main_mod = self.shell.new_main_mod(prog_ns) + else: + # Run in a fresh, empty namespace + if 'n' in opts: + name = os.path.splitext(os.path.basename(filename))[0] + else: + name = '__main__' + + main_mod = self.shell.new_main_mod() + prog_ns = main_mod.__dict__ + prog_ns['__name__'] = name + + # Since '%run foo' emulates 'python foo.py' at the cmd line, we must + # set the __file__ global in the script's namespace + prog_ns['__file__'] = filename + + # pickle fix. See interactiveshell for an explanation. But we need to + # make sure that, if we overwrite __main__, we replace it at the end + main_mod_name = prog_ns['__name__'] + + if main_mod_name == '__main__': + restore_main = sys.modules['__main__'] + else: + restore_main = False + + # This needs to be undone at the end to prevent holding references to + # every single object ever created. + sys.modules[main_mod_name] = main_mod + + try: + stats = None + with self.shell.readline_no_record: + if 'p' in opts: + stats = self.prun('', None, False, opts, arg_lst, prog_ns) + else: + if 'd' in opts: + deb = debugger.Pdb(self.shell.colors) + # reset Breakpoint state, which is moronically kept + # in a class + bdb.Breakpoint.next = 1 + bdb.Breakpoint.bplist = {} + bdb.Breakpoint.bpbynumber = [None] + # Set an initial breakpoint to stop execution + maxtries = 10 + bp = int(opts.get('b', [1])[0]) + checkline = deb.checkline(filename, bp) + if not checkline: + for bp in range(bp + 1, bp + maxtries + 1): + if deb.checkline(filename, bp): + break + else: + msg = ("\nI failed to find a valid line to set " + "a breakpoint\n" + "after trying up to line: %s.\n" + "Please set a valid breakpoint manually " + "with the -b option." % bp) + error(msg) + return + # if we find a good linenumber, set the breakpoint + deb.do_break('%s:%s' % (filename, bp)) + # Start file run + print "NOTE: Enter 'c' at the", + print "%s prompt to start your script." % deb.prompt + ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns} + try: + deb.run('execfile("%s", prog_ns)' % filename, ns) + + except: + etype, value, tb = sys.exc_info() + # Skip three frames in the traceback: the %run one, + # one inside bdb.py, and the command-line typed by the + # user (run by exec in pdb itself). + self.shell.InteractiveTB(etype, value, tb, tb_offset=3) + else: + if runner is None: + runner = self.default_runner + if runner is None: + runner = self.shell.safe_execfile + if 't' in opts: + # timed execution + try: + nruns = int(opts['N'][0]) + if nruns < 1: + error('Number of runs must be >=1') + return + except (KeyError): + nruns = 1 + twall0 = time.time() + if nruns == 1: + t0 = clock2() + runner(filename, prog_ns, prog_ns, + exit_ignore=exit_ignore) + t1 = clock2() + t_usr = t1[0] - t0[0] + t_sys = t1[1] - t0[1] + print "\nIPython CPU timings (estimated):" + print " User : %10.2f s." % t_usr + print " System : %10.2f s." % t_sys + else: + runs = range(nruns) + t0 = clock2() + for nr in runs: + runner(filename, prog_ns, prog_ns, + exit_ignore=exit_ignore) + t1 = clock2() + t_usr = t1[0] - t0[0] + t_sys = t1[1] - t0[1] + print "\nIPython CPU timings (estimated):" + print "Total runs performed:", nruns + print " Times : %10.2f %10.2f" % ('Total', 'Per run') + print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns) + print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns) + twall1 = time.time() + print "Wall time: %10.2f s." % (twall1 - twall0) + + else: + # regular execution + runner(filename, prog_ns, prog_ns, exit_ignore=exit_ignore) + + if 'i' in opts: + self.shell.user_ns['__name__'] = __name__save + else: + # The shell MUST hold a reference to prog_ns so after %run + # exits, the python deletion mechanism doesn't zero it out + # (leaving dangling references). + self.shell.cache_main_mod(prog_ns, filename) + # update IPython interactive namespace + + # Some forms of read errors on the file may mean the + # __name__ key was never set; using pop we don't have to + # worry about a possible KeyError. + prog_ns.pop('__name__', None) + + self.shell.user_ns.update(prog_ns) + finally: + # It's a bit of a mystery why, but __builtins__ can change from + # being a module to becoming a dict missing some key data after + # %run. As best I can see, this is NOT something IPython is doing + # at all, and similar problems have been reported before: + # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html + # Since this seems to be done by the interpreter itself, the best + # we can do is to at least restore __builtins__ for the user on + # exit. + self.shell.user_ns['__builtins__'] = builtin_mod + + # Ensure key global structures are restored + sys.argv = save_argv + if restore_main: + sys.modules['__main__'] = restore_main + else: + # Remove from sys.modules the reference to main_mod we'd + # added. Otherwise it will trap references to objects + # contained therein. + del sys.modules[main_mod_name] + + return stats + + @skip_doctest + @line_cell_magic + def timeit(self, line='', cell=None): + """Time execution of a Python statement or expression + + Usage, in line mode: + %timeit [-n -r [-t|-c]] statement + or in cell mode: + %%timeit [-n -r [-t|-c]] setup_code + code + code... + + Time execution of a Python statement or expression using the timeit + module. This function can be used both as a line and cell magic: + + - In line mode you can time a single-line statement (though multiple + ones can be chained with using semicolons). + + - In cell mode, the statement in the first line is used as setup code + (executed but not timed) and the body of the cell is timed. The cell + body has access to any variables created in the setup code. + + Options: + -n: execute the given statement times in a loop. If this value + is not given, a fitting value is chosen. + + -r: repeat the loop iteration times and take the best result. + Default: 3 + + -t: use time.time to measure the time, which is the default on Unix. + This function measures wall time. + + -c: use time.clock to measure the time, which is the default on + Windows and measures wall time. On Unix, resource.getrusage is used + instead and returns the CPU user time. + + -p

: use a precision of

digits to display the timing result. + Default: 3 + + + Examples + -------- + :: + + In [1]: %timeit pass + 10000000 loops, best of 3: 53.3 ns per loop + + In [2]: u = None + + In [3]: %timeit u is None + 10000000 loops, best of 3: 184 ns per loop + + In [4]: %timeit -r 4 u == None + 1000000 loops, best of 4: 242 ns per loop + + In [5]: import time + + In [6]: %timeit -n1 time.sleep(2) + 1 loops, best of 3: 2 s per loop + + + The times reported by %timeit will be slightly higher than those + reported by the timeit.py script when variables are accessed. This is + due to the fact that %timeit executes the statement in the namespace + of the shell, compared with timeit.py, which uses a single setup + statement to import function or create variables. Generally, the bias + does not matter as long as results from timeit.py are not mixed with + those from %timeit.""" + + import timeit + import math + + # XXX: Unfortunately the unicode 'micro' symbol can cause problems in + # certain terminals. Until we figure out a robust way of + # auto-detecting if the terminal can deal with it, use plain 'us' for + # microseconds. I am really NOT happy about disabling the proper + # 'micro' prefix, but crashing is worse... If anyone knows what the + # right solution for this is, I'm all ears... + # + # Note: using + # + # s = u'\xb5' + # s.encode(sys.getdefaultencoding()) + # + # is not sufficient, as I've seen terminals where that fails but + # print s + # + # succeeds + # + # See bug: https://bugs.launchpad.net/ipython/+bug/348466 + + #units = [u"s", u"ms",u'\xb5',"ns"] + units = [u"s", u"ms",u'us',"ns"] + + scaling = [1, 1e3, 1e6, 1e9] + + opts, stmt = self.parse_options(line,'n:r:tcp:', + posix=False, strict=False) + if stmt == "": + return + timefunc = timeit.default_timer + number = int(getattr(opts, "n", 0)) + repeat = int(getattr(opts, "r", timeit.default_repeat)) + precision = int(getattr(opts, "p", 3)) + if hasattr(opts, "t"): + timefunc = time.time + if hasattr(opts, "c"): + timefunc = clock + + timer = timeit.Timer(timer=timefunc) + # this code has tight coupling to the inner workings of timeit.Timer, + # but is there a better way to achieve that the code stmt has access + # to the shell namespace? + + if cell is None: + # called as line magic + setup = 'pass' + stmt = timeit.reindent(stmt, 8) + else: + setup = timeit.reindent(stmt, 4) + stmt = timeit.reindent(cell, 8) + + src = timeit.template % dict(stmt=stmt, setup=setup) + # Track compilation time so it can be reported if too long + # Minimum time above which compilation time will be reported + tc_min = 0.1 + + t0 = clock() + code = compile(src, "", "exec") + tc = clock()-t0 + + ns = {} + exec code in self.shell.user_ns, ns + timer.inner = ns["inner"] + + if number == 0: + # determine number so that 0.2 <= total time < 2.0 + number = 1 + for i in range(1, 10): + if timer.timeit(number) >= 0.2: + break + number *= 10 + + best = min(timer.repeat(repeat, number)) / number + + if best > 0.0 and best < 1000.0: + order = min(-int(math.floor(math.log10(best)) // 3), 3) + elif best >= 1000.0: + order = 0 + else: + order = 3 + print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat, + precision, + best * scaling[order], + units[order]) + if tc > tc_min: + print "Compiler time: %.2f s" % tc + + @skip_doctest + @needs_local_scope + @line_magic + def time(self,parameter_s, user_locals): + """Time execution of a Python statement or expression. + + The CPU and wall clock times are printed, and the value of the + expression (if any) is returned. Note that under Win32, system time + is always reported as 0, since it can not be measured. + + This function provides very basic timing functionality. In Python + 2.3, the timeit module offers more control and sophistication, so this + could be rewritten to use it (patches welcome). + + Examples + -------- + :: + + In [1]: time 2**128 + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.00 + Out[1]: 340282366920938463463374607431768211456L + + In [2]: n = 1000000 + + In [3]: time sum(range(n)) + CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s + Wall time: 1.37 + Out[3]: 499999500000L + + In [4]: time print 'hello world' + hello world + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.00 + + Note that the time needed by Python to compile the given expression + will be reported if it is more than 0.1s. In this example, the + actual exponentiation is done by Python at compilation time, so while + the expression can take a noticeable amount of time to compute, that + time is purely due to the compilation: + + In [5]: time 3**9999; + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.00 s + + In [6]: time 3**999999; + CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s + Wall time: 0.00 s + Compiler : 0.78 s + """ + + # fail immediately if the given expression can't be compiled + + expr = self.shell.prefilter(parameter_s,False) + + # Minimum time above which compilation time will be reported + tc_min = 0.1 + + try: + mode = 'eval' + t0 = clock() + code = compile(expr,'',mode) + tc = clock()-t0 + except SyntaxError: + mode = 'exec' + t0 = clock() + code = compile(expr,'',mode) + tc = clock()-t0 + # skew measurement as little as possible + glob = self.shell.user_ns + wtime = time.time + # time execution + wall_st = wtime() + if mode=='eval': + st = clock2() + out = eval(code, glob, user_locals) + end = clock2() + else: + st = clock2() + exec code in glob, user_locals + end = clock2() + out = None + wall_end = wtime() + # Compute actual times and report + wall_time = wall_end-wall_st + cpu_user = end[0]-st[0] + cpu_sys = end[1]-st[1] + cpu_tot = cpu_user+cpu_sys + print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \ + (cpu_user,cpu_sys,cpu_tot) + print "Wall time: %.2f s" % wall_time + if tc > tc_min: + print "Compiler : %.2f s" % tc + return out + + @skip_doctest + @line_magic + def macro(self, parameter_s=''): + """Define a macro for future re-execution. It accepts ranges of history, + filenames or string objects. + + Usage:\\ + %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ... + + Options: + + -r: use 'raw' input. By default, the 'processed' history is used, + so that magics are loaded in their transformed version to valid + Python. If this option is given, the raw input as typed as the + command line is used instead. + + This will define a global variable called `name` which is a string + made of joining the slices and lines you specify (n1,n2,... numbers + above) from your input history into a single string. This variable + acts like an automatic function which re-executes those lines as if + you had typed them. You just type 'name' at the prompt and the code + executes. + + The syntax for indicating input ranges is described in %history. + + Note: as a 'hidden' feature, you can also use traditional python slice + notation, where N:M means numbers N through M-1. + + For example, if your history contains (%hist prints it):: + + 44: x=1 + 45: y=3 + 46: z=x+y + 47: print x + 48: a=5 + 49: print 'x',x,'y',y + + you can create a macro with lines 44 through 47 (included) and line 49 + called my_macro with:: + + In [55]: %macro my_macro 44-47 49 + + Now, typing `my_macro` (without quotes) will re-execute all this code + in one pass. + + You don't need to give the line-numbers in order, and any given line + number can appear multiple times. You can assemble macros with any + lines from your input history in any order. + + The macro is a simple object which holds its value in an attribute, + but IPython's display system checks for macros and executes them as + code instead of printing them when you type their name. + + You can view a macro's contents by explicitly printing it with:: + + print macro_name + + """ + opts,args = self.parse_options(parameter_s,'r',mode='list') + if not args: # List existing macros + return sorted(k for k,v in self.shell.user_ns.iteritems() if\ + isinstance(v, Macro)) + if len(args) == 1: + raise UsageError( + "%macro insufficient args; usage '%macro name n1-n2 n3-4...") + name, codefrom = args[0], " ".join(args[1:]) + + #print 'rng',ranges # dbg + try: + lines = self.shell.find_user_code(codefrom, 'r' in opts) + except (ValueError, TypeError) as e: + print e.args[0] + return + macro = Macro(lines) + self.shell.define_macro(name, macro) + print 'Macro `%s` created. To execute, type its name (without quotes).' % name + print '=== Macro contents: ===' + print macro, diff --git a/IPython/core/magics/extension.py b/IPython/core/magics/extension.py new file mode 100644 index 00000000000..37982e54fab --- /dev/null +++ b/IPython/core/magics/extension.py @@ -0,0 +1,69 @@ +"""Implementation of magic functions for the extension machinery. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import os + +# Our own packages +from IPython.core.magic import Magics, magics_class, line_magic + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class ExtensionMagics(Magics): + """Magics to manage the IPython extensions system.""" + + @line_magic + def install_ext(self, parameter_s=''): + """Download and install an extension from a URL, e.g.:: + + %install_ext https://bitbucket.org/birkenfeld/ipython-physics/raw/d1310a2ab15d/physics.py + + The URL should point to an importable Python module - either a .py file + or a .zip file. + + Parameters: + + -n filename : Specify a name for the file, rather than taking it from + the URL. + """ + opts, args = self.parse_options(parameter_s, 'n:') + try: + filename = self.shell.extension_manager.install_extension(args, + opts.get('n')) + except ValueError as e: + print e + return + + filename = os.path.basename(filename) + print "Installed %s. To use it, type:" % filename + print " %%load_ext %s" % os.path.splitext(filename)[0] + + + @line_magic + def load_ext(self, module_str): + """Load an IPython extension by its module name.""" + return self.shell.extension_manager.load_extension(module_str) + + @line_magic + def unload_ext(self, module_str): + """Unload an IPython extension by its module name.""" + self.shell.extension_manager.unload_extension(module_str) + + @line_magic + def reload_ext(self, module_str): + """Reload an IPython extension by its module name.""" + self.shell.extension_manager.reload_extension(module_str) diff --git a/IPython/core/magics/history.py b/IPython/core/magics/history.py new file mode 100644 index 00000000000..594824dad83 --- /dev/null +++ b/IPython/core/magics/history.py @@ -0,0 +1,294 @@ +"""Implementation of magic functions related to History. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012, IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +from __future__ import print_function + +# Stdlib +import os +from io import open as io_open + +# Our own packages +from IPython.core.error import StdinNotImplementedError +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.testing.skipdoctest import skip_doctest +from IPython.utils import io + +#----------------------------------------------------------------------------- +# Magics class implementation +#----------------------------------------------------------------------------- + +@magics_class +class HistoryMagics(Magics): + + @skip_doctest + @line_magic + def history(self, parameter_s = ''): + """Print input history (_i variables), with most recent last. + + %history [-o -p -t -n] [-f filename] [range | -g pattern | -l number] + + By default, input history is printed without line numbers so it can be + directly pasted into an editor. Use -n to show them. + + By default, all input history from the current session is displayed. + Ranges of history can be indicated using the syntax: + 4 : Line 4, current session + 4-6 : Lines 4-6, current session + 243/1-5: Lines 1-5, session 243 + ~2/7 : Line 7, session 2 before current + ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line + of 6 sessions ago. + Multiple ranges can be entered, separated by spaces + + The same syntax is used by %macro, %save, %edit, %rerun + + Options: + + -n: print line numbers for each input. + This feature is only available if numbered prompts are in use. + + -o: also print outputs for each input. + + -p: print classic '>>>' python prompts before each input. This is + useful for making documentation, and in conjunction with -o, for + producing doctest-ready output. + + -r: (default) print the 'raw' history, i.e. the actual commands you + typed. + + -t: print the 'translated' history, as IPython understands it. + IPython filters your input and converts it all into valid Python + source before executing it (things like magics or aliases are turned + into function calls, for example). With this option, you'll see the + native history instead of the user-entered version: '%cd /' will be + seen as 'get_ipython().magic("%cd /")' instead of '%cd /'. + + -g: treat the arg as a pattern to grep for in (full) history. + This includes the saved history (almost all commands ever written). + Use '%hist -g' to show full saved history (may be very long). + + -l: get the last n lines from all sessions. Specify n as a single + arg, or the default is the last 10 lines. + + -f FILENAME: instead of printing the output to the screen, redirect + it to the given file. The file is always overwritten, though *when + it can*, IPython asks for confirmation first. In particular, running + the command 'history -f FILENAME' from the IPython Notebook + interface will replace FILENAME even if it already exists *without* + confirmation. + + Examples + -------- + :: + + In [6]: %hist -n 4-6 + 4:a = 12 + 5:print a**2 + 6:%hist -n 4-6 + + """ + + if not self.shell.displayhook.do_full_cache: + print('This feature is only available if numbered prompts ' + 'are in use.') + return + opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string') + + # For brevity + history_manager = self.shell.history_manager + + def _format_lineno(session, line): + """Helper function to format line numbers properly.""" + if session in (0, history_manager.session_number): + return str(line) + return "%s/%s" % (session, line) + + # Check if output to specific file was requested. + try: + outfname = opts['f'] + except KeyError: + outfile = io.stdout # default + # We don't want to close stdout at the end! + close_at_end = False + else: + if os.path.exists(outfname): + try: + ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname) + except StdinNotImplementedError: + ans = True + if not ans: + print('Aborting.') + return + print("Overwriting file.") + outfile = io_open(outfname, 'w', encoding='utf-8') + close_at_end = True + + print_nums = 'n' in opts + get_output = 'o' in opts + pyprompts = 'p' in opts + # Raw history is the default + raw = not('t' in opts) + + pattern = None + + if 'g' in opts: # Glob search + pattern = "*" + args + "*" if args else "*" + hist = history_manager.search(pattern, raw=raw, output=get_output) + print_nums = True + elif 'l' in opts: # Get 'tail' + try: + n = int(args) + except (ValueError, IndexError): + n = 10 + hist = history_manager.get_tail(n, raw=raw, output=get_output) + else: + if args: # Get history by ranges + hist = history_manager.get_range_by_str(args, raw, get_output) + else: # Just get history for the current session + hist = history_manager.get_range(raw=raw, output=get_output) + + # We could be displaying the entire history, so let's not try to pull + # it into a list in memory. Anything that needs more space will just + # misalign. + width = 4 + + for session, lineno, inline in hist: + # Print user history with tabs expanded to 4 spaces. The GUI + # clients use hard tabs for easier usability in auto-indented code, + # but we want to produce PEP-8 compliant history for safe pasting + # into an editor. + if get_output: + inline, output = inline + inline = inline.expandtabs(4).rstrip() + + multiline = "\n" in inline + line_sep = '\n' if multiline else ' ' + if print_nums: + print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width), + line_sep), file=outfile, end=u'') + if pyprompts: + print(u">>> ", end=u"", file=outfile) + if multiline: + inline = "\n... ".join(inline.splitlines()) + "\n..." + print(inline, file=outfile) + if get_output and output: + print(output, file=outfile) + + if close_at_end: + outfile.close() + + # For a long time we've had %hist as well as %history + @line_magic + def hist(self, arg): + return self.history(arg) + + hist.__doc__ = history.__doc__ + + @line_magic + def rep(self, arg): + r"""Repeat a command, or get command to input line for editing. + + %recall and %rep are equivalent. + + - %recall (no arguments): + + Place a string version of last computation result (stored in the + special '_' variable) to the next input prompt. Allows you to create + elaborate command lines without using copy-paste:: + + In[1]: l = ["hei", "vaan"] + In[2]: "".join(l) + Out[2]: heivaan + In[3]: %rep + In[4]: heivaan_ <== cursor blinking + + %recall 45 + + Place history line 45 on the next input prompt. Use %hist to find + out the number. + + %recall 1-4 + + Combine the specified lines into one cell, and place it on the next + input prompt. See %history for the slice syntax. + + %recall foo+bar + + If foo+bar can be evaluated in the user namespace, the result is + placed at the next input prompt. Otherwise, the history is searched + for lines which contain that substring, and the most recent one is + placed at the next input prompt. + """ + if not arg: # Last output + self.shell.set_next_input(str(self.shell.user_ns["_"])) + return + # Get history range + histlines = self.shell.history_manager.get_range_by_str(arg) + cmd = "\n".join(x[2] for x in histlines) + if cmd: + self.shell.set_next_input(cmd.rstrip()) + return + + try: # Variable in user namespace + cmd = str(eval(arg, self.shell.user_ns)) + except Exception: # Search for term in history + histlines = self.shell.history_manager.search("*"+arg+"*") + for h in reversed([x[2] for x in histlines]): + if 'rep' in h: + continue + self.shell.set_next_input(h.rstrip()) + return + else: + self.shell.set_next_input(cmd.rstrip()) + print("Couldn't evaluate or find in history:", arg) + + @line_magic + def rerun(self, parameter_s=''): + """Re-run previous input + + By default, you can specify ranges of input history to be repeated + (as with %history). With no arguments, it will repeat the last line. + + Options: + + -l : Repeat the last n lines of input, not including the + current command. + + -g foo : Repeat the most recent line which contains foo + """ + opts, args = self.parse_options(parameter_s, 'l:g:', mode='string') + if "l" in opts: # Last n lines + n = int(opts['l']) + hist = self.shell.history_manager.get_tail(n) + elif "g" in opts: # Search + p = "*"+opts['g']+"*" + hist = list(self.shell.history_manager.search(p)) + for l in reversed(hist): + if "rerun" not in l[2]: + hist = [l] # The last match which isn't a %rerun + break + else: + hist = [] # No matches except %rerun + elif args: # Specify history ranges + hist = self.shell.history_manager.get_range_by_str(args) + else: # Last line + hist = self.shell.history_manager.get_tail(1) + hist = [x[2] for x in hist] + if not hist: + print("No lines in history match specification") + return + histlines = "\n".join(hist) + print("=== Executing: ===") + print(histlines) + print("=== Output: ===") + self.shell.run_cell("\n".join(hist), store_history=False) diff --git a/IPython/core/magics/logging.py b/IPython/core/magics/logging.py new file mode 100644 index 00000000000..23b55677433 --- /dev/null +++ b/IPython/core/magics/logging.py @@ -0,0 +1,169 @@ +"""Implementation of magic functions for IPython's own logging. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import os +import sys + +# Our own packages +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.utils.warn import warn + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class LoggingMagics(Magics): + """Magics related to all logging machinery.""" + + @line_magic + def logstart(self, parameter_s=''): + """Start logging anywhere in a session. + + %logstart [-o|-r|-t] [log_name [log_mode]] + + If no name is given, it defaults to a file named 'ipython_log.py' in your + current directory, in 'rotate' mode (see below). + + '%logstart name' saves to file 'name' in 'backup' mode. It saves your + history up to that point and then continues logging. + + %logstart takes a second optional parameter: logging mode. This can be one + of (note that the modes are given unquoted):\\ + append: well, that says it.\\ + backup: rename (if exists) to name~ and start name.\\ + global: single logfile in your home dir, appended to.\\ + over : overwrite existing log.\\ + rotate: create rotating logs name.1~, name.2~, etc. + + Options: + + -o: log also IPython's output. In this mode, all commands which + generate an Out[NN] prompt are recorded to the logfile, right after + their corresponding input line. The output lines are always + prepended with a '#[Out]# ' marker, so that the log remains valid + Python code. + + Since this marker is always the same, filtering only the output from + a log is very easy, using for example a simple awk call:: + + awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py + + -r: log 'raw' input. Normally, IPython's logs contain the processed + input, so that user lines are logged in their final form, converted + into valid Python. For example, %Exit is logged as + _ip.magic("Exit"). If the -r flag is given, all input is logged + exactly as typed, with no transformations applied. + + -t: put timestamps before each input line logged (these are put in + comments).""" + + opts,par = self.parse_options(parameter_s,'ort') + log_output = 'o' in opts + log_raw_input = 'r' in opts + timestamp = 't' in opts + + logger = self.shell.logger + + # if no args are given, the defaults set in the logger constructor by + # ipython remain valid + if par: + try: + logfname,logmode = par.split() + except: + logfname = par + logmode = 'backup' + else: + logfname = logger.logfname + logmode = logger.logmode + # put logfname into rc struct as if it had been called on the command + # line, so it ends up saved in the log header Save it in case we need + # to restore it... + old_logfile = self.shell.logfile + if logfname: + logfname = os.path.expanduser(logfname) + self.shell.logfile = logfname + + loghead = '# IPython log file\n\n' + try: + logger.logstart(logfname, loghead, logmode, log_output, timestamp, + log_raw_input) + except: + self.shell.logfile = old_logfile + warn("Couldn't start log: %s" % sys.exc_info()[1]) + else: + # log input history up to this point, optionally interleaving + # output if requested + + if timestamp: + # disable timestamping for the previous history, since we've + # lost those already (no time machine here). + logger.timestamp = False + + if log_raw_input: + input_hist = self.shell.history_manager.input_hist_raw + else: + input_hist = self.shell.history_manager.input_hist_parsed + + if log_output: + log_write = logger.log_write + output_hist = self.shell.history_manager.output_hist + for n in range(1,len(input_hist)-1): + log_write(input_hist[n].rstrip() + '\n') + if n in output_hist: + log_write(repr(output_hist[n]),'output') + else: + logger.log_write('\n'.join(input_hist[1:])) + logger.log_write('\n') + if timestamp: + # re-enable timestamping + logger.timestamp = True + + print ('Activating auto-logging. ' + 'Current session state plus future input saved.') + logger.logstate() + + @line_magic + def logstop(self, parameter_s=''): + """Fully stop logging and close log file. + + In order to start logging again, a new %logstart call needs to be made, + possibly (though not necessarily) with a new filename, mode and other + options.""" + self.logger.logstop() + + @line_magic + def logoff(self, parameter_s=''): + """Temporarily stop logging. + + You must have previously started logging.""" + self.shell.logger.switch_log(0) + + @line_magic + def logon(self, parameter_s=''): + """Restart logging. + + This function is for restarting logging which you've temporarily + stopped with %logoff. For starting logging for the first time, you + must use the %logstart function, which allows you to specify an + optional log filename.""" + + self.shell.logger.switch_log(1) + + @line_magic + def logstate(self, parameter_s=''): + """Print the status of the logging system.""" + + self.shell.logger.logstate() diff --git a/IPython/core/magics/namespace.py b/IPython/core/magics/namespace.py new file mode 100644 index 00000000000..b9fa9b1345a --- /dev/null +++ b/IPython/core/magics/namespace.py @@ -0,0 +1,700 @@ +"""Implementation of namespace-related magic functions. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import gc +import re +import sys + +# Our own packages +from IPython.core import page +from IPython.core.error import StdinNotImplementedError +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.testing.skipdoctest import skip_doctest +from IPython.utils.encoding import DEFAULT_ENCODING +from IPython.utils.path import get_py_filename + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class NamespaceMagics(Magics): + """Magics to manage various aspects of the user's namespace. + + These include listing variables, introspecting into them, etc. + """ + + @line_magic + def pinfo(self, parameter_s='', namespaces=None): + """Provide detailed information about an object. + + '%pinfo object' is just a synonym for object? or ?object.""" + + #print 'pinfo par: <%s>' % parameter_s # dbg + # detail_level: 0 -> obj? , 1 -> obj?? + detail_level = 0 + # We need to detect if we got called as 'pinfo pinfo foo', which can + # happen if the user types 'pinfo foo?' at the cmd line. + pinfo,qmark1,oname,qmark2 = \ + re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups() + if pinfo or qmark1 or qmark2: + detail_level = 1 + if "*" in oname: + self.psearch(oname) + else: + self.shell._inspect('pinfo', oname, detail_level=detail_level, + namespaces=namespaces) + + @line_magic + def pinfo2(self, parameter_s='', namespaces=None): + """Provide extra detailed information about an object. + + '%pinfo2 object' is just a synonym for object?? or ??object.""" + self.shell._inspect('pinfo', parameter_s, detail_level=1, + namespaces=namespaces) + + @skip_doctest + @line_magic + def pdef(self, parameter_s='', namespaces=None): + """Print the definition header for any callable object. + + If the object is a class, print the constructor information. + + Examples + -------- + :: + + In [3]: %pdef urllib.urlopen + urllib.urlopen(url, data=None, proxies=None) + """ + self._inspect('pdef',parameter_s, namespaces) + + @line_magic + def 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) + + @line_magic + def psource(self, parameter_s='', namespaces=None): + """Print (or run through pager) the source code for an object.""" + self._inspect('psource',parameter_s, namespaces) + + @line_magic + def 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.page(self.shell.inspector.format(open(filename).read())) + + @line_magic + def psearch(self, parameter_s=''): + """Search for object in namespaces by wildcard. + + %psearch [options] PATTERN [OBJECT TYPE] + + Note: ? can be used as a synonym for %psearch, at the beginning or at + the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the + rest of the command line must be unchanged (options come first), so + for example the following forms are equivalent + + %psearch -i a* function + -i a* function? + ?-i a* function + + Arguments: + + PATTERN + + where PATTERN is a string containing * as a wildcard similar to its + use in a shell. The pattern is matched in all namespaces on the + search path. By default objects starting with a single _ are not + matched, many IPython generated objects have a single + underscore. The default is case insensitive matching. Matching is + also done on the attributes of objects and not only on the objects + in a module. + + [OBJECT TYPE] + + Is the name of a python type from the types module. The name is + given in lowercase without the ending type, ex. StringType is + written string. By adding a type here only objects matching the + given type are matched. Using all here makes the pattern match all + types (this is the default). + + Options: + + -a: makes the pattern match even objects whose names start with a + single underscore. These names are normally omitted from the + search. + + -i/-c: make the pattern case insensitive/sensitive. If neither of + these options are given, the default is read from your configuration + file, with the option ``InteractiveShell.wildcards_case_sensitive``. + If this option is not specified in your configuration file, IPython's + internal default is to do a case sensitive search. + + -e/-s NAMESPACE: exclude/search a given namespace. The pattern you + specify can be searched in any of the following namespaces: + 'builtin', 'user', 'user_global','internal', 'alias', where + 'builtin' and 'user' are the search defaults. Note that you should + not use quotes when specifying namespaces. + + 'Builtin' contains the python module builtin, 'user' contains all + user data, 'alias' only contain the shell aliases and no python + objects, 'internal' contains objects used by IPython. The + 'user_global' namespace is only used by embedded IPython instances, + and it contains module-level globals. You can add namespaces to the + search with -s or exclude them with -e (these options can be given + more than once). + + Examples + -------- + :: + + %psearch a* -> objects beginning with an a + %psearch -e builtin a* -> objects NOT in the builtin space starting in a + %psearch a* function -> all functions beginning with an a + %psearch re.e* -> objects beginning with an e in module re + %psearch r*.e* -> objects that start with e in modules starting in r + %psearch r*.* string -> all strings in modules beginning with r + + Case sensitive search:: + + %psearch -c a* list all object beginning with lower case a + + Show objects beginning with a single _:: + + %psearch -a _* list objects beginning with a single underscore + """ + try: + parameter_s.encode('ascii') + except UnicodeEncodeError: + print 'Python identifiers can only contain ascii characters.' + return + + # default namespaces to be searched + def_search = ['user_local', 'user_global', 'builtin'] + + # Process options/args + opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True) + opt = opts.get + shell = self.shell + psearch = shell.inspector.psearch + + # select case options + if opts.has_key('i'): + ignore_case = True + elif opts.has_key('c'): + ignore_case = False + else: + ignore_case = not shell.wildcards_case_sensitive + + # Build list of namespaces to search from user options + def_search.extend(opt('s',[])) + ns_exclude = ns_exclude=opt('e',[]) + ns_search = [nm for nm in def_search if nm not in ns_exclude] + + # Call the actual search + try: + psearch(args,shell.ns_table,ns_search, + show_all=opt('a'),ignore_case=ignore_case) + except: + shell.showtraceback() + + @skip_doctest + @line_magic + def who_ls(self, parameter_s=''): + """Return a sorted list of all interactive variables. + + If arguments are given, only variables of types matching these + arguments are returned. + + Examples + -------- + + Define two variables and list them with who_ls:: + + In [1]: alpha = 123 + + In [2]: beta = 'test' + + In [3]: %who_ls + Out[3]: ['alpha', 'beta'] + + In [4]: %who_ls int + Out[4]: ['alpha'] + + In [5]: %who_ls str + Out[5]: ['beta'] + """ + + user_ns = self.shell.user_ns + user_ns_hidden = self.shell.user_ns_hidden + out = [ i for i in user_ns + if not i.startswith('_') \ + and not i in user_ns_hidden ] + + typelist = parameter_s.split() + if typelist: + typeset = set(typelist) + out = [i for i in out if type(user_ns[i]).__name__ in typeset] + + out.sort() + return out + + @skip_doctest + @line_magic + def who(self, parameter_s=''): + """Print all interactive variables, with some minimal formatting. + + If any arguments are given, only variables whose type matches one of + these are printed. For example:: + + %who function str + + will only list functions and strings, excluding all other types of + variables. To find the proper type names, simply use type(var) at a + command line to see how python prints type names. For example: + + :: + + In [1]: type('hello')\\ + Out[1]: + + indicates that the type name for strings is 'str'. + + ``%who`` always excludes executed names loaded through your configuration + file and things which are internal to IPython. + + This is deliberate, as typically you may load many modules and the + purpose of %who is to show you only what you've manually defined. + + Examples + -------- + + Define two variables and list them with who:: + + In [1]: alpha = 123 + + In [2]: beta = 'test' + + In [3]: %who + alpha beta + + In [4]: %who int + alpha + + In [5]: %who str + beta + """ + + varlist = self.who_ls(parameter_s) + if not varlist: + if parameter_s: + print 'No variables match your requested type.' + else: + print 'Interactive namespace is empty.' + return + + # if we have variables, move on... + count = 0 + for i in varlist: + print i+'\t', + count += 1 + if count > 8: + count = 0 + print + print + + @skip_doctest + @line_magic + def whos(self, parameter_s=''): + """Like %who, but gives some extra information about each variable. + + The same type filtering of %who can be applied here. + + For all variables, the type is printed. Additionally it prints: + + - For {},[],(): their length. + + - For numpy arrays, a summary with shape, number of + elements, typecode and size in memory. + + - Everything else: a string representation, snipping their middle if + too long. + + Examples + -------- + + Define two variables and list them with whos:: + + In [1]: alpha = 123 + + In [2]: beta = 'test' + + In [3]: %whos + Variable Type Data/Info + -------------------------------- + alpha int 123 + beta str test + """ + + varnames = self.who_ls(parameter_s) + if not varnames: + if parameter_s: + print 'No variables match your requested type.' + else: + print 'Interactive namespace is empty.' + return + + # if we have variables, move on... + + # for these types, show len() instead of data: + seq_types = ['dict', 'list', 'tuple'] + + # for numpy arrays, display summary info + ndarray_type = None + if 'numpy' in sys.modules: + try: + from numpy import ndarray + except ImportError: + pass + else: + ndarray_type = ndarray.__name__ + + # Find all variable names and types so we can figure out column sizes + def get_vars(i): + return self.shell.user_ns[i] + + # some types are well known and can be shorter + abbrevs = {'IPython.core.macro.Macro' : 'Macro'} + def type_name(v): + tn = type(v).__name__ + return abbrevs.get(tn,tn) + + varlist = map(get_vars,varnames) + + typelist = [] + for vv in varlist: + tt = type_name(vv) + + if tt=='instance': + typelist.append( abbrevs.get(str(vv.__class__), + str(vv.__class__))) + else: + typelist.append(tt) + + # column labels and # of spaces as separator + varlabel = 'Variable' + typelabel = 'Type' + datalabel = 'Data/Info' + colsep = 3 + # variable format strings + vformat = "{0:<{varwidth}}{1:<{typewidth}}" + aformat = "%s: %s elems, type `%s`, %s bytes" + # find the size of the columns to format the output nicely + varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep + typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep + # table header + print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \ + ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1) + # and the table itself + kb = 1024 + Mb = 1048576 # kb**2 + for vname,var,vtype in zip(varnames,varlist,typelist): + print vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), + if vtype in seq_types: + print "n="+str(len(var)) + elif vtype == ndarray_type: + vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1] + if vtype==ndarray_type: + # numpy + vsize = var.size + vbytes = vsize*var.itemsize + vdtype = var.dtype + + if vbytes < 100000: + print aformat % (vshape, vsize, vdtype, vbytes) + else: + print aformat % (vshape, vsize, vdtype, vbytes), + if vbytes < Mb: + print '(%s kb)' % (vbytes/kb,) + else: + print '(%s Mb)' % (vbytes/Mb,) + else: + try: + vstr = str(var) + except UnicodeEncodeError: + vstr = unicode(var).encode(DEFAULT_ENCODING, + 'backslashreplace') + except: + vstr = "" % id(var) + vstr = vstr.replace('\n', '\\n') + if len(vstr) < 50: + print vstr + else: + print vstr[:25] + "<...>" + vstr[-25:] + + @line_magic + def reset(self, parameter_s=''): + """Resets the namespace by removing all names defined by the user, if + called without arguments, or by removing some types of objects, such + as everything currently in IPython's In[] and Out[] containers (see + the parameters for details). + + Parameters + ---------- + -f : force reset without asking for confirmation. + + -s : 'Soft' reset: Only clears your namespace, leaving history intact. + References to objects may be kept. By default (without this option), + we do a 'hard' reset, giving you a new session and removing all + references to objects from the current session. + + in : reset input history + + out : reset output history + + dhist : reset directory history + + array : reset only variables that are NumPy arrays + + See Also + -------- + magic_reset_selective : invoked as ``%reset_selective`` + + Examples + -------- + :: + + In [6]: a = 1 + + In [7]: a + Out[7]: 1 + + In [8]: 'a' in _ip.user_ns + Out[8]: True + + In [9]: %reset -f + + In [1]: 'a' in _ip.user_ns + Out[1]: False + + In [2]: %reset -f in + Flushing input history + + In [3]: %reset -f dhist in + Flushing directory history + Flushing input history + + Notes + ----- + Calling this magic from clients that do not implement standard input, + such as the ipython notebook interface, will reset the namespace + without confirmation. + """ + opts, args = self.parse_options(parameter_s,'sf', mode='list') + if 'f' in opts: + ans = True + else: + try: + ans = self.shell.ask_yes_no( + "Once deleted, variables cannot be recovered. Proceed (y/[n])?", + default='n') + except StdinNotImplementedError: + ans = True + if not ans: + print 'Nothing done.' + return + + if 's' in opts: # Soft reset + user_ns = self.shell.user_ns + for i in self.who_ls(): + del(user_ns[i]) + elif len(args) == 0: # Hard reset + self.shell.reset(new_session = False) + + # reset in/out/dhist/array: previously extensinions/clearcmd.py + ip = self.shell + user_ns = self.shell.user_ns # local lookup, heavily used + + for target in args: + target = target.lower() # make matches case insensitive + if target == 'out': + print "Flushing output cache (%d entries)" % len(user_ns['_oh']) + self.shell.displayhook.flush() + + elif target == 'in': + print "Flushing input history" + pc = self.shell.displayhook.prompt_count + 1 + for n in range(1, pc): + key = '_i'+repr(n) + user_ns.pop(key,None) + user_ns.update(dict(_i=u'',_ii=u'',_iii=u'')) + hm = ip.history_manager + # don't delete these, as %save and %macro depending on the + # length of these lists to be preserved + hm.input_hist_parsed[:] = [''] * pc + hm.input_hist_raw[:] = [''] * pc + # hm has internal machinery for _i,_ii,_iii, clear it out + hm._i = hm._ii = hm._iii = hm._i00 = u'' + + elif target == 'array': + # Support cleaning up numpy arrays + try: + from numpy import ndarray + # This must be done with items and not iteritems because + # we're going to modify the dict in-place. + for x,val in user_ns.items(): + if isinstance(val,ndarray): + del user_ns[x] + except ImportError: + print "reset array only works if Numpy is available." + + elif target == 'dhist': + print "Flushing directory history" + del user_ns['_dh'][:] + + else: + print "Don't know how to reset ", + print target + ", please run `%reset?` for details" + + gc.collect() + + @line_magic + def reset_selective(self, parameter_s=''): + """Resets the namespace by removing names defined by the user. + + Input/Output history are left around in case you need them. + + %reset_selective [-f] regex + + No action is taken if regex is not included + + Options + -f : force reset without asking for confirmation. + + See Also + -------- + magic_reset : invoked as ``%reset`` + + Examples + -------- + + We first fully reset the namespace so your output looks identical to + this example for pedagogical reasons; in practice you do not need a + full reset:: + + In [1]: %reset -f + + Now, with a clean namespace we can make a few variables and use + ``%reset_selective`` to only delete names that match our regexp:: + + In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8 + + In [3]: who_ls + Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c'] + + In [4]: %reset_selective -f b[2-3]m + + In [5]: who_ls + Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c'] + + In [6]: %reset_selective -f d + + In [7]: who_ls + Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c'] + + In [8]: %reset_selective -f c + + In [9]: who_ls + Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m'] + + In [10]: %reset_selective -f b + + In [11]: who_ls + Out[11]: ['a'] + + Notes + ----- + Calling this magic from clients that do not implement standard input, + such as the ipython notebook interface, will reset the namespace + without confirmation. + """ + + opts, regex = self.parse_options(parameter_s,'f') + + if opts.has_key('f'): + ans = True + else: + try: + ans = self.shell.ask_yes_no( + "Once deleted, variables cannot be recovered. Proceed (y/[n])? ", + default='n') + except StdinNotImplementedError: + ans = True + if not ans: + print 'Nothing done.' + return + user_ns = self.shell.user_ns + if not regex: + print 'No regex pattern specified. Nothing done.' + return + else: + try: + m = re.compile(regex) + except TypeError: + raise TypeError('regex must be a string or compiled pattern') + for i in self.who_ls(): + if m.search(i): + del(user_ns[i]) + + @line_magic + def xdel(self, parameter_s=''): + """Delete a variable, trying to clear it from anywhere that + IPython's machinery has references to it. By default, this uses + the identity of the named object in the user namespace to remove + references held under other names. The object is also removed + from the output history. + + Options + -n : Delete the specified name from all namespaces, without + checking their identity. + """ + opts, varname = self.parse_options(parameter_s,'n') + try: + self.shell.del_var(varname, ('n' in opts)) + except (NameError, ValueError) as e: + print type(e).__name__ +": "+ str(e) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py new file mode 100644 index 00000000000..723e12b885b --- /dev/null +++ b/IPython/core/magics/osm.py @@ -0,0 +1,674 @@ +"""Implementation of magic functions for interaction with the OS. + +Note: this module is named 'osm' instead of 'os' to avoid a collision with the +builtin. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import os +import re +import sys +from pprint import pformat + +# Our own packages +from IPython.core import oinspect +from IPython.core import page +from IPython.core.error import UsageError +from IPython.core.magic import (Magics, compress_dhist, magics_class, + line_magic) +from IPython.testing.skipdoctest import skip_doctest +from IPython.utils.io import file_read, nlprint +from IPython.utils.path import get_py_filename, unquote_filename +from IPython.utils.process import abbrev_cwd +from IPython.utils.terminal import set_term_title +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- +@magics_class +class OSMagics(Magics): + """Magics to interact with the underlying OS (shell-type functionality). + """ + + @skip_doctest + @line_magic + def alias(self, parameter_s=''): + """Define an alias for a system command. + + '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd' + + Then, typing 'alias_name params' will execute the system command 'cmd + params' (from your underlying operating system). + + Aliases have lower precedence than magic functions and Python normal + variables, so if 'foo' is both a Python variable and an alias, the + alias can not be executed until 'del foo' removes the Python variable. + + You can use the %l specifier in an alias definition to represent the + whole line when the alias is called. For example:: + + In [2]: alias bracket echo "Input in brackets: <%l>" + In [3]: bracket hello world + Input in brackets: + + You can also define aliases with parameters using %s specifiers (one + per parameter):: + + In [1]: alias parts echo first %s second %s + In [2]: %parts A B + first A second B + In [3]: %parts A + Incorrect number of arguments: 2 expected. + parts is an alias to: 'echo first %s second %s' + + Note that %l and %s are mutually exclusive. You can only use one or + the other in your aliases. + + Aliases expand Python variables just like system calls using ! or !! + do: all expressions prefixed with '$' get expanded. For details of + the semantic rules, see PEP-215: + http://www.python.org/peps/pep-0215.html. This is the library used by + IPython for variable expansion. If you want to access a true shell + variable, an extra $ is necessary to prevent its expansion by + IPython:: + + In [6]: alias show echo + In [7]: PATH='A Python string' + In [8]: show $PATH + A Python string + In [9]: show $$PATH + /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... + + You can use the alias facility to acess all of $PATH. See the %rehash + and %rehashx functions, which automatically create aliases for the + contents of your $PATH. + + If called with no parameters, %alias prints the current alias table.""" + + par = parameter_s.strip() + if not par: + aliases = sorted(self.shell.alias_manager.aliases) + # stored = self.shell.db.get('stored_aliases', {} ) + # for k, v in stored: + # atab.append(k, v[0]) + + print "Total number of aliases:", len(aliases) + sys.stdout.flush() + return aliases + + # Now try to define a new one + try: + alias,cmd = par.split(None, 1) + except: + print oinspect.getdoc(self.alias) + else: + self.shell.alias_manager.soft_define_alias(alias, cmd) + # end magic_alias + + @line_magic + def unalias(self, parameter_s=''): + """Remove an alias""" + + aname = parameter_s.strip() + self.shell.alias_manager.undefine_alias(aname) + stored = self.shell.db.get('stored_aliases', {} ) + if aname in stored: + print "Removing %stored alias",aname + del stored[aname] + self.shell.db['stored_aliases'] = stored + + @line_magic + def rehashx(self, parameter_s=''): + """Update the alias table with all executable files in $PATH. + + This version explicitly checks that every entry in $PATH is a file + with execute access (os.X_OK), so it is much slower than %rehash. + + Under Windows, it checks executability as a match against a + '|'-separated string of extensions, stored in the IPython config + variable win_exec_ext. This defaults to 'exe|com|bat'. + + This function also resets the root module cache of module completer, + used on slow filesystems. + """ + from IPython.core.alias import InvalidAliasError + + # for the benefit of module completer in ipy_completers.py + del self.shell.db['rootmodules'] + + path = [os.path.abspath(os.path.expanduser(p)) for p in + os.environ.get('PATH','').split(os.pathsep)] + path = filter(os.path.isdir,path) + + syscmdlist = [] + # Now define isexec in a cross platform manner. + if os.name == 'posix': + isexec = lambda fname:os.path.isfile(fname) and \ + os.access(fname,os.X_OK) + else: + try: + winext = os.environ['pathext'].replace(';','|').replace('.','') + except KeyError: + winext = 'exe|com|bat|py' + if 'py' not in winext: + winext += '|py' + execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) + isexec = lambda fname:os.path.isfile(fname) and execre.match(fname) + savedir = os.getcwdu() + + # Now walk the paths looking for executables to alias. + try: + # write the whole loop for posix/Windows so we don't have an if in + # the innermost part + if os.name == 'posix': + for pdir in path: + os.chdir(pdir) + for ff in os.listdir(pdir): + if isexec(ff): + try: + # Removes dots from the name since ipython + # will assume names with dots to be python. + self.shell.alias_manager.define_alias( + ff.replace('.',''), ff) + except InvalidAliasError: + pass + else: + syscmdlist.append(ff) + else: + no_alias = self.shell.alias_manager.no_alias + for pdir in path: + os.chdir(pdir) + for ff in os.listdir(pdir): + base, ext = os.path.splitext(ff) + if isexec(ff) and base.lower() not in no_alias: + if ext.lower() == '.exe': + ff = base + try: + # Removes dots from the name since ipython + # will assume names with dots to be python. + self.shell.alias_manager.define_alias( + base.lower().replace('.',''), ff) + except InvalidAliasError: + pass + syscmdlist.append(ff) + self.shell.db['syscmdlist'] = syscmdlist + finally: + os.chdir(savedir) + + @skip_doctest + @line_magic + def pwd(self, parameter_s=''): + """Return the current working directory path. + + Examples + -------- + :: + + In [9]: pwd + Out[9]: '/home/tsuser/sprint/ipython' + """ + return os.getcwdu() + + @skip_doctest + @line_magic + def cd(self, parameter_s=''): + """Change the current working directory. + + This command automatically maintains an internal list of directories + you visit during your IPython session, in the variable _dh. The + command %dhist shows this history nicely formatted. You can also + do 'cd -' to see directory history conveniently. + + Usage: + + cd 'dir': changes to directory 'dir'. + + cd -: changes to the last visited directory. + + cd -: changes to the n-th directory in the directory history. + + cd --foo: change to directory that matches 'foo' in history + + cd -b : jump to a bookmark set by %bookmark + (note: cd is enough if there is no + directory , but a bookmark with the name exists.) + 'cd -b ' allows you to tab-complete bookmark names. + + Options: + + -q: quiet. Do not print the working directory after the cd command is + executed. By default IPython's cd command does print this directory, + since the default prompts do not display path information. + + Note that !cd doesn't work for this purpose because the shell where + !command runs is immediately discarded after executing 'command'. + + Examples + -------- + :: + + In [10]: cd parent/child + /home/tsuser/parent/child + """ + + oldcwd = os.getcwdu() + numcd = re.match(r'(-)(\d+)$',parameter_s) + # jump in directory history by number + if numcd: + nn = int(numcd.group(2)) + try: + ps = self.shell.user_ns['_dh'][nn] + except IndexError: + print 'The requested directory does not exist in history.' + return + else: + opts = {} + elif parameter_s.startswith('--'): + ps = None + fallback = None + pat = parameter_s[2:] + dh = self.shell.user_ns['_dh'] + # first search only by basename (last component) + for ent in reversed(dh): + if pat in os.path.basename(ent) and os.path.isdir(ent): + ps = ent + break + + if fallback is None and pat in ent and os.path.isdir(ent): + fallback = ent + + # if we have no last part match, pick the first full path match + if ps is None: + ps = fallback + + if ps is None: + print "No matching entry in directory history" + return + else: + opts = {} + + + else: + #turn all non-space-escaping backslashes to slashes, + # for c:\windows\directory\names\ + parameter_s = re.sub(r'\\(?! )','/', parameter_s) + opts,ps = self.parse_options(parameter_s,'qb',mode='string') + # jump to previous + if ps == '-': + try: + ps = self.shell.user_ns['_dh'][-2] + except IndexError: + raise UsageError('%cd -: No previous directory to change to.') + # jump to bookmark if needed + else: + if not os.path.isdir(ps) or 'b' in opts: + bkms = self.shell.db.get('bookmarks', {}) + + if ps in bkms: + target = bkms[ps] + print '(bookmark:%s) -> %s' % (ps, target) + ps = target + else: + if 'b' in opts: + raise UsageError("Bookmark '%s' not found. " + "Use '%%bookmark -l' to see your bookmarks." % ps) + + # strip extra quotes on Windows, because os.chdir doesn't like them + ps = unquote_filename(ps) + # at this point ps should point to the target dir + if ps: + try: + os.chdir(os.path.expanduser(ps)) + if hasattr(self.shell, 'term_title') and self.shell.term_title: + set_term_title('IPython: ' + abbrev_cwd()) + except OSError: + print sys.exc_info()[1] + else: + cwd = os.getcwdu() + dhist = self.shell.user_ns['_dh'] + if oldcwd != cwd: + dhist.append(cwd) + self.shell.db['dhist'] = compress_dhist(dhist)[-100:] + + else: + os.chdir(self.shell.home_dir) + if hasattr(self.shell, 'term_title') and self.shell.term_title: + set_term_title('IPython: ' + '~') + cwd = os.getcwdu() + dhist = self.shell.user_ns['_dh'] + + if oldcwd != cwd: + dhist.append(cwd) + self.shell.db['dhist'] = compress_dhist(dhist)[-100:] + if not 'q' in opts and self.shell.user_ns['_dh']: + print self.shell.user_ns['_dh'][-1] + + + @line_magic + def env(self, parameter_s=''): + """List environment variables.""" + + return dict(os.environ) + + @line_magic + def pushd(self, parameter_s=''): + """Place the current dir on stack and change directory. + + Usage:\\ + %pushd ['dirname'] + """ + + dir_s = self.shell.dir_stack + tgt = os.path.expanduser(unquote_filename(parameter_s)) + cwd = os.getcwdu().replace(self.shell.home_dir,'~') + if tgt: + self.cd(parameter_s) + dir_s.insert(0,cwd) + return self.shell.magic('dirs') + + @line_magic + def popd(self, parameter_s=''): + """Change to directory popped off the top of the stack. + """ + if not self.shell.dir_stack: + raise UsageError("%popd on empty stack") + top = self.shell.dir_stack.pop(0) + self.cd(top) + print "popd ->",top + + @line_magic + def dirs(self, parameter_s=''): + """Return the current directory stack.""" + + return self.shell.dir_stack + + @line_magic + def 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 . + + Note that most of time, you should view directory history by entering + cd -. + + """ + + dh = self.shell.user_ns['_dh'] + if parameter_s: + try: + args = map(int,parameter_s.split()) + except: + self.arg_err(self.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(self.dhist) + return + else: + ini,fin = 0,len(dh) + nlprint(dh, + header = 'Directory history (kept in _dh)', + start=ini,stop=fin) + + @skip_doctest + @line_magic + def sc(self, parameter_s=''): + """Shell capture - execute a shell command and capture its output. + + DEPRECATED. Suboptimal, retained for backwards compatibility. + + You should use the form 'var = !command' instead. Example: + + "%sc -l myfiles = ls ~" should now be written as + + "myfiles = !ls ~" + + myfiles.s, myfiles.l and myfiles.n still apply as documented + below. + + -- + %sc [options] varname=command + + IPython will run the given command using commands.getoutput(), and + will then update the user's interactive namespace with a variable + called varname, containing the value of the call. Your command can + contain shell wildcards, pipes, etc. + + The '=' sign in the syntax is mandatory, and the variable name you + supply must follow Python's standard conventions for valid names. + + (A special format without variable name exists for internal use) + + Options: + + -l: list output. Split the output on newlines into a list before + assigning it to the given variable. By default the output is stored + as a single string. + + -v: verbose. Print the contents of the variable. + + In most cases you should not need to split as a list, because the + returned value is a special type of string which can automatically + provide its contents either as a list (split on newlines) or as a + space-separated string. These are convenient, respectively, either + for sequential processing or to be passed to a shell command. + + For example:: + + # Capture into variable a + In [1]: sc a=ls *py + + # a is a string with embedded newlines + In [2]: a + Out[2]: 'setup.py\\nwin32_manual_post_install.py' + + # which can be seen as a list: + In [3]: a.l + Out[3]: ['setup.py', 'win32_manual_post_install.py'] + + # or as a whitespace-separated string: + In [4]: a.s + Out[4]: 'setup.py win32_manual_post_install.py' + + # a.s is useful to pass as a single command line: + In [5]: !wc -l $a.s + 146 setup.py + 130 win32_manual_post_install.py + 276 total + + # while the list form is useful to loop over: + In [6]: for f in a.l: + ...: !wc -l $f + ...: + 146 setup.py + 130 win32_manual_post_install.py + + Similarly, the lists returned by the -l option are also special, in + the sense that you can equally invoke the .s attribute on them to + automatically get a whitespace-separated string from their contents:: + + In [7]: sc -l b=ls *py + + In [8]: b + Out[8]: ['setup.py', 'win32_manual_post_install.py'] + + In [9]: b.s + Out[9]: 'setup.py win32_manual_post_install.py' + + In summary, both the lists and strings used for output capture have + the following special attributes:: + + .l (or .list) : value as list. + .n (or .nlstr): value as newline-separated string. + .s (or .spstr): value as space-separated string. + """ + + opts,args = self.parse_options(parameter_s, 'lv') + # Try to get a variable name and command to run + try: + # the variable name must be obtained from the parse_options + # output, which uses shlex.split to strip options out. + var,_ = args.split('=', 1) + var = var.strip() + # But the command has to be extracted from the original input + # parameter_s, not on what parse_options returns, to avoid the + # quote stripping which shlex.split performs on it. + _,cmd = parameter_s.split('=', 1) + except ValueError: + var,cmd = '','' + # If all looks ok, proceed + split = 'l' in opts + out = self.shell.getoutput(cmd, split=split) + if 'v' in opts: + print '%s ==\n%s' % (var, pformat(out)) + if var: + self.shell.user_ns.update({var:out}) + else: + return out + + @line_magic + def sx(self, parameter_s=''): + """Shell execute - run a shell command and capture its output. + + %sx command + + IPython will run the given command using commands.getoutput(), and + return the result formatted as a list (split on '\\n'). Since the + output is _returned_, it will be stored in ipython's regular output + cache Out[N] and in the '_N' automatic variables. + + Notes: + + 1) If an input line begins with '!!', then %sx is automatically + invoked. That is, while:: + + !ls + + causes ipython to simply issue system('ls'), typing:: + + !!ls + + is a shorthand equivalent to:: + + %sx ls + + 2) %sx differs from %sc in that %sx automatically splits into a list, + like '%sc -l'. The reason for this is to make it as easy as possible + to process line-oriented shell output via further python commands. + %sc is meant to provide much finer control, but requires more + typing. + + 3) Just like %sc -l, this is a list with special attributes: + :: + + .l (or .list) : value as list. + .n (or .nlstr): value as newline-separated string. + .s (or .spstr): value as whitespace-separated string. + + This is very useful when trying to use such lists as arguments to + system commands.""" + + if parameter_s: + return self.shell.getoutput(parameter_s) + + + @line_magic + def bookmark(self, parameter_s=''): + """Manage IPython's bookmark system. + + %bookmark - set bookmark to current dir + %bookmark - set bookmark to + %bookmark -l - list all bookmarks + %bookmark -d - remove bookmark + %bookmark -r - remove all bookmarks + + You can later on access a bookmarked folder with:: + + %cd -b + + or simply '%cd ' if there is no directory called AND + there is such a bookmark defined. + + Your bookmarks persist through IPython sessions, but they are + associated with each profile.""" + + opts,args = self.parse_options(parameter_s,'drl',mode='list') + if len(args) > 2: + raise UsageError("%bookmark: too many arguments") + + bkms = self.shell.db.get('bookmarks',{}) + + if 'd' in opts: + try: + todel = args[0] + except IndexError: + raise UsageError( + "%bookmark -d: must provide a bookmark to delete") + else: + try: + del bkms[todel] + except KeyError: + raise UsageError( + "%%bookmark -d: Can't delete bookmark '%s'" % todel) + + elif 'r' in opts: + bkms = {} + elif 'l' in opts: + bks = bkms.keys() + bks.sort() + if bks: + size = max(map(len, bks)) + else: + size = 0 + fmt = '%-'+str(size)+'s -> %s' + print 'Current bookmarks:' + for bk in bks: + print fmt % (bk, bkms[bk]) + else: + if not args: + raise UsageError("%bookmark: You must specify the bookmark name") + elif len(args)==1: + bkms[args[0]] = os.getcwdu() + elif len(args)==2: + bkms[args[0]] = args[1] + self.shell.db['bookmarks'] = bkms + + @line_magic + def pycat(self, parameter_s=''): + """Show a syntax-highlighted file through a pager. + + This magic is similar to the cat utility, but it will assume the file + to be Python source and will show it with syntax highlighting. """ + + try: + filename = get_py_filename(parameter_s) + cont = file_read(filename) + except IOError: + try: + cont = eval(parameter_s, self.shell.user_ns) + except NameError: + cont = None + if cont is None: + print "Error: no such file or variable" + return + + page.page(self.shell.pycolorize(cont)) diff --git a/IPython/core/magics/pylab.py b/IPython/core/magics/pylab.py new file mode 100644 index 00000000000..f07b717e712 --- /dev/null +++ b/IPython/core/magics/pylab.py @@ -0,0 +1,88 @@ +"""Implementation of magic functions for matplotlib/pylab support. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Our own packages +from IPython.config.application import Application +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.testing.skipdoctest import skip_doctest + +#----------------------------------------------------------------------------- +# Magic implementation classes +#----------------------------------------------------------------------------- + +@magics_class +class PylabMagics(Magics): + """Magics related to matplotlib's pylab support""" + + @skip_doctest + @line_magic + def pylab(self, parameter_s=''): + """Load numpy and matplotlib to work interactively. + + %pylab [GUINAME] + + This function lets you activate pylab (matplotlib, numpy and + interactive support) at any point during an IPython session. + + It will import at the top level numpy as np, pyplot as plt, matplotlib, + pylab and mlab, as well as all names from numpy and pylab. + + If you are using the inline matplotlib backend for embedded figures, + you can adjust its behavior via the %config magic:: + + # enable SVG figures, necessary for SVG+XHTML export in the qtconsole + In [1]: %config InlineBackend.figure_format = 'svg' + + # change the behavior of closing all figures at the end of each + # execution (cell), or allowing reuse of active figures across + # cells: + In [2]: %config InlineBackend.close_figures = False + + Parameters + ---------- + guiname : optional + One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk', + 'osx' or 'tk'). If given, the corresponding Matplotlib backend is + used, otherwise matplotlib's default (which you can override in your + matplotlib config file) is used. + + Examples + -------- + In this case, where the MPL default is TkAgg:: + + In [2]: %pylab + + Welcome to pylab, a matplotlib-based Python environment. + Backend in use: TkAgg + For more information, type 'help(pylab)'. + + But you can explicitly request a different backend:: + + In [3]: %pylab qt + + Welcome to pylab, a matplotlib-based Python environment. + Backend in use: Qt4Agg + For more information, type 'help(pylab)'. + """ + + if Application.initialized(): + app = Application.instance() + try: + import_all_status = app.pylab_import_all + except AttributeError: + import_all_status = True + else: + import_all_status = True + + self.shell.enable_pylab(parameter_s, import_all=import_all_status) diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index 7c5c29611f2..22bf1e15ceb 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -612,7 +612,7 @@ def check(self, line_info): check_esc_chars. This just checks for automagic. Also, before triggering the magic handler, make sure that there is nothing in the user namespace which could shadow it.""" - if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun): + if not self.shell.automagic or not self.shell.find_magic(line_info.ifun): return None # We have a likely magic method. Make sure we should actually call it. @@ -807,7 +807,7 @@ def handle(self, line_info): pre = line_info.pre esc = line_info.esc continue_prompt = line_info.continue_prompt - obj = line_info.ofind(self)['obj'] + obj = line_info.ofind(self.shell)['obj'] #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg # This should only be active for single-line input! @@ -891,7 +891,7 @@ def handle(self, line_info): line = line[:-1] if line: #print 'line:<%r>' % line # dbg - self.shell.magic_pinfo(line_info.ifun) + self.shell.magic('pinfo %s' % line_info.ifun) else: self.shell.show_usage() return '' # Empty string is needed here! diff --git a/IPython/core/splitinput.py b/IPython/core/splitinput.py index ab9063b8cd4..7b957726fb1 100644 --- a/IPython/core/splitinput.py +++ b/IPython/core/splitinput.py @@ -44,11 +44,12 @@ line_split = re.compile(""" ^(\s*) # any leading space ([,;/%]|!!?|\?\??)? # escape character or characters - \s*(%?[\w\.\*]*) # function/method, possibly with leading % + \s*(%{0,2}[\w\.\*]*) # function/method, possibly with leading % # to correctly treat things like '?%magic' (.*?$|$) # rest of line """, re.VERBOSE) + def split_user_input(line, pattern=None): """Split user input into initial whitespace, escape character, function part and the rest. @@ -76,6 +77,7 @@ def split_user_input(line, pattern=None): #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg return pre, esc or '', ifun.strip(), the_rest.lstrip() + class LineInfo(object): """A single line of input and associated info. @@ -116,13 +118,11 @@ def __init__(self, line, continue_prompt=False): else: self.pre_whitespace = self.pre - self._oinfo = None - def ofind(self, ip): """Do a full, attribute-walking lookup of the ifun in the various namespaces for the given IPython InteractiveShell instance. - Return a dict with keys: found,obj,ospace,ismagic + Return a dict with keys: {found, obj, ospace, ismagic} Note: can cause state changes because of calling getattr, but should only be run if autocall is on and if the line hasn't matched any @@ -131,10 +131,7 @@ def ofind(self, ip): Does cache the results of the call, so can be called multiple times without worrying about *further* damaging state. """ - if not self._oinfo: - # ip.shell._ofind is actually on the Magic class! - self._oinfo = ip.shell._ofind(self.ifun) - return self._oinfo + return ip._ofind(self.ifun) def __str__(self): return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest) diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 821eedd1f98..c0bddd822d0 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -119,8 +119,8 @@ def setUp(self): self.sp = completer.CompletionSplitter() def test_delim_setting(self): - self.sp.set_delims(' ') - nt.assert_equal(self.sp.get_delims(), ' ') + self.sp.delims = ' ' + nt.assert_equal(self.sp.delims, ' ') nt.assert_equal(self.sp._delim_expr, '[\ ]') def test_spaces(self): @@ -202,13 +202,18 @@ def test_local_file_completions(): def test_greedy_completions(): ip = get_ipython() - ip.Completer.greedy = False - ip.ex('a=range(5)') - _,c = ip.complete('.',line='a[0].') - nt.assert_false('a[0].real' in c, "Shouldn't have completed on a[0]: %s"%c) - ip.Completer.greedy = True - _,c = ip.complete('.',line='a[0].') - nt.assert_true('a[0].real' in c, "Should have completed on a[0]: %s"%c) + greedy_original = ip.Completer.greedy + try: + ip.Completer.greedy = False + ip.ex('a=range(5)') + _,c = ip.complete('.',line='a[0].') + nt.assert_false('a[0].real' in c, + "Shouldn't have completed on a[0]: %s"%c) + ip.Completer.greedy = True + _,c = ip.complete('.',line='a[0].') + nt.assert_true('a[0].real' in c, "Should have completed on a[0]: %s"%c) + finally: + ip.Completer.greedy = greedy_original def test_omit__names(): @@ -280,7 +285,59 @@ def test_func_kw_completions(): ip = get_ipython() c = ip.Completer ip.ex('def myfunc(a=1,b=2): return a+b') - s, matches = c.complete(None,'myfunc(1,b') - nt.assert_true('b=' in matches) - s, matches = c.complete(None,'myfunc(1,b)',10)#cursor is right after b - nt.assert_true('b=' in matches) + s, matches = c.complete(None, 'myfunc(1,b') + nt.assert_in('b=', matches) + # Simulate completing with cursor right after b (pos==10): + s, matches = c.complete(None,'myfunc(1,b)', 10) + nt.assert_in('b=', matches) + + +def test_line_magics(): + ip = get_ipython() + c = ip.Completer + s, matches = c.complete(None, 'lsmag') + nt.assert_in('%lsmagic', matches) + s, matches = c.complete(None, '%lsmag') + nt.assert_in('%lsmagic', matches) + + +def test_cell_magics(): + from IPython.core.magic import register_cell_magic + + @register_cell_magic + def _foo_cellm(line, cell): + pass + + ip = get_ipython() + c = ip.Completer + + s, matches = c.complete(None, '_foo_ce') + nt.assert_in('%%_foo_cellm', matches) + s, matches = c.complete(None, '%%_foo_ce') + nt.assert_in('%%_foo_cellm', matches) + + +def test_line_cell_magics(): + from IPython.core.magic import register_line_cell_magic + + @register_line_cell_magic + def _bar_cellm(line, cell): + pass + + ip = get_ipython() + c = ip.Completer + + # The policy here is trickier, see comments in completion code. The + # returned values depend on whether the user passes %% or not explicitly, + # and this will show a difference if the same name is both a line and cell + # magic. + s, matches = c.complete(None, '_bar_ce') + nt.assert_in('%_bar_cellm', matches) + nt.assert_in('%%_bar_cellm', matches) + s, matches = c.complete(None, '%_bar_ce') + nt.assert_in('%_bar_cellm', matches) + nt.assert_in('%%_bar_cellm', matches) + s, matches = c.complete(None, '%%_bar_ce') + nt.assert_not_in('%_bar_cellm', matches) + nt.assert_in('%%_bar_cellm', matches) + diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index b55a8aab588..9e5e758936f 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -92,7 +92,7 @@ def test_history(): # Cross testing: check that magic %save can get previous session. testfilename = os.path.realpath(os.path.join(tmpdir, "test.py")) - ip.magic_save(testfilename + " ~1/1-3") + ip.magic("save " + testfilename + " ~1/1-3") with py3compat.open(testfilename) as testfile: nt.assert_equal(testfile.read(), u"# coding: utf-8\n" + u"\n".join(hist)) diff --git a/IPython/core/tests/test_inputsplitter.py b/IPython/core/tests/test_inputsplitter.py index 73e4dba3a12..4f8d491e5f2 100644 --- a/IPython/core/tests/test_inputsplitter.py +++ b/IPython/core/tests/test_inputsplitter.py @@ -455,7 +455,8 @@ def transform_checker(tests, func): (u'?x1', "get_ipython().magic({u}'pinfo x1')"), (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"), (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"), - (u'?%hist', "get_ipython().magic({u}'pinfo %hist')"), + (u'?%hist1', "get_ipython().magic({u}'pinfo %hist1')"), + (u'?%%hist2', "get_ipython().magic({u}'pinfo %%hist2')"), (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"), ]], @@ -463,13 +464,20 @@ def transform_checker(tests, func): [(i,py3compat.u_format(o)) for i,o in \ [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"), (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"), - (u'%hist?', "get_ipython().magic({u}'pinfo %hist')"), + (u'%hist1?', "get_ipython().magic({u}'pinfo %hist1')"), + (u'%hist2??', "get_ipython().magic({u}'pinfo2 %hist2')"), + (u'%%hist3?', "get_ipython().magic({u}'pinfo %%hist3')"), + (u'%%hist4??', "get_ipython().magic({u}'pinfo2 %%hist4')"), (u'f*?', "get_ipython().magic({u}'psearch f*')"), (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"), - (u'a = abc?', "get_ipython().magic({u}'pinfo abc', next_input={u}'a = abc')"), - (u'a = abc.qe??', "get_ipython().magic({u}'pinfo2 abc.qe', next_input={u}'a = abc.qe')"), - (u'a = *.items?', "get_ipython().magic({u}'psearch *.items', next_input={u}'a = *.items')"), - (u'plot(a?', "get_ipython().magic({u}'pinfo a', next_input={u}'plot(a')"), + (u'a = abc?', "get_ipython().set_next_input({u}'a = abc');" + "get_ipython().magic({u}'pinfo abc')"), + (u'a = abc.qe??', "get_ipython().set_next_input({u}'a = abc.qe');" + "get_ipython().magic({u}'pinfo2 abc.qe')"), + (u'a = *.items?', "get_ipython().set_next_input({u}'a = *.items');" + "get_ipython().magic({u}'psearch *.items')"), + (u'plot(a?', "get_ipython().set_next_input({u}'plot(a');" + "get_ipython().magic({u}'pinfo a')"), (u'a*2 #comment?', 'a*2 #comment?'), ]], @@ -616,7 +624,7 @@ def test_syntax(self): if raw.startswith(' '): continue - isp.push(raw) + isp.push(raw+'\n') out, out_raw = isp.source_raw_reset() self.assertEqual(out.rstrip(), out_t, tt.pair_fail_msg.format("inputsplitter",raw, out_t, out)) @@ -704,3 +712,87 @@ def test_syntax_multiline(self): print 'Raw source was:\n', raw except EOFError: print 'Bye' + +# Tests for cell magics support + +def test_last_blank(): + nt.assert_false(isp.last_blank('')) + nt.assert_false(isp.last_blank('abc')) + nt.assert_false(isp.last_blank('abc\n')) + nt.assert_false(isp.last_blank('abc\na')) + + nt.assert_true(isp.last_blank('\n')) + nt.assert_true(isp.last_blank('\n ')) + nt.assert_true(isp.last_blank('abc\n ')) + nt.assert_true(isp.last_blank('abc\n\n')) + nt.assert_true(isp.last_blank('abc\nd\n\n')) + nt.assert_true(isp.last_blank('abc\nd\ne\n\n')) + nt.assert_true(isp.last_blank('abc \n \n \n\n')) + + +def test_last_two_blanks(): + nt.assert_false(isp.last_two_blanks('')) + nt.assert_false(isp.last_two_blanks('abc')) + nt.assert_false(isp.last_two_blanks('abc\n')) + nt.assert_false(isp.last_two_blanks('abc\n\na')) + nt.assert_false(isp.last_two_blanks('abc\n \n')) + nt.assert_false(isp.last_two_blanks('abc\n\n')) + + nt.assert_true(isp.last_two_blanks('\n\n')) + nt.assert_true(isp.last_two_blanks('\n\n ')) + nt.assert_true(isp.last_two_blanks('\n \n')) + nt.assert_true(isp.last_two_blanks('abc\n\n ')) + nt.assert_true(isp.last_two_blanks('abc\n\n\n')) + nt.assert_true(isp.last_two_blanks('abc\n\n \n')) + nt.assert_true(isp.last_two_blanks('abc\n\n \n ')) + nt.assert_true(isp.last_two_blanks('abc\n\n \n \n')) + nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n')) + nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n')) + + +class CellMagicsCommon(object): + + def test_whole_cell(self): + src = "%%cellm line\nbody\n" + sp = self.sp + sp.push(src) + nt.assert_equal(sp.cell_magic_parts, ['body\n']) + out = sp.source + ref = u"get_ipython()._run_cached_cell_magic({u}'cellm', {u}'line')\n" + nt.assert_equal(out, py3compat.u_format(ref)) + + def tearDown(self): + self.sp.reset() + + +class CellModeCellMagics(CellMagicsCommon, unittest.TestCase): + sp = isp.IPythonInputSplitter(input_mode='cell') + + def test_incremental(self): + sp = self.sp + src = '%%cellm line2\n' + sp.push(src) + nt.assert_true(sp.push_accepts_more()) #1 + src += '\n' + sp.push(src) + # Note: if we ever change the logic to allow full blank lines (see + # _handle_cell_magic), then the following test should change to true + nt.assert_false(sp.push_accepts_more()) #2 + # By now, even with full blanks allowed, a second blank should signal + # the end. For now this test is only a redundancy safety, but don't + # delete it in case we change our mind and the previous one goes to + # true. + src += '\n' + sp.push(src) + nt.assert_false(sp.push_accepts_more()) #3 + + +class LineModeCellMagics(CellMagicsCommon, unittest.TestCase): + sp = isp.IPythonInputSplitter(input_mode='line') + + def test_incremental(self): + sp = self.sp + sp.push('%%cellm line2\n') + nt.assert_true(sp.push_accepts_more()) #1 + sp.push('\n') + nt.assert_false(sp.push_accepts_more()) #2 diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index 21008e77533..fa5bf1bf931 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -22,15 +22,25 @@ # stdlib import os import shutil +import sys import tempfile import unittest from os.path import join -import sys from StringIO import StringIO +# third-party +import nose.tools as nt + +# Our own from IPython.testing.decorators import skipif from IPython.utils import io +#----------------------------------------------------------------------------- +# Globals +#----------------------------------------------------------------------------- +# This is used by every single test, no point repeating it ad nauseam +ip = get_ipython() + #----------------------------------------------------------------------------- # Tests #----------------------------------------------------------------------------- @@ -38,7 +48,6 @@ class InteractiveShellTestCase(unittest.TestCase): def test_naked_string_cells(self): """Test that cells with only naked strings are fully executed""" - ip = get_ipython() # First, single-line inputs ip.run_cell('"a"\n') self.assertEquals(ip.user_ns['_'], 'a') @@ -49,7 +58,6 @@ def test_naked_string_cells(self): def test_run_empty_cell(self): """Just make sure we don't get a horrible error with a blank cell of input. Yes, I did overlook that.""" - ip = get_ipython() old_xc = ip.execution_count ip.run_cell('') self.assertEquals(ip.execution_count, old_xc) @@ -57,7 +65,6 @@ def test_run_empty_cell(self): def test_run_cell_multiline(self): """Multi-block, multi-line cells must execute correctly. """ - ip = get_ipython() src = '\n'.join(["x=1", "y=2", "if 1:", @@ -69,7 +76,6 @@ def test_run_cell_multiline(self): def test_multiline_string_cells(self): "Code sprinkled with multiline strings should execute (GH-306)" - ip = get_ipython() ip.run_cell('tmp=0') self.assertEquals(ip.user_ns['tmp'], 0) ip.run_cell('tmp=1;"""a\nb"""\n') @@ -77,7 +83,6 @@ def test_multiline_string_cells(self): def test_dont_cache_with_semicolon(self): "Ending a line with semicolon should not cache the returned object (GH-307)" - ip = get_ipython() oldlen = len(ip.user_ns['Out']) a = ip.run_cell('1;', store_history=True) newlen = len(ip.user_ns['Out']) @@ -89,7 +94,6 @@ def test_dont_cache_with_semicolon(self): def test_In_variable(self): "Verify that In variable grows with user input (GH-284)" - ip = get_ipython() oldlen = len(ip.user_ns['In']) ip.run_cell('1;', store_history=True) newlen = len(ip.user_ns['In']) @@ -97,13 +101,11 @@ def test_In_variable(self): self.assertEquals(ip.user_ns['In'][-1],'1;') def test_magic_names_in_string(self): - ip = get_ipython() ip.run_cell('a = """\n%exit\n"""') self.assertEquals(ip.user_ns['a'], '\n%exit\n') def test_alias_crash(self): """Errors in prefilter can't crash IPython""" - ip = get_ipython() ip.run_cell('%alias parts echo first %s second %s') # capture stderr: save_err = io.stderr @@ -115,7 +117,6 @@ def test_alias_crash(self): def test_trailing_newline(self): """test that running !(command) does not raise a SyntaxError""" - ip = get_ipython() ip.run_cell('!(true)\n', False) ip.run_cell('!(true)\n\n\n', False) @@ -132,7 +133,6 @@ def __repr__(self): def test_future_flags(self): """Check that future flags are used for parsing code (gh-777)""" - ip = get_ipython() ip.run_cell('from __future__ import print_function') try: ip.run_cell('prfunc_return_val = print(1,2, sep=" ")') @@ -143,7 +143,6 @@ def test_future_flags(self): def test_future_unicode(self): """Check that unicode_literals is imported from __future__ (gh #786)""" - ip = get_ipython() try: ip.run_cell(u'byte_str = "a"') assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default @@ -187,7 +186,6 @@ def test_global_ns(self): def test_bad_custom_tb(self): """Check that InteractiveShell is protected from bad custom exception handlers""" - ip = get_ipython() from IPython.utils import io save_stderr = io.stderr try: @@ -203,7 +201,6 @@ def test_bad_custom_tb(self): def test_bad_custom_tb_return(self): """Check that InteractiveShell is protected from bad return types in custom exception handlers""" - ip = get_ipython() from IPython.utils import io save_stderr = io.stderr try: @@ -218,7 +215,6 @@ def test_bad_custom_tb_return(self): io.stderr = save_stderr def test_drop_by_id(self): - ip = get_ipython() myvars = {"a":object(), "b":object(), "c": object()} ip.push(myvars, interactive=False) for name in myvars: @@ -233,7 +229,6 @@ def test_drop_by_id(self): ip.reset() def test_var_expand(self): - ip = get_ipython() ip.user_ns['f'] = u'Ca\xf1o' self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o') self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o') @@ -246,8 +241,6 @@ def test_var_expand(self): def test_bad_var_expand(self): """var_expand on invalid formats shouldn't raise""" - ip = get_ipython() - # SyntaxError self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}") # NameError @@ -257,8 +250,6 @@ def test_bad_var_expand(self): def test_silent_nopostexec(self): """run_cell(silent=True) doesn't invoke post-exec funcs""" - ip = get_ipython() - d = dict(called=False) def set_called(): d['called'] = True @@ -275,8 +266,6 @@ def set_called(): def test_silent_noadvance(self): """run_cell(silent=True) doesn't advance execution_count""" - ip = get_ipython() - ec = ip.execution_count # silent should force store_history=False ip.run_cell("1", store_history=True, silent=True) @@ -289,8 +278,6 @@ def test_silent_noadvance(self): def test_silent_nodisplayhook(self): """run_cell(silent=True) doesn't trigger displayhook""" - ip = get_ipython() - d = dict(called=False) trap = ip.display_trap @@ -322,6 +309,35 @@ def test_print_softspace(self): In [2]: print 1,; print 2 1 2 """ + + def test_ofind_line_magic(self): + from IPython.core.magic import register_line_magic + + @register_line_magic + def lmagic(line): + "A line magic" + + # Get info on line magic + lfind = ip._ofind('lmagic') + info = dict(found=True, isalias=False, ismagic=True, + namespace = 'IPython internal', obj= lmagic.__wrapped__, + parent = None) + nt.assert_equal(lfind, info) + + def test_ofind_cell_magic(self): + from IPython.core.magic import register_cell_magic + + @register_cell_magic + def cmagic(line, cell): + "A cell magic" + + # Get info on cell magic + find = ip._ofind('cmagic') + info = dict(found=True, isalias=False, ismagic=True, + namespace = 'IPython internal', obj= cmagic.__wrapped__, + parent = None) + nt.assert_equal(find, info) + class TestSafeExecfileNonAsciiPath(unittest.TestCase): @@ -335,7 +351,6 @@ def setUp(self): os.chdir(self.TESTDIR) self.fname = u"åäötestscript.py" - def tearDown(self): os.chdir(self.oldpath) shutil.rmtree(self.BASETESTDIR) @@ -343,7 +358,7 @@ def tearDown(self): def test_1(self): """Test safe_execfile with non-ascii path """ - _ip.shell.safe_execfile(self.fname, {}, raise_exceptions=True) + ip.safe_execfile(self.fname, {}, raise_exceptions=True) class TestSystemRaw(unittest.TestCase): @@ -351,7 +366,7 @@ def test_1(self): """Test system_raw with non-ascii cmd """ cmd = ur'''python -c "'åäö'" ''' - _ip.shell.system_raw(cmd) + ip.system_raw(cmd) def test__IPYTHON__(): diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 530085a70ff..296d8953469 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -13,9 +13,16 @@ import os import sys from StringIO import StringIO +from unittest import TestCase import nose.tools as nt +from IPython.core import magic +from IPython.core.magic import (Magics, magics_class, line_magic, + cell_magic, line_cell_magic, + register_line_magic, register_cell_magic, + register_line_cell_magic) +from IPython.core.magics import execution from IPython.nbformat.v3.tests.nbexamples import nb0 from IPython.nbformat import current from IPython.testing import decorators as dec @@ -27,6 +34,8 @@ # Test functions begin #----------------------------------------------------------------------------- +@magic.magics_class +class DummyMagics(magic.Magics): pass def test_rehashx(): # clear up everything @@ -51,7 +60,8 @@ def test_magic_parse_options(): """Test that we don't mangle paths when parsing magic options.""" ip = get_ipython() path = 'c:\\x' - opts = ip.parse_options('-f %s' % path,'f:')[0] + m = DummyMagics(ip) + opts = m.parse_options('-f %s' % path,'f:')[0] # argv splitting is os-dependent if os.name == 'posix': expected = 'c:x' @@ -284,8 +294,9 @@ def test_parse_options(): """Tests for basic options parsing in magics.""" # These are only the most minimal of tests, more should be added later. At # the very least we check that basic text/unicode calls work OK. - nt.assert_equal(_ip.parse_options('foo', '')[1], 'foo') - nt.assert_equal(_ip.parse_options(u'foo', '')[1], u'foo') + m = DummyMagics(_ip) + nt.assert_equal(m.parse_options('foo', '')[1], 'foo') + nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo') def test_dirops(): @@ -326,7 +337,7 @@ def __repr__(self): _ip.run_cell("a") nt.assert_equal(monitor, []) - _ip.magic_reset("-f") + _ip.magic("reset -f") nt.assert_equal(monitor, [1]) class TestXdel(tt.TempFileMixin): @@ -388,7 +399,7 @@ def __repr__(self): def doctest_precision(): """doctest for %precision - In [1]: f = get_ipython().shell.display_formatter.formatters['text/plain'] + In [1]: f = get_ipython().display_formatter.formatters['text/plain'] In [2]: %precision 5 Out[2]: {u}'%.5f' @@ -422,7 +433,8 @@ def test_timeit_arguments(): "Test valid timeit arguments, should not cause SyntaxError (GH #1269)" _ip.magic("timeit ('#')") -@dec.skipif(_ip.magic_prun == _ip.profile_missing_notice) + +@dec.skipif(execution.profile is None) def test_prun_quotes(): "Test that prun does not clobber string escapes (GH #1302)" _ip.magic("prun -q x = '\t'") @@ -478,3 +490,58 @@ def test_notebook_reformat_json(): def test_env(): env = _ip.magic("env") assert isinstance(env, dict), type(env) + + +class CellMagicTestCase(TestCase): + + def check_ident(self, magic): + # Manually called, we get the result + out = _ip.run_cell_magic(magic, 'a', 'b') + nt.assert_equals(out, ('a','b')) + # Via run_cell, it goes into the user's namespace via displayhook + _ip.run_cell('%%' + magic +' c\nd') + nt.assert_equals(_ip.user_ns['_'], ('c','d')) + + def test_cell_magic_func_deco(self): + "Cell magic using simple decorator" + @register_cell_magic + def cellm(line, cell): + return line, cell + + self.check_ident('cellm') + + def test_cell_magic_reg(self): + "Cell magic manually registered" + def cellm(line, cell): + return line, cell + + _ip.register_magic_function(cellm, 'cell', 'cellm2') + self.check_ident('cellm2') + + def test_cell_magic_class(self): + "Cell magics declared via a class" + @magics_class + class MyMagics(Magics): + + @cell_magic + def cellm3(self, line, cell): + return line, cell + + _ip.register_magics(MyMagics) + self.check_ident('cellm3') + + def test_cell_magic_class2(self): + "Cell magics declared via a class, #2" + @magics_class + class MyMagics2(Magics): + + @cell_magic('cellm4') + def cellm33(self, line, cell): + return line, cell + + _ip.register_magics(MyMagics2) + self.check_ident('cellm4') + # Check that nothing is registered as 'cellm33' + c33 = _ip.find_cell_magic('cellm33') + nt.assert_equals(c33, None) + diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index f7fc5ecd94e..bfdfc474591 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -20,6 +20,10 @@ # Our own imports from .. import oinspect +from IPython.core.magic import (Magics, magics_class, line_magic, + cell_magic, line_cell_magic, + register_line_magic, register_cell_magic, + register_line_cell_magic) from IPython.utils import py3compat #----------------------------------------------------------------------------- @@ -27,6 +31,7 @@ #----------------------------------------------------------------------------- inspector = oinspect.Inspector() +ip = get_ipython() #----------------------------------------------------------------------------- # Local utilities @@ -46,17 +51,50 @@ def __call__(self, *a, **kw): def method(self, x, z=2): """Some method's docstring""" + class OldStyle: """An old-style class for testing.""" pass + def f(x, y=2, *a, **kw): """A simple function.""" + def g(y, z=3, *a, **kw): pass # no docstring +@register_line_magic +def lmagic(line): + "A line magic" + + +@register_cell_magic +def cmagic(line, cell): + "A cell magic" + + +@register_line_cell_magic +def lcmagic(line, cell=None): + "A line/cell magic" + + +@magics_class +class SimpleMagics(Magics): + @line_magic + def Clmagic(self, cline): + "A class-based line magic" + + @cell_magic + def Ccmagic(self, cline, ccell): + "A class-based cell magic" + + @line_cell_magic + def Clcmagic(self, cline, ccell=None): + "A class-based line/cell magic" + + def check_calltip(obj, name, call, docstring): """Generic check pattern all calltip tests will use""" info = inspector.info(obj, name) @@ -93,6 +131,31 @@ def test_calltip_function2(): def test_calltip_builtin(): check_calltip(sum, 'sum', None, sum.__doc__) + +def test_calltip_line_magic(): + check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic") + + +def test_calltip_cell_magic(): + check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic") + + +def test_calltip_line_magic(): + check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)', + "A line/cell magic") + + +def test_class_magics(): + cm = SimpleMagics(ip) + ip.register_magics(cm) + check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)', + "A class-based line magic") + check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)', + "A class-based cell magic") + check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)', + "A class-based line/cell magic") + + def test_info(): "Check that Inspector.info fills out various fields as expected." i = inspector.info(Call, oname='Call') diff --git a/IPython/core/tests/test_prefilter.py b/IPython/core/tests/test_prefilter.py index 4da06b89840..8b262311cc2 100644 --- a/IPython/core/tests/test_prefilter.py +++ b/IPython/core/tests/test_prefilter.py @@ -79,7 +79,7 @@ def test_issue_114(): msp = ip.prefilter_manager.multi_line_specials ip.prefilter_manager.multi_line_specials = False try: - for mgk in ip.lsmagic(): + for mgk in ip.magics_manager.lsmagic()['line']: raw = template % mgk yield nt.assert_equals(ip.prefilter(raw), raw) finally: diff --git a/IPython/core/tests/test_splitinput.py b/IPython/core/tests/test_splitinput.py index cfc720985f3..4c31b0e3f36 100644 --- a/IPython/core/tests/test_splitinput.py +++ b/IPython/core/tests/test_splitinput.py @@ -20,7 +20,10 @@ (' ;ls', (' ', ';', 'ls', '')), ('f.g(x)', ('', '', 'f.g', '(x)')), ('f.g (x)', ('', '', 'f.g', '(x)')), - ('?%hist', ('', '?', '%hist', '')), + ('?%hist1', ('', '?', '%hist1', '')), + ('?%%hist2', ('', '?', '%%hist2', '')), + ('??%hist3', ('', '??', '%hist3', '')), + ('??%%hist4', ('', '??', '%%hist4', '')), ('?x*', ('', '?', 'x*', '')), ] if py3compat.PY3: diff --git a/IPython/core/usage.py b/IPython/core/usage.py index 90506b31672..309d1e21324 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -258,8 +258,9 @@ ?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. +Magic functions are prefixed by % or %%, and typically take their arguments +without parentheses, quotes or even commas for convenience. Line magics take a +single % and cell magics are prefixed with two %%. Example magic function calls: @@ -268,6 +269,10 @@ alist = %alias : Get list of aliases to 'alist' cd /usr/share : Obvious. cd - to choose from visited dirs. %cd?? : See help AND source for magic %cd +%timeit x=10 : time the 'x=10' statement with high precision. +%%timeit x=2**100 +x**100 : time 'x*100' with a setup of 'x=2**100'; setup code is not + counted. This is an example of a cell magic. System commands: diff --git a/IPython/extensions/autoreload.py b/IPython/extensions/autoreload.py index f3ffd1e16d9..6ca46356db6 100644 --- a/IPython/extensions/autoreload.py +++ b/IPython/extensions/autoreload.py @@ -1,6 +1,7 @@ -""" -``autoreload`` is an IPython extension that reloads modules -automatically before executing the line of code typed. +"""IPython extension to reload modules before executing user code. + +``autoreload`` reloads modules automatically before entering the execution of +code typed at the IPython prompt. This makes for example the following workflow possible: @@ -20,8 +21,8 @@ In [6]: some_function() Out[6]: 43 -The module was reloaded without reloading it explicitly, and the -object imported with ``from foo import ...`` was also updated. +The module was reloaded without reloading it explicitly, and the object +imported with ``from foo import ...`` was also updated. Usage ===== @@ -84,26 +85,39 @@ - Functions that are removed (eg. via monkey-patching) from a module before it is reloaded are not upgraded. -- C extension modules cannot be reloaded, and so cannot be - autoreloaded. - +- C extension modules cannot be reloaded, and so cannot be autoreloaded. """ skip_doctest = True -# Pauli Virtanen , 2008. -# Thomas Heller, 2000. +#----------------------------------------------------------------------------- +# Copyright (C) 2000 Thomas Heller +# Copyright (C) 2008 Pauli Virtanen +# Copyright (C) 2012 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#----------------------------------------------------------------------------- # # This IPython module is written by Pauli Virtanen, based on the autoreload # code by Thomas Heller. -#------------------------------------------------------------------------------ -# Autoreload functionality -#------------------------------------------------------------------------------ - -import time, os, threading, sys, types, imp, inspect, traceback, atexit +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +import atexit +import imp +import inspect +import os +import sys +import threading +import time +import traceback +import types import weakref + try: + # Reload is not defined by default in Python3. reload except NameError: from imp import reload @@ -111,14 +125,20 @@ from IPython.utils import pyfile from IPython.utils.py3compat import PY3 +#------------------------------------------------------------------------------ +# Autoreload functionality +#------------------------------------------------------------------------------ + def _get_compiled_ext(): """Official way to get the extension of compiled files (.pyc or .pyo)""" for ext, mode, typ in imp.get_suffixes(): if typ == imp.PY_COMPILED: return ext + PY_COMPILED_EXT = _get_compiled_ext() + class ModuleReloader(object): enabled = False """Whether this reloader is enabled""" @@ -239,6 +259,7 @@ def check(self, check_all=False): func_attrs = ['func_code', 'func_defaults', 'func_doc', 'func_closure', 'func_globals', 'func_dict'] + def update_function(old, new): """Upgrade the code object of a function""" for name in func_attrs: @@ -247,6 +268,7 @@ def update_function(old, new): except (AttributeError, TypeError): pass + def update_class(old, new): """Replace stuff in the __dict__ of a class, and upgrade method code objects""" @@ -270,15 +292,18 @@ def update_class(old, new): except (AttributeError, TypeError): pass # skip non-writable attributes + def update_property(old, new): """Replace get/set/del functions of a property""" update_generic(old.fdel, new.fdel) update_generic(old.fget, new.fget) update_generic(old.fset, new.fset) + def isinstance2(a, b, typ): return isinstance(a, typ) and isinstance(b, typ) + UPDATE_RULES = [ (lambda a, b: isinstance2(a, b, type), update_class), @@ -288,6 +313,7 @@ def isinstance2(a, b, typ): update_property), ] + if PY3: UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType), lambda a, b: update_function(a.__func__, b.__func__)), @@ -307,12 +333,14 @@ def update_generic(a, b): return True return False + class StrongRef(object): def __init__(self, obj): self.obj = obj def __call__(self): return self.obj + def superreload(module, reload=reload, old_objects={}): """Enhanced version of the builtin reload function. @@ -377,16 +405,19 @@ def superreload(module, reload=reload, old_objects={}): # IPython connectivity #------------------------------------------------------------------------------ -from IPython.core.plugin import Plugin from IPython.core.hooks import TryNext +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.core.plugin import Plugin -class AutoreloadInterface(object): +@magics_class +class AutoreloadMagics(Magics): def __init__(self, *a, **kw): - super(AutoreloadInterface, self).__init__(*a, **kw) + super(AutoreloadMagics, self).__init__(*a, **kw) self._reloader = ModuleReloader() self._reloader.check_all = False - def magic_autoreload(self, ipself, parameter_s=''): + @line_magic + def autoreload(self, parameter_s=''): r"""%autoreload => Reload modules automatically %autoreload @@ -441,7 +472,8 @@ def magic_autoreload(self, ipself, parameter_s=''): self._reloader.check_all = True self._reloader.enabled = True - def magic_aimport(self, ipself, parameter_s='', stream=None): + @line_magic + def aimport(self, parameter_s='', stream=None): """%aimport => Import modules for automatic reloading. %aimport @@ -452,9 +484,7 @@ def magic_aimport(self, ipself, parameter_s='', stream=None): %aimport -foo Mark module 'foo' to not be autoreloaded for %autoreload 1 - """ - modname = parameter_s if not modname: to_reload = self._reloader.modules.keys() @@ -475,9 +505,9 @@ def magic_aimport(self, ipself, parameter_s='', stream=None): top_module, top_name = self._reloader.aimport_module(modname) # Inject module to user namespace - ipself.push({top_name: top_module}) + self.shell.push({top_name: top_module}) - def pre_run_code_hook(self, ipself): + def pre_run_code_hook(self, ip): if not self._reloader.enabled: raise TryNext try: @@ -485,16 +515,18 @@ def pre_run_code_hook(self, ipself): except: pass -class AutoreloadPlugin(AutoreloadInterface, Plugin): + +class AutoreloadPlugin(Plugin): def __init__(self, shell=None, config=None): super(AutoreloadPlugin, self).__init__(shell=shell, config=config) + self.auto_magics = AutoreloadMagics(shell) + shell.register_magics(self.auto_magics) + shell.set_hook('pre_run_code_hook', self.auto_magics.pre_run_code_hook) - self.shell.define_magic('autoreload', self.magic_autoreload) - self.shell.define_magic('aimport', self.magic_aimport) - self.shell.set_hook('pre_run_code_hook', self.pre_run_code_hook) _loaded = False + def load_ipython_extension(ip): """Load the extension in IPython.""" global _loaded diff --git a/IPython/extensions/parallelmagic.py b/IPython/extensions/parallelmagic.py index 2677d27a020..abb49fb7c96 100644 --- a/IPython/extensions/parallelmagic.py +++ b/IPython/extensions/parallelmagic.py @@ -24,7 +24,7 @@ """ #----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team +# Copyright (C) 2008 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. @@ -37,41 +37,31 @@ import ast import re -from IPython.core.plugin import Plugin -from IPython.utils.traitlets import Bool, Any, Instance +from IPython.core.magic import Magics, magics_class, line_magic from IPython.testing.skipdoctest import skip_doctest #----------------------------------------------------------------------------- # Definitions of magic functions for use with IPython #----------------------------------------------------------------------------- - NO_ACTIVE_VIEW = """ Use activate() on a DirectView object to activate it for magics. """ -class ParalleMagic(Plugin): - """A component to manage the %result, %px and %autopx magics.""" - - active_view = Instance('IPython.parallel.client.view.DirectView') - verbose = Bool(False, config=True) - shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') +@magics_class +class ParallelMagics(Magics): + """A set of magics useful when controlling a parallel IPython cluster. + """ - def __init__(self, shell=None, config=None): - super(ParalleMagic, self).__init__(shell=shell, config=config) - self._define_magics() + def __init__(self, shell): + super(ParallelMagics, self).__init__(shell) # A flag showing if autopx is activated or not self.autopx = False - def _define_magics(self): - """Define the magic functions.""" - self.shell.define_magic('result', self.magic_result) - self.shell.define_magic('px', self.magic_px) - self.shell.define_magic('autopx', self.magic_autopx) - @skip_doctest - def magic_result(self, ipself, parameter_s=''): + @line_magic + def result(self, parameter_s=''): """Print the result of command i on all engines.. To use this a :class:`DirectView` instance must be created @@ -103,7 +93,8 @@ def magic_result(self, ipself, parameter_s=''): return result @skip_doctest - def magic_px(self, ipself, parameter_s=''): + @line_magic + def px(self, parameter_s=''): """Executes the given python command in parallel. To use this a :class:`DirectView` instance must be created @@ -129,7 +120,8 @@ def magic_px(self, ipself, parameter_s=''): self._maybe_display_output(result) @skip_doctest - def magic_autopx(self, ipself, parameter_s=''): + @line_magic + def autopx(self, parameter_s=''): """Toggles auto parallel mode. To use this a :class:`DirectView` instance must be created @@ -237,8 +229,9 @@ def pxrun_cell(self, raw_cell, store_history=False, silent=False): cell_name = ipself.compile.cache(cell, ipself.execution_count) try: - code_ast = ast.parse(cell, filename=cell_name) - except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError): + ast.parse(cell, filename=cell_name) + except (OverflowError, SyntaxError, ValueError, TypeError, + MemoryError): # Case 1 ipself.showsyntaxerror() ipself.execution_count += 1 @@ -282,8 +275,9 @@ def pxrun_code(self, code_obj): """ ipself = self.shell # check code object for the autopx magic - if 'get_ipython' in code_obj.co_names and 'magic' in code_obj.co_names and \ - any( [ isinstance(c, basestring) and 'autopx' in c for c in code_obj.co_consts ]): + if 'get_ipython' in code_obj.co_names and 'magic' in code_obj.co_names \ + and any( [ isinstance(c, basestring) and 'autopx' in c + for c in code_obj.co_consts ]): self._disable_autopx() return False else: @@ -305,12 +299,11 @@ def pxrun_code(self, code_obj): __doc__ = __doc__.replace('@AUTOPX_DOC@', - " " + ParalleMagic.magic_autopx.__doc__) + " " + ParallelMagics.autopx.__doc__) __doc__ = __doc__.replace('@PX_DOC@', - " " + ParalleMagic.magic_px.__doc__) + " " + ParallelMagics.px.__doc__) __doc__ = __doc__.replace('@RESULT_DOC@', - " " + ParalleMagic.magic_result.__doc__) - + " " + ParallelMagics.result.__doc__) _loaded = False @@ -319,7 +312,5 @@ def load_ipython_extension(ip): """Load the extension in IPython.""" global _loaded if not _loaded: - plugin = ParalleMagic(shell=ip, config=ip.config) - ip.plugin_manager.register_plugin('parallelmagic', plugin) + ip.register_magics(ParallelMagics) _loaded = True - diff --git a/IPython/extensions/storemagic.py b/IPython/extensions/storemagic.py index 09e63fc17d0..a30e1e2ea87 100644 --- a/IPython/extensions/storemagic.py +++ b/IPython/extensions/storemagic.py @@ -8,17 +8,33 @@ :file:`ipython_config.py` file:: c.StoreMagic.autorestore = True - """ - -from IPython.core.error import TryNext, UsageError +#----------------------------------------------------------------------------- +# Copyright (c) 2012, The IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import inspect, os, sys, textwrap + +# Our own +from IPython.core.error import UsageError +from IPython.core.fakemodule import FakeModule +from IPython.core.magic import Magics, magics_class, line_magic from IPython.core.plugin import Plugin from IPython.testing.skipdoctest import skip_doctest -from IPython.utils import pickleshare from IPython.utils.traitlets import Bool, Instance -import inspect,pickle,os,sys,textwrap -from IPython.core.fakemodule import FakeModule +#----------------------------------------------------------------------------- +# Functions and classes +#----------------------------------------------------------------------------- def restore_aliases(ip): staliases = ip.db.get('stored_aliases', {}) @@ -37,7 +53,7 @@ def refresh_variables(ip): obj = db[key] except KeyError: print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey - print "The error was:",sys.exc_info()[0] + print "The error was:", sys.exc_info()[0] else: #print "restored",justkey,"=",obj #dbg ip.user_ns[justkey] = obj @@ -46,141 +62,153 @@ def refresh_variables(ip): def restore_dhist(ip): ip.user_ns['_dh'] = ip.db.get('dhist',[]) + def restore_data(ip): refresh_variables(ip) restore_aliases(ip) restore_dhist(ip) -@skip_doctest -def magic_store(self, parameter_s=''): + +@magics_class +class StoreMagics(Magics): """Lightweight persistence for python variables. - Example:: + Provides the %store magic.""" - In [1]: l = ['hello',10,'world'] - In [2]: %store l - In [3]: exit + @skip_doctest + @line_magic + def store(self, parameter_s=''): + """Lightweight persistence for python variables. - (IPython session is closed and started again...) + Example:: - ville@badger:~$ ipython - In [1]: l - Out[1]: ['hello', 10, 'world'] + In [1]: l = ['hello',10,'world'] + In [2]: %store l + In [3]: exit - Usage: + (IPython session is closed and started again...) - * ``%store`` - Show list of all variables and their current values - * ``%store spam`` - Store the *current* value of the variable spam to disk - * ``%store -d spam`` - Remove the variable and its value from storage - * ``%store -z`` - Remove all variables from storage - * ``%store -r`` - Refresh all variables from store (delete current vals) - * ``%store foo >a.txt`` - Store value of foo to new file a.txt - * ``%store foo >>a.txt`` - Append value of foo to file a.txt + ville@badger:~$ ipython + In [1]: l + Out[1]: ['hello', 10, 'world'] - It should be noted that if you change the value of a variable, you - need to %store it again if you want to persist the new value. + Usage: - Note also that the variables will need to be pickleable; most basic - python types can be safely %store'd. + * ``%store`` - Show list of all variables and their current + values + * ``%store spam`` - Store the *current* value of the variable spam + to disk + * ``%store -d spam`` - Remove the variable and its value from storage + * ``%store -z`` - Remove all variables from storage + * ``%store -r`` - Refresh all variables from store (delete + current vals) + * ``%store foo >a.txt`` - Store value of foo to new file a.txt + * ``%store foo >>a.txt`` - Append value of foo to file a.txt - Also aliases can be %store'd across sessions. - """ + It should be noted that if you change the value of a variable, you + need to %store it again if you want to persist the new value. - opts,argsl = self.parse_options(parameter_s,'drz',mode='string') - args = argsl.split(None,1) - ip = self.shell - db = ip.db - # delete - if opts.has_key('d'): - try: - todel = args[0] - except IndexError: - raise UsageError('You must provide the variable to forget') - else: - try: - del db['autorestore/' + todel] - except: - raise UsageError("Can't delete variable '%s'" % todel) - # reset - elif opts.has_key('z'): - for k in db.keys('autorestore/*'): - del db[k] - - elif opts.has_key('r'): - refresh_variables(ip) - - - # run without arguments -> list variables & values - elif not args: - vars = self.db.keys('autorestore/*') - vars.sort() - if vars: - size = max(map(len,vars)) - else: - size = 0 - - print 'Stored variables and their in-db values:' - fmt = '%-'+str(size)+'s -> %s' - get = db.get - for var in vars: - justkey = os.path.basename(var) - # print 30 first characters from every var - print fmt % (justkey,repr(get(var,''))[:50]) - - # default action - store the variable - else: - # %store foo >file.txt or >>file.txt - if len(args) > 1 and args[1].startswith('>'): - fnam = os.path.expanduser(args[1].lstrip('>').lstrip()) - if args[1].startswith('>>'): - fil = open(fnam,'a') - else: - fil = open(fnam,'w') - obj = ip.ev(args[0]) - print "Writing '%s' (%s) to file '%s'." % (args[0], - obj.__class__.__name__, fnam) + Note also that the variables will need to be pickleable; most basic + python types can be safely %store'd. + Also aliases can be %store'd across sessions. + """ - if not isinstance (obj,basestring): - from pprint import pprint - pprint(obj,fil) + opts,argsl = self.parse_options(parameter_s,'drz',mode='string') + args = argsl.split(None,1) + ip = self.shell + db = ip.db + # delete + if opts.has_key('d'): + try: + todel = args[0] + except IndexError: + raise UsageError('You must provide the variable to forget') else: - fil.write(obj) - if not obj.endswith('\n'): - fil.write('\n') - - fil.close() - return - - # %store foo - try: - obj = ip.user_ns[args[0]] - except KeyError: - # it might be an alias - # This needs to be refactored to use the new AliasManager stuff. - if args[0] in self.alias_manager: - name = args[0] - nargs, cmd = self.alias_manager.alias_table[ name ] - staliases = db.get('stored_aliases',{}) - staliases[ name ] = cmd - db['stored_aliases'] = staliases - print "Alias stored: %s (%s)" % (name, cmd) - return + try: + del db['autorestore/' + todel] + except: + raise UsageError("Can't delete variable '%s'" % todel) + # reset + elif opts.has_key('z'): + for k in db.keys('autorestore/*'): + del db[k] + + elif opts.has_key('r'): + refresh_variables(ip) + + + # run without arguments -> list variables & values + elif not args: + vars = self.db.keys('autorestore/*') + vars.sort() + if vars: + size = max(map(len, vars)) else: - raise UsageError("Unknown variable '%s'" % args[0]) + size = 0 + print 'Stored variables and their in-db values:' + fmt = '%-'+str(size)+'s -> %s' + get = db.get + for var in vars: + justkey = os.path.basename(var) + # print 30 first characters from every var + print fmt % (justkey, repr(get(var, ''))[:50]) + + # default action - store the variable else: - if isinstance(inspect.getmodule(obj), FakeModule): - print textwrap.dedent("""\ - Warning:%s is %s - Proper storage of interactively declared classes (or instances - of those classes) is not possible! Only instances - of classes in real modules on file system can be %%store'd. - """ % (args[0], obj) ) + # %store foo >file.txt or >>file.txt + if len(args) > 1 and args[1].startswith('>'): + fnam = os.path.expanduser(args[1].lstrip('>').lstrip()) + if args[1].startswith('>>'): + fil = open(fnam, 'a') + else: + fil = open(fnam, 'w') + obj = ip.ev(args[0]) + print "Writing '%s' (%s) to file '%s'." % (args[0], + obj.__class__.__name__, fnam) + + + if not isinstance (obj, basestring): + from pprint import pprint + pprint(obj, fil) + else: + fil.write(obj) + if not obj.endswith('\n'): + fil.write('\n') + + fil.close() return - #pickled = pickle.dumps(obj) - self.db[ 'autorestore/' + args[0] ] = obj - print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__) + + # %store foo + try: + obj = ip.user_ns[args[0]] + except KeyError: + # it might be an alias + # This needs to be refactored to use the new AliasManager stuff. + if args[0] in self.alias_manager: + name = args[0] + nargs, cmd = self.alias_manager.alias_table[ name ] + staliases = db.get('stored_aliases',{}) + staliases[ name ] = cmd + db['stored_aliases'] = staliases + print "Alias stored: %s (%s)" % (name, cmd) + return + else: + raise UsageError("Unknown variable '%s'" % args[0]) + + else: + if isinstance(inspect.getmodule(obj), FakeModule): + print textwrap.dedent("""\ + Warning:%s is %s + Proper storage of interactively declared classes (or instances + of those classes) is not possible! Only instances + of classes in real modules on file system can be %%store'd. + """ % (args[0], obj) ) + return + #pickled = pickle.dumps(obj) + self.db[ 'autorestore/' + args[0] ] = obj + print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__) class StoreMagic(Plugin): @@ -189,11 +217,12 @@ class StoreMagic(Plugin): def __init__(self, shell, config): super(StoreMagic, self).__init__(shell=shell, config=config) - shell.define_magic('store', magic_store) + shell.register_magics(StoreMagics) if self.autorestore: restore_data(shell) + _loaded = False def load_ipython_extension(ip): diff --git a/IPython/extensions/sympyprinting.py b/IPython/extensions/sympyprinting.py index be0cfb90a41..03ddd0d457a 100644 --- a/IPython/extensions/sympyprinting.py +++ b/IPython/extensions/sympyprinting.py @@ -31,7 +31,7 @@ pass #----------------------------------------------------------------------------- -# Definitions of magic functions for use with IPython +# Definitions of special display functions for use with IPython #----------------------------------------------------------------------------- def print_basic_unicode(o, p, cycle): diff --git a/IPython/extensions/tests/test_autoreload.py b/IPython/extensions/tests/test_autoreload.py index d4b4005b144..1ac1204acbf 100644 --- a/IPython/extensions/tests/test_autoreload.py +++ b/IPython/extensions/tests/test_autoreload.py @@ -1,3 +1,17 @@ +"""Tests for autoreload extension. +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2012 IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + import os import sys import tempfile @@ -9,21 +23,25 @@ import nose.tools as nt import IPython.testing.tools as tt -from IPython.extensions.autoreload import AutoreloadInterface +from IPython.extensions.autoreload import AutoreloadPlugin from IPython.core.hooks import TryNext #----------------------------------------------------------------------------- # Test fixture #----------------------------------------------------------------------------- +noop = lambda *a, **kw: None + class FakeShell(object): def __init__(self): self.ns = {} - self.reloader = AutoreloadInterface() + self.reloader = AutoreloadPlugin(shell=self) + + register_magics = set_hook = noop def run_code(self, code): try: - self.reloader.pre_run_code_hook(self) + self.reloader.auto_magics.pre_run_code_hook(self) except TryNext: pass exec code in self.ns @@ -32,10 +50,10 @@ def push(self, items): self.ns.update(items) def magic_autoreload(self, parameter): - self.reloader.magic_autoreload(self, parameter) + self.reloader.auto_magics.autoreload(parameter) def magic_aimport(self, parameter, stream=None): - self.reloader.magic_aimport(self, parameter, stream=stream) + self.reloader.auto_magics.aimport(parameter, stream=stream) class Fixture(object): @@ -81,7 +99,6 @@ def write_file(self, filename, content): future, and without changing the timestamp of the .pyc file (because that is stored in the file). The only reliable way to achieve this seems to be to sleep. - """ # Sleep one second + eps @@ -160,7 +177,7 @@ def foo(self): self.shell.magic_aimport("", stream=stream) nt.assert_true("Modules to reload:\nall-except-skipped" in stream.getvalue()) - nt.assert_true(mod_name in self.shell.ns) + nt.assert_in(mod_name, self.shell.ns) mod = sys.modules[mod_name] diff --git a/IPython/external/decorator/_decorator.py b/IPython/external/decorator/_decorator.py index 2791c1d5430..2751ab145b3 100644 --- a/IPython/external/decorator/_decorator.py +++ b/IPython/external/decorator/_decorator.py @@ -1,37 +1,43 @@ ########################## LICENCE ############################### -## -## Copyright (c) 2005, Michele Simionato -## All rights reserved. -## -## Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## Redistributions in bytecode form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in -## the documentation and/or other materials provided with the -## distribution. - -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -## HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -## INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -## BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -## OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -## TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -## USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -## DAMAGE. + +# Copyright (c) 2005-2012, Michele Simionato +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: + +# Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# Redistributions in bytecode form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. """ Decorator module, see http://pypi.python.org/pypi/decorator for the documentation. """ -__all__ = ["decorator", "FunctionMaker", "partial", - "deprecated", "getinfo", "new_wrapper"] +__version__ = '3.3.3' + +__all__ = ["decorator", "FunctionMaker", "partial"] + +import sys, re, inspect -import os, sys, re, inspect, string, warnings try: from functools import partial except ImportError: # for Python version < 2.5 @@ -46,6 +52,22 @@ def __call__(self, *otherargs, **otherkw): kw.update(otherkw) return self.func(*(self.args + otherargs), **kw) +if sys.version >= '3': + from inspect import getfullargspec +else: + class getfullargspec(object): + "A quick and dirty replacement for getfullargspec for Python 2.X" + def __init__(self, f): + self.args, self.varargs, self.varkw, self.defaults = \ + inspect.getargspec(f) + self.kwonlyargs = [] + self.kwonlydefaults = None + def __iter__(self): + yield self.args + yield self.varargs + yield self.varkw + yield self.defaults + DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(') # basic functionality @@ -57,6 +79,7 @@ class FunctionMaker(object): """ def __init__(self, func=None, name=None, signature=None, defaults=None, doc=None, module=None, funcdict=None): + self.shortsignature = signature if func: # func can be a class or a callable, but not an instance method self.name = func.__name__ @@ -65,13 +88,31 @@ def __init__(self, func=None, name=None, signature=None, self.doc = func.__doc__ self.module = func.__module__ if inspect.isfunction(func): - argspec = inspect.getargspec(func) - self.args, self.varargs, self.keywords, self.defaults = argspec + argspec = getfullargspec(func) + self.annotations = getattr(func, '__annotations__', {}) + for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs', + 'kwonlydefaults'): + setattr(self, a, getattr(argspec, a)) for i, arg in enumerate(self.args): setattr(self, 'arg%d' % i, arg) - self.signature = inspect.formatargspec( - formatvalue=lambda val: "", *argspec)[1:-1] + if sys.version < '3': # easy way + self.shortsignature = self.signature = \ + inspect.formatargspec( + formatvalue=lambda val: "", *argspec)[1:-1] + else: # Python 3 way + self.signature = self.shortsignature = ', '.join(self.args) + if self.varargs: + self.signature += ', *' + self.varargs + self.shortsignature += ', *' + self.varargs + if self.kwonlyargs: + for a in self.kwonlyargs: + self.signature += ', %s=None' % a + self.shortsignature += ', %s=%s' % (a, a) + if self.varkw: + self.signature += ', **' + self.varkw + self.shortsignature += ', **' + self.varkw self.dict = func.__dict__.copy() + # func=None happens when decorating a caller if name: self.name = name if signature is not None: @@ -95,6 +136,8 @@ def update(self, func, **kw): func.__doc__ = getattr(self, 'doc', None) func.__dict__ = getattr(self, 'dict', {}) func.func_defaults = getattr(self, 'defaults', ()) + func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None) + func.__annotations__ = getattr(self, 'annotations', None) callermodule = sys._getframe(3).f_globals.get('__name__', '?') func.__module__ = getattr(self, 'module', callermodule) func.__dict__.update(kw) @@ -107,15 +150,16 @@ def make(self, src_templ, evaldict=None, addsource=False, **attrs): if mo is None: raise SyntaxError('not a valid function template\n%s' % src) name = mo.group(1) # extract the function name - reserved_names = set([name] + [ - arg.strip(' *') for arg in self.signature.split(',')]) - for n, v in evaldict.iteritems(): - if n in reserved_names: + names = set([name] + [arg.strip(' *') for arg in + self.shortsignature.split(',')]) + for n in names: + if n in ('_func_', '_call_'): raise NameError('%s is overridden in\n%s' % (n, src)) if not src.endswith('\n'): # add a newline just for safety - src += '\n' + src += '\n' # this is needed in old versions of Python try: code = compile(src, '', 'single') + # print >> sys.stderr, 'Compiling %s' % src exec code in evaldict except: print >> sys.stderr, 'Error in generated code:' @@ -129,7 +173,7 @@ def make(self, src_templ, evaldict=None, addsource=False, **attrs): @classmethod def create(cls, obj, body, evaldict, defaults=None, - doc=None, module=None, addsource=True,**attrs): + doc=None, module=None, addsource=True, **attrs): """ Create a function from the strings name, signature and body. evaldict is the evaluation dictionary. If addsource is true an attribute @@ -144,9 +188,9 @@ def create(cls, obj, body, evaldict, defaults=None, name = None signature = None func = obj - fun = cls(func, name, signature, defaults, doc, module) + self = cls(func, name, signature, defaults, doc, module) ibody = '\n'.join(' ' + line for line in body.splitlines()) - return fun.make('def %(name)s(%(signature)s):\n' + ibody, + return self.make('def %(name)s(%(signature)s):\n' + ibody, evaldict, addsource, **attrs) def decorator(caller, func=None): @@ -155,100 +199,22 @@ def decorator(caller, func=None): decorator(caller, func) decorates a function using a caller. """ if func is not None: # returns a decorated function + evaldict = func.func_globals.copy() + evaldict['_call_'] = caller + evaldict['_func_'] = func return FunctionMaker.create( - func, "return _call_(_func_, %(signature)s)", - dict(_call_=caller, _func_=func), undecorated=func) + func, "return _call_(_func_, %(shortsignature)s)", + evaldict, undecorated=func, __wrapped__=func) else: # returns a decorator if isinstance(caller, partial): return partial(decorator, caller) # otherwise assume caller is a function - f = inspect.getargspec(caller)[0][0] # first arg + first = inspect.getargspec(caller)[0][0] # first arg + evaldict = caller.func_globals.copy() + evaldict['_call_'] = caller + evaldict['decorator'] = decorator return FunctionMaker.create( - '%s(%s)' % (caller.__name__, f), - 'return decorator(_call_, %s)' % f, - dict(_call_=caller, decorator=decorator), undecorated=caller, + '%s(%s)' % (caller.__name__, first), + 'return decorator(_call_, %s)' % first, + evaldict, undecorated=caller, __wrapped__=caller, doc=caller.__doc__, module=caller.__module__) - -###################### deprecated functionality ######################### - -@decorator -def deprecated(func, *args, **kw): - "A decorator for deprecated functions" - warnings.warn( - ('Calling the deprecated function %r\n' - 'Downgrade to decorator 2.3 if you want to use this functionality') - % func.__name__, DeprecationWarning, stacklevel=3) - return func(*args, **kw) - -@deprecated -def getinfo(func): - """ - Returns an info dictionary containing: - - name (the name of the function : str) - - argnames (the names of the arguments : list) - - defaults (the values of the default arguments : tuple) - - signature (the signature : str) - - doc (the docstring : str) - - module (the module name : str) - - dict (the function __dict__ : str) - - >>> def f(self, x=1, y=2, *args, **kw): pass - - >>> info = getinfo(f) - - >>> info["name"] - 'f' - >>> info["argnames"] - ['self', 'x', 'y', 'args', 'kw'] - - >>> info["defaults"] - (1, 2) - - >>> info["signature"] - 'self, x, y, *args, **kw' - """ - assert inspect.ismethod(func) or inspect.isfunction(func) - regargs, varargs, varkwargs, defaults = inspect.getargspec(func) - argnames = list(regargs) - if varargs: - argnames.append(varargs) - if varkwargs: - argnames.append(varkwargs) - signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults, - formatvalue=lambda value: "")[1:-1] - return dict(name=func.__name__, argnames=argnames, signature=signature, - defaults = func.func_defaults, doc=func.__doc__, - module=func.__module__, dict=func.__dict__, - globals=func.func_globals, closure=func.func_closure) - -@deprecated -def update_wrapper(wrapper, model, infodict=None): - "A replacement for functools.update_wrapper" - infodict = infodict or getinfo(model) - wrapper.__name__ = infodict['name'] - wrapper.__doc__ = infodict['doc'] - wrapper.__module__ = infodict['module'] - wrapper.__dict__.update(infodict['dict']) - wrapper.func_defaults = infodict['defaults'] - wrapper.undecorated = model - return wrapper - -@deprecated -def new_wrapper(wrapper, model): - """ - An improvement over functools.update_wrapper. The wrapper is a generic - callable object. It works by generating a copy of the wrapper with the - right signature and by updating the copy, not the original. - Moreovoer, 'model' can be a dictionary with keys 'name', 'doc', 'module', - 'dict', 'defaults'. - """ - if isinstance(model, dict): - infodict = model - else: # assume model is a function - infodict = getinfo(model) - assert not '_wrapper_' in infodict["argnames"], ( - '"_wrapper_" is a reserved argument name!') - src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict - funcopy = eval(src, dict(_wrapper_=wrapper)) - return update_wrapper(funcopy, model, infodict) - diff --git a/IPython/external/mglob/_mglob.py b/IPython/external/mglob/_mglob.py index 86056505064..f4da11c748d 100644 --- a/IPython/external/mglob/_mglob.py +++ b/IPython/external/mglob/_mglob.py @@ -210,17 +210,23 @@ def main(): print "\n".join(expand(sys.argv[1:])), -def mglob_f(self, arg): + +def mglob(self, arg): from IPython.utils.text import SList if arg.strip(): return SList(expand(arg)) print "Please specify pattern!" print globsyntax + +mglob.__doc__ = globsyntax + + def init_ipython(ip): """ register %mglob for IPython """ - mglob_f.__doc__ = globsyntax - ip.define_magic("mglob",mglob_f) + + ip.function_as_magic(mglob) + # test() if __name__ == "__main__": diff --git a/IPython/frontend/terminal/embed.py b/IPython/frontend/terminal/embed.py index 7dbd5a8cf7e..f6506ee94f7 100644 --- a/IPython/frontend/terminal/embed.py +++ b/IPython/frontend/terminal/embed.py @@ -23,16 +23,19 @@ #----------------------------------------------------------------------------- from __future__ import with_statement -import __main__ import sys +import warnings + +# We need to use nested to support python 2.6, once we move to >=2.7, we can +# use the with keyword's new builtin support for nested managers try: from contextlib import nested except: from IPython.utils.nested_context import nested -import warnings from IPython.core import ultratb +from IPython.core.magic import Magics, magics_class, line_magic from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell from IPython.frontend.terminal.ipapp import load_default_config @@ -45,21 +48,27 @@ #----------------------------------------------------------------------------- # This is an additional magic that is exposed in embedded shells. -def kill_embedded(self,parameter_s=''): - """%kill_embedded : deactivate for good the current embedded IPython. - - This function (after asking for confirmation) sets an internal flag so that - an embedded IPython will never activate again. This is useful to - permanently disable a shell that is being called inside a loop: once you've - figured out what you needed from it, you may then kill it and the program - will then continue to run without the interactive shell interfering again. - """ +@magics_class +class EmbeddedMagics(Magics): + + @line_magic + def kill_embedded(self, parameter_s=''): + """%kill_embedded : deactivate for good the current embedded IPython. + + This function (after asking for confirmation) sets an internal flag so + that an embedded IPython will never activate again. This is useful to + permanently disable a shell that is being called inside a loop: once + you've figured out what you needed from it, you may then kill it and + the program will then continue to run without the interactive shell + interfering again. + """ - kill = ask_yes_no("Are you sure you want to kill this embedded instance " - "(y/n)? [y/N] ",'n') - if kill: - self.embedded_active = False - print "This embedded IPython will not reactivate anymore once you exit." + kill = ask_yes_no("Are you sure you want to kill this embedded instance " + "(y/n)? [y/N] ",'n') + if kill: + self.shell.embedded_active = False + print ("This embedded IPython will not reactivate anymore " + "once you exit.") class InteractiveShellEmbed(TerminalInteractiveShell): @@ -89,7 +98,6 @@ def __init__(self, config=None, ipython_dir=None, user_ns=None, ) self.exit_msg = exit_msg - self.define_magic("kill_embedded", kill_embedded) # don't use the ipython crash handler so that user exceptions aren't # trapped @@ -100,6 +108,10 @@ def __init__(self, config=None, ipython_dir=None, user_ns=None, def init_sys_modules(self): pass + def init_magics(self): + super(InteractiveShellEmbed, self).init_magics() + self.register_magics(EmbeddedMagics) + def __call__(self, header='', local_ns=None, module=None, dummy=None, stack_depth=1, global_ns=None): """Activate the interactive interpreter. diff --git a/IPython/frontend/terminal/interactiveshell.py b/IPython/frontend/terminal/interactiveshell.py index 49c88dd36e9..5ddbcccdb9d 100644 --- a/IPython/frontend/terminal/interactiveshell.py +++ b/IPython/frontend/terminal/interactiveshell.py @@ -14,13 +14,14 @@ # Imports #----------------------------------------------------------------------------- -import __builtin__ import bdb import os import re import sys import textwrap +# We need to use nested to support python 2.6, once we move to >=2.7, we can +# use the with keyword's new builtin support for nested managers try: from contextlib import nested except: @@ -29,7 +30,7 @@ from IPython.core.error import TryNext, UsageError from IPython.core.usage import interactive_usage, default_banner from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC -from IPython.core.pylabtools import pylab_activate +from IPython.core.magic import Magics, magics_class, line_magic from IPython.testing.skipdoctest import skip_doctest from IPython.utils.encoding import get_stream_enc from IPython.utils import py3compat @@ -120,6 +121,138 @@ def rerun_pasted(shell, name='pasted_block'): shell.run_cell(b) +#------------------------------------------------------------------------ +# Terminal-specific magics +#------------------------------------------------------------------------ + +@magics_class +class TerminalMagics(Magics): + + @line_magic + def autoindent(self, parameter_s = ''): + """Toggle autoindent on/off (if available).""" + + self.shell.set_autoindent() + print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent] + + @skip_doctest + @line_magic + def cpaste(self, parameter_s=''): + """Paste & execute a pre-formatted code block from clipboard. + + You must terminate the block with '--' (two minus-signs) or Ctrl-D + alone on the line. You can also provide your own sentinel with '%paste + -s %%' ('%%' is the new sentinel for this operation) + + The block is dedented prior to execution to enable execution of method + definitions. '>' and '+' characters at the beginning of a line are + ignored, to allow pasting directly from e-mails, diff files and + doctests (the '...' continuation prompt is also stripped). The + executed block is also assigned to variable named 'pasted_block' for + later editing with '%edit pasted_block'. + + You can also pass a variable name as an argument, e.g. '%cpaste foo'. + This assigns the pasted block to variable 'foo' as string, without + dedenting or executing it (preceding >>> and + is still stripped) + + '%cpaste -r' re-executes the block previously entered by cpaste. + + Do not be alarmed by garbled output on Windows (it's a readline bug). + Just press enter and type -- (and press enter again) and the block + will be what was just pasted. + + IPython statements (magics, shell escapes) are not supported (yet). + + See also + -------- + paste: automatically pull code from clipboard. + + Examples + -------- + :: + + In [8]: %cpaste + Pasting code; enter '--' alone on the line to stop. + :>>> a = ["world!", "Hello"] + :>>> print " ".join(sorted(a)) + :-- + Hello world! + """ + + opts, name = self.parse_options(parameter_s, 'rs:', mode='string') + if 'r' in opts: + rerun_pasted(self.shell) + return + + sentinel = opts.get('s', '--') + block = strip_email_quotes(get_pasted_lines(sentinel)) + store_or_execute(self.shell, block, name) + + @line_magic + def paste(self, parameter_s=''): + """Paste & execute a pre-formatted code block from clipboard. + + The text is pulled directly from the clipboard without user + intervention and printed back on the screen before execution (unless + the -q flag is given to force quiet mode). + + The block is dedented prior to execution to enable execution of method + definitions. '>' and '+' characters at the beginning of a line are + ignored, to allow pasting directly from e-mails, diff files and + doctests (the '...' continuation prompt is also stripped). The + executed block is also assigned to variable named 'pasted_block' for + later editing with '%edit pasted_block'. + + You can also pass a variable name as an argument, e.g. '%paste foo'. + This assigns the pasted block to variable 'foo' as string, without + dedenting or executing it (preceding >>> and + is still stripped) + + Options + ------- + + -r: re-executes the block previously entered by cpaste. + + -q: quiet mode: do not echo the pasted text back to the terminal. + + IPython statements (magics, shell escapes) are not supported (yet). + + See also + -------- + cpaste: manually paste code into terminal until you mark its end. + """ + opts, name = self.parse_options(parameter_s, 'rq', mode='string') + if 'r' in opts: + rerun_pasted(self.shell) + return + try: + text = self.shell.hooks.clipboard_get() + block = strip_email_quotes(text.splitlines()) + except TryNext as clipboard_exc: + message = getattr(clipboard_exc, 'args') + if message: + error(message[0]) + else: + error('Could not get text from the clipboard.') + return + + # By default, echo back to terminal unless quiet mode is requested + if 'q' not in opts: + write = self.shell.write + write(self.shell.pycolorize(block)) + if not block.endswith('\n'): + write('\n') + write("## -- End pasted text --\n") + + store_or_execute(self.shell, block, name) + + # Class-level: add a '%cls' magic only on Windows + if sys.platform == 'win32': + @line_magic + def cls(self, s): + """Clear screen. + """ + os.system("cls") + #----------------------------------------------------------------------------- # Main class #----------------------------------------------------------------------------- @@ -531,134 +664,13 @@ def exit(self): else: self.ask_exit() - #------------------------------------------------------------------------ - # Magic overrides - #------------------------------------------------------------------------ - # Once the base class stops inheriting from magic, this code needs to be - # moved into a separate machinery as well. For now, at least isolate here - # the magics which this class needs to implement differently from the base - # class, or that are unique to it. - - def magic_autoindent(self, parameter_s = ''): - """Toggle autoindent on/off (if available).""" - - self.shell.set_autoindent() - print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent] - - @skip_doctest - def magic_cpaste(self, parameter_s=''): - """Paste & execute a pre-formatted code block from clipboard. - - You must terminate the block with '--' (two minus-signs) or Ctrl-D - alone on the line. You can also provide your own sentinel with '%paste - -s %%' ('%%' is the new sentinel for this operation) - - The block is dedented prior to execution to enable execution of method - definitions. '>' and '+' characters at the beginning of a line are - ignored, to allow pasting directly from e-mails, diff files and - doctests (the '...' continuation prompt is also stripped). The - executed block is also assigned to variable named 'pasted_block' for - later editing with '%edit pasted_block'. - - You can also pass a variable name as an argument, e.g. '%cpaste foo'. - This assigns the pasted block to variable 'foo' as string, without - dedenting or executing it (preceding >>> and + is still stripped) - - '%cpaste -r' re-executes the block previously entered by cpaste. - - Do not be alarmed by garbled output on Windows (it's a readline bug). - Just press enter and type -- (and press enter again) and the block - will be what was just pasted. - - IPython statements (magics, shell escapes) are not supported (yet). - - See also - -------- - paste: automatically pull code from clipboard. - - Examples - -------- - :: - - In [8]: %cpaste - Pasting code; enter '--' alone on the line to stop. - :>>> a = ["world!", "Hello"] - :>>> print " ".join(sorted(a)) - :-- - Hello world! - """ - - opts, name = self.parse_options(parameter_s, 'rs:', mode='string') - if 'r' in opts: - rerun_pasted(self.shell) - return - - sentinel = opts.get('s', '--') - block = strip_email_quotes(get_pasted_lines(sentinel)) - store_or_execute(self.shell, block, name) - - def magic_paste(self, parameter_s=''): - """Paste & execute a pre-formatted code block from clipboard. - - The text is pulled directly from the clipboard without user - intervention and printed back on the screen before execution (unless - the -q flag is given to force quiet mode). - - The block is dedented prior to execution to enable execution of method - definitions. '>' and '+' characters at the beginning of a line are - ignored, to allow pasting directly from e-mails, diff files and - doctests (the '...' continuation prompt is also stripped). The - executed block is also assigned to variable named 'pasted_block' for - later editing with '%edit pasted_block'. - - You can also pass a variable name as an argument, e.g. '%paste foo'. - This assigns the pasted block to variable 'foo' as string, without - dedenting or executing it (preceding >>> and + is still stripped) - - Options - ------- - - -r: re-executes the block previously entered by cpaste. - - -q: quiet mode: do not echo the pasted text back to the terminal. - - IPython statements (magics, shell escapes) are not supported (yet). - - See also - -------- - cpaste: manually paste code into terminal until you mark its end. - """ - opts, name = self.parse_options(parameter_s, 'rq', mode='string') - if 'r' in opts: - rerun_pasted(self.shell) - return - try: - text = self.shell.hooks.clipboard_get() - block = strip_email_quotes(text.splitlines()) - except TryNext as clipboard_exc: - message = getattr(clipboard_exc, 'args') - if message: - error(message[0]) - else: - error('Could not get text from the clipboard.') - return - - # By default, echo back to terminal unless quiet mode is requested - if 'q' not in opts: - write = self.shell.write - write(self.shell.pycolorize(block)) - if not block.endswith('\n'): - write('\n') - write("## -- End pasted text --\n") - - store_or_execute(self.shell, block, name) + #------------------------------------------------------------------------- + # Things related to magics + #------------------------------------------------------------------------- - # Class-level: add a '%cls' magic only on Windows - if sys.platform == 'win32': - def magic_cls(self, s): - """Clear screen. - """ - os.system("cls") + def init_magics(self): + super(TerminalInteractiveShell, self).init_magics() + self.register_magics(TerminalMagics) def showindentationerror(self): super(TerminalInteractiveShell, self).showindentationerror() diff --git a/IPython/parallel/client/view.py b/IPython/parallel/client/view.py index ca29e841906..77075160c86 100644 --- a/IPython/parallel/client/view.py +++ b/IPython/parallel/client/view.py @@ -813,10 +813,10 @@ def activate(self): except NameError: print "The IPython parallel magics (%result, %px, %autopx) only work within IPython." else: - pmagic = ip.plugin_manager.get_plugin('parallelmagic') + pmagic = ip.magics_manager.registry.get('ParallelMagics') if pmagic is None: - ip.magic_load_ext('parallelmagic') - pmagic = ip.plugin_manager.get_plugin('parallelmagic') + ip.magic('load_ext parallelmagic') + pmagic = ip.magics_manager.registry.get('ParallelMagics') pmagic.active_view = self diff --git a/IPython/parallel/tests/test_view.py b/IPython/parallel/tests/test_view.py index 6c1a7a0e816..d8cc803eda6 100644 --- a/IPython/parallel/tests/test_view.py +++ b/IPython/parallel/tests/test_view.py @@ -374,21 +374,21 @@ def test_magic_px_blocking(self): v.activate() v.block=True - ip.magic_px('a=5') + ip.magic('px a=5') self.assertEquals(v['a'], 5) - ip.magic_px('a=10') + ip.magic('px a=10') self.assertEquals(v['a'], 10) sio = StringIO() savestdout = sys.stdout sys.stdout = sio # just 'print a' worst ~99% of the time, but this ensures that # the stdout message has arrived when the result is finished: - ip.magic_px('import sys,time;print (a); sys.stdout.flush();time.sleep(0.2)') + ip.magic('px import sys,time;print (a); sys.stdout.flush();time.sleep(0.2)') sys.stdout = savestdout buf = sio.getvalue() self.assertTrue('[stdout:' in buf, buf) self.assertTrue(buf.rstrip().endswith('10')) - self.assertRaisesRemote(ZeroDivisionError, ip.magic_px, '1/0') + self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0') def test_magic_px_nonblocking(self): ip = get_ipython() @@ -396,18 +396,18 @@ def test_magic_px_nonblocking(self): v.activate() v.block=False - ip.magic_px('a=5') + ip.magic('px a=5') self.assertEquals(v['a'], 5) - ip.magic_px('a=10') + ip.magic('px a=10') self.assertEquals(v['a'], 10) sio = StringIO() savestdout = sys.stdout sys.stdout = sio - ip.magic_px('print a') + ip.magic('px print a') sys.stdout = savestdout buf = sio.getvalue() self.assertFalse('[stdout:%i]'%v.targets in buf) - ip.magic_px('1/0') + ip.magic('px 1/0') ar = v.get_result(-1) self.assertRaisesRemote(ZeroDivisionError, ar.get) @@ -420,12 +420,12 @@ def test_magic_autopx_blocking(self): sio = StringIO() savestdout = sys.stdout sys.stdout = sio - ip.magic_autopx() + ip.magic('autopx') ip.run_cell('\n'.join(('a=5','b=10','c=0'))) ip.run_cell('b*=2') ip.run_cell('print (b)') ip.run_cell("b/c") - ip.magic_autopx() + ip.magic('autopx') sys.stdout = savestdout output = sio.getvalue().strip() self.assertTrue(output.startswith('%autopx enabled')) @@ -445,13 +445,13 @@ def test_magic_autopx_nonblocking(self): sio = StringIO() savestdout = sys.stdout sys.stdout = sio - ip.magic_autopx() + ip.magic('autopx') ip.run_cell('\n'.join(('a=5','b=10','c=0'))) ip.run_cell('print (b)') ip.run_cell('import time; time.sleep(0.1)') ip.run_cell("b/c") ip.run_cell('b*=2') - ip.magic_autopx() + ip.magic('autopx') sys.stdout = savestdout output = sio.getvalue().strip() self.assertTrue(output.startswith('%autopx enabled')) @@ -472,10 +472,10 @@ def test_magic_result(self): v['a'] = 111 ra = v['a'] - ar = ip.magic_result() + ar = ip.magic('result') self.assertEquals(ar.msg_ids, [v.history[-1]]) self.assertEquals(ar.get(), 111) - ar = ip.magic_result('-2') + ar = ip.magic('result -2') self.assertEquals(ar.msg_ids, [v.history[-2]]) def test_unicode_execute(self): diff --git a/IPython/zmq/tests/test_embed_kernel.py b/IPython/zmq/tests/test_embed_kernel.py index 4cc7f896823..ac5739e6085 100644 --- a/IPython/zmq/tests/test_embed_kernel.py +++ b/IPython/zmq/tests/test_embed_kernel.py @@ -25,7 +25,6 @@ from IPython.zmq.blockingkernelmanager import BlockingKernelManager from IPython.utils import path, py3compat - #------------------------------------------------------------------------------- # Tests #------------------------------------------------------------------------------- @@ -38,6 +37,8 @@ def setup(): IPYTHONDIR = tempfile.mkdtemp() env = dict(IPYTHONDIR=IPYTHONDIR) + if 'PYTHONPATH' in os.environ: + env['PYTHONPATH'] = os.environ['PYTHONPATH'] save_get_ipython_dir = path.get_ipython_dir path.get_ipython_dir = lambda : IPYTHONDIR diff --git a/IPython/zmq/zmqshell.py b/IPython/zmq/zmqshell.py index b8d420f3088..7d9a7b7ec15 100644 --- a/IPython/zmq/zmqshell.py +++ b/IPython/zmq/zmqshell.py @@ -33,7 +33,7 @@ from IPython.core.autocall import ZMQExitAutocall from IPython.core.displaypub import DisplayPublisher from IPython.core.macro import Macro -from IPython.core.magic import MacroToEdit +from IPython.core.magics import MacroToEdit from IPython.core.payloadpage import install_payload_page from IPython.lib.kernel import ( get_connection_file, get_connection_info, connect_qtconsole @@ -49,7 +49,6 @@ from IPython.zmq.session import extract_header from session import Session - #----------------------------------------------------------------------------- # Functions and classes #----------------------------------------------------------------------------- diff --git a/docs/source/interactive/reference.txt b/docs/source/interactive/reference.txt index 9a78c8c29a8..225ed3cbefc 100644 --- a/docs/source/interactive/reference.txt +++ b/docs/source/interactive/reference.txt @@ -100,17 +100,45 @@ IPython itself, plus a lot of system-type features. They are all prefixed with a % character, but parameters are given without parentheses or quotes. -Example: typing ``%cd mydir`` changes your working directory to 'mydir', if it -exists. - -If you have 'automagic' enabled (as it by default), you don't need -to type in the % explicitly. IPython will scan its internal list of -magic functions and call one if it exists. With automagic on you can -then just type ``cd mydir`` to go to directory 'mydir'. The automagic -system has the lowest possible precedence in name searches, so defining -an identifier with the same name as an existing magic function will -shadow it for automagic use. You can still access the shadowed magic -function by explicitly using the % character at the beginning of the line. +Lines that begin with ``%%`` signal a *cell magic*: they take as arguments not +only the rest of the current line, but all lines below them as well, in the +current execution block. Cell magics can in fact make arbitrary modifications +to the input they receive, which need not even be valid Python code at all. +They receive the whole block as a single string. + +As a line magic example, the ``%cd`` magic works just like the OS command of +the same name:: + + In [8]: %cd + /home/fperez + +The following uses the builtin ``timeit`` in cell mode:: + + In [10]: %%timeit x = range(10000) + ...: min(x) + ...: max(x) + ...: + 1000 loops, best of 3: 438 us per loop + +In this case, ``x = range(10000)`` is called as the line argument, and the +block with ``min(x)`` and ``max(x)`` is called as the cell body. The +``timeit`` magic receives both. + +If you have 'automagic' enabled (as it by default), you don't need to type in +the single ``%`` explicitly for line magics; IPython will scan its internal +list of magic functions and call one if it exists. With automagic on you can +then just type ``cd mydir`` to go to directory 'mydir':: + + In [9]: cd mydir + /home/fperez/mydir + +Note that cell magics *always* require an explicit ``%%`` prefix, automagic +calling only works for line magics. + +The automagic system has the lowest possible precedence in name searches, so +defining an identifier with the same name as an existing magic function will +shadow it for automagic use. You can still access the shadowed magic function +by explicitly using the ``%`` character at the beginning of the line. An example (with automagic on) should clarify all this: @@ -137,24 +165,141 @@ An example (with automagic on) should clarify all this: /home/fperez/ipython -You can define your own magic functions to extend the system. The -following example defines a new magic command, %impall: +Defining your own magics +~~~~~~~~~~~~~~~~~~~~~~~~ + +There are two main ways to define your own magic functions: from standalone +functions and by inheriting from a base class provided by IPython: +:class:`IPython.core.magic.Magics`. Below we show code you can place in a file +that you load from your configuration, such as any file in the ``startup`` +subdirectory of your default IPython profile. + +First, let us see the simplest case. The following shows how to create a line +magic, a cell one and one that works in both modes, using just plain functions: .. sourcecode:: python + from IPython.core.magic import (register_line_magic, register_cell_magic, + register_line_cell_magic) + + @register_line_magic + def lmagic(line): + "my line magic" + return line + + @register_cell_magic + def cmagic(line, cell): + "my cell magic" + return line, cell + + @register_line_cell_magic + def lcmagic(line, cell=None): + "Magic that works both as %lcmagic and as %%lcmagic" + if cell is None: + print "Called as line magic" + return line + else: + print "Called as cell magic" + return line, cell + + # We delete these to avoid name conflicts for automagic to work + del lmagic, lcmagic + + +You can also create magics of all three kinds by inheriting from the +:class:`IPython.core.magic.Magics` class. This lets you create magics that can +potentially hold state in between calls, and that have full access to the main +IPython object: + +.. sourcecode:: python + + # This code can be put in any Python module, it does not require IPython + # itself to be running already. It only creates the magics subclass but + # doesn't instantiate it yet. + from IPython.core.magic import (Magics, magics_class, line_magic, + cell_magic, line_cell_magic) + + # The class MUST call this class decorator at creation time + @magics_class + class MyMagics(Magics): + + @line_magic + def lmagic(self, line): + "my line magic" + print "Full access to the main IPython object:", self.shell + print "Variables in the user namespace:", self.user_ns.keys() + return line + + @cell_magic + def cmagic(self, line, cell): + "my cell magic" + return line, cell + + @line_cell_magic + def lcmagic(self, line, cell=None): + "Magic that works both as %lcmagic and as %%lcmagic" + if cell is None: + print "Called as line magic" + return line + else: + print "Called as cell magic" + return line, cell + + + # In order to actually use these magics, you must register them with a + # running IPython. This code must be placed in a file that is loaded once + # IPython is up and running: ip = get_ipython() + # You can register the class itself without instantiating it. IPython will + # call the default constructor on it. + ip.register_magics(MyMagics) - def doimp(self, arg): - ip = self.api - ip.ex("import %s; reload(%s); from %s import *" % (arg,arg,arg) ) +If you want to create a class with a different constructor that holds +additional state, then you should always call the parent constructor and +instantiate the class yourself before registration: - ip.define_magic('impall', doimp) +.. sourcecode:: python + + @magics_class + class StatefulMagics(Magics): + "Magics that hold additional state" + + def __init__(self, shell, data): + # You must call the parent constructor + super(StatefulMagics, self).__init__(shell) + self.data = data + + # etc... + + # This class must then be registered with a manually created instance, + # since its constructor has different arguments from the default: + ip = get_ipython() + magics = StatefulMagics(ip, some_data) + ip.register_magics(magics) + + +In earlier versions, IPython had an API for the creation of line magics (cell +magics did not exist at the time) that required you to create functions with a +method-looking signature and to manually pass both the function and the name. +While this API is no longer recommended, it remains indefinitely supported for +backwards compatibility purposes. With the old API, you'd create a magic as +follows: + +.. sourcecode:: python + + def func(self, line): + print "Line magic called with line:", line + print "IPython object:", self.shell + + ip = get_ipython() + # Declare this function as the magic %mycommand + ip.define_magic('mycommand', func) Type ``%magic`` for more information, including a list of all available magic functions at any time and their docstrings. You can also type -``%magic_function_name?`` (see :ref:`below ` for information on -the '?' system) to get information about any particular magic function you are -interested in. +``%magic_function_name?`` (see :ref:`below ` for +information on the '?' system) to get information about any particular magic +function you are interested in. The API documentation for the :mod:`IPython.core.magic` module contains the full docstrings of all currently available magic commands. diff --git a/docs/source/interactive/tutorial.txt b/docs/source/interactive/tutorial.txt index 107a290d81d..011beae92f0 100644 --- a/docs/source/interactive/tutorial.txt +++ b/docs/source/interactive/tutorial.txt @@ -35,20 +35,42 @@ Magic functions =============== IPython has a set of predefined 'magic functions' that you can call with a -command line style syntax. These include: +command line style syntax. There are two kinds of magics, line-oriented and +cell-oriented. Line magics are prefixed with the ``%`` character and work much +like OS command-line calls: they get as an argument the rest of the line, where +arguments are passed without parentheses or quotes. Cell magics are prefixed +with a double ``%%``, and they are functions that get as an argument not only +the rest of the line, but also the lines below it in a separate argument. + +The following examples show how to call the builtin ``timeit`` magic, both in +line and cell mode:: + + In [1]: %timeit range(1000) + 100000 loops, best of 3: 7.76 us per loop + + In [2]: %%timeit x = range(10000) + ...: max(x) + ...: + 1000 loops, best of 3: 223 us per loop + +The builtin magics include: - Functions that work with code: ``%run``, ``%edit``, ``%save``, ``%macro``, ``%recall``, etc. -- Functions which affect the shell: ``%colors``, ``%xmode``, ``%autoindent``, etc. +- Functions which affect the shell: ``%colors``, ``%xmode``, ``%autoindent``, + etc. - Other functions such as ``%reset``, ``%timeit`` or ``%paste``. -You can always call these using the % prefix, and if you're typing one on a line -by itself, you can omit even that:: +You can always call them using the % prefix, and if you're calling a line magic +on a line by itself, you can omit even that (cell magics must always have the +``%%`` prefix):: run thescript.py - -For more details on any magic function, call ``%somemagic?`` to read its -docstring. To see all the available magic functions, call ``%lsmagic``. + +A more detailed explanation of the magic system can be obtained by calling +``%magic``, and for more details on any magic function, call ``%somemagic?`` to +read its docstring. To see all the available magic functions, call +``%lsmagic``. Running and Editing -------------------