##// END OF EJS Templates
Merge remote-tracking branch 'upstream/master'
Nathan Heijermans -
r19284:8d2b1c3b merge
parent child Browse files
Show More
@@ -0,0 +1,135 b''
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
3
4 define([
5 'jquery',
6 'base/js/namespace',
7 'base/js/utils',
8 'base/js/dialog',
9 ], function ($, IPython, utils, dialog) {
10 "use strict";
11
12 var NewNotebookWidget = function (selector, options) {
13 this.selector = selector;
14 this.base_url = options.base_url;
15 this.notebook_path = options.notebook_path;
16 this.contents = options.contents;
17 this.default_kernel = null;
18 this.config = options.config;
19 this.kernelspecs = {};
20 if (this.selector !== undefined) {
21 this.element = $(selector);
22 this.request_kernelspecs();
23 }
24 this.bind_events();
25 };
26
27 NewNotebookWidget.prototype.bind_events = function () {
28 var that = this;
29 this.element.find('#new_notebook').click(function () {
30 that.new_notebook();
31 });
32 };
33
34 NewNotebookWidget.prototype.request_kernelspecs = function () {
35 /** request and then load kernel specs */
36 var url = utils.url_join_encode(this.base_url, 'api/kernelspecs');
37 utils.promising_ajax(url).then($.proxy(this._load_kernelspecs, this));
38 };
39
40 NewNotebookWidget.prototype._load_kernelspecs = function (data) {
41 /** load kernelspec list */
42 var that = this;
43 this.kernelspecs = data.kernelspecs;
44 var menu = this.element.find("#new-notebook-menu");
45 var keys = Object.keys(data.kernelspecs).sort(function (a, b) {
46 var da = data.kernelspecs[a].display_name;
47 var db = data.kernelspecs[b].display_name;
48 if (da === db) {
49 return 0;
50 } else if (da > db) {
51 return 1;
52 } else {
53 return -1;
54 }
55 });
56 for (var i = 0; i < keys.length; i++) {
57 var ks = this.kernelspecs[keys[i]];
58 var li = $("<li>")
59 .attr("id", "kernel-" +ks.name)
60 .data('kernelspec', ks).append(
61 $('<a>')
62 .attr('href', '#')
63 .click($.proxy(this.new_notebook, this, ks.name))
64 .text(ks.display_name)
65 .attr('title', 'Create a new notebook with ' + ks.display_name)
66 );
67 menu.append(li);
68 }
69 this.config.loaded.then(function () {
70 that._load_default_kernelspec(data['default']);
71 });
72 };
73
74 NewNotebookWidget.prototype._load_default_kernelspec = function (default_name) {
75 /** load default kernelspec name from config, if defined */
76 if (this.config.data.NewNotebookWidget &&
77 this.config.data.NewNotebookWidget.default_kernel &&
78 this.kernelspecs[this.config.data.NewNotebookWidget.default_kernel] !== undefined
79 ) {
80 default_name = this.config.data.NewNotebookWidget.default_kernel;
81 }
82 this.set_default_kernel(default_name);
83 };
84
85 NewNotebookWidget.prototype.set_default_kernel = function (kernel_name) {
86 /** select the current default kernel */
87 this.default_kernel = kernel_name;
88 this.config.update({
89 NewNotebookWidget: {
90 default_kernel: kernel_name
91 }
92 });
93 var spec = this.kernelspecs[kernel_name];
94 var display_name;
95 if (spec) {
96 display_name = spec.display_name;
97 this.element.find("#current-kernel")
98 .text(display_name)
99 .attr('title', display_name + " is the default kernel for new notebooks");
100 } else {
101 display_name = 'default kernel';
102 }
103 this.element.find("#new_notebook").attr('title',
104 'Create a new notebook with ' + display_name
105 );
106 };
107
108 NewNotebookWidget.prototype.new_notebook = function (kernel_name) {
109 /** create and open a new notebook */
110 var that = this;
111 kernel_name = kernel_name || this.default_kernel;
112 var w = window.open();
113 this.contents.new_untitled(that.notebook_path, {type: "notebook"}).then(
114 function (data) {
115 var url = utils.url_join_encode(
116 that.base_url, 'notebooks', data.path
117 );
118 if (kernel_name) {
119 url += "?kernel_name=" + kernel_name;
120 }
121 w.location = url;
122 },
123 function (error) {
124 w.close();
125 dialog.modal({
126 title : 'Creating Notebook Failed',
127 body : "The error was: " + error.message,
128 buttons : {'OK' : {'class' : 'btn-primary'}}
129 });
130 }
131 );
132 };
133
134 return {'NewNotebookWidget': NewNotebookWidget};
135 });
@@ -277,7 +277,7 b' class Pdb(OldPdb):'
277 try:
277 try:
278 OldPdb.interaction(self, frame, traceback)
278 OldPdb.interaction(self, frame, traceback)
279 except KeyboardInterrupt:
279 except KeyboardInterrupt:
280 self.shell.write("\nKeyboardInterrupt\n")
280 self.shell.write('\n' + self.shell.get_exception_only())
281 break
281 break
282 else:
282 else:
283 break
283 break
@@ -40,38 +40,21 b' else:'
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42
42
43 def _valid_formatter(f):
43 def _safe_get_formatter_method(obj, name):
44 """Return whether an object is a valid formatter
44 """Safely get a formatter method
45
46 Cases checked:
47
45
48 - bound methods OK
46 - Classes cannot have formatter methods, only instance
49 - unbound methods NO
47 - protect against proxy objects that claim to have everything
50 - callable with zero args OK
51 """
48 """
52 if f is None:
49 if inspect.isclass(obj):
53 return False
50 # repr methods only make sense on instances, not classes
54 elif isinstance(f, type(str.find)):
51 return None
55 # unbound methods on compiled classes have type method_descriptor
56 return False
57 elif isinstance(f, types.BuiltinFunctionType):
58 # bound methods on compiled classes have type builtin_function
59 return True
60 elif callable(f):
61 # anything that works with zero args should be okay
62 try:
63 inspect.getcallargs(f)
64 except Exception:
65 return False
66 else:
67 return True
68 return False
69
70 def _safe_get_formatter_method(obj, name):
71 """Safely get a formatter method"""
72 method = pretty._safe_getattr(obj, name, None)
52 method = pretty._safe_getattr(obj, name, None)
73 # formatter methods must be bound
53 if callable(method):
74 if _valid_formatter(method):
54 # obj claims to have repr method...
55 if callable(pretty._safe_getattr(obj, '_ipython_canary_method_should_not_exist_', None)):
56 # ...but don't trust proxy objects that claim to have everything
57 return None
75 return method
58 return method
76
59
77
60
@@ -22,6 +22,7 b' import re'
22 import runpy
22 import runpy
23 import sys
23 import sys
24 import tempfile
24 import tempfile
25 import traceback
25 import types
26 import types
26 import subprocess
27 import subprocess
27 from io import open as io_open
28 from io import open as io_open
@@ -1786,6 +1787,15 b' class InteractiveShell(SingletonConfigurable):'
1786 """
1787 """
1787 self.write_err("UsageError: %s" % exc)
1788 self.write_err("UsageError: %s" % exc)
1788
1789
1790 def get_exception_only(self, exc_tuple=None):
1791 """
1792 Return as a string (ending with a newline) the exception that
1793 just occurred, without any traceback.
1794 """
1795 etype, value, tb = self._get_exc_info(exc_tuple)
1796 msg = traceback.format_exception_only(etype, value)
1797 return ''.join(msg)
1798
1789 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1799 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1790 exception_only=False):
1800 exception_only=False):
1791 """Display the exception that just occurred.
1801 """Display the exception that just occurred.
@@ -1838,7 +1848,7 b' class InteractiveShell(SingletonConfigurable):'
1838 self._showtraceback(etype, value, stb)
1848 self._showtraceback(etype, value, stb)
1839
1849
1840 except KeyboardInterrupt:
1850 except KeyboardInterrupt:
1841 self.write_err("\nKeyboardInterrupt\n")
1851 self.write_err('\n' + self.get_exception_only())
1842
1852
1843 def _showtraceback(self, etype, evalue, stb):
1853 def _showtraceback(self, etype, evalue, stb):
1844 """Actually show a traceback.
1854 """Actually show a traceback.
@@ -1993,7 +2003,7 b' class InteractiveShell(SingletonConfigurable):'
1993 continue
2003 continue
1994
2004
1995 @skip_doctest
2005 @skip_doctest
1996 def set_next_input(self, s):
2006 def set_next_input(self, s, replace=False):
1997 """ Sets the 'default' input string for the next command line.
2007 """ Sets the 'default' input string for the next command line.
1998
2008
1999 Requires readline.
2009 Requires readline.
@@ -2355,7 +2365,7 b' class InteractiveShell(SingletonConfigurable):'
2355 try:
2365 try:
2356 ec = os.system(cmd)
2366 ec = os.system(cmd)
2357 except KeyboardInterrupt:
2367 except KeyboardInterrupt:
2358 self.write_err("\nKeyboardInterrupt\n")
2368 self.write_err('\n' + self.get_exception_only())
2359 ec = -2
2369 ec = -2
2360 else:
2370 else:
2361 cmd = py3compat.unicode_to_str(cmd)
2371 cmd = py3compat.unicode_to_str(cmd)
@@ -2374,7 +2384,7 b' class InteractiveShell(SingletonConfigurable):'
2374 ec = subprocess.call(cmd, shell=True, executable=executable)
2384 ec = subprocess.call(cmd, shell=True, executable=executable)
2375 except KeyboardInterrupt:
2385 except KeyboardInterrupt:
2376 # intercept control-C; a long traceback is not useful here
2386 # intercept control-C; a long traceback is not useful here
2377 self.write_err("\nKeyboardInterrupt\n")
2387 self.write_err('\n' + self.get_exception_only())
2378 ec = 130
2388 ec = 130
2379 if ec > 128:
2389 if ec > 128:
2380 ec = -(ec - 128)
2390 ec = -(ec - 128)
@@ -353,7 +353,9 b' class CodeMagics(Magics):'
353 print('Operation cancelled.')
353 print('Operation cancelled.')
354 return
354 return
355
355
356 self.shell.set_next_input(contents)
356 contents = "# %load {}\n".format(arg_s) + contents
357
358 self.shell.set_next_input(contents, replace=True)
357
359
358 @staticmethod
360 @staticmethod
359 def _find_edit_target(shell, args, opts, last_call):
361 def _find_edit_target(shell, args, opts, last_call):
@@ -165,7 +165,6 b' class OSMagics(Magics):'
165
165
166 path = [os.path.abspath(os.path.expanduser(p)) for p in
166 path = [os.path.abspath(os.path.expanduser(p)) for p in
167 os.environ.get('PATH','').split(os.pathsep)]
167 os.environ.get('PATH','').split(os.pathsep)]
168 path = filter(os.path.isdir,path)
169
168
170 syscmdlist = []
169 syscmdlist = []
171 # Now define isexec in a cross platform manner.
170 # Now define isexec in a cross platform manner.
@@ -189,8 +188,12 b' class OSMagics(Magics):'
189 # the innermost part
188 # the innermost part
190 if os.name == 'posix':
189 if os.name == 'posix':
191 for pdir in path:
190 for pdir in path:
192 os.chdir(pdir)
191 try:
193 for ff in os.listdir(pdir):
192 os.chdir(pdir)
193 dirlist = os.listdir(pdir)
194 except OSError:
195 continue
196 for ff in dirlist:
194 if isexec(ff):
197 if isexec(ff):
195 try:
198 try:
196 # Removes dots from the name since ipython
199 # Removes dots from the name since ipython
@@ -205,8 +208,12 b' class OSMagics(Magics):'
205 else:
208 else:
206 no_alias = Alias.blacklist
209 no_alias = Alias.blacklist
207 for pdir in path:
210 for pdir in path:
208 os.chdir(pdir)
211 try:
209 for ff in os.listdir(pdir):
212 os.chdir(pdir)
213 dirlist = os.listdir(pdir)
214 except OSError:
215 continue
216 for ff in dirlist:
210 base, ext = os.path.splitext(ff)
217 base, ext = os.path.splitext(ff)
211 if isexec(ff) and base.lower() not in no_alias:
218 if isexec(ff) and base.lower() not in no_alias:
212 if ext.lower() == '.exe':
219 if ext.lower() == '.exe':
@@ -314,7 +314,6 b' def test_print_method_bound():'
314 class MyHTML(object):
314 class MyHTML(object):
315 def _repr_html_(self):
315 def _repr_html_(self):
316 return "hello"
316 return "hello"
317
318 with capture_output() as captured:
317 with capture_output() as captured:
319 result = f(MyHTML)
318 result = f(MyHTML)
320 nt.assert_is(result, None)
319 nt.assert_is(result, None)
@@ -325,6 +324,44 b' def test_print_method_bound():'
325 nt.assert_equal(result, "hello")
324 nt.assert_equal(result, "hello")
326 nt.assert_equal(captured.stderr, "")
325 nt.assert_equal(captured.stderr, "")
327
326
327 def test_print_method_weird():
328
329 class TextMagicHat(object):
330 def __getattr__(self, key):
331 return key
332
333 f = HTMLFormatter()
334
335 text_hat = TextMagicHat()
336 nt.assert_equal(text_hat._repr_html_, '_repr_html_')
337 with capture_output() as captured:
338 result = f(text_hat)
339
340 nt.assert_is(result, None)
341 nt.assert_not_in("FormatterWarning", captured.stderr)
342
343 class CallableMagicHat(object):
344 def __getattr__(self, key):
345 return lambda : key
346
347 call_hat = CallableMagicHat()
348 with capture_output() as captured:
349 result = f(call_hat)
350
351 nt.assert_equal(result, None)
352
353 class BadReprArgs(object):
354 def _repr_html_(self, extra, args):
355 return "html"
356
357 bad = BadReprArgs()
358 with capture_output() as captured:
359 result = f(bad)
360
361 nt.assert_is(result, None)
362 nt.assert_not_in("FormatterWarning", captured.stderr)
363
364
328 def test_format_config():
365 def test_format_config():
329 """config objects don't pretend to support fancy reprs with lazy attrs"""
366 """config objects don't pretend to support fancy reprs with lazy attrs"""
330 f = HTMLFormatter()
367 f = HTMLFormatter()
@@ -482,6 +482,24 b' class InteractiveShellTestCase(unittest.TestCase):'
482 mod = ip.new_main_mod(u'%s.py' % name, name)
482 mod = ip.new_main_mod(u'%s.py' % name, name)
483 self.assertEqual(mod.__name__, name)
483 self.assertEqual(mod.__name__, name)
484
484
485 def test_get_exception_only(self):
486 try:
487 raise KeyboardInterrupt
488 except KeyboardInterrupt:
489 msg = ip.get_exception_only()
490 self.assertEqual(msg, 'KeyboardInterrupt\n')
491
492 class DerivedInterrupt(KeyboardInterrupt):
493 pass
494 try:
495 raise DerivedInterrupt("foo")
496 except KeyboardInterrupt:
497 msg = ip.get_exception_only()
498 if sys.version_info[0] <= 2:
499 self.assertEqual(msg, 'DerivedInterrupt: foo\n')
500 else:
501 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
502
485 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
503 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
486
504
487 @onlyif_unicode_paths
505 @onlyif_unicode_paths
@@ -245,14 +245,16 b' def fix_frame_records_filenames(records):'
245 """
245 """
246 fixed_records = []
246 fixed_records = []
247 for frame, filename, line_no, func_name, lines, index in records:
247 for frame, filename, line_no, func_name, lines, index in records:
248 # Look inside the frame's globals dictionary for __file__, which should
248 # Look inside the frame's globals dictionary for __file__,
249 # be better.
249 # which should be better. However, keep Cython filenames since
250 better_fn = frame.f_globals.get('__file__', None)
250 # we prefer the source filenames over the compiled .so file.
251 if isinstance(better_fn, str):
251 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
252 # Check the type just in case someone did something weird with
252 better_fn = frame.f_globals.get('__file__', None)
253 # __file__. It might also be None if the error occurred during
253 if isinstance(better_fn, str):
254 # import.
254 # Check the type just in case someone did something weird with
255 filename = better_fn
255 # __file__. It might also be None if the error occurred during
256 # import.
257 filename = better_fn
256 fixed_records.append((frame, filename, line_no, func_name, lines, index))
258 fixed_records.append((frame, filename, line_no, func_name, lines, index))
257 return fixed_records
259 return fixed_records
258
260
@@ -722,15 +724,23 b' class VerboseTB(TBTools):'
722 #print '*** record:',file,lnum,func,lines,index # dbg
724 #print '*** record:',file,lnum,func,lines,index # dbg
723 if not file:
725 if not file:
724 file = '?'
726 file = '?'
725 elif not (file.startswith(str("<")) and file.endswith(str(">"))):
727 elif file.startswith(str("<")) and file.endswith(str(">")):
726 # Guess that filenames like <string> aren't real filenames, so
728 # Not a real filename, no problem...
727 # don't call abspath on them.
729 pass
728 try:
730 elif not os.path.isabs(file):
729 file = abspath(file)
731 # Try to make the filename absolute by trying all
730 except OSError:
732 # sys.path entries (which is also what linecache does)
731 # Not sure if this can still happen: abspath now works with
733 for dirname in sys.path:
732 # file names like <string>
734 try:
733 pass
735 fullname = os.path.join(dirname, file)
736 if os.path.isfile(fullname):
737 file = os.path.abspath(fullname)
738 break
739 except Exception:
740 # Just in case that sys.path contains very
741 # strange entries...
742 pass
743
734 file = py3compat.cast_unicode(file, util_path.fs_encoding)
744 file = py3compat.cast_unicode(file, util_path.fs_encoding)
735 link = tpl_link % file
745 link = tpl_link % file
736 args, varargs, varkw, locals = inspect.getargvalues(frame)
746 args, varargs, varkw, locals = inspect.getargvalues(frame)
@@ -611,9 +611,9 b' class FileContentsManager(ContentsManager):'
611 return "Serving notebooks from local directory: %s" % self.root_dir
611 return "Serving notebooks from local directory: %s" % self.root_dir
612
612
613 def get_kernel_path(self, path, model=None):
613 def get_kernel_path(self, path, model=None):
614 """Return the initial working dir a kernel associated with a given notebook"""
614 """Return the initial API path of a kernel associated with a given notebook"""
615 if '/' in path:
615 if '/' in path:
616 parent_dir = path.rsplit('/', 1)[0]
616 parent_dir = path.rsplit('/', 1)[0]
617 else:
617 else:
618 parent_dir = ''
618 parent_dir = ''
619 return self._get_os_path(parent_dir)
619 return parent_dir
@@ -187,8 +187,12 b' class ContentsManager(LoggingConfigurable):'
187
187
188 KernelManagers can turn this value into a filesystem path,
188 KernelManagers can turn this value into a filesystem path,
189 or ignore it altogether.
189 or ignore it altogether.
190
191 The default value here will start kernels in the directory of the
192 notebook server. FileContentsManager overrides this to use the
193 directory containing the notebook.
190 """
194 """
191 return path
195 return ''
192
196
193 def increment_filename(self, filename, path='', insert=''):
197 def increment_filename(self, filename, path='', insert=''):
194 """Increment a filename until it is unique.
198 """Increment a filename until it is unique.
@@ -54,14 +54,10 b' class MappingKernelManager(MultiKernelManager):'
54
54
55 def cwd_for_path(self, path):
55 def cwd_for_path(self, path):
56 """Turn API path into absolute OS path."""
56 """Turn API path into absolute OS path."""
57 # short circuit for NotebookManagers that pass in absolute paths
58 if os.path.exists(path):
59 return path
60
61 os_path = to_os_path(path, self.root_dir)
57 os_path = to_os_path(path, self.root_dir)
62 # in the case of notebooks and kernels not being on the same filesystem,
58 # in the case of notebooks and kernels not being on the same filesystem,
63 # walk up to root_dir if the paths don't exist
59 # walk up to root_dir if the paths don't exist
64 while not os.path.exists(os_path) and os_path != self.root_dir:
60 while not os.path.isdir(os_path) and os_path != self.root_dir:
65 os_path = os.path.dirname(os_path)
61 os_path = os.path.dirname(os_path)
66 return os_path
62 return os_path
67
63
@@ -7,8 +7,6 b' from tornado import web'
7
7
8 from ...base.handlers import IPythonHandler, json_errors
8 from ...base.handlers import IPythonHandler, json_errors
9
9
10 from IPython.kernel.kernelspec import _pythonfirst
11
12
10
13 class MainKernelSpecHandler(IPythonHandler):
11 class MainKernelSpecHandler(IPythonHandler):
14 SUPPORTED_METHODS = ('GET',)
12 SUPPORTED_METHODS = ('GET',)
@@ -17,18 +15,21 b' class MainKernelSpecHandler(IPythonHandler):'
17 @json_errors
15 @json_errors
18 def get(self):
16 def get(self):
19 ksm = self.kernel_spec_manager
17 ksm = self.kernel_spec_manager
20 results = []
18 km = self.kernel_manager
21 for kernel_name in sorted(ksm.find_kernel_specs(), key=_pythonfirst):
19 model = {}
20 model['default'] = km.default_kernel_name
21 model['kernelspecs'] = specs = {}
22 for kernel_name in ksm.find_kernel_specs():
22 try:
23 try:
23 d = ksm.get_kernel_spec(kernel_name).to_dict()
24 d = ksm.get_kernel_spec(kernel_name).to_dict()
24 except Exception:
25 except Exception:
25 self.log.error("Failed to load kernel spec: '%s'", kernel_name, exc_info=True)
26 self.log.error("Failed to load kernel spec: '%s'", kernel_name, exc_info=True)
26 continue
27 continue
27 d['name'] = kernel_name
28 d['name'] = kernel_name
28 results.append(d)
29 specs[kernel_name] = d
29
30
30 self.set_header("Content-Type", 'application/json')
31 self.set_header("Content-Type", 'application/json')
31 self.finish(json.dumps(results))
32 self.finish(json.dumps(model))
32
33
33
34
34 class KernelSpecHandler(IPythonHandler):
35 class KernelSpecHandler(IPythonHandler):
@@ -78,16 +78,22 b' class APITest(NotebookTestBase):'
78 with open(pjoin(bad_kernel_dir, 'kernel.json'), 'w') as f:
78 with open(pjoin(bad_kernel_dir, 'kernel.json'), 'w') as f:
79 f.write("garbage")
79 f.write("garbage")
80
80
81 specs = self.ks_api.list().json()
81 model = self.ks_api.list().json()
82 assert isinstance(specs, list)
82 assert isinstance(model, dict)
83 self.assertEqual(model['default'], NATIVE_KERNEL_NAME)
84 specs = model['kernelspecs']
85 assert isinstance(specs, dict)
83 # 2: the sample kernelspec created in setUp, and the native Python kernel
86 # 2: the sample kernelspec created in setUp, and the native Python kernel
84 self.assertGreaterEqual(len(specs), 2)
87 self.assertGreaterEqual(len(specs), 2)
85
88
86 shutil.rmtree(bad_kernel_dir)
89 shutil.rmtree(bad_kernel_dir)
87
90
88 def test_list_kernelspecs(self):
91 def test_list_kernelspecs(self):
89 specs = self.ks_api.list().json()
92 model = self.ks_api.list().json()
90 assert isinstance(specs, list)
93 assert isinstance(model, dict)
94 self.assertEqual(model['default'], NATIVE_KERNEL_NAME)
95 specs = model['kernelspecs']
96 assert isinstance(specs, dict)
91
97
92 # 2: the sample kernelspec created in setUp, and the native Python kernel
98 # 2: the sample kernelspec created in setUp, and the native Python kernel
93 self.assertGreaterEqual(len(specs), 2)
99 self.assertGreaterEqual(len(specs), 2)
@@ -98,8 +104,8 b' class APITest(NotebookTestBase):'
98 def is_default_kernelspec(s):
104 def is_default_kernelspec(s):
99 return s['name'] == NATIVE_KERNEL_NAME and s['display_name'].startswith("IPython")
105 return s['name'] == NATIVE_KERNEL_NAME and s['display_name'].startswith("IPython")
100
106
101 assert any(is_sample_kernelspec(s) for s in specs), specs
107 assert any(is_sample_kernelspec(s) for s in specs.values()), specs
102 assert any(is_default_kernelspec(s) for s in specs), specs
108 assert any(is_default_kernelspec(s) for s in specs.values()), specs
103
109
104 def test_get_kernelspec(self):
110 def test_get_kernelspec(self):
105 spec = self.ks_api.kernel_spec_info('Sample').json() # Case insensitive
111 spec = self.ks_api.kernel_spec_info('Sample').json() # Case insensitive
@@ -4,14 +4,17 b''
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 ], function(IPython, $){
7 'base/js/events',
8 ], function(IPython, $, events){
8 "use strict";
9 "use strict";
9
10
10 var Page = function () {
11 var Page = function () {
11 this.bind_events();
12 this.bind_events();
13 this._resize_header();
12 };
14 };
13
15
14 Page.prototype.bind_events = function () {
16 Page.prototype.bind_events = function () {
17 events.on('resize-header.Page', $.proxy(this._resize_header, this));
15 };
18 };
16
19
17 Page.prototype.show = function () {
20 Page.prototype.show = function () {
@@ -41,6 +44,11 b' define(['
41 $('div#site').css('display','block');
44 $('div#site').css('display','block');
42 };
45 };
43
46
47 Page.prototype._resize_header = function() {
48 // Update the header's size.
49 $('#header-spacer').height($('#header').height());
50 };
51
44 // Register self in the global namespace for convenience.
52 // Register self in the global namespace for convenience.
45 IPython.Page = Page;
53 IPython.Page = Page;
46 return {'Page': Page};
54 return {'Page': Page};
@@ -541,7 +541,16 b' define(['
541 if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
541 if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
542 return OSName;
542 return OSName;
543 })();
543 })();
544
544
545 var get_url_param = function (name) {
546 // get a URL parameter. I cannot believe we actually need this.
547 // Based on http://stackoverflow.com/a/25359264/938949
548 var match = new RegExp('[\?&]' + name + '=([^&]*)').exec(window.location.search);
549 if (match){
550 return decodeURIComponent(match[1] || '');
551 }
552 };
553
545 var is_or_has = function (a, b) {
554 var is_or_has = function (a, b) {
546 /**
555 /**
547 * Is b a child of a or a itself?
556 * Is b a child of a or a itself?
@@ -632,6 +641,7 b' define(['
632 * Like $.ajax, but returning an ES6 promise. success and error settings
641 * Like $.ajax, but returning an ES6 promise. success and error settings
633 * will be ignored.
642 * will be ignored.
634 */
643 */
644 settings = settings || {};
635 return new Promise(function(resolve, reject) {
645 return new Promise(function(resolve, reject) {
636 settings.success = function(data, status, jqXHR) {
646 settings.success = function(data, status, jqXHR) {
637 resolve(data);
647 resolve(data);
@@ -766,6 +776,33 b' define(['
766 };
776 };
767 };
777 };
768
778
779 var typeset = function(element, text) {
780 /**
781 * Apply MathJax rendering to an element, and optionally set its text
782 *
783 * If MathJax is not available, make no changes.
784 *
785 * Returns the output any number of typeset elements, or undefined if
786 * MathJax was not available.
787 *
788 * Parameters
789 * ----------
790 * element: Node, NodeList, or jQuery selection
791 * text: option string
792 */
793 if(!window.MathJax){
794 return;
795 }
796 var $el = element.jquery ? element : $(element);
797 if(arguments.length > 1){
798 $el.text(text);
799 }
800 return $el.map(function(){
801 // MathJax takes a DOM node: $.map makes `this` the context
802 return MathJax.Hub.Queue(["Typeset", MathJax.Hub, this]);
803 });
804 };
805
769 var utils = {
806 var utils = {
770 regex_split : regex_split,
807 regex_split : regex_split,
771 uuid : uuid,
808 uuid : uuid,
@@ -786,6 +823,7 b' define(['
786 from_absolute_cursor_pos : from_absolute_cursor_pos,
823 from_absolute_cursor_pos : from_absolute_cursor_pos,
787 browser : browser,
824 browser : browser,
788 platform: platform,
825 platform: platform,
826 get_url_param: get_url_param,
789 is_or_has : is_or_has,
827 is_or_has : is_or_has,
790 is_focused : is_focused,
828 is_focused : is_focused,
791 mergeopt: mergeopt,
829 mergeopt: mergeopt,
@@ -799,6 +837,7 b' define(['
799 load_class: load_class,
837 load_class: load_class,
800 resolve_promises_dict: resolve_promises_dict,
838 resolve_promises_dict: resolve_promises_dict,
801 reject: reject,
839 reject: reject,
840 typeset: typeset,
802 };
841 };
803
842
804 // Backwards compatability.
843 // Backwards compatability.
@@ -20,11 +20,33 b' body {'
20 div#header {
20 div#header {
21 /* Initially hidden to prevent FLOUC */
21 /* Initially hidden to prevent FLOUC */
22 display: none;
22 display: none;
23 margin-bottom: 0px;
23 margin-bottom: -6px;
24 padding-left: 30px;
24 position: fixed;
25 padding-bottom: 5px;
25 top: 0;
26 border-bottom: 1px solid @navbar-default-border;
26 width: 100%;
27 .border-box-sizing();
27 background-color: @body-bg;
28 min-height: 31px;
29
30 /* Display over codemirror */
31 z-index: 100;
32
33 #header-container {
34 margin-bottom: 0px;
35 padding-left: 30px;
36 padding-bottom: 5px;
37 .border-box-sizing();
38 }
39
40 .header-bar {
41 width: 100%;
42 height: 0px;
43 border-bottom: 1px solid @navbar-default-border;
44 }
45 }
46
47 #header-spacer {
48 width: 100%;
49 visibility: hidden;
28 }
50 }
29
51
30 #ipython_notebook {
52 #ipython_notebook {
@@ -220,10 +220,7 b' define(['
220 * @method typeset
220 * @method typeset
221 */
221 */
222 Cell.prototype.typeset = function () {
222 Cell.prototype.typeset = function () {
223 if (window.MathJax) {
223 utils.typeset(this.element);
224 var cell_math = this.element.get(0);
225 MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]);
226 }
227 };
224 };
228
225
229 /**
226 /**
@@ -389,7 +389,7 b' define(['
389 * @private
389 * @private
390 */
390 */
391 CodeCell.prototype._handle_set_next_input = function (payload) {
391 CodeCell.prototype._handle_set_next_input = function (payload) {
392 var data = {'cell': this, 'text': payload.text};
392 var data = {'cell': this, 'text': payload.text, replace: payload.replace};
393 this.events.trigger('set_next_input.Notebook', data);
393 this.events.trigger('set_next_input.Notebook', data);
394 };
394 };
395
395
@@ -25,16 +25,27 b' define(['
25
25
26 KernelSelector.prototype.request_kernelspecs = function() {
26 KernelSelector.prototype.request_kernelspecs = function() {
27 var url = utils.url_join_encode(this.notebook.base_url, 'api/kernelspecs');
27 var url = utils.url_join_encode(this.notebook.base_url, 'api/kernelspecs');
28 $.ajax(url, {success: $.proxy(this._got_kernelspecs, this)});
28 utils.promising_ajax(url).then($.proxy(this._got_kernelspecs, this));
29 };
29 };
30
30
31 KernelSelector.prototype._got_kernelspecs = function(data, status, xhr) {
31 KernelSelector.prototype._got_kernelspecs = function(data) {
32 this.kernelspecs = {};
32 this.kernelspecs = data.kernelspecs;
33 var menu = this.element.find("#kernel_selector");
33 var menu = this.element.find("#kernel_selector");
34 var change_kernel_submenu = $("#menu-change-kernel-submenu");
34 var change_kernel_submenu = $("#menu-change-kernel-submenu");
35 for (var i = 0; i < data.length; i++) {
35 var keys = Object.keys(data.kernelspecs).sort(function (a, b) {
36 var ks = data[i];
36 // sort by display_name
37 this.kernelspecs[ks.name] = ks;
37 var da = data.kernelspecs[a].display_name;
38 var db = data.kernelspecs[b].display_name;
39 if (da === db) {
40 return 0;
41 } else if (da > db) {
42 return 1;
43 } else {
44 return -1;
45 }
46 });
47 for (var i = 0; i < keys.length; i++) {
48 var ks = this.kernelspecs[keys[i]];
38 var ksentry = $("<li>").attr("id", "kernel-" +ks.name).append($('<a>')
49 var ksentry = $("<li>").attr("id", "kernel-" +ks.name).append($('<a>')
39 .attr('href', '#')
50 .attr('href', '#')
40 .click($.proxy(this.change_kernel, this, ks.name))
51 .click($.proxy(this.change_kernel, this, ks.name))
@@ -9,7 +9,6 b' require(['
9 'services/config',
9 'services/config',
10 'base/js/utils',
10 'base/js/utils',
11 'base/js/page',
11 'base/js/page',
12 'notebook/js/layoutmanager',
13 'base/js/events',
12 'base/js/events',
14 'auth/js/loginwidget',
13 'auth/js/loginwidget',
15 'notebook/js/maintoolbar',
14 'notebook/js/maintoolbar',
@@ -34,7 +33,6 b' require(['
34 configmod,
33 configmod,
35 utils,
34 utils,
36 page,
35 page,
37 layoutmanager,
38 events,
36 events,
39 loginwidget,
37 loginwidget,
40 maintoolbar,
38 maintoolbar,
@@ -66,9 +64,7 b' require(['
66
64
67 var user_config = $.extend({}, config.default_config);
65 var user_config = $.extend({}, config.default_config);
68 var page = new page.Page();
66 var page = new page.Page();
69 var layout_manager = new layoutmanager.LayoutManager();
67 var pager = new pager.Pager('div#pager', {
70 var pager = new pager.Pager('div#pager', 'div#pager_splitter', {
71 layout_manager: layout_manager,
72 events: events});
68 events: events});
73 var acts = new actions.init();
69 var acts = new actions.init();
74 var keyboard_manager = new keyboardmanager.KeyboardManager({
70 var keyboard_manager = new keyboardmanager.KeyboardManager({
@@ -104,7 +100,6 b' require(['
104 var menubar = new menubar.MenuBar('#menubar', $.extend({
100 var menubar = new menubar.MenuBar('#menubar', $.extend({
105 notebook: notebook,
101 notebook: notebook,
106 contents: contents,
102 contents: contents,
107 layout_manager: layout_manager,
108 events: events,
103 events: events,
109 save_widget: save_widget,
104 save_widget: save_widget,
110 quick_help: quick_help},
105 quick_help: quick_help},
@@ -132,9 +127,7 b' require(['
132
127
133 page.show();
128 page.show();
134
129
135 layout_manager.do_resize();
136 var first_load = function () {
130 var first_load = function () {
137 layout_manager.do_resize();
138 var hash = document.location.hash;
131 var hash = document.location.hash;
139 if (hash) {
132 if (hash) {
140 document.location.hash = '';
133 document.location.hash = '';
@@ -147,7 +140,6 b' require(['
147 events.on('notebook_loaded.Notebook', first_load);
140 events.on('notebook_loaded.Notebook', first_load);
148
141
149 IPython.page = page;
142 IPython.page = page;
150 IPython.layout_manager = layout_manager;
151 IPython.notebook = notebook;
143 IPython.notebook = notebook;
152 IPython.contents = contents;
144 IPython.contents = contents;
153 IPython.pager = pager;
145 IPython.pager = pager;
@@ -24,7 +24,6 b' define(['
24 * Dictionary of keyword arguments.
24 * Dictionary of keyword arguments.
25 * notebook: Notebook instance
25 * notebook: Notebook instance
26 * contents: ContentManager instance
26 * contents: ContentManager instance
27 * layout_manager: LayoutManager instance
28 * events: $(Events) instance
27 * events: $(Events) instance
29 * save_widget: SaveWidget instance
28 * save_widget: SaveWidget instance
30 * quick_help: QuickHelp instance
29 * quick_help: QuickHelp instance
@@ -37,7 +36,6 b' define(['
37 this.selector = selector;
36 this.selector = selector;
38 this.notebook = options.notebook;
37 this.notebook = options.notebook;
39 this.contents = options.contents;
38 this.contents = options.contents;
40 this.layout_manager = options.layout_manager;
41 this.events = options.events;
39 this.events = options.events;
42 this.save_widget = options.save_widget;
40 this.save_widget = options.save_widget;
43 this.quick_help = options.quick_help;
41 this.quick_help = options.quick_help;
@@ -88,6 +86,13 b' define(['
88 }
86 }
89 };
87 };
90
88
89 MenuBar.prototype._size_header = function() {
90 /**
91 * Update header spacer size.
92 */
93 this.events.trigger('resize-header.Page');
94 };
95
91 MenuBar.prototype.bind_events = function () {
96 MenuBar.prototype.bind_events = function () {
92 /**
97 /**
93 * File
98 * File
@@ -149,6 +154,10 b' define(['
149 that._nbconvert('pdf', true);
154 that._nbconvert('pdf', true);
150 });
155 });
151
156
157 this.element.find('#download_script').click(function () {
158 that._nbconvert('script', true);
159 });
160
152 this.element.find('#rename_notebook').click(function () {
161 this.element.find('#rename_notebook').click(function () {
153 that.save_widget.rename_notebook({notebook: that.notebook});
162 that.save_widget.rename_notebook({notebook: that.notebook});
154 });
163 });
@@ -218,12 +227,12 b' define(['
218
227
219 // View
228 // View
220 this.element.find('#toggle_header').click(function () {
229 this.element.find('#toggle_header').click(function () {
221 $('div#header').toggle();
230 $('div#header-container').toggle();
222 that.layout_manager.do_resize();
231 that._size_header();
223 });
232 });
224 this.element.find('#toggle_toolbar').click(function () {
233 this.element.find('#toggle_toolbar').click(function () {
225 $('div#maintoolbar').toggle();
234 $('div#maintoolbar').toggle();
226 that.layout_manager.do_resize();
235 that._size_header();
227 });
236 });
228 // Insert
237 // Insert
229 this.element.find('#insert_cell_above').click(function () {
238 this.element.find('#insert_cell_above').click(function () {
@@ -371,20 +380,6 b' define(['
371 var langname = (langinfo.name || 'Script')
380 var langname = (langinfo.name || 'Script')
372 langname = langname.charAt(0).toUpperCase()+langname.substr(1) // Capitalise
381 langname = langname.charAt(0).toUpperCase()+langname.substr(1) // Capitalise
373 el.find('a').text(langname + ' ('+(langinfo.file_extension || 'txt')+')');
382 el.find('a').text(langname + ' ('+(langinfo.file_extension || 'txt')+')');
374
375 // Unregister any previously registered handlers
376 el.off('click');
377 if (langinfo.nbconvert_exporter) {
378 // Metadata specifies a specific exporter, e.g. 'python'
379 el.click(function() {
380 that._nbconvert(langinfo.nbconvert_exporter, true);
381 });
382 } else {
383 // Use generic 'script' exporter
384 el.click(function() {
385 that._nbconvert('script', true);
386 });
387 }
388 };
383 };
389
384
390 // Backwards compatability.
385 // Backwards compatability.
@@ -210,9 +210,14 b' define(['
210 var that = this;
210 var that = this;
211
211
212 this.events.on('set_next_input.Notebook', function (event, data) {
212 this.events.on('set_next_input.Notebook', function (event, data) {
213 var index = that.find_cell_index(data.cell);
213 if (data.replace) {
214 var new_cell = that.insert_cell_below('code',index);
214 data.cell.set_text(data.text);
215 new_cell.set_text(data.text);
215 data.cell.clear_output();
216 } else {
217 var index = that.find_cell_index(data.cell);
218 var new_cell = that.insert_cell_below('code',index);
219 new_cell.set_text(data.text);
220 }
216 that.dirty = true;
221 that.dirty = true;
217 });
222 });
218
223
@@ -2326,9 +2331,13 b' define(['
2326 // Create the session after the notebook is completely loaded to prevent
2331 // Create the session after the notebook is completely loaded to prevent
2327 // code execution upon loading, which is a security risk.
2332 // code execution upon loading, which is a security risk.
2328 if (this.session === null) {
2333 if (this.session === null) {
2329 var kernelspec = this.metadata.kernelspec || {};
2334 var kernel_name;
2330 var kernel_name = kernelspec.name;
2335 if (this.metadata.kernelspec) {
2331
2336 var kernelspec = this.metadata.kernelspec || {};
2337 kernel_name = kernelspec.name;
2338 } else {
2339 kernel_name = utils.get_url_param('kernel_name');
2340 }
2332 this.start_session(kernel_name);
2341 this.start_session(kernel_name);
2333 }
2342 }
2334 // load our checkpoint list
2343 // load our checkpoint list
@@ -199,9 +199,7 b' define(['
199
199
200 // typeset with MathJax if MathJax is available
200 // typeset with MathJax if MathJax is available
201 OutputArea.prototype.typeset = function () {
201 OutputArea.prototype.typeset = function () {
202 if (window.MathJax){
202 utils.typeset(this.element);
203 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
204 }
205 };
203 };
206
204
207
205
@@ -8,48 +8,22 b' define(['
8 ], function(IPython, $, utils) {
8 ], function(IPython, $, utils) {
9 "use strict";
9 "use strict";
10
10
11 var Pager = function (pager_selector, pager_splitter_selector, options) {
11 var Pager = function (pager_selector, options) {
12 /**
12 /**
13 * Constructor
13 * Constructor
14 *
14 *
15 * Parameters:
15 * Parameters:
16 * pager_selector: string
16 * pager_selector: string
17 * pager_splitter_selector: string
18 * options: dictionary
17 * options: dictionary
19 * Dictionary of keyword arguments.
18 * Dictionary of keyword arguments.
20 * events: $(Events) instance
19 * events: $(Events) instance
21 * layout_manager: LayoutManager instance
22 */
20 */
23 this.events = options.events;
21 this.events = options.events;
24 this.pager_element = $(pager_selector);
22 this.pager_element = $(pager_selector);
25 this.pager_button_area = $('#pager_button_area');
23 this.pager_button_area = $('#pager-button-area');
26 var that = this;
24 this._default_end_space = 200;
27 this.percentage_height = 0.40;
25 this.pager_element.resizable({handles: 'n', resize: $.proxy(this._resize, this)});
28 options.layout_manager.pager = this;
29 this.pager_splitter_element = $(pager_splitter_selector)
30 .draggable({
31 containment: 'window',
32 axis:'y',
33 helper: null ,
34 drag: function(event, ui) {
35 /**
36 * recalculate the amount of space the pager should take
37 */
38 var pheight = ($(document.body).height()-event.clientY-4);
39 var downprct = pheight/options.layout_manager.app_height();
40 downprct = Math.min(0.9, downprct);
41 if (downprct < 0.1) {
42 that.percentage_height = 0.1;
43 that.collapse({'duration':0});
44 } else if (downprct > 0.2) {
45 that.percentage_height = downprct;
46 that.expand({'duration':0});
47 }
48 options.layout_manager.do_resize();
49 }
50 });
51 this.expanded = false;
26 this.expanded = false;
52 this.style();
53 this.create_button_area();
27 this.create_button_area();
54 this.bind_events();
28 this.bind_events();
55 };
29 };
@@ -61,7 +35,6 b' define(['
61 .attr('title',"Open the pager in an external window")
35 .attr('title',"Open the pager in an external window")
62 .addClass('ui-button')
36 .addClass('ui-button')
63 .click(function(){that.detach();})
37 .click(function(){that.detach();})
64 .attr('style','position: absolute; right: 20px;')
65 .append(
38 .append(
66 $('<span>').addClass("ui-icon ui-icon-extlink")
39 $('<span>').addClass("ui-icon ui-icon-extlink")
67 )
40 )
@@ -71,49 +44,37 b' define(['
71 .attr('title',"Close the pager")
44 .attr('title',"Close the pager")
72 .addClass('ui-button')
45 .addClass('ui-button')
73 .click(function(){that.collapse();})
46 .click(function(){that.collapse();})
74 .attr('style','position: absolute; right: 5px;')
75 .append(
47 .append(
76 $('<span>').addClass("ui-icon ui-icon-close")
48 $('<span>').addClass("ui-icon ui-icon-close")
77 )
49 )
78 );
50 );
79 };
51 };
80
52
81 Pager.prototype.style = function () {
82 this.pager_splitter_element.addClass('ui-widget ui-state-default');
83 this.pager_splitter_element.attr('title', 'Click to Show/Hide pager area, drag to Resize');
84 };
85
86
53
87 Pager.prototype.bind_events = function () {
54 Pager.prototype.bind_events = function () {
88 var that = this;
55 var that = this;
89
56
90 this.pager_element.bind('collapse_pager', function (event, extrap) {
57 this.pager_element.bind('collapse_pager', function (event, extrap) {
91 var time = 'fast';
58 // Animate hiding of the pager.
92 if (extrap && extrap.duration) {
59 var time = (extrap && extrap.duration) ? extrap.duration : 'fast';
93 time = extrap.duration;
60 that.pager_element.hide(time, function() {
94 }
61 $('.end_space').css('height', that._default_end_space);
95 that.pager_element.hide(time);
62 });
96 });
63 });
97
64
98 this.pager_element.bind('expand_pager', function (event, extrap) {
65 this.pager_element.bind('expand_pager', function (event, extrap) {
99 var time = 'fast';
66 // Clear the pager's height attr if it's set. This allows the
100 if (extrap && extrap.duration) {
67 // pager to size itself according to its contents.
101 time = extrap.duration;
68 that.pager_element.height('initial');
102 }
69
103 that.pager_element.show(time);
70 // Animate the showing of the pager
104 });
71 var time = (extrap && extrap.duration) ? extrap.duration : 'fast';
105
72 that.pager_element.show(time, function() {
106 this.pager_splitter_element.hover(
73 // Explicitly set pager height once the pager has shown itself.
107 function () {
74 // This allows the pager-contents div to use percentage sizing.
108 that.pager_splitter_element.addClass('ui-state-hover');
75 that.pager_element.height(that.pager_element.height());
109 },
76 that._resize();
110 function () {
77 });
111 that.pager_splitter_element.removeClass('ui-state-hover');
112 }
113 );
114
115 this.pager_splitter_element.click(function () {
116 that.toggle();
117 });
78 });
118
79
119 this.events.on('open_with_text.Pager', function (event, payload) {
80 this.events.on('open_with_text.Pager', function (event, payload) {
@@ -130,7 +91,7 b' define(['
130 Pager.prototype.collapse = function (extrap) {
91 Pager.prototype.collapse = function (extrap) {
131 if (this.expanded === true) {
92 if (this.expanded === true) {
132 this.expanded = false;
93 this.expanded = false;
133 this.pager_element.add($('div#notebook')).trigger('collapse_pager', extrap);
94 this.pager_element.trigger('collapse_pager', extrap);
134 }
95 }
135 };
96 };
136
97
@@ -138,7 +99,7 b' define(['
138 Pager.prototype.expand = function (extrap) {
99 Pager.prototype.expand = function (extrap) {
139 if (this.expanded !== true) {
100 if (this.expanded !== true) {
140 this.expanded = true;
101 this.expanded = true;
141 this.pager_element.add($('div#notebook')).trigger('expand_pager', extrap);
102 this.pager_element.trigger('expand_pager', extrap);
142 }
103 }
143 };
104 };
144
105
@@ -184,6 +145,18 b' define(['
184 this.pager_element.find(".container").append($('<pre/>').html(utils.fixCarriageReturn(utils.fixConsole(text))));
145 this.pager_element.find(".container").append($('<pre/>').html(utils.fixCarriageReturn(utils.fixConsole(text))));
185 };
146 };
186
147
148
149 Pager.prototype._resize = function() {
150 /**
151 * Update document based on pager size.
152 */
153
154 // Make sure the padding at the end of the notebook is large
155 // enough that the user can scroll to the bottom of the
156 // notebook.
157 $('.end_space').css('height', Math.max(this.pager_element.height(), this._default_end_space));
158 };
159
187 // Backwards compatability.
160 // Backwards compatability.
188 IPython.Pager = Pager;
161 IPython.Pager = Pager;
189
162
@@ -1,12 +1,13 b''
1 #menubar {
1 #menubar {
2 margin-top: 0px;
2 margin-top: 0px;
3 margin-bottom: -19px;
3 margin-bottom: -24px;
4 position: relative;
4 position: relative;
5 .border-box-sizing();
5 .border-box-sizing();
6
6
7 .navbar {
7 .navbar {
8 border-top: 1px;
8 border-top: 1px;
9 border-radius: 0px 0px @border-radius-base @border-radius-base;
9 border-radius: 0px 0px @border-radius-base @border-radius-base;
10 margin-bottom: 23px;
10 }
11 }
11
12
12 .navbar-toggle {
13 .navbar-toggle {
@@ -3,10 +3,6 b' body {'
3 background-color: @body-bg;
3 background-color: @body-bg;
4 }
4 }
5
5
6 body.notebook_app {
7 overflow: hidden;
8 }
9
10 @media (max-width: 767px) {
6 @media (max-width: 767px) {
11 // remove bootstrap-responsive's body padding on small screens
7 // remove bootstrap-responsive's body padding on small screens
12 body.notebook_app {
8 body.notebook_app {
@@ -36,19 +32,17 b' span#notebook_name {'
36 div#notebook_panel {
32 div#notebook_panel {
37 margin: 0px 0px 0px 0px;
33 margin: 0px 0px 0px 0px;
38 padding: 0px;
34 padding: 0px;
39 .box-shadow(@notebook-shadow);
40 .border-box-sizing();
35 .border-box-sizing();
41 }
36 }
42 div#notebook {
37 div#notebook {
43 font-size: @notebook_font_size;
38 font-size: @notebook_font_size;
44 line-height: @notebook_line_height;
39 line-height: @notebook_line_height;
45 overflow-y: scroll;
40 overflow-y: hidden;
46 overflow-x: auto;
41 overflow-x: auto;
47 width: 100%;
42 width: 100%;
48 /* This spaces the cell away from the edge of the notebook area */
43 /* This spaces the cell away from the edge of the notebook area */
49 padding: 1em 0 1em 0;
44 padding: 2em 0 2em 0;
50 margin: 0px;
45 margin: 0px;
51 border-top: 1px solid @navbar-default-border;
52 outline: none;
46 outline: none;
53 .border-box-sizing();
47 .border-box-sizing();
54 }
48 }
@@ -86,3 +80,14 b' p {'
86 .end_space {
80 .end_space {
87 height: 200px;
81 height: 200px;
88 }
82 }
83
84 .lower-header-bar {
85 width: 100%;
86 height: 0px;
87 border-bottom: 1px solid @navbar-default-border;
88 margin-bottom: -1px;
89 }
90
91 .notebook_app #header {
92 .box-shadow(@notebook-shadow);
93 }
@@ -1,25 +1,51 b''
1 div#pager_splitter {
2 height: 8px;
3 .border-box-sizing();
4 }
5
6 #pager-container {
7 position: relative;
8 padding: 15px 0px;
9 .border-box-sizing();
10 }
11
12 div#pager {
1 div#pager {
2 background-color: @body-bg;
13 font-size: @notebook_font_size;
3 font-size: @notebook_font_size;
14 line-height: @notebook_line_height;
4 line-height: @notebook_line_height;
15 overflow: auto;
5 overflow: hidden;
16 display: none;
6 display: none;
7 position: fixed;
8 bottom: 0px;
9 width: 100%;
10 max-height: 50%;
11 padding-top: 7px;
12
13 /* Display over codemirror */
14 z-index: 100;
15
16 /* Hack which prevents jquery ui resizable from changing top. */
17 top: inherit !important;
17
18
18 pre {
19 pre {
19 line-height: @code_line_height;
20 line-height: @code_line_height;
20 color: @text-color;
21 color: @text-color;
21 background-color: @cell_background;
22 background-color: @cell_background;
22 padding: @code_padding;
23 padding: @code_padding;
24 }
25
26 #pager-button-area {
27 position: absolute;
28 top: 7px;
29 right: 20px;
30 }
31
32 #pager-contents {
33 position: relative;
34 overflow: auto;
35 width: 100%;
36 height: 100%;
37
38 #pager-container {
39 position: relative;
40 padding: 15px 0px;
41 .border-box-sizing();
42 }
43 }
44
45 .ui-resizable-handle {
46 top: 0px;
47 height: 7px;
48 background: @light_border_color;
49 border-bottom: 1px solid @border_color;
23 }
50 }
24 .border-box-sizing();
25 }
51 }
@@ -2,6 +2,7 b''
2 padding: 0px;
2 padding: 0px;
3 margin-left: -5px;
3 margin-left: -5px;
4 margin-top: -5px;
4 margin-top: -5px;
5 margin-bottom: 5px;
5
6
6 select, label {
7 select, label {
7 width: auto;
8 width: auto;
@@ -33,8 +34,8 b''
33 border: 0px;
34 border: 0px;
34 min-height: 27px;
35 min-height: 27px;
35 margin-left: 32px;
36 margin-left: 32px;
36 padding-top: 6px;
37 padding-top: 11px;
37 padding-bottom: 8px;
38 padding-bottom: 3px;
38
39
39 .navbar-text {
40 .navbar-text {
40 float: none;
41 float: none;
@@ -44,10 +45,6 b''
44 margin-right: 0px;
45 margin-right: 0px;
45 margin-top: 0px;
46 margin-top: 0px;
46 }
47 }
47
48 .toolbar {
49 margin-top: 0px;
50 }
51 }
48 }
52
49
53 .select-xs {
50 .select-xs {
@@ -10,7 +10,7 b''
10 @notebook_line_height: 20px;
10 @notebook_line_height: 20px;
11 @code_line_height: 1.21429em; // changed from 1.231 to get 17px even
11 @code_line_height: 1.21429em; // changed from 1.231 to get 17px even
12 @code_padding: 0.4em; // 5.6 px
12 @code_padding: 0.4em; // 5.6 px
13 @notebook-shadow: inset 1px 4px 9px -6px rgba(0,0,0,.25);
13 @notebook-shadow: 1px 4px 9px -6px rgba(0,0,0,.25);
14 @rendered_html_border_color: black;
14 @rendered_html_border_color: black;
15 @input_prompt_color: navy;
15 @input_prompt_color: navy;
16 @output_prompt_color: darkred;
16 @output_prompt_color: darkred;
@@ -7751,14 +7751,32 b' body {'
7751 div#header {
7751 div#header {
7752 /* Initially hidden to prevent FLOUC */
7752 /* Initially hidden to prevent FLOUC */
7753 display: none;
7753 display: none;
7754 margin-bottom: -6px;
7755 position: fixed;
7756 top: 0;
7757 width: 100%;
7758 background-color: #ffffff;
7759 min-height: 31px;
7760 /* Display over codemirror */
7761 z-index: 100;
7762 }
7763 div#header #header-container {
7754 margin-bottom: 0px;
7764 margin-bottom: 0px;
7755 padding-left: 30px;
7765 padding-left: 30px;
7756 padding-bottom: 5px;
7766 padding-bottom: 5px;
7757 border-bottom: 1px solid #e7e7e7;
7758 box-sizing: border-box;
7767 box-sizing: border-box;
7759 -moz-box-sizing: border-box;
7768 -moz-box-sizing: border-box;
7760 -webkit-box-sizing: border-box;
7769 -webkit-box-sizing: border-box;
7761 }
7770 }
7771 div#header .header-bar {
7772 width: 100%;
7773 height: 0px;
7774 border-bottom: 1px solid #e7e7e7;
7775 }
7776 #header-spacer {
7777 width: 100%;
7778 visibility: hidden;
7779 }
7762 #ipython_notebook {
7780 #ipython_notebook {
7763 padding-left: 0px;
7781 padding-left: 0px;
7764 }
7782 }
@@ -7981,14 +7999,15 b' span#login_widget > .button .badge,'
7981 margin: 0;
7999 margin: 0;
7982 }
8000 }
7983 .alternate_upload input.fileinput {
8001 .alternate_upload input.fileinput {
7984 background-color: red;
8002 display: inline;
7985 position: relative;
7986 opacity: 0;
8003 opacity: 0;
7987 z-index: 2;
8004 z-index: 2;
7988 width: 295px;
8005 width: 12ex;
7989 margin-left: 163px;
8006 margin-right: -12ex;
7990 cursor: pointer;
8007 }
7991 height: 26px;
8008 .alternate_upload .input-overlay {
8009 display: inline-block;
8010 font-weight: bold;
7992 }
8011 }
7993 /**
8012 /**
7994 * Primary styles
8013 * Primary styles
@@ -8146,6 +8165,21 b' input.engine_num_input {'
8146 .file_icon:before.pull-right {
8165 .file_icon:before.pull-right {
8147 margin-left: .3em;
8166 margin-left: .3em;
8148 }
8167 }
8168 ul#new-notebook-menu {
8169 left: auto;
8170 right: 0;
8171 }
8172 .kernel-menu-icon {
8173 padding-right: 12px;
8174 width: 24px;
8175 content: "\f096";
8176 }
8177 .kernel-menu-icon:before {
8178 content: "\f096";
8179 }
8180 .kernel-menu-icon-current:before {
8181 content: "\f00c";
8182 }
8149 /*!
8183 /*!
8150 *
8184 *
8151 * IPython notebook
8185 * IPython notebook
@@ -9461,9 +9495,6 b' h6:hover .anchor-link {'
9461 body {
9495 body {
9462 background-color: #ffffff;
9496 background-color: #ffffff;
9463 }
9497 }
9464 body.notebook_app {
9465 overflow: hidden;
9466 }
9467 @media (max-width: 767px) {
9498 @media (max-width: 767px) {
9468 body.notebook_app {
9499 body.notebook_app {
9469 padding-left: 0px;
9500 padding-left: 0px;
@@ -9489,8 +9520,6 b' span#notebook_name:hover {'
9489 div#notebook_panel {
9520 div#notebook_panel {
9490 margin: 0px 0px 0px 0px;
9521 margin: 0px 0px 0px 0px;
9491 padding: 0px;
9522 padding: 0px;
9492 -webkit-box-shadow: inset 1px 4px 9px -6px rgba(0, 0, 0, 0.25);
9493 box-shadow: inset 1px 4px 9px -6px rgba(0, 0, 0, 0.25);
9494 box-sizing: border-box;
9523 box-sizing: border-box;
9495 -moz-box-sizing: border-box;
9524 -moz-box-sizing: border-box;
9496 -webkit-box-sizing: border-box;
9525 -webkit-box-sizing: border-box;
@@ -9498,13 +9527,12 b' div#notebook_panel {'
9498 div#notebook {
9527 div#notebook {
9499 font-size: 14px;
9528 font-size: 14px;
9500 line-height: 20px;
9529 line-height: 20px;
9501 overflow-y: scroll;
9530 overflow-y: hidden;
9502 overflow-x: auto;
9531 overflow-x: auto;
9503 width: 100%;
9532 width: 100%;
9504 /* This spaces the cell away from the edge of the notebook area */
9533 /* This spaces the cell away from the edge of the notebook area */
9505 padding: 1em 0 1em 0;
9534 padding: 2em 0 2em 0;
9506 margin: 0px;
9535 margin: 0px;
9507 border-top: 1px solid #e7e7e7;
9508 outline: none;
9536 outline: none;
9509 box-sizing: border-box;
9537 box-sizing: border-box;
9510 -moz-box-sizing: border-box;
9538 -moz-box-sizing: border-box;
@@ -9542,6 +9570,16 b' p {'
9542 .end_space {
9570 .end_space {
9543 height: 200px;
9571 height: 200px;
9544 }
9572 }
9573 .lower-header-bar {
9574 width: 100%;
9575 height: 0px;
9576 border-bottom: 1px solid #e7e7e7;
9577 margin-bottom: -1px;
9578 }
9579 .notebook_app #header {
9580 -webkit-box-shadow: 1px 4px 9px -6px rgba(0, 0, 0, 0.25);
9581 box-shadow: 1px 4px 9px -6px rgba(0, 0, 0, 0.25);
9582 }
9545 /* CSS for the cell toolbar */
9583 /* CSS for the cell toolbar */
9546 .celltoolbar {
9584 .celltoolbar {
9547 border: thin solid #CFCFCF;
9585 border: thin solid #CFCFCF;
@@ -9779,7 +9817,7 b' fieldset[disabled] #kernel_selector_widget > button.active {'
9779 }
9817 }
9780 #menubar {
9818 #menubar {
9781 margin-top: 0px;
9819 margin-top: 0px;
9782 margin-bottom: -19px;
9820 margin-bottom: -24px;
9783 position: relative;
9821 position: relative;
9784 box-sizing: border-box;
9822 box-sizing: border-box;
9785 -moz-box-sizing: border-box;
9823 -moz-box-sizing: border-box;
@@ -9788,6 +9826,7 b' fieldset[disabled] #kernel_selector_widget > button.active {'
9788 #menubar .navbar {
9826 #menubar .navbar {
9789 border-top: 1px;
9827 border-top: 1px;
9790 border-radius: 0px 0px 4px 4px;
9828 border-radius: 0px 0px 4px 4px;
9829 margin-bottom: 23px;
9791 }
9830 }
9792 #menubar .navbar-toggle {
9831 #menubar .navbar-toggle {
9793 float: left;
9832 float: left;
@@ -10256,27 +10295,21 b' fieldset[disabled] .notification_widget.danger.active {'
10256 color: #d9534f;
10295 color: #d9534f;
10257 background-color: #ffffff;
10296 background-color: #ffffff;
10258 }
10297 }
10259 div#pager_splitter {
10260 height: 8px;
10261 box-sizing: border-box;
10262 -moz-box-sizing: border-box;
10263 -webkit-box-sizing: border-box;
10264 }
10265 #pager-container {
10266 position: relative;
10267 padding: 15px 0px;
10268 box-sizing: border-box;
10269 -moz-box-sizing: border-box;
10270 -webkit-box-sizing: border-box;
10271 }
10272 div#pager {
10298 div#pager {
10299 background-color: #ffffff;
10273 font-size: 14px;
10300 font-size: 14px;
10274 line-height: 20px;
10301 line-height: 20px;
10275 overflow: auto;
10302 overflow: hidden;
10276 display: none;
10303 display: none;
10277 box-sizing: border-box;
10304 position: fixed;
10278 -moz-box-sizing: border-box;
10305 bottom: 0px;
10279 -webkit-box-sizing: border-box;
10306 width: 100%;
10307 max-height: 50%;
10308 padding-top: 7px;
10309 /* Display over codemirror */
10310 z-index: 100;
10311 /* Hack which prevents jquery ui resizable from changing top. */
10312 top: inherit !important;
10280 }
10313 }
10281 div#pager pre {
10314 div#pager pre {
10282 line-height: 1.21429em;
10315 line-height: 1.21429em;
@@ -10284,6 +10317,30 b' div#pager pre {'
10284 background-color: #f7f7f7;
10317 background-color: #f7f7f7;
10285 padding: 0.4em;
10318 padding: 0.4em;
10286 }
10319 }
10320 div#pager #pager-button-area {
10321 position: absolute;
10322 top: 7px;
10323 right: 20px;
10324 }
10325 div#pager #pager-contents {
10326 position: relative;
10327 overflow: auto;
10328 width: 100%;
10329 height: 100%;
10330 }
10331 div#pager #pager-contents #pager-container {
10332 position: relative;
10333 padding: 15px 0px;
10334 box-sizing: border-box;
10335 -moz-box-sizing: border-box;
10336 -webkit-box-sizing: border-box;
10337 }
10338 div#pager .ui-resizable-handle {
10339 top: 0px;
10340 height: 7px;
10341 background: #cfcfcf;
10342 border-bottom: 1px solid #ababab;
10343 }
10287 .quickhelp {
10344 .quickhelp {
10288 /* Old browsers */
10345 /* Old browsers */
10289 display: -webkit-box;
10346 display: -webkit-box;
@@ -10350,6 +10407,7 b' span#autosave_status {'
10350 padding: 0px;
10407 padding: 0px;
10351 margin-left: -5px;
10408 margin-left: -5px;
10352 margin-top: -5px;
10409 margin-top: -5px;
10410 margin-bottom: 5px;
10353 box-sizing: border-box;
10411 box-sizing: border-box;
10354 -moz-box-sizing: border-box;
10412 -moz-box-sizing: border-box;
10355 -webkit-box-sizing: border-box;
10413 -webkit-box-sizing: border-box;
@@ -10380,8 +10438,8 b' span#autosave_status {'
10380 border: 0px;
10438 border: 0px;
10381 min-height: 27px;
10439 min-height: 27px;
10382 margin-left: 32px;
10440 margin-left: 32px;
10383 padding-top: 6px;
10441 padding-top: 11px;
10384 padding-bottom: 8px;
10442 padding-bottom: 3px;
10385 }
10443 }
10386 #maintoolbar .navbar-text {
10444 #maintoolbar .navbar-text {
10387 float: none;
10445 float: none;
@@ -10391,9 +10449,6 b' span#autosave_status {'
10391 margin-right: 0px;
10449 margin-right: 0px;
10392 margin-top: 0px;
10450 margin-top: 0px;
10393 }
10451 }
10394 #maintoolbar .toolbar {
10395 margin-top: 0px;
10396 }
10397 .select-xs {
10452 .select-xs {
10398 height: 24px;
10453 height: 24px;
10399 }
10454 }
@@ -8,12 +8,14 b' require(['
8 'base/js/events',
8 'base/js/events',
9 'base/js/page',
9 'base/js/page',
10 'base/js/utils',
10 'base/js/utils',
11 'services/config',
11 'contents',
12 'contents',
12 'tree/js/notebooklist',
13 'tree/js/notebooklist',
13 'tree/js/clusterlist',
14 'tree/js/clusterlist',
14 'tree/js/sessionlist',
15 'tree/js/sessionlist',
15 'tree/js/kernellist',
16 'tree/js/kernellist',
16 'tree/js/terminallist',
17 'tree/js/terminallist',
18 'tree/js/newnotebook',
17 'auth/js/loginwidget',
19 'auth/js/loginwidget',
18 // only loaded, not used:
20 // only loaded, not used:
19 'jqueryui',
21 'jqueryui',
@@ -26,12 +28,14 b' require(['
26 events,
28 events,
27 page,
29 page,
28 utils,
30 utils,
31 config,
29 contents_service,
32 contents_service,
30 notebooklist,
33 notebooklist,
31 clusterlist,
34 clusterlist,
32 sesssionlist,
35 sesssionlist,
33 kernellist,
36 kernellist,
34 terminallist,
37 terminallist,
38 newnotebook,
35 loginwidget){
39 loginwidget){
36 "use strict";
40 "use strict";
37
41
@@ -41,6 +45,10 b' require(['
41 base_url: utils.get_body_data("baseUrl"),
45 base_url: utils.get_body_data("baseUrl"),
42 notebook_path: utils.get_body_data("notebookPath"),
46 notebook_path: utils.get_body_data("notebookPath"),
43 };
47 };
48 var cfg = new config.ConfigSection('tree', common_options);
49 cfg.load();
50 common_options.config = cfg;
51
44 var session_list = new sesssionlist.SesssionList($.extend({
52 var session_list = new sesssionlist.SesssionList($.extend({
45 events: events},
53 events: events},
46 common_options));
54 common_options));
@@ -63,24 +71,12 b' require(['
63
71
64 var login_widget = new loginwidget.LoginWidget('#login_widget', common_options);
72 var login_widget = new loginwidget.LoginWidget('#login_widget', common_options);
65
73
66 $('#new_notebook').click(function (e) {
74 var nnw = new newnotebook.NewNotebookWidget("#new-notebook-buttons",
67 var w = window.open();
75 $.extend(
68 contents.new_untitled(common_options.notebook_path, {type: "notebook"}).then(
76 {contents: contents},
69 function (data) {
77 common_options
70 w.location = utils.url_join_encode(
78 )
71 common_options.base_url, 'notebooks', data.path
79 );
72 );
73 },
74 function(error) {
75 w.close();
76 dialog.modal({
77 title : 'Creating Notebook Failed',
78 body : "The error was: " + error.message,
79 buttons : {'OK' : {'class' : 'btn-primary'}}
80 });
81 }
82 );
83 });
84
80
85 var interval_id=0;
81 var interval_id=0;
86 // auto refresh every xx secondes, no need to be fast,
82 // auto refresh every xx secondes, no need to be fast,
@@ -93,18 +89,18 b' require(['
93 */
89 */
94 session_list.load_sessions();
90 session_list.load_sessions();
95 cluster_list.load_list();
91 cluster_list.load_list();
96 if (terminal_list) {
92 if (terminal_list) {
97 terminal_list.load_terminals();
93 terminal_list.load_terminals();
98 }
94 }
99 if (!interval_id){
95 if (!interval_id){
100 interval_id = setInterval(function(){
96 interval_id = setInterval(function(){
101 session_list.load_sessions();
97 session_list.load_sessions();
102 cluster_list.load_list();
98 cluster_list.load_list();
103 if (terminal_list) {
99 if (terminal_list) {
104 terminal_list.load_terminals();
100 terminal_list.load_terminals();
105 }
101 }
106 }, time_refresh*1000);
102 }, time_refresh*1000);
107 }
103 }
108 };
104 };
109
105
110 var disable_autorefresh = function(){
106 var disable_autorefresh = function(){
@@ -134,6 +130,7 b' require(['
134 IPython.session_list = session_list;
130 IPython.session_list = session_list;
135 IPython.kernel_list = kernel_list;
131 IPython.kernel_list = kernel_list;
136 IPython.login_widget = login_widget;
132 IPython.login_widget = login_widget;
133 IPython.new_notebook_widget = nnw;
137
134
138 events.trigger('app_initialized.DashboardApp');
135 events.trigger('app_initialized.DashboardApp');
139
136
@@ -15,12 +15,14 b''
15
15
16 .alternate_upload input.fileinput
16 .alternate_upload input.fileinput
17 {
17 {
18 background-color:red;
18 display: inline;
19 position:relative;
20 opacity: 0;
19 opacity: 0;
21 z-index: 2;
20 z-index: 2;
22 width: 295px;
21 width: 12ex;
23 margin-left:163px;
22 margin-right: -12ex;
24 cursor: pointer;
23 }
25 height: 26px;
24
25 .alternate_upload .input-overlay {
26 display: inline-block;
27 font-weight: bold;
26 }
28 }
@@ -154,3 +154,23 b' input.engine_num_input {'
154 .file_icon:before {
154 .file_icon:before {
155 .icon(@fa-var-file-o)
155 .icon(@fa-var-file-o)
156 }
156 }
157
158 ul#new-notebook-menu {
159 // align right instead of left
160 left: auto;
161 right: 0;
162 }
163
164 .kernel-menu-icon {
165 padding-right: 12px;
166 width: 24px;
167 content: @fa-var-square-o;
168 }
169
170 .kernel-menu-icon:before {
171 content: @fa-var-square-o;
172 }
173
174 .kernel-menu-icon-current:before {
175 content: @fa-var-check;
176 }
@@ -112,6 +112,7 b' define(['
112 return Promise.resolve(view.render()).then(function() {return view;});
112 return Promise.resolve(view.render()).then(function() {return view;});
113 }).catch(utils.reject("Couldn't create a view for model id '" + String(model.id) + "'", true));
113 }).catch(utils.reject("Couldn't create a view for model id '" + String(model.id) + "'", true));
114 });
114 });
115 model.views[utils.uuid()] = model.state_change;
115 return model.state_change;
116 return model.state_change;
116 };
117 };
117
118
@@ -65,11 +65,12 b' define(["widgets/js/manager",'
65 delete this.comm.model; // Delete ref so GC will collect widget model.
65 delete this.comm.model; // Delete ref so GC will collect widget model.
66 delete this.comm;
66 delete this.comm;
67 delete this.model_id; // Delete id from model so widget manager cleans up.
67 delete this.model_id; // Delete id from model so widget manager cleans up.
68 for (var id in this.views) {
68 _.each(this.views, function(v, id, views) {
69 if (this.views.hasOwnProperty(id)) {
69 v.then(function(view) {
70 this.views[id].remove();
70 view.remove();
71 }
71 delete views[id];
72 }
72 });
73 });
73 },
74 },
74
75
75 _handle_comm_msg: function (msg) {
76 _handle_comm_msg: function (msg) {
@@ -318,8 +319,6 b' define(["widgets/js/manager",'
318 */
319 */
319 this.model.on('change',this.update,this);
320 this.model.on('change',this.update,this);
320 this.options = parameters.options;
321 this.options = parameters.options;
321 this.id = this.id || utils.uuid();
322 this.model.views[this.id] = this;
323 this.on('displayed', function() {
322 this.on('displayed', function() {
324 this.is_displayed = true;
323 this.is_displayed = true;
325 }, this);
324 }, this);
@@ -388,7 +387,7 b' define(["widgets/js/manager",'
388 } else {
387 } else {
389 this.on('displayed', callback, context);
388 this.on('displayed', callback, context);
390 }
389 }
391 },
390 }
392 });
391 });
393
392
394
393
@@ -575,6 +574,10 b' define(["widgets/js/manager",'
575 }
574 }
576 return elements;
575 return elements;
577 },
576 },
577
578 typeset: function(element, text){
579 utils.typeset.apply(null, arguments);
580 },
578 });
581 });
579
582
580
583
@@ -62,8 +62,7 b' define(['
62 if (description.trim().length === 0) {
62 if (description.trim().length === 0) {
63 this.$label.hide();
63 this.$label.hide();
64 } else {
64 } else {
65 this.$label.text(description);
65 this.typeset(this.$label, description);
66 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
67 this.$label.show();
66 this.$label.show();
68 }
67 }
69 }
68 }
@@ -319,8 +319,7 b' define(['
319 if (description.trim().length === 0) {
319 if (description.trim().length === 0) {
320 this.$title.html("&nbsp;"); // Preserve title height
320 this.$title.html("&nbsp;"); // Preserve title height
321 } else {
321 } else {
322 this.$title.text(description);
322 this.typeset(this.$title, description);
323 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$title.get(0)]);
324 }
323 }
325
324
326 var button_text = this.model.get('button_text');
325 var button_text = this.model.get('button_text');
@@ -155,8 +155,7 b' define(['
155 if (description.length === 0) {
155 if (description.length === 0) {
156 this.$label.hide();
156 this.$label.hide();
157 } else {
157 } else {
158 this.$label.text(description);
158 this.typeset(this.$label, description);
159 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
160 this.$label.show();
159 this.$label.show();
161 }
160 }
162
161
@@ -323,8 +322,7 b' define(['
323 if (description.length === 0) {
322 if (description.length === 0) {
324 this.$label.hide();
323 this.$label.hide();
325 } else {
324 } else {
326 this.$label.text(description);
325 this.typeset(this.$label, description);
327 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
328 this.$label.show();
326 this.$label.show();
329 }
327 }
330 }
328 }
@@ -443,8 +441,7 b' define(['
443 if (description.length === 0) {
441 if (description.length === 0) {
444 this.$label.hide();
442 this.$label.hide();
445 } else {
443 } else {
446 this.$label.text(description);
444 this.typeset(this.$label, description);
447 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
448 this.$label.show();
445 this.$label.show();
449 }
446 }
450 return ProgressView.__super__.update.apply(this);
447 return ProgressView.__super__.update.apply(this);
@@ -97,8 +97,7 b' define(['
97 if (description.length === 0) {
97 if (description.length === 0) {
98 this.$label.hide();
98 this.$label.hide();
99 } else {
99 } else {
100 this.$label.text(description);
100 this.typeset(this.$label, description);
101 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
102 this.$label.show();
101 this.$label.show();
103 }
102 }
104 }
103 }
@@ -231,7 +230,7 b' define(['
231 this.$label.hide();
230 this.$label.hide();
232 } else {
231 } else {
233 this.$label.text(description);
232 this.$label.text(description);
234 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
233 this.typeset(this.$label, description);
235 this.$label.show();
234 this.$label.show();
236 }
235 }
237 }
236 }
@@ -345,8 +344,8 b' define(['
345 if (description.length === 0) {
344 if (description.length === 0) {
346 this.$label.hide();
345 this.$label.hide();
347 } else {
346 } else {
348 this.$label.text(description);
347 this.$label.text();
349 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
348 this.typeset(this.$label, description);
350 this.$label.show();
349 this.$label.show();
351 }
350 }
352 }
351 }
@@ -468,8 +467,7 b' define(['
468 if (description.length === 0) {
467 if (description.length === 0) {
469 this.$label.hide();
468 this.$label.hide();
470 } else {
469 } else {
471 this.$label.text(description);
470 this.typeset(this.$label, description);
472 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
473 this.$label.show();
471 this.$label.show();
474 }
472 }
475 }
473 }
@@ -43,9 +43,7 b' define(['
43 * Called when the model is changed. The model may have been
43 * Called when the model is changed. The model may have been
44 * changed by another view or by a state update from the back-end.
44 * changed by another view or by a state update from the back-end.
45 */
45 */
46 this.$el.text(this.model.get('value'));
46 this.typeset(this.$el, this.model.get('value'));
47 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$el.get(0)]);
48
49 return LatexView.__super__.update.apply(this);
47 return LatexView.__super__.update.apply(this);
50 },
48 },
51 });
49 });
@@ -116,8 +114,7 b' define(['
116 if (description.length === 0) {
114 if (description.length === 0) {
117 this.$label.hide();
115 this.$label.hide();
118 } else {
116 } else {
119 this.$label.text(description);
117 this.typeset(this.$label, description);
120 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
121 this.$label.show();
118 this.$label.show();
122 }
119 }
123 }
120 }
@@ -200,8 +197,7 b' define(['
200 if (description.length === 0) {
197 if (description.length === 0) {
201 this.$label.hide();
198 this.$label.hide();
202 } else {
199 } else {
203 this.$label.text(description);
200 this.typeset(this.$label, description);
204 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
205 this.$label.show();
201 this.$label.show();
206 }
202 }
207 }
203 }
@@ -32,7 +32,7 b' class="notebook_app"'
32 {% endblock %}
32 {% endblock %}
33
33
34
34
35 {% block header %}
35 {% block headercontainer %}
36
36
37
37
38 <span id="save_widget" class="nav pull-left">
38 <span id="save_widget" class="nav pull-left">
@@ -43,18 +43,16 b' class="notebook_app"'
43
43
44 <span id="kernel_selector_widget" class="pull-right dropdown">
44 <span id="kernel_selector_widget" class="pull-right dropdown">
45 <button class="dropdown-toggle" data-toggle="dropdown" type='button' id="current_kernel_spec">
45 <button class="dropdown-toggle" data-toggle="dropdown" type='button' id="current_kernel_spec">
46 <span class='kernel_name'>Python</span>
46 <span class='kernel_name'>Kernel</span>
47 <span class="caret"></span>
47 <span class="caret"></span>
48 </button>
48 </button>
49 <ul id="kernel_selector" class="dropdown-menu">
49 <ul id="kernel_selector" class="dropdown-menu">
50 </ul>
50 </ul>
51 </span>
51 </span>
52
52
53 {% endblock %}
53 {% endblock headercontainer %}
54
55
56 {% block site %}
57
54
55 {% block header %}
58 <div id="menubar-container" class="container">
56 <div id="menubar-container" class="container">
59 <div id="menubar">
57 <div id="menubar">
60 <div id="menus" class="navbar navbar-default" role="navigation">
58 <div id="menus" class="navbar navbar-default" role="navigation">
@@ -292,6 +290,7 b' class="notebook_app"'
292 </div>
290 </div>
293 </div>
291 </div>
294 </div>
292 </div>
293
295 <div id="maintoolbar" class="navbar">
294 <div id="maintoolbar" class="navbar">
296 <div class="toolbar-inner navbar-inner navbar-nobg">
295 <div class="toolbar-inner navbar-inner navbar-nobg">
297 <div id="maintoolbar-container" class="container"></div>
296 <div id="maintoolbar-container" class="container"></div>
@@ -299,19 +298,25 b' class="notebook_app"'
299 </div>
298 </div>
300 </div>
299 </div>
301
300
302 <div id="ipython-main-app">
301 <div class="lower-header-bar"></div>
302 {% endblock header %}
303
303
304 {% block site %}
305
306
307 <div id="ipython-main-app">
304 <div id="notebook_panel">
308 <div id="notebook_panel">
305 <div id="notebook"></div>
309 <div id="notebook"></div>
306 <div id="pager_splitter"></div>
307 <div id="pager">
308 <div id='pager_button_area'>
309 </div>
310 <div id="pager-container" class="container"></div>
311 </div>
312 </div>
310 </div>
311 </div>
313
312
313 <div id="pager">
314 <div id="pager-contents">
315 <div id="pager-container" class="container"></div>
316 </div>
317 <div id='pager-button-area'></div>
314 </div>
318 </div>
319
315 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
320 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
316
321
317
322
@@ -5,7 +5,7 b''
5 <meta charset="utf-8">
5 <meta charset="utf-8">
6
6
7 <title>{% block title %}IPython Notebook{% endblock %}</title>
7 <title>{% block title %}IPython Notebook{% endblock %}</title>
8 <link rel="shortcut icon" type="image/x-icon" href="{{static_url("base/images/favicon.ico") }}">
8 {% block favicon %}<link rel="shortcut icon" type="image/x-icon" href="{{static_url("base/images/favicon.ico") }}">{% endblock %}
9 <meta http-equiv="X-UA-Compatible" content="chrome=1">
9 <meta http-equiv="X-UA-Compatible" content="chrome=1">
10 <link rel="stylesheet" href="{{static_url("components/jquery-ui/themes/smoothness/jquery-ui.min.css") }}" type="text/css" />
10 <link rel="stylesheet" href="{{static_url("components/jquery-ui/themes/smoothness/jquery-ui.min.css") }}" type="text/css" />
11 <meta name="viewport" content="width=device-width, initial-scale=1.0">
11 <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -81,7 +81,7 b''
81 </noscript>
81 </noscript>
82
82
83 <div id="header" class="navbar navbar-static-top">
83 <div id="header" class="navbar navbar-static-top">
84 <div class="container">
84 <div id="header-container" class="container">
85 <div id="ipython_notebook" class="nav navbar-brand pull-left"><a href="{{base_url}}tree" alt='dashboard'>{% block logo %}<img src='{{static_url("base/images/logo.png") }}' alt='Jupyter Notebook'/>{% endblock %}</a></div>
85 <div id="ipython_notebook" class="nav navbar-brand pull-left"><a href="{{base_url}}tree" alt='dashboard'>{% block logo %}<img src='{{static_url("base/images/logo.png") }}' alt='Jupyter Notebook'/>{% endblock %}</a></div>
86
86
87 {% block login_widget %}
87 {% block login_widget %}
@@ -96,10 +96,15 b''
96
96
97 {% endblock %}
97 {% endblock %}
98
98
99 {% block header %}
99 {% block headercontainer %}
100 {% endblock %}
100 {% endblock %}
101 </div>
101 </div>
102 <div class="header-bar"></div>
103
104 {% block header %}
105 {% endblock %}
102 </div>
106 </div>
107 <div id="header-spacer"></div>
103
108
104 <div id="site">
109 <div id="site">
105 {% block site %}
110 {% block site %}
@@ -34,19 +34,31 b' data-terminals-available="{{terminals_available}}"'
34 <div class="tab-content">
34 <div class="tab-content">
35 <div id="notebooks" class="tab-pane active">
35 <div id="notebooks" class="tab-pane active">
36 <div id="notebook_toolbar" class="row">
36 <div id="notebook_toolbar" class="row">
37 <div class="col-sm-8 no-padding">
37 <div class="col-sm-12 no-padding">
38 <form id='alternate_upload' class='alternate_upload' >
38 <form id='alternate_upload' class='alternate_upload'>
39 <span id="notebook_list_info" style="position:absolute" >
39 <span id="notebook_list_info">
40 To import a notebook, drag the file onto the listing below or <strong>click here</strong>.
40 To import a notebook, drag the file onto the listing below or
41 <span class="input-overlay">
42 <input type="file" name="datafile" class="fileinput" multiple='multiple'>
43 click here.
44 </span>
41 </span>
45 </span>
42 <input type="file" name="datafile" class="fileinput" multiple='multiple'>
43 </form>
46 </form>
44 </div>
47 <span id="notebook_buttons" class="pull-right">
45 <div class="col-sm-4 no-padding tree-buttons">
48 <div id="new-notebook-buttons" class="btn-group">
46 <span id="notebook_buttons" class="pull-right">
49 <button id="new_notebook" class="btn btn-default btn-xs">
47 <button id="new_notebook" title="Create new notebook" class="btn btn-default btn-xs">New Notebook</button>
50 New Notebook
48 <button id="refresh_notebook_list" title="Refresh notebook list" class="btn btn-default btn-xs"><i class="fa fa-refresh"></i></button>
51 </button>
49 </span>
52 <button class="dropdown-toggle btn btn-default btn-xs" data-toggle="dropdown">
53 <span id="current-kernel">Loading...</span>
54 <span class="caret"></span>
55 </button>
56 <ul id="new-notebook-menu" class="dropdown-menu"></ul>
57 </div>
58
59
60 <button id="refresh_notebook_list" title="Refresh notebook list" class="btn btn-default btn-xs"><i class="fa fa-refresh"></i></button>
61 </span>
50 </div>
62 </div>
51 </div>
63 </div>
52
64
@@ -22,3 +22,8 b' from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, In'
22 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
22 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
23 from .widget_selectioncontainer import TabWidget, AccordionWidget
23 from .widget_selectioncontainer import TabWidget, AccordionWidget
24 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
24 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
25
26 # Warn on import
27 from IPython.utils.warn import warn
28 warn("""The widget API is still considered experimental and
29 may change by the next major release of IPython.""")
@@ -562,7 +562,7 b' class ConnectionFileMixin(LoggingConfigurable):'
562 return self._create_connected_socket('hb', identity=identity)
562 return self._create_connected_socket('hb', identity=identity)
563
563
564 def connect_control(self, identity=None):
564 def connect_control(self, identity=None):
565 """return zmq Socket connected to the Heartbeat channel"""
565 """return zmq Socket connected to the Control channel"""
566 return self._create_connected_socket('control', identity=identity)
566 return self._create_connected_socket('control', identity=identity)
567
567
568
568
@@ -101,25 +101,13 b" def make_ipkernel_cmd(mod='IPython.kernel', executable=None, extra_arguments=[],"
101 executable = sys.executable
101 executable = sys.executable
102 arguments = [ executable, '-m', mod, '-f', '{connection_file}' ]
102 arguments = [ executable, '-m', mod, '-f', '{connection_file}' ]
103 arguments.extend(extra_arguments)
103 arguments.extend(extra_arguments)
104
104
105 if sys.platform == 'win32':
106
107 # If the kernel is running on pythonw and stdout/stderr are not been
108 # re-directed, it will crash when more than 4KB of data is written to
109 # stdout or stderr. This is a bug that has been with Python for a very
110 # long time; see http://bugs.python.org/issue706263.
111 # A cleaner solution to this problem would be to pass os.devnull to
112 # Popen directly. Unfortunately, that does not work.
113 if executable.endswith('pythonw.exe'):
114 arguments.append('--no-stdout')
115 arguments.append('--no-stderr')
116
117 return arguments
105 return arguments
118
106
119
107
120 def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,
108 def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,
121 independent=False,
109 independent=False,
122 cwd=None, ipython_kernel=True,
110 cwd=None,
123 **kw
111 **kw
124 ):
112 ):
125 """ Launches a localhost kernel, binding to the specified ports.
113 """ Launches a localhost kernel, binding to the specified ports.
@@ -141,10 +129,6 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,'
141 cwd : path, optional
129 cwd : path, optional
142 The working dir of the kernel process (default: cwd of this process).
130 The working dir of the kernel process (default: cwd of this process).
143
131
144 ipython_kernel : bool, optional
145 Whether the kernel is an official IPython one,
146 and should get a bit of special treatment.
147
148 Returns
132 Returns
149 -------
133 -------
150
134
@@ -166,14 +150,22 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,'
166 # stderr are all invalid.
150 # stderr are all invalid.
167 redirect_out = sys.executable.endswith('pythonw.exe')
151 redirect_out = sys.executable.endswith('pythonw.exe')
168 if redirect_out:
152 if redirect_out:
169 _stdout = PIPE if stdout is None else stdout
153 blackhole = open(os.devnull, 'w')
170 _stderr = PIPE if stderr is None else stderr
154 _stdout = blackhole if stdout is None else stdout
155 _stderr = blackhole if stderr is None else stderr
171 else:
156 else:
172 _stdout, _stderr = stdout, stderr
157 _stdout, _stderr = stdout, stderr
173
158
174 env = env if (env is not None) else os.environ.copy()
159 env = env if (env is not None) else os.environ.copy()
175
160
176 encoding = getdefaultencoding(prefer_stream=False)
161 encoding = getdefaultencoding(prefer_stream=False)
162 kwargs = dict(
163 stdin=_stdin,
164 stdout=_stdout,
165 stderr=_stderr,
166 cwd=cwd,
167 env=env,
168 )
177
169
178 # Spawn a kernel.
170 # Spawn a kernel.
179 if sys.platform == 'win32':
171 if sys.platform == 'win32':
@@ -181,73 +173,49 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,'
181 cmd = [ cast_bytes_py2(c, encoding) for c in cmd ]
173 cmd = [ cast_bytes_py2(c, encoding) for c in cmd ]
182 if cwd:
174 if cwd:
183 cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii')
175 cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii')
176 kwargs['cwd'] = cwd
184
177
185 from IPython.kernel.zmq.parentpoller import ParentPollerWindows
178 from IPython.kernel.zmq.parentpoller import ParentPollerWindows
186 # Create a Win32 event for interrupting the kernel.
179 # Create a Win32 event for interrupting the kernel
180 # and store it in an environment variable.
187 interrupt_event = ParentPollerWindows.create_interrupt_event()
181 interrupt_event = ParentPollerWindows.create_interrupt_event()
188 # Store this in an environment variable for third party kernels, but at
182 env["JPY_INTERRUPT_EVENT"] = str(interrupt_event)
189 # present, our own kernel expects this as a command line argument.
183 # deprecated old env name:
190 env["IPY_INTERRUPT_EVENT"] = str(interrupt_event)
184 env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"]
191 if ipython_kernel:
185
192 cmd += [ '--interrupt=%i' % interrupt_event ]
186 try:
193
187 from _winapi import DuplicateHandle, GetCurrentProcess, \
194 # If the kernel is running on pythonw and stdout/stderr are not been
188 DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP
195 # re-directed, it will crash when more than 4KB of data is written to
189 except:
196 # stdout or stderr. This is a bug that has been with Python for a very
190 from _subprocess import DuplicateHandle, GetCurrentProcess, \
197 # long time; see http://bugs.python.org/issue706263.
191 DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP
198 # A cleaner solution to this problem would be to pass os.devnull to
192 # Launch the kernel process
199 # Popen directly. Unfortunately, that does not work.
200 if cmd[0].endswith('pythonw.exe'):
201 if stdout is None:
202 cmd.append('--no-stdout')
203 if stderr is None:
204 cmd.append('--no-stderr')
205
206 # Launch the kernel process.
207 if independent:
193 if independent:
208 proc = Popen(cmd,
194 kwargs['creationflags'] = CREATE_NEW_PROCESS_GROUP
209 creationflags=512, # CREATE_NEW_PROCESS_GROUP
210 stdin=_stdin, stdout=_stdout, stderr=_stderr, env=env)
211 else:
195 else:
212 if ipython_kernel:
196 pid = GetCurrentProcess()
213 try:
197 handle = DuplicateHandle(pid, pid, pid, 0,
214 from _winapi import DuplicateHandle, GetCurrentProcess, \
198 True, # Inheritable by new processes.
215 DUPLICATE_SAME_ACCESS
199 DUPLICATE_SAME_ACCESS)
216 except:
200 env['JPY_PARENT_PID'] = str(handle)
217 from _subprocess import DuplicateHandle, GetCurrentProcess, \
201
218 DUPLICATE_SAME_ACCESS
202 proc = Popen(cmd, **kwargs)
219 pid = GetCurrentProcess()
220 handle = DuplicateHandle(pid, pid, pid, 0,
221 True, # Inheritable by new processes.
222 DUPLICATE_SAME_ACCESS)
223 cmd +=[ '--parent=%i' % handle ]
224
225
226 proc = Popen(cmd,
227 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env)
228
203
229 # Attach the interrupt event to the Popen objet so it can be used later.
204 # Attach the interrupt event to the Popen objet so it can be used later.
230 proc.win32_interrupt_event = interrupt_event
205 proc.win32_interrupt_event = interrupt_event
231
206
232 else:
207 else:
233 if independent:
208 if independent:
234 proc = Popen(cmd, preexec_fn=lambda: os.setsid(),
209 kwargs['preexec_fn'] = lambda: os.setsid()
235 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env)
236 else:
210 else:
237 if ipython_kernel:
211 env['JPY_PARENT_PID'] = str(os.getpid())
238 cmd += ['--parent=1']
212
239 proc = Popen(cmd,
213 proc = Popen(cmd, **kwargs)
240 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env)
241
214
242 # Clean up pipes created to work around Popen bug.
215 # Clean up pipes created to work around Popen bug.
243 if redirect_in:
216 if redirect_in:
244 if stdin is None:
217 if stdin is None:
245 proc.stdin.close()
218 proc.stdin.close()
246 if redirect_out:
247 if stdout is None:
248 proc.stdout.close()
249 if stderr is None:
250 proc.stderr.close()
251
219
252 return proc
220 return proc
253
221
@@ -237,7 +237,6 b' class KernelManager(ConnectionFileMixin):'
237 env.update(self.kernel_spec.env or {})
237 env.update(self.kernel_spec.env or {})
238 # launch the kernel subprocess
238 # launch the kernel subprocess
239 self.kernel = self._launch_kernel(kernel_cmd, env=env,
239 self.kernel = self._launch_kernel(kernel_cmd, env=env,
240 ipython_kernel=self.ipython_kernel,
241 **kw)
240 **kw)
242 self.start_restarter()
241 self.start_restarter()
243 self._connect_control_socket()
242 self._connect_control_socket()
@@ -53,11 +53,8 b' kernel_aliases.update({'
53 'stdin' : 'IPKernelApp.stdin_port',
53 'stdin' : 'IPKernelApp.stdin_port',
54 'control' : 'IPKernelApp.control_port',
54 'control' : 'IPKernelApp.control_port',
55 'f' : 'IPKernelApp.connection_file',
55 'f' : 'IPKernelApp.connection_file',
56 'parent': 'IPKernelApp.parent_handle',
57 'transport': 'IPKernelApp.transport',
56 'transport': 'IPKernelApp.transport',
58 })
57 })
59 if sys.platform.startswith('win'):
60 kernel_aliases['interrupt'] = 'IPKernelApp.interrupt'
61
58
62 kernel_flags = dict(base_flags)
59 kernel_flags = dict(base_flags)
63 kernel_flags.update({
60 kernel_flags.update({
@@ -133,11 +130,11 b' class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,'
133 config=True, help="The importstring for the DisplayHook factory")
130 config=True, help="The importstring for the DisplayHook factory")
134
131
135 # polling
132 # polling
136 parent_handle = Integer(0, config=True,
133 parent_handle = Integer(int(os.environ.get('JPY_PARENT_PID') or 0), config=True,
137 help="""kill this process if its parent dies. On Windows, the argument
134 help="""kill this process if its parent dies. On Windows, the argument
138 specifies the HANDLE of the parent process, otherwise it is simply boolean.
135 specifies the HANDLE of the parent process, otherwise it is simply boolean.
139 """)
136 """)
140 interrupt = Integer(0, config=True,
137 interrupt = Integer(int(os.environ.get('JPY_INTERRUPT_EVENT') or 0), config=True,
141 help="""ONLY USED ON WINDOWS
138 help="""ONLY USED ON WINDOWS
142 Interrupt this process when the parent is signaled.
139 Interrupt this process when the parent is signaled.
143 """)
140 """)
@@ -11,14 +11,14 b' except:'
11 import pickle
11 import pickle
12
12
13 # IPython imports
13 # IPython imports
14 from IPython.utils import py3compat
14 from IPython.utils.py3compat import PY3, buffer_to_bytes_py2
15 from IPython.utils.data import flatten
15 from IPython.utils.data import flatten
16 from IPython.utils.pickleutil import (
16 from IPython.utils.pickleutil import (
17 can, uncan, can_sequence, uncan_sequence, CannedObject,
17 can, uncan, can_sequence, uncan_sequence, CannedObject,
18 istype, sequence_types, PICKLE_PROTOCOL,
18 istype, sequence_types, PICKLE_PROTOCOL,
19 )
19 )
20
20
21 if py3compat.PY3:
21 if PY3:
22 buffer = memoryview
22 buffer = memoryview
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
@@ -105,10 +105,7 b' def deserialize_object(buffers, g=None):'
105 (newobj, bufs) : unpacked object, and the list of remaining unused buffers.
105 (newobj, bufs) : unpacked object, and the list of remaining unused buffers.
106 """
106 """
107 bufs = list(buffers)
107 bufs = list(buffers)
108 pobj = bufs.pop(0)
108 pobj = buffer_to_bytes_py2(bufs.pop(0))
109 if not isinstance(pobj, bytes):
110 # a zmq message
111 pobj = bytes(pobj)
112 canned = pickle.loads(pobj)
109 canned = pickle.loads(pobj)
113 if istype(canned, sequence_types) and len(canned) < MAX_ITEMS:
110 if istype(canned, sequence_types) and len(canned) < MAX_ITEMS:
114 for c in canned:
111 for c in canned:
@@ -161,11 +158,10 b' def unpack_apply_message(bufs, g=None, copy=True):'
161 Returns: original f,args,kwargs"""
158 Returns: original f,args,kwargs"""
162 bufs = list(bufs) # allow us to pop
159 bufs = list(bufs) # allow us to pop
163 assert len(bufs) >= 2, "not enough buffers!"
160 assert len(bufs) >= 2, "not enough buffers!"
164 if not copy:
161 pf = buffer_to_bytes_py2(bufs.pop(0))
165 for i in range(2):
162 f = uncan(pickle.loads(pf), g)
166 bufs[i] = bufs[i].bytes
163 pinfo = buffer_to_bytes_py2(bufs.pop(0))
167 f = uncan(pickle.loads(bufs.pop(0)), g)
164 info = pickle.loads(pinfo)
168 info = pickle.loads(bufs.pop(0))
169 arg_bufs, kwarg_bufs = bufs[:info['narg_bufs']], bufs[info['narg_bufs']:]
165 arg_bufs, kwarg_bufs = bufs[:info['narg_bufs']], bufs[info['narg_bufs']:]
170
166
171 args = []
167 args = []
@@ -447,12 +447,13 b' class ZMQInteractiveShell(InteractiveShell):'
447
447
448 return exc_content
448 return exc_content
449
449
450 def set_next_input(self, text):
450 def set_next_input(self, text, replace=False):
451 """Send the specified text to the frontend to be presented at the next
451 """Send the specified text to the frontend to be presented at the next
452 input cell."""
452 input cell."""
453 payload = dict(
453 payload = dict(
454 source='set_next_input',
454 source='set_next_input',
455 text=text
455 text=text,
456 replace=replace,
456 )
457 )
457 self.payload_manager.write_payload(payload)
458 self.payload_manager.write_payload(payload)
458
459
@@ -1,14 +1,33 b''
1 """Generic script exporter class for any kernel language"""
1 """Generic script exporter class for any kernel language"""
2
2
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
5
3 from .templateexporter import TemplateExporter
6 from .templateexporter import TemplateExporter
4
7
8 from IPython.utils.traitlets import Dict
9
5 class ScriptExporter(TemplateExporter):
10 class ScriptExporter(TemplateExporter):
11
12 _exporters = Dict()
13
6 def _template_file_default(self):
14 def _template_file_default(self):
7 return 'script'
15 return 'script'
8
16
9 def from_notebook_node(self, nb, resources=None, **kw):
17 def from_notebook_node(self, nb, resources=None, **kw):
10 langinfo = nb.metadata.get('language_info', {})
18 langinfo = nb.metadata.get('language_info', {})
19
20 # delegate to custom exporter, if specified
21 exporter_name = langinfo.get('nbconvert_exporter')
22 if exporter_name and exporter_name != 'script':
23 self.log.debug("Loading script exporter: %s", exporter_name)
24 from .export import exporter_map
25 if exporter_name not in self._exporters:
26 Exporter = exporter_map[exporter_name]
27 self._exporters[exporter_name] = Exporter(parent=self)
28 exporter = self._exporters[exporter_name]
29 return exporter.from_notebook_node(nb, resources, **kw)
30
11 self.file_extension = langinfo.get('file_extension', '.txt')
31 self.file_extension = langinfo.get('file_extension', '.txt')
12 self.output_mimetype = langinfo.get('mimetype', 'text/plain')
32 self.output_mimetype = langinfo.get('mimetype', 'text/plain')
13
14 return super(ScriptExporter, self).from_notebook_node(nb, resources, **kw)
33 return super(ScriptExporter, self).from_notebook_node(nb, resources, **kw)
@@ -77,7 +77,7 b' class MathBlockGrammar(mistune.BlockGrammar):'
77
77
78 @undoc
78 @undoc
79 class MathBlockLexer(mistune.BlockLexer):
79 class MathBlockLexer(mistune.BlockLexer):
80 default_features = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_features
80 default_rules = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_rules
81
81
82 def __init__(self, rules=None, **kwargs):
82 def __init__(self, rules=None, **kwargs):
83 if rules is None:
83 if rules is None:
@@ -105,7 +105,7 b' class MathInlineGrammar(mistune.InlineGrammar):'
105
105
106 @undoc
106 @undoc
107 class MathInlineLexer(mistune.InlineLexer):
107 class MathInlineLexer(mistune.InlineLexer):
108 default_features = ['math'] + mistune.InlineLexer.default_features
108 default_rules = ['math'] + mistune.InlineLexer.default_rules
109
109
110 def __init__(self, renderer, rules=None, **kwargs):
110 def __init__(self, renderer, rules=None, **kwargs):
111 if rules is None:
111 if rules is None:
@@ -124,10 +124,10 b' class MarkdownWithMath(mistune.Markdown):'
124 kwargs['block'] = MathBlockLexer
124 kwargs['block'] = MathBlockLexer
125 super(MarkdownWithMath, self).__init__(renderer, **kwargs)
125 super(MarkdownWithMath, self).__init__(renderer, **kwargs)
126
126
127 def parse_block_math(self):
127 def output_block_math(self):
128 return self.renderer.block_math(self.token['text'])
128 return self.renderer.block_math(self.token['text'])
129
129
130 def parse_latex_environment(self):
130 def output_latex_environment(self):
131 return self.renderer.latex_environment(self.token['name'], self.token['text'])
131 return self.renderer.latex_environment(self.token['name'], self.token['text'])
132
132
133 @undoc
133 @undoc
@@ -5,6 +5,8 b' Use this module to read or write notebook files as particular nbformat versions.'
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 import io
9 from IPython.utils import py3compat
8
10
9 from IPython.utils.log import get_logger
11 from IPython.utils.log import get_logger
10
12
@@ -112,8 +114,8 b' def read(fp, as_version, **kwargs):'
112
114
113 Parameters
115 Parameters
114 ----------
116 ----------
115 fp : file
117 fp : file or str
116 Any file-like object with a read method.
118 Any file-like object with a read method, or a path to a file.
117 as_version: int
119 as_version: int
118 The version of the notebook format to return.
120 The version of the notebook format to return.
119 The notebook will be converted, if necessary.
121 The notebook will be converted, if necessary.
@@ -124,6 +126,10 b' def read(fp, as_version, **kwargs):'
124 nb : NotebookNode
126 nb : NotebookNode
125 The notebook that was read.
127 The notebook that was read.
126 """
128 """
129 if isinstance(fp, py3compat.string_types):
130 with io.open(fp, encoding='utf-8') as f:
131 return read(f, as_version, **kwargs)
132
127 return reads(fp.read(), as_version, **kwargs)
133 return reads(fp.read(), as_version, **kwargs)
128
134
129
135
@@ -136,14 +142,19 b' def write(nb, fp, version=NO_CONVERT, **kwargs):'
136 ----------
142 ----------
137 nb : NotebookNode
143 nb : NotebookNode
138 The notebook to write.
144 The notebook to write.
139 fp : file
145 fp : file or str
140 Any file-like object with a write method that accepts unicode.
146 Any file-like object with a write method that accepts unicode, or
147 a path to write a file.
141 version : int, optional
148 version : int, optional
142 The nbformat version to write.
149 The nbformat version to write.
143 If nb is not this version, it will be converted.
150 If nb is not this version, it will be converted.
144 If unspecified, or specified as nbformat.NO_CONVERT,
151 If unspecified, or specified as nbformat.NO_CONVERT,
145 the notebook's own version will be used and no conversion performed.
152 the notebook's own version will be used and no conversion performed.
146 """
153 """
154 if isinstance(fp, py3compat.string_types):
155 with io.open(fp, 'w', encoding='utf-8') as f:
156 return write(nb, f, version=version, **kwargs)
157
147 s = writes(nb, version, **kwargs)
158 s = writes(nb, version, **kwargs)
148 if isinstance(s, bytes):
159 if isinstance(s, bytes):
149 s = s.decode('utf8')
160 s = s.decode('utf8')
@@ -4,11 +4,13 b''
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import json
6 import json
7 import os
7
8
8 from .base import TestsBase
9 from .base import TestsBase
9
10
11 from IPython.utils.tempdir import TemporaryDirectory
10 from ..reader import get_version
12 from ..reader import get_version
11 from IPython.nbformat import read, current_nbformat, writes
13 from IPython.nbformat import read, current_nbformat, writes, write
12
14
13
15
14 class TestAPI(TestsBase):
16 class TestAPI(TestsBase):
@@ -35,3 +37,13 b' class TestAPI(TestsBase):'
35 nb2 = json.loads(jsons)
37 nb2 = json.loads(jsons)
36 (major, minor) = get_version(nb2)
38 (major, minor) = get_version(nb2)
37 self.assertEqual(major, 2)
39 self.assertEqual(major, 2)
40
41 def test_read_write_path(self):
42 """read() and write() take filesystem paths"""
43 path = os.path.join(self._get_files_path(), u'test4.ipynb')
44 nb = read(path, as_version=4)
45
46 with TemporaryDirectory() as td:
47 dest = os.path.join(td, 'echidna.ipynb')
48 write(nb, dest)
49 assert os.path.isfile(dest)
@@ -615,10 +615,11 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
615
615
616 if clear:
616 if clear:
617 self._control.clear()
617 self._control.clear()
618 self._append_plain_text(self.banner)
618 if self._display_banner:
619 if self.kernel_banner:
619 self._append_plain_text(self.banner)
620 self._append_plain_text(self.kernel_banner)
620 if self.kernel_banner:
621
621 self._append_plain_text(self.kernel_banner)
622
622 # update output marker for stdout/stderr, so that startup
623 # update output marker for stdout/stderr, so that startup
623 # messages appear after banner:
624 # messages appear after banner:
624 self._append_before_prompt_pos = self._get_cursor().position()
625 self._append_before_prompt_pos = self._get_cursor().position()
@@ -50,6 +50,7 b" if os.name == 'nt':"
50 from IPython.external.qt import QtCore, QtGui
50 from IPython.external.qt import QtCore, QtGui
51
51
52 # Local imports
52 # Local imports
53 from IPython.config.application import boolean_flag
53 from IPython.config.application import catch_config_error
54 from IPython.config.application import catch_config_error
54 from IPython.core.application import BaseIPythonApplication
55 from IPython.core.application import BaseIPythonApplication
55 from IPython.qt.console.ipython_widget import IPythonWidget
56 from IPython.qt.console.ipython_widget import IPythonWidget
@@ -91,6 +92,11 b' qt_flags = {'
91 'plain' : ({'IPythonQtConsoleApp' : {'plain' : True}},
92 'plain' : ({'IPythonQtConsoleApp' : {'plain' : True}},
92 "Disable rich text support."),
93 "Disable rich text support."),
93 }
94 }
95 qt_flags.update(boolean_flag(
96 'banner', 'IPythonQtConsoleApp.display_banner',
97 "Display a banner upon starting the QtConsole.",
98 "Don't display a banner upon starting the QtConsole."
99 ))
94
100
95 # and app_flags from the Console Mixin
101 # and app_flags from the Console Mixin
96 qt_flags.update(app_flags)
102 qt_flags.update(app_flags)
@@ -168,6 +174,10 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):'
168 plain = CBool(False, config=True,
174 plain = CBool(False, config=True,
169 help="Use a plaintext widget instead of rich text (plain can't print/save).")
175 help="Use a plaintext widget instead of rich text (plain can't print/save).")
170
176
177 display_banner = CBool(True, config=True,
178 help="Whether to display a banner upon starting the QtConsole."
179 )
180
171 def _plain_changed(self, name, old, new):
181 def _plain_changed(self, name, old, new):
172 kind = 'plain' if new else 'rich'
182 kind = 'plain' if new else 'rich'
173 self.config.ConsoleWidget.kind = kind
183 self.config.ConsoleWidget.kind = kind
@@ -255,6 +265,7 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):'
255 self.widget._existing = self.existing
265 self.widget._existing = self.existing
256 self.widget._may_close = not self.existing
266 self.widget._may_close = not self.existing
257 self.widget._confirm_exit = self.confirm_exit
267 self.widget._confirm_exit = self.confirm_exit
268 self.widget._display_banner = self.display_banner
258
269
259 self.widget.kernel_manager = self.kernel_manager
270 self.widget.kernel_manager = self.kernel_manager
260 self.widget.kernel_client = self.kernel_client
271 self.widget.kernel_client = self.kernel_client
@@ -17,10 +17,6 b' class ChannelQObject(SuperQObject):'
17 # Emitted when the channel is stopped.
17 # Emitted when the channel is stopped.
18 stopped = QtCore.Signal()
18 stopped = QtCore.Signal()
19
19
20 #---------------------------------------------------------------------------
21 # Channel interface
22 #---------------------------------------------------------------------------
23
24 def start(self):
20 def start(self):
25 """ Reimplemented to emit signal.
21 """ Reimplemented to emit signal.
26 """
22 """
@@ -61,10 +57,6 b' class QtShellChannelMixin(ChannelQObject):'
61 history_reply = QtCore.Signal(object)
57 history_reply = QtCore.Signal(object)
62 kernel_info_reply = QtCore.Signal(object)
58 kernel_info_reply = QtCore.Signal(object)
63
59
64 #---------------------------------------------------------------------------
65 # 'ShellChannel' interface
66 #---------------------------------------------------------------------------
67
68 def call_handlers(self, msg):
60 def call_handlers(self, msg):
69 """ Reimplemented to emit signals instead of making callbacks.
61 """ Reimplemented to emit signals instead of making callbacks.
70 """
62 """
@@ -108,10 +100,6 b' class QtIOPubChannelMixin(ChannelQObject):'
108 # Emitted when a shutdown is noticed.
100 # Emitted when a shutdown is noticed.
109 shutdown_reply_received = QtCore.Signal(object)
101 shutdown_reply_received = QtCore.Signal(object)
110
102
111 #---------------------------------------------------------------------------
112 # 'IOPubChannel' interface
113 #---------------------------------------------------------------------------
114
115 def call_handlers(self, msg):
103 def call_handlers(self, msg):
116 """ Reimplemented to emit signals instead of making callbacks.
104 """ Reimplemented to emit signals instead of making callbacks.
117 """
105 """
@@ -122,8 +110,6 b' class QtIOPubChannelMixin(ChannelQObject):'
122 signal = getattr(self, msg_type + '_received', None)
110 signal = getattr(self, msg_type + '_received', None)
123 if signal:
111 if signal:
124 signal.emit(msg)
112 signal.emit(msg)
125 elif msg_type in ('stdout', 'stderr'):
126 self.stream_received.emit(msg)
127
113
128 def flush(self):
114 def flush(self):
129 """ Reimplemented to ensure that signals are dispatched immediately.
115 """ Reimplemented to ensure that signals are dispatched immediately.
@@ -140,10 +126,6 b' class QtStdInChannelMixin(ChannelQObject):'
140 # Emitted when an input request is received.
126 # Emitted when an input request is received.
141 input_requested = QtCore.Signal(object)
127 input_requested = QtCore.Signal(object)
142
128
143 #---------------------------------------------------------------------------
144 # 'StdInChannel' interface
145 #---------------------------------------------------------------------------
146
147 def call_handlers(self, msg):
129 def call_handlers(self, msg):
148 """ Reimplemented to emit signals instead of making callbacks.
130 """ Reimplemented to emit signals instead of making callbacks.
149 """
131 """
@@ -161,14 +143,9 b' class QtHBChannelMixin(ChannelQObject):'
161 # Emitted when the kernel has died.
143 # Emitted when the kernel has died.
162 kernel_died = QtCore.Signal(object)
144 kernel_died = QtCore.Signal(object)
163
145
164 #---------------------------------------------------------------------------
165 # 'HBChannel' interface
166 #---------------------------------------------------------------------------
167
168 def call_handlers(self, since_last_heartbeat):
146 def call_handlers(self, since_last_heartbeat):
169 """ Reimplemented to emit signals instead of making callbacks.
147 """ Reimplemented to emit signals instead of making callbacks.
170 """
148 """
171 # Emit the generic signal.
172 self.kernel_died.emit(since_last_heartbeat)
149 self.kernel_died.emit(since_last_heartbeat)
173
150
174
151
@@ -529,7 +529,7 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
529 except KeyboardInterrupt:
529 except KeyboardInterrupt:
530 #double-guard against keyboardinterrupts during kbdint handling
530 #double-guard against keyboardinterrupts during kbdint handling
531 try:
531 try:
532 self.write('\nKeyboardInterrupt\n')
532 self.write('\n' + self.get_exception_only())
533 source_raw = self.input_splitter.raw_reset()
533 source_raw = self.input_splitter.raw_reset()
534 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
534 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
535 more = False
535 more = False
@@ -468,7 +468,7 b' class TerminalInteractiveShell(InteractiveShell):'
468 except KeyboardInterrupt:
468 except KeyboardInterrupt:
469 #double-guard against keyboardinterrupts during kbdint handling
469 #double-guard against keyboardinterrupts during kbdint handling
470 try:
470 try:
471 self.write('\nKeyboardInterrupt\n')
471 self.write('\n' + self.get_exception_only())
472 source_raw = self.input_splitter.raw_reset()
472 source_raw = self.input_splitter.raw_reset()
473 hlen_b4_cell = \
473 hlen_b4_cell = \
474 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
474 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
@@ -15,6 +15,7 b' import argparse'
15 import json
15 import json
16 import multiprocessing.pool
16 import multiprocessing.pool
17 import os
17 import os
18 import stat
18 import re
19 import re
19 import requests
20 import requests
20 import shutil
21 import shutil
@@ -170,6 +171,18 b' class PyTestController(TestController):'
170 # This means we won't get odd effects from our own matplotlib config
171 # This means we won't get odd effects from our own matplotlib config
171 self.env['MPLCONFIGDIR'] = workingdir.name
172 self.env['MPLCONFIGDIR'] = workingdir.name
172
173
174 # Add a non-accessible directory to PATH (see gh-7053)
175 noaccess = os.path.join(self.workingdir.name, "_no_access_")
176 self.noaccess = noaccess
177 os.mkdir(noaccess, 0)
178
179 PATH = os.environ.get('PATH', '')
180 if PATH:
181 PATH = noaccess + os.pathsep + PATH
182 else:
183 PATH = noaccess
184 self.env['PATH'] = PATH
185
173 # From options:
186 # From options:
174 if self.options.xunit:
187 if self.options.xunit:
175 self.add_xunit()
188 self.add_xunit()
@@ -178,6 +191,14 b' class PyTestController(TestController):'
178 self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams
191 self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams
179 self.cmd.extend(self.options.extra_args)
192 self.cmd.extend(self.options.extra_args)
180
193
194 def cleanup(self):
195 """
196 Make the non-accessible directory created in setup() accessible
197 again, otherwise deleting the workingdir will fail.
198 """
199 os.chmod(self.noaccess, stat.S_IRWXU)
200 TestController.cleanup(self)
201
181 @property
202 @property
182 def will_run(self):
203 def will_run(self):
183 try:
204 try:
@@ -17,7 +17,7 b' except ImportError:'
17 from . import codeutil # This registers a hook when it's imported
17 from . import codeutil # This registers a hook when it's imported
18 from . import py3compat
18 from . import py3compat
19 from .importstring import import_item
19 from .importstring import import_item
20 from .py3compat import string_types, iteritems
20 from .py3compat import string_types, iteritems, buffer_to_bytes_py2
21
21
22 from IPython.config import Application
22 from IPython.config import Application
23 from IPython.utils.log import get_logger
23 from IPython.utils.log import get_logger
@@ -260,8 +260,8 b' class CannedArray(CannedObject):'
260 from numpy import frombuffer
260 from numpy import frombuffer
261 data = self.buffers[0]
261 data = self.buffers[0]
262 if self.pickled:
262 if self.pickled:
263 # no shape, we just pickled it
263 # we just pickled it
264 return pickle.loads(data)
264 return pickle.loads(buffer_to_bytes_py2(data))
265 else:
265 else:
266 return frombuffer(data, dtype=self.dtype).reshape(self.shape)
266 return frombuffer(data, dtype=self.dtype).reshape(self.shape)
267
267
@@ -30,6 +30,12 b' def cast_bytes(s, encoding=None):'
30 return encode(s, encoding)
30 return encode(s, encoding)
31 return s
31 return s
32
32
33 def buffer_to_bytes(buf):
34 """Cast a buffer object to bytes"""
35 if not isinstance(buf, bytes):
36 buf = bytes(buf)
37 return buf
38
33 def _modify_str_or_docstring(str_change_func):
39 def _modify_str_or_docstring(str_change_func):
34 @functools.wraps(str_change_func)
40 @functools.wraps(str_change_func)
35 def wrapper(func_or_str):
41 def wrapper(func_or_str):
@@ -86,6 +92,7 b' if sys.version_info[0] >= 3:'
86 bytes_to_str = decode
92 bytes_to_str = decode
87 cast_bytes_py2 = no_code
93 cast_bytes_py2 = no_code
88 cast_unicode_py2 = no_code
94 cast_unicode_py2 = no_code
95 buffer_to_bytes_py2 = no_code
89
96
90 string_types = (str,)
97 string_types = (str,)
91 unicode_type = str
98 unicode_type = str
@@ -151,6 +158,7 b' else:'
151 bytes_to_str = no_code
158 bytes_to_str = no_code
152 cast_bytes_py2 = cast_bytes
159 cast_bytes_py2 = cast_bytes
153 cast_unicode_py2 = cast_unicode
160 cast_unicode_py2 = cast_unicode
161 buffer_to_bytes_py2 = buffer_to_bytes
154
162
155 string_types = (str, unicode)
163 string_types = (str, unicode)
156 unicode_type = unicode
164 unicode_type = unicode
@@ -429,6 +429,9 b' The main example being ``%load``.'
429 "source": "set_next_input",
429 "source": "set_next_input",
430 # the text contents of the cell to create
430 # the text contents of the cell to create
431 "text": "some cell content",
431 "text": "some cell content",
432 # If true, replace the current cell in document UIs instead of inserting
433 # a cell. Ignored in console UIs.
434 "replace": bool,
432 }
435 }
433
436
434 **edit**: open a file for editing.
437 **edit**: open a file for editing.
@@ -270,7 +270,7 b' extras_require = dict('
270 test = ['nose>=0.10.1', 'requests'],
270 test = ['nose>=0.10.1', 'requests'],
271 terminal = [],
271 terminal = [],
272 nbformat = ['jsonschema>=2.0'],
272 nbformat = ['jsonschema>=2.0'],
273 notebook = ['tornado>=4.0', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.3.1'],
273 notebook = ['tornado>=4.0', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.5'],
274 nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1']
274 nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1']
275 )
275 )
276
276
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now