diff --git a/COPYING.txt b/COPYING.rst similarity index 75% rename from COPYING.txt rename to COPYING.rst index 64205fe..dea9b87 100644 --- a/COPYING.txt +++ b/COPYING.rst @@ -3,12 +3,12 @@ ============================= IPython is licensed under the terms of the Modified BSD License (also known as -New or Revised BSD), as follows: +New or Revised or 3-Clause BSD), as follows: -Copyright (c) 2008-2010, IPython Development Team -Copyright (c) 2001-2007, Fernando Perez. -Copyright (c) 2001, Janko Hauser -Copyright (c) 2001, Nathaniel Gray +- Copyright (c) 2008-2014, IPython Development Team +- Copyright (c) 2001-2007, Fernando Perez +- Copyright (c) 2001, Janko Hauser +- Copyright (c) 2001, Nathaniel Gray All rights reserved. @@ -50,15 +50,7 @@ details is kept in the documentation directory, in the file ``about/credits.txt``. The core team that coordinates development on GitHub can be found here: -http://github.com/ipython. As of late 2010, it consists of: - -* Brian E. Granger -* Jonathan March -* Evan Patterson -* Fernando Perez -* Min Ragan-Kelley -* Robert Kern - +https://github.com/ipython/. Our Copyright Policy -------------------- @@ -73,13 +65,10 @@ changes/contributions they have specific copyright on, they should indicate their copyright in the commit message of the change, when they commit the change to one of the IPython repositories. -With this in mind, the following banner should be used in any source code file +With this in mind, the following banner should be used in any source code file to indicate the copyright and license terms: -#----------------------------------------------------------------------------- -# Copyright (c) 2010, 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. -#----------------------------------------------------------------------------- +:: + + # Copyright (c) IPython Development Team. + # Distributed under the terms of the Modified BSD License. diff --git a/IPython/core/history.py b/IPython/core/history.py index ce0df78..da10813 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -29,6 +29,7 @@ import threading # Our own packages from IPython.config.configurable import Configurable from IPython.external.decorator import decorator +from IPython.utils.decorators import undoc from IPython.utils.path import locate_profile from IPython.utils import py3compat from IPython.utils.traitlets import ( @@ -40,6 +41,7 @@ from IPython.utils.warn import warn # Classes and functions #----------------------------------------------------------------------------- +@undoc class DummyDB(object): """Dummy DB that will act as a black hole for history. @@ -59,7 +61,7 @@ class DummyDB(object): @decorator def needs_sqlite(f, self, *a, **kw): - """return an empty list in the absence of sqlite""" + """Decorator: return an empty list in the absence of sqlite.""" if sqlite3 is None or not self.enabled: return [] else: @@ -69,6 +71,7 @@ def needs_sqlite(f, self, *a, **kw): if sqlite3 is not None: DatabaseError = sqlite3.DatabaseError else: + @undoc class DatabaseError(Exception): "Dummy exception when sqlite could not be imported. Should never occur." @@ -159,7 +162,7 @@ class HistoryAccessor(Configurable): hist_file : str Path to an SQLite history database stored by IPython. If specified, hist_file overrides profile. - config : + config : :class:`~IPython.config.loader.Config` Config object. hist_file can also be set through this. """ # We need a pointer back to the shell for various tasks. @@ -254,34 +257,43 @@ class HistoryAccessor(Configurable): @needs_sqlite @catch_corrupt_db - def get_session_info(self, session=0): - """get info about a session + def get_session_info(self, session): + """Get info about a session. Parameters ---------- session : int - Session number to retrieve. The current session is 0, and negative - numbers count back from current session, so -1 is previous session. + Session number to retrieve. Returns ------- - - (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`. - + + session_id : int + Session ID number + start : datetime + Timestamp for the start of the session. + end : datetime + Timestamp for the end of the session, or None if IPython crashed. + num_cmds : int + Number of commands run, or None if IPython crashed. + remark : unicode + A manually set description. """ - - if session <= 0: - session += self.session_number - query = "SELECT * from sessions where session == ?" return self.db.execute(query, (session,)).fetchone() @catch_corrupt_db + def get_last_session_id(self): + """Get the last session ID currently in the database. + + Within IPython, this should be the same as the value stored in + :attr:`HistoryManager.session_number`. + """ + for record in self.get_tail(n=1, include_latest=True): + return record[0] + + @catch_corrupt_db def get_tail(self, n=10, raw=True, output=False, include_latest=False): """Get the last n lines from the history database. @@ -374,9 +386,10 @@ class HistoryAccessor(Configurable): Returns ------- - An iterator over the desired lines. Each line is a 3-tuple, either - (session, line, input) if output is False, or - (session, line, (input, output)) if output is True. + entries + An iterator over the desired lines. Each line is a 3-tuple, either + (session, line, input) if output is False, or + (session, line, (input, output)) if output is True. """ if stop: lineclause = "line >= ? AND line < ?" @@ -535,6 +548,35 @@ class HistoryManager(HistoryAccessor): # ------------------------------ # Methods for retrieving history # ------------------------------ + def get_session_info(self, session=0): + """Get info about a session. + + Parameters + ---------- + + session : int + Session number to retrieve. The current session is 0, and negative + numbers count back from current session, so -1 is the previous session. + + Returns + ------- + + session_id : int + Session ID number + start : datetime + Timestamp for the start of the session. + end : datetime + Timestamp for the end of the session, or None if IPython crashed. + num_cmds : int + Number of commands run, or None if IPython crashed. + remark : unicode + A manually set description. + """ + if session <= 0: + session += self.session_number + + return super(HistoryManager, self).get_session_info(session=session) + def _get_range_session(self, start=1, stop=None, raw=True, output=False): """Get input and output history from the current session. Called by get_range, and takes similar parameters.""" @@ -578,9 +620,10 @@ class HistoryManager(HistoryAccessor): Returns ------- - An iterator over the desired lines. Each line is a 3-tuple, either - (session, line, input) if output is False, or - (session, line, (input, output)) if output is True. + entries + An iterator over the desired lines. Each line is a 3-tuple, either + (session, line, input) if output is False, or + (session, line, (input, output)) if output is True. """ if session <= 0: session += self.session_number @@ -594,7 +637,7 @@ class HistoryManager(HistoryAccessor): ## ---------------------------- def store_inputs(self, line_num, source, source_raw=None): """Store source and raw input in history and create input cache - variables _i*. + variables ``_i*``. Parameters ---------- @@ -765,8 +808,8 @@ def extract_hist_ranges(ranges_str): Examples -------- - list(extract_input_ranges("~8/5-~7/4 2")) - [(-8, 5, None), (-7, 1, 4), (0, 2, 3)] + >>> list(extract_hist_ranges("~8/5-~7/4 2")) + [(-8, 5, None), (-7, 1, 5), (0, 2, 3)] """ for range_str in ranges_str.split(): rmatch = range_re.match(range_str) diff --git a/IPython/core/magics/script.py b/IPython/core/magics/script.py index 02ff627..e4fd1f0 100644 --- a/IPython/core/magics/script.py +++ b/IPython/core/magics/script.py @@ -97,6 +97,7 @@ class ScriptMagics(Magics): 'perl', 'ruby', 'python', + 'python2', 'python3', 'pypy', ] diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index 9565e89..265958e 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -96,7 +96,10 @@ def figsize(sizex, sizey): def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs): - """Print a figure to an image, and return the resulting bytes + """Print a figure to an image, and return the resulting file data + + Returned data will be bytes unless ``fmt='svg'``, + in which case it will be unicode. Any keyword args are passed to fig.canvas.print_figure, such as ``quality`` or ``bbox_inches``. @@ -125,7 +128,10 @@ def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs): bytes_io = BytesIO() fig.canvas.print_figure(bytes_io, **kw) - return bytes_io.getvalue() + data = bytes_io.getvalue() + if fmt == 'svg': + data = data.decode('utf-8') + return data def retina_figure(fig, **kwargs): """format a figure as a pixel-doubled (retina) PNG""" diff --git a/IPython/core/release.py b/IPython/core/release.py index d49f3d1..0b05f87 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -26,7 +26,8 @@ _version_extra = 'dev' # _version_extra = 'rc1' # _version_extra = '' # Uncomment this for full releases -codename = 'Work in Progress' +# release.codename is deprecated in 2.0, will be removed in 3.0 +codename = '' # Construct full version string from these. _ver = [_version_major, _version_minor, _version_patch] diff --git a/IPython/core/tests/test_pylabtools.py b/IPython/core/tests/test_pylabtools.py index aed981f..317e41f 100644 --- a/IPython/core/tests/test_pylabtools.py +++ b/IPython/core/tests/test_pylabtools.py @@ -58,7 +58,7 @@ def test_figure_to_svg(): ax.plot([1,2,3]) plt.draw() svg = pt.print_figure(fig, 'svg')[:100].lower() - nt.assert_in(b'doctype svg', svg) + nt.assert_in(u'doctype svg', svg) def _check_pil_jpeg_bytes(): """Skip if PIL can't write JPEGs to BytesIO objects""" diff --git a/IPython/html/notebookapp.py b/IPython/html/notebookapp.py index 3cd81f5..81fda2d 100644 --- a/IPython/html/notebookapp.py +++ b/IPython/html/notebookapp.py @@ -73,6 +73,7 @@ from .services.sessions.sessionmanager import SessionManager from .base.handlers import AuthenticatedFileHandler, FileFindHandler +from IPython.config import Config from IPython.config.application import catch_config_error, boolean_flag from IPython.core.application import BaseIPythonApplication from IPython.core.profiledir import ProfileDir @@ -554,10 +555,12 @@ class NotebookApp(BaseIPythonApplication): # Use config here, to ensure that it takes higher priority than # anything that comes from the profile. + c = Config() if os.path.isdir(f): - self.config.NotebookApp.notebook_dir = f + c.NotebookApp.notebook_dir = f elif os.path.isfile(f): - self.config.NotebookApp.file_to_run = f + c.NotebookApp.file_to_run = f + self.update_config(c) def init_kernel_argv(self): """construct the kernel arguments""" diff --git a/IPython/html/static/base/js/keyboard.js b/IPython/html/static/base/js/keyboard.js index 4fa77d5..56391e6 100644 --- a/IPython/html/static/base/js/keyboard.js +++ b/IPython/html/static/base/js/keyboard.js @@ -128,15 +128,6 @@ IPython.keyboard = (function (IPython) { return shortcut; }; - var trigger_keydown = function (shortcut, element) { - // Trigger shortcut keydown on an element - element = element || document; - element = $(element); - var event = shortcut_to_event(shortcut, 'keydown'); - element.trigger(event); - }; - - // Shortcut manager class var ShortcutManager = function (delay) { @@ -252,7 +243,7 @@ IPython.keyboard = (function (IPython) { ShortcutManager.prototype.handles = function (event) { var shortcut = event_to_shortcut(event); var data = this._shortcuts[shortcut]; - return !( data === undefined ) + return !( data === undefined || data.handler === undefined ) } return { @@ -262,8 +253,7 @@ IPython.keyboard = (function (IPython) { normalize_key : normalize_key, normalize_shortcut : normalize_shortcut, shortcut_to_event : shortcut_to_event, - event_to_shortcut : event_to_shortcut, - trigger_keydown : trigger_keydown + event_to_shortcut : event_to_shortcut }; }(IPython)); diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 05cb955..e9f7a78 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -58,6 +58,9 @@ var IPython = (function (IPython) { this.style(); this.create_elements(); this.bind_events(); + this.save_notebook = function() { // don't allow save until notebook_loaded + this.save_notebook_error(null, null, "Load failed, save is disabled"); + }; }; /** @@ -1723,7 +1726,8 @@ var IPython = (function (IPython) { }; /** - * Save this notebook on the server. + * Save this notebook on the server. This becomes a notebook instance's + * .save_notebook method *after* the entire notebook has been loaded. * * @method save_notebook */ @@ -1829,7 +1833,7 @@ var IPython = (function (IPython) { " Selecting trust will immediately reload this notebook in a trusted state." ).append( " For more information, see the " - ).append($("").attr("href", "http://ipython.org/security.html") + ).append($("").attr("href", "http://ipython.org/ipython-doc/2/notebook/security.html") .text("IPython security documentation") ).append(".") ); @@ -2100,7 +2104,9 @@ var IPython = (function (IPython) { IPython.CellToolbar.global_show(); IPython.CellToolbar.activate_preset(this.metadata.celltoolbar); } - + + // now that we're fully loaded, it is safe to restore save functionality + delete(this.save_notebook); $([IPython.events]).trigger('notebook_loaded.Notebook'); }; diff --git a/IPython/html/static/notebook/js/notificationarea.js b/IPython/html/static/notebook/js/notificationarea.js index 87f508e..a2ecad1 100644 --- a/IPython/html/static/notebook/js/notificationarea.js +++ b/IPython/html/static/notebook/js/notificationarea.js @@ -188,8 +188,8 @@ var IPython = (function (IPython) { $([IPython.events]).on('notebook_saved.Notebook', function () { nnw.set_message("Notebook saved",2000); }); - $([IPython.events]).on('notebook_save_failed.Notebook', function () { - nnw.set_message("Notebook save failed"); + $([IPython.events]).on('notebook_save_failed.Notebook', function (evt, xhr, status, data) { + nnw.set_message(data || "Notebook save failed"); }); // Checkpoint events diff --git a/IPython/html/static/notebook/js/outputarea.js b/IPython/html/static/notebook/js/outputarea.js index 47f239f..79b902e 100644 --- a/IPython/html/static/notebook/js/outputarea.js +++ b/IPython/html/static/notebook/js/outputarea.js @@ -541,6 +541,10 @@ var IPython = (function (IPython) { var container = element; container.show = function(){console.log('Warning "container.show()" is deprecated.')}; // end backward compat + + // Fix for ipython/issues/5293, make sure `element` is the area which + // output can be inserted into at the time of JS execution. + element = toinsert; try { eval(js); } catch(err) { diff --git a/IPython/html/static/notebook/js/tooltip.js b/IPython/html/static/notebook/js/tooltip.js index 915cca4..af5cbe6 100644 --- a/IPython/html/static/notebook/js/tooltip.js +++ b/IPython/html/static/notebook/js/tooltip.js @@ -131,17 +131,13 @@ var IPython = (function (IPython) { Tooltip.prototype.showInPager = function (cell) { // reexecute last call in pager by appending ? to show back in pager var that = this; - var empty = function () {}; - cell.kernel.execute( - that.name + '?', { - 'execute_reply': empty, - 'output': empty, - 'clear_output': empty, - 'cell': cell - }, { - 'silent': false, - 'store_history': true - }); + var callbacks = {'shell' : { + 'payload' : { + 'page' : $.proxy(cell._open_with_pager, cell) + } + } + }; + cell.kernel.execute(that.name + '?', callbacks, {'silent': false, 'store_history': true}); this.remove_and_cancel_tooltip(); }; diff --git a/IPython/html/static/notebook/less/cell.less b/IPython/html/static/notebook/less/cell.less index 5514360..3cecbdf 100644 --- a/IPython/html/static/notebook/less/cell.less +++ b/IPython/html/static/notebook/less/cell.less @@ -33,6 +33,14 @@ div.prompt { line-height: @code_line_height; } +@media (max-width: 480px) { + // prompts are in the main column on small screens, + // so text should be left-aligned + div.prompt { + text-align: left; + } +} + div.inner_cell { .vbox(); .box-flex1(); diff --git a/IPython/html/static/notebook/less/codecell.less b/IPython/html/static/notebook/less/codecell.less index 777f185..8fc60b5 100644 --- a/IPython/html/static/notebook/less/codecell.less +++ b/IPython/html/static/notebook/less/codecell.less @@ -10,13 +10,19 @@ div.input { .hbox(); } +@media (max-width: 480px) { + // move prompts above code on small screens + div.input { + .vbox(); + } +} + /* input_area and input_prompt must match in top border and margin for alignment */ div.input_prompt { color: navy; border-top: 1px solid transparent; } - // The styles related to div.highlight are for nbconvert HTML output only. This works // because the .highlight div isn't present in the live notebook. We could put this into // nbconvert, but it easily falls out of sync, can't use our less variables and doesn't diff --git a/IPython/html/static/notebook/less/notebook.less b/IPython/html/static/notebook/less/notebook.less index 8c6589e..f7345d0 100644 --- a/IPython/html/static/notebook/less/notebook.less +++ b/IPython/html/static/notebook/less/notebook.less @@ -7,6 +7,14 @@ body.notebook_app { overflow: hidden; } +@media (max-width: 767px) { + // remove bootstrap-responsive's body padding on small screens + body.notebook_app { + padding-left: 0px; + padding-right: 0px; + } +} + span#notebook_name { height: 1em; line-height: 1em; diff --git a/IPython/html/static/notebook/less/outputarea.less b/IPython/html/static/notebook/less/outputarea.less index e129385..5dd1614 100644 --- a/IPython/html/static/notebook/less/outputarea.less +++ b/IPython/html/static/notebook/less/outputarea.less @@ -72,6 +72,13 @@ div.output_area { .vbox(); } +@media (max-width: 480px) { + // move prompts above output on small screens + div.output_area { + .vbox(); + } +} + div.output_area pre { margin: 0; padding: 0; diff --git a/IPython/html/static/notebook/less/textcell.less b/IPython/html/static/notebook/less/textcell.less index 0ec35bf..7abe339 100644 --- a/IPython/html/static/notebook/less/textcell.less +++ b/IPython/html/static/notebook/less/textcell.less @@ -2,6 +2,12 @@ div.text_cell { padding: 5px 5px 5px 0px; .hbox(); } +@media (max-width: 480px) { + // remove prompt indentation on small screens + div.text_cell > div.prompt { + display: none; + } +} div.text_cell_render { /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/ diff --git a/IPython/html/static/style/ipython.min.css b/IPython/html/static/style/ipython.min.css index b608f69..06e5ec5 100644 --- a/IPython/html/static/style/ipython.min.css +++ b/IPython/html/static/style/ipython.min.css @@ -73,11 +73,11 @@ div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:ver div.cell.edit_mode{border-radius:4px;border:thin #008000 solid} div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none} div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em} -div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1} +@media (max-width:480px){div.prompt{text-align:left}}div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1} div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7} div.prompt:empty{padding-top:0;padding-bottom:0} div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch} -div.input_prompt{color:#000080;border-top:1px solid transparent} +@media (max-width:480px){div.input{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}}div.input_prompt{color:#000080;border-top:1px solid transparent} div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent} div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em} .CodeMirror{line-height:1.21429em;height:auto;background:none;} @@ -117,7 +117,7 @@ div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-bo div.output_area .rendered_html table{margin-left:0;margin-right:0} div.output_area .rendered_html img{margin-left:0;margin-right:0} .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch} -div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit} +@media (max-width:480px){div.output_area{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}}div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit} div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1} div.output_text{text-align:left;color:#000;line-height:1.21429em} div.output_stderr{background:#fdd;} @@ -170,7 +170,7 @@ p.p-space{margin-bottom:10px} .rendered_html img{display:block;margin-left:auto;margin-right:auto} .rendered_html *+img{margin-top:1em} div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch} -div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000} +@media (max-width:480px){div.text_cell>div.prompt{display:none}}div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000} a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden} h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible} div.cell.text_cell.rendered{padding:0} diff --git a/IPython/html/static/style/style.min.css b/IPython/html/static/style/style.min.css index 36563fd..df65a85 100644 --- a/IPython/html/static/style/style.min.css +++ b/IPython/html/static/style/style.min.css @@ -1350,11 +1350,11 @@ div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:ver div.cell.edit_mode{border-radius:4px;border:thin #008000 solid} div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none} div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em} -div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1} +@media (max-width:480px){div.prompt{text-align:left}}div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1} div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7} div.prompt:empty{padding-top:0;padding-bottom:0} div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch} -div.input_prompt{color:#000080;border-top:1px solid transparent} +@media (max-width:480px){div.input{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}}div.input_prompt{color:#000080;border-top:1px solid transparent} div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent} div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em} .CodeMirror{line-height:1.21429em;height:auto;background:none;} @@ -1394,7 +1394,7 @@ div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-bo div.output_area .rendered_html table{margin-left:0;margin-right:0} div.output_area .rendered_html img{margin-left:0;margin-right:0} .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch} -div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit} +@media (max-width:480px){div.output_area{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}}div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit} div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1} div.output_text{text-align:left;color:#000;line-height:1.21429em} div.output_stderr{background:#fdd;} @@ -1447,7 +1447,7 @@ p.p-space{margin-bottom:10px} .rendered_html img{display:block;margin-left:auto;margin-right:auto} .rendered_html *+img{margin-top:1em} div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch} -div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000} +@media (max-width:480px){div.text_cell>div.prompt{display:none}}div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000} a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden} h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible} div.cell.text_cell.rendered{padding:0} @@ -1476,7 +1476,7 @@ div.cell.text_cell.rendered{padding:0} .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important} body{background-color:#fff} body.notebook_app{overflow:hidden} -span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%} +@media (max-width:767px){body.notebook_app{padding-left:0;padding-right:0}}span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%} div#notebook_panel{margin:0 0 0 0;padding:0;-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)} div#notebook{font-size:14px;line-height:20px;overflow-y:scroll;overflow-x:auto;width:100%;padding:1em 0 1em 0;margin:0;border-top:1px solid #ababab;outline:none;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box} div.ui-widget-content{border:1px solid #ababab;outline:none} diff --git a/IPython/html/templates/notebook.html b/IPython/html/templates/notebook.html index 097a416..eebd652 100644 --- a/IPython/html/templates/notebook.html +++ b/IPython/html/templates/notebook.html @@ -227,14 +227,14 @@ class="notebook_app" ( ("http://ipython.org/documentation.html","IPython Help",True), ("http://nbviewer.ipython.org/github/ipython/ipython/tree/master/examples/notebooks/", "Notebook Examples", True), - ("http://ipython.org/ipython-doc/stable/interactive/notebook.html","Notebook Help",True), - ("http://ipython.org/ipython-doc/dev/interactive/cm_keyboard.html","Editor Shortcuts",True), + ("http://ipython.org/ipython-doc/2/notebook/notebook.html","Notebook Help",True), + ("http://ipython.org/ipython-doc/2/notebook/cm_keyboard.html","Editor Shortcuts",True), ),( ("http://docs.python.org","Python",True), ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True), ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True), ("http://matplotlib.org/contents.html","Matplotlib",True), - ("http://docs.sympy.org/dev/index.html","SymPy",True), + ("http://docs.sympy.org/latest/index.html","SymPy",True), ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True) ) ) diff --git a/IPython/html/tests/notebook/arrow_keys.js b/IPython/html/tests/notebook/arrow_keys.js deleted file mode 100644 index 6f089ba..0000000 --- a/IPython/html/tests/notebook/arrow_keys.js +++ /dev/null @@ -1,24 +0,0 @@ -// -// Check for errors with up and down arrow presses in a non-empty notebook. -// -casper.notebook_test(function () { - var result = this.evaluate(function() { - IPython.notebook.command_mode(); - pos0 = IPython.notebook.get_selected_index(); - IPython.keyboard.trigger_keydown('b'); - pos1 = IPython.notebook.get_selected_index(); - IPython.keyboard.trigger_keydown('b'); - pos2 = IPython.notebook.get_selected_index(); - // Simulate the "up arrow" and "down arrow" keys. - IPython.keyboard.trigger_keydown('up'); - pos3 = IPython.notebook.get_selected_index(); - IPython.keyboard.trigger_keydown('down'); - pos4 = IPython.notebook.get_selected_index(); - return pos0 == 0 && - pos1 == 1 && - pos2 == 2 && - pos3 == 1 && - pos4 == 2; - }); - this.test.assertTrue(result, 'Up/down arrow okay in non-empty notebook.'); -}); diff --git a/IPython/html/tests/notebook/dualmode.js b/IPython/html/tests/notebook/dualmode.js new file mode 100644 index 0000000..87b5567 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode.js @@ -0,0 +1,78 @@ +// Test the notebook dual mode feature. + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + this.validate_notebook_state('initial state', 'edit', 0); + this.trigger_keydown('esc'); + this.validate_notebook_state('esc', 'command', 0); + this.trigger_keydown('down'); + this.validate_notebook_state('down', 'command', 1); + this.trigger_keydown('enter'); + this.validate_notebook_state('enter', 'edit', 1); + this.trigger_keydown('j'); + this.validate_notebook_state('j in edit mode', 'edit', 1); + this.trigger_keydown('esc'); + this.validate_notebook_state('esc', 'command', 1); + this.trigger_keydown('j'); + this.validate_notebook_state('j in command mode', 'command', 2); + this.click_cell_editor(0); + this.validate_notebook_state('click cell 0', 'edit', 0); + this.click_cell_editor(3); + this.validate_notebook_state('click cell 3', 'edit', 3); + this.trigger_keydown('esc'); + this.validate_notebook_state('esc', 'command', 3); + + // Open keyboard help + this.evaluate(function(){ + $('#keyboard_shortcuts a').click(); + }, {}); + + this.trigger_keydown('k'); + this.validate_notebook_state('k in command mode while keyboard help is up', 'command', 3); + + // Close keyboard help + this.evaluate(function(){ + $('div.modal button.close').click(); + }, {}); + + this.trigger_keydown('k'); + this.validate_notebook_state('k in command mode', 'command', 2); + this.click_cell_editor(0); + this.validate_notebook_state('click cell 0', 'edit', 0); + this.focus_notebook(); + this.validate_notebook_state('focus #notebook', 'command', 0); + this.click_cell_editor(0); + this.validate_notebook_state('click cell 0', 'edit', 0); + this.focus_notebook(); + this.validate_notebook_state('focus #notebook', 'command', 0); + this.click_cell_editor(3); + this.validate_notebook_state('click cell 3', 'edit', 3); + + // Cell deletion + this.trigger_keydown('esc', 'd', 'd'); + this.test.assertEquals(this.get_cells_length(), 3, 'dd actually deletes a cell'); + this.validate_notebook_state('dd', 'command', 2); + + // Make sure that if the time between d presses is too long, nothing gets removed. + this.trigger_keydown('d'); + }); + this.wait(1000); + this.then(function () { + this.trigger_keydown('d'); + this.test.assertEquals(this.get_cells_length(), 3, "d, 1 second wait, d doesn't delete a cell"); + this.validate_notebook_state('d, 1 second wait, d', 'command', 2); + }); +}); diff --git a/IPython/html/tests/notebook/dualmode_arrows.js b/IPython/html/tests/notebook/dualmode_arrows.js new file mode 100644 index 0000000..034929b --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_arrows.js @@ -0,0 +1,51 @@ + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + + // Up and down in command mode + this.select_cell(3); + this.trigger_keydown('j'); + this.validate_notebook_state('j at end of notebook', 'command', 3); + this.trigger_keydown('down'); + this.validate_notebook_state('down at end of notebook', 'command', 3); + this.trigger_keydown('up'); + this.validate_notebook_state('up', 'command', 2); + this.select_cell(0); + this.validate_notebook_state('select 0', 'command', 0); + this.trigger_keydown('k'); + this.validate_notebook_state('k at top of notebook', 'command', 0); + this.trigger_keydown('up'); + this.validate_notebook_state('up at top of notebook', 'command', 0); + this.trigger_keydown('down'); + this.validate_notebook_state('down', 'command', 1); + + // Up and down in edit mode + this.click_cell_editor(3); + this.validate_notebook_state('click cell 3', 'edit', 3); + this.trigger_keydown('down'); + this.validate_notebook_state('down at end of notebook', 'edit', 3); + this.set_cell_editor_cursor(3, 0, 0); + this.trigger_keydown('up'); + this.validate_notebook_state('up', 'edit', 2); + this.click_cell_editor(0); + this.validate_notebook_state('click 0', 'edit', 0); + this.trigger_keydown('up'); + this.validate_notebook_state('up at top of notebook', 'edit', 0); + this.set_cell_editor_cursor(0, 0, 10); + this.trigger_keydown('down'); + this.validate_notebook_state('down', 'edit', 1); + }); +}); diff --git a/IPython/html/tests/notebook/dualmode_cellinsert.js b/IPython/html/tests/notebook/dualmode_cellinsert.js new file mode 100644 index 0000000..59b89a3 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_cellinsert.js @@ -0,0 +1,27 @@ + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + // Cell insertion + this.select_cell(2); + this.trigger_keydown('a'); // Creates one cell + this.test.assertEquals(this.get_cell_text(2), '', 'a; New cell 2 text is empty'); + this.validate_notebook_state('a', 'command', 2); + this.trigger_keydown('b'); // Creates one cell + this.test.assertEquals(this.get_cell_text(2), '', 'b; Cell 2 text is still empty'); + this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty'); + this.validate_notebook_state('b', 'command', 3); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_cellmode.js b/IPython/html/tests/notebook/dualmode_cellmode.js new file mode 100644 index 0000000..d4bf5f0 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_cellmode.js @@ -0,0 +1,28 @@ +// Test keyboard shortcuts that change the cell's mode. + +// Test +casper.notebook_test(function () { + this.then(function () { + // Cell mode change + this.select_cell(0); + this.trigger_keydown('esc','r'); + this.test.assertEquals(this.get_cell(0).cell_type, 'raw', 'r; cell is raw'); + this.trigger_keydown('1'); + this.test.assertEquals(this.get_cell(0).cell_type, 'heading', '1; cell is heading'); + this.test.assertEquals(this.get_cell(0).level, 1, '1; cell is level 1 heading'); + this.trigger_keydown('2'); + this.test.assertEquals(this.get_cell(0).level, 2, '2; cell is level 2 heading'); + this.trigger_keydown('3'); + this.test.assertEquals(this.get_cell(0).level, 3, '3; cell is level 3 heading'); + this.trigger_keydown('4'); + this.test.assertEquals(this.get_cell(0).level, 4, '4; cell is level 4 heading'); + this.trigger_keydown('5'); + this.test.assertEquals(this.get_cell(0).level, 5, '5; cell is level 5 heading'); + this.trigger_keydown('6'); + this.test.assertEquals(this.get_cell(0).level, 6, '6; cell is level 6 heading'); + this.trigger_keydown('m'); + this.test.assertEquals(this.get_cell(0).cell_type, 'markdown', 'm; cell is markdown'); + this.trigger_keydown('y'); + this.test.assertEquals(this.get_cell(0).cell_type, 'code', 'y; cell is code'); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_clipboard.js b/IPython/html/tests/notebook/dualmode_clipboard.js new file mode 100644 index 0000000..5068c49 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_clipboard.js @@ -0,0 +1,55 @@ + + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + // Copy/paste/cut + var num_cells = this.get_cells_length(); + this.test.assertEquals(this.get_cell_text(1), a, 'Verify that cell 1 is a'); + this.select_cell(1); + this.trigger_keydown('x'); // Cut + this.validate_notebook_state('x', 'command', 1); + this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that a cell was removed.'); + this.test.assertEquals(this.get_cell_text(1), b, 'Verify that cell 2 is now where cell 1 was.'); + this.select_cell(2); + this.trigger_keydown('v'); // Paste + this.validate_notebook_state('v', 'command', 3); // Selection should move to pasted cell, below current cell. + this.test.assertEquals(this.get_cell_text(3), a, 'Verify that cell 3 has the cut contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells, 'Verify a the cell was added.'); + this.trigger_keydown('v'); // Paste + this.validate_notebook_state('v', 'command', 4); // Selection should move to pasted cell, below current cell. + this.test.assertEquals(this.get_cell_text(4), a, 'Verify that cell 4 has the cut contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+1, 'Verify a the cell was added.'); + this.select_cell(1); + this.trigger_keydown('c'); // Copy + this.validate_notebook_state('c', 'command', 1); + this.test.assertEquals(this.get_cell_text(1), b, 'Verify that cell 1 is b'); + this.select_cell(2); + this.trigger_keydown('c'); // Copy + this.validate_notebook_state('c', 'command', 2); + this.test.assertEquals(this.get_cell_text(2), c, 'Verify that cell 2 is c'); + this.select_cell(4); + this.trigger_keydown('v'); // Paste + this.validate_notebook_state('v', 'command', 5); + this.test.assertEquals(this.get_cell_text(2), c, 'Verify that cell 2 still has the copied contents.'); + this.test.assertEquals(this.get_cell_text(5), c, 'Verify that cell 5 has the copied contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+2, 'Verify a the cell was added.'); + this.select_cell(0); + this.trigger_keydown('shift-v'); // Paste + this.validate_notebook_state('shift-v', 'command', 0); + this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.'); + this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.'); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_execute.js b/IPython/html/tests/notebook/dualmode_execute.js new file mode 100644 index 0000000..f4cd954 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_execute.js @@ -0,0 +1,72 @@ +// Test keyboard invoked execution. + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + var c = 'print("c")'; + index = this.append_cell(c); + this.execute_cell_then(index); + + this.then(function () { + + // shift-enter + // last cell in notebook + var base_index = 3; + this.select_cell(base_index); + this.trigger_keydown('shift-enter'); // Creates one cell + this.validate_notebook_state('shift-enter (no cell below)', 'edit', base_index + 1); + // not last cell in notebook & starts in edit mode + this.click_cell_editor(base_index); + this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); + this.trigger_keydown('shift-enter'); + this.validate_notebook_state('shift-enter (cell exists below)', 'command', base_index + 1); + // starts in command mode + this.trigger_keydown('k'); + this.validate_notebook_state('k in comand mode', 'command', base_index); + this.trigger_keydown('shift-enter'); + this.validate_notebook_state('shift-enter (start in command mode)', 'command', base_index + 1); + + // ctrl-enter + // last cell in notebook + base_index++; + this.trigger_keydown('ctrl-enter'); + this.validate_notebook_state('ctrl-enter (no cell below)', 'command', base_index); + // not last cell in notebook & starts in edit mode + this.click_cell_editor(base_index-1); + this.validate_notebook_state('click cell ' + (base_index-1), 'edit', base_index-1); + this.trigger_keydown('ctrl-enter'); + this.validate_notebook_state('ctrl-enter (cell exists below)', 'command', base_index-1); + // starts in command mode + this.trigger_keydown('j'); + this.validate_notebook_state('j in comand mode', 'command', base_index); + this.trigger_keydown('ctrl-enter'); + this.validate_notebook_state('ctrl-enter (start in command mode)', 'command', base_index); + + // alt-enter + // last cell in notebook + this.trigger_keydown('alt-enter'); // Creates one cell + this.validate_notebook_state('alt-enter (no cell below)', 'edit', base_index + 1); + // not last cell in notebook & starts in edit mode + this.click_cell_editor(base_index); + this.validate_notebook_state('click cell ' + base_index, 'edit', base_index); + this.trigger_keydown('alt-enter'); // Creates one cell + this.validate_notebook_state('alt-enter (cell exists below)', 'edit', base_index + 1); + // starts in command mode + this.trigger_keydown('esc', 'k'); + this.validate_notebook_state('k in comand mode', 'command', base_index); + this.trigger_keydown('alt-enter'); // Creates one cell + this.validate_notebook_state('alt-enter (start in command mode)', 'edit', base_index + 1); + + // Notebook will now have 8 cells, the index of the last cell will be 7. + this.test.assertEquals(this.get_cells_length(), 8, '*-enter commands added cells where needed.'); + this.select_cell(7); + this.validate_notebook_state('click cell ' + 7 + ' and esc', 'command', 7); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_markdown.js b/IPython/html/tests/notebook/dualmode_markdown.js new file mode 100644 index 0000000..d974057 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_markdown.js @@ -0,0 +1,39 @@ + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + this.then(function () { + // Markdown rendering / unredering + this.select_cell(1); + this.validate_notebook_state('select 1', 'command', 1); + this.trigger_keydown('m'); + this.test.assertEquals(this.get_cell(1).cell_type, 'markdown', 'm; cell is markdown'); + this.test.assertEquals(this.get_cell(1).rendered, false, 'm; cell is rendered'); + this.trigger_keydown('enter'); + this.test.assertEquals(this.get_cell(1).rendered, false, 'enter; cell is unrendered'); + this.validate_notebook_state('enter', 'edit', 1); + this.trigger_keydown('ctrl-enter'); + this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl-enter; cell is rendered'); + this.validate_notebook_state('enter', 'command', 1); + this.trigger_keydown('enter'); + this.test.assertEquals(this.get_cell(1).rendered, false, 'enter; cell is unrendered'); + this.select_cell(0); + this.test.assertEquals(this.get_cell(1).rendered, false, 'select 0; cell 1 is still unrendered'); + this.validate_notebook_state('select 0', 'command', 0); + this.select_cell(1); + this.validate_notebook_state('select 1', 'command', 1); + this.trigger_keydown('ctrl-enter'); + this.test.assertEquals(this.get_cell(1).rendered, true, 'ctrl-enter; cell is rendered'); + this.select_cell(0); + this.validate_notebook_state('select 0', 'command', 0); + this.trigger_keydown('shift-enter'); + this.validate_notebook_state('shift-enter', 'command', 1); + this.test.assertEquals(this.get_cell(1).rendered, true, 'shift-enter; cell is rendered'); + this.trigger_keydown('shift-enter'); // Creates one cell + this.validate_notebook_state('shift-enter', 'edit', 2); + this.test.assertEquals(this.get_cell(1).rendered, true, 'shift-enter; cell is rendered'); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_merge.js b/IPython/html/tests/notebook/dualmode_merge.js new file mode 100644 index 0000000..573b457 --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_merge.js @@ -0,0 +1,21 @@ + +// Test +casper.notebook_test(function () { + this.then(function () { + // Split and merge cells + this.select_cell(0); + this.trigger_keydown('a', 'enter'); // Create cell above and enter edit mode. + this.validate_notebook_state('a, enter', 'edit', 0); + this.set_cell_text(0, 'abcd'); + this.set_cell_editor_cursor(0, 0, 2); + this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.'); + this.trigger_keydown('ctrl-shift-subtract'); // Split + this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.'); + this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.'); + this.validate_notebook_state('split', 'edit', 1); + this.select_cell(0); // Move up to cell 0 + this.trigger_keydown('shift-m'); // Merge + this.validate_notebook_state('merge', 'command', 0); + this.test.assertEquals(this.get_cell_text(0), 'ab\ncd', 'merge; Verify that cell 0 has the merged contents.'); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/dualmode_movecell.js b/IPython/html/tests/notebook/dualmode_movecell.js new file mode 100644 index 0000000..d2d0fad --- /dev/null +++ b/IPython/html/tests/notebook/dualmode_movecell.js @@ -0,0 +1,25 @@ + +// Test +casper.notebook_test(function () { + var a = 'print("a")'; + var index = this.append_cell(a); + this.execute_cell_then(index); + + var b = 'print("b")'; + index = this.append_cell(b); + this.execute_cell_then(index); + + this.then(function () { + // Cell movement ( ctrl-(k or j) ) + this.select_cell(2); + this.test.assertEquals(this.get_cell_text(2), b, 'select 2; Cell 2 text is correct'); + this.trigger_keydown('ctrl-k'); // Move cell 2 up one + this.test.assertEquals(this.get_cell_text(1), b, 'ctrl-k; Cell 1 text is correct'); + this.test.assertEquals(this.get_cell_text(2), a, 'ctrl-k; Cell 2 text is correct'); + this.validate_notebook_state('ctrl-k', 'command', 1); + this.trigger_keydown('ctrl-j'); // Move cell 1 down one + this.test.assertEquals(this.get_cell_text(1), a, 'ctrl-j; Cell 1 text is correct'); + this.test.assertEquals(this.get_cell_text(2), b, 'ctrl-j; Cell 2 text is correct'); + this.validate_notebook_state('ctrl-j', 'command', 2); + }); +}); \ No newline at end of file diff --git a/IPython/html/tests/notebook/empty_arrow_keys.js b/IPython/html/tests/notebook/empty_arrow_keys.js index 6abed3a..a949ce5 100644 --- a/IPython/html/tests/notebook/empty_arrow_keys.js +++ b/IPython/html/tests/notebook/empty_arrow_keys.js @@ -10,12 +10,12 @@ casper.notebook_test(function () { for (i = 0; i < ncells; i++) { IPython.notebook.delete_cell(); } - - // Simulate the "up arrow" and "down arrow" keys. - // - IPython.keyboard.trigger_keydown('up'); - IPython.keyboard.trigger_keydown('down'); + return true; }); + + // Simulate the "up arrow" and "down arrow" keys. + this.trigger_keydown('up'); + this.trigger_keydown('down'); this.test.assertTrue(result, 'Up/down arrow okay in empty notebook.'); }); diff --git a/IPython/html/tests/notebook/execute_code.js b/IPython/html/tests/notebook/execute_code.js index 1af684f..076d3b7 100644 --- a/IPython/html/tests/notebook/execute_code.js +++ b/IPython/html/tests/notebook/execute_code.js @@ -22,7 +22,11 @@ casper.notebook_test(function () { var cell = IPython.notebook.get_cell(0); cell.set_text('a=11; print(a)'); cell.clear_output(); - IPython.keyboard.trigger_keydown('shift-enter'); + }); + + this.then(function(){ + + this.trigger_keydown('shift-enter'); }); this.wait_for_output(0); @@ -41,7 +45,10 @@ casper.notebook_test(function () { var cell = IPython.notebook.get_cell(0); cell.set_text('a=12; print(a)'); cell.clear_output(); - IPython.keyboard.trigger_keydown('ctrl-enter'); + }); + + this.then(function(){ + this.trigger_keydown('ctrl-enter'); }); this.wait_for_output(0); diff --git a/IPython/html/tests/notebook/interrupt.js b/IPython/html/tests/notebook/interrupt.js index 2bb87f8..7c2912c 100644 --- a/IPython/html/tests/notebook/interrupt.js +++ b/IPython/html/tests/notebook/interrupt.js @@ -31,8 +31,8 @@ casper.notebook_test(function () { }); // interrupt using Ctrl-M I keyboard shortcut - this.thenEvaluate( function() { - IPython.keyboard.trigger_keydown('i'); + this.then(function(){ + this.trigger_keydown('i'); }); this.wait_for_output(0); diff --git a/IPython/html/tests/notebook/merge_cells.js b/IPython/html/tests/notebook/merge_cells_api.js similarity index 54% rename from IPython/html/tests/notebook/merge_cells.js rename to IPython/html/tests/notebook/merge_cells_api.js index 2d85614..9dd2fbd 100644 --- a/IPython/html/tests/notebook/merge_cells.js +++ b/IPython/html/tests/notebook/merge_cells_api.js @@ -2,37 +2,42 @@ // Test merging two notebook cells. // casper.notebook_test(function() { - var output = this.evaluate(function () { - // Fill in test data. - IPython.notebook.command_mode(); - var set_cell_text = function () { + var that = this; + var set_cells_text = function () { + that.evaluate(function() { var cell_one = IPython.notebook.get_selected_cell(); cell_one.set_text('a = 5'); - - IPython.keyboard.trigger_keydown('b'); + }); + + that.trigger_keydown('b'); + + that.evaluate(function() { var cell_two = IPython.notebook.get_selected_cell(); cell_two.set_text('print(a)'); - }; + }); + }; + + this.evaluate(function () { + IPython.notebook.command_mode(); + }); - // merge_cell_above() - set_cell_text(); + // merge_cell_above() + set_cells_text(); + var output_above = this.evaluate(function () { IPython.notebook.merge_cell_above(); - var merged_above = IPython.notebook.get_selected_cell(); + return IPython.notebook.get_selected_cell().get_text(); + }); - // merge_cell_below() - set_cell_text(); + // merge_cell_below() + set_cells_text(); + var output_below = this.evaluate(function() { IPython.notebook.select(0); IPython.notebook.merge_cell_below(); - var merged_below = IPython.notebook.get_selected_cell(); - - return { - above: merged_above.get_text(), - below: merged_below.get_text() - }; + return IPython.notebook.get_selected_cell().get_text(); }); - this.test.assertEquals(output.above, 'a = 5\nprint(a)', + this.test.assertEquals(output_above, 'a = 5\nprint(a)', 'Successful merge_cell_above().'); - this.test.assertEquals(output.below, 'a = 5\nprint(a)', + this.test.assertEquals(output_below, 'a = 5\nprint(a)', 'Successful merge_cell_below().'); }); diff --git a/IPython/html/tests/util.js b/IPython/html/tests/util.js index 8c49dd2..a572190 100644 --- a/IPython/html/tests/util.js +++ b/IPython/html/tests/util.js @@ -2,15 +2,15 @@ // Utility functions for the HTML notebook's CasperJS tests. // -// Get the URL of a notebook server on which to run tests. casper.get_notebook_server = function () { - port = casper.cli.get("port") + // Get the URL of a notebook server on which to run tests. + port = casper.cli.get("port"); port = (typeof port === 'undefined') ? '8888' : port; - return 'http://127.0.0.1:' + port + return 'http://127.0.0.1:' + port; }; -// Create and open a new notebook. casper.open_new_notebook = function () { + // Create and open a new notebook. var baseUrl = this.get_notebook_server(); this.start(baseUrl); this.thenClick('button#new_notebook'); @@ -34,15 +34,15 @@ casper.open_new_notebook = function () { }); }; -// Return whether or not the kernel is running. casper.kernel_running = function kernel_running() { + // Return whether or not the kernel is running. return this.evaluate(function kernel_running() { return IPython.notebook.kernel.running; }); }; -// Shut down the current notebook's kernel. casper.shutdown_current_kernel = function () { + // Shut down the current notebook's kernel. this.thenEvaluate(function() { IPython.notebook.kernel.kill(); }); @@ -50,8 +50,9 @@ casper.shutdown_current_kernel = function () { this.wait(1000); }; -// Delete created notebook. casper.delete_current_notebook = function () { + // Delete created notebook. + // For some unknown reason, this doesn't work?!? this.thenEvaluate(function() { IPython.notebook.delete(); @@ -59,6 +60,7 @@ casper.delete_current_notebook = function () { }; casper.wait_for_busy = function () { + // Waits for the notebook to enter a busy state. this.waitFor(function () { return this.evaluate(function () { return IPython._status == 'busy'; @@ -67,6 +69,7 @@ casper.wait_for_busy = function () { }; casper.wait_for_idle = function () { + // Waits for the notebook to idle. this.waitFor(function () { return this.evaluate(function () { return IPython._status == 'idle'; @@ -74,8 +77,8 @@ casper.wait_for_idle = function () { }); }; -// wait for the nth output in a given cell casper.wait_for_output = function (cell_num, out_num) { + // wait for the nth output in a given cell this.wait_for_idle(); out_num = out_num || 0; this.then(function() { @@ -94,29 +97,29 @@ casper.wait_for_output = function (cell_num, out_num) { }); }; -// wait for a widget msg que to reach 0 -// -// Parameters -// ---------- -// widget_info : object -// Object which contains info related to the widget. The model_id property -// is used to identify the widget. casper.wait_for_widget = function (widget_info) { + // wait for a widget msg que to reach 0 + // + // Parameters + // ---------- + // widget_info : object + // Object which contains info related to the widget. The model_id property + // is used to identify the widget. this.waitFor(function () { var pending = this.evaluate(function (m) { return IPython.notebook.kernel.widget_manager.get_model(m).pending_msgs; }, {m: widget_info.model_id}); - if (pending == 0) { + if (pending === 0) { return true; } else { return false; } }); -} +}; -// return an output of a given cell casper.get_output_cell = function (cell_num, out_num) { + // return an output of a given cell out_num = out_num || 0; var result = casper.evaluate(function (c, o) { var cell = IPython.notebook.get_cell(c); @@ -137,25 +140,33 @@ casper.get_output_cell = function (cell_num, out_num) { } }; -// return the number of cells in the notebook casper.get_cells_length = function () { + // return the number of cells in the notebook var result = casper.evaluate(function () { return IPython.notebook.get_cells().length; - }) + }); return result; }; -// Set the text content of a cell. casper.set_cell_text = function(index, text){ + // Set the text content of a cell. this.evaluate(function (index, text) { var cell = IPython.notebook.get_cell(index); cell.set_text(text); }, index, text); }; -// Inserts a cell at the bottom of the notebook -// Returns the new cell's index. +casper.get_cell_text = function(index){ + // Get the text content of a cell. + return this.evaluate(function (index) { + var cell = IPython.notebook.get_cell(index); + return cell.get_text(); + }, index); +}; + casper.insert_cell_at_bottom = function(cell_type){ + // Inserts a cell at the bottom of the notebook + // Returns the new cell's index. cell_type = cell_type || 'code'; return this.evaluate(function (cell_type) { @@ -164,9 +175,9 @@ casper.insert_cell_at_bottom = function(cell_type){ }, cell_type); }; -// Insert a cell at the bottom of the notebook and set the cells text. -// Returns the new cell's index. casper.append_cell = function(text, cell_type) { + // Insert a cell at the bottom of the notebook and set the cells text. + // Returns the new cell's index. var index = this.insert_cell_at_bottom(cell_type); if (text !== undefined) { this.set_cell_text(index, text); @@ -174,9 +185,9 @@ casper.append_cell = function(text, cell_type) { return index; }; -// Asynchronously executes a cell by index. -// Returns the cell's index. casper.execute_cell = function(index){ + // Asynchronously executes a cell by index. + // Returns the cell's index. var that = this; this.then(function(){ that.evaluate(function (index) { @@ -187,11 +198,11 @@ casper.execute_cell = function(index){ return index; }; -// Synchronously executes a cell by index. -// Optionally accepts a then_callback parameter. then_callback will get called -// when the cell has finished executing. -// Returns the cell's index. casper.execute_cell_then = function(index, then_callback) { + // Synchronously executes a cell by index. + // Optionally accepts a then_callback parameter. then_callback will get called + // when the cell has finished executing. + // Returns the cell's index. var return_val = this.execute_cell(index); this.wait_for_idle(); @@ -206,18 +217,18 @@ casper.execute_cell_then = function(index, then_callback) { return return_val; }; -// Utility function that allows us to easily check if an element exists -// within a cell. Uses JQuery selector to look for the element. casper.cell_element_exists = function(index, selector){ + // Utility function that allows us to easily check if an element exists + // within a cell. Uses JQuery selector to look for the element. return casper.evaluate(function (index, selector) { var $cell = IPython.notebook.get_cell(index).element; return $cell.find(selector).length > 0; }, index, selector); }; -// Utility function that allows us to execute a jQuery function on an -// element within a cell. casper.cell_element_function = function(index, selector, function_name, function_args){ + // Utility function that allows us to execute a jQuery function on an + // element within a cell. return casper.evaluate(function (index, selector, function_name, function_args) { var $cell = IPython.notebook.get_cell(index).element; var $el = $cell.find(selector); @@ -225,8 +236,183 @@ casper.cell_element_function = function(index, selector, function_name, function }, index, selector, function_name, function_args); }; -// Wrap a notebook test to reduce boilerplate. +casper.validate_notebook_state = function(message, mode, cell_index) { + // Validate the entire dual mode state of the notebook. Make sure no more than + // one cell is selected, focused, in edit mode, etc... + + // General tests. + this.test.assertEquals(this.get_keyboard_mode(), this.get_notebook_mode(), + message + '; keyboard and notebook modes match'); + // Is the selected cell the only cell that is selected? + if (cell_index!==undefined) { + this.test.assert(this.is_only_cell_selected(cell_index), + message + '; cell ' + cell_index + ' is the only cell selected'); + } + + // Mode specific tests. + if (mode==='command') { + // Are the notebook and keyboard manager in command mode? + this.test.assertEquals(this.get_keyboard_mode(), 'command', + message + '; in command mode'); + // Make sure there isn't a single cell in edit mode. + this.test.assert(this.is_only_cell_edit(null), + message + '; all cells in command mode'); + this.test.assert(this.is_cell_editor_focused(null), + message + '; no cell editors are focused while in command mode'); + + } else if (mode==='edit') { + // Are the notebook and keyboard manager in edit mode? + this.test.assertEquals(this.get_keyboard_mode(), 'edit', + message + '; in edit mode'); + if (cell_index!==undefined) { + // Is the specified cell the only cell in edit mode? + this.test.assert(this.is_only_cell_edit(cell_index), + message + '; cell ' + cell_index + ' is the only cell in edit mode'); + // Is the specified cell the only cell with a focused code mirror? + this.test.assert(this.is_cell_editor_focused(cell_index), + message + '; cell ' + cell_index + '\'s editor is appropriately focused'); + } + + } else { + this.test.assert(false, message + '; ' + mode + ' is an unknown mode'); + } +}; + +casper.select_cell = function(index) { + // Select a cell in the notebook. + this.evaluate(function (i) { + IPython.notebook.select(i); + }, {i: index}); +}; + +casper.click_cell_editor = function(index) { + // Emulate a click on a cell's editor. + + // Code Mirror does not play nicely with emulated brower events. + // Instead of trying to emulate a click, here we run code similar to + // the code used in Code Mirror that handles the mousedown event on a + // region of codemirror that the user can focus. + this.evaluate(function (i) { + var cm = IPython.notebook.get_cell(i).code_mirror; + if (cm.options.readOnly != "nocursor" && (document.activeElement != cm.display.input)) + cm.display.input.focus(); + }, {i: index}); +}; + +casper.set_cell_editor_cursor = function(index, line_index, char_index) { + // Set the Code Mirror instance cursor's location. + this.evaluate(function (i, l, c) { + IPython.notebook.get_cell(i).code_mirror.setCursor(l, c); + }, {i: index, l: line_index, c: char_index}); +}; + +casper.focus_notebook = function() { + // Focus the notebook div. + this.evaluate(function (){ + $('#notebook').focus(); + }, {}); +}; + +casper.trigger_keydown = function() { + // Emulate a keydown in the notebook. + for (var i = 0; i < arguments.length; i++) { + this.evaluate(function (k) { + var element = $(document); + var event = IPython.keyboard.shortcut_to_event(k, 'keydown'); + element.trigger(event); + }, {k: arguments[i]}); + } +}; + +casper.get_keyboard_mode = function() { + // Get the mode of the keyboard manager. + return this.evaluate(function() { + return IPython.keyboard_manager.mode; + }, {}); +}; + +casper.get_notebook_mode = function() { + // Get the mode of the notebook. + return this.evaluate(function() { + return IPython.notebook.mode; + }, {}); +}; + +casper.get_cell = function(index) { + // Get a single cell. + // + // Note: Handles to DOM elements stored in the cell will be useless once in + // CasperJS context. + return this.evaluate(function(i) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return cell; + } + return null; + }, {i : index}); +}; + +casper.is_cell_editor_focused = function(index) { + // Make sure a cell's editor is the only editor focused on the page. + return this.evaluate(function(i) { + var focused_textarea = $('#notebook .CodeMirror-focused textarea'); + if (focused_textarea.length > 1) { throw 'More than one Code Mirror editor is focused at once!'; } + if (i === null) { + return focused_textarea.length === 0; + } else { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return cell.code_mirror.getInputField() == focused_textarea[0]; + } + } + return false; + }, {i : index}); +}; + +casper.is_only_cell_selected = function(index) { + // Check if a cell is the only cell selected. + // Pass null as the index to check if no cells are selected. + return this.is_only_cell_on(index, 'selected', 'unselected'); +}; + +casper.is_only_cell_edit = function(index) { + // Check if a cell is the only cell in edit mode. + // Pass null as the index to check if all of the cells are in command mode. + return this.is_only_cell_on(index, 'edit_mode', 'command_mode'); +}; + +casper.is_only_cell_on = function(i, on_class, off_class) { + // Check if a cell is the only cell with the `on_class` DOM class applied to it. + // All of the other cells are checked for the `off_class` DOM class. + // Pass null as the index to check if all of the cells have the `off_class`. + var cells_length = this.get_cells_length(); + for (var j = 0; j < cells_length; j++) { + if (j === i) { + if (this.cell_has_class(j, off_class) || !this.cell_has_class(j, on_class)) { + return false; + } + } else { + if (!this.cell_has_class(j, off_class) || this.cell_has_class(j, on_class)) { + return false; + } + } + } + return true; +}; + +casper.cell_has_class = function(index, classes) { + // Check if a cell has a class. + return this.evaluate(function(i, c) { + var cell = IPython.notebook.get_cell(i); + if (cell) { + return cell.element.hasClass(c); + } + return false; + }, {i : index, c: classes}); +}; + casper.notebook_test = function(test) { + // Wrap a notebook test to reduce boilerplate. this.open_new_notebook(); this.then(test); @@ -253,14 +439,14 @@ casper.notebook_test = function(test) { casper.wait_for_dashboard = function () { // Wait for the dashboard list to load. casper.waitForSelector('.list_item'); -} +}; casper.open_dashboard = function () { // Start casper by opening the dashboard page. var baseUrl = this.get_notebook_server(); this.start(baseUrl); this.wait_for_dashboard(); -} +}; casper.dashboard_test = function (test) { // Open the dashboard page and run a test. @@ -276,16 +462,16 @@ casper.dashboard_test = function (test) { this.run(function() { this.test.done(); }); -} +}; -casper.options.waitTimeout=10000 +casper.options.waitTimeout=10000; casper.on('waitFor.timeout', function onWaitForTimeout(timeout) { this.echo("Timeout for " + casper.get_notebook_server()); this.echo("Is the notebook server running?"); }); -// Pass `console.log` calls from page JS to casper. -casper.printLog = function () { +casper.print_log = function () { + // Pass `console.log` calls from page JS to casper. this.on('remote.message', function(msg) { this.echo('Remote message caught: ' + msg); }); diff --git a/IPython/nbconvert/exporters/tests/test_rst.py b/IPython/nbconvert/exporters/tests/test_rst.py index 99e3e76..c9840a9 100644 --- a/IPython/nbconvert/exporters/tests/test_rst.py +++ b/IPython/nbconvert/exporters/tests/test_rst.py @@ -12,6 +12,10 @@ # Imports #----------------------------------------------------------------------------- +import io + +from IPython.nbformat import current + from .base import ExportersTestsBase from ..rst import RSTExporter from IPython.testing.decorators import onlyif_cmds_exist @@ -40,3 +44,22 @@ class TestRSTExporter(ExportersTestsBase): """ (output, resources) = RSTExporter().from_filename(self._get_notebook()) assert len(output) > 0 + + @onlyif_cmds_exist('pandoc') + def test_empty_code_cell(self): + """No empty code cells in rst""" + nbname = self._get_notebook() + with io.open(nbname, encoding='utf8') as f: + nb = current.read(f, 'json') + + exporter = self.exporter_class() + + (output, resources) = exporter.from_notebook_node(nb) + # add an empty code cell + nb.worksheets[0].cells.append( + current.new_code_cell(input="") + ) + (output2, resources) = exporter.from_notebook_node(nb) + # adding an empty code cell shouldn't change output + self.assertEqual(output.strip(), output2.strip()) + diff --git a/IPython/nbconvert/templates/rst.tpl b/IPython/nbconvert/templates/rst.tpl index fdabe2a..1dc7f69 100644 --- a/IPython/nbconvert/templates/rst.tpl +++ b/IPython/nbconvert/templates/rst.tpl @@ -8,7 +8,7 @@ {% endblock output_prompt %} {% block input %} -{%- if not cell.input.isspace() -%} +{%- if cell.input.strip() -%} .. code:: python {{ cell.input | indent}} diff --git a/IPython/parallel/tests/test_client.py b/IPython/parallel/tests/test_client.py index 11d7480..06aefd3 100644 --- a/IPython/parallel/tests/test_client.py +++ b/IPython/parallel/tests/test_client.py @@ -522,19 +522,23 @@ class TestClient(ClusterTestCase): def test_spin_thread(self): self.client.spin_thread(0.01) ar = self.client[-1].apply_async(lambda : 1) - time.sleep(0.1) - self.assertTrue(ar.wall_time < 0.1, - "spin should have kept wall_time < 0.1, but got %f" % ar.wall_time - ) + md = self.client.metadata[ar.msg_ids[0]] + # 3s timeout, 100ms poll + for i in range(30): + time.sleep(0.1) + if md['received'] is not None: + break + self.assertIsInstance(md['received'], datetime) def test_stop_spin_thread(self): self.client.spin_thread(0.01) self.client.stop_spin_thread() ar = self.client[-1].apply_async(lambda : 1) - time.sleep(0.15) - self.assertTrue(ar.wall_time > 0.1, - "Shouldn't be spinning, but got wall_time=%f" % ar.wall_time - ) + md = self.client.metadata[ar.msg_ids[0]] + # 500ms timeout, 100ms poll + for i in range(5): + time.sleep(0.1) + self.assertIsNone(md['received'], None) def test_activate(self): ip = get_ipython() diff --git a/IPython/utils/sysinfo.py b/IPython/utils/sysinfo.py index a61c764..003eca4 100644 --- a/IPython/utils/sysinfo.py +++ b/IPython/utils/sysinfo.py @@ -82,7 +82,6 @@ def pkg_info(pkg_path): return dict( ipython_version=release.version, ipython_path=pkg_path, - codename=release.codename, commit_source=src, commit_hash=hsh, sys_version=sys.version, diff --git a/MANIFEST.in b/MANIFEST.in index d34b8e9..57a79d0 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ include README.rst -include COPYING.txt +include COPYING.rst include setupbase.py include setupegg.py diff --git a/docs/source/_templates/htmlnotebook.html b/docs/source/_templates/notebook_redirect.html similarity index 55% rename from docs/source/_templates/htmlnotebook.html rename to docs/source/_templates/notebook_redirect.html index 7133e91..0114404 100644 --- a/docs/source/_templates/htmlnotebook.html +++ b/docs/source/_templates/notebook_redirect.html @@ -1,9 +1,9 @@ - - Notebook page has move - + + Notebook docs have moved + -

The notebook page has moved to this link.

+

The notebook docs have moved here.

diff --git a/docs/source/conf.py b/docs/source/conf.py index 381c3f6..7113048 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -95,8 +95,7 @@ numpydoc_class_members_toctree = False # other places throughout the built documents. # # The full version, including alpha/beta/rc tags. -codename = iprelease['codename'] -release = "%s: %s" % (iprelease['version'], codename) +release = "%s" % iprelease['version'] # Just the X.Y.Z part, no '-dev' version = iprelease['version'].split('-', 1)[0] @@ -164,7 +163,10 @@ html_last_updated_fmt = '%b %d, %Y' # Additional templates that should be rendered to pages, maps page names to # template names. html_additional_pages = { - 'interactive/htmlnotebook': 'htmlnotebook.html', + 'interactive/htmlnotebook': 'notebook_redirect.html', + 'interactive/notebook': 'notebook_redirect.html', + 'interactive/nbconvert': 'notebook_redirect.html', + 'interactive/public_server': 'notebook_redirect.html', } # If false, no module index is generated. diff --git a/docs/source/config/extensions/octavemagic.rst b/docs/source/config/extensions/octavemagic.rst index a13330f..d563ad4 100644 --- a/docs/source/config/extensions/octavemagic.rst +++ b/docs/source/config/extensions/octavemagic.rst @@ -4,4 +4,9 @@ octavemagic =========== +.. note:: + + The octavemagic extension has been moved to `oct2py `_ + as :mod:`oct2py.ipython`. + .. automodule:: IPython.extensions.octavemagic diff --git a/docs/source/config/extensions/rmagic.rst b/docs/source/config/extensions/rmagic.rst index 5e4e2e5..77104f2 100644 --- a/docs/source/config/extensions/rmagic.rst +++ b/docs/source/config/extensions/rmagic.rst @@ -4,4 +4,9 @@ rmagic =========== +.. note:: + + The rmagic extension has been moved to `rpy2 `_ + as :mod:`rpy2.interactive.ipython`. + .. automodule:: IPython.extensions.rmagic diff --git a/docs/source/development/gitwash/branch_list.png b/docs/source/development/gitwash/branch_list.png deleted file mode 100644 index 1196eb754d361dbb2e53a25745f913c2f0cdb83e..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@?mlOoI<>3Lr|!M0 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 C_-JPU diff --git a/docs/source/development/gitwash/branch_list_compare.png b/docs/source/development/gitwash/branch_list_compare.png deleted file mode 100644 index 336afa3746040f118c073e7d02a5843bc8eed152..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@in~jpXmL2WySux)6nFQ79^By+cXx;4?hcpt{r>;1t21k6 zGCNsGR+4A0=Sg8L0!3{f>s zbolWDYw%0_C&c?dcWy^X!Uuw2C!y{L0fB`1&jSgOo{9GX!Z}IGh{7$yz`|lNWkal^ zLO^_hko@^W*=_lB&D{&r`R(CyflV@j&DsNkKbIa$!>lae%O<455E*<#>zCYSDS*5d zF1D(?-KB=YBf@&FvWgmps6RHA=A&W^Q2x^=I+zF|`bp@6I1ZUd!K=pCOH=pm@!W^-N}xdJP%H~dTZxt71Jn-gM}xhX9JC&G@X0a& zo=re1_?~2>aAn7+9NvDY_IF(+yq^HMO^GMojTGWe^!4{PVw z{QXzyR&sDgx1#VKaCJF;m}Mbeu(bz21)NR(4Er&YxPnusJT-7F8%FU@IhE~9-HV&H zk7>u$O1a|0KcQ5{zw*1HEX}VwF+p8S@i6fiSUaK=16X}KwIQ9Xu@P1!$#^;YVI4)^- z{^FKZJ*_`_kul==(kzZh4&7;N

UNgpM}lH-E^?^HdokGszXhsicM*lxgEWe98^ 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 diff --git a/docs/source/development/gitwash/configure_git.rst b/docs/source/development/gitwash/configure_git.rst deleted file mode 100644 index 260898d..0000000 --- a/docs/source/development/gitwash/configure_git.rst +++ /dev/null @@ -1,89 +0,0 @@ -.. _configure-git: - -=============== - Configure git -=============== - -.. _git-config-basic: - -Overview -======== - -:: - - git config --global user.email you@yourdomain.example.com - git config --global user.name "Your Name Comes Here" - - -In detail -========= - -This is to tell git_ who you are, for labeling any changes you make to -the code. The simplest way to do this is from the command line:: - - git config --global user.email you@yourdomain.example.com - git config --global user.name "Your Name Comes Here" - -This will write the settings into your git configuration file - a file -called ``.gitconfig`` in your home directory. - -Advanced git configuration -========================== - -You might well benefit from some aliases to common commands. - -For example, you might well want to be able to shorten ``git checkout`` to ``git co``. - -The easiest way to do this, is to create a ``.gitconfig`` file in your -home directory, with contents like this:: - - [core] - editor = emacs - [user] - email = you@yourdomain.example.com - name = Your Name Comes Here - [alias] - st = status - stat = status - co = checkout - [color] - diff = auto - status = true - -(of course you'll need to set your email and name, and may want to set -your editor). If you prefer, you can do the same thing from the command -line:: - - git config --global core.editor emacs - git config --global user.email you@yourdomain.example.com - git config --global user.name "Your Name Comes Here" - git config --global alias.st status - git config --global alias.stat status - git config --global alias.co checkout - git config --global color.diff auto - git config --global color.status true - -These commands will write to your user's git configuration file -``~/.gitconfig``. - -To set up on another computer, you can copy your ``~/.gitconfig`` file, -or run the commands above. - -Other configuration recommended by Yarik -======================================== - -In your ``~/.gitconfig`` file alias section:: - - wdiff = diff --color-words - -so that ``git wdiff`` gives a nicely formatted output of the diff. - -To enforce summaries when doing merges(``~/.gitconfig`` file again):: - - [merge] - summary = true - - -.. include:: git_links.txt - - diff --git a/docs/source/development/gitwash/development_workflow.rst b/docs/source/development/gitwash/development_workflow.rst deleted file mode 100644 index 00b8412..0000000 --- a/docs/source/development/gitwash/development_workflow.rst +++ /dev/null @@ -1,232 +0,0 @@ -.. _development-workflow: - -==================== -Development workflow -==================== - -You already have your own forked copy of the ipython_ repository, by -following :ref:`forking`, :ref:`set-up-fork`, and you have configured -git_ by following :ref:`configure-git`. - -Workflow summary -================ - -* Keep your ``master`` branch clean of edits that have not been merged - to the main ipython_ development repo. Your ``master`` then will follow - the main ipython_ repository. -* Start a new *feature branch* for each set of edits that you do. -* If you can avoid it, try not to merge other branches into your feature - branch while you are working. -* Ask for review! - -This way of working really helps to keep work well organized, and in -keeping history as clear as possible. - -See - for example - `linux git workflow`_. - -Making a new feature branch -=========================== - -:: - - git branch my-new-feature - git checkout my-new-feature - -Generally, you will want to keep this also on your public github_ fork -of ipython_. To do this, you `git push`_ this new branch up to your github_ -repo. Generally (if you followed the instructions in these pages, and -by default), git will have a link to your github_ repo, called -``origin``. You push up to your own repo on github_ with:: - - git push origin my-new-feature - -From now on git_ will know that ``my-new-feature`` is related to the -``my-new-feature`` branch in the github_ repo. - -The editing workflow -==================== - -Overview --------- - -:: - - # hack hack - git add my_new_file - git commit -am 'NF - some message' - git push - -In more detail --------------- - -#. Make some changes -#. See which files have changed with ``git status`` (see `git status`_). - You'll see a listing like this one:: - - # On branch ny-new-feature - # Changed but not updated: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: README - # - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # INSTALL - no changes added to commit (use "git add" and/or "git commit -a") - -#. Check what the actual changes are with ``git diff`` (`git diff`_). -#. Add any new files to version control ``git add new_file_name`` (see - `git add`_). -#. To commit all modified files into the local copy of your repo,, do - ``git commit -am 'A commit message'``. Note the ``-am`` options to - ``commit``. The ``m`` flag just signals that you're going to type a - message on the command line. The ``a`` flag - you can just take on - faith - or see `why the -a flag?`_. See also the `git commit`_ manual - page. -#. To push the changes up to your forked repo on github_, do a ``git - push`` (see `git push`). - -Asking for code review -====================== - -#. Go to your repo URL - e.g. ``http://github.com/your-user-name/ipython``. -#. Click on the *Branch list* button: - - .. image:: branch_list.png - -#. Click on the *Compare* button for your feature branch - here ``my-new-feature``: - - .. image:: branch_list_compare.png - -#. If asked, select the *base* and *comparison* branch names you want to - compare. Usually these will be ``master`` and ``my-new-feature`` - (where that is your feature branch name). -#. At this point you should get a nice summary of the changes. Copy the - URL for this, and post it to the `ipython mailing list`_, asking for - review. The URL will look something like: - ``http://github.com/your-user-name/ipython/compare/master...my-new-feature``. - There's an example at - http://github.com/matthew-brett/nipy/compare/master...find-install-data - See: http://github.com/blog/612-introducing-github-compare-view for - more detail. - -The generated comparison, is between your feature branch -``my-new-feature``, and the place in ``master`` from which you branched -``my-new-feature``. In other words, you can keep updating ``master`` -without interfering with the output from the comparison. More detail? -Note the three dots in the URL above (``master...my-new-feature``). - -Asking for your changes to be merged with the main repo -======================================================= - -When you are ready to ask for the merge of your code: - -#. Go to the URL of your forked repo, say - ``http://github.com/your-user-name/ipython.git``. -#. Click on the 'Pull request' button: - - .. image:: pull_button.png - - Enter a message; we suggest you select only ``ipython`` as the - recipient. The message will go to the `ipython mailing list`_. Please - feel free to add others from the list as you like. - -Merging from trunk -================== - -This updates your code from the upstream `ipython github`_ repo. - -Overview --------- - -:: - - # go to your master branch - git checkout master - # pull changes from github - git fetch upstream - # merge from upstream - git merge upstream/master - -In detail ---------- - -We suggest that you do this only for your ``master`` branch, and leave -your 'feature' branches unmerged, to keep their history as clean as -possible. This makes code review easier:: - - git checkout master - -Make sure you have done :ref:`linking-to-upstream`. - -Merge the upstream code into your current development by first pulling -the upstream repo to a copy on your local machine:: - - git fetch upstream - -then merging into your current branch:: - - git merge upstream/master - -Deleting a branch on github_ -============================ - -:: - - git checkout master - # delete branch locally - git branch -D my-unwanted-branch - # delete branch on github - git push origin :my-unwanted-branch - -(Note the colon ``:`` before ``test-branch``. See also: -http://github.com/guides/remove-a-remote-branch - -Several people sharing a single repository -========================================== - -If you want to work on some stuff with other people, where you are all -committing into the same repository, or even the same branch, then just -share it via github_. - -First fork ipython into your account, as from :ref:`forking`. - -Then, go to your forked repository github page, say -``http://github.com/your-user-name/ipython`` - -Click on the 'Admin' button, and add anyone else to the repo as a -collaborator: - - .. image:: pull_button.png - -Now all those people can do:: - - git clone git@githhub.com:your-user-name/ipython.git - -Remember that links starting with ``git@`` use the ssh protocol and are -read-write; links starting with ``git://`` are read-only. - -Your collaborators can then commit directly into that repo with the -usual:: - - git commit -am 'ENH - much better code' - git push origin master # pushes directly into your repo - -Exploring your repository -========================= - -To see a graphical representation of the repository branches and -commits:: - - gitk --all - -To see a linear list of commits for this branch:: - - git log - -You can also look at the `network graph visualizer`_ for your github_ -repo. - -.. include:: git_links.txt diff --git a/docs/source/development/gitwash/following_latest.rst b/docs/source/development/gitwash/following_latest.rst deleted file mode 100644 index 475e092..0000000 --- a/docs/source/development/gitwash/following_latest.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _following-latest: - -============================= - Following the latest source -============================= - -These are the instructions if you just want to follow the latest -*ipython* source, but you don't need to do any development for now. - -The steps are: - -* :ref:`install-git` -* get local copy of the git repository from github_ -* update local copy from time to time - -Get the local copy of the code -============================== - -From the command line:: - - git clone git://github.com/ipython/ipython.git - -You now have a copy of the code tree in the new ``ipython`` directory. - -Updating the code -================= - -From time to time you may want to pull down the latest code. Do this with:: - - cd ipython - git pull - -The tree in ``ipython`` will now have the latest changes from the initial -repository. - -.. include:: git_links.txt diff --git a/docs/source/development/gitwash/forking_button.png b/docs/source/development/gitwash/forking_button.png deleted file mode 100644 index d0e04134d4d086d0c78c45188848c4a0b71b157d..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@Jtv zkc=!G5D*d&8F3LcchF0HXfL(Fr!QBo%*_V*PzabH1sMG}N*FARAZSHUVz{yu6!-wG z?*JI;w<2n?01R(GBVi9{(m7J$GJob;EyNnmuQa|Fqygc zKjTArX-`P zkd-y@#SiP_vXo3TgOVb zozy}V`ZRr_W^d1^r>FOYo81}eK@%?xv4P`*8T^iG8Y3n#*Zn+4N5^($&>~k?uSIVp zYE(gttS;uaJ9JY)y>X4>Oh7y5=gHK`%DSI&)k(#*1&9HW+7XoWOT6-?*Ar}*Lme3( z@2~jV6>&J83f~?-=e*fni_K&J@xGt$in4PR+#bZ|Ob1-<%MR4Vy|}_Km28{f=(U#` zF=I`eJo41gSd8vZXS1xank5rqPNY(lYJS;BB&7 z58-h>g7Li&U}LNA%Q^j9Dc0@t$?T(^zvyKCNKR`12x%95cugOOs~L0A69aIho<7g8 zyk6ftAI^Tv*^JU^vQ1awW@m5EljE}AqykGp*e~!^$5$m<>Rc!OG&F>+I+%LX(=SFt zM~5GpI@7B&gJor99UBz3()ESRePD_a={DZ4y)tup)o0TiXjilUkS)m#>OcRSb@=#$ z#(iKs-%fEx*%8|H#WA(Pnri49U8JF~T``Agf2sjl_2-}}sJLR*s>Zk7T+HIGfbcs_ZA zj%D|O%ehAM4h`zj0Wq`oA>6qBS$_9W{*zgwlQ@~juM%QNLaJ!~^yad8d+%(q0*B24 z;qBp6)#xzAA{z(sRn#%JNq=_Bu;VS&jg8pgU% zLF^MSBTzBB)Eae|`j#Vgh!Eg2Ht_Z+TLuGd1B%3H^~*#o-#b?r&~}rEN$9W2(tfkG z@U-&1FDzXZ6SL4)pYUc-X^A-!m1xh>@bhXsnNAZTmn;)OL_{Qw!v<@mQg%i(Y56P`|!t@cxq(PqkqU^4m>eNV%$a;qhTmCkdB4!p;nf%M!0?;%RB zx*HfMA9n2ii~*w~&wFD}E3}em>&Q++?*R3)skHk;YO_oIkk$JBIPpcUGj^1HsxGko zt8}eu3%jbGcX%D6CHzg4?(Dls)cZycGlZ=SW~_xGlqRNJ|C>Nh$JGkbp&wb{j-LUS zG#u~LvMo#ntoxf?Gzx=N(5QIo~eoT1ox!J)Q#9?>NtQ^9_z z{kL9K;?V1@?7#;LafRV8@yK+c9)0RkKQxOAU4C?%>CK)%(-Kp?YrlfYjYT(CYv0}g zNT8DwnjY;%QZ^)~Yl#1-+Sl2I>?(y_=ze#7Zs3B+;41~wZt|frcdAj4?uO`(&7VCD z4no54=0s1QZmgUuA*NgH5<^s+nrArKu*9%!yYsJx1;vY^+*G^s(7C+^cAUZxb}e

24g z0A8lXMxMXFu5DDnqaw<_PzvRnx2dt!_uMnyuUn}7FWgVcuc)cmKa8}2z6yey$bVwXH z5<#0J+#U}(&yW(fKV?bOsWOAv+YUpJ>0OFB>{Q_X6?L`87W}j&1{3w%1$E$*5uNRH z2Bb|f3_(b?kOFRwR=UCjYT&LXkV3_2r|Jd*M^C=LxYe6LpkKL(XV|0IE zLPI9pCWppgQW$Owy>5er8*EujZgYLVcqkRJs8O7>8P?djP&@^2XO%;1neOW1CN&Si zbnV#_ObU!#9YfK>1wKvaO{&ZCfxjpP%Jphw_JBr~+)tOQk&|>9qye(B8BoIIu|ra( zLK5zh)PiX&n8>n!Y#3}KA2POuDdU-I0FaLJAc^soNUn;=iBiw zK^RKt2g*$20qSHv{c2tfCfK6Gow4QU9y{VIscAo)24;M z%pjU+s;_gZBV=RCE8~|x5U4Atp0)Ye?8oZzWOXoqoJJm*FTrFINPzQQ(EL6zWy4gq zuG5NG>K%&+(Ke+wc*JdMJr?;s7Nnm7NZ7uTZh7OA}`miUPhr zN%%AHZy(8{cQo6*-sr1U8N)*n@&hIFjx&fIB_APjJUbW|8D0`p@b=$>iStuSi3Hkm zC1WZgqA0|WpDklWpb&j(M^Q#w^#b?CN(x-{^KQoDp1}J&W_N-x=Ufed>(r5D)TVX}vE+QYDECwiul8G7k zFk;x#`;sY0W%V$6n6ke7G~v=3Y8ng!O(da!H#kbedSEOj%v-R}l#PoG6B3uxuow#* zI-+k#ZMesHU{VdGA<%EeW9(cvS~#D-z3}DDi)Y0V=!1LIFDRAxGoTd|AR!nL+aMkA znVfianYQtmHcaG+;P3CR)#g%e97t)>vh%}xu9?JEKmnVS$Goak`P&7o+zSl%Nvb{R$qpM2C>uIYlqVG6IGB`BIPMb zkyQ5M{I-G_jfeP3HAYMHbAXy4y>SX9ZW@%+378o9>=4i9C)?C;}4XI#-nJ#z`132 z*dmy4@HtzcdAQnqZ-T5g+s=8nM;r>K4a?JtfH+FZ7B5C)R~s>AJI@=X@~tY>k`=|G zP(}vBe?_f5%U}9w#CRj8lrtV#!*gbh0Q+ZEo>I3)8`y%m;`!T={b2FJK2R#Ac1Xna~kls?&(ETuZkkHD@bdp`DEGcPk0-KoH5u+a3_cz9|a z=d;Ml>xCVe{46PNb^qE()PXHv^S(9(&U3{)kAtslQ5j&zn3aB%7|YGl#+=Y8(}9{t zM&+-{*1_fjHeo6EQdi+eBQj=A+?IFvm& zaL~QZy#o!0;OKaCC*@vEm!SA~a#>8FJRZ-2i;Bp5tAHObjs${UI2W{vva%6zLwfK? zeZRD5V|dL45tU;vg3sx;hoTyHx$8_>1a%*=%PpvhtgZ|u;LOb7xaK$;PG|puJVU<= z1Tg9koEo2VVqA{G{@y<`6!m!CozAxeurbbZ!A`O$F-V%ohf^X^nX>H?&!l;v1h>LB z?L7En;s{=Gbnu^3BS1nh84RPr%9SPjq$b23ZXr-)aa+xe@iG@!72-_FmiG~XyV!O# zf=;zfoh?_TB8_P!)Y8V1t?E~xq)a3#;cvW&#V%ju8F6+1(-2#jo4!5oorf_Lz&=ka zEpvup5JDj3B`|TGCyPnkWrWR++Fb7rLGGN+Y`{owKxS&3RCx%FNWveh7*?K%AHK~N z7>{%=f>p#r&W4;*7)I`m{@7KWCf;K7(@2aYkQa=C>Wg>TS+4P3>3)Om1v76WtHm-j zh&&_aFqrA;&5>7FYGKqweBl(MiWuk3g)s-}_STFv(V(oof{r*4^cEbh=h@Am>RTbC zrcU+0nNrofWqt=ZcA`vB)>+F4u5%e}-wM3!o&!lUp4_drG$g>MLs*)@<X9JsI6O8{ZJ$Q5yJ+;HUOm>}}#!fL`}%by=}{>5DI-aRJrh zFQ2-SPIMZ5qaz~vjwUmMJ^sCAq81j^28M^>ub{ASv9LmJZf@$nIoRIA!xIO>=?BO> z&2_~(>TkRoiUC8f#2u08bP6D(g|)6uh9-LOdN8zZtaY{&NL&J7Z+r8W>nNE)#=BEy z#?UI4fsBQH$GN@+(zsmqdLl7%dvIuxU2())sYB#Yckr1E0q}i4pnuXg5Zv(cs=np? zCN_QBB5>lwgyM>zTDBJfo*0TibhglGA5Kt-q|N&7B?^xEX6@cHV|lS)ZIx>79a;_> zO@&DFKTT1&(;kR?Z2KCbjC`HTsMe5ugeWPz+`tUln1&_%b?6;Vv>&jDHnh&o(5D*TP62x&L>i~hgWhkR2C`GGP&LHsk~n3t>_6@w^IhI z|Ml0gr2NjprHo|r`VgQ&uKzK@A#8VeXl0a0M^ajq9ngVuMnH%FB|w<7dau&jp|_^N z*V;cHtusEJ-=*{&@mM@SBI_kDCnqK?EginHXGj-#d;YiEK*{RyY_Tu7ykMZ-=}^{R zSoUp|FnB;v4t{7S%u=yj6ih59JcZG+?M~_oQm3*3kKu<|@^25+aGd+RDO1e`ILB$y z4a}<^`4T;hs3+V(t8GnO%P$P-6d2DimwpP@GDIvG{lwto-#jFm4QZzAQ~R{C(j?(a7KGxWdAvEUk*vJsb5gh4 zkW{|b%BX{-(RndRf~w|`-D^j}ea~2lp^EX__i={Ns(xT&-(Y`e_46$LrB0Dc3*AY9 zjN~z##|c53T|G&ztB9nIR@FjC@WH9bom#>azExXDm@Q~KwSpL~m}s>ReF3Yf=)xde5<8cFbABqIvFhOCd+8hdI+ zbB)^J7Oje&hMYOG#k0z)|LWiFFIsv7+vOfCR!K>rj~j4)>$-aGqqf$1VQ4N^i^ckE ziQlTXQ$N4kxtY7GL`8x`pv~yH&5lkGbvLvLJbAI)U0>X#M7UefV6S4vG}Xcg6JSGq zUA(8S-cTc$2^X^myP*~R%`ReBxbhjC8f6y2||mW8RVHn~}rWP~-ekz8k0D-1UM}>i4eCaN537 z&cpR&!`Q#K{8c9n-xl5fSR;u%FV#IkLUv-T|1oN13=rI>OIUXu`v1^81+pHQW`&4s zij=ma81;&9s4Kz@Bb+%QK16sR&9Sd z?Rd=)fc`ffC(2HWy_nesK5 zZ*rZx3WrzyfnNXUz4eX#4)iPGg5?BvtbXV`%0_{p+0z|w72eNiETF4@qCSs}d`=31 zcy4%~d?fUTTJT%3e8kY;ipxmHr!t93CX(avG%3r!t&b1CIy=_5zxVbh`QIO-=an5p zn~#o`$T3YE<6PKrAMKnx1v0b4gv2@!X|ddUsrcSD`kRE@hn2zV1Da*MURQw36zL1|pS-B1T88t4A`t~$GdREbG6#z)D& z4vsP83Z5|P6WR+MXeO(%9aetuwE@w?P#9@(LZS0n4b(;Y0p7kpsR^A=G-=?LjQh_o zLWmYC$q(MR7*Pf&iv1+#w2h{2tb!5<*)R6LROa@Uo7C`*=L9F~Z`v_i#=iNbN{sU( z<*Xv}C##vH@o>z2+47|`dno72j3N!`EW!e*u6!!k>rZN=txaOd`K zfo`7M<>-7?c$IFG@cItTgnK)*EhQf5WG22KWo z7<8%loWHco9a68+I?G4bA*;dJ0xmhIR>TiZ{XUj4H;oalf>wkh6`#3W7a*dml)LFz zJyG28alaKN9e1+@XA`;GFx7lcKmcv>AO3h(Cqz!ppE0w90u|Jew6N7t6F)Buzrc|w zBJNbFF_>|z93%K67!cofJD1=4>!T8UsdU@`Xu410aXBu+rpSFWG1J@S^#yfq2L?dL z(w_qQJCb7tEv_01YIY^~j<)kitfV;uc^X@OETG0h*OYyBe!JIRer`GE@I^TTeKq%S zGk$s*4-&pY;2Kpt(4~B$Ck|1IG7W4VF`p3IKKF=S1>M@JRC$&F3KfNqnD6Y7GUbVE z>7^V-dth8=!B;f3}~PByuTg9$y0{X#J{u`NlVKxB%DQ zV$eFVtl<`+{#J?22E!>RX0n14=;BcPEfkEZA zGlKRH8;r->k+Ara^*+s!1Rco?762NZX7(WXbTsK8hFx<~*mmvLPw)=TKiGO@4UCWc zoPXcJSyu6=`SJ4K_Z4^Jk^DtF{qRtAmrRdW&34-oBp8ZoTHBl=RCw=j@a3FJne*vN2gO0O#Nw1Op20l7>WhK3T_9gD{@p|qdp5B(< z$lg6v`8%|h%uTcRC(GPVhme7CL8usC!VvB4-HGZ?rDsBLP-qxAeEymDQx-KvfsABw!#^31qd)8WBom+dx*k^?=?zF=p8Z^LSWT#P-Xju| zMs0>uyjzk=ik;xt?KcSnLj=HBIfIRqhmGdf>_pq73a3uyX^GMBopo160>*nsCzBJY z;`|x#nS@twC0tzUNtpIoW5n_EJ#HvEp2Ydm9)G*vW*et98NriPpUu*XYs=lK6{uH0 zac5yg+ccA(6xEQvzhN4?ssGJEJ7tNNPIV1xpNvZCu7*o%wA)4YUSlCxam6D1{v>W- z4o@i$i${b?*mS_}kH20OB(RNUyx+~hX`vga;Q9MdlSU4h?bB$XCwz&=ANWbqMJB^SRKzUsG(DKb5idlx!yE_^A-svTI2Ae=rusBxCjCU7lPQk(5+>BJQ~Bc)&UKq$%E!VxrK)}fnsG#yqfFqC z8A+hE4n{raurQF)5Ea}|t7a}G>R*=QMBVks`>rXSS);%W|E+g%qyNdCXf7%)h2A&zHL(R_eJw|x44FLuxi+qQ z^SK5tt^TX;h6OOwxWzyK@LI~9B&%2ms(h%Io^}JAkA#iK$B#_4g^ZU&QICeEqPj)Y zEa!^=gicfwQ9P}vko1}gmixU?ie`4GwWF0|(zTf-;io=0iSfgM-oyk!$^fEZ`bV@S zuWpc9c0(hXzKlWqaHZrEE*I{Q2SiCU2Dr%OZ2x3y+)KukDZ{`>Ys#P}UkLeV%i4S4 zA0n5jOP@;CzwuP}fzd^aRcZ-e7CG(>$T-~0-Iu%To%I_)!Fz4i>qaA!;Q=O$97ds>r3lQ>yH zO;)8~l1h2AGWr)|z}~zX4)2|^J5D0}9nW^jvyNVSrN8qt)yxkI5y5QTo?;G4`P^s+ z?1{d@22HAKP@j}0%;6nbnt|%A9v>(PpKT^RVwc7f5xswssX(n?2{Z^g#(diW za?3;R@_m&g`0O-XK}$IVw+J5Zy0cZf&Owu_!i26NH2Mvqa&oG)7uiLJ8j`-87BaI) z8Ya$^hwQs2F`Y@I7{tEMcwi$9oKF`4gwB>EAF2aTvE9)!fx0NIxHF71nBUDt_)iigg z#(xI#o=f+_@oKM$KtRyO{`(6c$%*s0Y1IBk>S}h_v$_c>6Z#B@=Di(QpTAXu*HMEO z2-@79?CBz>^jv!?!J%VNtTzB?1&at4nL;5>FtfN*rx|gsuq2M<73fV^GR4dM^DXas zN?^z~Bcf&fD+`$z^$H|9<#gGtuR?^+3xMjMEDr_;n8`Q>?rQV=8-Q>{u}?IFGobisqGU;Up)1k9M`h zjT^@VQhsr*fiZuWueGl775x+f%k2{7)1-A4_`tFy>bxBd1?<{!^v)Cue!ZE&enoT# z8%JMAru~5~@nMGhO4_OlhZoFk#toe|Cu7$lP%4x%7=9O9@3UZu@31ghofSW56@dDT zu6v!7un_KQJ%b4^{KOY-gXYYeW6=`wWPO6*6sy3poBcImV})51w1pyWU0YmY&6F}v z4a=8_TPWT4l>A+Yjt!_RB5!830;9P%R`vkYuw+|V4DOGI6O+_v%Qc*?Ku#-O#DZYM z-dVTX(a#7mBcugQ#Pwp5x&v#6#Hzo|SLwScbaL=iTs=dRmF2My@*e4_AXz@#D)t~Nq?c(~c_ zqe$*iHS^EVyI+IZ@>tFz-|P{=DK$T4w^h5b=i!q2?09y;~IN zT8-2{!t6MK)ToT3v{cv)U1~T1ryvWU{s3oXd)EP;9EBgJ*0s&jS=Pg;(B2elz@*Q1 zMa{dv33fDUfI?k(!LG-VV+3-8FjC6`NKP(Zgb7m!1edFM$SDiLx>3a4Sx0ip_o3aH zH^Vrf0OY95sVKu2`{dyi+2EpQUM9EZNmIfo00P;=Ry0TlnqqxP#Y*DBhU17-$|kR$ z{S5k&dQp-Jf*qk~VeWPEkGVHPIAcZChte;(RE>o`qd;e2Vy`y?I&lJlnEGSJorhib zxAhoCz;@pbXD3aSM7eb=Eqt+c;b<>Cf9B_2+(3b3Ny=J&KXf8Ztj14A3M8)@J}`!A zC48&CFB>#US5m{R+WoMIt{|cPQwLSkj+?K@yx>Y^X&ALRz@9Fg8gip)i7UCsTGuJV zzq>UqX~tHsivtJ2r8L`2P`4HlrOF5(ox#dgcT5fJpEIB22BKy*>-7MebcEYaBEo zo`@|fGKqQF)q8EpH|hE!$W(&zEyW;C9d_1A4qH}k8Q4*PObgN>mdcyPrWPU!;uajU zj00c#Vf262$zf9{k0@{F^C|U?pSdPK6Gmw_8yv6fKoIpm8Bd-CHCCF5t1Nc!yh@og0Il zgOLny2{@_R4HM7Uv?rM7US&wJIQ#sf!h5;~jH~1hYkKXxf^yUz3(tylnXP_C@aBky zvbU>b>=l*h}Md?W<##GO)*y0Tgp#WvU z)Q_S;++g?g+jklr73Ye`4hvviK6iKtTC|CM>ga<)tAeWMVGs!KK_uh-{rHMbA73>n*%AoiR~N-cFI9#QFRxG2nVj*&wTq8U`i?&Y^BS&Mw5z2Xj4#cYs=Yr-u+xZ znH#N<3Et2%zac(61z^A5uB;Tg`UTEuL}w96eOPgvq(`+NF|^u61=yzoz%kwrEPrd^ z-IsnQ7f4EjHwBk+Zz6t3z~|9r_moNuD}zwHzI^wzVKKfn0+egk9i=D@Io`@bcRsn6v^`q z;?ARspVu<14@8=pM!Lz5C$_0j%$p*(96)JaFCQH{5sh6c@h=IRV?*+Ee~ zB`Kxa`Lz)E_DMpkw<^&YAY<f^r&zbc;6%b`9g485=Rvzs-p)5lUffA-kmkL?S<6< zj!&op>$}Z7>!WiiAz|i}>?4_H&{c7s8f*OOE!n|U{qKI*x(Eoi@uP?){d2K|T4?y@ ztbs=SWzipv!^7B!nUgLkSmAJmX^FaVP`GW#E7hU!kL_ zVcSJq0R4N{BvnxbaHQ`2T|I1kYG_dvzh<`sYi!B|O%Z`^WHBr7e8Bn#vn>T<1C4Bf zqgz+*YCGcl_Xqg<(`A1(qLAs=8h~98x#Qt%pM4DKWL6tePb)aL-!yO58Wq2bNNSG4 zYNZfgO@mkX#>T(I^%B;4IjoWpQ-{->3v$G5rM13hkyWFY_;9VLP-#0n*Qc-ifZ)U_ zvBqW*>R{I7#p-WKTmo@cypx_9f&GB~z?7kd={LjA33qhdR}FTn^$1F5D2RapJxZp+p zzjKg{v^?KLR35HZ(uGaC1x$^jB8guq2mdNij06wz9@XrhQd@B*5^K&zVfm3w>`Qm( zDyAOctaQVk4olFdJ+dhb8c zM&+LLk>JXvyF7{X8)>u)I$>%MwL?|$;C@Ek^kH(Jh?rj9xk@9HT0 zf|OBjcCm*4L(V2A$_Hj4!d{ek!HDfEGVoR$22?wr#{_tAh?w4^xbR5a78hw3(;^h` zpU0p}-y^Ha7_yUsv->Z~RW8>|TOo{n5xa(bhXn7M3{ElR4jjx9lCoLP9;Zv)EN1{e zp1|)D!bw|>;jNA(Qt-4605UFlUAjq=%&r%vS`Bx|A9n)vKpF_a zC>o}jQyRPM#{(*}6twjap#?#|Gm{kk-+QPPWig7G@_IRoETOgSK&uo}ZD-Iz0Te;@Ww0;H9ICZ5?v9$DdDUb4ib0k>%EEXxBR|! zLr;SbFcy#p4yT>S?4u7!D?(;Y9)O!~r}x#dkKmcS(23PrtYX>fJax{H=pJ|o3Bd|{ z6pbKXMjyRb@87Il_ZGp%9-XYNLJm(G^n66?v)q>tvplgNYJ8!_P;3XoAA*l2CuS7n z1**9{5U&zzYG^9t-1!~3UO+-UxioLa@8B z08%T5*AhyZmD~#@fY*b`x88%+hv<&{^w| z6WWdTc@n#`59nILf(CwM3Cf2~(1e>yXE%Dp_?+_eiE4FiQLG>UN+S&{SJGM zD<2w(mJ`W@BW)mffC}Ms^FOL&rP_eTI-GWfg#pFI>k{jjKw;|sde#fM z=II}8HSki>x%jdWRA|PFTYwuCm~DF+EQQ`-=X^CxI8wmUzacIl4I0Uh%0w zwwUsQl9k7DqI3SKto|@Q!ldlpvn=-T3v1G(IC0TSp78+*J{cpBKzAl_dTMkM8g#3n zm5g;#Iq_STn%Y0IlxgEYd_h|~U|izrNJhvtu3w9pl7`>Qd&hQeN26NAHs;`TU#>d| z?GD8k?o>y1Ini(lHpPn}%7Uuw1H4DvWNaL@S=+^kGXLC7Bbd&sL)}GgAb=ntxxSQ2 z+f9d8y5NpIeHD2fgVuMKWI`5#gyL{%V=N%u9#>5vNBAyx{N~dAsOB=5*v60Kpcn>ICi-T6qyGX+pP zYv@Sw+DV7MZUEdQA(m@2)JF(Xz8aJ00e!!~eDKNYk6Cu#g@otKakRDj#4_zkBOp2( zzRU_qRmLoSip_g=$iBb%e9H8o!C_V|IaZg4!%ay40(;WA82!{wA#EN`^E!a%?`(Wd z+k8yeL(r8k#;l_9{A&K+oQ;4ORt?q(r@L^?r0}%Q-Pk-Ewig#+l5B1&gSW@?!PoKzz2qoovf+j#%ADw?X3BbRCI=>6 zgN!63;WC_8&`8~~7z>J|DIeUSGmiN)UHTc3biI~tDSpKw7u`02`l~n4iDF{Ys8<(S zJKlTvia6fc>*@5=;G_f?tulRYR73g=*|9f@9BT@(C3)UOCVI!|&QTaQSFs++$S|1~ z`P0oSGX09e3TYMIxZ1Q6?!Rf$T6hdlX7O6m&{_#e+9u?Dp~ehjiEnauU6+=r$w^f7 z)>`k2tVS!I?)lk~zygMtj5R8Fg}Aa&>X-9d^3bV=%n;cX zAGJnA3Y>(|4u)3|9~TG*wTl&;V5fdoyKEd}gf!Jg=Feezh)x;f!R9Bte^`j%yS2gR z#T<;@c7(~a(GN-KTG==0+ATylC}%t6xR zsPr^aK+VW(s?~0+oifYhm+Z?=E5YCx<%x#6`MCFSHYc5b(e|N{t7)WYpT?{lM8*Rh zJ{=HjE@h$N3)C5woE&^~;DAh)D(W`N)^f5z7UUIAPp>_5R=4%&j5bR@X~^}S^pmI# z9c!2)U4mrC(Ca`Da2N5p6r@DX3@!$Onyy{FYv3PpDHWkH7H<)7e{}zxHx!SWQr8L_ z`!k3x&{C5I~{xllltY#Q9m#CPnARi}7h-@(0 zo1&e?rv|GW@HB^xT96Wv6q*&qx|K(scktPTp0nLc;+k`H?0eolb#12?yYR`0M9p=l z9%|a@?p{>@67@ejV$B=`x(9WWU!-w^ zH-GZ~azcO*VK&Joz diff --git a/docs/source/development/gitwash/forking_hell.rst b/docs/source/development/gitwash/forking_hell.rst deleted file mode 100644 index dab481a..0000000 --- a/docs/source/development/gitwash/forking_hell.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. _forking: - -========================================== -Making your own copy (fork) of ipython -========================================== - -You need to do this only once. The instructions here are very similar -to the instructions at http://help.github.com/forking/ - please see that -page for more detail. We're repeating some of it here just to give the -specifics for the ipython_ project, and to suggest some default names. - -Set up and configure a github_ account -====================================== - -If you don't have a github_ account, go to the github_ page, and make one. - -You then need to configure your account to allow write access - see the -``Generating SSH keys`` help on `github help`_. - -Create your own forked copy of ipython_ -========================================= - -#. Log into your github_ account. -#. Go to the ipython_ github home at `ipython github`_. -#. Click on the *fork* button: - - .. image:: forking_button.png - - Now, after a short pause and some 'Hardcore forking action', you - should find yourself at the home page for your own forked copy of ipython_. - -.. include:: git_links.txt - diff --git a/docs/source/development/gitwash/git_development.rst b/docs/source/development/gitwash/git_development.rst deleted file mode 100644 index 64522c6..0000000 --- a/docs/source/development/gitwash/git_development.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. _git-development: - -===================== - Git for development -===================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - forking_hell - set_up_fork - configure_git - development_workflow - diff --git a/docs/source/development/gitwash/git_install.rst b/docs/source/development/gitwash/git_install.rst deleted file mode 100644 index 6c6a57c..0000000 --- a/docs/source/development/gitwash/git_install.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. _install-git: - -============= - Install git -============= - -Overview -======== - -================ ============= -Debian / Ubuntu ``sudo apt-get install git-core`` -Fedora ``sudo yum install git-core`` -Windows Download and install msysGit_ -OS X Use the git-osx-installer_ -================ ============= - -In detail -========= - -See the git_ page for the most recent information. - -Have a look at the github_ install help pages available from `github help`_ - -There are good instructions here: http://book.git-scm.com/2_installing_git.html - -.. include:: git_links.txt diff --git a/docs/source/development/gitwash/git_links.txt b/docs/source/development/gitwash/git_links.txt deleted file mode 100644 index 16e27d2..0000000 --- a/docs/source/development/gitwash/git_links.txt +++ /dev/null @@ -1,67 +0,0 @@ -.. This (-*- rst -*-) format file contains commonly used link targets - and name substitutions. It may be included in many files, - therefore it should only contain link targets and name - substitutions. Try grepping for "^\.\. _" to find plausible - candidates for this list. - -.. NOTE: reST targets are - __not_case_sensitive__, so only one target definition is needed for - nipy, NIPY, Nipy, etc... - -.. PROJECTNAME placeholders -.. _PROJECTNAME: http://neuroimaging.scipy.org -.. _`PROJECTNAME github`: http://github.com/nipy -.. _`PROJECTNAME mailing list`: http://projects.scipy.org/mailman/listinfo/nipy-devel - -.. nipy -.. _nipy: http://nipy.org/nipy -.. _`nipy github`: http://github.com/nipy/nipy -.. _`nipy mailing list`: http://mail.scipy.org/mailman/listinfo/nipy-devel - -.. ipython -.. _ipython: http://ipython.org -.. _`ipython github`: http://github.com/ipython/ipython -.. _`ipython mailing list`: http://mail.scipy.org/mailman/listinfo/IPython-dev - -.. nipy -.. _dipy: http://nipy.org/dipy -.. _`dipy github`: http://github.com/Garyfallidis/dipy -.. _`dipy mailing list`: http://mail.scipy.org/mailman/listinfo/nipy-devel - -.. git stuff -.. _git: http://git-scm.com/ -.. _github: http://github.com -.. _github help: http://help.github.com -.. _msysgit: http://code.google.com/p/msysgit/downloads/list -.. _git-osx-installer: http://code.google.com/p/git-osx-installer/downloads/list -.. _subversion: http://subversion.tigris.org/ -.. _git cheat sheet: http://github.com/guides/git-cheat-sheet -.. _pro git book: http://progit.org/ -.. _git svn crash course: http://git-scm.com/course/svn.html -.. _learn.github: http://learn.github.com/ -.. _network graph visualizer: http://github.com/blog/39-say-hello-to-the-network-graph-visualizer -.. _git user manual: http://www.kernel.org/pub/software/scm/git/docs/user-manual.html -.. _git tutorial: http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html -.. _git community book: http://book.git-scm.com/ -.. _git ready: http://www.gitready.com/ -.. _git casts: http://www.gitcasts.com/ -.. _Fernando's git page: http://www.fperez.org/py4science/git.html -.. _git magic: http://www-cs-students.stanford.edu/~blynn/gitmagic/index.html -.. _git concepts: http://www.eecs.harvard.edu/~cduan/technical/git/ -.. _git clone: http://www.kernel.org/pub/software/scm/git/docs/git-clone.html -.. _git checkout: http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html -.. _git commit: http://www.kernel.org/pub/software/scm/git/docs/git-commit.html -.. _git push: http://www.kernel.org/pub/software/scm/git/docs/git-push.html -.. _git pull: http://www.kernel.org/pub/software/scm/git/docs/git-pull.html -.. _git add: http://www.kernel.org/pub/software/scm/git/docs/git-add.html -.. _git status: http://www.kernel.org/pub/software/scm/git/docs/git-status.html -.. _git diff: http://www.kernel.org/pub/software/scm/git/docs/git-diff.html -.. _git log: http://www.kernel.org/pub/software/scm/git/docs/git-log.html -.. _git branch: http://www.kernel.org/pub/software/scm/git/docs/git-branch.html -.. _git remote: http://www.kernel.org/pub/software/scm/git/docs/git-remote.html -.. _git config: http://www.kernel.org/pub/software/scm/git/docs/git-config.html -.. _why the -a flag?: http://www.gitready.com/beginner/2009/01/18/the-staging-area.html -.. _git staging area: http://www.gitready.com/beginner/2009/01/18/the-staging-area.html -.. _git management: http://kerneltrap.org/Linux/Git_Management -.. _linux git workflow: http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html -.. _git parable: http://tom.preston-werner.com/2009/05/19/the-git-parable.html diff --git a/docs/source/development/gitwash/git_resources.rst b/docs/source/development/gitwash/git_resources.rst deleted file mode 100644 index 69e344e..0000000 --- a/docs/source/development/gitwash/git_resources.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. _git-resources: - -================ - git_ resources -================ - -Tutorials and summaries -======================= - -* `github help`_ has an excellent series of how-to guides. -* `learn.github`_ has an excellent series of tutorials -* The `pro git book`_ is a good in-depth book on git. -* A `git cheat sheet`_ is a page giving summaries of common commands. -* The `git user manual`_ -* The `git tutorial`_ -* The `git community book`_ -* `git ready`_ - a nice series of tutorials -* `git casts`_ - video snippets giving git how-tos. -* `git magic`_ - extended introduction with intermediate detail -* Fernando Perez' git page - `Fernando's git page`_ - many links and tips -* A good but technical page on `git concepts`_ -* Th `git parable`_ is an easy read explaining the concepts behind git. -* `git svn crash course`_: git_ for those of us used to subversion_ - -Advanced git workflow -===================== - -There are many ways of working with git_; here are some posts on the -rules of thumb that other projects have come up with: - -* Linus Torvalds on `git management`_ -* Linus Torvalds on `linux git workflow`_ . Summary; use the git tools - to make the history of your edits as clean as possible; merge from - upstream edits as little as possible in branches where you are doing - active development. - -Manual pages online -=================== - -You can get these on your own machine with (e.g) ``git help push`` or -(same thing) ``git push --help``, but, for convenience, here are the -online manual pages for some common commands: - -* `git add`_ -* `git branch`_ -* `git checkout`_ -* `git clone`_ -* `git commit`_ -* `git config`_ -* `git diff`_ -* `git log`_ -* `git pull`_ -* `git push`_ -* `git remote`_ -* `git status`_ - -.. include:: git_links.txt diff --git a/docs/source/development/gitwash/index.rst b/docs/source/development/gitwash/index.rst deleted file mode 100644 index f3bb40e..0000000 --- a/docs/source/development/gitwash/index.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _using-git: - -Working with IPython source code -================================ - -These pages describe a git_ and github_ workflow for the IPython_ project. - -There are several different workflows here, for different ways of -working with IPython. - -This is not a comprehensive git_ reference, it's just a workflow for our -own project. It's tailored to the github_ hosting service. You may well -find better or quicker ways of getting stuff done with git, but these -should get you started. - -For general resources for learning git_ see :ref:`git-resources`. - - -Contents: - -.. toctree:: - :maxdepth: 2 - - git_install - following_latest - patching - git_development - git_resources - -.. include:: git_links.txt diff --git a/docs/source/development/gitwash/patching.rst b/docs/source/development/gitwash/patching.rst deleted file mode 100644 index 9053db6..0000000 --- a/docs/source/development/gitwash/patching.rst +++ /dev/null @@ -1,123 +0,0 @@ -================ - Making a patch -================ - -You've discovered a bug or something else you want to change in ipython_ - excellent! - -You've worked out a way to fix it - even better! - -You want to tell us about it - best of all! - -The easiest way is to make a *patch* or set of patches. Here we explain -how. Making a patch is the simplest and quickest, but if you're going -to be doing anything more than simple quick things, please consider -following the :ref:`git-development` model instead. - -.. _making-patches: - -Making patches -============== - -Overview --------- - -:: - - # tell git who you are - git config --global user.email you@yourdomain.example.com - git config --global user.name "Your Name Comes Here" - # get the repository if you don't have it - git clone git://github.com/ipython/ipython.git - # make a branch for your patching - cd ipython - git branch the-fix-im-thinking-of - git checkout the-fix-im-thinking-of - # hack, hack, hack - # Tell git about any new files you've made - git add somewhere/tests/test_my_bug.py - # commit work in progress as you go - git commit -am 'BF - added tests for Funny bug' - # hack hack, hack - git commit -am 'BF - added fix for Funny bug' - # make the patch files - git format-patch -M -C master - -Then, send the generated patch files to the `ipython mailing list`_ - where we will thank you warmly. - -In detail ---------- - -#. Tell git_ who you are so it can label the commits you've made:: - - git config --global user.email you@yourdomain.example.com - git config --global user.name "Your Name Comes Here" - -#. If you don't already have one, clone a copy of the ipython_ repository:: - - git clone git://github.com/ipython/ipython.git - cd ipython - -#. Make a 'feature branch'. This will be where you work on your bug - fix. It's nice and safe and leaves you with access to an unmodified - copy of the code in the main branch:: - - git branch the-fix-im-thinking-of - git checkout the-fix-im-thinking-of - -#. Do some edits, and commit them as you go:: - - # hack, hack, hack - # Tell git about any new files you've made - git add somewhere/tests/test_my_bug.py - # commit work in progress as you go - git commit -am 'BF - added tests for Funny bug' - # hack hack, hack - git commit -am 'BF - added fix for Funny bug' - - Note the ``-am`` options to ``commit``. The ``m`` flag just signals - that you're going to type a message on the command line. The ``a`` - flag - you can just take on faith - or see `why the -a flag?`_. - -#. When you have finished, check you have committed all your changes:: - - git status - -#. Finally, make your commits into patches. You want all the commits - since you branched from the ``master`` branch:: - - git format-patch -M -C master - - You will now have several files named for the commits:: - - 0001-BF-added-tests-for-Funny-bug.patch - 0002-BF-added-fix-for-Funny-bug.patch - - Send these files to the `ipython mailing list`_. - -When you are done, to switch back to the main copy of the code, just -return to the ``master`` branch:: - - git checkout master - -Moving from patching to development -=================================== - -If you find you have done some patches, and you have one or more feature -branches, you will probably want to switch to development mode. You can -do this with the repository you have. - -Fork the ipython_ repository on github_ - :ref:`forking`. Then:: - - # checkout and refresh master branch from main repo - git checkout master - git pull origin master - # rename pointer to main repository to 'upstream' - git remote rename origin upstream - # point your repo to default read / write to your fork on github - git remote add origin git@github.com:your-user-name/ipython.git - # push up any branches you've made and want to keep - git push origin the-fix-im-thinking-of - -Then you can, if you want, follow the :ref:`development-workflow`. - -.. include:: git_links.txt diff --git a/docs/source/development/gitwash/pull_button.png b/docs/source/development/gitwash/pull_button.png deleted file mode 100644 index e5031681b97bcc3b323a01653153c8d6bcfb5507..0000000000000000000000000000000000000000 GIT binary patch literal 0 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 diff --git a/docs/source/development/gitwash/set_up_fork.rst b/docs/source/development/gitwash/set_up_fork.rst deleted file mode 100644 index 2ae413a..0000000 --- a/docs/source/development/gitwash/set_up_fork.rst +++ /dev/null @@ -1,68 +0,0 @@ -.. _set-up-fork: - -================== - Set up your fork -================== - -First you follow the instructions for :ref:`forking`. - -Overview -======== - -:: - - git clone git@github.com:your-user-name/ipython.git - cd ipython - git remote add upstream git://github.com/ipython/ipython.git - -In detail -========= - -Clone your fork ---------------- - -#. Clone your fork to the local computer with ``git clone - git@github.com:your-user-name/ipython.git`` -#. Investigate. Change directory to your new repo: ``cd ipython``. Then - ``git branch -a`` to show you all branches. You'll get something - like:: - - * master - remotes/origin/master - - This tells you that you are currently on the ``master`` branch, and - that you also have a ``remote`` connection to ``origin/master``. - What remote repository is ``remote/origin``? Try ``git remote -v`` to - see the URLs for the remote. They will point to your github_ fork. - - Now you want to connect to the upstream `ipython github`_ repository, so - you can merge in changes from trunk. - -.. _linking-to-upstream: - -Linking your repository to the upstream repo --------------------------------------------- - -:: - - cd ipython - git remote add upstream git://github.com/ipython/ipython.git - -``upstream`` here is just the arbitrary name we're using to refer to the -main ipython_ repository at `ipython github`_. - -Note that we've used ``git://`` for the URL rather than ``git@``. The -``git://`` URL is read only. This means we that we can't accidentally -(or deliberately) write to the upstream repo, and we are only going to -use it to merge into our own code. - -Just for your own satisfaction, show yourself that you now have a new -'remote', with ``git remote -v show``, giving you something like:: - - upstream git://github.com/ipython/ipython.git (fetch) - upstream git://github.com/ipython/ipython.git (push) - origin git@github.com:your-user-name/ipython.git (fetch) - origin git@github.com:your-user-name/ipython.git (push) - -.. include:: git_links.txt - diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index c8a7142..533fc03 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -19,8 +19,6 @@ on the IPython GitHub wiki. .. toctree:: :maxdepth: 1 - - gitwash/index messaging parallel_messages parallel_connections diff --git a/docs/source/index.rst b/docs/source/index.rst index 2ddf644..72fc197 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -25,6 +25,7 @@ Contents whatsnew/index install/index interactive/index + notebook/index parallel/index config/index development/index diff --git a/docs/source/interactive/index.rst b/docs/source/interactive/index.rst index fd24a05..9a4ecdf 100644 --- a/docs/source/interactive/index.rst +++ b/docs/source/interactive/index.rst @@ -10,9 +10,7 @@ Using IPython for interactive work reference shell qtconsole - notebook - cm_keyboard - nbconvert - public_server +.. seealso:: + :doc:`/notebook/index` diff --git a/docs/source/interactive/cm_keyboard.rst b/docs/source/notebook/cm_keyboard.rst similarity index 100% rename from docs/source/interactive/cm_keyboard.rst rename to docs/source/notebook/cm_keyboard.rst diff --git a/docs/source/notebook/index.rst b/docs/source/notebook/index.rst new file mode 100644 index 0000000..2191fda --- /dev/null +++ b/docs/source/notebook/index.rst @@ -0,0 +1,13 @@ +==================== +The IPython notebook +==================== + +.. toctree:: + :maxdepth: 2 + + notebook + cm_keyboard + nbconvert + public_server + security + diff --git a/docs/source/notebook/ipython_security.asc b/docs/source/notebook/ipython_security.asc new file mode 100644 index 0000000..9543681 --- /dev/null +++ b/docs/source/notebook/ipython_security.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.22 (GNU/Linux) + +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 +5vmLc+Ibz+eT+rM= +=XVDe +-----END PGP PUBLIC KEY BLOCK----- diff --git a/docs/source/interactive/nbconvert.rst b/docs/source/notebook/nbconvert.rst similarity index 100% rename from docs/source/interactive/nbconvert.rst rename to docs/source/notebook/nbconvert.rst diff --git a/docs/source/interactive/notebook.rst b/docs/source/notebook/notebook.rst similarity index 100% rename from docs/source/interactive/notebook.rst rename to docs/source/notebook/notebook.rst diff --git a/docs/source/interactive/public_server.rst b/docs/source/notebook/public_server.rst similarity index 98% rename from docs/source/interactive/public_server.rst rename to docs/source/notebook/public_server.rst index aae62c8..9454cd0 100644 --- a/docs/source/interactive/public_server.rst +++ b/docs/source/notebook/public_server.rst @@ -19,8 +19,8 @@ a public interface `. .. _notebook_security: -Notebook security ------------------ +Securing a notebook server +-------------------------- You can protect your notebook server with a simple single password by setting the :attr:`NotebookApp.password` configurable. You can prepare a diff --git a/docs/source/notebook/security.rst b/docs/source/notebook/security.rst new file mode 100644 index 0000000..fa68579 --- /dev/null +++ b/docs/source/notebook/security.rst @@ -0,0 +1,146 @@ +Security in IPython notebooks +============================= + +As IPython notebooks become more popular for sharing and collaboration, +the potential for malicious people to attempt to exploit the notebook +for their nefarious purposes increases. IPython 2.0 introduces a +security model to prevent execution of untrusted code without explicit +user input. + +The problem +----------- + +The whole point of IPython is arbitrary code execution. We have no +desire to limit what can be done with a notebook, which would negatively +impact its utility. + +Unlike other programs, an IPython notebook document includes output. +Unlike other documents, that output exists in a context that can execute +code (via Javascript). + +The security problem we need to solve is that no code should execute +just because a user has **opened** a notebook that **they did not +write**. Like any other program, once a user decides to execute code in +a notebook, it is considered trusted, and should be allowed to do +anything. + +Our security model +------------------ + +- Untrusted HTML is always sanitized +- Untrusted Javascript is never executed +- HTML and Javascript in Markdown cells are never trusted +- **Outputs** generated by the user are trusted +- Any other HTML or Javascript (in Markdown cells, output generated by + others) is never trusted +- The central question of trust is "Did the current user do this?" + +The details of trust +-------------------- + +IPython notebooks store a signature in metadata, which is used to answer +the question "Did the current user do this?" + +This signature is a digest of the notebooks contents plus a secret key, +known only to the user. The secret key is a user-only readable file in +the IPython profile's security directory. By default, this is:: + + ~/.ipython/profile_default/security/notebook_secret + +When a notebook is opened by a user, the server computes a signature +with the user's key, and compares it with the signature stored in the +notebook's metadata. If the signature matches, HTML and Javascript +output in the notebook will be trusted at load, otherwise it will be +untrusted. + +Any output generated during an interactive session is trusted. + +Updating trust +************** + +A notebook's trust is updated when the notebook is saved. If there are +any untrusted outputs still in the notebook, the notebook will not be +trusted, and no signature will be stored. If all untrusted outputs have +been removed (either via ``Clear Output`` or re-execution), then the +notebook will become trusted. + +While trust is updated per output, this is only for the duration of a +single session. A notebook file on disk is either trusted or not in its +entirety. + +Explicit trust +************** + +Sometimes re-executing a notebook to generate trusted output is not an +option, either because dependencies are unavailable, or it would take a +long time. Users can explicitly trust a notebook in two ways: + +- At the command-line, with:: + + ipython trust /path/to/notebook.ipynb + +- After loading the untrusted notebook, with ``File / Trust Notebook`` + +These two methods simply load the notebook, compute a new signature with +the user's key, and then store the newly signed notebook. + +Reporting security issues +------------------------- + +If you find a security vulnerability in IPython, either a failure of the +code to properly implement the model described here, or a failure of the +model itself, please report it to security@ipython.org. + +If you prefer to encrypt your security reports, +you can use :download:`this PGP public key `. + +Affected use cases +------------------ + +Some use cases that work in IPython 1.0 will become less convenient in +2.0 as a result of the security changes. We do our best to minimize +these annoyance, but security is always at odds with convenience. + +Javascript and CSS in Markdown cells +************************************ + +While never officially supported, it had become common practice to put +hidden Javascript or CSS styling in Markdown cells, so that they would +not be visible on the page. Since Markdown cells are now sanitized (by +`Google Caja `__), all Javascript +(including click event handlers, etc.) and CSS will be stripped. + +We plan to provide a mechanism for notebook themes, but in the meantime +styling the notebook can only be done via either ``custom.css`` or CSS +in HTML output. The latter only have an effect if the notebook is +trusted, because otherwise the output will be sanitized just like +Markdown. + +Collaboration +************* + +When collaborating on a notebook, people probably want to see the +outputs produced by their colleagues' most recent executions. Since each +collaborator's key will differ, this will result in each share starting +in an untrusted state. There are three basic approaches to this: + +- re-run notebooks when you get them (not always viable) +- explicitly trust notebooks via ``ipython trust`` or the notebook menu + (annoying, but easy) +- share a notebook secret, and use an IPython profile dedicated to the + collaboration while working on the project. + +Multiple profiles or machines +***************************** + +Since the notebook secret is stored in a profile directory by default, +opening a notebook with a different profile or on a different machine +will result in a different key, and thus be untrusted. The only current +way to address this is by sharing the notebook secret. This can be +facilitated by setting the configurable: + +.. sourcecode:: python + + c.NotebookApp.secret_file = "/path/to/notebook_secret" + +in each profile, and only sharing the secret once per machine. diff --git a/docs/source/parallel/dag_dependencies.rst b/docs/source/parallel/dag_dependencies.rst index 719913c..9d03b28 100644 --- a/docs/source/parallel/dag_dependencies.rst +++ b/docs/source/parallel/dag_dependencies.rst @@ -58,9 +58,9 @@ The code to generate the simple DAG: .. sourcecode:: python import networkx as nx - + G = nx.DiGraph() - + # add 5 nodes, labeled 0-4: map(G.add_node, range(5)) # 1,2 depend on 0: @@ -71,7 +71,7 @@ The code to generate the simple DAG: G.add_edge(2,3) # 4 depends on 1 G.add_edge(1,4) - + # now draw the graph: pos = { 0 : (0,0), 1 : (1,1), 2 : (-1,1), 3 : (0,2), 4 : (2,2)} @@ -96,11 +96,11 @@ Now, we need to build our dict of jobs corresponding to the nodes on the graph: .. sourcecode:: ipython In [3]: jobs = {} - + # in reality, each job would presumably be different # randomwait is just a function that sleeps for a random interval In [4]: for node in G: - ...: jobs[node] = randomwait + ...: jobs[node] = randomwait Once we have a dict of jobs matching the nodes on the graph, we can start submitting jobs, and linking up the dependencies. Since we don't know a job's msg_id until it is submitted, @@ -114,10 +114,10 @@ on which it depends: In [5]: rc = Client() In [5]: view = rc.load_balanced_view() - + In [6]: results = {} - - In [7]: for node in G.topological_sort(): + + In [7]: for node in nx.topological_sort(G): ...: # get list of AsyncResult objects from nodes ...: # leading into this one as dependencies ...: deps = [ results[n] for n in G.predecessors(node) ] @@ -152,18 +152,18 @@ will be at the top, and quick, small tasks will be at the bottom. .. sourcecode:: ipython In [10]: from matplotlib.dates import date2num - + In [11]: from matplotlib.cm import gist_rainbow - + In [12]: pos = {}; colors = {} - + In [12]: for node in G: ....: md = results[node].metadata ....: start = date2num(md.started) ....: runtime = date2num(md.completed) - start ....: pos[node] = (start, runtime) ....: colors[node] = md.engine_id - + In [13]: nx.draw(G, pos, node_list=colors.keys(), node_color=colors.values(), ....: cmap=gist_rainbow) diff --git a/docs/source/whatsnew/development.rst b/docs/source/whatsnew/development.rst index c7db774..0f60025 100644 --- a/docs/source/whatsnew/development.rst +++ b/docs/source/whatsnew/development.rst @@ -191,6 +191,13 @@ Dashboard "Running" Tab The dashboard now has a "Running" tab which shows all of the running notebooks. +Interactive Notebook Tour +------------------------- + +Familiarize yourself with the updated notebook user interface, including an +explanation of Edit and Command modes, by going through the short guided tour +which can be started from the Help menu. + Other changes ------------- diff --git a/docs/source/whatsnew/pr/notebook-tour.rst b/docs/source/whatsnew/pr/notebook-tour.rst deleted file mode 100644 index 9ffaf41..0000000 --- a/docs/source/whatsnew/pr/notebook-tour.rst +++ /dev/null @@ -1,6 +0,0 @@ -Interactive Notebook Tour -------------------------- - -Familiarize yourself with the updated notebook user interface, including an -explanation of Edit and Command modes, by going through the short guided tour -which can be started from the Help menu. diff --git a/setup.py b/setup.py index 07ea5a5..7ef9289 100755 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ requires utilities which are not available under Windows.""" # # Distributed under the terms of the Modified BSD License. # -# The full license is in the file COPYING.txt, distributed with this software. +# The full license is in the file COPYING.rst, distributed with this software. #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- diff --git a/setupbase.py b/setupbase.py index 1d474e4..21a2857 100644 --- a/setupbase.py +++ b/setupbase.py @@ -161,6 +161,7 @@ def find_package_data(): pjoin(components, "jquery", "jquery.min.js"), pjoin(components, "jquery-ui", "ui", "minified", "jquery-ui.min.js"), pjoin(components, "jquery-ui", "themes", "smoothness", "jquery-ui.min.css"), + pjoin(components, "jquery-ui", "themes", "smoothness", "images", "*"), pjoin(components, "marked", "lib", "marked.js"), pjoin(components, "requirejs", "require.js"), pjoin(components, "underscore", "underscore-min.js"), diff --git a/tools/gh_api.py b/tools/gh_api.py index b2b048b..9d2a756 100644 --- a/tools/gh_api.py +++ b/tools/gh_api.py @@ -142,7 +142,7 @@ def get_pulls_list(project, auth=False, **params): headers = make_auth_header() else: headers = None - pages = get_paged_request(url, headers=headers, params=params) + pages = get_paged_request(url, headers=headers, **params) return pages def get_issues_list(project, auth=False, **params): diff --git a/tools/github_stats.py b/tools/github_stats.py index fdbcd90..97ffdb2 100755 --- a/tools/github_stats.py +++ b/tools/github_stats.py @@ -1,5 +1,9 @@ #!/usr/bin/env python """Simple tools to query github.com and gather stats about issues. + +To generate a report for IPython 2.0, run: + + python github_stats.py --milestone 2.0 --since-tag rel-1.0.0 """ #----------------------------------------------------------------------------- # Imports @@ -7,14 +11,18 @@ from __future__ import print_function +import codecs import json import re import sys +from argparse import ArgumentParser from datetime import datetime, timedelta from subprocess import check_output -from gh_api import get_paged_request, make_auth_header, get_pull_request, is_pull_request - +from gh_api import ( + get_paged_request, make_auth_header, get_pull_request, is_pull_request, + get_milestone_id, get_issues_list, +) #----------------------------------------------------------------------------- # Globals #----------------------------------------------------------------------------- @@ -26,12 +34,6 @@ PER_PAGE = 100 # Functions #----------------------------------------------------------------------------- -def get_issues(project="ipython/ipython", state="closed", pulls=False): - """Get a list of the issues from the Github API.""" - which = 'pulls' if pulls else 'issues' - url = "https://api.github.com/repos/%s/%s?state=%s&per_page=%i" % (project, which, state, PER_PAGE) - return get_paged_request(url, headers=make_auth_header()) - def round_hour(dt): return dt.replace(minute=0,second=0,microsecond=0) @@ -42,7 +44,6 @@ def _parse_datetime(s): else: return datetime.fromtimestamp(0) - def issues2dict(issues): """Convert a list of issues to a dict, keyed by issue number.""" idict = {} @@ -63,7 +64,6 @@ def split_pulls(all_issues, project="ipython/ipython"): return issues, pulls - def issues_closed_since(period=timedelta(days=365), project="ipython/ipython", pulls=False): """Get all issues closed since a particular point in time. period can either be a datetime object, or a timedelta object. In the @@ -114,23 +114,31 @@ def report(issues, show_urls=False): if __name__ == "__main__": # deal with unicode - import codecs sys.stdout = codecs.getwriter('utf8')(sys.stdout) # Whether to add reST urls for all issues in printout. show_urls = True - - # By default, search one month back - tag = None - if len(sys.argv) > 1: - try: - days = int(sys.argv[1]) - except: - tag = sys.argv[1] - else: - tag = check_output(['git', 'describe', '--abbrev=0']).strip() - if tag: + parser = ArgumentParser() + parser.add_argument('--since-tag', type=str, + help="The git tag to use for the starting point (typically the last major release)." + ) + parser.add_argument('--milestone', type=str, + help="The GitHub milestone to use for filtering issues [optional]." + ) + parser.add_argument('--days', type=int, + help="The number of days of data to summarize (use this or --since-tag)." + ) + + opts = parser.parse_args() + tag = opts.since_tag + + # set `since` from days or git tag + if opts.days: + since = datetime.utcnow() - timedelta(days=opts.days) + else: + if not tag: + tag = check_output(['git', 'describe', '--abbrev=0']).strip() cmd = ['git', 'log', '-1', '--format=%ai', tag] tagday, tz = check_output(cmd).strip().rsplit(' ', 1) since = datetime.strptime(tagday, "%Y-%m-%d %H:%M:%S") @@ -141,16 +149,23 @@ if __name__ == "__main__": since += td else: since -= td - else: - since = datetime.utcnow() - timedelta(days=days) since = round_hour(since) - - print("fetching GitHub stats since %s (tag: %s)" % (since, tag), file=sys.stderr) - # turn off to play interactively without redownloading, use %run -i - if 1: + + milestone = opts.milestone + + print("fetching GitHub stats since %s (tag: %s, milestone: %s)" % (since, tag, milestone), file=sys.stderr) + if milestone: + milestone_id = get_milestone_id("ipython/ipython", milestone, + auth=True) + issues = get_issues_list("ipython/ipython", + milestone=milestone_id, + state='closed', + auth=True, + ) + else: issues = issues_closed_since(since, pulls=False) - pulls = issues_closed_since(since, pulls=True) + pulls = issues_closed_since(since, pulls=True) # For regular reports, it's nice to show them in reverse chronological order issues = sorted_by_field(issues, reverse=True)