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 | 277 | try: |
|
278 | 278 | OldPdb.interaction(self, frame, traceback) |
|
279 | 279 | except KeyboardInterrupt: |
|
280 |
self.shell.write( |
|
|
280 | self.shell.write('\n' + self.shell.get_exception_only()) | |
|
281 | 281 | break |
|
282 | 282 | else: |
|
283 | 283 | break |
@@ -40,38 +40,21 b' else:' | |||
|
40 | 40 | #----------------------------------------------------------------------------- |
|
41 | 41 | |
|
42 | 42 | |
|
43 | def _valid_formatter(f): | |
|
44 | """Return whether an object is a valid formatter | |
|
45 | ||
|
46 | Cases checked: | |
|
43 | def _safe_get_formatter_method(obj, name): | |
|
44 | """Safely get a formatter method | |
|
47 | 45 | |
|
48 | - bound methods OK | |
|
49 | - unbound methods NO | |
|
50 | - callable with zero args OK | |
|
46 | - Classes cannot have formatter methods, only instance | |
|
47 | - protect against proxy objects that claim to have everything | |
|
51 | 48 | """ |
|
52 | if f is None: | |
|
53 | return False | |
|
54 | elif isinstance(f, type(str.find)): | |
|
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""" | |
|
49 | if inspect.isclass(obj): | |
|
50 | # repr methods only make sense on instances, not classes | |
|
51 | return None | |
|
72 | 52 | method = pretty._safe_getattr(obj, name, None) |
|
73 | # formatter methods must be bound | |
|
74 | if _valid_formatter(method): | |
|
53 | if callable(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 | 58 | return method |
|
76 | 59 | |
|
77 | 60 |
@@ -22,6 +22,7 b' import re' | |||
|
22 | 22 | import runpy |
|
23 | 23 | import sys |
|
24 | 24 | import tempfile |
|
25 | import traceback | |
|
25 | 26 | import types |
|
26 | 27 | import subprocess |
|
27 | 28 | from io import open as io_open |
@@ -1786,6 +1787,15 b' class InteractiveShell(SingletonConfigurable):' | |||
|
1786 | 1787 | """ |
|
1787 | 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 | 1799 | def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None, |
|
1790 | 1800 | exception_only=False): |
|
1791 | 1801 | """Display the exception that just occurred. |
@@ -1838,7 +1848,7 b' class InteractiveShell(SingletonConfigurable):' | |||
|
1838 | 1848 | self._showtraceback(etype, value, stb) |
|
1839 | 1849 | |
|
1840 | 1850 | except KeyboardInterrupt: |
|
1841 |
self.write_err( |
|
|
1851 | self.write_err('\n' + self.get_exception_only()) | |
|
1842 | 1852 | |
|
1843 | 1853 | def _showtraceback(self, etype, evalue, stb): |
|
1844 | 1854 | """Actually show a traceback. |
@@ -1993,7 +2003,7 b' class InteractiveShell(SingletonConfigurable):' | |||
|
1993 | 2003 | continue |
|
1994 | 2004 | |
|
1995 | 2005 | @skip_doctest |
|
1996 | def set_next_input(self, s): | |
|
2006 | def set_next_input(self, s, replace=False): | |
|
1997 | 2007 | """ Sets the 'default' input string for the next command line. |
|
1998 | 2008 | |
|
1999 | 2009 | Requires readline. |
@@ -2355,7 +2365,7 b' class InteractiveShell(SingletonConfigurable):' | |||
|
2355 | 2365 | try: |
|
2356 | 2366 | ec = os.system(cmd) |
|
2357 | 2367 | except KeyboardInterrupt: |
|
2358 |
self.write_err( |
|
|
2368 | self.write_err('\n' + self.get_exception_only()) | |
|
2359 | 2369 | ec = -2 |
|
2360 | 2370 | else: |
|
2361 | 2371 | cmd = py3compat.unicode_to_str(cmd) |
@@ -2374,7 +2384,7 b' class InteractiveShell(SingletonConfigurable):' | |||
|
2374 | 2384 | ec = subprocess.call(cmd, shell=True, executable=executable) |
|
2375 | 2385 | except KeyboardInterrupt: |
|
2376 | 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 | 2388 | ec = 130 |
|
2379 | 2389 | if ec > 128: |
|
2380 | 2390 | ec = -(ec - 128) |
@@ -353,7 +353,9 b' class CodeMagics(Magics):' | |||
|
353 | 353 | print('Operation cancelled.') |
|
354 | 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 | 360 | @staticmethod |
|
359 | 361 | def _find_edit_target(shell, args, opts, last_call): |
@@ -165,7 +165,6 b' class OSMagics(Magics):' | |||
|
165 | 165 | |
|
166 | 166 | path = [os.path.abspath(os.path.expanduser(p)) for p in |
|
167 | 167 | os.environ.get('PATH','').split(os.pathsep)] |
|
168 | path = filter(os.path.isdir,path) | |
|
169 | 168 | |
|
170 | 169 | syscmdlist = [] |
|
171 | 170 | # Now define isexec in a cross platform manner. |
@@ -189,8 +188,12 b' class OSMagics(Magics):' | |||
|
189 | 188 | # the innermost part |
|
190 | 189 | if os.name == 'posix': |
|
191 | 190 | for pdir in path: |
|
192 |
|
|
|
193 |
|
|
|
191 | try: | |
|
192 | os.chdir(pdir) | |
|
193 | dirlist = os.listdir(pdir) | |
|
194 | except OSError: | |
|
195 | continue | |
|
196 | for ff in dirlist: | |
|
194 | 197 | if isexec(ff): |
|
195 | 198 | try: |
|
196 | 199 | # Removes dots from the name since ipython |
@@ -205,8 +208,12 b' class OSMagics(Magics):' | |||
|
205 | 208 | else: |
|
206 | 209 | no_alias = Alias.blacklist |
|
207 | 210 | for pdir in path: |
|
208 |
|
|
|
209 |
|
|
|
211 | try: | |
|
212 | os.chdir(pdir) | |
|
213 | dirlist = os.listdir(pdir) | |
|
214 | except OSError: | |
|
215 | continue | |
|
216 | for ff in dirlist: | |
|
210 | 217 | base, ext = os.path.splitext(ff) |
|
211 | 218 | if isexec(ff) and base.lower() not in no_alias: |
|
212 | 219 | if ext.lower() == '.exe': |
@@ -314,7 +314,6 b' def test_print_method_bound():' | |||
|
314 | 314 | class MyHTML(object): |
|
315 | 315 | def _repr_html_(self): |
|
316 | 316 | return "hello" |
|
317 | ||
|
318 | 317 | with capture_output() as captured: |
|
319 | 318 | result = f(MyHTML) |
|
320 | 319 | nt.assert_is(result, None) |
@@ -325,6 +324,44 b' def test_print_method_bound():' | |||
|
325 | 324 | nt.assert_equal(result, "hello") |
|
326 | 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 | 365 | def test_format_config(): |
|
329 | 366 | """config objects don't pretend to support fancy reprs with lazy attrs""" |
|
330 | 367 | f = HTMLFormatter() |
@@ -482,6 +482,24 b' class InteractiveShellTestCase(unittest.TestCase):' | |||
|
482 | 482 | mod = ip.new_main_mod(u'%s.py' % name, name) |
|
483 | 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 | 503 | class TestSafeExecfileNonAsciiPath(unittest.TestCase): |
|
486 | 504 | |
|
487 | 505 | @onlyif_unicode_paths |
@@ -245,14 +245,16 b' def fix_frame_records_filenames(records):' | |||
|
245 | 245 | """ |
|
246 | 246 | fixed_records = [] |
|
247 | 247 | for frame, filename, line_no, func_name, lines, index in records: |
|
248 |
# Look inside the frame's globals dictionary for __file__, |
|
|
249 | # be better. | |
|
250 | better_fn = frame.f_globals.get('__file__', None) | |
|
251 | if isinstance(better_fn, str): | |
|
252 | # Check the type just in case someone did something weird with | |
|
253 | # __file__. It might also be None if the error occurred during | |
|
254 | # import. | |
|
255 | filename = better_fn | |
|
248 | # Look inside the frame's globals dictionary for __file__, | |
|
249 | # which should be better. However, keep Cython filenames since | |
|
250 | # we prefer the source filenames over the compiled .so file. | |
|
251 | if not filename.endswith(('.pyx', '.pxd', '.pxi')): | |
|
252 | better_fn = frame.f_globals.get('__file__', None) | |
|
253 | if isinstance(better_fn, str): | |
|
254 | # Check the type just in case someone did something weird with | |
|
255 | # __file__. It might also be None if the error occurred during | |
|
256 | # import. | |
|
257 | filename = better_fn | |
|
256 | 258 | fixed_records.append((frame, filename, line_no, func_name, lines, index)) |
|
257 | 259 | return fixed_records |
|
258 | 260 | |
@@ -722,15 +724,23 b' class VerboseTB(TBTools):' | |||
|
722 | 724 | #print '*** record:',file,lnum,func,lines,index # dbg |
|
723 | 725 | if not file: |
|
724 | 726 | file = '?' |
|
725 |
elif |
|
|
726 | # Guess that filenames like <string> aren't real filenames, so | |
|
727 | # don't call abspath on them. | |
|
728 | try: | |
|
729 | file = abspath(file) | |
|
730 | except OSError: | |
|
731 | # Not sure if this can still happen: abspath now works with | |
|
732 |
|
|
|
733 | pass | |
|
727 | elif file.startswith(str("<")) and file.endswith(str(">")): | |
|
728 | # Not a real filename, no problem... | |
|
729 | pass | |
|
730 | elif not os.path.isabs(file): | |
|
731 | # Try to make the filename absolute by trying all | |
|
732 | # sys.path entries (which is also what linecache does) | |
|
733 | for dirname in sys.path: | |
|
734 | try: | |
|
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 | 744 | file = py3compat.cast_unicode(file, util_path.fs_encoding) |
|
735 | 745 | link = tpl_link % file |
|
736 | 746 | args, varargs, varkw, locals = inspect.getargvalues(frame) |
@@ -611,9 +611,9 b' class FileContentsManager(ContentsManager):' | |||
|
611 | 611 | return "Serving notebooks from local directory: %s" % self.root_dir |
|
612 | 612 | |
|
613 | 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 | 615 | if '/' in path: |
|
616 | 616 | parent_dir = path.rsplit('/', 1)[0] |
|
617 | 617 | else: |
|
618 | 618 | parent_dir = '' |
|
619 |
return |
|
|
619 | return parent_dir |
@@ -187,8 +187,12 b' class ContentsManager(LoggingConfigurable):' | |||
|
187 | 187 | |
|
188 | 188 | KernelManagers can turn this value into a filesystem path, |
|
189 | 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 | 197 | def increment_filename(self, filename, path='', insert=''): |
|
194 | 198 | """Increment a filename until it is unique. |
@@ -54,14 +54,10 b' class MappingKernelManager(MultiKernelManager):' | |||
|
54 | 54 | |
|
55 | 55 | def cwd_for_path(self, path): |
|
56 | 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 | 57 | os_path = to_os_path(path, self.root_dir) |
|
62 | 58 | # in the case of notebooks and kernels not being on the same filesystem, |
|
63 | 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 | 61 | os_path = os.path.dirname(os_path) |
|
66 | 62 | return os_path |
|
67 | 63 |
@@ -7,8 +7,6 b' from tornado import web' | |||
|
7 | 7 | |
|
8 | 8 | from ...base.handlers import IPythonHandler, json_errors |
|
9 | 9 | |
|
10 | from IPython.kernel.kernelspec import _pythonfirst | |
|
11 | ||
|
12 | 10 | |
|
13 | 11 | class MainKernelSpecHandler(IPythonHandler): |
|
14 | 12 | SUPPORTED_METHODS = ('GET',) |
@@ -17,18 +15,21 b' class MainKernelSpecHandler(IPythonHandler):' | |||
|
17 | 15 | @json_errors |
|
18 | 16 | def get(self): |
|
19 | 17 | ksm = self.kernel_spec_manager |
|
20 | results = [] | |
|
21 | for kernel_name in sorted(ksm.find_kernel_specs(), key=_pythonfirst): | |
|
18 | km = self.kernel_manager | |
|
19 | model = {} | |
|
20 | model['default'] = km.default_kernel_name | |
|
21 | model['kernelspecs'] = specs = {} | |
|
22 | for kernel_name in ksm.find_kernel_specs(): | |
|
22 | 23 | try: |
|
23 | 24 | d = ksm.get_kernel_spec(kernel_name).to_dict() |
|
24 | 25 | except Exception: |
|
25 | 26 | self.log.error("Failed to load kernel spec: '%s'", kernel_name, exc_info=True) |
|
26 | 27 | continue |
|
27 | 28 | d['name'] = kernel_name |
|
28 | results.append(d) | |
|
29 | specs[kernel_name] = d | |
|
29 | 30 | |
|
30 | 31 | self.set_header("Content-Type", 'application/json') |
|
31 |
self.finish(json.dumps( |
|
|
32 | self.finish(json.dumps(model)) | |
|
32 | 33 | |
|
33 | 34 | |
|
34 | 35 | class KernelSpecHandler(IPythonHandler): |
@@ -78,16 +78,22 b' class APITest(NotebookTestBase):' | |||
|
78 | 78 | with open(pjoin(bad_kernel_dir, 'kernel.json'), 'w') as f: |
|
79 | 79 | f.write("garbage") |
|
80 | 80 | |
|
81 |
|
|
|
82 |
assert isinstance( |
|
|
81 | model = self.ks_api.list().json() | |
|
82 | assert isinstance(model, dict) | |
|
83 | self.assertEqual(model['default'], NATIVE_KERNEL_NAME) | |
|
84 | specs = model['kernelspecs'] | |
|
85 | assert isinstance(specs, dict) | |
|
83 | 86 | # 2: the sample kernelspec created in setUp, and the native Python kernel |
|
84 | 87 | self.assertGreaterEqual(len(specs), 2) |
|
85 | 88 | |
|
86 | 89 | shutil.rmtree(bad_kernel_dir) |
|
87 | 90 | |
|
88 | 91 | def test_list_kernelspecs(self): |
|
89 |
|
|
|
90 |
assert isinstance( |
|
|
92 | model = self.ks_api.list().json() | |
|
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 | 98 | # 2: the sample kernelspec created in setUp, and the native Python kernel |
|
93 | 99 | self.assertGreaterEqual(len(specs), 2) |
@@ -98,8 +104,8 b' class APITest(NotebookTestBase):' | |||
|
98 | 104 | def is_default_kernelspec(s): |
|
99 | 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 | |
|
102 | assert any(is_default_kernelspec(s) for s in specs), specs | |
|
107 | assert any(is_sample_kernelspec(s) for s in specs.values()), specs | |
|
108 | assert any(is_default_kernelspec(s) for s in specs.values()), specs | |
|
103 | 109 | |
|
104 | 110 | def test_get_kernelspec(self): |
|
105 | 111 | spec = self.ks_api.kernel_spec_info('Sample').json() # Case insensitive |
@@ -4,14 +4,17 b'' | |||
|
4 | 4 | define([ |
|
5 | 5 | 'base/js/namespace', |
|
6 | 6 | 'jquery', |
|
7 | ], function(IPython, $){ | |
|
7 | 'base/js/events', | |
|
8 | ], function(IPython, $, events){ | |
|
8 | 9 | "use strict"; |
|
9 | 10 | |
|
10 | 11 | var Page = function () { |
|
11 | 12 | this.bind_events(); |
|
13 | this._resize_header(); | |
|
12 | 14 | }; |
|
13 | 15 | |
|
14 | 16 | Page.prototype.bind_events = function () { |
|
17 | events.on('resize-header.Page', $.proxy(this._resize_header, this)); | |
|
15 | 18 | }; |
|
16 | 19 | |
|
17 | 20 | Page.prototype.show = function () { |
@@ -41,6 +44,11 b' define([' | |||
|
41 | 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 | 52 | // Register self in the global namespace for convenience. |
|
45 | 53 | IPython.Page = Page; |
|
46 | 54 | return {'Page': Page}; |
@@ -541,7 +541,16 b' define([' | |||
|
541 | 541 | if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux"; |
|
542 | 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 | 554 | var is_or_has = function (a, b) { |
|
546 | 555 | /** |
|
547 | 556 | * Is b a child of a or a itself? |
@@ -632,6 +641,7 b' define([' | |||
|
632 | 641 | * Like $.ajax, but returning an ES6 promise. success and error settings |
|
633 | 642 | * will be ignored. |
|
634 | 643 | */ |
|
644 | settings = settings || {}; | |
|
635 | 645 | return new Promise(function(resolve, reject) { |
|
636 | 646 | settings.success = function(data, status, jqXHR) { |
|
637 | 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 | 806 | var utils = { |
|
770 | 807 | regex_split : regex_split, |
|
771 | 808 | uuid : uuid, |
@@ -786,6 +823,7 b' define([' | |||
|
786 | 823 | from_absolute_cursor_pos : from_absolute_cursor_pos, |
|
787 | 824 | browser : browser, |
|
788 | 825 | platform: platform, |
|
826 | get_url_param: get_url_param, | |
|
789 | 827 | is_or_has : is_or_has, |
|
790 | 828 | is_focused : is_focused, |
|
791 | 829 | mergeopt: mergeopt, |
@@ -799,6 +837,7 b' define([' | |||
|
799 | 837 | load_class: load_class, |
|
800 | 838 | resolve_promises_dict: resolve_promises_dict, |
|
801 | 839 | reject: reject, |
|
840 | typeset: typeset, | |
|
802 | 841 | }; |
|
803 | 842 | |
|
804 | 843 | // Backwards compatability. |
@@ -20,11 +20,33 b' body {' | |||
|
20 | 20 | div#header { |
|
21 | 21 | /* Initially hidden to prevent FLOUC */ |
|
22 | 22 | display: none; |
|
23 |
margin-bottom: |
|
|
24 | padding-left: 30px; | |
|
25 | padding-bottom: 5px; | |
|
26 | border-bottom: 1px solid @navbar-default-border; | |
|
27 | .border-box-sizing(); | |
|
23 | margin-bottom: -6px; | |
|
24 | position: fixed; | |
|
25 | top: 0; | |
|
26 | width: 100%; | |
|
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 | 52 | #ipython_notebook { |
@@ -220,10 +220,7 b' define([' | |||
|
220 | 220 | * @method typeset |
|
221 | 221 | */ |
|
222 | 222 | Cell.prototype.typeset = function () { |
|
223 | if (window.MathJax) { | |
|
224 | var cell_math = this.element.get(0); | |
|
225 | MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]); | |
|
226 | } | |
|
223 | utils.typeset(this.element); | |
|
227 | 224 | }; |
|
228 | 225 | |
|
229 | 226 | /** |
@@ -389,7 +389,7 b' define([' | |||
|
389 | 389 | * @private |
|
390 | 390 | */ |
|
391 | 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 | 393 | this.events.trigger('set_next_input.Notebook', data); |
|
394 | 394 | }; |
|
395 | 395 |
@@ -25,16 +25,27 b' define([' | |||
|
25 | 25 | |
|
26 | 26 | KernelSelector.prototype.request_kernelspecs = function() { |
|
27 | 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 |
|
|
32 |
this.kernelspecs = |
|
|
31 | KernelSelector.prototype._got_kernelspecs = function(data) { | |
|
32 | this.kernelspecs = data.kernelspecs; | |
|
33 | 33 | var menu = this.element.find("#kernel_selector"); |
|
34 | 34 | var change_kernel_submenu = $("#menu-change-kernel-submenu"); |
|
35 | for (var i = 0; i < data.length; i++) { | |
|
36 | var ks = data[i]; | |
|
37 |
|
|
|
35 | var keys = Object.keys(data.kernelspecs).sort(function (a, b) { | |
|
36 | // sort by display_name | |
|
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 | 49 | var ksentry = $("<li>").attr("id", "kernel-" +ks.name).append($('<a>') |
|
39 | 50 | .attr('href', '#') |
|
40 | 51 | .click($.proxy(this.change_kernel, this, ks.name)) |
@@ -9,7 +9,6 b' require([' | |||
|
9 | 9 | 'services/config', |
|
10 | 10 | 'base/js/utils', |
|
11 | 11 | 'base/js/page', |
|
12 | 'notebook/js/layoutmanager', | |
|
13 | 12 | 'base/js/events', |
|
14 | 13 | 'auth/js/loginwidget', |
|
15 | 14 | 'notebook/js/maintoolbar', |
@@ -34,7 +33,6 b' require([' | |||
|
34 | 33 | configmod, |
|
35 | 34 | utils, |
|
36 | 35 | page, |
|
37 | layoutmanager, | |
|
38 | 36 | events, |
|
39 | 37 | loginwidget, |
|
40 | 38 | maintoolbar, |
@@ -66,9 +64,7 b' require([' | |||
|
66 | 64 | |
|
67 | 65 | var user_config = $.extend({}, config.default_config); |
|
68 | 66 | var page = new page.Page(); |
|
69 | var layout_manager = new layoutmanager.LayoutManager(); | |
|
70 | var pager = new pager.Pager('div#pager', 'div#pager_splitter', { | |
|
71 | layout_manager: layout_manager, | |
|
67 | var pager = new pager.Pager('div#pager', { | |
|
72 | 68 | events: events}); |
|
73 | 69 | var acts = new actions.init(); |
|
74 | 70 | var keyboard_manager = new keyboardmanager.KeyboardManager({ |
@@ -104,7 +100,6 b' require([' | |||
|
104 | 100 | var menubar = new menubar.MenuBar('#menubar', $.extend({ |
|
105 | 101 | notebook: notebook, |
|
106 | 102 | contents: contents, |
|
107 | layout_manager: layout_manager, | |
|
108 | 103 | events: events, |
|
109 | 104 | save_widget: save_widget, |
|
110 | 105 | quick_help: quick_help}, |
@@ -132,9 +127,7 b' require([' | |||
|
132 | 127 | |
|
133 | 128 | page.show(); |
|
134 | 129 | |
|
135 | layout_manager.do_resize(); | |
|
136 | 130 | var first_load = function () { |
|
137 | layout_manager.do_resize(); | |
|
138 | 131 | var hash = document.location.hash; |
|
139 | 132 | if (hash) { |
|
140 | 133 | document.location.hash = ''; |
@@ -147,7 +140,6 b' require([' | |||
|
147 | 140 | events.on('notebook_loaded.Notebook', first_load); |
|
148 | 141 | |
|
149 | 142 | IPython.page = page; |
|
150 | IPython.layout_manager = layout_manager; | |
|
151 | 143 | IPython.notebook = notebook; |
|
152 | 144 | IPython.contents = contents; |
|
153 | 145 | IPython.pager = pager; |
@@ -24,7 +24,6 b' define([' | |||
|
24 | 24 | * Dictionary of keyword arguments. |
|
25 | 25 | * notebook: Notebook instance |
|
26 | 26 | * contents: ContentManager instance |
|
27 | * layout_manager: LayoutManager instance | |
|
28 | 27 | * events: $(Events) instance |
|
29 | 28 | * save_widget: SaveWidget instance |
|
30 | 29 | * quick_help: QuickHelp instance |
@@ -37,7 +36,6 b' define([' | |||
|
37 | 36 | this.selector = selector; |
|
38 | 37 | this.notebook = options.notebook; |
|
39 | 38 | this.contents = options.contents; |
|
40 | this.layout_manager = options.layout_manager; | |
|
41 | 39 | this.events = options.events; |
|
42 | 40 | this.save_widget = options.save_widget; |
|
43 | 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 | 96 | MenuBar.prototype.bind_events = function () { |
|
92 | 97 | /** |
|
93 | 98 | * File |
@@ -149,6 +154,10 b' define([' | |||
|
149 | 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 | 161 | this.element.find('#rename_notebook').click(function () { |
|
153 | 162 | that.save_widget.rename_notebook({notebook: that.notebook}); |
|
154 | 163 | }); |
@@ -218,12 +227,12 b' define([' | |||
|
218 | 227 | |
|
219 | 228 | // View |
|
220 | 229 | this.element.find('#toggle_header').click(function () { |
|
221 | $('div#header').toggle(); | |
|
222 |
that. |
|
|
230 | $('div#header-container').toggle(); | |
|
231 | that._size_header(); | |
|
223 | 232 | }); |
|
224 | 233 | this.element.find('#toggle_toolbar').click(function () { |
|
225 | 234 | $('div#maintoolbar').toggle(); |
|
226 |
that. |
|
|
235 | that._size_header(); | |
|
227 | 236 | }); |
|
228 | 237 | // Insert |
|
229 | 238 | this.element.find('#insert_cell_above').click(function () { |
@@ -371,20 +380,6 b' define([' | |||
|
371 | 380 | var langname = (langinfo.name || 'Script') |
|
372 | 381 | langname = langname.charAt(0).toUpperCase()+langname.substr(1) // Capitalise |
|
373 | 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 | 385 | // Backwards compatability. |
@@ -210,9 +210,14 b' define([' | |||
|
210 | 210 | var that = this; |
|
211 | 211 | |
|
212 | 212 | this.events.on('set_next_input.Notebook', function (event, data) { |
|
213 | var index = that.find_cell_index(data.cell); | |
|
214 | var new_cell = that.insert_cell_below('code',index); | |
|
215 | new_cell.set_text(data.text); | |
|
213 | if (data.replace) { | |
|
214 | data.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 | 221 | that.dirty = true; |
|
217 | 222 | }); |
|
218 | 223 | |
@@ -2326,9 +2331,13 b' define([' | |||
|
2326 | 2331 | // Create the session after the notebook is completely loaded to prevent |
|
2327 | 2332 | // code execution upon loading, which is a security risk. |
|
2328 | 2333 | if (this.session === null) { |
|
2329 | var kernelspec = this.metadata.kernelspec || {}; | |
|
2330 | var kernel_name = kernelspec.name; | |
|
2331 | ||
|
2334 | var kernel_name; | |
|
2335 | if (this.metadata.kernelspec) { | |
|
2336 | var kernelspec = this.metadata.kernelspec || {}; | |
|
2337 | kernel_name = kernelspec.name; | |
|
2338 | } else { | |
|
2339 | kernel_name = utils.get_url_param('kernel_name'); | |
|
2340 | } | |
|
2332 | 2341 | this.start_session(kernel_name); |
|
2333 | 2342 | } |
|
2334 | 2343 | // load our checkpoint list |
@@ -199,9 +199,7 b' define([' | |||
|
199 | 199 | |
|
200 | 200 | // typeset with MathJax if MathJax is available |
|
201 | 201 | OutputArea.prototype.typeset = function () { |
|
202 | if (window.MathJax){ | |
|
203 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
|
204 | } | |
|
202 | utils.typeset(this.element); | |
|
205 | 203 | }; |
|
206 | 204 | |
|
207 | 205 |
@@ -8,48 +8,22 b' define([' | |||
|
8 | 8 | ], function(IPython, $, utils) { |
|
9 | 9 | "use strict"; |
|
10 | 10 | |
|
11 |
var Pager = function (pager_selector, |
|
|
11 | var Pager = function (pager_selector, options) { | |
|
12 | 12 | /** |
|
13 | 13 | * Constructor |
|
14 | 14 | * |
|
15 | 15 | * Parameters: |
|
16 | 16 | * pager_selector: string |
|
17 | * pager_splitter_selector: string | |
|
18 | 17 | * options: dictionary |
|
19 | 18 | * Dictionary of keyword arguments. |
|
20 | 19 | * events: $(Events) instance |
|
21 | * layout_manager: LayoutManager instance | |
|
22 | 20 | */ |
|
23 | 21 | this.events = options.events; |
|
24 | 22 | this.pager_element = $(pager_selector); |
|
25 |
this.pager_button_area = $('#pager |
|
|
26 | var that = this; | |
|
27 | this.percentage_height = 0.40; | |
|
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 | }); | |
|
23 | this.pager_button_area = $('#pager-button-area'); | |
|
24 | this._default_end_space = 200; | |
|
25 | this.pager_element.resizable({handles: 'n', resize: $.proxy(this._resize, this)}); | |
|
51 | 26 | this.expanded = false; |
|
52 | this.style(); | |
|
53 | 27 | this.create_button_area(); |
|
54 | 28 | this.bind_events(); |
|
55 | 29 | }; |
@@ -61,7 +35,6 b' define([' | |||
|
61 | 35 | .attr('title',"Open the pager in an external window") |
|
62 | 36 | .addClass('ui-button') |
|
63 | 37 | .click(function(){that.detach();}) |
|
64 | .attr('style','position: absolute; right: 20px;') | |
|
65 | 38 | .append( |
|
66 | 39 | $('<span>').addClass("ui-icon ui-icon-extlink") |
|
67 | 40 | ) |
@@ -71,49 +44,37 b' define([' | |||
|
71 | 44 | .attr('title',"Close the pager") |
|
72 | 45 | .addClass('ui-button') |
|
73 | 46 | .click(function(){that.collapse();}) |
|
74 | .attr('style','position: absolute; right: 5px;') | |
|
75 | 47 | .append( |
|
76 | 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 | 54 | Pager.prototype.bind_events = function () { |
|
88 | 55 | var that = this; |
|
89 | 56 | |
|
90 | 57 | this.pager_element.bind('collapse_pager', function (event, extrap) { |
|
91 | var time = 'fast'; | |
|
92 |
|
|
|
93 | time = extrap.duration; | |
|
94 | } | |
|
95 | that.pager_element.hide(time); | |
|
58 | // Animate hiding of the pager. | |
|
59 | var time = (extrap && extrap.duration) ? extrap.duration : 'fast'; | |
|
60 | that.pager_element.hide(time, function() { | |
|
61 | $('.end_space').css('height', that._default_end_space); | |
|
62 | }); | |
|
96 | 63 | }); |
|
97 | 64 | |
|
98 | 65 | this.pager_element.bind('expand_pager', function (event, extrap) { |
|
99 | var time = 'fast'; | |
|
100 | if (extrap && extrap.duration) { | |
|
101 | time = extrap.duration; | |
|
102 | } | |
|
103 | that.pager_element.show(time); | |
|
104 | }); | |
|
105 | ||
|
106 | this.pager_splitter_element.hover( | |
|
107 | function () { | |
|
108 | that.pager_splitter_element.addClass('ui-state-hover'); | |
|
109 | }, | |
|
110 |
|
|
|
111 | that.pager_splitter_element.removeClass('ui-state-hover'); | |
|
112 | } | |
|
113 | ); | |
|
114 | ||
|
115 | this.pager_splitter_element.click(function () { | |
|
116 | that.toggle(); | |
|
66 | // Clear the pager's height attr if it's set. This allows the | |
|
67 | // pager to size itself according to its contents. | |
|
68 | that.pager_element.height('initial'); | |
|
69 | ||
|
70 | // Animate the showing of the pager | |
|
71 | var time = (extrap && extrap.duration) ? extrap.duration : 'fast'; | |
|
72 | that.pager_element.show(time, function() { | |
|
73 | // Explicitly set pager height once the pager has shown itself. | |
|
74 | // This allows the pager-contents div to use percentage sizing. | |
|
75 | that.pager_element.height(that.pager_element.height()); | |
|
76 | that._resize(); | |
|
77 | }); | |
|
117 | 78 | }); |
|
118 | 79 | |
|
119 | 80 | this.events.on('open_with_text.Pager', function (event, payload) { |
@@ -130,7 +91,7 b' define([' | |||
|
130 | 91 | Pager.prototype.collapse = function (extrap) { |
|
131 | 92 | if (this.expanded === true) { |
|
132 | 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 | 99 | Pager.prototype.expand = function (extrap) { |
|
139 | 100 | if (this.expanded !== true) { |
|
140 | 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 | 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 | 160 | // Backwards compatability. |
|
188 | 161 | IPython.Pager = Pager; |
|
189 | 162 |
@@ -1,12 +1,13 b'' | |||
|
1 | 1 | #menubar { |
|
2 | 2 | margin-top: 0px; |
|
3 |
margin-bottom: - |
|
|
3 | margin-bottom: -24px; | |
|
4 | 4 | position: relative; |
|
5 | 5 | .border-box-sizing(); |
|
6 | 6 | |
|
7 | 7 | .navbar { |
|
8 | 8 | border-top: 1px; |
|
9 | 9 | border-radius: 0px 0px @border-radius-base @border-radius-base; |
|
10 | margin-bottom: 23px; | |
|
10 | 11 | } |
|
11 | 12 | |
|
12 | 13 | .navbar-toggle { |
@@ -3,10 +3,6 b' body {' | |||
|
3 | 3 | background-color: @body-bg; |
|
4 | 4 | } |
|
5 | 5 | |
|
6 | body.notebook_app { | |
|
7 | overflow: hidden; | |
|
8 | } | |
|
9 | ||
|
10 | 6 | @media (max-width: 767px) { |
|
11 | 7 | // remove bootstrap-responsive's body padding on small screens |
|
12 | 8 | body.notebook_app { |
@@ -36,19 +32,17 b' span#notebook_name {' | |||
|
36 | 32 | div#notebook_panel { |
|
37 | 33 | margin: 0px 0px 0px 0px; |
|
38 | 34 | padding: 0px; |
|
39 | .box-shadow(@notebook-shadow); | |
|
40 | 35 | .border-box-sizing(); |
|
41 | 36 | } |
|
42 | 37 | div#notebook { |
|
43 | 38 | font-size: @notebook_font_size; |
|
44 | 39 | line-height: @notebook_line_height; |
|
45 |
overflow-y: |
|
|
40 | overflow-y: hidden; | |
|
46 | 41 | overflow-x: auto; |
|
47 | 42 | width: 100%; |
|
48 | 43 | /* This spaces the cell away from the edge of the notebook area */ |
|
49 |
padding: |
|
|
44 | padding: 2em 0 2em 0; | |
|
50 | 45 | margin: 0px; |
|
51 | border-top: 1px solid @navbar-default-border; | |
|
52 | 46 | outline: none; |
|
53 | 47 | .border-box-sizing(); |
|
54 | 48 | } |
@@ -86,3 +80,14 b' p {' | |||
|
86 | 80 | .end_space { |
|
87 | 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 |
|
|
2 | background-color: @body-bg; | |
|
13 | 3 | font-size: @notebook_font_size; |
|
14 | 4 | line-height: @notebook_line_height; |
|
15 |
overflow: |
|
|
5 | overflow: hidden; | |
|
16 | 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 | 19 | pre { |
|
19 | line-height: @code_line_height; | |
|
20 | color: @text-color; | |
|
21 | background-color: @cell_background; | |
|
22 | padding: @code_padding; | |
|
20 | line-height: @code_line_height; | |
|
21 | color: @text-color; | |
|
22 | background-color: @cell_background; | |
|
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 | 2 | padding: 0px; |
|
3 | 3 | margin-left: -5px; |
|
4 | 4 | margin-top: -5px; |
|
5 | margin-bottom: 5px; | |
|
5 | 6 | |
|
6 | 7 | select, label { |
|
7 | 8 | width: auto; |
@@ -33,8 +34,8 b'' | |||
|
33 | 34 | border: 0px; |
|
34 | 35 | min-height: 27px; |
|
35 | 36 | margin-left: 32px; |
|
36 |
padding-top: |
|
|
37 |
padding-bottom: |
|
|
37 | padding-top: 11px; | |
|
38 | padding-bottom: 3px; | |
|
38 | 39 | |
|
39 | 40 | .navbar-text { |
|
40 | 41 | float: none; |
@@ -44,10 +45,6 b'' | |||
|
44 | 45 | margin-right: 0px; |
|
45 | 46 | margin-top: 0px; |
|
46 | 47 | } |
|
47 | ||
|
48 | .toolbar { | |
|
49 | margin-top: 0px; | |
|
50 | } | |
|
51 | 48 | } |
|
52 | 49 | |
|
53 | 50 | .select-xs { |
@@ -10,7 +10,7 b'' | |||
|
10 | 10 | @notebook_line_height: 20px; |
|
11 | 11 | @code_line_height: 1.21429em; // changed from 1.231 to get 17px even |
|
12 | 12 | @code_padding: 0.4em; // 5.6 px |
|
13 |
@notebook-shadow: |
|
|
13 | @notebook-shadow: 1px 4px 9px -6px rgba(0,0,0,.25); | |
|
14 | 14 | @rendered_html_border_color: black; |
|
15 | 15 | @input_prompt_color: navy; |
|
16 | 16 | @output_prompt_color: darkred; |
@@ -7751,14 +7751,32 b' body {' | |||
|
7751 | 7751 | div#header { |
|
7752 | 7752 | /* Initially hidden to prevent FLOUC */ |
|
7753 | 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 | 7764 | margin-bottom: 0px; |
|
7755 | 7765 | padding-left: 30px; |
|
7756 | 7766 | padding-bottom: 5px; |
|
7757 | border-bottom: 1px solid #e7e7e7; | |
|
7758 | 7767 | box-sizing: border-box; |
|
7759 | 7768 | -moz-box-sizing: border-box; |
|
7760 | 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 | 7780 | #ipython_notebook { |
|
7763 | 7781 | padding-left: 0px; |
|
7764 | 7782 | } |
@@ -7981,14 +7999,15 b' span#login_widget > .button .badge,' | |||
|
7981 | 7999 | margin: 0; |
|
7982 | 8000 | } |
|
7983 | 8001 | .alternate_upload input.fileinput { |
|
7984 | background-color: red; | |
|
7985 | position: relative; | |
|
8002 | display: inline; | |
|
7986 | 8003 | opacity: 0; |
|
7987 | 8004 | z-index: 2; |
|
7988 |
width: |
|
|
7989 |
margin- |
|
|
7990 | cursor: pointer; | |
|
7991 | height: 26px; | |
|
8005 | width: 12ex; | |
|
8006 | margin-right: -12ex; | |
|
8007 | } | |
|
8008 | .alternate_upload .input-overlay { | |
|
8009 | display: inline-block; | |
|
8010 | font-weight: bold; | |
|
7992 | 8011 | } |
|
7993 | 8012 | /** |
|
7994 | 8013 | * Primary styles |
@@ -8146,6 +8165,21 b' input.engine_num_input {' | |||
|
8146 | 8165 | .file_icon:before.pull-right { |
|
8147 | 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 | 8185 | * IPython notebook |
@@ -9461,9 +9495,6 b' h6:hover .anchor-link {' | |||
|
9461 | 9495 | body { |
|
9462 | 9496 | background-color: #ffffff; |
|
9463 | 9497 | } |
|
9464 | body.notebook_app { | |
|
9465 | overflow: hidden; | |
|
9466 | } | |
|
9467 | 9498 | @media (max-width: 767px) { |
|
9468 | 9499 | body.notebook_app { |
|
9469 | 9500 | padding-left: 0px; |
@@ -9489,8 +9520,6 b' span#notebook_name:hover {' | |||
|
9489 | 9520 | div#notebook_panel { |
|
9490 | 9521 | margin: 0px 0px 0px 0px; |
|
9491 | 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 | 9523 | box-sizing: border-box; |
|
9495 | 9524 | -moz-box-sizing: border-box; |
|
9496 | 9525 | -webkit-box-sizing: border-box; |
@@ -9498,13 +9527,12 b' div#notebook_panel {' | |||
|
9498 | 9527 | div#notebook { |
|
9499 | 9528 | font-size: 14px; |
|
9500 | 9529 | line-height: 20px; |
|
9501 |
overflow-y: |
|
|
9530 | overflow-y: hidden; | |
|
9502 | 9531 | overflow-x: auto; |
|
9503 | 9532 | width: 100%; |
|
9504 | 9533 | /* This spaces the cell away from the edge of the notebook area */ |
|
9505 |
padding: |
|
|
9534 | padding: 2em 0 2em 0; | |
|
9506 | 9535 | margin: 0px; |
|
9507 | border-top: 1px solid #e7e7e7; | |
|
9508 | 9536 | outline: none; |
|
9509 | 9537 | box-sizing: border-box; |
|
9510 | 9538 | -moz-box-sizing: border-box; |
@@ -9542,6 +9570,16 b' p {' | |||
|
9542 | 9570 | .end_space { |
|
9543 | 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 | 9583 | /* CSS for the cell toolbar */ |
|
9546 | 9584 | .celltoolbar { |
|
9547 | 9585 | border: thin solid #CFCFCF; |
@@ -9779,7 +9817,7 b' fieldset[disabled] #kernel_selector_widget > button.active {' | |||
|
9779 | 9817 | } |
|
9780 | 9818 | #menubar { |
|
9781 | 9819 | margin-top: 0px; |
|
9782 |
margin-bottom: - |
|
|
9820 | margin-bottom: -24px; | |
|
9783 | 9821 | position: relative; |
|
9784 | 9822 | box-sizing: border-box; |
|
9785 | 9823 | -moz-box-sizing: border-box; |
@@ -9788,6 +9826,7 b' fieldset[disabled] #kernel_selector_widget > button.active {' | |||
|
9788 | 9826 | #menubar .navbar { |
|
9789 | 9827 | border-top: 1px; |
|
9790 | 9828 | border-radius: 0px 0px 4px 4px; |
|
9829 | margin-bottom: 23px; | |
|
9791 | 9830 | } |
|
9792 | 9831 | #menubar .navbar-toggle { |
|
9793 | 9832 | float: left; |
@@ -10256,27 +10295,21 b' fieldset[disabled] .notification_widget.danger.active {' | |||
|
10256 | 10295 | color: #d9534f; |
|
10257 | 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 | 10298 | div#pager { |
|
10299 | background-color: #ffffff; | |
|
10273 | 10300 | font-size: 14px; |
|
10274 | 10301 | line-height: 20px; |
|
10275 |
overflow: |
|
|
10302 | overflow: hidden; | |
|
10276 | 10303 | display: none; |
|
10277 | box-sizing: border-box; | |
|
10278 | -moz-box-sizing: border-box; | |
|
10279 | -webkit-box-sizing: border-box; | |
|
10304 | position: fixed; | |
|
10305 | bottom: 0px; | |
|
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 | 10314 | div#pager pre { |
|
10282 | 10315 | line-height: 1.21429em; |
@@ -10284,6 +10317,30 b' div#pager pre {' | |||
|
10284 | 10317 | background-color: #f7f7f7; |
|
10285 | 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 | 10344 | .quickhelp { |
|
10288 | 10345 | /* Old browsers */ |
|
10289 | 10346 | display: -webkit-box; |
@@ -10350,6 +10407,7 b' span#autosave_status {' | |||
|
10350 | 10407 | padding: 0px; |
|
10351 | 10408 | margin-left: -5px; |
|
10352 | 10409 | margin-top: -5px; |
|
10410 | margin-bottom: 5px; | |
|
10353 | 10411 | box-sizing: border-box; |
|
10354 | 10412 | -moz-box-sizing: border-box; |
|
10355 | 10413 | -webkit-box-sizing: border-box; |
@@ -10380,8 +10438,8 b' span#autosave_status {' | |||
|
10380 | 10438 | border: 0px; |
|
10381 | 10439 | min-height: 27px; |
|
10382 | 10440 | margin-left: 32px; |
|
10383 |
padding-top: |
|
|
10384 |
padding-bottom: |
|
|
10441 | padding-top: 11px; | |
|
10442 | padding-bottom: 3px; | |
|
10385 | 10443 | } |
|
10386 | 10444 | #maintoolbar .navbar-text { |
|
10387 | 10445 | float: none; |
@@ -10391,9 +10449,6 b' span#autosave_status {' | |||
|
10391 | 10449 | margin-right: 0px; |
|
10392 | 10450 | margin-top: 0px; |
|
10393 | 10451 | } |
|
10394 | #maintoolbar .toolbar { | |
|
10395 | margin-top: 0px; | |
|
10396 | } | |
|
10397 | 10452 | .select-xs { |
|
10398 | 10453 | height: 24px; |
|
10399 | 10454 | } |
@@ -8,12 +8,14 b' require([' | |||
|
8 | 8 | 'base/js/events', |
|
9 | 9 | 'base/js/page', |
|
10 | 10 | 'base/js/utils', |
|
11 | 'services/config', | |
|
11 | 12 | 'contents', |
|
12 | 13 | 'tree/js/notebooklist', |
|
13 | 14 | 'tree/js/clusterlist', |
|
14 | 15 | 'tree/js/sessionlist', |
|
15 | 16 | 'tree/js/kernellist', |
|
16 | 17 | 'tree/js/terminallist', |
|
18 | 'tree/js/newnotebook', | |
|
17 | 19 | 'auth/js/loginwidget', |
|
18 | 20 | // only loaded, not used: |
|
19 | 21 | 'jqueryui', |
@@ -26,12 +28,14 b' require([' | |||
|
26 | 28 | events, |
|
27 | 29 | page, |
|
28 | 30 | utils, |
|
31 | config, | |
|
29 | 32 | contents_service, |
|
30 |
notebooklist, |
|
|
31 |
clusterlist, |
|
|
32 |
sesssionlist, |
|
|
33 | notebooklist, | |
|
34 | clusterlist, | |
|
35 | sesssionlist, | |
|
33 | 36 | kernellist, |
|
34 | 37 | terminallist, |
|
38 | newnotebook, | |
|
35 | 39 | loginwidget){ |
|
36 | 40 | "use strict"; |
|
37 | 41 | |
@@ -41,6 +45,10 b' require([' | |||
|
41 | 45 | base_url: utils.get_body_data("baseUrl"), |
|
42 | 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 | 52 | var session_list = new sesssionlist.SesssionList($.extend({ |
|
45 | 53 | events: events}, |
|
46 | 54 | common_options)); |
@@ -63,24 +71,12 b' require([' | |||
|
63 | 71 | |
|
64 | 72 | var login_widget = new loginwidget.LoginWidget('#login_widget', common_options); |
|
65 | 73 | |
|
66 | $('#new_notebook').click(function (e) { | |
|
67 | var w = window.open(); | |
|
68 | contents.new_untitled(common_options.notebook_path, {type: "notebook"}).then( | |
|
69 | function (data) { | |
|
70 | w.location = utils.url_join_encode( | |
|
71 | common_options.base_url, 'notebooks', data.path | |
|
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 | }); | |
|
74 | var nnw = new newnotebook.NewNotebookWidget("#new-notebook-buttons", | |
|
75 | $.extend( | |
|
76 | {contents: contents}, | |
|
77 | common_options | |
|
78 | ) | |
|
79 | ); | |
|
84 | 80 | |
|
85 | 81 | var interval_id=0; |
|
86 | 82 | // auto refresh every xx secondes, no need to be fast, |
@@ -93,18 +89,18 b' require([' | |||
|
93 | 89 | */ |
|
94 | 90 | session_list.load_sessions(); |
|
95 | 91 | cluster_list.load_list(); |
|
96 |
|
|
|
97 |
|
|
|
98 | } | |
|
92 | if (terminal_list) { | |
|
93 | terminal_list.load_terminals(); | |
|
94 | } | |
|
99 | 95 | if (!interval_id){ |
|
100 | 96 | interval_id = setInterval(function(){ |
|
101 |
|
|
|
102 |
|
|
|
103 |
|
|
|
104 |
|
|
|
105 | } | |
|
106 |
|
|
|
107 |
|
|
|
97 | session_list.load_sessions(); | |
|
98 | cluster_list.load_list(); | |
|
99 | if (terminal_list) { | |
|
100 | terminal_list.load_terminals(); | |
|
101 | } | |
|
102 | }, time_refresh*1000); | |
|
103 | } | |
|
108 | 104 | }; |
|
109 | 105 | |
|
110 | 106 | var disable_autorefresh = function(){ |
@@ -134,6 +130,7 b' require([' | |||
|
134 | 130 | IPython.session_list = session_list; |
|
135 | 131 | IPython.kernel_list = kernel_list; |
|
136 | 132 | IPython.login_widget = login_widget; |
|
133 | IPython.new_notebook_widget = nnw; | |
|
137 | 134 | |
|
138 | 135 | events.trigger('app_initialized.DashboardApp'); |
|
139 | 136 |
@@ -15,12 +15,14 b'' | |||
|
15 | 15 | |
|
16 | 16 | .alternate_upload input.fileinput |
|
17 | 17 | { |
|
18 | background-color:red; | |
|
19 | position:relative; | |
|
18 | display: inline; | |
|
20 | 19 | opacity: 0; |
|
21 | 20 | z-index: 2; |
|
22 |
width: |
|
|
23 |
margin- |
|
|
24 | cursor: pointer; | |
|
25 | height: 26px; | |
|
21 | width: 12ex; | |
|
22 | margin-right: -12ex; | |
|
23 | } | |
|
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 | 154 | .file_icon:before { |
|
155 | 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 | 112 | return Promise.resolve(view.render()).then(function() {return view;}); |
|
113 | 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 | 116 | return model.state_change; |
|
116 | 117 | }; |
|
117 | 118 |
@@ -65,11 +65,12 b' define(["widgets/js/manager",' | |||
|
65 | 65 | delete this.comm.model; // Delete ref so GC will collect widget model. |
|
66 | 66 | delete this.comm; |
|
67 | 67 | delete this.model_id; // Delete id from model so widget manager cleans up. |
|
68 | for (var id in this.views) { | |
|
69 | if (this.views.hasOwnProperty(id)) { | |
|
70 |
|
|
|
71 | } | |
|
72 | } | |
|
68 | _.each(this.views, function(v, id, views) { | |
|
69 | v.then(function(view) { | |
|
70 | view.remove(); | |
|
71 | delete views[id]; | |
|
72 | }); | |
|
73 | }); | |
|
73 | 74 | }, |
|
74 | 75 | |
|
75 | 76 | _handle_comm_msg: function (msg) { |
@@ -318,8 +319,6 b' define(["widgets/js/manager",' | |||
|
318 | 319 | */ |
|
319 | 320 | this.model.on('change',this.update,this); |
|
320 | 321 | this.options = parameters.options; |
|
321 | this.id = this.id || utils.uuid(); | |
|
322 | this.model.views[this.id] = this; | |
|
323 | 322 | this.on('displayed', function() { |
|
324 | 323 | this.is_displayed = true; |
|
325 | 324 | }, this); |
@@ -388,7 +387,7 b' define(["widgets/js/manager",' | |||
|
388 | 387 | } else { |
|
389 | 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 | 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 | 62 | if (description.trim().length === 0) { |
|
63 | 63 | this.$label.hide(); |
|
64 | 64 | } else { |
|
65 |
this.$label |
|
|
66 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]); | |
|
65 | this.typeset(this.$label, description); | |
|
67 | 66 | this.$label.show(); |
|
68 | 67 | } |
|
69 | 68 | } |
@@ -319,8 +319,7 b' define([' | |||
|
319 | 319 | if (description.trim().length === 0) { |
|
320 | 320 | this.$title.html(" "); // Preserve title height |
|
321 | 321 | } else { |
|
322 |
this.$title |
|
|
323 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$title.get(0)]); | |
|
322 | this.typeset(this.$title, description); | |
|
324 | 323 | } |
|
325 | 324 | |
|
326 | 325 | var button_text = this.model.get('button_text'); |
@@ -155,8 +155,7 b' define([' | |||
|
155 | 155 | if (description.length === 0) { |
|
156 | 156 | this.$label.hide(); |
|
157 | 157 | } else { |
|
158 |
this.$label |
|
|
159 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]); | |
|
158 | this.typeset(this.$label, description); | |
|
160 | 159 | this.$label.show(); |
|
161 | 160 | } |
|
162 | 161 | |
@@ -323,8 +322,7 b' define([' | |||
|
323 | 322 | if (description.length === 0) { |
|
324 | 323 | this.$label.hide(); |
|
325 | 324 | } else { |
|
326 |
this.$label |
|
|
327 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]); | |
|
325 | this.typeset(this.$label, description); | |
|
328 | 326 | this.$label.show(); |
|
329 | 327 | } |
|
330 | 328 | } |
@@ -443,8 +441,7 b' define([' | |||
|
443 | 441 | if (description.length === 0) { |
|
444 | 442 | this.$label.hide(); |
|
445 | 443 | } else { |
|
446 |
this.$label |
|
|
447 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]); | |
|
444 | this.typeset(this.$label, description); | |
|
448 | 445 | this.$label.show(); |
|
449 | 446 | } |
|
450 | 447 | return ProgressView.__super__.update.apply(this); |
@@ -97,8 +97,7 b' define([' | |||
|
97 | 97 | if (description.length === 0) { |
|
98 | 98 | this.$label.hide(); |
|
99 | 99 | } else { |
|
100 |
this.$label |
|
|
101 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]); | |
|
100 | this.typeset(this.$label, description); | |
|
102 | 101 | this.$label.show(); |
|
103 | 102 | } |
|
104 | 103 | } |
@@ -231,7 +230,7 b' define([' | |||
|
231 | 230 | this.$label.hide(); |
|
232 | 231 | } else { |
|
233 | 232 | this.$label.text(description); |
|
234 |
|
|
|
233 | this.typeset(this.$label, description); | |
|
235 | 234 | this.$label.show(); |
|
236 | 235 | } |
|
237 | 236 | } |
@@ -345,8 +344,8 b' define([' | |||
|
345 | 344 | if (description.length === 0) { |
|
346 | 345 | this.$label.hide(); |
|
347 | 346 | } else { |
|
348 |
this.$label.text( |
|
|
349 |
|
|
|
347 | this.$label.text(); | |
|
348 | this.typeset(this.$label, description); | |
|
350 | 349 | this.$label.show(); |
|
351 | 350 | } |
|
352 | 351 | } |
@@ -468,8 +467,7 b' define([' | |||
|
468 | 467 | if (description.length === 0) { |
|
469 | 468 | this.$label.hide(); |
|
470 | 469 | } else { |
|
471 |
this.$label |
|
|
472 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]); | |
|
470 | this.typeset(this.$label, description); | |
|
473 | 471 | this.$label.show(); |
|
474 | 472 | } |
|
475 | 473 | } |
@@ -43,9 +43,7 b' define([' | |||
|
43 | 43 | * Called when the model is changed. The model may have been |
|
44 | 44 | * changed by another view or by a state update from the back-end. |
|
45 | 45 | */ |
|
46 |
this.$el |
|
|
47 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$el.get(0)]); | |
|
48 | ||
|
46 | this.typeset(this.$el, this.model.get('value')); | |
|
49 | 47 | return LatexView.__super__.update.apply(this); |
|
50 | 48 | }, |
|
51 | 49 | }); |
@@ -116,8 +114,7 b' define([' | |||
|
116 | 114 | if (description.length === 0) { |
|
117 | 115 | this.$label.hide(); |
|
118 | 116 | } else { |
|
119 |
this.$label |
|
|
120 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]); | |
|
117 | this.typeset(this.$label, description); | |
|
121 | 118 | this.$label.show(); |
|
122 | 119 | } |
|
123 | 120 | } |
@@ -200,8 +197,7 b' define([' | |||
|
200 | 197 | if (description.length === 0) { |
|
201 | 198 | this.$label.hide(); |
|
202 | 199 | } else { |
|
203 |
this.$label |
|
|
204 | MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]); | |
|
200 | this.typeset(this.$label, description); | |
|
205 | 201 | this.$label.show(); |
|
206 | 202 | } |
|
207 | 203 | } |
@@ -32,7 +32,7 b' class="notebook_app"' | |||
|
32 | 32 | {% endblock %} |
|
33 | 33 | |
|
34 | 34 | |
|
35 | {% block header %} | |
|
35 | {% block headercontainer %} | |
|
36 | 36 | |
|
37 | 37 | |
|
38 | 38 | <span id="save_widget" class="nav pull-left"> |
@@ -43,18 +43,16 b' class="notebook_app"' | |||
|
43 | 43 | |
|
44 | 44 | <span id="kernel_selector_widget" class="pull-right dropdown"> |
|
45 | 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 | 47 | <span class="caret"></span> |
|
48 | 48 | </button> |
|
49 | 49 | <ul id="kernel_selector" class="dropdown-menu"> |
|
50 | 50 | </ul> |
|
51 | 51 | </span> |
|
52 | 52 | |
|
53 | {% endblock %} | |
|
54 | ||
|
55 | ||
|
56 | {% block site %} | |
|
53 | {% endblock headercontainer %} | |
|
57 | 54 | |
|
55 | {% block header %} | |
|
58 | 56 | <div id="menubar-container" class="container"> |
|
59 | 57 | <div id="menubar"> |
|
60 | 58 | <div id="menus" class="navbar navbar-default" role="navigation"> |
@@ -292,6 +290,7 b' class="notebook_app"' | |||
|
292 | 290 | </div> |
|
293 | 291 | </div> |
|
294 | 292 | </div> |
|
293 | ||
|
295 | 294 | <div id="maintoolbar" class="navbar"> |
|
296 | 295 | <div class="toolbar-inner navbar-inner navbar-nobg"> |
|
297 | 296 | <div id="maintoolbar-container" class="container"></div> |
@@ -299,19 +298,25 b' class="notebook_app"' | |||
|
299 | 298 | </div> |
|
300 | 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 | 308 | <div id="notebook_panel"> |
|
305 | 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 | 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 | 318 | </div> |
|
319 | ||
|
315 | 320 | <div id='tooltip' class='ipython_tooltip' style='display:none'></div> |
|
316 | 321 | |
|
317 | 322 |
@@ -5,7 +5,7 b'' | |||
|
5 | 5 | <meta charset="utf-8"> |
|
6 | 6 | |
|
7 | 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 | 9 | <meta http-equiv="X-UA-Compatible" content="chrome=1"> |
|
10 | 10 | <link rel="stylesheet" href="{{static_url("components/jquery-ui/themes/smoothness/jquery-ui.min.css") }}" type="text/css" /> |
|
11 | 11 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
@@ -81,7 +81,7 b'' | |||
|
81 | 81 | </noscript> |
|
82 | 82 | |
|
83 | 83 | <div id="header" class="navbar navbar-static-top"> |
|
84 | <div class="container"> | |
|
84 | <div id="header-container" class="container"> | |
|
85 | 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 | 87 | {% block login_widget %} |
@@ -96,10 +96,15 b'' | |||
|
96 | 96 | |
|
97 | 97 | {% endblock %} |
|
98 | 98 | |
|
99 | {% block header %} | |
|
99 | {% block headercontainer %} | |
|
100 | 100 | {% endblock %} |
|
101 | 101 | </div> |
|
102 | <div class="header-bar"></div> | |
|
103 | ||
|
104 | {% block header %} | |
|
105 | {% endblock %} | |
|
102 | 106 | </div> |
|
107 | <div id="header-spacer"></div> | |
|
103 | 108 | |
|
104 | 109 | <div id="site"> |
|
105 | 110 | {% block site %} |
@@ -34,19 +34,31 b' data-terminals-available="{{terminals_available}}"' | |||
|
34 | 34 | <div class="tab-content"> |
|
35 | 35 | <div id="notebooks" class="tab-pane active"> |
|
36 | 36 | <div id="notebook_toolbar" class="row"> |
|
37 |
<div class="col-sm- |
|
|
38 |
<form id='alternate_upload' class='alternate_upload' |
|
|
39 |
<span id="notebook_list_info" |
|
|
40 |
To import a notebook, drag the file onto the listing below or |
|
|
37 | <div class="col-sm-12 no-padding"> | |
|
38 | <form id='alternate_upload' class='alternate_upload'> | |
|
39 | <span id="notebook_list_info"> | |
|
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 | 45 | </span> |
|
42 | <input type="file" name="datafile" class="fileinput" multiple='multiple'> | |
|
43 | 46 | </form> |
|
44 | </div> | |
|
45 | <div class="col-sm-4 no-padding tree-buttons"> | |
|
46 |
< |
|
|
47 | <button id="new_notebook" title="Create new notebook" class="btn btn-default btn-xs">New Notebook</button> | |
|
48 | <button id="refresh_notebook_list" title="Refresh notebook list" class="btn btn-default btn-xs"><i class="fa fa-refresh"></i></button> | |
|
49 | </span> | |
|
47 | <span id="notebook_buttons" class="pull-right"> | |
|
48 | <div id="new-notebook-buttons" class="btn-group"> | |
|
49 | <button id="new_notebook" class="btn btn-default btn-xs"> | |
|
50 | New Notebook | |
|
51 | </button> | |
|
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 | 62 | </div> |
|
51 | 63 | </div> |
|
52 | 64 |
@@ -22,3 +22,8 b' from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, In' | |||
|
22 | 22 | from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget |
|
23 | 23 | from .widget_selectioncontainer import TabWidget, AccordionWidget |
|
24 | 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 | 562 | return self._create_connected_socket('hb', identity=identity) |
|
563 | 563 | |
|
564 | 564 | def connect_control(self, identity=None): |
|
565 |
"""return zmq Socket connected to the |
|
|
565 | """return zmq Socket connected to the Control channel""" | |
|
566 | 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 | 101 | executable = sys.executable |
|
102 | 102 | arguments = [ executable, '-m', mod, '-f', '{connection_file}' ] |
|
103 | 103 | arguments.extend(extra_arguments) |
|
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 | ||
|
104 | ||
|
117 | 105 | return arguments |
|
118 | 106 | |
|
119 | 107 | |
|
120 | 108 | def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None, |
|
121 | 109 | independent=False, |
|
122 |
cwd=None, |
|
|
110 | cwd=None, | |
|
123 | 111 | **kw |
|
124 | 112 | ): |
|
125 | 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 | 129 | cwd : path, optional |
|
142 | 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 | 132 | Returns |
|
149 | 133 | ------- |
|
150 | 134 | |
@@ -166,14 +150,22 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,' | |||
|
166 | 150 | # stderr are all invalid. |
|
167 | 151 | redirect_out = sys.executable.endswith('pythonw.exe') |
|
168 | 152 | if redirect_out: |
|
169 | _stdout = PIPE if stdout is None else stdout | |
|
170 |
_std |
|
|
153 | blackhole = open(os.devnull, 'w') | |
|
154 | _stdout = blackhole if stdout is None else stdout | |
|
155 | _stderr = blackhole if stderr is None else stderr | |
|
171 | 156 | else: |
|
172 | 157 | _stdout, _stderr = stdout, stderr |
|
173 | 158 | |
|
174 | 159 | env = env if (env is not None) else os.environ.copy() |
|
175 | 160 | |
|
176 | 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 | 170 | # Spawn a kernel. |
|
179 | 171 | if sys.platform == 'win32': |
@@ -181,73 +173,49 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,' | |||
|
181 | 173 | cmd = [ cast_bytes_py2(c, encoding) for c in cmd ] |
|
182 | 174 | if cwd: |
|
183 | 175 | cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii') |
|
176 | kwargs['cwd'] = cwd | |
|
184 | 177 | |
|
185 | 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 | 181 | interrupt_event = ParentPollerWindows.create_interrupt_event() |
|
188 | # Store this in an environment variable for third party kernels, but at | |
|
189 | # present, our own kernel expects this as a command line argument. | |
|
190 |
env["IPY_INTERRUPT_EVENT"] = |
|
|
191 | if ipython_kernel: | |
|
192 | cmd += [ '--interrupt=%i' % interrupt_event ] | |
|
193 | ||
|
194 | # If the kernel is running on pythonw and stdout/stderr are not been | |
|
195 | # re-directed, it will crash when more than 4KB of data is written to | |
|
196 | # stdout or stderr. This is a bug that has been with Python for a very | |
|
197 | # long time; see http://bugs.python.org/issue706263. | |
|
198 | # A cleaner solution to this problem would be to pass os.devnull to | |
|
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. | |
|
182 | env["JPY_INTERRUPT_EVENT"] = str(interrupt_event) | |
|
183 | # deprecated old env name: | |
|
184 | env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"] | |
|
185 | ||
|
186 | try: | |
|
187 | from _winapi import DuplicateHandle, GetCurrentProcess, \ | |
|
188 | DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP | |
|
189 | except: | |
|
190 | from _subprocess import DuplicateHandle, GetCurrentProcess, \ | |
|
191 | DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP | |
|
192 | # Launch the kernel process | |
|
207 | 193 | if independent: |
|
208 | proc = Popen(cmd, | |
|
209 | creationflags=512, # CREATE_NEW_PROCESS_GROUP | |
|
210 | stdin=_stdin, stdout=_stdout, stderr=_stderr, env=env) | |
|
194 | kwargs['creationflags'] = CREATE_NEW_PROCESS_GROUP | |
|
211 | 195 | else: |
|
212 | if ipython_kernel: | |
|
213 | try: | |
|
214 | from _winapi import DuplicateHandle, GetCurrentProcess, \ | |
|
215 | DUPLICATE_SAME_ACCESS | |
|
216 | except: | |
|
217 | from _subprocess import DuplicateHandle, GetCurrentProcess, \ | |
|
218 | DUPLICATE_SAME_ACCESS | |
|
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) | |
|
196 | pid = GetCurrentProcess() | |
|
197 | handle = DuplicateHandle(pid, pid, pid, 0, | |
|
198 | True, # Inheritable by new processes. | |
|
199 | DUPLICATE_SAME_ACCESS) | |
|
200 | env['JPY_PARENT_PID'] = str(handle) | |
|
201 | ||
|
202 | proc = Popen(cmd, **kwargs) | |
|
228 | 203 | |
|
229 | 204 | # Attach the interrupt event to the Popen objet so it can be used later. |
|
230 | 205 | proc.win32_interrupt_event = interrupt_event |
|
231 | 206 | |
|
232 | 207 | else: |
|
233 | 208 | if independent: |
|
234 |
|
|
|
235 | stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env) | |
|
209 | kwargs['preexec_fn'] = lambda: os.setsid() | |
|
236 | 210 | else: |
|
237 | if ipython_kernel: | |
|
238 | cmd += ['--parent=1'] | |
|
239 |
|
|
|
240 | stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env) | |
|
211 | env['JPY_PARENT_PID'] = str(os.getpid()) | |
|
212 | ||
|
213 | proc = Popen(cmd, **kwargs) | |
|
241 | 214 | |
|
242 | 215 | # Clean up pipes created to work around Popen bug. |
|
243 | 216 | if redirect_in: |
|
244 | 217 | if stdin is None: |
|
245 | 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 | 220 | return proc |
|
253 | 221 |
@@ -237,7 +237,6 b' class KernelManager(ConnectionFileMixin):' | |||
|
237 | 237 | env.update(self.kernel_spec.env or {}) |
|
238 | 238 | # launch the kernel subprocess |
|
239 | 239 | self.kernel = self._launch_kernel(kernel_cmd, env=env, |
|
240 | ipython_kernel=self.ipython_kernel, | |
|
241 | 240 | **kw) |
|
242 | 241 | self.start_restarter() |
|
243 | 242 | self._connect_control_socket() |
@@ -53,11 +53,8 b' kernel_aliases.update({' | |||
|
53 | 53 | 'stdin' : 'IPKernelApp.stdin_port', |
|
54 | 54 | 'control' : 'IPKernelApp.control_port', |
|
55 | 55 | 'f' : 'IPKernelApp.connection_file', |
|
56 | 'parent': 'IPKernelApp.parent_handle', | |
|
57 | 56 | 'transport': 'IPKernelApp.transport', |
|
58 | 57 | }) |
|
59 | if sys.platform.startswith('win'): | |
|
60 | kernel_aliases['interrupt'] = 'IPKernelApp.interrupt' | |
|
61 | 58 | |
|
62 | 59 | kernel_flags = dict(base_flags) |
|
63 | 60 | kernel_flags.update({ |
@@ -133,11 +130,11 b' class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,' | |||
|
133 | 130 | config=True, help="The importstring for the DisplayHook factory") |
|
134 | 131 | |
|
135 | 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 | 134 | help="""kill this process if its parent dies. On Windows, the argument |
|
138 | 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 | 138 | help="""ONLY USED ON WINDOWS |
|
142 | 139 | Interrupt this process when the parent is signaled. |
|
143 | 140 | """) |
@@ -11,14 +11,14 b' except:' | |||
|
11 | 11 | import pickle |
|
12 | 12 | |
|
13 | 13 | # IPython imports |
|
14 | from IPython.utils import py3compat | |
|
14 | from IPython.utils.py3compat import PY3, buffer_to_bytes_py2 | |
|
15 | 15 | from IPython.utils.data import flatten |
|
16 | 16 | from IPython.utils.pickleutil import ( |
|
17 | 17 | can, uncan, can_sequence, uncan_sequence, CannedObject, |
|
18 | 18 | istype, sequence_types, PICKLE_PROTOCOL, |
|
19 | 19 | ) |
|
20 | 20 | |
|
21 | if py3compat.PY3: | |
|
21 | if PY3: | |
|
22 | 22 | buffer = memoryview |
|
23 | 23 | |
|
24 | 24 | #----------------------------------------------------------------------------- |
@@ -105,10 +105,7 b' def deserialize_object(buffers, g=None):' | |||
|
105 | 105 | (newobj, bufs) : unpacked object, and the list of remaining unused buffers. |
|
106 | 106 | """ |
|
107 | 107 | bufs = list(buffers) |
|
108 | pobj = bufs.pop(0) | |
|
109 | if not isinstance(pobj, bytes): | |
|
110 | # a zmq message | |
|
111 | pobj = bytes(pobj) | |
|
108 | pobj = buffer_to_bytes_py2(bufs.pop(0)) | |
|
112 | 109 | canned = pickle.loads(pobj) |
|
113 | 110 | if istype(canned, sequence_types) and len(canned) < MAX_ITEMS: |
|
114 | 111 | for c in canned: |
@@ -161,11 +158,10 b' def unpack_apply_message(bufs, g=None, copy=True):' | |||
|
161 | 158 | Returns: original f,args,kwargs""" |
|
162 | 159 | bufs = list(bufs) # allow us to pop |
|
163 | 160 | assert len(bufs) >= 2, "not enough buffers!" |
|
164 | if not copy: | |
|
165 | for i in range(2): | |
|
166 | bufs[i] = bufs[i].bytes | |
|
167 |
f = |
|
|
168 | info = pickle.loads(bufs.pop(0)) | |
|
161 | pf = buffer_to_bytes_py2(bufs.pop(0)) | |
|
162 | f = uncan(pickle.loads(pf), g) | |
|
163 | pinfo = buffer_to_bytes_py2(bufs.pop(0)) | |
|
164 | info = pickle.loads(pinfo) | |
|
169 | 165 | arg_bufs, kwarg_bufs = bufs[:info['narg_bufs']], bufs[info['narg_bufs']:] |
|
170 | 166 | |
|
171 | 167 | args = [] |
@@ -447,12 +447,13 b' class ZMQInteractiveShell(InteractiveShell):' | |||
|
447 | 447 | |
|
448 | 448 | return exc_content |
|
449 | 449 | |
|
450 | def set_next_input(self, text): | |
|
450 | def set_next_input(self, text, replace=False): | |
|
451 | 451 | """Send the specified text to the frontend to be presented at the next |
|
452 | 452 | input cell.""" |
|
453 | 453 | payload = dict( |
|
454 | 454 | source='set_next_input', |
|
455 | text=text | |
|
455 | text=text, | |
|
456 | replace=replace, | |
|
456 | 457 | ) |
|
457 | 458 | self.payload_manager.write_payload(payload) |
|
458 | 459 |
@@ -1,14 +1,33 b'' | |||
|
1 | 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 | 6 | from .templateexporter import TemplateExporter |
|
4 | 7 | |
|
8 | from IPython.utils.traitlets import Dict | |
|
9 | ||
|
5 | 10 | class ScriptExporter(TemplateExporter): |
|
11 | ||
|
12 | _exporters = Dict() | |
|
13 | ||
|
6 | 14 | def _template_file_default(self): |
|
7 | 15 | return 'script' |
|
8 | 16 | |
|
9 | 17 | def from_notebook_node(self, nb, resources=None, **kw): |
|
10 | 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 | 31 | self.file_extension = langinfo.get('file_extension', '.txt') |
|
12 | 32 | self.output_mimetype = langinfo.get('mimetype', 'text/plain') |
|
13 | ||
|
14 | 33 | return super(ScriptExporter, self).from_notebook_node(nb, resources, **kw) |
@@ -77,7 +77,7 b' class MathBlockGrammar(mistune.BlockGrammar):' | |||
|
77 | 77 | |
|
78 | 78 | @undoc |
|
79 | 79 | class MathBlockLexer(mistune.BlockLexer): |
|
80 |
default_ |
|
|
80 | default_rules = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_rules | |
|
81 | 81 | |
|
82 | 82 | def __init__(self, rules=None, **kwargs): |
|
83 | 83 | if rules is None: |
@@ -105,7 +105,7 b' class MathInlineGrammar(mistune.InlineGrammar):' | |||
|
105 | 105 | |
|
106 | 106 | @undoc |
|
107 | 107 | class MathInlineLexer(mistune.InlineLexer): |
|
108 |
default_ |
|
|
108 | default_rules = ['math'] + mistune.InlineLexer.default_rules | |
|
109 | 109 | |
|
110 | 110 | def __init__(self, renderer, rules=None, **kwargs): |
|
111 | 111 | if rules is None: |
@@ -124,10 +124,10 b' class MarkdownWithMath(mistune.Markdown):' | |||
|
124 | 124 | kwargs['block'] = MathBlockLexer |
|
125 | 125 | super(MarkdownWithMath, self).__init__(renderer, **kwargs) |
|
126 | 126 | |
|
127 |
def |
|
|
127 | def output_block_math(self): | |
|
128 | 128 | return self.renderer.block_math(self.token['text']) |
|
129 | 129 | |
|
130 |
def |
|
|
130 | def output_latex_environment(self): | |
|
131 | 131 | return self.renderer.latex_environment(self.token['name'], self.token['text']) |
|
132 | 132 | |
|
133 | 133 | @undoc |
@@ -5,6 +5,8 b' Use this module to read or write notebook files as particular nbformat versions.' | |||
|
5 | 5 | |
|
6 | 6 | # Copyright (c) IPython Development Team. |
|
7 | 7 | # Distributed under the terms of the Modified BSD License. |
|
8 | import io | |
|
9 | from IPython.utils import py3compat | |
|
8 | 10 | |
|
9 | 11 | from IPython.utils.log import get_logger |
|
10 | 12 | |
@@ -112,8 +114,8 b' def read(fp, as_version, **kwargs):' | |||
|
112 | 114 | |
|
113 | 115 | Parameters |
|
114 | 116 | ---------- |
|
115 | fp : file | |
|
116 | Any file-like object with a read method. | |
|
117 | fp : file or str | |
|
118 | Any file-like object with a read method, or a path to a file. | |
|
117 | 119 | as_version: int |
|
118 | 120 | The version of the notebook format to return. |
|
119 | 121 | The notebook will be converted, if necessary. |
@@ -124,6 +126,10 b' def read(fp, as_version, **kwargs):' | |||
|
124 | 126 | nb : NotebookNode |
|
125 | 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 | 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 | 143 | nb : NotebookNode |
|
138 | 144 | The notebook to write. |
|
139 | fp : file | |
|
140 |
Any file-like object with a write method that accepts unicode |
|
|
145 | fp : file or str | |
|
146 | Any file-like object with a write method that accepts unicode, or | |
|
147 | a path to write a file. | |
|
141 | 148 | version : int, optional |
|
142 | 149 | The nbformat version to write. |
|
143 | 150 | If nb is not this version, it will be converted. |
|
144 | 151 | If unspecified, or specified as nbformat.NO_CONVERT, |
|
145 | 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 | 158 | s = writes(nb, version, **kwargs) |
|
148 | 159 | if isinstance(s, bytes): |
|
149 | 160 | s = s.decode('utf8') |
@@ -4,11 +4,13 b'' | |||
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | import json |
|
7 | import os | |
|
7 | 8 | |
|
8 | 9 | from .base import TestsBase |
|
9 | 10 | |
|
11 | from IPython.utils.tempdir import TemporaryDirectory | |
|
10 | 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 | 16 | class TestAPI(TestsBase): |
@@ -35,3 +37,13 b' class TestAPI(TestsBase):' | |||
|
35 | 37 | nb2 = json.loads(jsons) |
|
36 | 38 | (major, minor) = get_version(nb2) |
|
37 | 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 | 616 | if clear: |
|
617 | 617 | self._control.clear() |
|
618 |
self._ |
|
|
619 |
|
|
|
620 |
|
|
|
621 | ||
|
618 | if self._display_banner: | |
|
619 | self._append_plain_text(self.banner) | |
|
620 | if self.kernel_banner: | |
|
621 | self._append_plain_text(self.kernel_banner) | |
|
622 | ||
|
622 | 623 | # update output marker for stdout/stderr, so that startup |
|
623 | 624 | # messages appear after banner: |
|
624 | 625 | self._append_before_prompt_pos = self._get_cursor().position() |
@@ -50,6 +50,7 b" if os.name == 'nt':" | |||
|
50 | 50 | from IPython.external.qt import QtCore, QtGui |
|
51 | 51 | |
|
52 | 52 | # Local imports |
|
53 | from IPython.config.application import boolean_flag | |
|
53 | 54 | from IPython.config.application import catch_config_error |
|
54 | 55 | from IPython.core.application import BaseIPythonApplication |
|
55 | 56 | from IPython.qt.console.ipython_widget import IPythonWidget |
@@ -91,6 +92,11 b' qt_flags = {' | |||
|
91 | 92 | 'plain' : ({'IPythonQtConsoleApp' : {'plain' : True}}, |
|
92 | 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 | 101 | # and app_flags from the Console Mixin |
|
96 | 102 | qt_flags.update(app_flags) |
@@ -168,6 +174,10 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||
|
168 | 174 | plain = CBool(False, config=True, |
|
169 | 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 | 181 | def _plain_changed(self, name, old, new): |
|
172 | 182 | kind = 'plain' if new else 'rich' |
|
173 | 183 | self.config.ConsoleWidget.kind = kind |
@@ -255,6 +265,7 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||
|
255 | 265 | self.widget._existing = self.existing |
|
256 | 266 | self.widget._may_close = not self.existing |
|
257 | 267 | self.widget._confirm_exit = self.confirm_exit |
|
268 | self.widget._display_banner = self.display_banner | |
|
258 | 269 | |
|
259 | 270 | self.widget.kernel_manager = self.kernel_manager |
|
260 | 271 | self.widget.kernel_client = self.kernel_client |
@@ -17,10 +17,6 b' class ChannelQObject(SuperQObject):' | |||
|
17 | 17 | # Emitted when the channel is stopped. |
|
18 | 18 | stopped = QtCore.Signal() |
|
19 | 19 | |
|
20 | #--------------------------------------------------------------------------- | |
|
21 | # Channel interface | |
|
22 | #--------------------------------------------------------------------------- | |
|
23 | ||
|
24 | 20 | def start(self): |
|
25 | 21 | """ Reimplemented to emit signal. |
|
26 | 22 | """ |
@@ -61,10 +57,6 b' class QtShellChannelMixin(ChannelQObject):' | |||
|
61 | 57 | history_reply = QtCore.Signal(object) |
|
62 | 58 | kernel_info_reply = QtCore.Signal(object) |
|
63 | 59 | |
|
64 | #--------------------------------------------------------------------------- | |
|
65 | # 'ShellChannel' interface | |
|
66 | #--------------------------------------------------------------------------- | |
|
67 | ||
|
68 | 60 | def call_handlers(self, msg): |
|
69 | 61 | """ Reimplemented to emit signals instead of making callbacks. |
|
70 | 62 | """ |
@@ -108,10 +100,6 b' class QtIOPubChannelMixin(ChannelQObject):' | |||
|
108 | 100 | # Emitted when a shutdown is noticed. |
|
109 | 101 | shutdown_reply_received = QtCore.Signal(object) |
|
110 | 102 | |
|
111 | #--------------------------------------------------------------------------- | |
|
112 | # 'IOPubChannel' interface | |
|
113 | #--------------------------------------------------------------------------- | |
|
114 | ||
|
115 | 103 | def call_handlers(self, msg): |
|
116 | 104 | """ Reimplemented to emit signals instead of making callbacks. |
|
117 | 105 | """ |
@@ -122,8 +110,6 b' class QtIOPubChannelMixin(ChannelQObject):' | |||
|
122 | 110 | signal = getattr(self, msg_type + '_received', None) |
|
123 | 111 | if signal: |
|
124 | 112 | signal.emit(msg) |
|
125 | elif msg_type in ('stdout', 'stderr'): | |
|
126 | self.stream_received.emit(msg) | |
|
127 | 113 | |
|
128 | 114 | def flush(self): |
|
129 | 115 | """ Reimplemented to ensure that signals are dispatched immediately. |
@@ -140,10 +126,6 b' class QtStdInChannelMixin(ChannelQObject):' | |||
|
140 | 126 | # Emitted when an input request is received. |
|
141 | 127 | input_requested = QtCore.Signal(object) |
|
142 | 128 | |
|
143 | #--------------------------------------------------------------------------- | |
|
144 | # 'StdInChannel' interface | |
|
145 | #--------------------------------------------------------------------------- | |
|
146 | ||
|
147 | 129 | def call_handlers(self, msg): |
|
148 | 130 | """ Reimplemented to emit signals instead of making callbacks. |
|
149 | 131 | """ |
@@ -161,14 +143,9 b' class QtHBChannelMixin(ChannelQObject):' | |||
|
161 | 143 | # Emitted when the kernel has died. |
|
162 | 144 | kernel_died = QtCore.Signal(object) |
|
163 | 145 | |
|
164 | #--------------------------------------------------------------------------- | |
|
165 | # 'HBChannel' interface | |
|
166 | #--------------------------------------------------------------------------- | |
|
167 | ||
|
168 | 146 | def call_handlers(self, since_last_heartbeat): |
|
169 | 147 | """ Reimplemented to emit signals instead of making callbacks. |
|
170 | 148 | """ |
|
171 | # Emit the generic signal. | |
|
172 | 149 | self.kernel_died.emit(since_last_heartbeat) |
|
173 | 150 | |
|
174 | 151 |
@@ -529,7 +529,7 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):' | |||
|
529 | 529 | except KeyboardInterrupt: |
|
530 | 530 | #double-guard against keyboardinterrupts during kbdint handling |
|
531 | 531 | try: |
|
532 |
self.write('\n |
|
|
532 | self.write('\n' + self.get_exception_only()) | |
|
533 | 533 | source_raw = self.input_splitter.raw_reset() |
|
534 | 534 | hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell) |
|
535 | 535 | more = False |
@@ -468,7 +468,7 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
468 | 468 | except KeyboardInterrupt: |
|
469 | 469 | #double-guard against keyboardinterrupts during kbdint handling |
|
470 | 470 | try: |
|
471 |
self.write('\n |
|
|
471 | self.write('\n' + self.get_exception_only()) | |
|
472 | 472 | source_raw = self.input_splitter.raw_reset() |
|
473 | 473 | hlen_b4_cell = \ |
|
474 | 474 | self._replace_rlhist_multiline(source_raw, hlen_b4_cell) |
@@ -15,6 +15,7 b' import argparse' | |||
|
15 | 15 | import json |
|
16 | 16 | import multiprocessing.pool |
|
17 | 17 | import os |
|
18 | import stat | |
|
18 | 19 | import re |
|
19 | 20 | import requests |
|
20 | 21 | import shutil |
@@ -170,6 +171,18 b' class PyTestController(TestController):' | |||
|
170 | 171 | # This means we won't get odd effects from our own matplotlib config |
|
171 | 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 | 186 | # From options: |
|
174 | 187 | if self.options.xunit: |
|
175 | 188 | self.add_xunit() |
@@ -178,6 +191,14 b' class PyTestController(TestController):' | |||
|
178 | 191 | self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams |
|
179 | 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 | 202 | @property |
|
182 | 203 | def will_run(self): |
|
183 | 204 | try: |
@@ -17,7 +17,7 b' except ImportError:' | |||
|
17 | 17 | from . import codeutil # This registers a hook when it's imported |
|
18 | 18 | from . import py3compat |
|
19 | 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 | 22 | from IPython.config import Application |
|
23 | 23 | from IPython.utils.log import get_logger |
@@ -260,8 +260,8 b' class CannedArray(CannedObject):' | |||
|
260 | 260 | from numpy import frombuffer |
|
261 | 261 | data = self.buffers[0] |
|
262 | 262 | if self.pickled: |
|
263 |
# |
|
|
264 | return pickle.loads(data) | |
|
263 | # we just pickled it | |
|
264 | return pickle.loads(buffer_to_bytes_py2(data)) | |
|
265 | 265 | else: |
|
266 | 266 | return frombuffer(data, dtype=self.dtype).reshape(self.shape) |
|
267 | 267 |
@@ -30,6 +30,12 b' def cast_bytes(s, encoding=None):' | |||
|
30 | 30 | return encode(s, encoding) |
|
31 | 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 | 39 | def _modify_str_or_docstring(str_change_func): |
|
34 | 40 | @functools.wraps(str_change_func) |
|
35 | 41 | def wrapper(func_or_str): |
@@ -86,6 +92,7 b' if sys.version_info[0] >= 3:' | |||
|
86 | 92 | bytes_to_str = decode |
|
87 | 93 | cast_bytes_py2 = no_code |
|
88 | 94 | cast_unicode_py2 = no_code |
|
95 | buffer_to_bytes_py2 = no_code | |
|
89 | 96 | |
|
90 | 97 | string_types = (str,) |
|
91 | 98 | unicode_type = str |
@@ -151,6 +158,7 b' else:' | |||
|
151 | 158 | bytes_to_str = no_code |
|
152 | 159 | cast_bytes_py2 = cast_bytes |
|
153 | 160 | cast_unicode_py2 = cast_unicode |
|
161 | buffer_to_bytes_py2 = buffer_to_bytes | |
|
154 | 162 | |
|
155 | 163 | string_types = (str, unicode) |
|
156 | 164 | unicode_type = unicode |
@@ -429,6 +429,9 b' The main example being ``%load``.' | |||
|
429 | 429 | "source": "set_next_input", |
|
430 | 430 | # the text contents of the cell to create |
|
431 | 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 | 437 | **edit**: open a file for editing. |
@@ -270,7 +270,7 b' extras_require = dict(' | |||
|
270 | 270 | test = ['nose>=0.10.1', 'requests'], |
|
271 | 271 | terminal = [], |
|
272 | 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 | 274 | nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1'] |
|
275 | 275 | ) |
|
276 | 276 |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now