##// END OF EJS Templates
remove ipython_kernel.zmq sub-pkg
Min RK -
Show More
@@ -1,29 +1,31 b''
1 """
1 """
2 Shim to maintain backwards compatibility with old IPython.kernel imports.
2 Shim to maintain backwards compatibility with old IPython.kernel imports.
3 """
3 """
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import sys
7 import sys
8 from warnings import warn
8 from warnings import warn
9
9
10 warn("The `IPython.kernel` package has been deprecated. "
10 warn("The `IPython.kernel` package has been deprecated. "
11 "You should import from ipython_kernel or jupyter_client instead.")
11 "You should import from ipython_kernel or jupyter_client instead.")
12
12
13
13
14 from IPython.utils.shimmodule import ShimModule
14 from IPython.utils.shimmodule import ShimModule
15
15
16 # session moved relative to top-level
16 # zmq subdir is gone
17 sys.modules['IPython.kernel.zmq.session'] = ShimModule('session', mirror='jupyter_client.session')
17 sys.modules['IPython.kernel.zmq.session'] = ShimModule('session', mirror='jupyter_client.session')
18 sys.modules['IPython.kernel.zmq'] = ShimModule('zmq', mirror='ipython_kernel')
18
19
19 for pkg in ('comm', 'inprocess', 'resources', 'zmq'):
20 for pkg in ('comm', 'inprocess', 'resources'):
20 sys.modules['IPython.kernel.%s' % pkg] = ShimModule(pkg, mirror='ipython_kernel.%s' % pkg)
21 sys.modules['IPython.kernel.%s' % pkg] = ShimModule(pkg, mirror='ipython_kernel.%s' % pkg)
22
21 for pkg in ('ioloop', 'blocking'):
23 for pkg in ('ioloop', 'blocking'):
22 sys.modules['IPython.kernel.%s' % pkg] = ShimModule(pkg, mirror='jupyter_client.%s' % pkg)
24 sys.modules['IPython.kernel.%s' % pkg] = ShimModule(pkg, mirror='jupyter_client.%s' % pkg)
23
25
24 # required for `from IPython.kernel import PKG`
26 # required for `from IPython.kernel import PKG`
25 from ipython_kernel import comm, inprocess, resources, zmq
27 from ipython_kernel import comm, inprocess, resources
26 from jupyter_client import ioloop, blocking
28 from jupyter_client import ioloop, blocking
27 # public API
29 # public API
28 from ipython_kernel.connect import *
30 from ipython_kernel.connect import *
29 from jupyter_client import *
31 from jupyter_client import *
@@ -1,520 +1,520 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Suite Runner.
2 """IPython Test Suite Runner.
3
3
4 This module provides a main entry point to a user script to test IPython
4 This module provides a main entry point to a user script to test IPython
5 itself from the command line. There are two ways of running this script:
5 itself from the command line. There are two ways of running this script:
6
6
7 1. With the syntax `iptest all`. This runs our entire test suite by
7 1. With the syntax `iptest all`. This runs our entire test suite by
8 calling this script (with different arguments) recursively. This
8 calling this script (with different arguments) recursively. This
9 causes modules and package to be tested in different processes, using nose
9 causes modules and package to be tested in different processes, using nose
10 or trial where appropriate.
10 or trial where appropriate.
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 the script simply calls nose, but with special command line flags and
12 the script simply calls nose, but with special command line flags and
13 plugins loaded.
13 plugins loaded.
14
14
15 """
15 """
16
16
17 # Copyright (c) IPython Development Team.
17 # Copyright (c) IPython Development Team.
18 # Distributed under the terms of the Modified BSD License.
18 # Distributed under the terms of the Modified BSD License.
19
19
20 from __future__ import print_function
20 from __future__ import print_function
21
21
22 import glob
22 import glob
23 from io import BytesIO
23 from io import BytesIO
24 import os
24 import os
25 import os.path as path
25 import os.path as path
26 import sys
26 import sys
27 from threading import Thread, Lock, Event
27 from threading import Thread, Lock, Event
28 import warnings
28 import warnings
29
29
30 import nose.plugins.builtin
30 import nose.plugins.builtin
31 from nose.plugins.xunit import Xunit
31 from nose.plugins.xunit import Xunit
32 from nose import SkipTest
32 from nose import SkipTest
33 from nose.core import TestProgram
33 from nose.core import TestProgram
34 from nose.plugins import Plugin
34 from nose.plugins import Plugin
35 from nose.util import safe_str
35 from nose.util import safe_str
36
36
37 from IPython.utils.process import is_cmd_found
37 from IPython.utils.process import is_cmd_found
38 from IPython.utils.py3compat import bytes_to_str
38 from IPython.utils.py3compat import bytes_to_str
39 from IPython.utils.importstring import import_item
39 from IPython.utils.importstring import import_item
40 from IPython.testing.plugin.ipdoctest import IPythonDoctest
40 from IPython.testing.plugin.ipdoctest import IPythonDoctest
41 from IPython.external.decorators import KnownFailure, knownfailureif
41 from IPython.external.decorators import KnownFailure, knownfailureif
42
42
43 pjoin = path.join
43 pjoin = path.join
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Warnings control
46 # Warnings control
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 # Twisted generates annoying warnings with Python 2.6, as will do other code
49 # Twisted generates annoying warnings with Python 2.6, as will do other code
50 # that imports 'sets' as of today
50 # that imports 'sets' as of today
51 warnings.filterwarnings('ignore', 'the sets module is deprecated',
51 warnings.filterwarnings('ignore', 'the sets module is deprecated',
52 DeprecationWarning )
52 DeprecationWarning )
53
53
54 # This one also comes from Twisted
54 # This one also comes from Twisted
55 warnings.filterwarnings('ignore', 'the sha module is deprecated',
55 warnings.filterwarnings('ignore', 'the sha module is deprecated',
56 DeprecationWarning)
56 DeprecationWarning)
57
57
58 # Wx on Fedora11 spits these out
58 # Wx on Fedora11 spits these out
59 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
59 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
60 UserWarning)
60 UserWarning)
61
61
62 # ------------------------------------------------------------------------------
62 # ------------------------------------------------------------------------------
63 # Monkeypatch Xunit to count known failures as skipped.
63 # Monkeypatch Xunit to count known failures as skipped.
64 # ------------------------------------------------------------------------------
64 # ------------------------------------------------------------------------------
65 def monkeypatch_xunit():
65 def monkeypatch_xunit():
66 try:
66 try:
67 knownfailureif(True)(lambda: None)()
67 knownfailureif(True)(lambda: None)()
68 except Exception as e:
68 except Exception as e:
69 KnownFailureTest = type(e)
69 KnownFailureTest = type(e)
70
70
71 def addError(self, test, err, capt=None):
71 def addError(self, test, err, capt=None):
72 if issubclass(err[0], KnownFailureTest):
72 if issubclass(err[0], KnownFailureTest):
73 err = (SkipTest,) + err[1:]
73 err = (SkipTest,) + err[1:]
74 return self.orig_addError(test, err, capt)
74 return self.orig_addError(test, err, capt)
75
75
76 Xunit.orig_addError = Xunit.addError
76 Xunit.orig_addError = Xunit.addError
77 Xunit.addError = addError
77 Xunit.addError = addError
78
78
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80 # Check which dependencies are installed and greater than minimum version.
80 # Check which dependencies are installed and greater than minimum version.
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 def extract_version(mod):
82 def extract_version(mod):
83 return mod.__version__
83 return mod.__version__
84
84
85 def test_for(item, min_version=None, callback=extract_version):
85 def test_for(item, min_version=None, callback=extract_version):
86 """Test to see if item is importable, and optionally check against a minimum
86 """Test to see if item is importable, and optionally check against a minimum
87 version.
87 version.
88
88
89 If min_version is given, the default behavior is to check against the
89 If min_version is given, the default behavior is to check against the
90 `__version__` attribute of the item, but specifying `callback` allows you to
90 `__version__` attribute of the item, but specifying `callback` allows you to
91 extract the value you are interested in. e.g::
91 extract the value you are interested in. e.g::
92
92
93 In [1]: import sys
93 In [1]: import sys
94
94
95 In [2]: from IPython.testing.iptest import test_for
95 In [2]: from IPython.testing.iptest import test_for
96
96
97 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
97 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
98 Out[3]: True
98 Out[3]: True
99
99
100 """
100 """
101 try:
101 try:
102 check = import_item(item)
102 check = import_item(item)
103 except (ImportError, RuntimeError):
103 except (ImportError, RuntimeError):
104 # GTK reports Runtime error if it can't be initialized even if it's
104 # GTK reports Runtime error if it can't be initialized even if it's
105 # importable.
105 # importable.
106 return False
106 return False
107 else:
107 else:
108 if min_version:
108 if min_version:
109 if callback:
109 if callback:
110 # extra processing step to get version to compare
110 # extra processing step to get version to compare
111 check = callback(check)
111 check = callback(check)
112
112
113 return check >= min_version
113 return check >= min_version
114 else:
114 else:
115 return True
115 return True
116
116
117 # Global dict where we can store information on what we have and what we don't
117 # Global dict where we can store information on what we have and what we don't
118 # have available at test run time
118 # have available at test run time
119 have = {}
119 have = {}
120
120
121 have['curses'] = test_for('_curses')
121 have['curses'] = test_for('_curses')
122 have['matplotlib'] = test_for('matplotlib')
122 have['matplotlib'] = test_for('matplotlib')
123 have['numpy'] = test_for('numpy')
123 have['numpy'] = test_for('numpy')
124 have['pexpect'] = test_for('pexpect')
124 have['pexpect'] = test_for('pexpect')
125 have['pymongo'] = test_for('pymongo')
125 have['pymongo'] = test_for('pymongo')
126 have['pygments'] = test_for('pygments')
126 have['pygments'] = test_for('pygments')
127 have['qt'] = test_for('IPython.external.qt')
127 have['qt'] = test_for('IPython.external.qt')
128 have['sqlite3'] = test_for('sqlite3')
128 have['sqlite3'] = test_for('sqlite3')
129 have['tornado'] = test_for('tornado.version_info', (4,0), callback=None)
129 have['tornado'] = test_for('tornado.version_info', (4,0), callback=None)
130 have['jinja2'] = test_for('jinja2')
130 have['jinja2'] = test_for('jinja2')
131 have['mistune'] = test_for('mistune')
131 have['mistune'] = test_for('mistune')
132 have['requests'] = test_for('requests')
132 have['requests'] = test_for('requests')
133 have['sphinx'] = test_for('sphinx')
133 have['sphinx'] = test_for('sphinx')
134 have['jsonschema'] = test_for('jsonschema')
134 have['jsonschema'] = test_for('jsonschema')
135 have['terminado'] = test_for('terminado')
135 have['terminado'] = test_for('terminado')
136 have['casperjs'] = is_cmd_found('casperjs')
136 have['casperjs'] = is_cmd_found('casperjs')
137 have['phantomjs'] = is_cmd_found('phantomjs')
137 have['phantomjs'] = is_cmd_found('phantomjs')
138 have['slimerjs'] = is_cmd_found('slimerjs')
138 have['slimerjs'] = is_cmd_found('slimerjs')
139
139
140 min_zmq = (13,)
140 min_zmq = (13,)
141
141
142 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
142 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
143
143
144 #-----------------------------------------------------------------------------
144 #-----------------------------------------------------------------------------
145 # Test suite definitions
145 # Test suite definitions
146 #-----------------------------------------------------------------------------
146 #-----------------------------------------------------------------------------
147
147
148 test_group_names = ['parallel', 'kernel', 'kernel.inprocess', 'config', 'core',
148 test_group_names = ['parallel', 'kernel', 'kernel.inprocess', 'config', 'core',
149 'extensions', 'lib', 'terminal', 'testing', 'utils',
149 'extensions', 'lib', 'terminal', 'testing', 'utils',
150 'nbformat', 'qt', 'html', 'nbconvert'
150 'nbformat', 'qt', 'html', 'nbconvert'
151 ]
151 ]
152
152
153 class TestSection(object):
153 class TestSection(object):
154 def __init__(self, name, includes):
154 def __init__(self, name, includes):
155 self.name = name
155 self.name = name
156 self.includes = includes
156 self.includes = includes
157 self.excludes = []
157 self.excludes = []
158 self.dependencies = []
158 self.dependencies = []
159 self.enabled = True
159 self.enabled = True
160
160
161 def exclude(self, module):
161 def exclude(self, module):
162 if not module.startswith('IPython'):
162 if not module.startswith('IPython'):
163 module = self.includes[0] + "." + module
163 module = self.includes[0] + "." + module
164 self.excludes.append(module.replace('.', os.sep))
164 self.excludes.append(module.replace('.', os.sep))
165
165
166 def requires(self, *packages):
166 def requires(self, *packages):
167 self.dependencies.extend(packages)
167 self.dependencies.extend(packages)
168
168
169 @property
169 @property
170 def will_run(self):
170 def will_run(self):
171 return self.enabled and all(have[p] for p in self.dependencies)
171 return self.enabled and all(have[p] for p in self.dependencies)
172
172
173 shims = {
173 shims = {
174 'parallel': 'ipython_parallel',
174 'parallel': 'ipython_parallel',
175 'kernel': 'ipython_kernel',
175 'kernel': 'ipython_kernel',
176 'kernel.inprocess': 'ipython_kernel.inprocess',
176 'kernel.inprocess': 'ipython_kernel.inprocess',
177 }
177 }
178
178
179 # Name -> (include, exclude, dependencies_met)
179 # Name -> (include, exclude, dependencies_met)
180 test_sections = {n:TestSection(n, [shims.get(n, 'IPython.%s' % n)]) for n in test_group_names}
180 test_sections = {n:TestSection(n, [shims.get(n, 'IPython.%s' % n)]) for n in test_group_names}
181
181
182
182
183 # Exclusions and dependencies
183 # Exclusions and dependencies
184 # ---------------------------
184 # ---------------------------
185
185
186 # core:
186 # core:
187 sec = test_sections['core']
187 sec = test_sections['core']
188 if not have['sqlite3']:
188 if not have['sqlite3']:
189 sec.exclude('tests.test_history')
189 sec.exclude('tests.test_history')
190 sec.exclude('history')
190 sec.exclude('history')
191 if not have['matplotlib']:
191 if not have['matplotlib']:
192 sec.exclude('pylabtools'),
192 sec.exclude('pylabtools'),
193 sec.exclude('tests.test_pylabtools')
193 sec.exclude('tests.test_pylabtools')
194
194
195 # lib:
195 # lib:
196 sec = test_sections['lib']
196 sec = test_sections['lib']
197 if not have['zmq']:
197 if not have['zmq']:
198 sec.exclude('kernel')
198 sec.exclude('kernel')
199 # We do this unconditionally, so that the test suite doesn't import
199 # We do this unconditionally, so that the test suite doesn't import
200 # gtk, changing the default encoding and masking some unicode bugs.
200 # gtk, changing the default encoding and masking some unicode bugs.
201 sec.exclude('inputhookgtk')
201 sec.exclude('inputhookgtk')
202 # We also do this unconditionally, because wx can interfere with Unix signals.
202 # We also do this unconditionally, because wx can interfere with Unix signals.
203 # There are currently no tests for it anyway.
203 # There are currently no tests for it anyway.
204 sec.exclude('inputhookwx')
204 sec.exclude('inputhookwx')
205 # Testing inputhook will need a lot of thought, to figure out
205 # Testing inputhook will need a lot of thought, to figure out
206 # how to have tests that don't lock up with the gui event
206 # how to have tests that don't lock up with the gui event
207 # loops in the picture
207 # loops in the picture
208 sec.exclude('inputhook')
208 sec.exclude('inputhook')
209
209
210 # testing:
210 # testing:
211 sec = test_sections['testing']
211 sec = test_sections['testing']
212 # These have to be skipped on win32 because they use echo, rm, cd, etc.
212 # These have to be skipped on win32 because they use echo, rm, cd, etc.
213 # See ticket https://github.com/ipython/ipython/issues/87
213 # See ticket https://github.com/ipython/ipython/issues/87
214 if sys.platform == 'win32':
214 if sys.platform == 'win32':
215 sec.exclude('plugin.test_exampleip')
215 sec.exclude('plugin.test_exampleip')
216 sec.exclude('plugin.dtexample')
216 sec.exclude('plugin.dtexample')
217
217
218 # terminal:
218 # terminal:
219 if (not have['pexpect']) or (not have['zmq']):
219 if (not have['pexpect']) or (not have['zmq']):
220 test_sections['terminal'].exclude('console')
220 test_sections['terminal'].exclude('console')
221
221
222 # parallel
222 # parallel
223 sec = test_sections['parallel']
223 sec = test_sections['parallel']
224 sec.requires('zmq')
224 sec.requires('zmq')
225 if not have['pymongo']:
225 if not have['pymongo']:
226 sec.exclude('controller.mongodb')
226 sec.exclude('controller.mongodb')
227 sec.exclude('tests.test_mongodb')
227 sec.exclude('tests.test_mongodb')
228
228
229 # kernel:
229 # kernel:
230 sec = test_sections['kernel']
230 sec = test_sections['kernel']
231 sec.requires('zmq')
231 sec.requires('zmq')
232 # The in-process kernel tests are done in a separate section
232 # The in-process kernel tests are done in a separate section
233 sec.exclude('inprocess')
233 sec.exclude('inprocess')
234 # importing gtk sets the default encoding, which we want to avoid
234 # importing gtk sets the default encoding, which we want to avoid
235 sec.exclude('zmq.gui.gtkembed')
235 sec.exclude('gui.gtkembed')
236 sec.exclude('zmq.gui.gtk3embed')
236 sec.exclude('gui.gtk3embed')
237 if not have['matplotlib']:
237 if not have['matplotlib']:
238 sec.exclude('zmq.pylab')
238 sec.exclude('pylab')
239
239
240 # kernel.inprocess:
240 # kernel.inprocess:
241 test_sections['kernel.inprocess'].requires('zmq')
241 test_sections['kernel.inprocess'].requires('zmq')
242
242
243 # extensions:
243 # extensions:
244 sec = test_sections['extensions']
244 sec = test_sections['extensions']
245 # This is deprecated in favour of rpy2
245 # This is deprecated in favour of rpy2
246 sec.exclude('rmagic')
246 sec.exclude('rmagic')
247 # autoreload does some strange stuff, so move it to its own test section
247 # autoreload does some strange stuff, so move it to its own test section
248 sec.exclude('autoreload')
248 sec.exclude('autoreload')
249 sec.exclude('tests.test_autoreload')
249 sec.exclude('tests.test_autoreload')
250 test_sections['autoreload'] = TestSection('autoreload',
250 test_sections['autoreload'] = TestSection('autoreload',
251 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
251 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
252 test_group_names.append('autoreload')
252 test_group_names.append('autoreload')
253
253
254 # qt:
254 # qt:
255 test_sections['qt'].requires('zmq', 'qt', 'pygments')
255 test_sections['qt'].requires('zmq', 'qt', 'pygments')
256
256
257 # html:
257 # html:
258 sec = test_sections['html']
258 sec = test_sections['html']
259 sec.requires('zmq', 'tornado', 'requests', 'sqlite3', 'jsonschema')
259 sec.requires('zmq', 'tornado', 'requests', 'sqlite3', 'jsonschema')
260 # The notebook 'static' directory contains JS, css and other
260 # The notebook 'static' directory contains JS, css and other
261 # files for web serving. Occasionally projects may put a .py
261 # files for web serving. Occasionally projects may put a .py
262 # file in there (MathJax ships a conf.py), so we might as
262 # file in there (MathJax ships a conf.py), so we might as
263 # well play it safe and skip the whole thing.
263 # well play it safe and skip the whole thing.
264 sec.exclude('static')
264 sec.exclude('static')
265 sec.exclude('tasks')
265 sec.exclude('tasks')
266 if not have['jinja2']:
266 if not have['jinja2']:
267 sec.exclude('notebookapp')
267 sec.exclude('notebookapp')
268 if not have['pygments'] or not have['jinja2']:
268 if not have['pygments'] or not have['jinja2']:
269 sec.exclude('nbconvert')
269 sec.exclude('nbconvert')
270 if not have['terminado']:
270 if not have['terminado']:
271 sec.exclude('terminal')
271 sec.exclude('terminal')
272
272
273 # config:
273 # config:
274 # Config files aren't really importable stand-alone
274 # Config files aren't really importable stand-alone
275 test_sections['config'].exclude('profile')
275 test_sections['config'].exclude('profile')
276
276
277 # nbconvert:
277 # nbconvert:
278 sec = test_sections['nbconvert']
278 sec = test_sections['nbconvert']
279 sec.requires('pygments', 'jinja2', 'jsonschema', 'mistune')
279 sec.requires('pygments', 'jinja2', 'jsonschema', 'mistune')
280 # Exclude nbconvert directories containing config files used to test.
280 # Exclude nbconvert directories containing config files used to test.
281 # Executing the config files with iptest would cause an exception.
281 # Executing the config files with iptest would cause an exception.
282 sec.exclude('tests.files')
282 sec.exclude('tests.files')
283 sec.exclude('exporters.tests.files')
283 sec.exclude('exporters.tests.files')
284 if not have['tornado']:
284 if not have['tornado']:
285 sec.exclude('nbconvert.post_processors.serve')
285 sec.exclude('nbconvert.post_processors.serve')
286 sec.exclude('nbconvert.post_processors.tests.test_serve')
286 sec.exclude('nbconvert.post_processors.tests.test_serve')
287
287
288 # nbformat:
288 # nbformat:
289 test_sections['nbformat'].requires('jsonschema')
289 test_sections['nbformat'].requires('jsonschema')
290
290
291 #-----------------------------------------------------------------------------
291 #-----------------------------------------------------------------------------
292 # Functions and classes
292 # Functions and classes
293 #-----------------------------------------------------------------------------
293 #-----------------------------------------------------------------------------
294
294
295 def check_exclusions_exist():
295 def check_exclusions_exist():
296 from IPython.utils.path import get_ipython_package_dir
296 from IPython.utils.path import get_ipython_package_dir
297 from IPython.utils.warn import warn
297 from IPython.utils.warn import warn
298 parent = os.path.dirname(get_ipython_package_dir())
298 parent = os.path.dirname(get_ipython_package_dir())
299 for sec in test_sections:
299 for sec in test_sections:
300 for pattern in sec.exclusions:
300 for pattern in sec.exclusions:
301 fullpath = pjoin(parent, pattern)
301 fullpath = pjoin(parent, pattern)
302 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
302 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
303 warn("Excluding nonexistent file: %r" % pattern)
303 warn("Excluding nonexistent file: %r" % pattern)
304
304
305
305
306 class ExclusionPlugin(Plugin):
306 class ExclusionPlugin(Plugin):
307 """A nose plugin to effect our exclusions of files and directories.
307 """A nose plugin to effect our exclusions of files and directories.
308 """
308 """
309 name = 'exclusions'
309 name = 'exclusions'
310 score = 3000 # Should come before any other plugins
310 score = 3000 # Should come before any other plugins
311
311
312 def __init__(self, exclude_patterns=None):
312 def __init__(self, exclude_patterns=None):
313 """
313 """
314 Parameters
314 Parameters
315 ----------
315 ----------
316
316
317 exclude_patterns : sequence of strings, optional
317 exclude_patterns : sequence of strings, optional
318 Filenames containing these patterns (as raw strings, not as regular
318 Filenames containing these patterns (as raw strings, not as regular
319 expressions) are excluded from the tests.
319 expressions) are excluded from the tests.
320 """
320 """
321 self.exclude_patterns = exclude_patterns or []
321 self.exclude_patterns = exclude_patterns or []
322 super(ExclusionPlugin, self).__init__()
322 super(ExclusionPlugin, self).__init__()
323
323
324 def options(self, parser, env=os.environ):
324 def options(self, parser, env=os.environ):
325 Plugin.options(self, parser, env)
325 Plugin.options(self, parser, env)
326
326
327 def configure(self, options, config):
327 def configure(self, options, config):
328 Plugin.configure(self, options, config)
328 Plugin.configure(self, options, config)
329 # Override nose trying to disable plugin.
329 # Override nose trying to disable plugin.
330 self.enabled = True
330 self.enabled = True
331
331
332 def wantFile(self, filename):
332 def wantFile(self, filename):
333 """Return whether the given filename should be scanned for tests.
333 """Return whether the given filename should be scanned for tests.
334 """
334 """
335 if any(pat in filename for pat in self.exclude_patterns):
335 if any(pat in filename for pat in self.exclude_patterns):
336 return False
336 return False
337 return None
337 return None
338
338
339 def wantDirectory(self, directory):
339 def wantDirectory(self, directory):
340 """Return whether the given directory should be scanned for tests.
340 """Return whether the given directory should be scanned for tests.
341 """
341 """
342 if any(pat in directory for pat in self.exclude_patterns):
342 if any(pat in directory for pat in self.exclude_patterns):
343 return False
343 return False
344 return None
344 return None
345
345
346
346
347 class StreamCapturer(Thread):
347 class StreamCapturer(Thread):
348 daemon = True # Don't hang if main thread crashes
348 daemon = True # Don't hang if main thread crashes
349 started = False
349 started = False
350 def __init__(self, echo=False):
350 def __init__(self, echo=False):
351 super(StreamCapturer, self).__init__()
351 super(StreamCapturer, self).__init__()
352 self.echo = echo
352 self.echo = echo
353 self.streams = []
353 self.streams = []
354 self.buffer = BytesIO()
354 self.buffer = BytesIO()
355 self.readfd, self.writefd = os.pipe()
355 self.readfd, self.writefd = os.pipe()
356 self.buffer_lock = Lock()
356 self.buffer_lock = Lock()
357 self.stop = Event()
357 self.stop = Event()
358
358
359 def run(self):
359 def run(self):
360 self.started = True
360 self.started = True
361
361
362 while not self.stop.is_set():
362 while not self.stop.is_set():
363 chunk = os.read(self.readfd, 1024)
363 chunk = os.read(self.readfd, 1024)
364
364
365 with self.buffer_lock:
365 with self.buffer_lock:
366 self.buffer.write(chunk)
366 self.buffer.write(chunk)
367 if self.echo:
367 if self.echo:
368 sys.stdout.write(bytes_to_str(chunk))
368 sys.stdout.write(bytes_to_str(chunk))
369
369
370 os.close(self.readfd)
370 os.close(self.readfd)
371 os.close(self.writefd)
371 os.close(self.writefd)
372
372
373 def reset_buffer(self):
373 def reset_buffer(self):
374 with self.buffer_lock:
374 with self.buffer_lock:
375 self.buffer.truncate(0)
375 self.buffer.truncate(0)
376 self.buffer.seek(0)
376 self.buffer.seek(0)
377
377
378 def get_buffer(self):
378 def get_buffer(self):
379 with self.buffer_lock:
379 with self.buffer_lock:
380 return self.buffer.getvalue()
380 return self.buffer.getvalue()
381
381
382 def ensure_started(self):
382 def ensure_started(self):
383 if not self.started:
383 if not self.started:
384 self.start()
384 self.start()
385
385
386 def halt(self):
386 def halt(self):
387 """Safely stop the thread."""
387 """Safely stop the thread."""
388 if not self.started:
388 if not self.started:
389 return
389 return
390
390
391 self.stop.set()
391 self.stop.set()
392 os.write(self.writefd, b'\0') # Ensure we're not locked in a read()
392 os.write(self.writefd, b'\0') # Ensure we're not locked in a read()
393 self.join()
393 self.join()
394
394
395 class SubprocessStreamCapturePlugin(Plugin):
395 class SubprocessStreamCapturePlugin(Plugin):
396 name='subprocstreams'
396 name='subprocstreams'
397 def __init__(self):
397 def __init__(self):
398 Plugin.__init__(self)
398 Plugin.__init__(self)
399 self.stream_capturer = StreamCapturer()
399 self.stream_capturer = StreamCapturer()
400 self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
400 self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
401 # This is ugly, but distant parts of the test machinery need to be able
401 # This is ugly, but distant parts of the test machinery need to be able
402 # to redirect streams, so we make the object globally accessible.
402 # to redirect streams, so we make the object globally accessible.
403 nose.iptest_stdstreams_fileno = self.get_write_fileno
403 nose.iptest_stdstreams_fileno = self.get_write_fileno
404
404
405 def get_write_fileno(self):
405 def get_write_fileno(self):
406 if self.destination == 'capture':
406 if self.destination == 'capture':
407 self.stream_capturer.ensure_started()
407 self.stream_capturer.ensure_started()
408 return self.stream_capturer.writefd
408 return self.stream_capturer.writefd
409 elif self.destination == 'discard':
409 elif self.destination == 'discard':
410 return os.open(os.devnull, os.O_WRONLY)
410 return os.open(os.devnull, os.O_WRONLY)
411 else:
411 else:
412 return sys.__stdout__.fileno()
412 return sys.__stdout__.fileno()
413
413
414 def configure(self, options, config):
414 def configure(self, options, config):
415 Plugin.configure(self, options, config)
415 Plugin.configure(self, options, config)
416 # Override nose trying to disable plugin.
416 # Override nose trying to disable plugin.
417 if self.destination == 'capture':
417 if self.destination == 'capture':
418 self.enabled = True
418 self.enabled = True
419
419
420 def startTest(self, test):
420 def startTest(self, test):
421 # Reset log capture
421 # Reset log capture
422 self.stream_capturer.reset_buffer()
422 self.stream_capturer.reset_buffer()
423
423
424 def formatFailure(self, test, err):
424 def formatFailure(self, test, err):
425 # Show output
425 # Show output
426 ec, ev, tb = err
426 ec, ev, tb = err
427 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
427 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
428 if captured.strip():
428 if captured.strip():
429 ev = safe_str(ev)
429 ev = safe_str(ev)
430 out = [ev, '>> begin captured subprocess output <<',
430 out = [ev, '>> begin captured subprocess output <<',
431 captured,
431 captured,
432 '>> end captured subprocess output <<']
432 '>> end captured subprocess output <<']
433 return ec, '\n'.join(out), tb
433 return ec, '\n'.join(out), tb
434
434
435 return err
435 return err
436
436
437 formatError = formatFailure
437 formatError = formatFailure
438
438
439 def finalize(self, result):
439 def finalize(self, result):
440 self.stream_capturer.halt()
440 self.stream_capturer.halt()
441
441
442
442
443 def run_iptest():
443 def run_iptest():
444 """Run the IPython test suite using nose.
444 """Run the IPython test suite using nose.
445
445
446 This function is called when this script is **not** called with the form
446 This function is called when this script is **not** called with the form
447 `iptest all`. It simply calls nose with appropriate command line flags
447 `iptest all`. It simply calls nose with appropriate command line flags
448 and accepts all of the standard nose arguments.
448 and accepts all of the standard nose arguments.
449 """
449 """
450 # Apply our monkeypatch to Xunit
450 # Apply our monkeypatch to Xunit
451 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
451 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
452 monkeypatch_xunit()
452 monkeypatch_xunit()
453
453
454 warnings.filterwarnings('ignore',
454 warnings.filterwarnings('ignore',
455 'This will be removed soon. Use IPython.testing.util instead')
455 'This will be removed soon. Use IPython.testing.util instead')
456
456
457 arg1 = sys.argv[1]
457 arg1 = sys.argv[1]
458 if arg1 in test_sections:
458 if arg1 in test_sections:
459 section = test_sections[arg1]
459 section = test_sections[arg1]
460 sys.argv[1:2] = section.includes
460 sys.argv[1:2] = section.includes
461 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
461 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
462 section = test_sections[arg1[8:]]
462 section = test_sections[arg1[8:]]
463 sys.argv[1:2] = section.includes
463 sys.argv[1:2] = section.includes
464 else:
464 else:
465 section = TestSection(arg1, includes=[arg1])
465 section = TestSection(arg1, includes=[arg1])
466
466
467
467
468 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
468 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
469
469
470 '--with-ipdoctest',
470 '--with-ipdoctest',
471 '--ipdoctest-tests','--ipdoctest-extension=txt',
471 '--ipdoctest-tests','--ipdoctest-extension=txt',
472
472
473 # We add --exe because of setuptools' imbecility (it
473 # We add --exe because of setuptools' imbecility (it
474 # blindly does chmod +x on ALL files). Nose does the
474 # blindly does chmod +x on ALL files). Nose does the
475 # right thing and it tries to avoid executables,
475 # right thing and it tries to avoid executables,
476 # setuptools unfortunately forces our hand here. This
476 # setuptools unfortunately forces our hand here. This
477 # has been discussed on the distutils list and the
477 # has been discussed on the distutils list and the
478 # setuptools devs refuse to fix this problem!
478 # setuptools devs refuse to fix this problem!
479 '--exe',
479 '--exe',
480 ]
480 ]
481 if '-a' not in argv and '-A' not in argv:
481 if '-a' not in argv and '-A' not in argv:
482 argv = argv + ['-a', '!crash']
482 argv = argv + ['-a', '!crash']
483
483
484 if nose.__version__ >= '0.11':
484 if nose.__version__ >= '0.11':
485 # I don't fully understand why we need this one, but depending on what
485 # I don't fully understand why we need this one, but depending on what
486 # directory the test suite is run from, if we don't give it, 0 tests
486 # directory the test suite is run from, if we don't give it, 0 tests
487 # get run. Specifically, if the test suite is run from the source dir
487 # get run. Specifically, if the test suite is run from the source dir
488 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
488 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
489 # even if the same call done in this directory works fine). It appears
489 # even if the same call done in this directory works fine). It appears
490 # that if the requested package is in the current dir, nose bails early
490 # that if the requested package is in the current dir, nose bails early
491 # by default. Since it's otherwise harmless, leave it in by default
491 # by default. Since it's otherwise harmless, leave it in by default
492 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
492 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
493 argv.append('--traverse-namespace')
493 argv.append('--traverse-namespace')
494
494
495 # use our plugin for doctesting. It will remove the standard doctest plugin
495 # use our plugin for doctesting. It will remove the standard doctest plugin
496 # if it finds it enabled
496 # if it finds it enabled
497 plugins = [ExclusionPlugin(section.excludes), IPythonDoctest(), KnownFailure(),
497 plugins = [ExclusionPlugin(section.excludes), IPythonDoctest(), KnownFailure(),
498 SubprocessStreamCapturePlugin() ]
498 SubprocessStreamCapturePlugin() ]
499
499
500 # Use working directory set by parent process (see iptestcontroller)
500 # Use working directory set by parent process (see iptestcontroller)
501 if 'IPTEST_WORKING_DIR' in os.environ:
501 if 'IPTEST_WORKING_DIR' in os.environ:
502 os.chdir(os.environ['IPTEST_WORKING_DIR'])
502 os.chdir(os.environ['IPTEST_WORKING_DIR'])
503
503
504 # We need a global ipython running in this process, but the special
504 # We need a global ipython running in this process, but the special
505 # in-process group spawns its own IPython kernels, so for *that* group we
505 # in-process group spawns its own IPython kernels, so for *that* group we
506 # must avoid also opening the global one (otherwise there's a conflict of
506 # must avoid also opening the global one (otherwise there's a conflict of
507 # singletons). Ultimately the solution to this problem is to refactor our
507 # singletons). Ultimately the solution to this problem is to refactor our
508 # assumptions about what needs to be a singleton and what doesn't (app
508 # assumptions about what needs to be a singleton and what doesn't (app
509 # objects should, individual shells shouldn't). But for now, this
509 # objects should, individual shells shouldn't). But for now, this
510 # workaround allows the test suite for the inprocess module to complete.
510 # workaround allows the test suite for the inprocess module to complete.
511 if 'kernel.inprocess' not in section.name:
511 if 'kernel.inprocess' not in section.name:
512 from IPython.testing import globalipapp
512 from IPython.testing import globalipapp
513 globalipapp.start_ipython()
513 globalipapp.start_ipython()
514
514
515 # Now nose can run
515 # Now nose can run
516 TestProgram(argv=argv, addplugins=plugins)
516 TestProgram(argv=argv, addplugins=plugins)
517
517
518 if __name__ == '__main__':
518 if __name__ == '__main__':
519 run_iptest()
519 run_iptest()
520
520
@@ -1,3 +1,3 b''
1 if __name__ == '__main__':
1 if __name__ == '__main__':
2 from ipython_kernel.zmq import kernelapp as app
2 from ipython_kernel import kernelapp as app
3 app.launch_new_instance()
3 app.launch_new_instance()
@@ -1,169 +1,169 b''
1 """Base class for a Comm"""
1 """Base class for a Comm"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import threading
6 import threading
7 import uuid
7 import uuid
8
8
9 from zmq.eventloop.ioloop import IOLoop
9 from zmq.eventloop.ioloop import IOLoop
10
10
11 from IPython.config import LoggingConfigurable
11 from IPython.config import LoggingConfigurable
12 from ipython_kernel.zmq.kernelbase import Kernel
12 from ipython_kernel.kernelbase import Kernel
13
13
14 from IPython.utils.jsonutil import json_clean
14 from IPython.utils.jsonutil import json_clean
15 from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any
15 from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any
16
16
17
17
18 class Comm(LoggingConfigurable):
18 class Comm(LoggingConfigurable):
19 """Class for communicating between a Frontend and a Kernel"""
19 """Class for communicating between a Frontend and a Kernel"""
20 # If this is instantiated by a non-IPython kernel, shell will be None
20 # If this is instantiated by a non-IPython kernel, shell will be None
21 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
21 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
22 allow_none=True)
22 allow_none=True)
23 kernel = Instance('ipython_kernel.zmq.kernelbase.Kernel')
23 kernel = Instance('ipython_kernel.kernelbase.Kernel')
24 def _kernel_default(self):
24 def _kernel_default(self):
25 if Kernel.initialized():
25 if Kernel.initialized():
26 return Kernel.instance()
26 return Kernel.instance()
27
27
28 iopub_socket = Any()
28 iopub_socket = Any()
29 def _iopub_socket_default(self):
29 def _iopub_socket_default(self):
30 return self.kernel.iopub_socket
30 return self.kernel.iopub_socket
31 session = Instance('ipython_kernel.zmq.session.Session')
31 session = Instance('ipython_kernel.session.Session')
32 def _session_default(self):
32 def _session_default(self):
33 if self.kernel is not None:
33 if self.kernel is not None:
34 return self.kernel.session
34 return self.kernel.session
35
35
36 target_name = Unicode('comm')
36 target_name = Unicode('comm')
37 target_module = Unicode(None, allow_none=True, help="""requirejs module from
37 target_module = Unicode(None, allow_none=True, help="""requirejs module from
38 which to load comm target.""")
38 which to load comm target.""")
39
39
40 topic = Bytes()
40 topic = Bytes()
41 def _topic_default(self):
41 def _topic_default(self):
42 return ('comm-%s' % self.comm_id).encode('ascii')
42 return ('comm-%s' % self.comm_id).encode('ascii')
43
43
44 _open_data = Dict(help="data dict, if any, to be included in comm_open")
44 _open_data = Dict(help="data dict, if any, to be included in comm_open")
45 _close_data = Dict(help="data dict, if any, to be included in comm_close")
45 _close_data = Dict(help="data dict, if any, to be included in comm_close")
46
46
47 _msg_callback = Any()
47 _msg_callback = Any()
48 _close_callback = Any()
48 _close_callback = Any()
49
49
50 _closed = Bool(True)
50 _closed = Bool(True)
51 comm_id = Unicode()
51 comm_id = Unicode()
52 def _comm_id_default(self):
52 def _comm_id_default(self):
53 return uuid.uuid4().hex
53 return uuid.uuid4().hex
54
54
55 primary = Bool(True, help="Am I the primary or secondary Comm?")
55 primary = Bool(True, help="Am I the primary or secondary Comm?")
56
56
57 def __init__(self, target_name='', data=None, **kwargs):
57 def __init__(self, target_name='', data=None, **kwargs):
58 if target_name:
58 if target_name:
59 kwargs['target_name'] = target_name
59 kwargs['target_name'] = target_name
60 super(Comm, self).__init__(**kwargs)
60 super(Comm, self).__init__(**kwargs)
61 if self.primary:
61 if self.primary:
62 # I am primary, open my peer.
62 # I am primary, open my peer.
63 self.open(data)
63 self.open(data)
64 else:
64 else:
65 self._closed = False
65 self._closed = False
66
66
67 def _publish_msg(self, msg_type, data=None, metadata=None, buffers=None, **keys):
67 def _publish_msg(self, msg_type, data=None, metadata=None, buffers=None, **keys):
68 """Helper for sending a comm message on IOPub"""
68 """Helper for sending a comm message on IOPub"""
69 if threading.current_thread().name != 'MainThread' and IOLoop.initialized():
69 if threading.current_thread().name != 'MainThread' and IOLoop.initialized():
70 # make sure we never send on a zmq socket outside the main IOLoop thread
70 # make sure we never send on a zmq socket outside the main IOLoop thread
71 IOLoop.instance().add_callback(lambda : self._publish_msg(msg_type, data, metadata, buffers, **keys))
71 IOLoop.instance().add_callback(lambda : self._publish_msg(msg_type, data, metadata, buffers, **keys))
72 return
72 return
73 data = {} if data is None else data
73 data = {} if data is None else data
74 metadata = {} if metadata is None else metadata
74 metadata = {} if metadata is None else metadata
75 content = json_clean(dict(data=data, comm_id=self.comm_id, **keys))
75 content = json_clean(dict(data=data, comm_id=self.comm_id, **keys))
76 self.session.send(self.iopub_socket, msg_type,
76 self.session.send(self.iopub_socket, msg_type,
77 content,
77 content,
78 metadata=json_clean(metadata),
78 metadata=json_clean(metadata),
79 parent=self.kernel._parent_header,
79 parent=self.kernel._parent_header,
80 ident=self.topic,
80 ident=self.topic,
81 buffers=buffers,
81 buffers=buffers,
82 )
82 )
83
83
84 def __del__(self):
84 def __del__(self):
85 """trigger close on gc"""
85 """trigger close on gc"""
86 self.close()
86 self.close()
87
87
88 # publishing messages
88 # publishing messages
89
89
90 def open(self, data=None, metadata=None, buffers=None):
90 def open(self, data=None, metadata=None, buffers=None):
91 """Open the frontend-side version of this comm"""
91 """Open the frontend-side version of this comm"""
92 if data is None:
92 if data is None:
93 data = self._open_data
93 data = self._open_data
94 comm_manager = getattr(self.kernel, 'comm_manager', None)
94 comm_manager = getattr(self.kernel, 'comm_manager', None)
95 if comm_manager is None:
95 if comm_manager is None:
96 raise RuntimeError("Comms cannot be opened without a kernel "
96 raise RuntimeError("Comms cannot be opened without a kernel "
97 "and a comm_manager attached to that kernel.")
97 "and a comm_manager attached to that kernel.")
98
98
99 comm_manager.register_comm(self)
99 comm_manager.register_comm(self)
100 try:
100 try:
101 self._publish_msg('comm_open',
101 self._publish_msg('comm_open',
102 data=data, metadata=metadata, buffers=buffers,
102 data=data, metadata=metadata, buffers=buffers,
103 target_name=self.target_name,
103 target_name=self.target_name,
104 target_module=self.target_module,
104 target_module=self.target_module,
105 )
105 )
106 self._closed = False
106 self._closed = False
107 except:
107 except:
108 comm_manager.unregister_comm(self)
108 comm_manager.unregister_comm(self)
109 raise
109 raise
110
110
111 def close(self, data=None, metadata=None, buffers=None):
111 def close(self, data=None, metadata=None, buffers=None):
112 """Close the frontend-side version of this comm"""
112 """Close the frontend-side version of this comm"""
113 if self._closed:
113 if self._closed:
114 # only close once
114 # only close once
115 return
115 return
116 self._closed = True
116 self._closed = True
117 if data is None:
117 if data is None:
118 data = self._close_data
118 data = self._close_data
119 self._publish_msg('comm_close',
119 self._publish_msg('comm_close',
120 data=data, metadata=metadata, buffers=buffers,
120 data=data, metadata=metadata, buffers=buffers,
121 )
121 )
122 self.kernel.comm_manager.unregister_comm(self)
122 self.kernel.comm_manager.unregister_comm(self)
123
123
124 def send(self, data=None, metadata=None, buffers=None):
124 def send(self, data=None, metadata=None, buffers=None):
125 """Send a message to the frontend-side version of this comm"""
125 """Send a message to the frontend-side version of this comm"""
126 self._publish_msg('comm_msg',
126 self._publish_msg('comm_msg',
127 data=data, metadata=metadata, buffers=buffers,
127 data=data, metadata=metadata, buffers=buffers,
128 )
128 )
129
129
130 # registering callbacks
130 # registering callbacks
131
131
132 def on_close(self, callback):
132 def on_close(self, callback):
133 """Register a callback for comm_close
133 """Register a callback for comm_close
134
134
135 Will be called with the `data` of the close message.
135 Will be called with the `data` of the close message.
136
136
137 Call `on_close(None)` to disable an existing callback.
137 Call `on_close(None)` to disable an existing callback.
138 """
138 """
139 self._close_callback = callback
139 self._close_callback = callback
140
140
141 def on_msg(self, callback):
141 def on_msg(self, callback):
142 """Register a callback for comm_msg
142 """Register a callback for comm_msg
143
143
144 Will be called with the `data` of any comm_msg messages.
144 Will be called with the `data` of any comm_msg messages.
145
145
146 Call `on_msg(None)` to disable an existing callback.
146 Call `on_msg(None)` to disable an existing callback.
147 """
147 """
148 self._msg_callback = callback
148 self._msg_callback = callback
149
149
150 # handling of incoming messages
150 # handling of incoming messages
151
151
152 def handle_close(self, msg):
152 def handle_close(self, msg):
153 """Handle a comm_close message"""
153 """Handle a comm_close message"""
154 self.log.debug("handle_close[%s](%s)", self.comm_id, msg)
154 self.log.debug("handle_close[%s](%s)", self.comm_id, msg)
155 if self._close_callback:
155 if self._close_callback:
156 self._close_callback(msg)
156 self._close_callback(msg)
157
157
158 def handle_msg(self, msg):
158 def handle_msg(self, msg):
159 """Handle a comm_msg message"""
159 """Handle a comm_msg message"""
160 self.log.debug("handle_msg[%s](%s)", self.comm_id, msg)
160 self.log.debug("handle_msg[%s](%s)", self.comm_id, msg)
161 if self._msg_callback:
161 if self._msg_callback:
162 if self.shell:
162 if self.shell:
163 self.shell.events.trigger('pre_execute')
163 self.shell.events.trigger('pre_execute')
164 self._msg_callback(msg)
164 self._msg_callback(msg)
165 if self.shell:
165 if self.shell:
166 self.shell.events.trigger('post_execute')
166 self.shell.events.trigger('post_execute')
167
167
168
168
169 __all__ = ['Comm']
169 __all__ = ['Comm']
@@ -1,157 +1,157 b''
1 """Base class to manage comms"""
1 """Base class to manage comms"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import sys
6 import sys
7
7
8 from IPython.config import LoggingConfigurable
8 from IPython.config import LoggingConfigurable
9 from IPython.core.prompts import LazyEvaluate
9 from IPython.core.prompts import LazyEvaluate
10 from IPython.core.getipython import get_ipython
10 from IPython.core.getipython import get_ipython
11
11
12 from IPython.utils.importstring import import_item
12 from IPython.utils.importstring import import_item
13 from IPython.utils.py3compat import string_types
13 from IPython.utils.py3compat import string_types
14 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
14 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
15
15
16 from .comm import Comm
16 from .comm import Comm
17
17
18
18
19 def lazy_keys(dikt):
19 def lazy_keys(dikt):
20 """Return lazy-evaluated string representation of a dictionary's keys
20 """Return lazy-evaluated string representation of a dictionary's keys
21
21
22 Key list is only constructed if it will actually be used.
22 Key list is only constructed if it will actually be used.
23 Used for debug-logging.
23 Used for debug-logging.
24 """
24 """
25 return LazyEvaluate(lambda d: list(d.keys()))
25 return LazyEvaluate(lambda d: list(d.keys()))
26
26
27
27
28 class CommManager(LoggingConfigurable):
28 class CommManager(LoggingConfigurable):
29 """Manager for Comms in the Kernel"""
29 """Manager for Comms in the Kernel"""
30
30
31 # If this is instantiated by a non-IPython kernel, shell will be None
31 # If this is instantiated by a non-IPython kernel, shell will be None
32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
33 allow_none=True)
33 allow_none=True)
34 kernel = Instance('ipython_kernel.zmq.kernelbase.Kernel')
34 kernel = Instance('ipython_kernel.kernelbase.Kernel')
35
35
36 iopub_socket = Any()
36 iopub_socket = Any()
37 def _iopub_socket_default(self):
37 def _iopub_socket_default(self):
38 return self.kernel.iopub_socket
38 return self.kernel.iopub_socket
39 session = Instance('ipython_kernel.zmq.session.Session')
39 session = Instance('ipython_kernel.session.Session')
40 def _session_default(self):
40 def _session_default(self):
41 return self.kernel.session
41 return self.kernel.session
42
42
43 comms = Dict()
43 comms = Dict()
44 targets = Dict()
44 targets = Dict()
45
45
46 # Public APIs
46 # Public APIs
47
47
48 def register_target(self, target_name, f):
48 def register_target(self, target_name, f):
49 """Register a callable f for a given target name
49 """Register a callable f for a given target name
50
50
51 f will be called with two arguments when a comm_open message is received with `target`:
51 f will be called with two arguments when a comm_open message is received with `target`:
52
52
53 - the Comm instance
53 - the Comm instance
54 - the `comm_open` message itself.
54 - the `comm_open` message itself.
55
55
56 f can be a Python callable or an import string for one.
56 f can be a Python callable or an import string for one.
57 """
57 """
58 if isinstance(f, string_types):
58 if isinstance(f, string_types):
59 f = import_item(f)
59 f = import_item(f)
60
60
61 self.targets[target_name] = f
61 self.targets[target_name] = f
62
62
63 def unregister_target(self, target_name, f):
63 def unregister_target(self, target_name, f):
64 """Unregister a callable registered with register_target"""
64 """Unregister a callable registered with register_target"""
65 return self.targets.pop(target_name);
65 return self.targets.pop(target_name);
66
66
67 def register_comm(self, comm):
67 def register_comm(self, comm):
68 """Register a new comm"""
68 """Register a new comm"""
69 comm_id = comm.comm_id
69 comm_id = comm.comm_id
70 comm.shell = self.shell
70 comm.shell = self.shell
71 comm.kernel = self.kernel
71 comm.kernel = self.kernel
72 comm.iopub_socket = self.iopub_socket
72 comm.iopub_socket = self.iopub_socket
73 self.comms[comm_id] = comm
73 self.comms[comm_id] = comm
74 return comm_id
74 return comm_id
75
75
76 def unregister_comm(self, comm):
76 def unregister_comm(self, comm):
77 """Unregister a comm, and close its counterpart"""
77 """Unregister a comm, and close its counterpart"""
78 # unlike get_comm, this should raise a KeyError
78 # unlike get_comm, this should raise a KeyError
79 comm = self.comms.pop(comm.comm_id)
79 comm = self.comms.pop(comm.comm_id)
80
80
81 def get_comm(self, comm_id):
81 def get_comm(self, comm_id):
82 """Get a comm with a particular id
82 """Get a comm with a particular id
83
83
84 Returns the comm if found, otherwise None.
84 Returns the comm if found, otherwise None.
85
85
86 This will not raise an error,
86 This will not raise an error,
87 it will log messages if the comm cannot be found.
87 it will log messages if the comm cannot be found.
88 """
88 """
89 if comm_id not in self.comms:
89 if comm_id not in self.comms:
90 self.log.error("No such comm: %s", comm_id)
90 self.log.error("No such comm: %s", comm_id)
91 self.log.debug("Current comms: %s", lazy_keys(self.comms))
91 self.log.debug("Current comms: %s", lazy_keys(self.comms))
92 return
92 return
93 # call, because we store weakrefs
93 # call, because we store weakrefs
94 comm = self.comms[comm_id]
94 comm = self.comms[comm_id]
95 return comm
95 return comm
96
96
97 # Message handlers
97 # Message handlers
98 def comm_open(self, stream, ident, msg):
98 def comm_open(self, stream, ident, msg):
99 """Handler for comm_open messages"""
99 """Handler for comm_open messages"""
100 content = msg['content']
100 content = msg['content']
101 comm_id = content['comm_id']
101 comm_id = content['comm_id']
102 target_name = content['target_name']
102 target_name = content['target_name']
103 f = self.targets.get(target_name, None)
103 f = self.targets.get(target_name, None)
104 comm = Comm(comm_id=comm_id,
104 comm = Comm(comm_id=comm_id,
105 shell=self.shell,
105 shell=self.shell,
106 kernel=self.kernel,
106 kernel=self.kernel,
107 iopub_socket=self.iopub_socket,
107 iopub_socket=self.iopub_socket,
108 primary=False,
108 primary=False,
109 )
109 )
110 self.register_comm(comm)
110 self.register_comm(comm)
111 if f is None:
111 if f is None:
112 self.log.error("No such comm target registered: %s", target_name)
112 self.log.error("No such comm target registered: %s", target_name)
113 else:
113 else:
114 try:
114 try:
115 f(comm, msg)
115 f(comm, msg)
116 return
116 return
117 except Exception:
117 except Exception:
118 self.log.error("Exception opening comm with target: %s", target_name, exc_info=True)
118 self.log.error("Exception opening comm with target: %s", target_name, exc_info=True)
119
119
120 # Failure.
120 # Failure.
121 try:
121 try:
122 comm.close()
122 comm.close()
123 except:
123 except:
124 self.log.error("""Could not close comm during `comm_open` failure
124 self.log.error("""Could not close comm during `comm_open` failure
125 clean-up. The comm may not have been opened yet.""", exc_info=True)
125 clean-up. The comm may not have been opened yet.""", exc_info=True)
126
126
127 def comm_msg(self, stream, ident, msg):
127 def comm_msg(self, stream, ident, msg):
128 """Handler for comm_msg messages"""
128 """Handler for comm_msg messages"""
129 content = msg['content']
129 content = msg['content']
130 comm_id = content['comm_id']
130 comm_id = content['comm_id']
131 comm = self.get_comm(comm_id)
131 comm = self.get_comm(comm_id)
132 if comm is None:
132 if comm is None:
133 # no such comm
133 # no such comm
134 return
134 return
135 try:
135 try:
136 comm.handle_msg(msg)
136 comm.handle_msg(msg)
137 except Exception:
137 except Exception:
138 self.log.error("Exception in comm_msg for %s", comm_id, exc_info=True)
138 self.log.error("Exception in comm_msg for %s", comm_id, exc_info=True)
139
139
140 def comm_close(self, stream, ident, msg):
140 def comm_close(self, stream, ident, msg):
141 """Handler for comm_close messages"""
141 """Handler for comm_close messages"""
142 content = msg['content']
142 content = msg['content']
143 comm_id = content['comm_id']
143 comm_id = content['comm_id']
144 comm = self.get_comm(comm_id)
144 comm = self.get_comm(comm_id)
145 if comm is None:
145 if comm is None:
146 # no such comm
146 # no such comm
147 self.log.debug("No such comm to close: %s", comm_id)
147 self.log.debug("No such comm to close: %s", comm_id)
148 return
148 return
149 del self.comms[comm_id]
149 del self.comms[comm_id]
150
150
151 try:
151 try:
152 comm.handle_close(msg)
152 comm.handle_close(msg)
153 except Exception:
153 except Exception:
154 self.log.error("Exception handling comm_close for %s", comm_id, exc_info=True)
154 self.log.error("Exception handling comm_close for %s", comm_id, exc_info=True)
155
155
156
156
157 __all__ = ['CommManager']
157 __all__ = ['CommManager']
@@ -1,70 +1,70 b''
1 """Publishing native (typically pickled) objects.
1 """Publishing native (typically pickled) objects.
2 """
2 """
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2012 The IPython Development Team
5 # Copyright (C) 2012 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from IPython.config import Configurable
15 from IPython.config import Configurable
16 from ipython_kernel.inprocess.socket import SocketABC
16 from ipython_kernel.inprocess.socket import SocketABC
17 from IPython.utils.jsonutil import json_clean
17 from IPython.utils.jsonutil import json_clean
18 from IPython.utils.traitlets import Instance, Dict, CBytes
18 from IPython.utils.traitlets import Instance, Dict, CBytes
19 from ipython_kernel.zmq.serialize import serialize_object
19 from ipython_kernel.serialize import serialize_object
20 from ipython_kernel.zmq.session import Session, extract_header
20 from ipython_kernel.session import Session, extract_header
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Code
23 # Code
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 class ZMQDataPublisher(Configurable):
27 class ZMQDataPublisher(Configurable):
28
28
29 topic = topic = CBytes(b'datapub')
29 topic = topic = CBytes(b'datapub')
30 session = Instance(Session, allow_none=True)
30 session = Instance(Session, allow_none=True)
31 pub_socket = Instance(SocketABC, allow_none=True)
31 pub_socket = Instance(SocketABC, allow_none=True)
32 parent_header = Dict({})
32 parent_header = Dict({})
33
33
34 def set_parent(self, parent):
34 def set_parent(self, parent):
35 """Set the parent for outbound messages."""
35 """Set the parent for outbound messages."""
36 self.parent_header = extract_header(parent)
36 self.parent_header = extract_header(parent)
37
37
38 def publish_data(self, data):
38 def publish_data(self, data):
39 """publish a data_message on the IOPub channel
39 """publish a data_message on the IOPub channel
40
40
41 Parameters
41 Parameters
42 ----------
42 ----------
43
43
44 data : dict
44 data : dict
45 The data to be published. Think of it as a namespace.
45 The data to be published. Think of it as a namespace.
46 """
46 """
47 session = self.session
47 session = self.session
48 buffers = serialize_object(data,
48 buffers = serialize_object(data,
49 buffer_threshold=session.buffer_threshold,
49 buffer_threshold=session.buffer_threshold,
50 item_threshold=session.item_threshold,
50 item_threshold=session.item_threshold,
51 )
51 )
52 content = json_clean(dict(keys=data.keys()))
52 content = json_clean(dict(keys=data.keys()))
53 session.send(self.pub_socket, 'data_message', content=content,
53 session.send(self.pub_socket, 'data_message', content=content,
54 parent=self.parent_header,
54 parent=self.parent_header,
55 buffers=buffers,
55 buffers=buffers,
56 ident=self.topic,
56 ident=self.topic,
57 )
57 )
58
58
59
59
60 def publish_data(data):
60 def publish_data(data):
61 """publish a data_message on the IOPub channel
61 """publish a data_message on the IOPub channel
62
62
63 Parameters
63 Parameters
64 ----------
64 ----------
65
65
66 data : dict
66 data : dict
67 The data to be published. Think of it as a namespace.
67 The data to be published. Think of it as a namespace.
68 """
68 """
69 from ipython_kernel.zmq.zmqshell import ZMQInteractiveShell
69 from ipython_kernel.zmqshell import ZMQInteractiveShell
70 ZMQInteractiveShell.instance().data_pub.publish_data(data)
70 ZMQInteractiveShell.instance().data_pub.publish_data(data)
1 NO CONTENT: file renamed from ipython_kernel/zmq/displayhook.py to ipython_kernel/displayhook.py
NO CONTENT: file renamed from ipython_kernel/zmq/displayhook.py to ipython_kernel/displayhook.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/embed.py to ipython_kernel/embed.py
NO CONTENT: file renamed from ipython_kernel/zmq/embed.py to ipython_kernel/embed.py
@@ -1,273 +1,273 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Event loop integration for the ZeroMQ-based kernels."""
2 """Event loop integration for the ZeroMQ-based kernels."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import sys
8 import sys
9
9
10 import zmq
10 import zmq
11
11
12 from IPython.config.application import Application
12 from IPython.config.application import Application
13 from IPython.utils import io
13 from IPython.utils import io
14 from IPython.lib.inputhook import _use_appnope
14 from IPython.lib.inputhook import _use_appnope
15
15
16 def _notify_stream_qt(kernel, stream):
16 def _notify_stream_qt(kernel, stream):
17
17
18 from IPython.external.qt_for_kernel import QtCore
18 from IPython.external.qt_for_kernel import QtCore
19
19
20 if _use_appnope() and kernel._darwin_app_nap:
20 if _use_appnope() and kernel._darwin_app_nap:
21 from appnope import nope_scope as context
21 from appnope import nope_scope as context
22 else:
22 else:
23 from IPython.core.interactiveshell import NoOpContext as context
23 from IPython.core.interactiveshell import NoOpContext as context
24
24
25 def process_stream_events():
25 def process_stream_events():
26 while stream.getsockopt(zmq.EVENTS) & zmq.POLLIN:
26 while stream.getsockopt(zmq.EVENTS) & zmq.POLLIN:
27 with context():
27 with context():
28 kernel.do_one_iteration()
28 kernel.do_one_iteration()
29
29
30 fd = stream.getsockopt(zmq.FD)
30 fd = stream.getsockopt(zmq.FD)
31 notifier = QtCore.QSocketNotifier(fd, QtCore.QSocketNotifier.Read, kernel.app)
31 notifier = QtCore.QSocketNotifier(fd, QtCore.QSocketNotifier.Read, kernel.app)
32 notifier.activated.connect(process_stream_events)
32 notifier.activated.connect(process_stream_events)
33
33
34 # mapping of keys to loop functions
34 # mapping of keys to loop functions
35 loop_map = {
35 loop_map = {
36 'inline': None,
36 'inline': None,
37 'nbagg': None,
37 'nbagg': None,
38 'notebook': None,
38 'notebook': None,
39 None : None,
39 None : None,
40 }
40 }
41
41
42 def register_integration(*toolkitnames):
42 def register_integration(*toolkitnames):
43 """Decorator to register an event loop to integrate with the IPython kernel
43 """Decorator to register an event loop to integrate with the IPython kernel
44
44
45 The decorator takes names to register the event loop as for the %gui magic.
45 The decorator takes names to register the event loop as for the %gui magic.
46 You can provide alternative names for the same toolkit.
46 You can provide alternative names for the same toolkit.
47
47
48 The decorated function should take a single argument, the IPython kernel
48 The decorated function should take a single argument, the IPython kernel
49 instance, arrange for the event loop to call ``kernel.do_one_iteration()``
49 instance, arrange for the event loop to call ``kernel.do_one_iteration()``
50 at least every ``kernel._poll_interval`` seconds, and start the event loop.
50 at least every ``kernel._poll_interval`` seconds, and start the event loop.
51
51
52 :mod:`ipython_kernel.zmq.eventloops` provides and registers such functions
52 :mod:`ipython_kernel.eventloops` provides and registers such functions
53 for a few common event loops.
53 for a few common event loops.
54 """
54 """
55 def decorator(func):
55 def decorator(func):
56 for name in toolkitnames:
56 for name in toolkitnames:
57 loop_map[name] = func
57 loop_map[name] = func
58 return func
58 return func
59
59
60 return decorator
60 return decorator
61
61
62
62
63 @register_integration('qt', 'qt4')
63 @register_integration('qt', 'qt4')
64 def loop_qt4(kernel):
64 def loop_qt4(kernel):
65 """Start a kernel with PyQt4 event loop integration."""
65 """Start a kernel with PyQt4 event loop integration."""
66
66
67 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
67 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
68
68
69 kernel.app = get_app_qt4([" "])
69 kernel.app = get_app_qt4([" "])
70 kernel.app.setQuitOnLastWindowClosed(False)
70 kernel.app.setQuitOnLastWindowClosed(False)
71
71
72 for s in kernel.shell_streams:
72 for s in kernel.shell_streams:
73 _notify_stream_qt(kernel, s)
73 _notify_stream_qt(kernel, s)
74
74
75 start_event_loop_qt4(kernel.app)
75 start_event_loop_qt4(kernel.app)
76
76
77 @register_integration('qt5')
77 @register_integration('qt5')
78 def loop_qt5(kernel):
78 def loop_qt5(kernel):
79 """Start a kernel with PyQt5 event loop integration."""
79 """Start a kernel with PyQt5 event loop integration."""
80 os.environ['QT_API'] = 'pyqt5'
80 os.environ['QT_API'] = 'pyqt5'
81 return loop_qt4(kernel)
81 return loop_qt4(kernel)
82
82
83
83
84 @register_integration('wx')
84 @register_integration('wx')
85 def loop_wx(kernel):
85 def loop_wx(kernel):
86 """Start a kernel with wx event loop support."""
86 """Start a kernel with wx event loop support."""
87
87
88 import wx
88 import wx
89 from IPython.lib.guisupport import start_event_loop_wx
89 from IPython.lib.guisupport import start_event_loop_wx
90
90
91 if _use_appnope() and kernel._darwin_app_nap:
91 if _use_appnope() and kernel._darwin_app_nap:
92 # we don't hook up App Nap contexts for Wx,
92 # we don't hook up App Nap contexts for Wx,
93 # just disable it outright.
93 # just disable it outright.
94 from appnope import nope
94 from appnope import nope
95 nope()
95 nope()
96
96
97 doi = kernel.do_one_iteration
97 doi = kernel.do_one_iteration
98 # Wx uses milliseconds
98 # Wx uses milliseconds
99 poll_interval = int(1000*kernel._poll_interval)
99 poll_interval = int(1000*kernel._poll_interval)
100
100
101 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
101 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
102 # We make the Frame hidden when we create it in the main app below.
102 # We make the Frame hidden when we create it in the main app below.
103 class TimerFrame(wx.Frame):
103 class TimerFrame(wx.Frame):
104 def __init__(self, func):
104 def __init__(self, func):
105 wx.Frame.__init__(self, None, -1)
105 wx.Frame.__init__(self, None, -1)
106 self.timer = wx.Timer(self)
106 self.timer = wx.Timer(self)
107 # Units for the timer are in milliseconds
107 # Units for the timer are in milliseconds
108 self.timer.Start(poll_interval)
108 self.timer.Start(poll_interval)
109 self.Bind(wx.EVT_TIMER, self.on_timer)
109 self.Bind(wx.EVT_TIMER, self.on_timer)
110 self.func = func
110 self.func = func
111
111
112 def on_timer(self, event):
112 def on_timer(self, event):
113 self.func()
113 self.func()
114
114
115 # We need a custom wx.App to create our Frame subclass that has the
115 # We need a custom wx.App to create our Frame subclass that has the
116 # wx.Timer to drive the ZMQ event loop.
116 # wx.Timer to drive the ZMQ event loop.
117 class IPWxApp(wx.App):
117 class IPWxApp(wx.App):
118 def OnInit(self):
118 def OnInit(self):
119 self.frame = TimerFrame(doi)
119 self.frame = TimerFrame(doi)
120 self.frame.Show(False)
120 self.frame.Show(False)
121 return True
121 return True
122
122
123 # The redirect=False here makes sure that wx doesn't replace
123 # The redirect=False here makes sure that wx doesn't replace
124 # sys.stdout/stderr with its own classes.
124 # sys.stdout/stderr with its own classes.
125 kernel.app = IPWxApp(redirect=False)
125 kernel.app = IPWxApp(redirect=False)
126
126
127 # The import of wx on Linux sets the handler for signal.SIGINT
127 # The import of wx on Linux sets the handler for signal.SIGINT
128 # to 0. This is a bug in wx or gtk. We fix by just setting it
128 # to 0. This is a bug in wx or gtk. We fix by just setting it
129 # back to the Python default.
129 # back to the Python default.
130 import signal
130 import signal
131 if not callable(signal.getsignal(signal.SIGINT)):
131 if not callable(signal.getsignal(signal.SIGINT)):
132 signal.signal(signal.SIGINT, signal.default_int_handler)
132 signal.signal(signal.SIGINT, signal.default_int_handler)
133
133
134 start_event_loop_wx(kernel.app)
134 start_event_loop_wx(kernel.app)
135
135
136
136
137 @register_integration('tk')
137 @register_integration('tk')
138 def loop_tk(kernel):
138 def loop_tk(kernel):
139 """Start a kernel with the Tk event loop."""
139 """Start a kernel with the Tk event loop."""
140
140
141 try:
141 try:
142 from tkinter import Tk # Py 3
142 from tkinter import Tk # Py 3
143 except ImportError:
143 except ImportError:
144 from Tkinter import Tk # Py 2
144 from Tkinter import Tk # Py 2
145 doi = kernel.do_one_iteration
145 doi = kernel.do_one_iteration
146 # Tk uses milliseconds
146 # Tk uses milliseconds
147 poll_interval = int(1000*kernel._poll_interval)
147 poll_interval = int(1000*kernel._poll_interval)
148 # For Tkinter, we create a Tk object and call its withdraw method.
148 # For Tkinter, we create a Tk object and call its withdraw method.
149 class Timer(object):
149 class Timer(object):
150 def __init__(self, func):
150 def __init__(self, func):
151 self.app = Tk()
151 self.app = Tk()
152 self.app.withdraw()
152 self.app.withdraw()
153 self.func = func
153 self.func = func
154
154
155 def on_timer(self):
155 def on_timer(self):
156 self.func()
156 self.func()
157 self.app.after(poll_interval, self.on_timer)
157 self.app.after(poll_interval, self.on_timer)
158
158
159 def start(self):
159 def start(self):
160 self.on_timer() # Call it once to get things going.
160 self.on_timer() # Call it once to get things going.
161 self.app.mainloop()
161 self.app.mainloop()
162
162
163 kernel.timer = Timer(doi)
163 kernel.timer = Timer(doi)
164 kernel.timer.start()
164 kernel.timer.start()
165
165
166
166
167 @register_integration('gtk')
167 @register_integration('gtk')
168 def loop_gtk(kernel):
168 def loop_gtk(kernel):
169 """Start the kernel, coordinating with the GTK event loop"""
169 """Start the kernel, coordinating with the GTK event loop"""
170 from .gui.gtkembed import GTKEmbed
170 from .gui.gtkembed import GTKEmbed
171
171
172 gtk_kernel = GTKEmbed(kernel)
172 gtk_kernel = GTKEmbed(kernel)
173 gtk_kernel.start()
173 gtk_kernel.start()
174
174
175
175
176 @register_integration('gtk3')
176 @register_integration('gtk3')
177 def loop_gtk3(kernel):
177 def loop_gtk3(kernel):
178 """Start the kernel, coordinating with the GTK event loop"""
178 """Start the kernel, coordinating with the GTK event loop"""
179 from .gui.gtk3embed import GTKEmbed
179 from .gui.gtk3embed import GTKEmbed
180
180
181 gtk_kernel = GTKEmbed(kernel)
181 gtk_kernel = GTKEmbed(kernel)
182 gtk_kernel.start()
182 gtk_kernel.start()
183
183
184
184
185 @register_integration('osx')
185 @register_integration('osx')
186 def loop_cocoa(kernel):
186 def loop_cocoa(kernel):
187 """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
187 """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
188 via the matplotlib MacOSX backend.
188 via the matplotlib MacOSX backend.
189 """
189 """
190 import matplotlib
190 import matplotlib
191 if matplotlib.__version__ < '1.1.0':
191 if matplotlib.__version__ < '1.1.0':
192 kernel.log.warn(
192 kernel.log.warn(
193 "MacOSX backend in matplotlib %s doesn't have a Timer, "
193 "MacOSX backend in matplotlib %s doesn't have a Timer, "
194 "falling back on Tk for CFRunLoop integration. Note that "
194 "falling back on Tk for CFRunLoop integration. Note that "
195 "even this won't work if Tk is linked against X11 instead of "
195 "even this won't work if Tk is linked against X11 instead of "
196 "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
196 "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
197 "you must use matplotlib >= 1.1.0, or a native libtk."
197 "you must use matplotlib >= 1.1.0, or a native libtk."
198 )
198 )
199 return loop_tk(kernel)
199 return loop_tk(kernel)
200
200
201 from matplotlib.backends.backend_macosx import TimerMac, show
201 from matplotlib.backends.backend_macosx import TimerMac, show
202
202
203 # scale interval for sec->ms
203 # scale interval for sec->ms
204 poll_interval = int(1000*kernel._poll_interval)
204 poll_interval = int(1000*kernel._poll_interval)
205
205
206 real_excepthook = sys.excepthook
206 real_excepthook = sys.excepthook
207 def handle_int(etype, value, tb):
207 def handle_int(etype, value, tb):
208 """don't let KeyboardInterrupts look like crashes"""
208 """don't let KeyboardInterrupts look like crashes"""
209 if etype is KeyboardInterrupt:
209 if etype is KeyboardInterrupt:
210 io.raw_print("KeyboardInterrupt caught in CFRunLoop")
210 io.raw_print("KeyboardInterrupt caught in CFRunLoop")
211 else:
211 else:
212 real_excepthook(etype, value, tb)
212 real_excepthook(etype, value, tb)
213
213
214 # add doi() as a Timer to the CFRunLoop
214 # add doi() as a Timer to the CFRunLoop
215 def doi():
215 def doi():
216 # restore excepthook during IPython code
216 # restore excepthook during IPython code
217 sys.excepthook = real_excepthook
217 sys.excepthook = real_excepthook
218 kernel.do_one_iteration()
218 kernel.do_one_iteration()
219 # and back:
219 # and back:
220 sys.excepthook = handle_int
220 sys.excepthook = handle_int
221
221
222 t = TimerMac(poll_interval)
222 t = TimerMac(poll_interval)
223 t.add_callback(doi)
223 t.add_callback(doi)
224 t.start()
224 t.start()
225
225
226 # but still need a Poller for when there are no active windows,
226 # but still need a Poller for when there are no active windows,
227 # during which time mainloop() returns immediately
227 # during which time mainloop() returns immediately
228 poller = zmq.Poller()
228 poller = zmq.Poller()
229 if kernel.control_stream:
229 if kernel.control_stream:
230 poller.register(kernel.control_stream.socket, zmq.POLLIN)
230 poller.register(kernel.control_stream.socket, zmq.POLLIN)
231 for stream in kernel.shell_streams:
231 for stream in kernel.shell_streams:
232 poller.register(stream.socket, zmq.POLLIN)
232 poller.register(stream.socket, zmq.POLLIN)
233
233
234 while True:
234 while True:
235 try:
235 try:
236 # double nested try/except, to properly catch KeyboardInterrupt
236 # double nested try/except, to properly catch KeyboardInterrupt
237 # due to pyzmq Issue #130
237 # due to pyzmq Issue #130
238 try:
238 try:
239 # don't let interrupts during mainloop invoke crash_handler:
239 # don't let interrupts during mainloop invoke crash_handler:
240 sys.excepthook = handle_int
240 sys.excepthook = handle_int
241 show.mainloop()
241 show.mainloop()
242 sys.excepthook = real_excepthook
242 sys.excepthook = real_excepthook
243 # use poller if mainloop returned (no windows)
243 # use poller if mainloop returned (no windows)
244 # scale by extra factor of 10, since it's a real poll
244 # scale by extra factor of 10, since it's a real poll
245 poller.poll(10*poll_interval)
245 poller.poll(10*poll_interval)
246 kernel.do_one_iteration()
246 kernel.do_one_iteration()
247 except:
247 except:
248 raise
248 raise
249 except KeyboardInterrupt:
249 except KeyboardInterrupt:
250 # Ctrl-C shouldn't crash the kernel
250 # Ctrl-C shouldn't crash the kernel
251 io.raw_print("KeyboardInterrupt caught in kernel")
251 io.raw_print("KeyboardInterrupt caught in kernel")
252 finally:
252 finally:
253 # ensure excepthook is restored
253 # ensure excepthook is restored
254 sys.excepthook = real_excepthook
254 sys.excepthook = real_excepthook
255
255
256
256
257
257
258 def enable_gui(gui, kernel=None):
258 def enable_gui(gui, kernel=None):
259 """Enable integration with a given GUI"""
259 """Enable integration with a given GUI"""
260 if gui not in loop_map:
260 if gui not in loop_map:
261 e = "Invalid GUI request %r, valid ones are:%s" % (gui, loop_map.keys())
261 e = "Invalid GUI request %r, valid ones are:%s" % (gui, loop_map.keys())
262 raise ValueError(e)
262 raise ValueError(e)
263 if kernel is None:
263 if kernel is None:
264 if Application.initialized():
264 if Application.initialized():
265 kernel = getattr(Application.instance(), 'kernel', None)
265 kernel = getattr(Application.instance(), 'kernel', None)
266 if kernel is None:
266 if kernel is None:
267 raise RuntimeError("You didn't specify a kernel,"
267 raise RuntimeError("You didn't specify a kernel,"
268 " and no IPython Application with a kernel appears to be running."
268 " and no IPython Application with a kernel appears to be running."
269 )
269 )
270 loop = loop_map[gui]
270 loop = loop_map[gui]
271 if loop and kernel.eventloop is not None and kernel.eventloop is not loop:
271 if loop and kernel.eventloop is not None and kernel.eventloop is not loop:
272 raise RuntimeError("Cannot activate multiple GUI eventloops")
272 raise RuntimeError("Cannot activate multiple GUI eventloops")
273 kernel.eventloop = loop
273 kernel.eventloop = loop
1 NO CONTENT: file renamed from ipython_kernel/zmq/gui/__init__.py to ipython_kernel/gui/__init__.py
NO CONTENT: file renamed from ipython_kernel/zmq/gui/__init__.py to ipython_kernel/gui/__init__.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/gui/gtk3embed.py to ipython_kernel/gui/gtk3embed.py
NO CONTENT: file renamed from ipython_kernel/zmq/gui/gtk3embed.py to ipython_kernel/gui/gtk3embed.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/gui/gtkembed.py to ipython_kernel/gui/gtkembed.py
NO CONTENT: file renamed from ipython_kernel/zmq/gui/gtkembed.py to ipython_kernel/gui/gtkembed.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/heartbeat.py to ipython_kernel/heartbeat.py
NO CONTENT: file renamed from ipython_kernel/zmq/heartbeat.py to ipython_kernel/heartbeat.py
@@ -1,171 +1,171 b''
1 """An in-process kernel"""
1 """An in-process kernel"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from contextlib import contextmanager
6 from contextlib import contextmanager
7 import logging
7 import logging
8 import sys
8 import sys
9
9
10 from IPython.core.interactiveshell import InteractiveShellABC
10 from IPython.core.interactiveshell import InteractiveShellABC
11 from IPython.utils.jsonutil import json_clean
11 from IPython.utils.jsonutil import json_clean
12 from IPython.utils.traitlets import Any, Enum, Instance, List, Type
12 from IPython.utils.traitlets import Any, Enum, Instance, List, Type
13 from ipython_kernel.zmq.ipkernel import IPythonKernel
13 from ipython_kernel.ipkernel import IPythonKernel
14 from ipython_kernel.zmq.zmqshell import ZMQInteractiveShell
14 from ipython_kernel.zmqshell import ZMQInteractiveShell
15
15
16 from .socket import DummySocket
16 from .socket import DummySocket
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Main kernel class
19 # Main kernel class
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 class InProcessKernel(IPythonKernel):
22 class InProcessKernel(IPythonKernel):
23
23
24 #-------------------------------------------------------------------------
24 #-------------------------------------------------------------------------
25 # InProcessKernel interface
25 # InProcessKernel interface
26 #-------------------------------------------------------------------------
26 #-------------------------------------------------------------------------
27
27
28 # The frontends connected to this kernel.
28 # The frontends connected to this kernel.
29 frontends = List(
29 frontends = List(
30 Instance('ipython_kernel.inprocess.client.InProcessKernelClient',
30 Instance('ipython_kernel.inprocess.client.InProcessKernelClient',
31 allow_none=True)
31 allow_none=True)
32 )
32 )
33
33
34 # The GUI environment that the kernel is running under. This need not be
34 # The GUI environment that the kernel is running under. This need not be
35 # specified for the normal operation for the kernel, but is required for
35 # specified for the normal operation for the kernel, but is required for
36 # IPython's GUI support (including pylab). The default is 'inline' because
36 # IPython's GUI support (including pylab). The default is 'inline' because
37 # it is safe under all GUI toolkits.
37 # it is safe under all GUI toolkits.
38 gui = Enum(('tk', 'gtk', 'wx', 'qt', 'qt4', 'inline'),
38 gui = Enum(('tk', 'gtk', 'wx', 'qt', 'qt4', 'inline'),
39 default_value='inline')
39 default_value='inline')
40
40
41 raw_input_str = Any()
41 raw_input_str = Any()
42 stdout = Any()
42 stdout = Any()
43 stderr = Any()
43 stderr = Any()
44
44
45 #-------------------------------------------------------------------------
45 #-------------------------------------------------------------------------
46 # Kernel interface
46 # Kernel interface
47 #-------------------------------------------------------------------------
47 #-------------------------------------------------------------------------
48
48
49 shell_class = Type(allow_none=True)
49 shell_class = Type(allow_none=True)
50 shell_streams = List()
50 shell_streams = List()
51 control_stream = Any()
51 control_stream = Any()
52 iopub_socket = Instance(DummySocket, ())
52 iopub_socket = Instance(DummySocket, ())
53 stdin_socket = Instance(DummySocket, ())
53 stdin_socket = Instance(DummySocket, ())
54
54
55 def __init__(self, **traits):
55 def __init__(self, **traits):
56 super(InProcessKernel, self).__init__(**traits)
56 super(InProcessKernel, self).__init__(**traits)
57
57
58 self.iopub_socket.on_trait_change(self._io_dispatch, 'message_sent')
58 self.iopub_socket.on_trait_change(self._io_dispatch, 'message_sent')
59 self.shell.kernel = self
59 self.shell.kernel = self
60
60
61 def execute_request(self, stream, ident, parent):
61 def execute_request(self, stream, ident, parent):
62 """ Override for temporary IO redirection. """
62 """ Override for temporary IO redirection. """
63 with self._redirected_io():
63 with self._redirected_io():
64 super(InProcessKernel, self).execute_request(stream, ident, parent)
64 super(InProcessKernel, self).execute_request(stream, ident, parent)
65
65
66 def start(self):
66 def start(self):
67 """ Override registration of dispatchers for streams. """
67 """ Override registration of dispatchers for streams. """
68 self.shell.exit_now = False
68 self.shell.exit_now = False
69
69
70 def _abort_queue(self, stream):
70 def _abort_queue(self, stream):
71 """ The in-process kernel doesn't abort requests. """
71 """ The in-process kernel doesn't abort requests. """
72 pass
72 pass
73
73
74 def _input_request(self, prompt, ident, parent, password=False):
74 def _input_request(self, prompt, ident, parent, password=False):
75 # Flush output before making the request.
75 # Flush output before making the request.
76 self.raw_input_str = None
76 self.raw_input_str = None
77 sys.stderr.flush()
77 sys.stderr.flush()
78 sys.stdout.flush()
78 sys.stdout.flush()
79
79
80 # Send the input request.
80 # Send the input request.
81 content = json_clean(dict(prompt=prompt, password=password))
81 content = json_clean(dict(prompt=prompt, password=password))
82 msg = self.session.msg(u'input_request', content, parent)
82 msg = self.session.msg(u'input_request', content, parent)
83 for frontend in self.frontends:
83 for frontend in self.frontends:
84 if frontend.session.session == parent['header']['session']:
84 if frontend.session.session == parent['header']['session']:
85 frontend.stdin_channel.call_handlers(msg)
85 frontend.stdin_channel.call_handlers(msg)
86 break
86 break
87 else:
87 else:
88 logging.error('No frontend found for raw_input request')
88 logging.error('No frontend found for raw_input request')
89 return str()
89 return str()
90
90
91 # Await a response.
91 # Await a response.
92 while self.raw_input_str is None:
92 while self.raw_input_str is None:
93 frontend.stdin_channel.process_events()
93 frontend.stdin_channel.process_events()
94 return self.raw_input_str
94 return self.raw_input_str
95
95
96 #-------------------------------------------------------------------------
96 #-------------------------------------------------------------------------
97 # Protected interface
97 # Protected interface
98 #-------------------------------------------------------------------------
98 #-------------------------------------------------------------------------
99
99
100 @contextmanager
100 @contextmanager
101 def _redirected_io(self):
101 def _redirected_io(self):
102 """ Temporarily redirect IO to the kernel.
102 """ Temporarily redirect IO to the kernel.
103 """
103 """
104 sys_stdout, sys_stderr = sys.stdout, sys.stderr
104 sys_stdout, sys_stderr = sys.stdout, sys.stderr
105 sys.stdout, sys.stderr = self.stdout, self.stderr
105 sys.stdout, sys.stderr = self.stdout, self.stderr
106 yield
106 yield
107 sys.stdout, sys.stderr = sys_stdout, sys_stderr
107 sys.stdout, sys.stderr = sys_stdout, sys_stderr
108
108
109 #------ Trait change handlers --------------------------------------------
109 #------ Trait change handlers --------------------------------------------
110
110
111 def _io_dispatch(self):
111 def _io_dispatch(self):
112 """ Called when a message is sent to the IO socket.
112 """ Called when a message is sent to the IO socket.
113 """
113 """
114 ident, msg = self.session.recv(self.iopub_socket, copy=False)
114 ident, msg = self.session.recv(self.iopub_socket, copy=False)
115 for frontend in self.frontends:
115 for frontend in self.frontends:
116 frontend.iopub_channel.call_handlers(msg)
116 frontend.iopub_channel.call_handlers(msg)
117
117
118 #------ Trait initializers -----------------------------------------------
118 #------ Trait initializers -----------------------------------------------
119
119
120 def _log_default(self):
120 def _log_default(self):
121 return logging.getLogger(__name__)
121 return logging.getLogger(__name__)
122
122
123 def _session_default(self):
123 def _session_default(self):
124 from ipython_kernel.zmq.session import Session
124 from ipython_kernel.session import Session
125 return Session(parent=self, key=b'')
125 return Session(parent=self, key=b'')
126
126
127 def _shell_class_default(self):
127 def _shell_class_default(self):
128 return InProcessInteractiveShell
128 return InProcessInteractiveShell
129
129
130 def _stdout_default(self):
130 def _stdout_default(self):
131 from ipython_kernel.zmq.iostream import OutStream
131 from ipython_kernel.iostream import OutStream
132 return OutStream(self.session, self.iopub_socket, u'stdout', pipe=False)
132 return OutStream(self.session, self.iopub_socket, u'stdout', pipe=False)
133
133
134 def _stderr_default(self):
134 def _stderr_default(self):
135 from ipython_kernel.zmq.iostream import OutStream
135 from ipython_kernel.iostream import OutStream
136 return OutStream(self.session, self.iopub_socket, u'stderr', pipe=False)
136 return OutStream(self.session, self.iopub_socket, u'stderr', pipe=False)
137
137
138 #-----------------------------------------------------------------------------
138 #-----------------------------------------------------------------------------
139 # Interactive shell subclass
139 # Interactive shell subclass
140 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
141
141
142 class InProcessInteractiveShell(ZMQInteractiveShell):
142 class InProcessInteractiveShell(ZMQInteractiveShell):
143
143
144 kernel = Instance('ipython_kernel.inprocess.ipkernel.InProcessKernel',
144 kernel = Instance('ipython_kernel.inprocess.ipkernel.InProcessKernel',
145 allow_none=True)
145 allow_none=True)
146
146
147 #-------------------------------------------------------------------------
147 #-------------------------------------------------------------------------
148 # InteractiveShell interface
148 # InteractiveShell interface
149 #-------------------------------------------------------------------------
149 #-------------------------------------------------------------------------
150
150
151 def enable_gui(self, gui=None):
151 def enable_gui(self, gui=None):
152 """Enable GUI integration for the kernel."""
152 """Enable GUI integration for the kernel."""
153 from ipython_kernel.zmq.eventloops import enable_gui
153 from ipython_kernel.eventloops import enable_gui
154 if not gui:
154 if not gui:
155 gui = self.kernel.gui
155 gui = self.kernel.gui
156 return enable_gui(gui, kernel=self.kernel)
156 return enable_gui(gui, kernel=self.kernel)
157
157
158 def enable_matplotlib(self, gui=None):
158 def enable_matplotlib(self, gui=None):
159 """Enable matplotlib integration for the kernel."""
159 """Enable matplotlib integration for the kernel."""
160 if not gui:
160 if not gui:
161 gui = self.kernel.gui
161 gui = self.kernel.gui
162 return super(InProcessInteractiveShell, self).enable_matplotlib(gui)
162 return super(InProcessInteractiveShell, self).enable_matplotlib(gui)
163
163
164 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
164 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
165 """Activate pylab support at runtime."""
165 """Activate pylab support at runtime."""
166 if not gui:
166 if not gui:
167 gui = self.kernel.gui
167 gui = self.kernel.gui
168 return super(InProcessInteractiveShell, self).enable_pylab(gui, import_all,
168 return super(InProcessInteractiveShell, self).enable_pylab(gui, import_all,
169 welcome_message)
169 welcome_message)
170
170
171 InteractiveShellABC.register(InProcessInteractiveShell)
171 InteractiveShellABC.register(InProcessInteractiveShell)
1 NO CONTENT: file renamed from ipython_kernel/zmq/iostream.py to ipython_kernel/iostream.py
NO CONTENT: file renamed from ipython_kernel/zmq/iostream.py to ipython_kernel/iostream.py
@@ -1,368 +1,368 b''
1 """The IPython kernel implementation"""
1 """The IPython kernel implementation"""
2
2
3 import getpass
3 import getpass
4 import sys
4 import sys
5 import traceback
5 import traceback
6
6
7 from IPython.core import release
7 from IPython.core import release
8 from IPython.utils.py3compat import builtin_mod, PY3
8 from IPython.utils.py3compat import builtin_mod, PY3
9 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
9 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
10 from IPython.utils.traitlets import Instance, Type, Any, List
10 from IPython.utils.traitlets import Instance, Type, Any, List
11 from IPython.utils.decorators import undoc
11 from IPython.utils.decorators import undoc
12
12
13 from ..comm import CommManager
13 from .comm import CommManager
14 from .kernelbase import Kernel as KernelBase
14 from .kernelbase import Kernel as KernelBase
15 from .serialize import serialize_object, unpack_apply_message
15 from .serialize import serialize_object, unpack_apply_message
16 from .zmqshell import ZMQInteractiveShell
16 from .zmqshell import ZMQInteractiveShell
17
17
18
18
19 def lazy_import_handle_comm_opened(*args, **kwargs):
19 def lazy_import_handle_comm_opened(*args, **kwargs):
20 from IPython.html.widgets import Widget
20 from IPython.html.widgets import Widget
21 Widget.handle_comm_opened(*args, **kwargs)
21 Widget.handle_comm_opened(*args, **kwargs)
22
22
23
23
24 class IPythonKernel(KernelBase):
24 class IPythonKernel(KernelBase):
25 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
25 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
26 allow_none=True)
26 allow_none=True)
27 shell_class = Type(ZMQInteractiveShell)
27 shell_class = Type(ZMQInteractiveShell)
28
28
29 user_module = Any()
29 user_module = Any()
30 def _user_module_changed(self, name, old, new):
30 def _user_module_changed(self, name, old, new):
31 if self.shell is not None:
31 if self.shell is not None:
32 self.shell.user_module = new
32 self.shell.user_module = new
33
33
34 user_ns = Instance(dict, args=None, allow_none=True)
34 user_ns = Instance(dict, args=None, allow_none=True)
35 def _user_ns_changed(self, name, old, new):
35 def _user_ns_changed(self, name, old, new):
36 if self.shell is not None:
36 if self.shell is not None:
37 self.shell.user_ns = new
37 self.shell.user_ns = new
38 self.shell.init_user_ns()
38 self.shell.init_user_ns()
39
39
40 # A reference to the Python builtin 'raw_input' function.
40 # A reference to the Python builtin 'raw_input' function.
41 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
41 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
42 _sys_raw_input = Any()
42 _sys_raw_input = Any()
43 _sys_eval_input = Any()
43 _sys_eval_input = Any()
44
44
45 def __init__(self, **kwargs):
45 def __init__(self, **kwargs):
46 super(IPythonKernel, self).__init__(**kwargs)
46 super(IPythonKernel, self).__init__(**kwargs)
47
47
48 # Initialize the InteractiveShell subclass
48 # Initialize the InteractiveShell subclass
49 self.shell = self.shell_class.instance(parent=self,
49 self.shell = self.shell_class.instance(parent=self,
50 profile_dir = self.profile_dir,
50 profile_dir = self.profile_dir,
51 user_module = self.user_module,
51 user_module = self.user_module,
52 user_ns = self.user_ns,
52 user_ns = self.user_ns,
53 kernel = self,
53 kernel = self,
54 )
54 )
55 self.shell.displayhook.session = self.session
55 self.shell.displayhook.session = self.session
56 self.shell.displayhook.pub_socket = self.iopub_socket
56 self.shell.displayhook.pub_socket = self.iopub_socket
57 self.shell.displayhook.topic = self._topic('execute_result')
57 self.shell.displayhook.topic = self._topic('execute_result')
58 self.shell.display_pub.session = self.session
58 self.shell.display_pub.session = self.session
59 self.shell.display_pub.pub_socket = self.iopub_socket
59 self.shell.display_pub.pub_socket = self.iopub_socket
60 self.shell.data_pub.session = self.session
60 self.shell.data_pub.session = self.session
61 self.shell.data_pub.pub_socket = self.iopub_socket
61 self.shell.data_pub.pub_socket = self.iopub_socket
62
62
63 # TMP - hack while developing
63 # TMP - hack while developing
64 self.shell._reply_content = None
64 self.shell._reply_content = None
65
65
66 self.comm_manager = CommManager(shell=self.shell, parent=self,
66 self.comm_manager = CommManager(shell=self.shell, parent=self,
67 kernel=self)
67 kernel=self)
68 self.comm_manager.register_target('ipython.widget', lazy_import_handle_comm_opened)
68 self.comm_manager.register_target('ipython.widget', lazy_import_handle_comm_opened)
69
69
70 self.shell.configurables.append(self.comm_manager)
70 self.shell.configurables.append(self.comm_manager)
71 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
71 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
72 for msg_type in comm_msg_types:
72 for msg_type in comm_msg_types:
73 self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type)
73 self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type)
74
74
75 help_links = List([
75 help_links = List([
76 {
76 {
77 'text': "Python",
77 'text': "Python",
78 'url': "http://docs.python.org/%i.%i" % sys.version_info[:2],
78 'url': "http://docs.python.org/%i.%i" % sys.version_info[:2],
79 },
79 },
80 {
80 {
81 'text': "IPython",
81 'text': "IPython",
82 'url': "http://ipython.org/documentation.html",
82 'url': "http://ipython.org/documentation.html",
83 },
83 },
84 {
84 {
85 'text': "NumPy",
85 'text': "NumPy",
86 'url': "http://docs.scipy.org/doc/numpy/reference/",
86 'url': "http://docs.scipy.org/doc/numpy/reference/",
87 },
87 },
88 {
88 {
89 'text': "SciPy",
89 'text': "SciPy",
90 'url': "http://docs.scipy.org/doc/scipy/reference/",
90 'url': "http://docs.scipy.org/doc/scipy/reference/",
91 },
91 },
92 {
92 {
93 'text': "Matplotlib",
93 'text': "Matplotlib",
94 'url': "http://matplotlib.org/contents.html",
94 'url': "http://matplotlib.org/contents.html",
95 },
95 },
96 {
96 {
97 'text': "SymPy",
97 'text': "SymPy",
98 'url': "http://docs.sympy.org/latest/index.html",
98 'url': "http://docs.sympy.org/latest/index.html",
99 },
99 },
100 {
100 {
101 'text': "pandas",
101 'text': "pandas",
102 'url': "http://pandas.pydata.org/pandas-docs/stable/",
102 'url': "http://pandas.pydata.org/pandas-docs/stable/",
103 },
103 },
104 ])
104 ])
105
105
106 # Kernel info fields
106 # Kernel info fields
107 implementation = 'ipython'
107 implementation = 'ipython'
108 implementation_version = release.version
108 implementation_version = release.version
109 language_info = {
109 language_info = {
110 'name': 'python',
110 'name': 'python',
111 'version': sys.version.split()[0],
111 'version': sys.version.split()[0],
112 'mimetype': 'text/x-python',
112 'mimetype': 'text/x-python',
113 'codemirror_mode': {'name': 'ipython',
113 'codemirror_mode': {'name': 'ipython',
114 'version': sys.version_info[0]},
114 'version': sys.version_info[0]},
115 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
115 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
116 'nbconvert_exporter': 'python',
116 'nbconvert_exporter': 'python',
117 'file_extension': '.py'
117 'file_extension': '.py'
118 }
118 }
119 @property
119 @property
120 def banner(self):
120 def banner(self):
121 return self.shell.banner
121 return self.shell.banner
122
122
123 def start(self):
123 def start(self):
124 self.shell.exit_now = False
124 self.shell.exit_now = False
125 super(IPythonKernel, self).start()
125 super(IPythonKernel, self).start()
126
126
127 def set_parent(self, ident, parent):
127 def set_parent(self, ident, parent):
128 """Overridden from parent to tell the display hook and output streams
128 """Overridden from parent to tell the display hook and output streams
129 about the parent message.
129 about the parent message.
130 """
130 """
131 super(IPythonKernel, self).set_parent(ident, parent)
131 super(IPythonKernel, self).set_parent(ident, parent)
132 self.shell.set_parent(parent)
132 self.shell.set_parent(parent)
133
133
134 def _forward_input(self, allow_stdin=False):
134 def _forward_input(self, allow_stdin=False):
135 """Forward raw_input and getpass to the current frontend.
135 """Forward raw_input and getpass to the current frontend.
136
136
137 via input_request
137 via input_request
138 """
138 """
139 self._allow_stdin = allow_stdin
139 self._allow_stdin = allow_stdin
140
140
141 if PY3:
141 if PY3:
142 self._sys_raw_input = builtin_mod.input
142 self._sys_raw_input = builtin_mod.input
143 builtin_mod.input = self.raw_input
143 builtin_mod.input = self.raw_input
144 else:
144 else:
145 self._sys_raw_input = builtin_mod.raw_input
145 self._sys_raw_input = builtin_mod.raw_input
146 self._sys_eval_input = builtin_mod.input
146 self._sys_eval_input = builtin_mod.input
147 builtin_mod.raw_input = self.raw_input
147 builtin_mod.raw_input = self.raw_input
148 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
148 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
149 self._save_getpass = getpass.getpass
149 self._save_getpass = getpass.getpass
150 getpass.getpass = self.getpass
150 getpass.getpass = self.getpass
151
151
152 def _restore_input(self):
152 def _restore_input(self):
153 """Restore raw_input, getpass"""
153 """Restore raw_input, getpass"""
154 if PY3:
154 if PY3:
155 builtin_mod.input = self._sys_raw_input
155 builtin_mod.input = self._sys_raw_input
156 else:
156 else:
157 builtin_mod.raw_input = self._sys_raw_input
157 builtin_mod.raw_input = self._sys_raw_input
158 builtin_mod.input = self._sys_eval_input
158 builtin_mod.input = self._sys_eval_input
159
159
160 getpass.getpass = self._save_getpass
160 getpass.getpass = self._save_getpass
161
161
162 @property
162 @property
163 def execution_count(self):
163 def execution_count(self):
164 return self.shell.execution_count
164 return self.shell.execution_count
165
165
166 @execution_count.setter
166 @execution_count.setter
167 def execution_count(self, value):
167 def execution_count(self, value):
168 # Ignore the incrememnting done by KernelBase, in favour of our shell's
168 # Ignore the incrememnting done by KernelBase, in favour of our shell's
169 # execution counter.
169 # execution counter.
170 pass
170 pass
171
171
172 def do_execute(self, code, silent, store_history=True,
172 def do_execute(self, code, silent, store_history=True,
173 user_expressions=None, allow_stdin=False):
173 user_expressions=None, allow_stdin=False):
174 shell = self.shell # we'll need this a lot here
174 shell = self.shell # we'll need this a lot here
175
175
176 self._forward_input(allow_stdin)
176 self._forward_input(allow_stdin)
177
177
178 reply_content = {}
178 reply_content = {}
179 # FIXME: the shell calls the exception handler itself.
179 # FIXME: the shell calls the exception handler itself.
180 shell._reply_content = None
180 shell._reply_content = None
181 try:
181 try:
182 shell.run_cell(code, store_history=store_history, silent=silent)
182 shell.run_cell(code, store_history=store_history, silent=silent)
183 except:
183 except:
184 status = u'error'
184 status = u'error'
185 # FIXME: this code right now isn't being used yet by default,
185 # FIXME: this code right now isn't being used yet by default,
186 # because the run_cell() call above directly fires off exception
186 # because the run_cell() call above directly fires off exception
187 # reporting. This code, therefore, is only active in the scenario
187 # reporting. This code, therefore, is only active in the scenario
188 # where runlines itself has an unhandled exception. We need to
188 # where runlines itself has an unhandled exception. We need to
189 # uniformize this, for all exception construction to come from a
189 # uniformize this, for all exception construction to come from a
190 # single location in the codbase.
190 # single location in the codbase.
191 etype, evalue, tb = sys.exc_info()
191 etype, evalue, tb = sys.exc_info()
192 tb_list = traceback.format_exception(etype, evalue, tb)
192 tb_list = traceback.format_exception(etype, evalue, tb)
193 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
193 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
194 else:
194 else:
195 status = u'ok'
195 status = u'ok'
196 finally:
196 finally:
197 self._restore_input()
197 self._restore_input()
198
198
199 reply_content[u'status'] = status
199 reply_content[u'status'] = status
200
200
201 # Return the execution counter so clients can display prompts
201 # Return the execution counter so clients can display prompts
202 reply_content['execution_count'] = shell.execution_count - 1
202 reply_content['execution_count'] = shell.execution_count - 1
203
203
204 # FIXME - fish exception info out of shell, possibly left there by
204 # FIXME - fish exception info out of shell, possibly left there by
205 # runlines. We'll need to clean up this logic later.
205 # runlines. We'll need to clean up this logic later.
206 if shell._reply_content is not None:
206 if shell._reply_content is not None:
207 reply_content.update(shell._reply_content)
207 reply_content.update(shell._reply_content)
208 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
208 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
209 reply_content['engine_info'] = e_info
209 reply_content['engine_info'] = e_info
210 # reset after use
210 # reset after use
211 shell._reply_content = None
211 shell._reply_content = None
212
212
213 if 'traceback' in reply_content:
213 if 'traceback' in reply_content:
214 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
214 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
215
215
216
216
217 # At this point, we can tell whether the main code execution succeeded
217 # At this point, we can tell whether the main code execution succeeded
218 # or not. If it did, we proceed to evaluate user_expressions
218 # or not. If it did, we proceed to evaluate user_expressions
219 if reply_content['status'] == 'ok':
219 if reply_content['status'] == 'ok':
220 reply_content[u'user_expressions'] = \
220 reply_content[u'user_expressions'] = \
221 shell.user_expressions(user_expressions or {})
221 shell.user_expressions(user_expressions or {})
222 else:
222 else:
223 # If there was an error, don't even try to compute expressions
223 # If there was an error, don't even try to compute expressions
224 reply_content[u'user_expressions'] = {}
224 reply_content[u'user_expressions'] = {}
225
225
226 # Payloads should be retrieved regardless of outcome, so we can both
226 # Payloads should be retrieved regardless of outcome, so we can both
227 # recover partial output (that could have been generated early in a
227 # recover partial output (that could have been generated early in a
228 # block, before an error) and clear the payload system always.
228 # block, before an error) and clear the payload system always.
229 reply_content[u'payload'] = shell.payload_manager.read_payload()
229 reply_content[u'payload'] = shell.payload_manager.read_payload()
230 # Be agressive about clearing the payload because we don't want
230 # Be agressive about clearing the payload because we don't want
231 # it to sit in memory until the next execute_request comes in.
231 # it to sit in memory until the next execute_request comes in.
232 shell.payload_manager.clear_payload()
232 shell.payload_manager.clear_payload()
233
233
234 return reply_content
234 return reply_content
235
235
236 def do_complete(self, code, cursor_pos):
236 def do_complete(self, code, cursor_pos):
237 # FIXME: IPython completers currently assume single line,
237 # FIXME: IPython completers currently assume single line,
238 # but completion messages give multi-line context
238 # but completion messages give multi-line context
239 # For now, extract line from cell, based on cursor_pos:
239 # For now, extract line from cell, based on cursor_pos:
240 if cursor_pos is None:
240 if cursor_pos is None:
241 cursor_pos = len(code)
241 cursor_pos = len(code)
242 line, offset = line_at_cursor(code, cursor_pos)
242 line, offset = line_at_cursor(code, cursor_pos)
243 line_cursor = cursor_pos - offset
243 line_cursor = cursor_pos - offset
244
244
245 txt, matches = self.shell.complete('', line, line_cursor)
245 txt, matches = self.shell.complete('', line, line_cursor)
246 return {'matches' : matches,
246 return {'matches' : matches,
247 'cursor_end' : cursor_pos,
247 'cursor_end' : cursor_pos,
248 'cursor_start' : cursor_pos - len(txt),
248 'cursor_start' : cursor_pos - len(txt),
249 'metadata' : {},
249 'metadata' : {},
250 'status' : 'ok'}
250 'status' : 'ok'}
251
251
252 def do_inspect(self, code, cursor_pos, detail_level=0):
252 def do_inspect(self, code, cursor_pos, detail_level=0):
253 name = token_at_cursor(code, cursor_pos)
253 name = token_at_cursor(code, cursor_pos)
254 info = self.shell.object_inspect(name)
254 info = self.shell.object_inspect(name)
255
255
256 reply_content = {'status' : 'ok'}
256 reply_content = {'status' : 'ok'}
257 reply_content['data'] = data = {}
257 reply_content['data'] = data = {}
258 reply_content['metadata'] = {}
258 reply_content['metadata'] = {}
259 reply_content['found'] = info['found']
259 reply_content['found'] = info['found']
260 if info['found']:
260 if info['found']:
261 info_text = self.shell.object_inspect_text(
261 info_text = self.shell.object_inspect_text(
262 name,
262 name,
263 detail_level=detail_level,
263 detail_level=detail_level,
264 )
264 )
265 data['text/plain'] = info_text
265 data['text/plain'] = info_text
266
266
267 return reply_content
267 return reply_content
268
268
269 def do_history(self, hist_access_type, output, raw, session=None, start=None,
269 def do_history(self, hist_access_type, output, raw, session=None, start=None,
270 stop=None, n=None, pattern=None, unique=False):
270 stop=None, n=None, pattern=None, unique=False):
271 if hist_access_type == 'tail':
271 if hist_access_type == 'tail':
272 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
272 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
273 include_latest=True)
273 include_latest=True)
274
274
275 elif hist_access_type == 'range':
275 elif hist_access_type == 'range':
276 hist = self.shell.history_manager.get_range(session, start, stop,
276 hist = self.shell.history_manager.get_range(session, start, stop,
277 raw=raw, output=output)
277 raw=raw, output=output)
278
278
279 elif hist_access_type == 'search':
279 elif hist_access_type == 'search':
280 hist = self.shell.history_manager.search(
280 hist = self.shell.history_manager.search(
281 pattern, raw=raw, output=output, n=n, unique=unique)
281 pattern, raw=raw, output=output, n=n, unique=unique)
282 else:
282 else:
283 hist = []
283 hist = []
284
284
285 return {'history' : list(hist)}
285 return {'history' : list(hist)}
286
286
287 def do_shutdown(self, restart):
287 def do_shutdown(self, restart):
288 self.shell.exit_now = True
288 self.shell.exit_now = True
289 return dict(status='ok', restart=restart)
289 return dict(status='ok', restart=restart)
290
290
291 def do_is_complete(self, code):
291 def do_is_complete(self, code):
292 status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
292 status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
293 r = {'status': status}
293 r = {'status': status}
294 if status == 'incomplete':
294 if status == 'incomplete':
295 r['indent'] = ' ' * indent_spaces
295 r['indent'] = ' ' * indent_spaces
296 return r
296 return r
297
297
298 def do_apply(self, content, bufs, msg_id, reply_metadata):
298 def do_apply(self, content, bufs, msg_id, reply_metadata):
299 shell = self.shell
299 shell = self.shell
300 try:
300 try:
301 working = shell.user_ns
301 working = shell.user_ns
302
302
303 prefix = "_"+str(msg_id).replace("-","")+"_"
303 prefix = "_"+str(msg_id).replace("-","")+"_"
304
304
305 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
305 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
306
306
307 fname = getattr(f, '__name__', 'f')
307 fname = getattr(f, '__name__', 'f')
308
308
309 fname = prefix+"f"
309 fname = prefix+"f"
310 argname = prefix+"args"
310 argname = prefix+"args"
311 kwargname = prefix+"kwargs"
311 kwargname = prefix+"kwargs"
312 resultname = prefix+"result"
312 resultname = prefix+"result"
313
313
314 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
314 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
315 # print ns
315 # print ns
316 working.update(ns)
316 working.update(ns)
317 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
317 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
318 try:
318 try:
319 exec(code, shell.user_global_ns, shell.user_ns)
319 exec(code, shell.user_global_ns, shell.user_ns)
320 result = working.get(resultname)
320 result = working.get(resultname)
321 finally:
321 finally:
322 for key in ns:
322 for key in ns:
323 working.pop(key)
323 working.pop(key)
324
324
325 result_buf = serialize_object(result,
325 result_buf = serialize_object(result,
326 buffer_threshold=self.session.buffer_threshold,
326 buffer_threshold=self.session.buffer_threshold,
327 item_threshold=self.session.item_threshold,
327 item_threshold=self.session.item_threshold,
328 )
328 )
329
329
330 except:
330 except:
331 # invoke IPython traceback formatting
331 # invoke IPython traceback formatting
332 shell.showtraceback()
332 shell.showtraceback()
333 # FIXME - fish exception info out of shell, possibly left there by
333 # FIXME - fish exception info out of shell, possibly left there by
334 # run_code. We'll need to clean up this logic later.
334 # run_code. We'll need to clean up this logic later.
335 reply_content = {}
335 reply_content = {}
336 if shell._reply_content is not None:
336 if shell._reply_content is not None:
337 reply_content.update(shell._reply_content)
337 reply_content.update(shell._reply_content)
338 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
338 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
339 reply_content['engine_info'] = e_info
339 reply_content['engine_info'] = e_info
340 # reset after use
340 # reset after use
341 shell._reply_content = None
341 shell._reply_content = None
342
342
343 self.send_response(self.iopub_socket, u'error', reply_content,
343 self.send_response(self.iopub_socket, u'error', reply_content,
344 ident=self._topic('error'))
344 ident=self._topic('error'))
345 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
345 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
346 result_buf = []
346 result_buf = []
347
347
348 if reply_content['ename'] == 'UnmetDependency':
348 if reply_content['ename'] == 'UnmetDependency':
349 reply_metadata['dependencies_met'] = False
349 reply_metadata['dependencies_met'] = False
350 else:
350 else:
351 reply_content = {'status' : 'ok'}
351 reply_content = {'status' : 'ok'}
352
352
353 return reply_content, result_buf
353 return reply_content, result_buf
354
354
355 def do_clear(self):
355 def do_clear(self):
356 self.shell.reset(False)
356 self.shell.reset(False)
357 return dict(status='ok')
357 return dict(status='ok')
358
358
359
359
360 # This exists only for backwards compatibility - use IPythonKernel instead
360 # This exists only for backwards compatibility - use IPythonKernel instead
361
361
362 @undoc
362 @undoc
363 class Kernel(IPythonKernel):
363 class Kernel(IPythonKernel):
364 def __init__(self, *args, **kwargs):
364 def __init__(self, *args, **kwargs):
365 import warnings
365 import warnings
366 warnings.warn('Kernel is a deprecated alias of ipython_kernel.zmq.ipkernel.IPythonKernel',
366 warnings.warn('Kernel is a deprecated alias of ipython_kernel.ipkernel.IPythonKernel',
367 DeprecationWarning)
367 DeprecationWarning)
368 super(Kernel, self).__init__(*args, **kwargs)
368 super(Kernel, self).__init__(*args, **kwargs)
@@ -1,387 +1,387 b''
1 """An Application for launching a kernel"""
1 """An Application for launching a kernel"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 import atexit
8 import atexit
9 import os
9 import os
10 import sys
10 import sys
11 import signal
11 import signal
12
12
13 import zmq
13 import zmq
14 from zmq.eventloop import ioloop
14 from zmq.eventloop import ioloop
15 from zmq.eventloop.zmqstream import ZMQStream
15 from zmq.eventloop.zmqstream import ZMQStream
16
16
17 from IPython.core.ultratb import FormattedTB
17 from IPython.core.ultratb import FormattedTB
18 from IPython.core.application import (
18 from IPython.core.application import (
19 BaseIPythonApplication, base_flags, base_aliases, catch_config_error
19 BaseIPythonApplication, base_flags, base_aliases, catch_config_error
20 )
20 )
21 from IPython.core.profiledir import ProfileDir
21 from IPython.core.profiledir import ProfileDir
22 from IPython.core.shellapp import (
22 from IPython.core.shellapp import (
23 InteractiveShellApp, shell_flags, shell_aliases
23 InteractiveShellApp, shell_flags, shell_aliases
24 )
24 )
25 from IPython.utils import io
25 from IPython.utils import io
26 from IPython.utils.path import filefind
26 from IPython.utils.path import filefind
27 from IPython.utils.traitlets import (
27 from IPython.utils.traitlets import (
28 Any, Instance, Dict, Unicode, Integer, Bool, DottedObjectName, Type,
28 Any, Instance, Dict, Unicode, Integer, Bool, DottedObjectName, Type,
29 )
29 )
30 from IPython.utils.importstring import import_item
30 from IPython.utils.importstring import import_item
31 from jupyter_client import write_connection_file
31 from jupyter_client import write_connection_file
32 from ipython_kernel.connect import ConnectionFileMixin
32 from ipython_kernel.connect import ConnectionFileMixin
33
33
34 # local imports
34 # local imports
35 from .heartbeat import Heartbeat
35 from .heartbeat import Heartbeat
36 from .ipkernel import IPythonKernel
36 from .ipkernel import IPythonKernel
37 from .parentpoller import ParentPollerUnix, ParentPollerWindows
37 from .parentpoller import ParentPollerUnix, ParentPollerWindows
38 from .session import (
38 from .session import (
39 Session, session_flags, session_aliases,
39 Session, session_flags, session_aliases,
40 )
40 )
41 from .zmqshell import ZMQInteractiveShell
41 from .zmqshell import ZMQInteractiveShell
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Flags and Aliases
44 # Flags and Aliases
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 kernel_aliases = dict(base_aliases)
47 kernel_aliases = dict(base_aliases)
48 kernel_aliases.update({
48 kernel_aliases.update({
49 'ip' : 'IPKernelApp.ip',
49 'ip' : 'IPKernelApp.ip',
50 'hb' : 'IPKernelApp.hb_port',
50 'hb' : 'IPKernelApp.hb_port',
51 'shell' : 'IPKernelApp.shell_port',
51 'shell' : 'IPKernelApp.shell_port',
52 'iopub' : 'IPKernelApp.iopub_port',
52 'iopub' : 'IPKernelApp.iopub_port',
53 'stdin' : 'IPKernelApp.stdin_port',
53 'stdin' : 'IPKernelApp.stdin_port',
54 'control' : 'IPKernelApp.control_port',
54 'control' : 'IPKernelApp.control_port',
55 'f' : 'IPKernelApp.connection_file',
55 'f' : 'IPKernelApp.connection_file',
56 'transport': 'IPKernelApp.transport',
56 'transport': 'IPKernelApp.transport',
57 })
57 })
58
58
59 kernel_flags = dict(base_flags)
59 kernel_flags = dict(base_flags)
60 kernel_flags.update({
60 kernel_flags.update({
61 'no-stdout' : (
61 'no-stdout' : (
62 {'IPKernelApp' : {'no_stdout' : True}},
62 {'IPKernelApp' : {'no_stdout' : True}},
63 "redirect stdout to the null device"),
63 "redirect stdout to the null device"),
64 'no-stderr' : (
64 'no-stderr' : (
65 {'IPKernelApp' : {'no_stderr' : True}},
65 {'IPKernelApp' : {'no_stderr' : True}},
66 "redirect stderr to the null device"),
66 "redirect stderr to the null device"),
67 'pylab' : (
67 'pylab' : (
68 {'IPKernelApp' : {'pylab' : 'auto'}},
68 {'IPKernelApp' : {'pylab' : 'auto'}},
69 """Pre-load matplotlib and numpy for interactive use with
69 """Pre-load matplotlib and numpy for interactive use with
70 the default matplotlib backend."""),
70 the default matplotlib backend."""),
71 })
71 })
72
72
73 # inherit flags&aliases for any IPython shell apps
73 # inherit flags&aliases for any IPython shell apps
74 kernel_aliases.update(shell_aliases)
74 kernel_aliases.update(shell_aliases)
75 kernel_flags.update(shell_flags)
75 kernel_flags.update(shell_flags)
76
76
77 # inherit flags&aliases for Sessions
77 # inherit flags&aliases for Sessions
78 kernel_aliases.update(session_aliases)
78 kernel_aliases.update(session_aliases)
79 kernel_flags.update(session_flags)
79 kernel_flags.update(session_flags)
80
80
81 _ctrl_c_message = """\
81 _ctrl_c_message = """\
82 NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.
82 NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.
83
83
84 To exit, you will have to explicitly quit this process, by either sending
84 To exit, you will have to explicitly quit this process, by either sending
85 "quit" from a client, or using Ctrl-\\ in UNIX-like environments.
85 "quit" from a client, or using Ctrl-\\ in UNIX-like environments.
86
86
87 To read more about this, see https://github.com/ipython/ipython/issues/2049
87 To read more about this, see https://github.com/ipython/ipython/issues/2049
88
88
89 """
89 """
90
90
91 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
92 # Application class for starting an IPython Kernel
92 # Application class for starting an IPython Kernel
93 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
94
94
95 class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,
95 class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,
96 ConnectionFileMixin):
96 ConnectionFileMixin):
97 name='ipython-kernel'
97 name='ipython-kernel'
98 aliases = Dict(kernel_aliases)
98 aliases = Dict(kernel_aliases)
99 flags = Dict(kernel_flags)
99 flags = Dict(kernel_flags)
100 classes = [IPythonKernel, ZMQInteractiveShell, ProfileDir, Session]
100 classes = [IPythonKernel, ZMQInteractiveShell, ProfileDir, Session]
101 # the kernel class, as an importstring
101 # the kernel class, as an importstring
102 kernel_class = Type('ipython_kernel.zmq.ipkernel.IPythonKernel', config=True,
102 kernel_class = Type('ipython_kernel.ipkernel.IPythonKernel', config=True,
103 klass='ipython_kernel.zmq.kernelbase.Kernel',
103 klass='ipython_kernel.kernelbase.Kernel',
104 help="""The Kernel subclass to be used.
104 help="""The Kernel subclass to be used.
105
105
106 This should allow easy re-use of the IPKernelApp entry point
106 This should allow easy re-use of the IPKernelApp entry point
107 to configure and launch kernels other than IPython's own.
107 to configure and launch kernels other than IPython's own.
108 """)
108 """)
109 kernel = Any()
109 kernel = Any()
110 poller = Any() # don't restrict this even though current pollers are all Threads
110 poller = Any() # don't restrict this even though current pollers are all Threads
111 heartbeat = Instance(Heartbeat, allow_none=True)
111 heartbeat = Instance(Heartbeat, allow_none=True)
112 ports = Dict()
112 ports = Dict()
113
113
114 # connection info:
114 # connection info:
115
115
116 @property
116 @property
117 def abs_connection_file(self):
117 def abs_connection_file(self):
118 if os.path.basename(self.connection_file) == self.connection_file:
118 if os.path.basename(self.connection_file) == self.connection_file:
119 return os.path.join(self.profile_dir.security_dir, self.connection_file)
119 return os.path.join(self.profile_dir.security_dir, self.connection_file)
120 else:
120 else:
121 return self.connection_file
121 return self.connection_file
122
122
123
123
124 # streams, etc.
124 # streams, etc.
125 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
125 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
126 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
126 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
127 outstream_class = DottedObjectName('ipython_kernel.zmq.iostream.OutStream',
127 outstream_class = DottedObjectName('ipython_kernel.iostream.OutStream',
128 config=True, help="The importstring for the OutStream factory")
128 config=True, help="The importstring for the OutStream factory")
129 displayhook_class = DottedObjectName('ipython_kernel.zmq.displayhook.ZMQDisplayHook',
129 displayhook_class = DottedObjectName('ipython_kernel.displayhook.ZMQDisplayHook',
130 config=True, help="The importstring for the DisplayHook factory")
130 config=True, help="The importstring for the DisplayHook factory")
131
131
132 # polling
132 # polling
133 parent_handle = Integer(int(os.environ.get('JPY_PARENT_PID') or 0), config=True,
133 parent_handle = Integer(int(os.environ.get('JPY_PARENT_PID') or 0), config=True,
134 help="""kill this process if its parent dies. On Windows, the argument
134 help="""kill this process if its parent dies. On Windows, the argument
135 specifies the HANDLE of the parent process, otherwise it is simply boolean.
135 specifies the HANDLE of the parent process, otherwise it is simply boolean.
136 """)
136 """)
137 interrupt = Integer(int(os.environ.get('JPY_INTERRUPT_EVENT') or 0), config=True,
137 interrupt = Integer(int(os.environ.get('JPY_INTERRUPT_EVENT') or 0), config=True,
138 help="""ONLY USED ON WINDOWS
138 help="""ONLY USED ON WINDOWS
139 Interrupt this process when the parent is signaled.
139 Interrupt this process when the parent is signaled.
140 """)
140 """)
141
141
142 def init_crash_handler(self):
142 def init_crash_handler(self):
143 # Install minimal exception handling
143 # Install minimal exception handling
144 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
144 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
145 ostream=sys.__stdout__)
145 ostream=sys.__stdout__)
146
146
147 def init_poller(self):
147 def init_poller(self):
148 if sys.platform == 'win32':
148 if sys.platform == 'win32':
149 if self.interrupt or self.parent_handle:
149 if self.interrupt or self.parent_handle:
150 self.poller = ParentPollerWindows(self.interrupt, self.parent_handle)
150 self.poller = ParentPollerWindows(self.interrupt, self.parent_handle)
151 elif self.parent_handle:
151 elif self.parent_handle:
152 self.poller = ParentPollerUnix()
152 self.poller = ParentPollerUnix()
153
153
154 def _bind_socket(self, s, port):
154 def _bind_socket(self, s, port):
155 iface = '%s://%s' % (self.transport, self.ip)
155 iface = '%s://%s' % (self.transport, self.ip)
156 if self.transport == 'tcp':
156 if self.transport == 'tcp':
157 if port <= 0:
157 if port <= 0:
158 port = s.bind_to_random_port(iface)
158 port = s.bind_to_random_port(iface)
159 else:
159 else:
160 s.bind("tcp://%s:%i" % (self.ip, port))
160 s.bind("tcp://%s:%i" % (self.ip, port))
161 elif self.transport == 'ipc':
161 elif self.transport == 'ipc':
162 if port <= 0:
162 if port <= 0:
163 port = 1
163 port = 1
164 path = "%s-%i" % (self.ip, port)
164 path = "%s-%i" % (self.ip, port)
165 while os.path.exists(path):
165 while os.path.exists(path):
166 port = port + 1
166 port = port + 1
167 path = "%s-%i" % (self.ip, port)
167 path = "%s-%i" % (self.ip, port)
168 else:
168 else:
169 path = "%s-%i" % (self.ip, port)
169 path = "%s-%i" % (self.ip, port)
170 s.bind("ipc://%s" % path)
170 s.bind("ipc://%s" % path)
171 return port
171 return port
172
172
173 def write_connection_file(self):
173 def write_connection_file(self):
174 """write connection info to JSON file"""
174 """write connection info to JSON file"""
175 cf = self.abs_connection_file
175 cf = self.abs_connection_file
176 self.log.debug("Writing connection file: %s", cf)
176 self.log.debug("Writing connection file: %s", cf)
177 write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport,
177 write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport,
178 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
178 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
179 iopub_port=self.iopub_port, control_port=self.control_port)
179 iopub_port=self.iopub_port, control_port=self.control_port)
180
180
181 def cleanup_connection_file(self):
181 def cleanup_connection_file(self):
182 cf = self.abs_connection_file
182 cf = self.abs_connection_file
183 self.log.debug("Cleaning up connection file: %s", cf)
183 self.log.debug("Cleaning up connection file: %s", cf)
184 try:
184 try:
185 os.remove(cf)
185 os.remove(cf)
186 except (IOError, OSError):
186 except (IOError, OSError):
187 pass
187 pass
188
188
189 self.cleanup_ipc_files()
189 self.cleanup_ipc_files()
190
190
191 def init_connection_file(self):
191 def init_connection_file(self):
192 if not self.connection_file:
192 if not self.connection_file:
193 self.connection_file = "kernel-%s.json"%os.getpid()
193 self.connection_file = "kernel-%s.json"%os.getpid()
194 try:
194 try:
195 self.connection_file = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
195 self.connection_file = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
196 except IOError:
196 except IOError:
197 self.log.debug("Connection file not found: %s", self.connection_file)
197 self.log.debug("Connection file not found: %s", self.connection_file)
198 # This means I own it, so I will clean it up:
198 # This means I own it, so I will clean it up:
199 atexit.register(self.cleanup_connection_file)
199 atexit.register(self.cleanup_connection_file)
200 return
200 return
201 try:
201 try:
202 self.load_connection_file()
202 self.load_connection_file()
203 except Exception:
203 except Exception:
204 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
204 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
205 self.exit(1)
205 self.exit(1)
206
206
207 def init_sockets(self):
207 def init_sockets(self):
208 # Create a context, a session, and the kernel sockets.
208 # Create a context, a session, and the kernel sockets.
209 self.log.info("Starting the kernel at pid: %i", os.getpid())
209 self.log.info("Starting the kernel at pid: %i", os.getpid())
210 context = zmq.Context.instance()
210 context = zmq.Context.instance()
211 # Uncomment this to try closing the context.
211 # Uncomment this to try closing the context.
212 # atexit.register(context.term)
212 # atexit.register(context.term)
213
213
214 self.shell_socket = context.socket(zmq.ROUTER)
214 self.shell_socket = context.socket(zmq.ROUTER)
215 self.shell_socket.linger = 1000
215 self.shell_socket.linger = 1000
216 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
216 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
217 self.log.debug("shell ROUTER Channel on port: %i" % self.shell_port)
217 self.log.debug("shell ROUTER Channel on port: %i" % self.shell_port)
218
218
219 self.iopub_socket = context.socket(zmq.PUB)
219 self.iopub_socket = context.socket(zmq.PUB)
220 self.iopub_socket.linger = 1000
220 self.iopub_socket.linger = 1000
221 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
221 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
222 self.log.debug("iopub PUB Channel on port: %i" % self.iopub_port)
222 self.log.debug("iopub PUB Channel on port: %i" % self.iopub_port)
223
223
224 self.stdin_socket = context.socket(zmq.ROUTER)
224 self.stdin_socket = context.socket(zmq.ROUTER)
225 self.stdin_socket.linger = 1000
225 self.stdin_socket.linger = 1000
226 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
226 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
227 self.log.debug("stdin ROUTER Channel on port: %i" % self.stdin_port)
227 self.log.debug("stdin ROUTER Channel on port: %i" % self.stdin_port)
228
228
229 self.control_socket = context.socket(zmq.ROUTER)
229 self.control_socket = context.socket(zmq.ROUTER)
230 self.control_socket.linger = 1000
230 self.control_socket.linger = 1000
231 self.control_port = self._bind_socket(self.control_socket, self.control_port)
231 self.control_port = self._bind_socket(self.control_socket, self.control_port)
232 self.log.debug("control ROUTER Channel on port: %i" % self.control_port)
232 self.log.debug("control ROUTER Channel on port: %i" % self.control_port)
233
233
234 def init_heartbeat(self):
234 def init_heartbeat(self):
235 """start the heart beating"""
235 """start the heart beating"""
236 # heartbeat doesn't share context, because it mustn't be blocked
236 # heartbeat doesn't share context, because it mustn't be blocked
237 # by the GIL, which is accessed by libzmq when freeing zero-copy messages
237 # by the GIL, which is accessed by libzmq when freeing zero-copy messages
238 hb_ctx = zmq.Context()
238 hb_ctx = zmq.Context()
239 self.heartbeat = Heartbeat(hb_ctx, (self.transport, self.ip, self.hb_port))
239 self.heartbeat = Heartbeat(hb_ctx, (self.transport, self.ip, self.hb_port))
240 self.hb_port = self.heartbeat.port
240 self.hb_port = self.heartbeat.port
241 self.log.debug("Heartbeat REP Channel on port: %i" % self.hb_port)
241 self.log.debug("Heartbeat REP Channel on port: %i" % self.hb_port)
242 self.heartbeat.start()
242 self.heartbeat.start()
243
243
244 def log_connection_info(self):
244 def log_connection_info(self):
245 """display connection info, and store ports"""
245 """display connection info, and store ports"""
246 basename = os.path.basename(self.connection_file)
246 basename = os.path.basename(self.connection_file)
247 if basename == self.connection_file or \
247 if basename == self.connection_file or \
248 os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
248 os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
249 # use shortname
249 # use shortname
250 tail = basename
250 tail = basename
251 if self.profile != 'default':
251 if self.profile != 'default':
252 tail += " --profile %s" % self.profile
252 tail += " --profile %s" % self.profile
253 else:
253 else:
254 tail = self.connection_file
254 tail = self.connection_file
255 lines = [
255 lines = [
256 "To connect another client to this kernel, use:",
256 "To connect another client to this kernel, use:",
257 " --existing %s" % tail,
257 " --existing %s" % tail,
258 ]
258 ]
259 # log connection info
259 # log connection info
260 # info-level, so often not shown.
260 # info-level, so often not shown.
261 # frontends should use the %connect_info magic
261 # frontends should use the %connect_info magic
262 # to see the connection info
262 # to see the connection info
263 for line in lines:
263 for line in lines:
264 self.log.info(line)
264 self.log.info(line)
265 # also raw print to the terminal if no parent_handle (`ipython kernel`)
265 # also raw print to the terminal if no parent_handle (`ipython kernel`)
266 if not self.parent_handle:
266 if not self.parent_handle:
267 io.rprint(_ctrl_c_message)
267 io.rprint(_ctrl_c_message)
268 for line in lines:
268 for line in lines:
269 io.rprint(line)
269 io.rprint(line)
270
270
271 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
271 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
272 stdin=self.stdin_port, hb=self.hb_port,
272 stdin=self.stdin_port, hb=self.hb_port,
273 control=self.control_port)
273 control=self.control_port)
274
274
275 def init_blackhole(self):
275 def init_blackhole(self):
276 """redirects stdout/stderr to devnull if necessary"""
276 """redirects stdout/stderr to devnull if necessary"""
277 if self.no_stdout or self.no_stderr:
277 if self.no_stdout or self.no_stderr:
278 blackhole = open(os.devnull, 'w')
278 blackhole = open(os.devnull, 'w')
279 if self.no_stdout:
279 if self.no_stdout:
280 sys.stdout = sys.__stdout__ = blackhole
280 sys.stdout = sys.__stdout__ = blackhole
281 if self.no_stderr:
281 if self.no_stderr:
282 sys.stderr = sys.__stderr__ = blackhole
282 sys.stderr = sys.__stderr__ = blackhole
283
283
284 def init_io(self):
284 def init_io(self):
285 """Redirect input streams and set a display hook."""
285 """Redirect input streams and set a display hook."""
286 if self.outstream_class:
286 if self.outstream_class:
287 outstream_factory = import_item(str(self.outstream_class))
287 outstream_factory = import_item(str(self.outstream_class))
288 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
288 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
289 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
289 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
290 if self.displayhook_class:
290 if self.displayhook_class:
291 displayhook_factory = import_item(str(self.displayhook_class))
291 displayhook_factory = import_item(str(self.displayhook_class))
292 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
292 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
293
293
294 def init_signal(self):
294 def init_signal(self):
295 signal.signal(signal.SIGINT, signal.SIG_IGN)
295 signal.signal(signal.SIGINT, signal.SIG_IGN)
296
296
297 def init_kernel(self):
297 def init_kernel(self):
298 """Create the Kernel object itself"""
298 """Create the Kernel object itself"""
299 shell_stream = ZMQStream(self.shell_socket)
299 shell_stream = ZMQStream(self.shell_socket)
300 control_stream = ZMQStream(self.control_socket)
300 control_stream = ZMQStream(self.control_socket)
301
301
302 kernel_factory = self.kernel_class.instance
302 kernel_factory = self.kernel_class.instance
303
303
304 kernel = kernel_factory(parent=self, session=self.session,
304 kernel = kernel_factory(parent=self, session=self.session,
305 shell_streams=[shell_stream, control_stream],
305 shell_streams=[shell_stream, control_stream],
306 iopub_socket=self.iopub_socket,
306 iopub_socket=self.iopub_socket,
307 stdin_socket=self.stdin_socket,
307 stdin_socket=self.stdin_socket,
308 log=self.log,
308 log=self.log,
309 profile_dir=self.profile_dir,
309 profile_dir=self.profile_dir,
310 user_ns=self.user_ns,
310 user_ns=self.user_ns,
311 )
311 )
312 kernel.record_ports(self.ports)
312 kernel.record_ports(self.ports)
313 self.kernel = kernel
313 self.kernel = kernel
314
314
315 def init_gui_pylab(self):
315 def init_gui_pylab(self):
316 """Enable GUI event loop integration, taking pylab into account."""
316 """Enable GUI event loop integration, taking pylab into account."""
317
317
318 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
318 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
319 # to ensure that any exception is printed straight to stderr.
319 # to ensure that any exception is printed straight to stderr.
320 # Normally _showtraceback associates the reply with an execution,
320 # Normally _showtraceback associates the reply with an execution,
321 # which means frontends will never draw it, as this exception
321 # which means frontends will never draw it, as this exception
322 # is not associated with any execute request.
322 # is not associated with any execute request.
323
323
324 shell = self.shell
324 shell = self.shell
325 _showtraceback = shell._showtraceback
325 _showtraceback = shell._showtraceback
326 try:
326 try:
327 # replace error-sending traceback with stderr
327 # replace error-sending traceback with stderr
328 def print_tb(etype, evalue, stb):
328 def print_tb(etype, evalue, stb):
329 print ("GUI event loop or pylab initialization failed",
329 print ("GUI event loop or pylab initialization failed",
330 file=io.stderr)
330 file=io.stderr)
331 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
331 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
332 shell._showtraceback = print_tb
332 shell._showtraceback = print_tb
333 InteractiveShellApp.init_gui_pylab(self)
333 InteractiveShellApp.init_gui_pylab(self)
334 finally:
334 finally:
335 shell._showtraceback = _showtraceback
335 shell._showtraceback = _showtraceback
336
336
337 def init_shell(self):
337 def init_shell(self):
338 self.shell = getattr(self.kernel, 'shell', None)
338 self.shell = getattr(self.kernel, 'shell', None)
339 if self.shell:
339 if self.shell:
340 self.shell.configurables.append(self)
340 self.shell.configurables.append(self)
341
341
342 @catch_config_error
342 @catch_config_error
343 def initialize(self, argv=None):
343 def initialize(self, argv=None):
344 super(IPKernelApp, self).initialize(argv)
344 super(IPKernelApp, self).initialize(argv)
345 self.init_blackhole()
345 self.init_blackhole()
346 self.init_connection_file()
346 self.init_connection_file()
347 self.init_poller()
347 self.init_poller()
348 self.init_sockets()
348 self.init_sockets()
349 self.init_heartbeat()
349 self.init_heartbeat()
350 # writing/displaying connection info must be *after* init_sockets/heartbeat
350 # writing/displaying connection info must be *after* init_sockets/heartbeat
351 self.log_connection_info()
351 self.log_connection_info()
352 self.write_connection_file()
352 self.write_connection_file()
353 self.init_io()
353 self.init_io()
354 self.init_signal()
354 self.init_signal()
355 self.init_kernel()
355 self.init_kernel()
356 # shell init steps
356 # shell init steps
357 self.init_path()
357 self.init_path()
358 self.init_shell()
358 self.init_shell()
359 if self.shell:
359 if self.shell:
360 self.init_gui_pylab()
360 self.init_gui_pylab()
361 self.init_extensions()
361 self.init_extensions()
362 self.init_code()
362 self.init_code()
363 # flush stdout/stderr, so that anything written to these streams during
363 # flush stdout/stderr, so that anything written to these streams during
364 # initialization do not get associated with the first execution request
364 # initialization do not get associated with the first execution request
365 sys.stdout.flush()
365 sys.stdout.flush()
366 sys.stderr.flush()
366 sys.stderr.flush()
367
367
368 def start(self):
368 def start(self):
369 if self.poller is not None:
369 if self.poller is not None:
370 self.poller.start()
370 self.poller.start()
371 self.kernel.start()
371 self.kernel.start()
372 try:
372 try:
373 ioloop.IOLoop.instance().start()
373 ioloop.IOLoop.instance().start()
374 except KeyboardInterrupt:
374 except KeyboardInterrupt:
375 pass
375 pass
376
376
377 launch_new_instance = IPKernelApp.launch_instance
377 launch_new_instance = IPKernelApp.launch_instance
378
378
379 def main():
379 def main():
380 """Run an IPKernel as an application"""
380 """Run an IPKernel as an application"""
381 app = IPKernelApp.instance()
381 app = IPKernelApp.instance()
382 app.initialize()
382 app.initialize()
383 app.start()
383 app.start()
384
384
385
385
386 if __name__ == '__main__':
386 if __name__ == '__main__':
387 main()
387 main()
1 NO CONTENT: file renamed from ipython_kernel/zmq/kernelbase.py to ipython_kernel/kernelbase.py
NO CONTENT: file renamed from ipython_kernel/zmq/kernelbase.py to ipython_kernel/kernelbase.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/log.py to ipython_kernel/log.py
NO CONTENT: file renamed from ipython_kernel/zmq/log.py to ipython_kernel/log.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/parentpoller.py to ipython_kernel/parentpoller.py
NO CONTENT: file renamed from ipython_kernel/zmq/parentpoller.py to ipython_kernel/parentpoller.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/pylab/__init__.py to ipython_kernel/pylab/__init__.py
NO CONTENT: file renamed from ipython_kernel/zmq/pylab/__init__.py to ipython_kernel/pylab/__init__.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/pylab/backend_inline.py to ipython_kernel/pylab/backend_inline.py
NO CONTENT: file renamed from ipython_kernel/zmq/pylab/backend_inline.py to ipython_kernel/pylab/backend_inline.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/pylab/config.py to ipython_kernel/pylab/config.py
NO CONTENT: file renamed from ipython_kernel/zmq/pylab/config.py to ipython_kernel/pylab/config.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/serialize.py to ipython_kernel/serialize.py
NO CONTENT: file renamed from ipython_kernel/zmq/serialize.py to ipython_kernel/serialize.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/session.py to ipython_kernel/session.py
NO CONTENT: file renamed from ipython_kernel/zmq/session.py to ipython_kernel/session.py
1 NO CONTENT: file renamed from ipython_kernel/zmq/tests/test_embed_kernel.py to ipython_kernel/tests/test_embed_kernel.py
NO CONTENT: file renamed from ipython_kernel/zmq/tests/test_embed_kernel.py to ipython_kernel/tests/test_embed_kernel.py
@@ -1,208 +1,208 b''
1 """test serialization tools"""
1 """test serialization tools"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import pickle
6 import pickle
7 from collections import namedtuple
7 from collections import namedtuple
8
8
9 import nose.tools as nt
9 import nose.tools as nt
10
10
11 # from unittest import TestCaes
11 # from unittest import TestCaes
12 from ipython_kernel.zmq.serialize import serialize_object, deserialize_object
12 from ipython_kernel.serialize import serialize_object, deserialize_object
13 from IPython.testing import decorators as dec
13 from IPython.testing import decorators as dec
14 from IPython.utils.pickleutil import CannedArray, CannedClass
14 from IPython.utils.pickleutil import CannedArray, CannedClass
15 from IPython.utils.py3compat import iteritems
15 from IPython.utils.py3compat import iteritems
16 from IPython.parallel import interactive
16 from IPython.parallel import interactive
17
17
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19 # Globals and Utilities
19 # Globals and Utilities
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21
21
22 def roundtrip(obj):
22 def roundtrip(obj):
23 """roundtrip an object through serialization"""
23 """roundtrip an object through serialization"""
24 bufs = serialize_object(obj)
24 bufs = serialize_object(obj)
25 obj2, remainder = deserialize_object(bufs)
25 obj2, remainder = deserialize_object(bufs)
26 nt.assert_equals(remainder, [])
26 nt.assert_equals(remainder, [])
27 return obj2
27 return obj2
28
28
29 class C(object):
29 class C(object):
30 """dummy class for """
30 """dummy class for """
31
31
32 def __init__(self, **kwargs):
32 def __init__(self, **kwargs):
33 for key,value in iteritems(kwargs):
33 for key,value in iteritems(kwargs):
34 setattr(self, key, value)
34 setattr(self, key, value)
35
35
36 SHAPES = ((100,), (1024,10), (10,8,6,5), (), (0,))
36 SHAPES = ((100,), (1024,10), (10,8,6,5), (), (0,))
37 DTYPES = ('uint8', 'float64', 'int32', [('g', 'float32')], '|S10')
37 DTYPES = ('uint8', 'float64', 'int32', [('g', 'float32')], '|S10')
38
38
39 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
40 # Tests
40 # Tests
41 #-------------------------------------------------------------------------------
41 #-------------------------------------------------------------------------------
42
42
43 def new_array(shape, dtype):
43 def new_array(shape, dtype):
44 import numpy
44 import numpy
45 return numpy.random.random(shape).astype(dtype)
45 return numpy.random.random(shape).astype(dtype)
46
46
47 def test_roundtrip_simple():
47 def test_roundtrip_simple():
48 for obj in [
48 for obj in [
49 'hello',
49 'hello',
50 dict(a='b', b=10),
50 dict(a='b', b=10),
51 [1,2,'hi'],
51 [1,2,'hi'],
52 (b'123', 'hello'),
52 (b'123', 'hello'),
53 ]:
53 ]:
54 obj2 = roundtrip(obj)
54 obj2 = roundtrip(obj)
55 nt.assert_equal(obj, obj2)
55 nt.assert_equal(obj, obj2)
56
56
57 def test_roundtrip_nested():
57 def test_roundtrip_nested():
58 for obj in [
58 for obj in [
59 dict(a=range(5), b={1:b'hello'}),
59 dict(a=range(5), b={1:b'hello'}),
60 [range(5),[range(3),(1,[b'whoda'])]],
60 [range(5),[range(3),(1,[b'whoda'])]],
61 ]:
61 ]:
62 obj2 = roundtrip(obj)
62 obj2 = roundtrip(obj)
63 nt.assert_equal(obj, obj2)
63 nt.assert_equal(obj, obj2)
64
64
65 def test_roundtrip_buffered():
65 def test_roundtrip_buffered():
66 for obj in [
66 for obj in [
67 dict(a=b"x"*1025),
67 dict(a=b"x"*1025),
68 b"hello"*500,
68 b"hello"*500,
69 [b"hello"*501, 1,2,3]
69 [b"hello"*501, 1,2,3]
70 ]:
70 ]:
71 bufs = serialize_object(obj)
71 bufs = serialize_object(obj)
72 nt.assert_equal(len(bufs), 2)
72 nt.assert_equal(len(bufs), 2)
73 obj2, remainder = deserialize_object(bufs)
73 obj2, remainder = deserialize_object(bufs)
74 nt.assert_equal(remainder, [])
74 nt.assert_equal(remainder, [])
75 nt.assert_equal(obj, obj2)
75 nt.assert_equal(obj, obj2)
76
76
77 @dec.skip_without('numpy')
77 @dec.skip_without('numpy')
78 def test_numpy():
78 def test_numpy():
79 import numpy
79 import numpy
80 from numpy.testing.utils import assert_array_equal
80 from numpy.testing.utils import assert_array_equal
81 for shape in SHAPES:
81 for shape in SHAPES:
82 for dtype in DTYPES:
82 for dtype in DTYPES:
83 A = new_array(shape, dtype=dtype)
83 A = new_array(shape, dtype=dtype)
84 bufs = serialize_object(A)
84 bufs = serialize_object(A)
85 B, r = deserialize_object(bufs)
85 B, r = deserialize_object(bufs)
86 nt.assert_equal(r, [])
86 nt.assert_equal(r, [])
87 nt.assert_equal(A.shape, B.shape)
87 nt.assert_equal(A.shape, B.shape)
88 nt.assert_equal(A.dtype, B.dtype)
88 nt.assert_equal(A.dtype, B.dtype)
89 assert_array_equal(A,B)
89 assert_array_equal(A,B)
90
90
91 @dec.skip_without('numpy')
91 @dec.skip_without('numpy')
92 def test_recarray():
92 def test_recarray():
93 import numpy
93 import numpy
94 from numpy.testing.utils import assert_array_equal
94 from numpy.testing.utils import assert_array_equal
95 for shape in SHAPES:
95 for shape in SHAPES:
96 for dtype in [
96 for dtype in [
97 [('f', float), ('s', '|S10')],
97 [('f', float), ('s', '|S10')],
98 [('n', int), ('s', '|S1'), ('u', 'uint32')],
98 [('n', int), ('s', '|S1'), ('u', 'uint32')],
99 ]:
99 ]:
100 A = new_array(shape, dtype=dtype)
100 A = new_array(shape, dtype=dtype)
101
101
102 bufs = serialize_object(A)
102 bufs = serialize_object(A)
103 B, r = deserialize_object(bufs)
103 B, r = deserialize_object(bufs)
104 nt.assert_equal(r, [])
104 nt.assert_equal(r, [])
105 nt.assert_equal(A.shape, B.shape)
105 nt.assert_equal(A.shape, B.shape)
106 nt.assert_equal(A.dtype, B.dtype)
106 nt.assert_equal(A.dtype, B.dtype)
107 assert_array_equal(A,B)
107 assert_array_equal(A,B)
108
108
109 @dec.skip_without('numpy')
109 @dec.skip_without('numpy')
110 def test_numpy_in_seq():
110 def test_numpy_in_seq():
111 import numpy
111 import numpy
112 from numpy.testing.utils import assert_array_equal
112 from numpy.testing.utils import assert_array_equal
113 for shape in SHAPES:
113 for shape in SHAPES:
114 for dtype in DTYPES:
114 for dtype in DTYPES:
115 A = new_array(shape, dtype=dtype)
115 A = new_array(shape, dtype=dtype)
116 bufs = serialize_object((A,1,2,b'hello'))
116 bufs = serialize_object((A,1,2,b'hello'))
117 canned = pickle.loads(bufs[0])
117 canned = pickle.loads(bufs[0])
118 nt.assert_is_instance(canned[0], CannedArray)
118 nt.assert_is_instance(canned[0], CannedArray)
119 tup, r = deserialize_object(bufs)
119 tup, r = deserialize_object(bufs)
120 B = tup[0]
120 B = tup[0]
121 nt.assert_equal(r, [])
121 nt.assert_equal(r, [])
122 nt.assert_equal(A.shape, B.shape)
122 nt.assert_equal(A.shape, B.shape)
123 nt.assert_equal(A.dtype, B.dtype)
123 nt.assert_equal(A.dtype, B.dtype)
124 assert_array_equal(A,B)
124 assert_array_equal(A,B)
125
125
126 @dec.skip_without('numpy')
126 @dec.skip_without('numpy')
127 def test_numpy_in_dict():
127 def test_numpy_in_dict():
128 import numpy
128 import numpy
129 from numpy.testing.utils import assert_array_equal
129 from numpy.testing.utils import assert_array_equal
130 for shape in SHAPES:
130 for shape in SHAPES:
131 for dtype in DTYPES:
131 for dtype in DTYPES:
132 A = new_array(shape, dtype=dtype)
132 A = new_array(shape, dtype=dtype)
133 bufs = serialize_object(dict(a=A,b=1,c=range(20)))
133 bufs = serialize_object(dict(a=A,b=1,c=range(20)))
134 canned = pickle.loads(bufs[0])
134 canned = pickle.loads(bufs[0])
135 nt.assert_is_instance(canned['a'], CannedArray)
135 nt.assert_is_instance(canned['a'], CannedArray)
136 d, r = deserialize_object(bufs)
136 d, r = deserialize_object(bufs)
137 B = d['a']
137 B = d['a']
138 nt.assert_equal(r, [])
138 nt.assert_equal(r, [])
139 nt.assert_equal(A.shape, B.shape)
139 nt.assert_equal(A.shape, B.shape)
140 nt.assert_equal(A.dtype, B.dtype)
140 nt.assert_equal(A.dtype, B.dtype)
141 assert_array_equal(A,B)
141 assert_array_equal(A,B)
142
142
143 def test_class():
143 def test_class():
144 @interactive
144 @interactive
145 class C(object):
145 class C(object):
146 a=5
146 a=5
147 bufs = serialize_object(dict(C=C))
147 bufs = serialize_object(dict(C=C))
148 canned = pickle.loads(bufs[0])
148 canned = pickle.loads(bufs[0])
149 nt.assert_is_instance(canned['C'], CannedClass)
149 nt.assert_is_instance(canned['C'], CannedClass)
150 d, r = deserialize_object(bufs)
150 d, r = deserialize_object(bufs)
151 C2 = d['C']
151 C2 = d['C']
152 nt.assert_equal(C2.a, C.a)
152 nt.assert_equal(C2.a, C.a)
153
153
154 def test_class_oldstyle():
154 def test_class_oldstyle():
155 @interactive
155 @interactive
156 class C:
156 class C:
157 a=5
157 a=5
158
158
159 bufs = serialize_object(dict(C=C))
159 bufs = serialize_object(dict(C=C))
160 canned = pickle.loads(bufs[0])
160 canned = pickle.loads(bufs[0])
161 nt.assert_is_instance(canned['C'], CannedClass)
161 nt.assert_is_instance(canned['C'], CannedClass)
162 d, r = deserialize_object(bufs)
162 d, r = deserialize_object(bufs)
163 C2 = d['C']
163 C2 = d['C']
164 nt.assert_equal(C2.a, C.a)
164 nt.assert_equal(C2.a, C.a)
165
165
166 def test_tuple():
166 def test_tuple():
167 tup = (lambda x:x, 1)
167 tup = (lambda x:x, 1)
168 bufs = serialize_object(tup)
168 bufs = serialize_object(tup)
169 canned = pickle.loads(bufs[0])
169 canned = pickle.loads(bufs[0])
170 nt.assert_is_instance(canned, tuple)
170 nt.assert_is_instance(canned, tuple)
171 t2, r = deserialize_object(bufs)
171 t2, r = deserialize_object(bufs)
172 nt.assert_equal(t2[0](t2[1]), tup[0](tup[1]))
172 nt.assert_equal(t2[0](t2[1]), tup[0](tup[1]))
173
173
174 point = namedtuple('point', 'x y')
174 point = namedtuple('point', 'x y')
175
175
176 def test_namedtuple():
176 def test_namedtuple():
177 p = point(1,2)
177 p = point(1,2)
178 bufs = serialize_object(p)
178 bufs = serialize_object(p)
179 canned = pickle.loads(bufs[0])
179 canned = pickle.loads(bufs[0])
180 nt.assert_is_instance(canned, point)
180 nt.assert_is_instance(canned, point)
181 p2, r = deserialize_object(bufs, globals())
181 p2, r = deserialize_object(bufs, globals())
182 nt.assert_equal(p2.x, p.x)
182 nt.assert_equal(p2.x, p.x)
183 nt.assert_equal(p2.y, p.y)
183 nt.assert_equal(p2.y, p.y)
184
184
185 def test_list():
185 def test_list():
186 lis = [lambda x:x, 1]
186 lis = [lambda x:x, 1]
187 bufs = serialize_object(lis)
187 bufs = serialize_object(lis)
188 canned = pickle.loads(bufs[0])
188 canned = pickle.loads(bufs[0])
189 nt.assert_is_instance(canned, list)
189 nt.assert_is_instance(canned, list)
190 l2, r = deserialize_object(bufs)
190 l2, r = deserialize_object(bufs)
191 nt.assert_equal(l2[0](l2[1]), lis[0](lis[1]))
191 nt.assert_equal(l2[0](l2[1]), lis[0](lis[1]))
192
192
193 def test_class_inheritance():
193 def test_class_inheritance():
194 @interactive
194 @interactive
195 class C(object):
195 class C(object):
196 a=5
196 a=5
197
197
198 @interactive
198 @interactive
199 class D(C):
199 class D(C):
200 b=10
200 b=10
201
201
202 bufs = serialize_object(dict(D=D))
202 bufs = serialize_object(dict(D=D))
203 canned = pickle.loads(bufs[0])
203 canned = pickle.loads(bufs[0])
204 nt.assert_is_instance(canned['D'], CannedClass)
204 nt.assert_is_instance(canned['D'], CannedClass)
205 d, r = deserialize_object(bufs)
205 d, r = deserialize_object(bufs)
206 D2 = d['D']
206 D2 = d['D']
207 nt.assert_equal(D2.a, D.a)
207 nt.assert_equal(D2.a, D.a)
208 nt.assert_equal(D2.b, D.b)
208 nt.assert_equal(D2.b, D.b)
1 NO CONTENT: file renamed from ipython_kernel/zmq/tests/test_start_kernel.py to ipython_kernel/tests/test_start_kernel.py
NO CONTENT: file renamed from ipython_kernel/zmq/tests/test_start_kernel.py to ipython_kernel/tests/test_start_kernel.py
@@ -1,486 +1,486 b''
1 """A ZMQ-based subclass of InteractiveShell.
1 """A ZMQ-based subclass of InteractiveShell.
2
2
3 This code is meant to ease the refactoring of the base InteractiveShell into
3 This code is meant to ease the refactoring of the base InteractiveShell into
4 something with a cleaner architecture for 2-process use, without actually
4 something with a cleaner architecture for 2-process use, without actually
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 we subclass and override what we want to fix. Once this is working well, we
6 we subclass and override what we want to fix. Once this is working well, we
7 can go back to the base class and refactor the code for a cleaner inheritance
7 can go back to the base class and refactor the code for a cleaner inheritance
8 implementation that doesn't rely on so much monkeypatching.
8 implementation that doesn't rely on so much monkeypatching.
9
9
10 But this lets us maintain a fully working IPython as we develop the new
10 But this lets us maintain a fully working IPython as we develop the new
11 machinery. This should thus be thought of as scaffolding.
11 machinery. This should thus be thought of as scaffolding.
12 """
12 """
13
13
14 # Copyright (c) IPython Development Team.
14 # Copyright (c) IPython Development Team.
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16
16
17 from __future__ import print_function
17 from __future__ import print_function
18
18
19 import os
19 import os
20 import sys
20 import sys
21 import time
21 import time
22
22
23 from zmq.eventloop import ioloop
23 from zmq.eventloop import ioloop
24
24
25 from IPython.core.interactiveshell import (
25 from IPython.core.interactiveshell import (
26 InteractiveShell, InteractiveShellABC
26 InteractiveShell, InteractiveShellABC
27 )
27 )
28 from IPython.core import page
28 from IPython.core import page
29 from IPython.core.autocall import ZMQExitAutocall
29 from IPython.core.autocall import ZMQExitAutocall
30 from IPython.core.displaypub import DisplayPublisher
30 from IPython.core.displaypub import DisplayPublisher
31 from IPython.core.error import UsageError
31 from IPython.core.error import UsageError
32 from IPython.core.magics import MacroToEdit, CodeMagics
32 from IPython.core.magics import MacroToEdit, CodeMagics
33 from IPython.core.magic import magics_class, line_magic, Magics
33 from IPython.core.magic import magics_class, line_magic, Magics
34 from IPython.core import payloadpage
34 from IPython.core import payloadpage
35 from IPython.core.usage import default_gui_banner
35 from IPython.core.usage import default_gui_banner
36 from IPython.display import display, Javascript
36 from IPython.display import display, Javascript
37 from ipython_kernel.inprocess.socket import SocketABC
37 from ipython_kernel.inprocess.socket import SocketABC
38 from ipython_kernel import (
38 from ipython_kernel import (
39 get_connection_file, get_connection_info, connect_qtconsole
39 get_connection_file, get_connection_info, connect_qtconsole
40 )
40 )
41 from IPython.testing.skipdoctest import skip_doctest
41 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.utils import openpy
42 from IPython.utils import openpy
43 from IPython.utils.jsonutil import json_clean, encode_images
43 from IPython.utils.jsonutil import json_clean, encode_images
44 from IPython.utils.process import arg_split
44 from IPython.utils.process import arg_split
45 from IPython.utils import py3compat
45 from IPython.utils import py3compat
46 from IPython.utils.py3compat import unicode_type
46 from IPython.utils.py3compat import unicode_type
47 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes, Any
47 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes, Any
48 from IPython.utils.warn import error
48 from IPython.utils.warn import error
49 from ipython_kernel.zmq.displayhook import ZMQShellDisplayHook
49 from ipython_kernel.displayhook import ZMQShellDisplayHook
50 from ipython_kernel.zmq.datapub import ZMQDataPublisher
50 from ipython_kernel.datapub import ZMQDataPublisher
51 from ipython_kernel.zmq.session import extract_header
51 from ipython_kernel.session import extract_header
52 from .session import Session
52 from .session import Session
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Functions and classes
55 # Functions and classes
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58 class ZMQDisplayPublisher(DisplayPublisher):
58 class ZMQDisplayPublisher(DisplayPublisher):
59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
60
60
61 session = Instance(Session, allow_none=True)
61 session = Instance(Session, allow_none=True)
62 pub_socket = Instance(SocketABC, allow_none=True)
62 pub_socket = Instance(SocketABC, allow_none=True)
63 parent_header = Dict({})
63 parent_header = Dict({})
64 topic = CBytes(b'display_data')
64 topic = CBytes(b'display_data')
65
65
66 def set_parent(self, parent):
66 def set_parent(self, parent):
67 """Set the parent for outbound messages."""
67 """Set the parent for outbound messages."""
68 self.parent_header = extract_header(parent)
68 self.parent_header = extract_header(parent)
69
69
70 def _flush_streams(self):
70 def _flush_streams(self):
71 """flush IO Streams prior to display"""
71 """flush IO Streams prior to display"""
72 sys.stdout.flush()
72 sys.stdout.flush()
73 sys.stderr.flush()
73 sys.stderr.flush()
74
74
75 def publish(self, data, metadata=None, source=None):
75 def publish(self, data, metadata=None, source=None):
76 self._flush_streams()
76 self._flush_streams()
77 if metadata is None:
77 if metadata is None:
78 metadata = {}
78 metadata = {}
79 self._validate_data(data, metadata)
79 self._validate_data(data, metadata)
80 content = {}
80 content = {}
81 content['data'] = encode_images(data)
81 content['data'] = encode_images(data)
82 content['metadata'] = metadata
82 content['metadata'] = metadata
83 self.session.send(
83 self.session.send(
84 self.pub_socket, u'display_data', json_clean(content),
84 self.pub_socket, u'display_data', json_clean(content),
85 parent=self.parent_header, ident=self.topic,
85 parent=self.parent_header, ident=self.topic,
86 )
86 )
87
87
88 def clear_output(self, wait=False):
88 def clear_output(self, wait=False):
89 content = dict(wait=wait)
89 content = dict(wait=wait)
90 self._flush_streams()
90 self._flush_streams()
91 self.session.send(
91 self.session.send(
92 self.pub_socket, u'clear_output', content,
92 self.pub_socket, u'clear_output', content,
93 parent=self.parent_header, ident=self.topic,
93 parent=self.parent_header, ident=self.topic,
94 )
94 )
95
95
96 @magics_class
96 @magics_class
97 class KernelMagics(Magics):
97 class KernelMagics(Magics):
98 #------------------------------------------------------------------------
98 #------------------------------------------------------------------------
99 # Magic overrides
99 # Magic overrides
100 #------------------------------------------------------------------------
100 #------------------------------------------------------------------------
101 # Once the base class stops inheriting from magic, this code needs to be
101 # Once the base class stops inheriting from magic, this code needs to be
102 # moved into a separate machinery as well. For now, at least isolate here
102 # moved into a separate machinery as well. For now, at least isolate here
103 # the magics which this class needs to implement differently from the base
103 # the magics which this class needs to implement differently from the base
104 # class, or that are unique to it.
104 # class, or that are unique to it.
105
105
106 _find_edit_target = CodeMagics._find_edit_target
106 _find_edit_target = CodeMagics._find_edit_target
107
107
108 @skip_doctest
108 @skip_doctest
109 @line_magic
109 @line_magic
110 def edit(self, parameter_s='', last_call=['','']):
110 def edit(self, parameter_s='', last_call=['','']):
111 """Bring up an editor and execute the resulting code.
111 """Bring up an editor and execute the resulting code.
112
112
113 Usage:
113 Usage:
114 %edit [options] [args]
114 %edit [options] [args]
115
115
116 %edit runs an external text editor. You will need to set the command for
116 %edit runs an external text editor. You will need to set the command for
117 this editor via the ``TerminalInteractiveShell.editor`` option in your
117 this editor via the ``TerminalInteractiveShell.editor`` option in your
118 configuration file before it will work.
118 configuration file before it will work.
119
119
120 This command allows you to conveniently edit multi-line code right in
120 This command allows you to conveniently edit multi-line code right in
121 your IPython session.
121 your IPython session.
122
122
123 If called without arguments, %edit opens up an empty editor with a
123 If called without arguments, %edit opens up an empty editor with a
124 temporary file and will execute the contents of this file when you
124 temporary file and will execute the contents of this file when you
125 close it (don't forget to save it!).
125 close it (don't forget to save it!).
126
126
127 Options:
127 Options:
128
128
129 -n <number>
129 -n <number>
130 Open the editor at a specified line number. By default, the IPython
130 Open the editor at a specified line number. By default, the IPython
131 editor hook uses the unix syntax 'editor +N filename', but you can
131 editor hook uses the unix syntax 'editor +N filename', but you can
132 configure this by providing your own modified hook if your favorite
132 configure this by providing your own modified hook if your favorite
133 editor supports line-number specifications with a different syntax.
133 editor supports line-number specifications with a different syntax.
134
134
135 -p
135 -p
136 Call the editor with the same data as the previous time it was used,
136 Call the editor with the same data as the previous time it was used,
137 regardless of how long ago (in your current session) it was.
137 regardless of how long ago (in your current session) it was.
138
138
139 -r
139 -r
140 Use 'raw' input. This option only applies to input taken from the
140 Use 'raw' input. This option only applies to input taken from the
141 user's history. By default, the 'processed' history is used, so that
141 user's history. By default, the 'processed' history is used, so that
142 magics are loaded in their transformed version to valid Python. If
142 magics are loaded in their transformed version to valid Python. If
143 this option is given, the raw input as typed as the command line is
143 this option is given, the raw input as typed as the command line is
144 used instead. When you exit the editor, it will be executed by
144 used instead. When you exit the editor, it will be executed by
145 IPython's own processor.
145 IPython's own processor.
146
146
147 Arguments:
147 Arguments:
148
148
149 If arguments are given, the following possibilites exist:
149 If arguments are given, the following possibilites exist:
150
150
151 - The arguments are numbers or pairs of colon-separated numbers (like
151 - The arguments are numbers or pairs of colon-separated numbers (like
152 1 4:8 9). These are interpreted as lines of previous input to be
152 1 4:8 9). These are interpreted as lines of previous input to be
153 loaded into the editor. The syntax is the same of the %macro command.
153 loaded into the editor. The syntax is the same of the %macro command.
154
154
155 - If the argument doesn't start with a number, it is evaluated as a
155 - If the argument doesn't start with a number, it is evaluated as a
156 variable and its contents loaded into the editor. You can thus edit
156 variable and its contents loaded into the editor. You can thus edit
157 any string which contains python code (including the result of
157 any string which contains python code (including the result of
158 previous edits).
158 previous edits).
159
159
160 - If the argument is the name of an object (other than a string),
160 - If the argument is the name of an object (other than a string),
161 IPython will try to locate the file where it was defined and open the
161 IPython will try to locate the file where it was defined and open the
162 editor at the point where it is defined. You can use ``%edit function``
162 editor at the point where it is defined. You can use ``%edit function``
163 to load an editor exactly at the point where 'function' is defined,
163 to load an editor exactly at the point where 'function' is defined,
164 edit it and have the file be executed automatically.
164 edit it and have the file be executed automatically.
165
165
166 If the object is a macro (see %macro for details), this opens up your
166 If the object is a macro (see %macro for details), this opens up your
167 specified editor with a temporary file containing the macro's data.
167 specified editor with a temporary file containing the macro's data.
168 Upon exit, the macro is reloaded with the contents of the file.
168 Upon exit, the macro is reloaded with the contents of the file.
169
169
170 Note: opening at an exact line is only supported under Unix, and some
170 Note: opening at an exact line is only supported under Unix, and some
171 editors (like kedit and gedit up to Gnome 2.8) do not understand the
171 editors (like kedit and gedit up to Gnome 2.8) do not understand the
172 '+NUMBER' parameter necessary for this feature. Good editors like
172 '+NUMBER' parameter necessary for this feature. Good editors like
173 (X)Emacs, vi, jed, pico and joe all do.
173 (X)Emacs, vi, jed, pico and joe all do.
174
174
175 - If the argument is not found as a variable, IPython will look for a
175 - If the argument is not found as a variable, IPython will look for a
176 file with that name (adding .py if necessary) and load it into the
176 file with that name (adding .py if necessary) and load it into the
177 editor. It will execute its contents with execfile() when you exit,
177 editor. It will execute its contents with execfile() when you exit,
178 loading any code in the file into your interactive namespace.
178 loading any code in the file into your interactive namespace.
179
179
180 Unlike in the terminal, this is designed to use a GUI editor, and we do
180 Unlike in the terminal, this is designed to use a GUI editor, and we do
181 not know when it has closed. So the file you edit will not be
181 not know when it has closed. So the file you edit will not be
182 automatically executed or printed.
182 automatically executed or printed.
183
183
184 Note that %edit is also available through the alias %ed.
184 Note that %edit is also available through the alias %ed.
185 """
185 """
186
186
187 opts,args = self.parse_options(parameter_s,'prn:')
187 opts,args = self.parse_options(parameter_s,'prn:')
188
188
189 try:
189 try:
190 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
190 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
191 except MacroToEdit as e:
191 except MacroToEdit as e:
192 # TODO: Implement macro editing over 2 processes.
192 # TODO: Implement macro editing over 2 processes.
193 print("Macro editing not yet implemented in 2-process model.")
193 print("Macro editing not yet implemented in 2-process model.")
194 return
194 return
195
195
196 # Make sure we send to the client an absolute path, in case the working
196 # Make sure we send to the client an absolute path, in case the working
197 # directory of client and kernel don't match
197 # directory of client and kernel don't match
198 filename = os.path.abspath(filename)
198 filename = os.path.abspath(filename)
199
199
200 payload = {
200 payload = {
201 'source' : 'edit_magic',
201 'source' : 'edit_magic',
202 'filename' : filename,
202 'filename' : filename,
203 'line_number' : lineno
203 'line_number' : lineno
204 }
204 }
205 self.shell.payload_manager.write_payload(payload)
205 self.shell.payload_manager.write_payload(payload)
206
206
207 # A few magics that are adapted to the specifics of using pexpect and a
207 # A few magics that are adapted to the specifics of using pexpect and a
208 # remote terminal
208 # remote terminal
209
209
210 @line_magic
210 @line_magic
211 def clear(self, arg_s):
211 def clear(self, arg_s):
212 """Clear the terminal."""
212 """Clear the terminal."""
213 if os.name == 'posix':
213 if os.name == 'posix':
214 self.shell.system("clear")
214 self.shell.system("clear")
215 else:
215 else:
216 self.shell.system("cls")
216 self.shell.system("cls")
217
217
218 if os.name == 'nt':
218 if os.name == 'nt':
219 # This is the usual name in windows
219 # This is the usual name in windows
220 cls = line_magic('cls')(clear)
220 cls = line_magic('cls')(clear)
221
221
222 # Terminal pagers won't work over pexpect, but we do have our own pager
222 # Terminal pagers won't work over pexpect, but we do have our own pager
223
223
224 @line_magic
224 @line_magic
225 def less(self, arg_s):
225 def less(self, arg_s):
226 """Show a file through the pager.
226 """Show a file through the pager.
227
227
228 Files ending in .py are syntax-highlighted."""
228 Files ending in .py are syntax-highlighted."""
229 if not arg_s:
229 if not arg_s:
230 raise UsageError('Missing filename.')
230 raise UsageError('Missing filename.')
231
231
232 if arg_s.endswith('.py'):
232 if arg_s.endswith('.py'):
233 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
233 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
234 else:
234 else:
235 cont = open(arg_s).read()
235 cont = open(arg_s).read()
236 page.page(cont)
236 page.page(cont)
237
237
238 more = line_magic('more')(less)
238 more = line_magic('more')(less)
239
239
240 # Man calls a pager, so we also need to redefine it
240 # Man calls a pager, so we also need to redefine it
241 if os.name == 'posix':
241 if os.name == 'posix':
242 @line_magic
242 @line_magic
243 def man(self, arg_s):
243 def man(self, arg_s):
244 """Find the man page for the given command and display in pager."""
244 """Find the man page for the given command and display in pager."""
245 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
245 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
246 split=False))
246 split=False))
247
247
248 @line_magic
248 @line_magic
249 def connect_info(self, arg_s):
249 def connect_info(self, arg_s):
250 """Print information for connecting other clients to this kernel
250 """Print information for connecting other clients to this kernel
251
251
252 It will print the contents of this session's connection file, as well as
252 It will print the contents of this session's connection file, as well as
253 shortcuts for local clients.
253 shortcuts for local clients.
254
254
255 In the simplest case, when called from the most recently launched kernel,
255 In the simplest case, when called from the most recently launched kernel,
256 secondary clients can be connected, simply with:
256 secondary clients can be connected, simply with:
257
257
258 $> ipython <app> --existing
258 $> ipython <app> --existing
259
259
260 """
260 """
261
261
262 from IPython.core.application import BaseIPythonApplication as BaseIPApp
262 from IPython.core.application import BaseIPythonApplication as BaseIPApp
263
263
264 if BaseIPApp.initialized():
264 if BaseIPApp.initialized():
265 app = BaseIPApp.instance()
265 app = BaseIPApp.instance()
266 security_dir = app.profile_dir.security_dir
266 security_dir = app.profile_dir.security_dir
267 profile = app.profile
267 profile = app.profile
268 else:
268 else:
269 profile = 'default'
269 profile = 'default'
270 security_dir = ''
270 security_dir = ''
271
271
272 try:
272 try:
273 connection_file = get_connection_file()
273 connection_file = get_connection_file()
274 info = get_connection_info(unpack=False)
274 info = get_connection_info(unpack=False)
275 except Exception as e:
275 except Exception as e:
276 error("Could not get connection info: %r" % e)
276 error("Could not get connection info: %r" % e)
277 return
277 return
278
278
279 # add profile flag for non-default profile
279 # add profile flag for non-default profile
280 profile_flag = "--profile %s" % profile if profile != 'default' else ""
280 profile_flag = "--profile %s" % profile if profile != 'default' else ""
281
281
282 # if it's in the security dir, truncate to basename
282 # if it's in the security dir, truncate to basename
283 if security_dir == os.path.dirname(connection_file):
283 if security_dir == os.path.dirname(connection_file):
284 connection_file = os.path.basename(connection_file)
284 connection_file = os.path.basename(connection_file)
285
285
286
286
287 print (info + '\n')
287 print (info + '\n')
288 print ("Paste the above JSON into a file, and connect with:\n"
288 print ("Paste the above JSON into a file, and connect with:\n"
289 " $> ipython <app> --existing <file>\n"
289 " $> ipython <app> --existing <file>\n"
290 "or, if you are local, you can connect with just:\n"
290 "or, if you are local, you can connect with just:\n"
291 " $> ipython <app> --existing {0} {1}\n"
291 " $> ipython <app> --existing {0} {1}\n"
292 "or even just:\n"
292 "or even just:\n"
293 " $> ipython <app> --existing {1}\n"
293 " $> ipython <app> --existing {1}\n"
294 "if this is the most recent IPython session you have started.".format(
294 "if this is the most recent IPython session you have started.".format(
295 connection_file, profile_flag
295 connection_file, profile_flag
296 )
296 )
297 )
297 )
298
298
299 @line_magic
299 @line_magic
300 def qtconsole(self, arg_s):
300 def qtconsole(self, arg_s):
301 """Open a qtconsole connected to this kernel.
301 """Open a qtconsole connected to this kernel.
302
302
303 Useful for connecting a qtconsole to running notebooks, for better
303 Useful for connecting a qtconsole to running notebooks, for better
304 debugging.
304 debugging.
305 """
305 """
306
306
307 # %qtconsole should imply bind_kernel for engines:
307 # %qtconsole should imply bind_kernel for engines:
308 try:
308 try:
309 from IPython.parallel import bind_kernel
309 from IPython.parallel import bind_kernel
310 except ImportError:
310 except ImportError:
311 # technically possible, because parallel has higher pyzmq min-version
311 # technically possible, because parallel has higher pyzmq min-version
312 pass
312 pass
313 else:
313 else:
314 bind_kernel()
314 bind_kernel()
315
315
316 try:
316 try:
317 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
317 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
318 except Exception as e:
318 except Exception as e:
319 error("Could not start qtconsole: %r" % e)
319 error("Could not start qtconsole: %r" % e)
320 return
320 return
321
321
322 @line_magic
322 @line_magic
323 def autosave(self, arg_s):
323 def autosave(self, arg_s):
324 """Set the autosave interval in the notebook (in seconds).
324 """Set the autosave interval in the notebook (in seconds).
325
325
326 The default value is 120, or two minutes.
326 The default value is 120, or two minutes.
327 ``%autosave 0`` will disable autosave.
327 ``%autosave 0`` will disable autosave.
328
328
329 This magic only has an effect when called from the notebook interface.
329 This magic only has an effect when called from the notebook interface.
330 It has no effect when called in a startup file.
330 It has no effect when called in a startup file.
331 """
331 """
332
332
333 try:
333 try:
334 interval = int(arg_s)
334 interval = int(arg_s)
335 except ValueError:
335 except ValueError:
336 raise UsageError("%%autosave requires an integer, got %r" % arg_s)
336 raise UsageError("%%autosave requires an integer, got %r" % arg_s)
337
337
338 # javascript wants milliseconds
338 # javascript wants milliseconds
339 milliseconds = 1000 * interval
339 milliseconds = 1000 * interval
340 display(Javascript("IPython.notebook.set_autosave_interval(%i)" % milliseconds),
340 display(Javascript("IPython.notebook.set_autosave_interval(%i)" % milliseconds),
341 include=['application/javascript']
341 include=['application/javascript']
342 )
342 )
343 if interval:
343 if interval:
344 print("Autosaving every %i seconds" % interval)
344 print("Autosaving every %i seconds" % interval)
345 else:
345 else:
346 print("Autosave disabled")
346 print("Autosave disabled")
347
347
348
348
349 class ZMQInteractiveShell(InteractiveShell):
349 class ZMQInteractiveShell(InteractiveShell):
350 """A subclass of InteractiveShell for ZMQ."""
350 """A subclass of InteractiveShell for ZMQ."""
351
351
352 displayhook_class = Type(ZMQShellDisplayHook)
352 displayhook_class = Type(ZMQShellDisplayHook)
353 display_pub_class = Type(ZMQDisplayPublisher)
353 display_pub_class = Type(ZMQDisplayPublisher)
354 data_pub_class = Type(ZMQDataPublisher)
354 data_pub_class = Type(ZMQDataPublisher)
355 kernel = Any()
355 kernel = Any()
356 parent_header = Any()
356 parent_header = Any()
357
357
358 def _banner1_default(self):
358 def _banner1_default(self):
359 return default_gui_banner
359 return default_gui_banner
360
360
361 # Override the traitlet in the parent class, because there's no point using
361 # Override the traitlet in the parent class, because there's no point using
362 # readline for the kernel. Can be removed when the readline code is moved
362 # readline for the kernel. Can be removed when the readline code is moved
363 # to the terminal frontend.
363 # to the terminal frontend.
364 colors_force = CBool(True)
364 colors_force = CBool(True)
365 readline_use = CBool(False)
365 readline_use = CBool(False)
366 # autoindent has no meaning in a zmqshell, and attempting to enable it
366 # autoindent has no meaning in a zmqshell, and attempting to enable it
367 # will print a warning in the absence of readline.
367 # will print a warning in the absence of readline.
368 autoindent = CBool(False)
368 autoindent = CBool(False)
369
369
370 exiter = Instance(ZMQExitAutocall)
370 exiter = Instance(ZMQExitAutocall)
371 def _exiter_default(self):
371 def _exiter_default(self):
372 return ZMQExitAutocall(self)
372 return ZMQExitAutocall(self)
373
373
374 def _exit_now_changed(self, name, old, new):
374 def _exit_now_changed(self, name, old, new):
375 """stop eventloop when exit_now fires"""
375 """stop eventloop when exit_now fires"""
376 if new:
376 if new:
377 loop = ioloop.IOLoop.instance()
377 loop = ioloop.IOLoop.instance()
378 loop.add_timeout(time.time()+0.1, loop.stop)
378 loop.add_timeout(time.time()+0.1, loop.stop)
379
379
380 keepkernel_on_exit = None
380 keepkernel_on_exit = None
381
381
382 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
382 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
383 # interactive input being read; we provide event loop support in ipkernel
383 # interactive input being read; we provide event loop support in ipkernel
384 @staticmethod
384 @staticmethod
385 def enable_gui(gui):
385 def enable_gui(gui):
386 from .eventloops import enable_gui as real_enable_gui
386 from .eventloops import enable_gui as real_enable_gui
387 try:
387 try:
388 real_enable_gui(gui)
388 real_enable_gui(gui)
389 except ValueError as e:
389 except ValueError as e:
390 raise UsageError("%s" % e)
390 raise UsageError("%s" % e)
391
391
392 def init_environment(self):
392 def init_environment(self):
393 """Configure the user's environment."""
393 """Configure the user's environment."""
394 env = os.environ
394 env = os.environ
395 # These two ensure 'ls' produces nice coloring on BSD-derived systems
395 # These two ensure 'ls' produces nice coloring on BSD-derived systems
396 env['TERM'] = 'xterm-color'
396 env['TERM'] = 'xterm-color'
397 env['CLICOLOR'] = '1'
397 env['CLICOLOR'] = '1'
398 # Since normal pagers don't work at all (over pexpect we don't have
398 # Since normal pagers don't work at all (over pexpect we don't have
399 # single-key control of the subprocess), try to disable paging in
399 # single-key control of the subprocess), try to disable paging in
400 # subprocesses as much as possible.
400 # subprocesses as much as possible.
401 env['PAGER'] = 'cat'
401 env['PAGER'] = 'cat'
402 env['GIT_PAGER'] = 'cat'
402 env['GIT_PAGER'] = 'cat'
403
403
404 def init_hooks(self):
404 def init_hooks(self):
405 super(ZMQInteractiveShell, self).init_hooks()
405 super(ZMQInteractiveShell, self).init_hooks()
406 self.set_hook('show_in_pager', page.as_hook(payloadpage.page), 99)
406 self.set_hook('show_in_pager', page.as_hook(payloadpage.page), 99)
407
407
408 def ask_exit(self):
408 def ask_exit(self):
409 """Engage the exit actions."""
409 """Engage the exit actions."""
410 self.exit_now = (not self.keepkernel_on_exit)
410 self.exit_now = (not self.keepkernel_on_exit)
411 payload = dict(
411 payload = dict(
412 source='ask_exit',
412 source='ask_exit',
413 keepkernel=self.keepkernel_on_exit,
413 keepkernel=self.keepkernel_on_exit,
414 )
414 )
415 self.payload_manager.write_payload(payload)
415 self.payload_manager.write_payload(payload)
416
416
417 def _showtraceback(self, etype, evalue, stb):
417 def _showtraceback(self, etype, evalue, stb):
418 # try to preserve ordering of tracebacks and print statements
418 # try to preserve ordering of tracebacks and print statements
419 sys.stdout.flush()
419 sys.stdout.flush()
420 sys.stderr.flush()
420 sys.stderr.flush()
421
421
422 exc_content = {
422 exc_content = {
423 u'traceback' : stb,
423 u'traceback' : stb,
424 u'ename' : unicode_type(etype.__name__),
424 u'ename' : unicode_type(etype.__name__),
425 u'evalue' : py3compat.safe_unicode(evalue),
425 u'evalue' : py3compat.safe_unicode(evalue),
426 }
426 }
427
427
428 dh = self.displayhook
428 dh = self.displayhook
429 # Send exception info over pub socket for other clients than the caller
429 # Send exception info over pub socket for other clients than the caller
430 # to pick up
430 # to pick up
431 topic = None
431 topic = None
432 if dh.topic:
432 if dh.topic:
433 topic = dh.topic.replace(b'execute_result', b'error')
433 topic = dh.topic.replace(b'execute_result', b'error')
434
434
435 exc_msg = dh.session.send(dh.pub_socket, u'error', json_clean(exc_content), dh.parent_header, ident=topic)
435 exc_msg = dh.session.send(dh.pub_socket, u'error', json_clean(exc_content), dh.parent_header, ident=topic)
436
436
437 # FIXME - Hack: store exception info in shell object. Right now, the
437 # FIXME - Hack: store exception info in shell object. Right now, the
438 # caller is reading this info after the fact, we need to fix this logic
438 # caller is reading this info after the fact, we need to fix this logic
439 # to remove this hack. Even uglier, we need to store the error status
439 # to remove this hack. Even uglier, we need to store the error status
440 # here, because in the main loop, the logic that sets it is being
440 # here, because in the main loop, the logic that sets it is being
441 # skipped because runlines swallows the exceptions.
441 # skipped because runlines swallows the exceptions.
442 exc_content[u'status'] = u'error'
442 exc_content[u'status'] = u'error'
443 self._reply_content = exc_content
443 self._reply_content = exc_content
444 # /FIXME
444 # /FIXME
445
445
446 return exc_content
446 return exc_content
447
447
448 def set_next_input(self, text, replace=False):
448 def set_next_input(self, text, replace=False):
449 """Send the specified text to the frontend to be presented at the next
449 """Send the specified text to the frontend to be presented at the next
450 input cell."""
450 input cell."""
451 payload = dict(
451 payload = dict(
452 source='set_next_input',
452 source='set_next_input',
453 text=text,
453 text=text,
454 replace=replace,
454 replace=replace,
455 )
455 )
456 self.payload_manager.write_payload(payload)
456 self.payload_manager.write_payload(payload)
457
457
458 def set_parent(self, parent):
458 def set_parent(self, parent):
459 """Set the parent header for associating output with its triggering input"""
459 """Set the parent header for associating output with its triggering input"""
460 self.parent_header = parent
460 self.parent_header = parent
461 self.displayhook.set_parent(parent)
461 self.displayhook.set_parent(parent)
462 self.display_pub.set_parent(parent)
462 self.display_pub.set_parent(parent)
463 self.data_pub.set_parent(parent)
463 self.data_pub.set_parent(parent)
464 try:
464 try:
465 sys.stdout.set_parent(parent)
465 sys.stdout.set_parent(parent)
466 except AttributeError:
466 except AttributeError:
467 pass
467 pass
468 try:
468 try:
469 sys.stderr.set_parent(parent)
469 sys.stderr.set_parent(parent)
470 except AttributeError:
470 except AttributeError:
471 pass
471 pass
472
472
473 def get_parent(self):
473 def get_parent(self):
474 return self.parent_header
474 return self.parent_header
475
475
476 #-------------------------------------------------------------------------
476 #-------------------------------------------------------------------------
477 # Things related to magics
477 # Things related to magics
478 #-------------------------------------------------------------------------
478 #-------------------------------------------------------------------------
479
479
480 def init_magics(self):
480 def init_magics(self):
481 super(ZMQInteractiveShell, self).init_magics()
481 super(ZMQInteractiveShell, self).init_magics()
482 self.register_magics(KernelMagics)
482 self.register_magics(KernelMagics)
483 self.magics_manager.register_alias('ed', 'edit')
483 self.magics_manager.register_alias('ed', 'edit')
484
484
485
485
486 InteractiveShellABC.register(ZMQInteractiveShell)
486 InteractiveShellABC.register(ZMQInteractiveShell)
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now