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( |
|
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( |
|
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( |
|
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( |
|
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 |
|
|
191 | try: | |
193 |
|
|
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 |
|
|
211 | try: | |
209 |
|
|
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__, |
|
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 |
|
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 |
|
|
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 |
|
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 |
|
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 |
|
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. |
|
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( |
|
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 |
|
|
81 | model = self.ks_api.list().json() | |
82 |
assert isinstance( |
|
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 |
|
|
92 | model = self.ks_api.list().json() | |
90 |
assert isinstance( |
|
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: |
|
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 |
|
|
28 | utils.promising_ajax(url).then($.proxy(this._got_kernelspecs, this)); | |
29 | }; |
|
29 | }; | |
30 |
|
30 | |||
31 |
KernelSelector.prototype._got_kernelspecs = function(data |
|
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 |
|
|
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. |
|
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. |
|
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, |
|
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 |
|
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 |
|
|
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 |
|
|
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 |
|
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 |
|
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: - |
|
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: |
|
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: |
|
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 |
|
|
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: |
|
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: |
|
37 | padding-top: 11px; | |
37 |
padding-bottom: |
|
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: |
|
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: |
|
8005 | width: 12ex; | |
7989 |
margin- |
|
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: |
|
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: |
|
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: - |
|
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: |
|
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: |
|
10441 | padding-top: 11px; | |
10384 |
padding-bottom: |
|
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 |
|
|
92 | if (terminal_list) { | |
97 |
|
|
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 |
|
|
97 | session_list.load_sessions(); | |
102 |
|
|
98 | cluster_list.load_list(); | |
103 |
|
|
99 | if (terminal_list) { | |
104 |
|
|
100 | terminal_list.load_terminals(); | |
105 | } |
|
101 | } | |
106 |
|
|
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: |
|
21 | width: 12ex; | |
23 |
margin- |
|
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 |
|
|
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 |
|
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(" "); // Preserve title height |
|
320 | this.$title.html(" "); // Preserve title height | |
321 | } else { |
|
321 | } else { | |
322 |
this.$title |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
|
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( |
|
347 | this.$label.text(); | |
349 |
|
|
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 |
|
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 |
|
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 |
|
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 |
|
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'> |
|
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- |
|
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" |
|
39 | <span id="notebook_list_info"> | |
40 |
To import a notebook, drag the file onto the listing below or |
|
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 |
< |
|
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 |
|
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, |
|
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 |
_std |
|
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"] = |
|
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 |
|
|
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 |
|
|
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 = |
|
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_ |
|
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_ |
|
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 |
|
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 |
|
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._ |
|
618 | if self._display_banner: | |
619 |
|
|
619 | self._append_plain_text(self.banner) | |
620 |
|
|
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('\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('\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 |
# |
|
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. |
|
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