diff --git a/IPython/html/static/notebook/js/cell.js b/IPython/html/static/notebook/js/cell.js index 514144f..032b413 100644 --- a/IPython/html/static/notebook/js/cell.js +++ b/IPython/html/static/notebook/js/cell.js @@ -147,10 +147,7 @@ var IPython = (function (IPython) { } if (this.code_mirror) { this.code_mirror.on('blur', function(cm, change) { - // Check if this unfocus event is legit. - if (!that.should_cancel_blur()) { - $([IPython.events]).trigger('command_mode.Cell', {cell: that}); - } + $([IPython.events]).trigger('command_mode.Cell', {cell: that}); }); } }; @@ -331,18 +328,7 @@ var IPython = (function (IPython) { return false; } }; - - /** - * Determine whether or not the unfocus event should be aknowledged. - * - * @method should_cancel_blur - * - * @return results {bool} Whether or not to ignore the cell's blur event. - **/ - Cell.prototype.should_cancel_blur = function () { - return false; - }; - + /** * Focus the cell in the DOM sense * @method focus_cell diff --git a/IPython/html/static/notebook/js/codecell.js b/IPython/html/static/notebook/js/codecell.js index c799681..44d4c79 100644 --- a/IPython/html/static/notebook/js/codecell.js +++ b/IPython/html/static/notebook/js/codecell.js @@ -358,21 +358,6 @@ var IPython = (function (IPython) { return false; }; - /** - * Determine whether or not the unfocus event should be aknowledged. - * - * @method should_cancel_blur - * - * @return results {bool} Whether or not to ignore the cell's blur event. - **/ - CodeCell.prototype.should_cancel_blur = function () { - // Cancel this unfocus event if the base wants to cancel or the cell - // completer is open or the tooltip is open. - return IPython.Cell.prototype.should_cancel_blur.apply(this) || - (this.completer && this.completer.is_visible()) || - (IPython.tooltip && IPython.tooltip.is_visible()); - }; - CodeCell.prototype.select_all = function () { var start = {line: 0, ch: 0}; var nlines = this.code_mirror.lineCount(); @@ -508,6 +493,23 @@ var IPython = (function (IPython) { return data; }; + /** + * handle cell level logic when a cell is unselected + * @method unselect + * @return is the action being taken + */ + CodeCell.prototype.unselect = function () { + var cont = IPython.Cell.prototype.unselect.apply(this); + if (cont) { + // When a code cell is usnelected, make sure that the corresponding + // tooltip and completer to that cell is closed. + IPython.tooltip.remove_and_cancel_tooltip(true); + if (this.completer !== null) { + this.completer.close(); + } + } + return cont; + }; IPython.CodeCell = CodeCell; diff --git a/IPython/html/static/notebook/js/completer.js b/IPython/html/static/notebook/js/completer.js index 3fd7245..14e13b6 100644 --- a/IPython/html/static/notebook/js/completer.js +++ b/IPython/html/static/notebook/js/completer.js @@ -73,7 +73,6 @@ var IPython = (function (IPython) { var Completer = function (cell) { - this._visible = false; this.cell = cell; this.editor = cell.code_mirror; var that = this; @@ -85,15 +84,9 @@ var IPython = (function (IPython) { }); }; - Completer.prototype.is_visible = function () { - // Return whether or not the completer is visible. - return this._visible; - }; - Completer.prototype.startCompletion = function () { // call for a 'first' completion, that will set the editor and do some - // special behaviour like autopicking if only one completion availlable - // + // special behavior like autopicking if only one completion available. if (this.editor.somethingSelected()) return; this.done = false; // use to get focus back on opera @@ -221,17 +214,37 @@ var IPython = (function (IPython) { } } - this.complete = $('
').addClass('completions'); - this.complete.attr('id', 'complete'); - - // Currently webkit doesn't use the size attr correctly. See: - // https://code.google.com/p/chromium/issues/detail?id=4579 - this.sel = $('') + .attr('tabindex', -1) + .attr('multiple', 'true'); + this.complete.append(this.sel); + this.visible = true; + $('body').append(this.complete); + + //build the container + var that = this; + this.sel.dblclick(function () { + that.pick(); + }); + this.sel.focus(function () { + that.editor.focus(); + }); + this._handle_keydown = function (cm, event) { + that.keydown(event); + }; + this.editor.on('keydown', this._handle_keydown); + this._handle_keypress = function (cm, event) { + that.keypress(event); + }; + this.editor.on('keypress', this._handle_keypress); + } + this.sel.attr('size', Math.min(10, this.raw_result.length)); // After everything is on the page, compute the postion. // We put it above the code if it is too close to the bottom of the page. @@ -249,28 +262,9 @@ var IPython = (function (IPython) { this.complete.css('left', left + 'px'); this.complete.css('top', top + 'px'); - - //build the container - var that = this; - this.sel.dblclick(function () { - that.pick(); - }); - this.sel.blur(this.close); - this.sel.keydown(function (event) { - that.keydown(event); - }); - this.sel.keypress(function (event) { - that.keypress(event); - }); - + // Clear and fill the list. + this.sel.text(''); this.build_gui_list(this.raw_result); - - this.sel.focus(); - IPython.keyboard_manager.disable(); - // Opera sometimes ignores focusing a freshly created node - if (window.opera) setTimeout(function () { - if (!this.done) this.sel.focus(); - }, 100); return true; }; @@ -288,20 +282,16 @@ var IPython = (function (IPython) { }; Completer.prototype.close = function () { - this._visible = false; - if (this.done) return; this.done = true; - $('.completions').remove(); - IPython.keyboard_manager.enable(); + $('#complete').remove(); + this.editor.off('keydown', this._handle_keydown); + this.editor.off('keypress', this._handle_keypress); + this.visible = false; }; Completer.prototype.pick = function () { this.insert(this.raw_result[this.sel[0].selectedIndex]); this.close(); - var that = this; - setTimeout(function () { - that.editor.focus(); - }, 50); }; Completer.prototype.keydown = function (event) { @@ -312,16 +302,10 @@ var IPython = (function (IPython) { if (code == keycodes.enter) { CodeMirror.e_stop(event); this.pick(); - } // Escape or backspace - else if (code == keycodes.esc) { + } else if (code == keycodes.esc || code == keycodes.backspace) { CodeMirror.e_stop(event); this.close(); - this.editor.focus(); - - } else if (code == keycodes.backspace) { - this.close(); - this.editor.focus(); } else if (code == keycodes.tab) { //all the fastforwarding operation, //Check that shared start is not null which can append with prefixed completion @@ -332,8 +316,6 @@ var IPython = (function (IPython) { this.insert(sh); } this.close(); - CodeMirror.e_stop(event); - this.editor.focus(); //reinvoke self setTimeout(function () { that.carry_on_completion(); @@ -341,10 +323,23 @@ var IPython = (function (IPython) { } else if (code == keycodes.up || code == keycodes.down) { // need to do that to be able to move the arrow // when on the first or last line ofo a code cell - event.stopPropagation(); + CodeMirror.e_stop(event); + + var options = this.sel.find('option'); + var index = this.sel[0].selectedIndex; + if (code == keycodes.up) { + index--; + } + if (code == keycodes.down) { + index++; + } + index = Math.min(Math.max(index, 0), options.length-1); + this.sel[0].selectedIndex = index; + } else if (code == keycodes.left || code == keycodes.right) { + this.close(); } }; - + Completer.prototype.keypress = function (event) { // FIXME: This is a band-aid. // on keypress, trigger insertion of a single character. @@ -358,26 +353,16 @@ var IPython = (function (IPython) { // don't handle keypress if it's not a character (arrows on FF) // or ENTER/TAB if (event.charCode === 0 || - code == keycodes.enter || - code == keycodes.tab + code == keycodes.tab || + code == keycodes.enter ) return; - var cur = this.editor.getCursor(); - var completion = { - str: String.fromCharCode(event.which), - type: "introspection", - from: cur, - to: cur, - }; - this.insert(completion); - this.close(); this.editor.focus(); setTimeout(function () { that.carry_on_completion(); }, 50); }; - IPython.Completer = Completer; return IPython; diff --git a/IPython/html/static/notebook/less/completer.less b/IPython/html/static/notebook/less/completer.less index 6f633de..1e564a2 100644 --- a/IPython/html/static/notebook/less/completer.less +++ b/IPython/html/static/notebook/less/completer.less @@ -17,6 +17,7 @@ font-family: @monoFontFamily; font-size: 110%; color: @textColor; + width: auto; } .completions select option.context { diff --git a/IPython/html/static/style/style.min.css b/IPython/html/static/style/style.min.css index 3c01e1d..36563fd 100644 --- a/IPython/html/static/style/style.min.css +++ b/IPython/html/static/style/style.min.css @@ -1,7 +1,3 @@ -.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0} -.clearfix:after{clear:both} -.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} -.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block} audio,canvas,video{display:inline-block;*display:inline;*zoom:1} audio:not([controls]){display:none} @@ -856,6 +852,10 @@ a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decorati .show{display:block} .invisible{visibility:hidden} .affix{position:fixed} +.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0} +.clearfix:after{clear:both} +.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} +.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} @-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden} .visible-phone{display:none !important} .visible-tablet{display:none !important} @@ -1497,7 +1497,7 @@ p{margin-bottom:0} .celltoolbar input[type=checkbox]{margin:0;margin-left:4px;margin-right:4px} .celltoolbar .ui-button{border:none;vertical-align:top;height:20px;min-width:30px} .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;border-radius:4px;-webkit-box-shadow:0 6px 10px -1px #adadad;-moz-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad} -.completions select{background:#fff;outline:none;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000} +.completions select{background:#fff;outline:none;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000;width:auto} .completions select option.context{color:#0064cd} #menubar .navbar-inner{min-height:28px;border-top:1px;border-radius:0 0 4px 4px} #menubar .navbar{margin-bottom:8px} diff --git a/IPython/html/static/widgets/js/widget.js b/IPython/html/static/widgets/js/widget.js index 110b06c..04a1fd8 100644 --- a/IPython/html/static/widgets/js/widget.js +++ b/IPython/html/static/widgets/js/widget.js @@ -83,6 +83,7 @@ function(WidgetManager, _, Backbone){ break; case 'display': this.widget_manager.display_view(msg, this); + this.trigger('displayed'); break; } }, diff --git a/IPython/html/static/widgets/js/widget_selectioncontainer.js b/IPython/html/static/widgets/js/widget_selectioncontainer.js index 12cd9cc..2031356 100644 --- a/IPython/html/static/widgets/js/widget_selectioncontainer.js +++ b/IPython/html/static/widgets/js/widget_selectioncontainer.js @@ -29,40 +29,44 @@ define(["widgets/js/widget"], function(WidgetManager){ this.model.on('change:_children', function(model, value, options) { this.update_children(model.previous('_children'), value); }, this); + this.model.on('change:selected_index', function(model, value, options) { + this.update_selected_index(model.previous('selected_index'), value, options); + }, this); + this.model.on('change:_titles', function(model, value, options) { + this.update_titles(value); + }, this); + this.model.on('displayed', function() { + this.update_titles(); + }, this); }, - - update: function(options) { - // Update the contents of this view - // - // Called when the model is changed. The model may have been - // changed by another view or by a state update from the back-end. - if (options === undefined || options.updated_view != this) { - // Set tab titles - var titles = this.model.get('_titles'); - var that = this; - _.each(titles, function(title, page_index) { - var accordian = that.containers[page_index]; - if (accordian !== undefined) { - accordian - .find('.accordion-heading') - .find('.accordion-toggle') - .text(title); - } - }); - // Set selected page - var selected_index = this.model.get("selected_index"); - if (0 <= selected_index && selected_index < this.containers.length) { - _.each(this.containers, function(container, index) { - if (index==selected_index) { - container.find('.accordion-body').collapse('show'); - } else { - container.find('.accordion-body').collapse('hide'); - } - }); + update_titles: function(titles) { + // Set tab titles + if (!titles) { + titles = this.model.get('_titles'); + } + + var that = this; + _.each(titles, function(title, page_index) { + var accordian = that.containers[page_index]; + if (accordian !== undefined) { + accordian + .find('.accordion-heading') + .find('.accordion-toggle') + .text(title); + } + }); + }, + + update_selected_index: function(old_index, new_index, options) { + // Only update the selection if the selection wasn't triggered + // by the front-end. It must be triggered by the back-end. + if (options === undefined || options.updated_view != this) { + this.containers[old_index].find('.accordion-body').collapse('hide'); + if (0 <= new_index && new_index < this.containers.length) { + this.containers[new_index].find('.accordion-body').collapse('show'); } } - return AccordionView.__super__.update.apply(this); }, update_children: function(old_list, new_list) { @@ -103,7 +107,7 @@ define(["widgets/js/widget"], function(WidgetManager){ // Calling model.set will trigger all of the other views of the // model to update. - that.model.set("selected_index", index, {updated_view: this}); + that.model.set("selected_index", index, {updated_view: that}); that.touch(); }) .text('Page ' + index) @@ -120,12 +124,7 @@ define(["widgets/js/widget"], function(WidgetManager){ accordion_inner.append(view.$el); this.update(); - - // Stupid workaround to close the bootstrap accordion tabs which - // open by default even though they don't have the `in` class - // attached to them. For some reason a delay is required. - // TODO: Better fix. - setTimeout(function(){ that.update(); }, 500); + this.update_titles(); }, }); WidgetManager.register_widget_view('AccordionView', AccordionView); diff --git a/IPython/html/tests/widgets/widget_multicontainer.js b/IPython/html/tests/widgets/widget_selectioncontainer.js similarity index 97% rename from IPython/html/tests/widgets/widget_multicontainer.js rename to IPython/html/tests/widgets/widget_selectioncontainer.js index 2004306..c9219e7 100644 --- a/IPython/html/tests/widgets/widget_multicontainer.js +++ b/IPython/html/tests/widgets/widget_selectioncontainer.js @@ -104,5 +104,10 @@ casper.notebook_test(function () { this.execute_cell_then(index, function(index){ this.test.assertEquals(this.get_output_cell(index).text, '1\n', // 0 based 'selected_index property updated with tab change.'); + + var is_collapsed = this.evaluate(function(s){ + return $(s + ' div.accordion-group:nth-child(2) a').hasClass('collapsed'); // 1 based + }, {s: multicontainer2_query}); + this.test.assertEquals(is_collapsed, false, 'Was tab actually opened?'); }); }); \ No newline at end of file diff --git a/IPython/lib/demo.py b/IPython/lib/demo.py index 7834cae..435670d 100644 --- a/IPython/lib/demo.py +++ b/IPython/lib/demo.py @@ -304,7 +304,7 @@ class Demo(object): self.src_blocks = src_blocks # also build syntax-highlighted source - self.src_blocks_colored = map(self.ip_colorize,self.src_blocks) + self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks)) # ensure clean namespace and seek offset self.reset() diff --git a/IPython/parallel/apps/launcher.py b/IPython/parallel/apps/launcher.py index 67a53b5..10e5a46 100644 --- a/IPython/parallel/apps/launcher.py +++ b/IPython/parallel/apps/launcher.py @@ -593,7 +593,7 @@ class SSHLauncher(LocalProcessLauncher): def _send_file(self, local, remote): """send a single file""" - remote = "%s:%s" % (self.location, remote) + full_remote = "%s:%s" % (self.location, remote) for i in range(10): if not os.path.exists(local): self.log.debug("waiting for %s" % local) @@ -605,8 +605,8 @@ class SSHLauncher(LocalProcessLauncher): check_output(self.ssh_cmd + self.ssh_args + \ [self.location, 'mkdir', '-p', '--', remote_dir] ) - self.log.info("sending %s to %s", local, remote) - check_output(self.scp_cmd + [local, remote]) + self.log.info("sending %s to %s", local, full_remote) + check_output(self.scp_cmd + [local, full_remote]) def send_files(self): """send our files (called before start)""" diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index ba1442f..45d2c78 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -268,7 +268,7 @@ test_sections['qt'].requires('zmq', 'qt', 'pygments') # html: sec = test_sections['html'] -sec.requires('zmq', 'tornado', 'requests') +sec.requires('zmq', 'tornado', 'requests', 'sqlite3') # The notebook 'static' directory contains JS, css and other # files for web serving. Occasionally projects may put a .py # file in there (MathJax ships a conf.py), so we might as diff --git a/IPython/testing/iptestcontroller.py b/IPython/testing/iptestcontroller.py index 66d62f9..adc2ea1 100644 --- a/IPython/testing/iptestcontroller.py +++ b/IPython/testing/iptestcontroller.py @@ -19,8 +19,8 @@ test suite. from __future__ import print_function import argparse +import json import multiprocessing.pool -from multiprocessing import Process, Queue import os import shutil import signal @@ -28,7 +28,7 @@ import sys import subprocess import time -from .iptest import have, test_group_names as py_test_group_names, test_sections +from .iptest import have, test_group_names as py_test_group_names, test_sections, StreamCapturer from IPython.utils.path import compress_user from IPython.utils.py3compat import bytes_to_str from IPython.utils.sysinfo import get_sys_info @@ -127,13 +127,14 @@ class PyTestController(TestController): #: str, Python command to execute in subprocess pycmd = None - def __init__(self, section): + def __init__(self, section, options): """Create new test runner.""" TestController.__init__(self) self.section = section # pycmd is put into cmd[2] in PyTestController.launch() self.cmd = [sys.executable, '-c', None, section] self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()" + self.options = options def setup(self): ipydir = TemporaryDirectory() @@ -145,6 +146,14 @@ class PyTestController(TestController): # This means we won't get odd effects from our own matplotlib config self.env['MPLCONFIGDIR'] = workingdir.name + # From options: + if self.options.xunit: + self.add_xunit() + if self.options.coverage: + self.add_coverage() + self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams + self.cmd.extend(self.options.extra_args) + @property def will_run(self): try: @@ -211,48 +220,77 @@ class JSController(TestController): os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub ∂ir2', u'sub ∂ir 1b'))) # start the ipython notebook, so we get the port number + self.server_port = 0 self._init_server() - self.cmd.append('--port=%s' % self.server_port) - + if self.server_port: + self.cmd.append("--port=%i" % self.server_port) + else: + # don't launch tests if the server didn't start + self.cmd = [sys.executable, '-c', 'raise SystemExit(1)'] + def print_extra_info(self): print("Running tests with notebook directory %r" % self.nbdir.name) @property def will_run(self): - return all(have[a] for a in ['zmq', 'tornado', 'jinja2', 'casperjs']) + return all(have[a] for a in ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3']) def _init_server(self): "Start the notebook server in a separate process" - self.queue = q = Queue() - self.server = Process(target=run_webapp, args=(q, self.ipydir.name, self.nbdir.name)) - self.server.start() - self.server_port = q.get() + self.server_command = command = [sys.executable, + '-m', 'IPython.html', + '--no-browser', + '--ipython-dir', self.ipydir.name, + '--notebook-dir', self.nbdir.name, + ] + # ipc doesn't work on Windows, and darwin has crazy-long temp paths, + # which run afoul of ipc's maximum path length. + if sys.platform.startswith('linux'): + command.append('--KernelManager.transport=ipc') + self.stream_capturer = c = StreamCapturer() + c.start() + self.server = subprocess.Popen(command, stdout=c.writefd, stderr=subprocess.STDOUT) + self.server_info_file = os.path.join(self.ipydir.name, + 'profile_default', 'security', 'nbserver-%i.json' % self.server.pid + ) + self._wait_for_server() + + def _wait_for_server(self): + """Wait 30 seconds for the notebook server to start""" + for i in range(300): + if self.server.poll() is not None: + return self._failed_to_start() + if os.path.exists(self.server_info_file): + self._load_server_info() + return + time.sleep(0.1) + print("Notebook server-info file never arrived: %s" % self.server_info_file, + file=sys.stderr + ) + + def _failed_to_start(self): + """Notebook server exited prematurely""" + captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace') + print("Notebook failed to start: ", file=sys.stderr) + print(self.server_command) + print(captured, file=sys.stderr) + + def _load_server_info(self): + """Notebook server started, load connection info from JSON""" + with open(self.server_info_file) as f: + info = json.load(f) + self.server_port = info['port'] def cleanup(self): - self.server.terminate() - self.server.join() + try: + self.server.terminate() + except OSError: + # already dead + pass + self.server.wait() + self.stream_capturer.halt() TestController.cleanup(self) -def run_webapp(q, ipydir, nbdir, loglevel=0): - """start the IPython Notebook, and pass port back to the queue""" - import os - import IPython.html.notebookapp as nbapp - import sys - sys.stderr = open(os.devnull, 'w') - server = nbapp.NotebookApp() - args = ['--no-browser'] - args.extend(['--ipython-dir', ipydir, - '--notebook-dir', nbdir, - '--log-level', str(loglevel), - ]) - # ipc doesn't work on Windows, and darwin has crazy-long temp paths, - # which run afoul of ipc's maximum path length. - if sys.platform.startswith('linux'): - args.append('--KernelManager.transport=ipc') - server.initialize(args) - # communicate the port number to the parent process - q.put(server.port) - server.start() def prepare_controllers(options): """Returns two lists of TestController instances, those to run, and those @@ -273,28 +311,13 @@ def prepare_controllers(options): test_sections['parallel'].enabled = False c_js = [JSController(name) for name in js_testgroups] - c_py = [PyTestController(name) for name in py_testgroups] - - configure_py_controllers(c_py, xunit=options.xunit, - coverage=options.coverage, subproc_streams=options.subproc_streams, - extra_args=options.extra_args) + c_py = [PyTestController(name, options) for name in py_testgroups] controllers = c_py + c_js to_run = [c for c in controllers if c.will_run] not_run = [c for c in controllers if not c.will_run] return to_run, not_run -def configure_py_controllers(controllers, xunit=False, coverage=False, - subproc_streams='capture', extra_args=()): - """Apply options for a collection of TestController objects.""" - for controller in controllers: - if xunit: - controller.add_xunit() - if coverage: - controller.add_coverage() - controller.env['IPTEST_SUBPROC_STREAMS'] = subproc_streams - controller.cmd.extend(extra_args) - def do_run(controller, buffer_output=True): """Setup and run a test controller. diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index c054d8a..bfcde8f 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -26,19 +26,6 @@ files for each profile, and the files look like :file:`ipython_config.py` or which defaults to :file:`$HOME/.ipython`. For Windows users, :envvar:`HOME` resolves to :file:`C:\\Users\\{YourUserName}` in most instances. - -Eventloop integration ---------------------- - -Previously IPython had command line options for controlling GUI event loop -integration (-gthread, -qthread, -q4thread, -wthread, -pylab). As of IPython -version 0.11, these have been removed. Please see the new ``%gui`` -magic command or :ref:`this section ` for details on the new -interface, or specify the gui at the commandline:: - - $ ipython --gui=qt - - Command-line Options -------------------- @@ -131,11 +118,9 @@ 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: +you can freely use variables with the same names as magic commands. If a magic +command is 'shadowed' by a variable, you will need the explicit ``%`` prefix to +use it: .. sourcecode:: ipython @@ -378,25 +363,16 @@ Search command history IPython provides two ways for searching through previous input and thus reduce the need for repetitive typing: - 1. Start typing, and then use Ctrl-p (previous,up) and Ctrl-n - (next,down) to search through only the history items that match - what you've typed so far. If you use Ctrl-p/Ctrl-n at a blank - prompt, they just behave like normal arrow keys. - 2. Hit Ctrl-r: opens a search prompt. Begin typing and the system + 1. Start typing, and then use the up and down arrow keys (or :kbd:`Ctrl-p` + and :kbd:`Ctrl-n`) to search through only the history items that match + what you've typed so far. + 2. Hit :kbd:`Ctrl-r`: to open a search prompt. Begin typing and the system searches your history for lines that contain what you've typed so far, completing as much as it can. - -Persistent command history across sessions -++++++++++++++++++++++++++++++++++++++++++ - IPython will save your input history when it leaves and reload it next time you restart it. By default, the history file is named -$IPYTHONDIR/profile_/history.sqlite. This allows you to keep -separate histories related to various tasks: commands related to -numerical work will not be clobbered by a system shell history, for -example. - +:file:`.ipython/profile_{name}/history.sqlite`. Autoindent ++++++++++ @@ -405,7 +381,7 @@ IPython can recognize lines ending in ':' and indent the next line, while also un-indenting automatically after 'raise' or 'return'. This feature uses the readline library, so it will honor your -:file:`~/.inputrc` configuration (or whatever file your INPUTRC variable points +:file:`~/.inputrc` configuration (or whatever file your :envvar:`INPUTRC` environment variable points to). Adding the following lines to your :file:`.inputrc` file can make indenting/unindenting more convenient (M-i indents, M-u unindents):: @@ -441,20 +417,15 @@ Customizing readline behavior All these features are based on the GNU readline library, which has an extremely customizable interface. Normally, readline is configured via a -file which defines the behavior of the library; the details of the -syntax for this can be found in the readline documentation available -with your system or on the Internet. IPython doesn't read this file (if -it exists) directly, but it does support passing to readline valid -options via a simple interface. In brief, you can customize readline by -setting the following options in your configuration file (note -that these options can not be specified at the command line): - - * **readline_parse_and_bind**: this holds a list of strings to be executed +:file:`.inputrc` file. IPython respects this, and you can also customise readline +by setting the following :doc:`configuration ` options: + + * ``InteractiveShell.readline_parse_and_bind``: this holds a list of strings to be executed via a readline.parse_and_bind() command. The syntax for valid commands of this kind can be found by reading the documentation for the GNU readline library, as these commands are of the kind which readline accepts in its configuration file. - * **readline_remove_delims**: a string of characters to be removed + * ``InteractiveShell.readline_remove_delims``: a string of characters to be removed from the default word-delimiters list used by readline, so that completions may be performed on strings which contain them. Do not change the default value unless you know what you're doing. @@ -595,7 +566,7 @@ detailed tracebacks. Furthermore, both normal and verbose tracebacks can be colored (if your terminal supports it) which makes them much easier to parse visually. -See the magic xmode and colors functions for details (just type %magic). +See the magic xmode and colors functions for details. These features are basically a terminal version of Ka-Ping Yee's cgitb module, now part of the standard Python library. @@ -612,7 +583,7 @@ retrieved as variables (besides the usual arrow key recall), in addition to the %rep magic command that brings a history entry up for editing on the next command line. -The following GLOBAL variables always exist (so don't overwrite them!): +The following variables always exist: * _i, _ii, _iii: store previous, next previous and next-next previous inputs. * In, _ih : a list of all inputs; _ih[n] is the input from line n. If you @@ -622,14 +593,13 @@ The following GLOBAL variables always exist (so don't overwrite them!): Additionally, global variables named _i are dynamically created ( being the prompt counter), so ``_i == _ih[] == In[]``. -For example, what you typed at prompt 14 is available as _i14, _ih[14] -and In[14]. +For example, what you typed at prompt 14 is available as ``_i14``, ``_ih[14]`` +and ``In[14]``. This allows you to easily cut and paste multi line interactive prompts by printing them out: they print like a clean string, without prompt characters. You can also manipulate them like regular variables (they -are strings), modify or exec them (typing ``exec _i9`` will re-execute the -contents of input prompt 9. +are strings), modify or exec them. You can also re-execute multiple lines of input easily by using the magic %rerun or %macro functions. The macro system also allows you to re-execute @@ -655,9 +625,9 @@ result (NOT assignments, for example) are cached. If you are familiar with Mathematica, IPython's _ variables behave exactly like Mathematica's % variables. -The following GLOBAL variables always exist (so don't overwrite them!): +The following variables always exist: - * [_] (a single underscore) : stores previous output, like Python's + * [_] (a single underscore): stores previous output, like Python's default interpreter. * [__] (two underscores): next previous. * [___] (three underscores): next-next previous. @@ -665,22 +635,21 @@ The following GLOBAL variables always exist (so don't overwrite them!): Additionally, global variables named _ are dynamically created ( being the prompt counter), such that the result of output is always available as _ (don't use the angle brackets, just the number, e.g. -_21). +``_21``). These variables are also stored in a global dictionary (not a list, since it only has entries for lines which returned a result) available under the names _oh and Out (similar to _ih and In). So the -output from line 12 can be obtained as _12, Out[12] or _oh[12]. If you +output from line 12 can be obtained as ``_12``, ``Out[12]`` or ``_oh[12]``. If you accidentally overwrite the Out variable you can recover it by typing -'Out=_oh' at the prompt. +``Out=_oh`` at the prompt. This system obviously can potentially put heavy memory demands on your system, since it prevents Python's garbage collector from removing any previously computed results. You can control how many results are kept -in memory with the option (at the command line or in your configuration -file) cache_size. If you set it to 0, the whole system is completely -disabled and the prompts revert to the classic '>>>' of normal Python. - +in memory with the configuration option ``InteractiveShell.cache_size``. +If you set it to 0, output caching is disabled. You can also use the ``%reset`` +and ``%xdel`` magics to clear large items from memory. Directory history ----------------- @@ -697,16 +666,17 @@ Automatic parentheses and quotes These features were adapted from Nathan Gray's LazyPython. They are meant to allow less typing for common situations. - -Automatic parentheses -+++++++++++++++++++++ - Callable objects (i.e. functions, methods, etc) can be invoked like this (notice the commas between the arguments):: In [1]: callable_ob arg1, arg2, arg3 ------> callable_ob(arg1, arg2, arg3) +.. note:: + This feature is disabled by default. To enable it, use the ``%autocall`` + magic command. The commands below with special prefixes will always work, + however. + You can force automatic parentheses by using '/' as the first character of a line. For example:: @@ -730,17 +700,10 @@ but this will work:: Out[5]: [(1, 4), (2, 5), (3, 6)] IPython tells you that it has altered your command line by displaying -the new command line preceded by ->. e.g.:: - - In [6]: callable list - ------> callable(list) +the new command line preceded by ``--->``. - -Automatic quoting -+++++++++++++++++ - -You can force automatic quoting of a function's arguments by using ',' -or ';' as the first character of a line. For example:: +You can force automatic quoting of a function's arguments by using ``,`` +or ``;`` as the first character of a line. For example:: In [1]: ,my_function /home/me # becomes my_function("/home/me") @@ -770,7 +733,7 @@ environment anytime you start Python:: raise SystemExit The ``raise SystemExit`` is needed to exit Python when -it finishes, otherwise you'll be back at the normal Python '>>>' +it finishes, otherwise you'll be back at the normal Python ``>>>`` prompt. This is probably useful to developers who manage multiple Python @@ -788,12 +751,12 @@ You can start a regular IPython session with .. sourcecode:: python import IPython - IPython.start_ipython() + IPython.start_ipython(argv=[]) at any point in your program. This will load IPython configuration, startup files, and everything, just as if it were a normal IPython session. -In addition to this, -it is possible to embed an IPython instance inside your own Python programs. + +It is also possible to embed an IPython shell in a namespace in your Python code. This allows you to evaluate dynamically the state of your code, operate with your variables, analyze them, etc. Note however that any changes you make to values while in the shell do not propagate back @@ -826,13 +789,10 @@ your Python programs for this to work (detailed examples follow later):: embed() # this call anywhere in your program will start IPython -.. note:: - - As of 0.13, you can embed an IPython *kernel*, for use with qtconsole, - etc. via ``IPython.embed_kernel()`` instead of ``IPython.embed()``. - It should function just the same as regular embed, but you connect - an external frontend rather than IPython starting up in the local - terminal. +You can also embed an IPython *kernel*, for use with qtconsole, etc. via +``IPython.embed_kernel()``. This should function work the same way, but you can +connect an external frontend (``ipython qtconsole`` or ``ipython console``), +rather than interacting with it in the terminal. You can run embedded instances even in code which is itself being run at the IPython interactive prompt with '%run '. Since it's easy @@ -872,45 +832,31 @@ pdb, the Python debugger, is a powerful interactive debugger which allows you to step through code, set breakpoints, watch variables, etc. IPython makes it very easy to start any script under the control of pdb, regardless of whether you have wrapped it into a 'main()' -function or not. For this, simply type '%run -d myscript' at an -IPython prompt. See the %run command's documentation (via '%run?' or -in Sec. magic_ for more details, including how to control where pdb -will stop execution first. - -For more information on the use of the pdb debugger, read the included -pdb.doc file (part of the standard Python distribution). On a stock -Linux system it is located at /usr/lib/python2.3/pdb.doc, but the -easiest way to read it is by using the help() function of the pdb module -as follows (in an IPython prompt):: +function or not. For this, simply type ``%run -d myscript`` at an +IPython prompt. See the %run command's documentation for more details, including +how to control where pdb will stop execution first. - In [1]: import pdb - In [2]: pdb.help() +For more information on the use of the pdb debugger, see :ref:`debugger-commands` +in the Python documentation. -This will load the pdb.doc document in a file viewer for you automatically. +Post-mortem debugging +--------------------- -Automatic invocation of pdb on exceptions ------------------------------------------ - -IPython, if started with the ``--pdb`` option (or if the option is set in -your config file) can call the Python pdb debugger every time your code -triggers an uncaught exception. This feature -can also be toggled at any time with the %pdb magic command. This can be +Going into a debugger when an exception occurs can be extremely useful in order to find the origin of subtle bugs, because pdb opens up at the point in your code which triggered the exception, and while your program is at this point 'dead', all the data is still available and you can walk up and down the stack frame and understand the origin of the problem. -Furthermore, you can use these debugging facilities both with the -embedded IPython mode and without IPython at all. For an embedded shell -(see sec. Embedding_), simply call the constructor with -``--pdb`` in the argument string and pdb will automatically be called if an -uncaught exception is triggered by your code. +You can use the ``%debug`` magic after an exception has occurred to start +post-mortem debugging. IPython can also call debugger every time your code +triggers an uncaught exception. This feature can be toggled with the %pdb magic +command, or you can start IPython with the ``--pdb`` option. -For stand-alone use of the feature in your programs which do not use -IPython at all, put the following lines toward the top of your 'main' -routine:: +For a post-mortem debugger in your programs outside IPython, +put the following lines toward the top of your 'main' routine:: import sys from IPython.core import ultratb @@ -925,25 +871,10 @@ options which can be set in IPython with ``--colors`` and ``--xmode``. This will give any of your programs detailed, colored tracebacks with automatic invocation of pdb. - -Extensions for syntax processing -================================ - -This isn't for the faint of heart, because the potential for breaking -things is quite high. But it can be a very powerful and useful feature. -In a nutshell, you can redefine the way IPython processes the user input -line to accept new, special extensions to the syntax without needing to -change any of IPython's own code. - -In the IPython/extensions directory you will find some examples -supplied, which we will briefly describe now. These can be used 'as is' -(and both provide very useful functionality), or you can use them as a -starting point for writing your own extensions. - .. _pasting_with_prompts: Pasting of code starting with Python or IPython prompts -------------------------------------------------------- +======================================================= IPython is smart enough to filter out input prompts, be they plain Python ones (``>>>`` and ``...``) or IPython ones (``In [N]:`` and ``...:``). You can @@ -1012,6 +943,11 @@ object, do:: %gui wx +You can also start IPython with an event loop set up using the :option:`--gui` +flag:: + + $ ipython --gui=qt + For information on IPython's matplotlib_ integration (and the ``matplotlib`` mode) see :ref:`this section `. @@ -1135,29 +1071,23 @@ demo:: mydemo = Demo('myscript.py') This creates the mydemo object, whose blocks you run one at a time by -simply calling the object with no arguments. If you have autocall active -in IPython (the default), all you need to do is type:: +simply calling the object with no arguments. Then call it to run each step +of the demo:: - mydemo + mydemo() -and IPython will call it, executing each block. Demo objects can be +Demo objects can be restarted, you can move forward or back skipping blocks, re-execute the -last block, etc. Simply use the Tab key on a demo object to see its -methods, and call '?' on them to see their docstrings for more usage -details. In addition, the demo module itself contains a comprehensive -docstring, which you can access via:: - - from IPython.lib import demo - - demo? +last block, etc. See the :mod:`IPython.lib.demo` module and the +:class:`~IPython.lib.demo.Demo` class for details. -Limitations: It is important to note that these demos are limited to +Limitations: These demos are limited to fairly simple uses. In particular, you cannot break up sections within indented code (loops, if statements, function definitions, etc.) Supporting something like this would basically require tracking the internal execution state of the Python interpreter, so only top-level divisions are allowed. If you want to be able to open an IPython instance at an arbitrary point in a program, you can use IPython's -embedding facilities, see :func:`IPython.embed` for details. +:ref:`embedding facilities `. .. include:: ../links.txt diff --git a/examples/core/example-embed.py b/examples/core/example-embed.py index fd7bf35..f8cffe4 100755 --- a/examples/core/example-embed.py +++ b/examples/core/example-embed.py @@ -1,5 +1,4 @@ #!/usr/bin/env python - """An example of how to embed an IPython shell into a running program. Please see the documentation in the IPython.Shell module for more details. @@ -13,7 +12,7 @@ from __future__ import print_function # The basics to get you going: -# IPython sets the __IPYTHON__ variable so you can know if you have nested +# IPython injects get_ipython into builtins, so you can know if you have nested # copies running. # Try running this code both at the command line and from inside IPython (with diff --git a/examples/lib/example-demo.py b/examples/lib/example-demo.py index 0db779d..fcdce76 100644 --- a/examples/lib/example-demo.py +++ b/examples/lib/example-demo.py @@ -16,7 +16,6 @@ print('unless auto_all has been set to true in the demo object') # The mark below defines a block boundary, which is a point where IPython will # stop execution and return to the interactive prompt. -# Note that in actual interactive execution, # --- stop --- x = 1