##// END OF EJS Templates
move IPython.inprocess to IPython.kernel.inprocess
MinRK -
Show More
@@ -1,85 +1,85 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IPython: tools for interactive and parallel computing in Python.
3 IPython: tools for interactive and parallel computing in Python.
4
4
5 http://ipython.org
5 http://ipython.org
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2008-2011, IPython Development Team.
8 # Copyright (c) 2008-2011, IPython Development Team.
9 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
9 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
10 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
10 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
11 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
11 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
12 #
12 #
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14 #
14 #
15 # The full license is in the file COPYING.txt, distributed with this software.
15 # The full license is in the file COPYING.txt, distributed with this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 from __future__ import absolute_import
21 from __future__ import absolute_import
22
22
23 import os
23 import os
24 import sys
24 import sys
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Setup everything
27 # Setup everything
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 # Don't forget to also update setup.py when this changes!
30 # Don't forget to also update setup.py when this changes!
31 if sys.version[0:3] < '2.6':
31 if sys.version[0:3] < '2.6':
32 raise ImportError('Python Version 2.6 or above is required for IPython.')
32 raise ImportError('Python Version 2.6 or above is required for IPython.')
33
33
34 # Make it easy to import extensions - they are always directly on pythonpath.
34 # Make it easy to import extensions - they are always directly on pythonpath.
35 # Therefore, non-IPython modules can be added to extensions directory.
35 # Therefore, non-IPython modules can be added to extensions directory.
36 # This should probably be in ipapp.py.
36 # This should probably be in ipapp.py.
37 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
37 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Setup the top level names
40 # Setup the top level names
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43 from .config.loader import Config
43 from .config.loader import Config
44 from .core import release
44 from .core import release
45 from .core.application import Application
45 from .core.application import Application
46 from .frontend.terminal.embed import embed
46 from .frontend.terminal.embed import embed
47
47
48 from .core.error import TryNext
48 from .core.error import TryNext
49 from .core.interactiveshell import InteractiveShell
49 from .core.interactiveshell import InteractiveShell
50 from .testing import test
50 from .testing import test
51 from .utils.sysinfo import sys_info
51 from .utils.sysinfo import sys_info
52 from .utils.frame import extract_module_locals
52 from .utils.frame import extract_module_locals
53
53
54 # Release data
54 # Release data
55 __author__ = '%s <%s>' % (release.author, release.author_email)
55 __author__ = '%s <%s>' % (release.author, release.author_email)
56 __license__ = release.license
56 __license__ = release.license
57 __version__ = release.version
57 __version__ = release.version
58 version_info = release.version_info
58 version_info = release.version_info
59
59
60 def embed_kernel(module=None, local_ns=None, **kwargs):
60 def embed_kernel(module=None, local_ns=None, **kwargs):
61 """Embed and start an IPython kernel in a given scope.
61 """Embed and start an IPython kernel in a given scope.
62
62
63 Parameters
63 Parameters
64 ----------
64 ----------
65 module : ModuleType, optional
65 module : ModuleType, optional
66 The module to load into IPython globals (default: caller)
66 The module to load into IPython globals (default: caller)
67 local_ns : dict, optional
67 local_ns : dict, optional
68 The namespace to load into IPython user namespace (default: caller)
68 The namespace to load into IPython user namespace (default: caller)
69
69
70 kwargs : various, optional
70 kwargs : various, optional
71 Further keyword args are relayed to the KernelApp constructor,
71 Further keyword args are relayed to the KernelApp constructor,
72 allowing configuration of the Kernel. Will only have an effect
72 allowing configuration of the Kernel. Will only have an effect
73 on the first embed_kernel call for a given process.
73 on the first embed_kernel call for a given process.
74
74
75 """
75 """
76
76
77 (caller_module, caller_locals) = extract_module_locals(1)
77 (caller_module, caller_locals) = extract_module_locals(1)
78 if module is None:
78 if module is None:
79 module = caller_module
79 module = caller_module
80 if local_ns is None:
80 if local_ns is None:
81 local_ns = caller_locals
81 local_ns = caller_locals
82
82
83 # Only import .zmq when we really need it
83 # Only import .zmq when we really need it
84 from .zmq.embed import embed_kernel as real_embed_kernel
84 from IPython.kernel.zmq.embed import embed_kernel as real_embed_kernel
85 real_embed_kernel(module=module, local_ns=local_ns, **kwargs)
85 real_embed_kernel(module=module, local_ns=local_ns, **kwargs)
@@ -1,33 +1,33 b''
1 """ Defines an in-process KernelManager with signals and slots.
1 """ Defines an in-process KernelManager with signals and slots.
2 """
2 """
3
3
4 # Local imports.
4 # Local imports.
5 from IPython.inprocess.kernelmanager import \
5 from IPython.kernel.inprocess.kernelmanager import \
6 InProcessShellChannel, InProcessIOPubChannel, InProcessStdInChannel, \
6 InProcessShellChannel, InProcessIOPubChannel, InProcessStdInChannel, \
7 InProcessHBChannel, InProcessKernelManager
7 InProcessHBChannel, InProcessKernelManager
8 from IPython.utils.traitlets import Type
8 from IPython.utils.traitlets import Type
9 from base_kernelmanager import QtShellChannelMixin, QtIOPubChannelMixin, \
9 from base_kernelmanager import QtShellChannelMixin, QtIOPubChannelMixin, \
10 QtStdInChannelMixin, QtHBChannelMixin, QtKernelManagerMixin
10 QtStdInChannelMixin, QtHBChannelMixin, QtKernelManagerMixin
11
11
12
12
13 class QtInProcessShellChannel(QtShellChannelMixin, InProcessShellChannel):
13 class QtInProcessShellChannel(QtShellChannelMixin, InProcessShellChannel):
14 pass
14 pass
15
15
16 class QtInProcessIOPubChannel(QtIOPubChannelMixin, InProcessIOPubChannel):
16 class QtInProcessIOPubChannel(QtIOPubChannelMixin, InProcessIOPubChannel):
17 pass
17 pass
18
18
19 class QtInProcessStdInChannel(QtStdInChannelMixin, InProcessStdInChannel):
19 class QtInProcessStdInChannel(QtStdInChannelMixin, InProcessStdInChannel):
20 pass
20 pass
21
21
22 class QtInProcessHBChannel(QtHBChannelMixin, InProcessHBChannel):
22 class QtInProcessHBChannel(QtHBChannelMixin, InProcessHBChannel):
23 pass
23 pass
24
24
25
25
26 class QtInProcessKernelManager(QtKernelManagerMixin, InProcessKernelManager):
26 class QtInProcessKernelManager(QtKernelManagerMixin, InProcessKernelManager):
27 """ An in-process KernelManager with signals and slots.
27 """ An in-process KernelManager with signals and slots.
28 """
28 """
29
29
30 iopub_channel_class = Type(QtInProcessIOPubChannel)
30 iopub_channel_class = Type(QtInProcessIOPubChannel)
31 shell_channel_class = Type(QtInProcessShellChannel)
31 shell_channel_class = Type(QtInProcessShellChannel)
32 stdin_channel_class = Type(QtInProcessStdInChannel)
32 stdin_channel_class = Type(QtInProcessStdInChannel)
33 hb_channel_class = Type(QtInProcessHBChannel)
33 hb_channel_class = Type(QtInProcessHBChannel)
1 NO CONTENT: file renamed from IPython/inprocess/__init__.py to IPython/kernel/inprocess/__init__.py
NO CONTENT: file renamed from IPython/inprocess/__init__.py to IPython/kernel/inprocess/__init__.py
1 NO CONTENT: file renamed from IPython/inprocess/blockingkernelmanager.py to IPython/kernel/inprocess/blockingkernelmanager.py
NO CONTENT: file renamed from IPython/inprocess/blockingkernelmanager.py to IPython/kernel/inprocess/blockingkernelmanager.py
@@ -1,176 +1,177 b''
1 """ An in-process kernel. """
1 """An in-process kernel"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2012 The IPython Development Team
4 # Copyright (C) 2012 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 # Standard library imports
14 # Standard library imports
15 from contextlib import contextmanager
15 from contextlib import contextmanager
16 import logging
16 import logging
17 import sys
17 import sys
18
18
19 # Local imports.
19 # Local imports
20 from IPython.core.interactiveshell import InteractiveShellABC
20 from IPython.core.interactiveshell import InteractiveShellABC
21 from IPython.inprocess.socket import DummySocket
22 from IPython.utils.jsonutil import json_clean
21 from IPython.utils.jsonutil import json_clean
23 from IPython.utils.traitlets import Any, Enum, Instance, List, Type
22 from IPython.utils.traitlets import Any, Enum, Instance, List, Type
24 from IPython.kernel.zmq.ipkernel import Kernel
23 from IPython.kernel.zmq.ipkernel import Kernel
25 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
24 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
26
25
26 from .socket import DummySocket
27
27 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
28 # Main kernel class
29 # Main kernel class
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30
31
31 class InProcessKernel(Kernel):
32 class InProcessKernel(Kernel):
32
33
33 #-------------------------------------------------------------------------
34 #-------------------------------------------------------------------------
34 # InProcessKernel interface
35 # InProcessKernel interface
35 #-------------------------------------------------------------------------
36 #-------------------------------------------------------------------------
36
37
37 # The frontends connected to this kernel.
38 # The frontends connected to this kernel.
38 frontends = List(
39 frontends = List(
39 Instance('IPython.inprocess.kernelmanager.InProcessKernelManager'))
40 Instance('IPython.kernel.inprocess.kernelmanager.InProcessKernelManager'))
40
41
41 # The GUI environment that the kernel is running under. This need not be
42 # The GUI environment that the kernel is running under. This need not be
42 # specified for the normal operation for the kernel, but is required for
43 # specified for the normal operation for the kernel, but is required for
43 # IPython's GUI support (including pylab). The default is 'inline' because
44 # IPython's GUI support (including pylab). The default is 'inline' because
44 # it is safe under all GUI toolkits.
45 # it is safe under all GUI toolkits.
45 gui = Enum(('tk', 'gtk', 'wx', 'qt', 'qt4', 'inline'),
46 gui = Enum(('tk', 'gtk', 'wx', 'qt', 'qt4', 'inline'),
46 default_value='inline')
47 default_value='inline')
47
48
48 raw_input_str = Any()
49 raw_input_str = Any()
49 stdout = Any()
50 stdout = Any()
50 stderr = Any()
51 stderr = Any()
51
52
52 #-------------------------------------------------------------------------
53 #-------------------------------------------------------------------------
53 # Kernel interface
54 # Kernel interface
54 #-------------------------------------------------------------------------
55 #-------------------------------------------------------------------------
55
56
56 shell_class = Type()
57 shell_class = Type()
57 shell_streams = List()
58 shell_streams = List()
58 control_stream = Any()
59 control_stream = Any()
59 iopub_socket = Instance(DummySocket, ())
60 iopub_socket = Instance(DummySocket, ())
60 stdin_socket = Instance(DummySocket, ())
61 stdin_socket = Instance(DummySocket, ())
61
62
62 def __init__(self, **traits):
63 def __init__(self, **traits):
63 # When an InteractiveShell is instantiated by our base class, it binds
64 # When an InteractiveShell is instantiated by our base class, it binds
64 # the current values of sys.stdout and sys.stderr.
65 # the current values of sys.stdout and sys.stderr.
65 with self._redirected_io():
66 with self._redirected_io():
66 super(InProcessKernel, self).__init__(**traits)
67 super(InProcessKernel, self).__init__(**traits)
67
68
68 self.iopub_socket.on_trait_change(self._io_dispatch, 'message_sent')
69 self.iopub_socket.on_trait_change(self._io_dispatch, 'message_sent')
69 self.shell.kernel = self
70 self.shell.kernel = self
70
71
71 def execute_request(self, stream, ident, parent):
72 def execute_request(self, stream, ident, parent):
72 """ Override for temporary IO redirection. """
73 """ Override for temporary IO redirection. """
73 with self._redirected_io():
74 with self._redirected_io():
74 super(InProcessKernel, self).execute_request(stream, ident, parent)
75 super(InProcessKernel, self).execute_request(stream, ident, parent)
75
76
76 def start(self):
77 def start(self):
77 """ Override registration of dispatchers for streams. """
78 """ Override registration of dispatchers for streams. """
78 self.shell.exit_now = False
79 self.shell.exit_now = False
79
80
80 def _abort_queue(self, stream):
81 def _abort_queue(self, stream):
81 """ The in-process kernel doesn't abort requests. """
82 """ The in-process kernel doesn't abort requests. """
82 pass
83 pass
83
84
84 def _raw_input(self, prompt, ident, parent):
85 def _raw_input(self, prompt, ident, parent):
85 # Flush output before making the request.
86 # Flush output before making the request.
86 self.raw_input_str = None
87 self.raw_input_str = None
87 sys.stderr.flush()
88 sys.stderr.flush()
88 sys.stdout.flush()
89 sys.stdout.flush()
89
90
90 # Send the input request.
91 # Send the input request.
91 content = json_clean(dict(prompt=prompt))
92 content = json_clean(dict(prompt=prompt))
92 msg = self.session.msg(u'input_request', content, parent)
93 msg = self.session.msg(u'input_request', content, parent)
93 for frontend in self.frontends:
94 for frontend in self.frontends:
94 if frontend.session.session == parent['header']['session']:
95 if frontend.session.session == parent['header']['session']:
95 frontend.stdin_channel.call_handlers(msg)
96 frontend.stdin_channel.call_handlers(msg)
96 break
97 break
97 else:
98 else:
98 logging.error('No frontend found for raw_input request')
99 logging.error('No frontend found for raw_input request')
99 return str()
100 return str()
100
101
101 # Await a response.
102 # Await a response.
102 while self.raw_input_str is None:
103 while self.raw_input_str is None:
103 frontend.stdin_channel.process_events()
104 frontend.stdin_channel.process_events()
104 return self.raw_input_str
105 return self.raw_input_str
105
106
106 #-------------------------------------------------------------------------
107 #-------------------------------------------------------------------------
107 # Protected interface
108 # Protected interface
108 #-------------------------------------------------------------------------
109 #-------------------------------------------------------------------------
109
110
110 @contextmanager
111 @contextmanager
111 def _redirected_io(self):
112 def _redirected_io(self):
112 """ Temporarily redirect IO to the kernel.
113 """ Temporarily redirect IO to the kernel.
113 """
114 """
114 sys_stdout, sys_stderr = sys.stdout, sys.stderr
115 sys_stdout, sys_stderr = sys.stdout, sys.stderr
115 sys.stdout, sys.stderr = self.stdout, self.stderr
116 sys.stdout, sys.stderr = self.stdout, self.stderr
116 yield
117 yield
117 sys.stdout, sys.stderr = sys_stdout, sys_stderr
118 sys.stdout, sys.stderr = sys_stdout, sys_stderr
118
119
119 #------ Trait change handlers --------------------------------------------
120 #------ Trait change handlers --------------------------------------------
120
121
121 def _io_dispatch(self):
122 def _io_dispatch(self):
122 """ Called when a message is sent to the IO socket.
123 """ Called when a message is sent to the IO socket.
123 """
124 """
124 ident, msg = self.session.recv(self.iopub_socket, copy=False)
125 ident, msg = self.session.recv(self.iopub_socket, copy=False)
125 for frontend in self.frontends:
126 for frontend in self.frontends:
126 frontend.iopub_channel.call_handlers(msg)
127 frontend.iopub_channel.call_handlers(msg)
127
128
128 #------ Trait initializers -----------------------------------------------
129 #------ Trait initializers -----------------------------------------------
129
130
130 def _log_default(self):
131 def _log_default(self):
131 return logging.getLogger(__name__)
132 return logging.getLogger(__name__)
132
133
133 def _session_default(self):
134 def _session_default(self):
134 from IPython.kernel.zmq.session import Session
135 from IPython.kernel.zmq.session import Session
135 return Session(config=self.config)
136 return Session(config=self.config)
136
137
137 def _shell_class_default(self):
138 def _shell_class_default(self):
138 return InProcessInteractiveShell
139 return InProcessInteractiveShell
139
140
140 def _stdout_default(self):
141 def _stdout_default(self):
141 from IPython.kernel.zmq.iostream import OutStream
142 from IPython.kernel.zmq.iostream import OutStream
142 return OutStream(self.session, self.iopub_socket, u'stdout')
143 return OutStream(self.session, self.iopub_socket, u'stdout')
143
144
144 def _stderr_default(self):
145 def _stderr_default(self):
145 from IPython.kernel.zmq.iostream import OutStream
146 from IPython.kernel.zmq.iostream import OutStream
146 return OutStream(self.session, self.iopub_socket, u'stderr')
147 return OutStream(self.session, self.iopub_socket, u'stderr')
147
148
148 #-----------------------------------------------------------------------------
149 #-----------------------------------------------------------------------------
149 # Interactive shell subclass
150 # Interactive shell subclass
150 #-----------------------------------------------------------------------------
151 #-----------------------------------------------------------------------------
151
152
152 class InProcessInteractiveShell(ZMQInteractiveShell):
153 class InProcessInteractiveShell(ZMQInteractiveShell):
153
154
154 kernel = Instance('IPython.inprocess.ipkernel.InProcessKernel')
155 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel')
155
156
156 #-------------------------------------------------------------------------
157 #-------------------------------------------------------------------------
157 # InteractiveShell interface
158 # InteractiveShell interface
158 #-------------------------------------------------------------------------
159 #-------------------------------------------------------------------------
159
160
160 def enable_gui(self, gui=None):
161 def enable_gui(self, gui=None):
161 """ Enable GUI integration for the kernel.
162 """ Enable GUI integration for the kernel.
162 """
163 """
163 from IPython.kernel.zmq.eventloops import enable_gui
164 from IPython.kernel.zmq.eventloops import enable_gui
164 if not gui:
165 if not gui:
165 gui = self.kernel.gui
166 gui = self.kernel.gui
166 enable_gui(gui, kernel=self.kernel)
167 enable_gui(gui, kernel=self.kernel)
167
168
168 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
169 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
169 """ Activate pylab support at runtime.
170 """ Activate pylab support at runtime.
170 """
171 """
171 if not gui:
172 if not gui:
172 gui = self.kernel.gui
173 gui = self.kernel.gui
173 super(InProcessInteractiveShell, self).enable_pylab(gui, import_all,
174 super(InProcessInteractiveShell, self).enable_pylab(gui, import_all,
174 welcome_message)
175 welcome_message)
175
176
176 InteractiveShellABC.register(InProcessInteractiveShell)
177 InteractiveShellABC.register(InProcessInteractiveShell)
@@ -1,313 +1,314 b''
1 """ A kernel manager for in-process kernels. """
1 """ A kernel manager for in-process kernels. """
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2012 The IPython Development Team
4 # Copyright (C) 2012 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 # Local imports.
14 # Local imports.
15 from IPython.config.configurable import Configurable
15 from IPython.config.configurable import Configurable
16 from IPython.inprocess.socket import DummySocket
17 from IPython.utils.traitlets import Any, Instance, Type
16 from IPython.utils.traitlets import Any, Instance, Type
18 from IPython.kernel import (
17 from IPython.kernel import (
19 ShellChannelABC, IOPubChannelABC,
18 ShellChannelABC, IOPubChannelABC,
20 HBChannelABC, StdInChannelABC,
19 HBChannelABC, StdInChannelABC,
21 KernelManagerABC
20 KernelManagerABC
22 )
21 )
23
22
23 from .socket import DummySocket
24
24 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
25 # Channel classes
26 # Channel classes
26 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
27
28
28 class InProcessChannel(object):
29 class InProcessChannel(object):
29 """Base class for in-process channels."""
30 """Base class for in-process channels."""
30
31
31 def __init__(self, manager):
32 def __init__(self, manager):
32 super(InProcessChannel, self).__init__()
33 super(InProcessChannel, self).__init__()
33 self.manager = manager
34 self.manager = manager
34 self._is_alive = False
35 self._is_alive = False
35
36
36 #--------------------------------------------------------------------------
37 #--------------------------------------------------------------------------
37 # Channel interface
38 # Channel interface
38 #--------------------------------------------------------------------------
39 #--------------------------------------------------------------------------
39
40
40 def is_alive(self):
41 def is_alive(self):
41 return self._is_alive
42 return self._is_alive
42
43
43 def start(self):
44 def start(self):
44 self._is_alive = True
45 self._is_alive = True
45
46
46 def stop(self):
47 def stop(self):
47 self._is_alive = False
48 self._is_alive = False
48
49
49 def call_handlers(self, msg):
50 def call_handlers(self, msg):
50 """ This method is called in the main thread when a message arrives.
51 """ This method is called in the main thread when a message arrives.
51
52
52 Subclasses should override this method to handle incoming messages.
53 Subclasses should override this method to handle incoming messages.
53 """
54 """
54 raise NotImplementedError('call_handlers must be defined in a subclass.')
55 raise NotImplementedError('call_handlers must be defined in a subclass.')
55
56
56 #--------------------------------------------------------------------------
57 #--------------------------------------------------------------------------
57 # InProcessChannel interface
58 # InProcessChannel interface
58 #--------------------------------------------------------------------------
59 #--------------------------------------------------------------------------
59
60
60 def call_handlers_later(self, *args, **kwds):
61 def call_handlers_later(self, *args, **kwds):
61 """ Call the message handlers later.
62 """ Call the message handlers later.
62
63
63 The default implementation just calls the handlers immediately, but this
64 The default implementation just calls the handlers immediately, but this
64 method exists so that GUI toolkits can defer calling the handlers until
65 method exists so that GUI toolkits can defer calling the handlers until
65 after the event loop has run, as expected by GUI frontends.
66 after the event loop has run, as expected by GUI frontends.
66 """
67 """
67 self.call_handlers(*args, **kwds)
68 self.call_handlers(*args, **kwds)
68
69
69 def process_events(self):
70 def process_events(self):
70 """ Process any pending GUI events.
71 """ Process any pending GUI events.
71
72
72 This method will be never be called from a frontend without an event
73 This method will be never be called from a frontend without an event
73 loop (e.g., a terminal frontend).
74 loop (e.g., a terminal frontend).
74 """
75 """
75 raise NotImplementedError
76 raise NotImplementedError
76
77
77
78
78 class InProcessShellChannel(InProcessChannel):
79 class InProcessShellChannel(InProcessChannel):
79 """See `IPython.kernel.kernelmanager.ShellChannel` for docstrings."""
80 """See `IPython.kernel.kernelmanager.ShellChannel` for docstrings."""
80
81
81 # flag for whether execute requests should be allowed to call raw_input
82 # flag for whether execute requests should be allowed to call raw_input
82 allow_stdin = True
83 allow_stdin = True
83
84
84 #--------------------------------------------------------------------------
85 #--------------------------------------------------------------------------
85 # ShellChannel interface
86 # ShellChannel interface
86 #--------------------------------------------------------------------------
87 #--------------------------------------------------------------------------
87
88
88 def execute(self, code, silent=False, store_history=True,
89 def execute(self, code, silent=False, store_history=True,
89 user_variables=[], user_expressions={}, allow_stdin=None):
90 user_variables=[], user_expressions={}, allow_stdin=None):
90 if allow_stdin is None:
91 if allow_stdin is None:
91 allow_stdin = self.allow_stdin
92 allow_stdin = self.allow_stdin
92 content = dict(code=code, silent=silent, store_history=store_history,
93 content = dict(code=code, silent=silent, store_history=store_history,
93 user_variables=user_variables,
94 user_variables=user_variables,
94 user_expressions=user_expressions,
95 user_expressions=user_expressions,
95 allow_stdin=allow_stdin)
96 allow_stdin=allow_stdin)
96 msg = self.manager.session.msg('execute_request', content)
97 msg = self.manager.session.msg('execute_request', content)
97 self._dispatch_to_kernel(msg)
98 self._dispatch_to_kernel(msg)
98 return msg['header']['msg_id']
99 return msg['header']['msg_id']
99
100
100 def complete(self, text, line, cursor_pos, block=None):
101 def complete(self, text, line, cursor_pos, block=None):
101 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
102 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
102 msg = self.manager.session.msg('complete_request', content)
103 msg = self.manager.session.msg('complete_request', content)
103 self._dispatch_to_kernel(msg)
104 self._dispatch_to_kernel(msg)
104 return msg['header']['msg_id']
105 return msg['header']['msg_id']
105
106
106 def object_info(self, oname, detail_level=0):
107 def object_info(self, oname, detail_level=0):
107 content = dict(oname=oname, detail_level=detail_level)
108 content = dict(oname=oname, detail_level=detail_level)
108 msg = self.manager.session.msg('object_info_request', content)
109 msg = self.manager.session.msg('object_info_request', content)
109 self._dispatch_to_kernel(msg)
110 self._dispatch_to_kernel(msg)
110 return msg['header']['msg_id']
111 return msg['header']['msg_id']
111
112
112 def history(self, raw=True, output=False, hist_access_type='range', **kwds):
113 def history(self, raw=True, output=False, hist_access_type='range', **kwds):
113 content = dict(raw=raw, output=output,
114 content = dict(raw=raw, output=output,
114 hist_access_type=hist_access_type, **kwds)
115 hist_access_type=hist_access_type, **kwds)
115 msg = self.manager.session.msg('history_request', content)
116 msg = self.manager.session.msg('history_request', content)
116 self._dispatch_to_kernel(msg)
117 self._dispatch_to_kernel(msg)
117 return msg['header']['msg_id']
118 return msg['header']['msg_id']
118
119
119 def shutdown(self, restart=False):
120 def shutdown(self, restart=False):
120 # FIXME: What to do here?
121 # FIXME: What to do here?
121 raise NotImplementedError('Cannot shutdown in-process kernel')
122 raise NotImplementedError('Cannot shutdown in-process kernel')
122
123
123 #--------------------------------------------------------------------------
124 #--------------------------------------------------------------------------
124 # Protected interface
125 # Protected interface
125 #--------------------------------------------------------------------------
126 #--------------------------------------------------------------------------
126
127
127 def _dispatch_to_kernel(self, msg):
128 def _dispatch_to_kernel(self, msg):
128 """ Send a message to the kernel and handle a reply.
129 """ Send a message to the kernel and handle a reply.
129 """
130 """
130 kernel = self.manager.kernel
131 kernel = self.manager.kernel
131 if kernel is None:
132 if kernel is None:
132 raise RuntimeError('Cannot send request. No kernel exists.')
133 raise RuntimeError('Cannot send request. No kernel exists.')
133
134
134 stream = DummySocket()
135 stream = DummySocket()
135 self.manager.session.send(stream, msg)
136 self.manager.session.send(stream, msg)
136 msg_parts = stream.recv_multipart()
137 msg_parts = stream.recv_multipart()
137 kernel.dispatch_shell(stream, msg_parts)
138 kernel.dispatch_shell(stream, msg_parts)
138
139
139 idents, reply_msg = self.manager.session.recv(stream, copy=False)
140 idents, reply_msg = self.manager.session.recv(stream, copy=False)
140 self.call_handlers_later(reply_msg)
141 self.call_handlers_later(reply_msg)
141
142
142
143
143 class InProcessIOPubChannel(InProcessChannel):
144 class InProcessIOPubChannel(InProcessChannel):
144 """See `IPython.kernel.kernelmanager.IOPubChannel` for docstrings."""
145 """See `IPython.kernel.kernelmanager.IOPubChannel` for docstrings."""
145
146
146 def flush(self, timeout=1.0):
147 def flush(self, timeout=1.0):
147 pass
148 pass
148
149
149
150
150 class InProcessStdInChannel(InProcessChannel):
151 class InProcessStdInChannel(InProcessChannel):
151 """See `IPython.kernel.kernelmanager.StdInChannel` for docstrings."""
152 """See `IPython.kernel.kernelmanager.StdInChannel` for docstrings."""
152
153
153 def input(self, string):
154 def input(self, string):
154 kernel = self.manager.kernel
155 kernel = self.manager.kernel
155 if kernel is None:
156 if kernel is None:
156 raise RuntimeError('Cannot send input reply. No kernel exists.')
157 raise RuntimeError('Cannot send input reply. No kernel exists.')
157 kernel.raw_input_str = string
158 kernel.raw_input_str = string
158
159
159
160
160 class InProcessHBChannel(InProcessChannel):
161 class InProcessHBChannel(InProcessChannel):
161 """See `IPython.kernel.kernelmanager.HBChannel` for docstrings."""
162 """See `IPython.kernel.kernelmanager.HBChannel` for docstrings."""
162
163
163 time_to_dead = 3.0
164 time_to_dead = 3.0
164
165
165 def __init__(self, *args, **kwds):
166 def __init__(self, *args, **kwds):
166 super(InProcessHBChannel, self).__init__(*args, **kwds)
167 super(InProcessHBChannel, self).__init__(*args, **kwds)
167 self._pause = True
168 self._pause = True
168
169
169 def pause(self):
170 def pause(self):
170 self._pause = True
171 self._pause = True
171
172
172 def unpause(self):
173 def unpause(self):
173 self._pause = False
174 self._pause = False
174
175
175 def is_beating(self):
176 def is_beating(self):
176 return not self._pause
177 return not self._pause
177
178
178
179
179 #-----------------------------------------------------------------------------
180 #-----------------------------------------------------------------------------
180 # Main kernel manager class
181 # Main kernel manager class
181 #-----------------------------------------------------------------------------
182 #-----------------------------------------------------------------------------
182
183
183 class InProcessKernelManager(Configurable):
184 class InProcessKernelManager(Configurable):
184 """A manager for an in-process kernel.
185 """A manager for an in-process kernel.
185
186
186 This class implements the interface of
187 This class implements the interface of
187 `IPython.kernel.kernelmanagerabc.KernelManagerABC` and allows
188 `IPython.kernel.kernelmanagerabc.KernelManagerABC` and allows
188 (asynchronous) frontends to be used seamlessly with an in-process kernel.
189 (asynchronous) frontends to be used seamlessly with an in-process kernel.
189
190
190 See `IPython.kernel.kernelmanager.KernelManager` for docstrings.
191 See `IPython.kernel.kernelmanager.KernelManager` for docstrings.
191 """
192 """
192
193
193 # The Session to use for building messages.
194 # The Session to use for building messages.
194 session = Instance('IPython.kernel.zmq.session.Session')
195 session = Instance('IPython.kernel.zmq.session.Session')
195 def _session_default(self):
196 def _session_default(self):
196 from IPython.kernel.zmq.session import Session
197 from IPython.kernel.zmq.session import Session
197 return Session(config=self.config)
198 return Session(config=self.config)
198
199
199 # The kernel process with which the KernelManager is communicating.
200 # The kernel process with which the KernelManager is communicating.
200 kernel = Instance('IPython.inprocess.ipkernel.InProcessKernel')
201 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel')
201
202
202 # The classes to use for the various channels.
203 # The classes to use for the various channels.
203 shell_channel_class = Type(InProcessShellChannel)
204 shell_channel_class = Type(InProcessShellChannel)
204 iopub_channel_class = Type(InProcessIOPubChannel)
205 iopub_channel_class = Type(InProcessIOPubChannel)
205 stdin_channel_class = Type(InProcessStdInChannel)
206 stdin_channel_class = Type(InProcessStdInChannel)
206 hb_channel_class = Type(InProcessHBChannel)
207 hb_channel_class = Type(InProcessHBChannel)
207
208
208 # Protected traits.
209 # Protected traits.
209 _shell_channel = Any
210 _shell_channel = Any
210 _iopub_channel = Any
211 _iopub_channel = Any
211 _stdin_channel = Any
212 _stdin_channel = Any
212 _hb_channel = Any
213 _hb_channel = Any
213
214
214 #--------------------------------------------------------------------------
215 #--------------------------------------------------------------------------
215 # Channel management methods.
216 # Channel management methods.
216 #--------------------------------------------------------------------------
217 #--------------------------------------------------------------------------
217
218
218 def start_channels(self, shell=True, iopub=True, stdin=True, hb=True):
219 def start_channels(self, shell=True, iopub=True, stdin=True, hb=True):
219 if shell:
220 if shell:
220 self.shell_channel.start()
221 self.shell_channel.start()
221 if iopub:
222 if iopub:
222 self.iopub_channel.start()
223 self.iopub_channel.start()
223 if stdin:
224 if stdin:
224 self.stdin_channel.start()
225 self.stdin_channel.start()
225 self.shell_channel.allow_stdin = True
226 self.shell_channel.allow_stdin = True
226 else:
227 else:
227 self.shell_channel.allow_stdin = False
228 self.shell_channel.allow_stdin = False
228 if hb:
229 if hb:
229 self.hb_channel.start()
230 self.hb_channel.start()
230
231
231 def stop_channels(self):
232 def stop_channels(self):
232 if self.shell_channel.is_alive():
233 if self.shell_channel.is_alive():
233 self.shell_channel.stop()
234 self.shell_channel.stop()
234 if self.iopub_channel.is_alive():
235 if self.iopub_channel.is_alive():
235 self.iopub_channel.stop()
236 self.iopub_channel.stop()
236 if self.stdin_channel.is_alive():
237 if self.stdin_channel.is_alive():
237 self.stdin_channel.stop()
238 self.stdin_channel.stop()
238 if self.hb_channel.is_alive():
239 if self.hb_channel.is_alive():
239 self.hb_channel.stop()
240 self.hb_channel.stop()
240
241
241 @property
242 @property
242 def channels_running(self):
243 def channels_running(self):
243 return (self.shell_channel.is_alive() or self.iopub_channel.is_alive() or
244 return (self.shell_channel.is_alive() or self.iopub_channel.is_alive() or
244 self.stdin_channel.is_alive() or self.hb_channel.is_alive())
245 self.stdin_channel.is_alive() or self.hb_channel.is_alive())
245
246
246 @property
247 @property
247 def shell_channel(self):
248 def shell_channel(self):
248 if self._shell_channel is None:
249 if self._shell_channel is None:
249 self._shell_channel = self.shell_channel_class(self)
250 self._shell_channel = self.shell_channel_class(self)
250 return self._shell_channel
251 return self._shell_channel
251
252
252 @property
253 @property
253 def iopub_channel(self):
254 def iopub_channel(self):
254 if self._iopub_channel is None:
255 if self._iopub_channel is None:
255 self._iopub_channel = self.iopub_channel_class(self)
256 self._iopub_channel = self.iopub_channel_class(self)
256 return self._iopub_channel
257 return self._iopub_channel
257
258
258 @property
259 @property
259 def stdin_channel(self):
260 def stdin_channel(self):
260 if self._stdin_channel is None:
261 if self._stdin_channel is None:
261 self._stdin_channel = self.stdin_channel_class(self)
262 self._stdin_channel = self.stdin_channel_class(self)
262 return self._stdin_channel
263 return self._stdin_channel
263
264
264 @property
265 @property
265 def hb_channel(self):
266 def hb_channel(self):
266 if self._hb_channel is None:
267 if self._hb_channel is None:
267 self._hb_channel = self.hb_channel_class(self)
268 self._hb_channel = self.hb_channel_class(self)
268 return self._hb_channel
269 return self._hb_channel
269
270
270 #--------------------------------------------------------------------------
271 #--------------------------------------------------------------------------
271 # Kernel management methods:
272 # Kernel management methods:
272 #--------------------------------------------------------------------------
273 #--------------------------------------------------------------------------
273
274
274 def start_kernel(self, **kwds):
275 def start_kernel(self, **kwds):
275 from IPython.inprocess.ipkernel import InProcessKernel
276 from IPython.kernel.inprocess.ipkernel import InProcessKernel
276 self.kernel = InProcessKernel()
277 self.kernel = InProcessKernel()
277 self.kernel.frontends.append(self)
278 self.kernel.frontends.append(self)
278
279
279 def shutdown_kernel(self):
280 def shutdown_kernel(self):
280 self._kill_kernel()
281 self._kill_kernel()
281
282
282 def restart_kernel(self, now=False, **kwds):
283 def restart_kernel(self, now=False, **kwds):
283 self.shutdown_kernel()
284 self.shutdown_kernel()
284 self.start_kernel(**kwds)
285 self.start_kernel(**kwds)
285
286
286 @property
287 @property
287 def has_kernel(self):
288 def has_kernel(self):
288 return self.kernel is not None
289 return self.kernel is not None
289
290
290 def _kill_kernel(self):
291 def _kill_kernel(self):
291 self.kernel.frontends.remove(self)
292 self.kernel.frontends.remove(self)
292 self.kernel = None
293 self.kernel = None
293
294
294 def interrupt_kernel(self):
295 def interrupt_kernel(self):
295 raise NotImplementedError("Cannot interrupt in-process kernel.")
296 raise NotImplementedError("Cannot interrupt in-process kernel.")
296
297
297 def signal_kernel(self, signum):
298 def signal_kernel(self, signum):
298 raise NotImplementedError("Cannot signal in-process kernel.")
299 raise NotImplementedError("Cannot signal in-process kernel.")
299
300
300 @property
301 @property
301 def is_alive(self):
302 def is_alive(self):
302 return True
303 return True
303
304
304
305
305 #-----------------------------------------------------------------------------
306 #-----------------------------------------------------------------------------
306 # ABC Registration
307 # ABC Registration
307 #-----------------------------------------------------------------------------
308 #-----------------------------------------------------------------------------
308
309
309 ShellChannelABC.register(InProcessShellChannel)
310 ShellChannelABC.register(InProcessShellChannel)
310 IOPubChannelABC.register(InProcessIOPubChannel)
311 IOPubChannelABC.register(InProcessIOPubChannel)
311 HBChannelABC.register(InProcessHBChannel)
312 HBChannelABC.register(InProcessHBChannel)
312 StdInChannelABC.register(InProcessStdInChannel)
313 StdInChannelABC.register(InProcessStdInChannel)
313 KernelManagerABC.register(InProcessKernelManager)
314 KernelManagerABC.register(InProcessKernelManager)
1 NO CONTENT: file renamed from IPython/inprocess/socket.py to IPython/kernel/inprocess/socket.py
NO CONTENT: file renamed from IPython/inprocess/socket.py to IPython/kernel/inprocess/socket.py
1 NO CONTENT: file renamed from IPython/inprocess/tests/__init__.py to IPython/kernel/inprocess/tests/__init__.py
NO CONTENT: file renamed from IPython/inprocess/tests/__init__.py to IPython/kernel/inprocess/tests/__init__.py
@@ -1,89 +1,89 b''
1 #-------------------------------------------------------------------------------
1 #-------------------------------------------------------------------------------
2 # Copyright (C) 2012 The IPython Development Team
2 # Copyright (C) 2012 The IPython Development Team
3 #
3 #
4 # Distributed under the terms of the BSD License. The full license is in
4 # Distributed under the terms of the BSD License. The full license is in
5 # the file COPYING, distributed as part of this software.
5 # the file COPYING, distributed as part of this software.
6 #-------------------------------------------------------------------------------
6 #-------------------------------------------------------------------------------
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 # Standard library imports
13 # Standard library imports
14 from StringIO import StringIO
14 from StringIO import StringIO
15 import sys
15 import sys
16 import unittest
16 import unittest
17
17
18 # Local imports
18 # Local imports
19 from IPython.inprocess.blockingkernelmanager import \
19 from IPython.kernel.inprocess.blockingkernelmanager import \
20 BlockingInProcessKernelManager
20 BlockingInProcessKernelManager
21 from IPython.inprocess.ipkernel import InProcessKernel
21 from IPython.kernel.inprocess.ipkernel import InProcessKernel
22 from IPython.testing.decorators import skipif_not_matplotlib
22 from IPython.testing.decorators import skipif_not_matplotlib
23 from IPython.utils.io import capture_output
23 from IPython.utils.io import capture_output
24 from IPython.utils import py3compat
24 from IPython.utils import py3compat
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Test case
27 # Test case
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class InProcessKernelTestCase(unittest.TestCase):
30 class InProcessKernelTestCase(unittest.TestCase):
31
31
32 @skipif_not_matplotlib
32 @skipif_not_matplotlib
33 def test_pylab(self):
33 def test_pylab(self):
34 """ Does pylab work in the in-process kernel?
34 """ Does pylab work in the in-process kernel?
35 """
35 """
36 km = BlockingInProcessKernelManager()
36 km = BlockingInProcessKernelManager()
37 km.start_kernel()
37 km.start_kernel()
38 km.shell_channel.execute('%pylab')
38 km.shell_channel.execute('%pylab')
39 msg = get_stream_message(km)
39 msg = get_stream_message(km)
40 self.assert_('Welcome to pylab' in msg['content']['data'])
40 self.assert_('Welcome to pylab' in msg['content']['data'])
41
41
42 def test_raw_input(self):
42 def test_raw_input(self):
43 """ Does the in-process kernel handle raw_input correctly?
43 """ Does the in-process kernel handle raw_input correctly?
44 """
44 """
45 km = BlockingInProcessKernelManager()
45 km = BlockingInProcessKernelManager()
46 km.start_kernel()
46 km.start_kernel()
47
47
48 io = StringIO('foobar\n')
48 io = StringIO('foobar\n')
49 sys_stdin = sys.stdin
49 sys_stdin = sys.stdin
50 sys.stdin = io
50 sys.stdin = io
51 try:
51 try:
52 if py3compat.PY3:
52 if py3compat.PY3:
53 km.shell_channel.execute('x = input()')
53 km.shell_channel.execute('x = input()')
54 else:
54 else:
55 km.shell_channel.execute('x = raw_input()')
55 km.shell_channel.execute('x = raw_input()')
56 finally:
56 finally:
57 sys.stdin = sys_stdin
57 sys.stdin = sys_stdin
58 self.assertEqual(km.kernel.shell.user_ns.get('x'), 'foobar')
58 self.assertEqual(km.kernel.shell.user_ns.get('x'), 'foobar')
59
59
60 def test_stdout(self):
60 def test_stdout(self):
61 """ Does the in-process kernel correctly capture IO?
61 """ Does the in-process kernel correctly capture IO?
62 """
62 """
63 kernel = InProcessKernel()
63 kernel = InProcessKernel()
64
64
65 with capture_output() as io:
65 with capture_output() as io:
66 kernel.shell.run_cell('print("foo")')
66 kernel.shell.run_cell('print("foo")')
67 self.assertEqual(io.stdout, 'foo\n')
67 self.assertEqual(io.stdout, 'foo\n')
68
68
69 km = BlockingInProcessKernelManager(kernel=kernel)
69 km = BlockingInProcessKernelManager(kernel=kernel)
70 kernel.frontends.append(km)
70 kernel.frontends.append(km)
71 km.shell_channel.execute('print("bar")')
71 km.shell_channel.execute('print("bar")')
72 msg = get_stream_message(km)
72 msg = get_stream_message(km)
73 self.assertEqual(msg['content']['data'], 'bar\n')
73 self.assertEqual(msg['content']['data'], 'bar\n')
74
74
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76 # Utility functions
76 # Utility functions
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78
78
79 def get_stream_message(kernel_manager, timeout=5):
79 def get_stream_message(kernel_manager, timeout=5):
80 """ Gets a single stream message synchronously from the sub channel.
80 """ Gets a single stream message synchronously from the sub channel.
81 """
81 """
82 while True:
82 while True:
83 msg = kernel_manager.iopub_channel.get_msg(timeout=timeout)
83 msg = kernel_manager.iopub_channel.get_msg(timeout=timeout)
84 if msg['header']['msg_type'] == 'stream':
84 if msg['header']['msg_type'] == 'stream':
85 return msg
85 return msg
86
86
87
87
88 if __name__ == '__main__':
88 if __name__ == '__main__':
89 unittest.main()
89 unittest.main()
@@ -1,102 +1,102 b''
1 #-------------------------------------------------------------------------------
1 #-------------------------------------------------------------------------------
2 # Copyright (C) 2012 The IPython Development Team
2 # Copyright (C) 2012 The IPython Development Team
3 #
3 #
4 # Distributed under the terms of the BSD License. The full license is in
4 # Distributed under the terms of the BSD License. The full license is in
5 # the file COPYING, distributed as part of this software.
5 # the file COPYING, distributed as part of this software.
6 #-------------------------------------------------------------------------------
6 #-------------------------------------------------------------------------------
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 # Standard library imports
13 # Standard library imports
14 import unittest
14 import unittest
15
15
16 # Local imports
16 # Local imports
17 from IPython.inprocess.blockingkernelmanager import \
17 from IPython.kernel.inprocess.blockingkernelmanager import \
18 BlockingInProcessKernelManager
18 BlockingInProcessKernelManager
19 from IPython.inprocess.ipkernel import InProcessKernel
19 from IPython.kernel.inprocess.ipkernel import InProcessKernel
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Test case
22 # Test case
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class InProcessKernelManagerTestCase(unittest.TestCase):
25 class InProcessKernelManagerTestCase(unittest.TestCase):
26
26
27 def test_inteface(self):
27 def test_inteface(self):
28 """ Does the in-process kernel manager implement the basic KM interface?
28 """ Does the in-process kernel manager implement the basic KM interface?
29 """
29 """
30 km = BlockingInProcessKernelManager()
30 km = BlockingInProcessKernelManager()
31 self.assert_(not km.channels_running)
31 self.assert_(not km.channels_running)
32 self.assert_(not km.has_kernel)
32 self.assert_(not km.has_kernel)
33
33
34 km.start_channels()
34 km.start_channels()
35 self.assert_(km.channels_running)
35 self.assert_(km.channels_running)
36
36
37 km.start_kernel()
37 km.start_kernel()
38 self.assert_(km.has_kernel)
38 self.assert_(km.has_kernel)
39 self.assert_(km.kernel is not None)
39 self.assert_(km.kernel is not None)
40
40
41 old_kernel = km.kernel
41 old_kernel = km.kernel
42 km.restart_kernel()
42 km.restart_kernel()
43 self.assert_(km.kernel is not None)
43 self.assert_(km.kernel is not None)
44 self.assertNotEquals(km.kernel, old_kernel)
44 self.assertNotEquals(km.kernel, old_kernel)
45
45
46 km.shutdown_kernel()
46 km.shutdown_kernel()
47 self.assert_(not km.has_kernel)
47 self.assert_(not km.has_kernel)
48
48
49 self.assertRaises(NotImplementedError, km.interrupt_kernel)
49 self.assertRaises(NotImplementedError, km.interrupt_kernel)
50 self.assertRaises(NotImplementedError, km.signal_kernel, 9)
50 self.assertRaises(NotImplementedError, km.signal_kernel, 9)
51
51
52 km.stop_channels()
52 km.stop_channels()
53 self.assert_(not km.channels_running)
53 self.assert_(not km.channels_running)
54
54
55 def test_execute(self):
55 def test_execute(self):
56 """ Does executing code in an in-process kernel work?
56 """ Does executing code in an in-process kernel work?
57 """
57 """
58 km = BlockingInProcessKernelManager()
58 km = BlockingInProcessKernelManager()
59 km.start_kernel()
59 km.start_kernel()
60 km.shell_channel.execute('foo = 1')
60 km.shell_channel.execute('foo = 1')
61 self.assertEquals(km.kernel.shell.user_ns['foo'], 1)
61 self.assertEquals(km.kernel.shell.user_ns['foo'], 1)
62
62
63 def test_complete(self):
63 def test_complete(self):
64 """ Does requesting completion from an in-process kernel work?
64 """ Does requesting completion from an in-process kernel work?
65 """
65 """
66 km = BlockingInProcessKernelManager()
66 km = BlockingInProcessKernelManager()
67 km.start_kernel()
67 km.start_kernel()
68 km.kernel.shell.push({'my_bar': 0, 'my_baz': 1})
68 km.kernel.shell.push({'my_bar': 0, 'my_baz': 1})
69 km.shell_channel.complete('my_ba', 'my_ba', 5)
69 km.shell_channel.complete('my_ba', 'my_ba', 5)
70 msg = km.shell_channel.get_msg()
70 msg = km.shell_channel.get_msg()
71 self.assertEquals(msg['header']['msg_type'], 'complete_reply')
71 self.assertEquals(msg['header']['msg_type'], 'complete_reply')
72 self.assertEquals(sorted(msg['content']['matches']),
72 self.assertEquals(sorted(msg['content']['matches']),
73 ['my_bar', 'my_baz'])
73 ['my_bar', 'my_baz'])
74
74
75 def test_object_info(self):
75 def test_object_info(self):
76 """ Does requesting object information from an in-process kernel work?
76 """ Does requesting object information from an in-process kernel work?
77 """
77 """
78 km = BlockingInProcessKernelManager()
78 km = BlockingInProcessKernelManager()
79 km.start_kernel()
79 km.start_kernel()
80 km.kernel.shell.user_ns['foo'] = 1
80 km.kernel.shell.user_ns['foo'] = 1
81 km.shell_channel.object_info('foo')
81 km.shell_channel.object_info('foo')
82 msg = km.shell_channel.get_msg()
82 msg = km.shell_channel.get_msg()
83 self.assertEquals(msg['header']['msg_type'], 'object_info_reply')
83 self.assertEquals(msg['header']['msg_type'], 'object_info_reply')
84 self.assertEquals(msg['content']['name'], 'foo')
84 self.assertEquals(msg['content']['name'], 'foo')
85 self.assertEquals(msg['content']['type_name'], 'int')
85 self.assertEquals(msg['content']['type_name'], 'int')
86
86
87 def test_history(self):
87 def test_history(self):
88 """ Does requesting history from an in-process kernel work?
88 """ Does requesting history from an in-process kernel work?
89 """
89 """
90 km = BlockingInProcessKernelManager()
90 km = BlockingInProcessKernelManager()
91 km.start_kernel()
91 km.start_kernel()
92 km.shell_channel.execute('%who')
92 km.shell_channel.execute('%who')
93 km.shell_channel.history(hist_access_type='tail', n=1)
93 km.shell_channel.history(hist_access_type='tail', n=1)
94 msg = km.shell_channel.get_msgs()[-1]
94 msg = km.shell_channel.get_msgs()[-1]
95 self.assertEquals(msg['header']['msg_type'], 'history_reply')
95 self.assertEquals(msg['header']['msg_type'], 'history_reply')
96 history = msg['content']['history']
96 history = msg['content']['history']
97 self.assertEquals(len(history), 1)
97 self.assertEquals(len(history), 1)
98 self.assertEquals(history[0][2], '%who')
98 self.assertEquals(history[0][2], '%who')
99
99
100
100
101 if __name__ == '__main__':
101 if __name__ == '__main__':
102 unittest.main()
102 unittest.main()
1 NO CONTENT: file renamed from IPython/kernel/zmq/tests/test_kernelmanager.py to IPython/kernel/tests/test_kernelmanager.py
NO CONTENT: file renamed from IPython/kernel/zmq/tests/test_kernelmanager.py to IPython/kernel/tests/test_kernelmanager.py
@@ -1,70 +1,70 b''
1 """Publishing
1 """Publishing
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.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.zmq.serialize import serialize_object
20 from IPython.kernel.zmq.session import Session, extract_header
20 from IPython.kernel.zmq.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)
30 session = Instance(Session)
31 pub_socket = Instance(SocketABC)
31 pub_socket = Instance(SocketABC)
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.zmq.zmqshell import ZMQInteractiveShell
70 ZMQInteractiveShell.instance().data_pub.publish_data(data)
70 ZMQInteractiveShell.instance().data_pub.publish_data(data)
@@ -1,64 +1,64 b''
1 import __builtin__
1 import __builtin__
2 import sys
2 import sys
3
3
4 from IPython.core.displayhook import DisplayHook
4 from IPython.core.displayhook import DisplayHook
5 from IPython.inprocess.socket import SocketABC
5 from IPython.kernel.inprocess.socket import SocketABC
6 from IPython.utils.jsonutil import encode_images
6 from IPython.utils.jsonutil import encode_images
7 from IPython.utils.traitlets import Instance, Dict
7 from IPython.utils.traitlets import Instance, Dict
8 from session import extract_header, Session
8 from session import extract_header, Session
9
9
10 class ZMQDisplayHook(object):
10 class ZMQDisplayHook(object):
11 """A simple displayhook that publishes the object's repr over a ZeroMQ
11 """A simple displayhook that publishes the object's repr over a ZeroMQ
12 socket."""
12 socket."""
13 topic=None
13 topic=None
14
14
15 def __init__(self, session, pub_socket):
15 def __init__(self, session, pub_socket):
16 self.session = session
16 self.session = session
17 self.pub_socket = pub_socket
17 self.pub_socket = pub_socket
18 self.parent_header = {}
18 self.parent_header = {}
19
19
20 def __call__(self, obj):
20 def __call__(self, obj):
21 if obj is None:
21 if obj is None:
22 return
22 return
23
23
24 __builtin__._ = obj
24 __builtin__._ = obj
25 sys.stdout.flush()
25 sys.stdout.flush()
26 sys.stderr.flush()
26 sys.stderr.flush()
27 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
27 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
28 parent=self.parent_header, ident=self.topic)
28 parent=self.parent_header, ident=self.topic)
29
29
30 def set_parent(self, parent):
30 def set_parent(self, parent):
31 self.parent_header = extract_header(parent)
31 self.parent_header = extract_header(parent)
32
32
33
33
34 class ZMQShellDisplayHook(DisplayHook):
34 class ZMQShellDisplayHook(DisplayHook):
35 """A displayhook subclass that publishes data using ZeroMQ. This is intended
35 """A displayhook subclass that publishes data using ZeroMQ. This is intended
36 to work with an InteractiveShell instance. It sends a dict of different
36 to work with an InteractiveShell instance. It sends a dict of different
37 representations of the object."""
37 representations of the object."""
38 topic=None
38 topic=None
39
39
40 session = Instance(Session)
40 session = Instance(Session)
41 pub_socket = Instance(SocketABC)
41 pub_socket = Instance(SocketABC)
42 parent_header = Dict({})
42 parent_header = Dict({})
43
43
44 def set_parent(self, parent):
44 def set_parent(self, parent):
45 """Set the parent for outbound messages."""
45 """Set the parent for outbound messages."""
46 self.parent_header = extract_header(parent)
46 self.parent_header = extract_header(parent)
47
47
48 def start_displayhook(self):
48 def start_displayhook(self):
49 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
49 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
50
50
51 def write_output_prompt(self):
51 def write_output_prompt(self):
52 """Write the output prompt."""
52 """Write the output prompt."""
53 self.msg['content']['execution_count'] = self.prompt_count
53 self.msg['content']['execution_count'] = self.prompt_count
54
54
55 def write_format_data(self, format_dict):
55 def write_format_data(self, format_dict):
56 self.msg['content']['data'] = encode_images(format_dict)
56 self.msg['content']['data'] = encode_images(format_dict)
57
57
58 def finish_displayhook(self):
58 def finish_displayhook(self):
59 """Finish up all displayhook activities."""
59 """Finish up all displayhook activities."""
60 sys.stdout.flush()
60 sys.stdout.flush()
61 sys.stderr.flush()
61 sys.stderr.flush()
62 self.session.send(self.pub_socket, self.msg, ident=self.topic)
62 self.session.send(self.pub_socket, self.msg, ident=self.topic)
63 self.msg = None
63 self.msg = None
64
64
@@ -1,591 +1,591 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 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import os
19 import os
20 import sys
20 import sys
21 import time
21 import time
22
22
23 # System library imports
23 # System library imports
24 from zmq.eventloop import ioloop
24 from zmq.eventloop import ioloop
25
25
26 # Our own
26 # Our own
27 from IPython.core.interactiveshell import (
27 from IPython.core.interactiveshell import (
28 InteractiveShell, InteractiveShellABC
28 InteractiveShell, InteractiveShellABC
29 )
29 )
30 from IPython.core import page
30 from IPython.core import page
31 from IPython.core.autocall import ZMQExitAutocall
31 from IPython.core.autocall import ZMQExitAutocall
32 from IPython.core.displaypub import DisplayPublisher
32 from IPython.core.displaypub import DisplayPublisher
33 from IPython.core.error import UsageError
33 from IPython.core.error import UsageError
34 from IPython.core.magics import MacroToEdit, CodeMagics
34 from IPython.core.magics import MacroToEdit, CodeMagics
35 from IPython.core.magic import magics_class, line_magic, Magics
35 from IPython.core.magic import magics_class, line_magic, Magics
36 from IPython.core.payloadpage import install_payload_page
36 from IPython.core.payloadpage import install_payload_page
37 from IPython.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 io, openpy
42 from IPython.utils import io, 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.traitlets import Instance, Type, Dict, CBool, CBytes
46 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
47 from IPython.utils.warn import warn, error
47 from IPython.utils.warn import warn, error
48 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
48 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
49 from IPython.kernel.zmq.datapub import ZMQDataPublisher
49 from IPython.kernel.zmq.datapub import ZMQDataPublisher
50 from IPython.kernel.zmq.session import extract_header
50 from IPython.kernel.zmq.session import extract_header
51 from session import Session
51 from session import Session
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Functions and classes
54 # Functions and classes
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 class ZMQDisplayPublisher(DisplayPublisher):
57 class ZMQDisplayPublisher(DisplayPublisher):
58 """A display publisher that publishes data using a ZeroMQ PUB socket."""
58 """A display publisher that publishes data using a ZeroMQ PUB socket."""
59
59
60 session = Instance(Session)
60 session = Instance(Session)
61 pub_socket = Instance(SocketABC)
61 pub_socket = Instance(SocketABC)
62 parent_header = Dict({})
62 parent_header = Dict({})
63 topic = CBytes(b'displaypub')
63 topic = CBytes(b'displaypub')
64
64
65 def set_parent(self, parent):
65 def set_parent(self, parent):
66 """Set the parent for outbound messages."""
66 """Set the parent for outbound messages."""
67 self.parent_header = extract_header(parent)
67 self.parent_header = extract_header(parent)
68
68
69 def _flush_streams(self):
69 def _flush_streams(self):
70 """flush IO Streams prior to display"""
70 """flush IO Streams prior to display"""
71 sys.stdout.flush()
71 sys.stdout.flush()
72 sys.stderr.flush()
72 sys.stderr.flush()
73
73
74 def publish(self, source, data, metadata=None):
74 def publish(self, source, data, metadata=None):
75 self._flush_streams()
75 self._flush_streams()
76 if metadata is None:
76 if metadata is None:
77 metadata = {}
77 metadata = {}
78 self._validate_data(source, data, metadata)
78 self._validate_data(source, data, metadata)
79 content = {}
79 content = {}
80 content['source'] = source
80 content['source'] = source
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, stdout=True, stderr=True, other=True):
88 def clear_output(self, stdout=True, stderr=True, other=True):
89 content = dict(stdout=stdout, stderr=stderr, other=other)
89 content = dict(stdout=stdout, stderr=stderr, other=other)
90
90
91 if stdout:
91 if stdout:
92 print('\r', file=sys.stdout, end='')
92 print('\r', file=sys.stdout, end='')
93 if stderr:
93 if stderr:
94 print('\r', file=sys.stderr, end='')
94 print('\r', file=sys.stderr, end='')
95
95
96 self._flush_streams()
96 self._flush_streams()
97
97
98 self.session.send(
98 self.session.send(
99 self.pub_socket, u'clear_output', content,
99 self.pub_socket, u'clear_output', content,
100 parent=self.parent_header, ident=self.topic,
100 parent=self.parent_header, ident=self.topic,
101 )
101 )
102
102
103 @magics_class
103 @magics_class
104 class KernelMagics(Magics):
104 class KernelMagics(Magics):
105 #------------------------------------------------------------------------
105 #------------------------------------------------------------------------
106 # Magic overrides
106 # Magic overrides
107 #------------------------------------------------------------------------
107 #------------------------------------------------------------------------
108 # Once the base class stops inheriting from magic, this code needs to be
108 # Once the base class stops inheriting from magic, this code needs to be
109 # moved into a separate machinery as well. For now, at least isolate here
109 # moved into a separate machinery as well. For now, at least isolate here
110 # the magics which this class needs to implement differently from the base
110 # the magics which this class needs to implement differently from the base
111 # class, or that are unique to it.
111 # class, or that are unique to it.
112
112
113 @line_magic
113 @line_magic
114 def doctest_mode(self, parameter_s=''):
114 def doctest_mode(self, parameter_s=''):
115 """Toggle doctest mode on and off.
115 """Toggle doctest mode on and off.
116
116
117 This mode is intended to make IPython behave as much as possible like a
117 This mode is intended to make IPython behave as much as possible like a
118 plain Python shell, from the perspective of how its prompts, exceptions
118 plain Python shell, from the perspective of how its prompts, exceptions
119 and output look. This makes it easy to copy and paste parts of a
119 and output look. This makes it easy to copy and paste parts of a
120 session into doctests. It does so by:
120 session into doctests. It does so by:
121
121
122 - Changing the prompts to the classic ``>>>`` ones.
122 - Changing the prompts to the classic ``>>>`` ones.
123 - Changing the exception reporting mode to 'Plain'.
123 - Changing the exception reporting mode to 'Plain'.
124 - Disabling pretty-printing of output.
124 - Disabling pretty-printing of output.
125
125
126 Note that IPython also supports the pasting of code snippets that have
126 Note that IPython also supports the pasting of code snippets that have
127 leading '>>>' and '...' prompts in them. This means that you can paste
127 leading '>>>' and '...' prompts in them. This means that you can paste
128 doctests from files or docstrings (even if they have leading
128 doctests from files or docstrings (even if they have leading
129 whitespace), and the code will execute correctly. You can then use
129 whitespace), and the code will execute correctly. You can then use
130 '%history -t' to see the translated history; this will give you the
130 '%history -t' to see the translated history; this will give you the
131 input after removal of all the leading prompts and whitespace, which
131 input after removal of all the leading prompts and whitespace, which
132 can be pasted back into an editor.
132 can be pasted back into an editor.
133
133
134 With these features, you can switch into this mode easily whenever you
134 With these features, you can switch into this mode easily whenever you
135 need to do testing and changes to doctests, without having to leave
135 need to do testing and changes to doctests, without having to leave
136 your existing IPython session.
136 your existing IPython session.
137 """
137 """
138
138
139 from IPython.utils.ipstruct import Struct
139 from IPython.utils.ipstruct import Struct
140
140
141 # Shorthands
141 # Shorthands
142 shell = self.shell
142 shell = self.shell
143 disp_formatter = self.shell.display_formatter
143 disp_formatter = self.shell.display_formatter
144 ptformatter = disp_formatter.formatters['text/plain']
144 ptformatter = disp_formatter.formatters['text/plain']
145 # dstore is a data store kept in the instance metadata bag to track any
145 # dstore is a data store kept in the instance metadata bag to track any
146 # changes we make, so we can undo them later.
146 # changes we make, so we can undo them later.
147 dstore = shell.meta.setdefault('doctest_mode', Struct())
147 dstore = shell.meta.setdefault('doctest_mode', Struct())
148 save_dstore = dstore.setdefault
148 save_dstore = dstore.setdefault
149
149
150 # save a few values we'll need to recover later
150 # save a few values we'll need to recover later
151 mode = save_dstore('mode', False)
151 mode = save_dstore('mode', False)
152 save_dstore('rc_pprint', ptformatter.pprint)
152 save_dstore('rc_pprint', ptformatter.pprint)
153 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
153 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
154 save_dstore('xmode', shell.InteractiveTB.mode)
154 save_dstore('xmode', shell.InteractiveTB.mode)
155
155
156 if mode == False:
156 if mode == False:
157 # turn on
157 # turn on
158 ptformatter.pprint = False
158 ptformatter.pprint = False
159 disp_formatter.plain_text_only = True
159 disp_formatter.plain_text_only = True
160 shell.magic('xmode Plain')
160 shell.magic('xmode Plain')
161 else:
161 else:
162 # turn off
162 # turn off
163 ptformatter.pprint = dstore.rc_pprint
163 ptformatter.pprint = dstore.rc_pprint
164 disp_formatter.plain_text_only = dstore.rc_plain_text_only
164 disp_formatter.plain_text_only = dstore.rc_plain_text_only
165 shell.magic("xmode " + dstore.xmode)
165 shell.magic("xmode " + dstore.xmode)
166
166
167 # Store new mode and inform on console
167 # Store new mode and inform on console
168 dstore.mode = bool(1-int(mode))
168 dstore.mode = bool(1-int(mode))
169 mode_label = ['OFF','ON'][dstore.mode]
169 mode_label = ['OFF','ON'][dstore.mode]
170 print('Doctest mode is:', mode_label)
170 print('Doctest mode is:', mode_label)
171
171
172 # Send the payload back so that clients can modify their prompt display
172 # Send the payload back so that clients can modify their prompt display
173 payload = dict(
173 payload = dict(
174 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.doctest_mode',
174 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.doctest_mode',
175 mode=dstore.mode)
175 mode=dstore.mode)
176 shell.payload_manager.write_payload(payload)
176 shell.payload_manager.write_payload(payload)
177
177
178
178
179 _find_edit_target = CodeMagics._find_edit_target
179 _find_edit_target = CodeMagics._find_edit_target
180
180
181 @skip_doctest
181 @skip_doctest
182 @line_magic
182 @line_magic
183 def edit(self, parameter_s='', last_call=['','']):
183 def edit(self, parameter_s='', last_call=['','']):
184 """Bring up an editor and execute the resulting code.
184 """Bring up an editor and execute the resulting code.
185
185
186 Usage:
186 Usage:
187 %edit [options] [args]
187 %edit [options] [args]
188
188
189 %edit runs an external text editor. You will need to set the command for
189 %edit runs an external text editor. You will need to set the command for
190 this editor via the ``TerminalInteractiveShell.editor`` option in your
190 this editor via the ``TerminalInteractiveShell.editor`` option in your
191 configuration file before it will work.
191 configuration file before it will work.
192
192
193 This command allows you to conveniently edit multi-line code right in
193 This command allows you to conveniently edit multi-line code right in
194 your IPython session.
194 your IPython session.
195
195
196 If called without arguments, %edit opens up an empty editor with a
196 If called without arguments, %edit opens up an empty editor with a
197 temporary file and will execute the contents of this file when you
197 temporary file and will execute the contents of this file when you
198 close it (don't forget to save it!).
198 close it (don't forget to save it!).
199
199
200
200
201 Options:
201 Options:
202
202
203 -n <number>: open the editor at a specified line number. By default,
203 -n <number>: open the editor at a specified line number. By default,
204 the IPython editor hook uses the unix syntax 'editor +N filename', but
204 the IPython editor hook uses the unix syntax 'editor +N filename', but
205 you can configure this by providing your own modified hook if your
205 you can configure this by providing your own modified hook if your
206 favorite editor supports line-number specifications with a different
206 favorite editor supports line-number specifications with a different
207 syntax.
207 syntax.
208
208
209 -p: this will call the editor with the same data as the previous time
209 -p: this will call the editor with the same data as the previous time
210 it was used, regardless of how long ago (in your current session) it
210 it was used, regardless of how long ago (in your current session) it
211 was.
211 was.
212
212
213 -r: use 'raw' input. This option only applies to input taken from the
213 -r: use 'raw' input. This option only applies to input taken from the
214 user's history. By default, the 'processed' history is used, so that
214 user's history. By default, the 'processed' history is used, so that
215 magics are loaded in their transformed version to valid Python. If
215 magics are loaded in their transformed version to valid Python. If
216 this option is given, the raw input as typed as the command line is
216 this option is given, the raw input as typed as the command line is
217 used instead. When you exit the editor, it will be executed by
217 used instead. When you exit the editor, it will be executed by
218 IPython's own processor.
218 IPython's own processor.
219
219
220 -x: do not execute the edited code immediately upon exit. This is
220 -x: do not execute the edited code immediately upon exit. This is
221 mainly useful if you are editing programs which need to be called with
221 mainly useful if you are editing programs which need to be called with
222 command line arguments, which you can then do using %run.
222 command line arguments, which you can then do using %run.
223
223
224
224
225 Arguments:
225 Arguments:
226
226
227 If arguments are given, the following possibilites exist:
227 If arguments are given, the following possibilites exist:
228
228
229 - The arguments are numbers or pairs of colon-separated numbers (like
229 - The arguments are numbers or pairs of colon-separated numbers (like
230 1 4:8 9). These are interpreted as lines of previous input to be
230 1 4:8 9). These are interpreted as lines of previous input to be
231 loaded into the editor. The syntax is the same of the %macro command.
231 loaded into the editor. The syntax is the same of the %macro command.
232
232
233 - If the argument doesn't start with a number, it is evaluated as a
233 - If the argument doesn't start with a number, it is evaluated as a
234 variable and its contents loaded into the editor. You can thus edit
234 variable and its contents loaded into the editor. You can thus edit
235 any string which contains python code (including the result of
235 any string which contains python code (including the result of
236 previous edits).
236 previous edits).
237
237
238 - If the argument is the name of an object (other than a string),
238 - If the argument is the name of an object (other than a string),
239 IPython will try to locate the file where it was defined and open the
239 IPython will try to locate the file where it was defined and open the
240 editor at the point where it is defined. You can use `%edit function`
240 editor at the point where it is defined. You can use `%edit function`
241 to load an editor exactly at the point where 'function' is defined,
241 to load an editor exactly at the point where 'function' is defined,
242 edit it and have the file be executed automatically.
242 edit it and have the file be executed automatically.
243
243
244 If the object is a macro (see %macro for details), this opens up your
244 If the object is a macro (see %macro for details), this opens up your
245 specified editor with a temporary file containing the macro's data.
245 specified editor with a temporary file containing the macro's data.
246 Upon exit, the macro is reloaded with the contents of the file.
246 Upon exit, the macro is reloaded with the contents of the file.
247
247
248 Note: opening at an exact line is only supported under Unix, and some
248 Note: opening at an exact line is only supported under Unix, and some
249 editors (like kedit and gedit up to Gnome 2.8) do not understand the
249 editors (like kedit and gedit up to Gnome 2.8) do not understand the
250 '+NUMBER' parameter necessary for this feature. Good editors like
250 '+NUMBER' parameter necessary for this feature. Good editors like
251 (X)Emacs, vi, jed, pico and joe all do.
251 (X)Emacs, vi, jed, pico and joe all do.
252
252
253 - If the argument is not found as a variable, IPython will look for a
253 - If the argument is not found as a variable, IPython will look for a
254 file with that name (adding .py if necessary) and load it into the
254 file with that name (adding .py if necessary) and load it into the
255 editor. It will execute its contents with execfile() when you exit,
255 editor. It will execute its contents with execfile() when you exit,
256 loading any code in the file into your interactive namespace.
256 loading any code in the file into your interactive namespace.
257
257
258 After executing your code, %edit will return as output the code you
258 After executing your code, %edit will return as output the code you
259 typed in the editor (except when it was an existing file). This way
259 typed in the editor (except when it was an existing file). This way
260 you can reload the code in further invocations of %edit as a variable,
260 you can reload the code in further invocations of %edit as a variable,
261 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
261 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
262 the output.
262 the output.
263
263
264 Note that %edit is also available through the alias %ed.
264 Note that %edit is also available through the alias %ed.
265
265
266 This is an example of creating a simple function inside the editor and
266 This is an example of creating a simple function inside the editor and
267 then modifying it. First, start up the editor:
267 then modifying it. First, start up the editor:
268
268
269 In [1]: ed
269 In [1]: ed
270 Editing... done. Executing edited code...
270 Editing... done. Executing edited code...
271 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
271 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
272
272
273 We can then call the function foo():
273 We can then call the function foo():
274
274
275 In [2]: foo()
275 In [2]: foo()
276 foo() was defined in an editing session
276 foo() was defined in an editing session
277
277
278 Now we edit foo. IPython automatically loads the editor with the
278 Now we edit foo. IPython automatically loads the editor with the
279 (temporary) file where foo() was previously defined:
279 (temporary) file where foo() was previously defined:
280
280
281 In [3]: ed foo
281 In [3]: ed foo
282 Editing... done. Executing edited code...
282 Editing... done. Executing edited code...
283
283
284 And if we call foo() again we get the modified version:
284 And if we call foo() again we get the modified version:
285
285
286 In [4]: foo()
286 In [4]: foo()
287 foo() has now been changed!
287 foo() has now been changed!
288
288
289 Here is an example of how to edit a code snippet successive
289 Here is an example of how to edit a code snippet successive
290 times. First we call the editor:
290 times. First we call the editor:
291
291
292 In [5]: ed
292 In [5]: ed
293 Editing... done. Executing edited code...
293 Editing... done. Executing edited code...
294 hello
294 hello
295 Out[5]: "print 'hello'n"
295 Out[5]: "print 'hello'n"
296
296
297 Now we call it again with the previous output (stored in _):
297 Now we call it again with the previous output (stored in _):
298
298
299 In [6]: ed _
299 In [6]: ed _
300 Editing... done. Executing edited code...
300 Editing... done. Executing edited code...
301 hello world
301 hello world
302 Out[6]: "print 'hello world'n"
302 Out[6]: "print 'hello world'n"
303
303
304 Now we call it with the output #8 (stored in _8, also as Out[8]):
304 Now we call it with the output #8 (stored in _8, also as Out[8]):
305
305
306 In [7]: ed _8
306 In [7]: ed _8
307 Editing... done. Executing edited code...
307 Editing... done. Executing edited code...
308 hello again
308 hello again
309 Out[7]: "print 'hello again'n"
309 Out[7]: "print 'hello again'n"
310 """
310 """
311
311
312 opts,args = self.parse_options(parameter_s,'prn:')
312 opts,args = self.parse_options(parameter_s,'prn:')
313
313
314 try:
314 try:
315 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
315 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
316 except MacroToEdit as e:
316 except MacroToEdit as e:
317 # TODO: Implement macro editing over 2 processes.
317 # TODO: Implement macro editing over 2 processes.
318 print("Macro editing not yet implemented in 2-process model.")
318 print("Macro editing not yet implemented in 2-process model.")
319 return
319 return
320
320
321 # Make sure we send to the client an absolute path, in case the working
321 # Make sure we send to the client an absolute path, in case the working
322 # directory of client and kernel don't match
322 # directory of client and kernel don't match
323 filename = os.path.abspath(filename)
323 filename = os.path.abspath(filename)
324
324
325 payload = {
325 payload = {
326 'source' : 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
326 'source' : 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
327 'filename' : filename,
327 'filename' : filename,
328 'line_number' : lineno
328 'line_number' : lineno
329 }
329 }
330 self.shell.payload_manager.write_payload(payload)
330 self.shell.payload_manager.write_payload(payload)
331
331
332 # A few magics that are adapted to the specifics of using pexpect and a
332 # A few magics that are adapted to the specifics of using pexpect and a
333 # remote terminal
333 # remote terminal
334
334
335 @line_magic
335 @line_magic
336 def clear(self, arg_s):
336 def clear(self, arg_s):
337 """Clear the terminal."""
337 """Clear the terminal."""
338 if os.name == 'posix':
338 if os.name == 'posix':
339 self.shell.system("clear")
339 self.shell.system("clear")
340 else:
340 else:
341 self.shell.system("cls")
341 self.shell.system("cls")
342
342
343 if os.name == 'nt':
343 if os.name == 'nt':
344 # This is the usual name in windows
344 # This is the usual name in windows
345 cls = line_magic('cls')(clear)
345 cls = line_magic('cls')(clear)
346
346
347 # Terminal pagers won't work over pexpect, but we do have our own pager
347 # Terminal pagers won't work over pexpect, but we do have our own pager
348
348
349 @line_magic
349 @line_magic
350 def less(self, arg_s):
350 def less(self, arg_s):
351 """Show a file through the pager.
351 """Show a file through the pager.
352
352
353 Files ending in .py are syntax-highlighted."""
353 Files ending in .py are syntax-highlighted."""
354 if not arg_s:
354 if not arg_s:
355 raise UsageError('Missing filename.')
355 raise UsageError('Missing filename.')
356
356
357 cont = open(arg_s).read()
357 cont = open(arg_s).read()
358 if arg_s.endswith('.py'):
358 if arg_s.endswith('.py'):
359 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
359 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
360 else:
360 else:
361 cont = open(arg_s).read()
361 cont = open(arg_s).read()
362 page.page(cont)
362 page.page(cont)
363
363
364 more = line_magic('more')(less)
364 more = line_magic('more')(less)
365
365
366 # Man calls a pager, so we also need to redefine it
366 # Man calls a pager, so we also need to redefine it
367 if os.name == 'posix':
367 if os.name == 'posix':
368 @line_magic
368 @line_magic
369 def man(self, arg_s):
369 def man(self, arg_s):
370 """Find the man page for the given command and display in pager."""
370 """Find the man page for the given command and display in pager."""
371 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
371 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
372 split=False))
372 split=False))
373
373
374 @line_magic
374 @line_magic
375 def connect_info(self, arg_s):
375 def connect_info(self, arg_s):
376 """Print information for connecting other clients to this kernel
376 """Print information for connecting other clients to this kernel
377
377
378 It will print the contents of this session's connection file, as well as
378 It will print the contents of this session's connection file, as well as
379 shortcuts for local clients.
379 shortcuts for local clients.
380
380
381 In the simplest case, when called from the most recently launched kernel,
381 In the simplest case, when called from the most recently launched kernel,
382 secondary clients can be connected, simply with:
382 secondary clients can be connected, simply with:
383
383
384 $> ipython <app> --existing
384 $> ipython <app> --existing
385
385
386 """
386 """
387
387
388 from IPython.core.application import BaseIPythonApplication as BaseIPApp
388 from IPython.core.application import BaseIPythonApplication as BaseIPApp
389
389
390 if BaseIPApp.initialized():
390 if BaseIPApp.initialized():
391 app = BaseIPApp.instance()
391 app = BaseIPApp.instance()
392 security_dir = app.profile_dir.security_dir
392 security_dir = app.profile_dir.security_dir
393 profile = app.profile
393 profile = app.profile
394 else:
394 else:
395 profile = 'default'
395 profile = 'default'
396 security_dir = ''
396 security_dir = ''
397
397
398 try:
398 try:
399 connection_file = get_connection_file()
399 connection_file = get_connection_file()
400 info = get_connection_info(unpack=False)
400 info = get_connection_info(unpack=False)
401 except Exception as e:
401 except Exception as e:
402 error("Could not get connection info: %r" % e)
402 error("Could not get connection info: %r" % e)
403 return
403 return
404
404
405 # add profile flag for non-default profile
405 # add profile flag for non-default profile
406 profile_flag = "--profile %s" % profile if profile != 'default' else ""
406 profile_flag = "--profile %s" % profile if profile != 'default' else ""
407
407
408 # if it's in the security dir, truncate to basename
408 # if it's in the security dir, truncate to basename
409 if security_dir == os.path.dirname(connection_file):
409 if security_dir == os.path.dirname(connection_file):
410 connection_file = os.path.basename(connection_file)
410 connection_file = os.path.basename(connection_file)
411
411
412
412
413 print (info + '\n')
413 print (info + '\n')
414 print ("Paste the above JSON into a file, and connect with:\n"
414 print ("Paste the above JSON into a file, and connect with:\n"
415 " $> ipython <app> --existing <file>\n"
415 " $> ipython <app> --existing <file>\n"
416 "or, if you are local, you can connect with just:\n"
416 "or, if you are local, you can connect with just:\n"
417 " $> ipython <app> --existing {0} {1}\n"
417 " $> ipython <app> --existing {0} {1}\n"
418 "or even just:\n"
418 "or even just:\n"
419 " $> ipython <app> --existing {1}\n"
419 " $> ipython <app> --existing {1}\n"
420 "if this is the most recent IPython session you have started.".format(
420 "if this is the most recent IPython session you have started.".format(
421 connection_file, profile_flag
421 connection_file, profile_flag
422 )
422 )
423 )
423 )
424
424
425 @line_magic
425 @line_magic
426 def qtconsole(self, arg_s):
426 def qtconsole(self, arg_s):
427 """Open a qtconsole connected to this kernel.
427 """Open a qtconsole connected to this kernel.
428
428
429 Useful for connecting a qtconsole to running notebooks, for better
429 Useful for connecting a qtconsole to running notebooks, for better
430 debugging.
430 debugging.
431 """
431 """
432
432
433 # %qtconsole should imply bind_kernel for engines:
433 # %qtconsole should imply bind_kernel for engines:
434 try:
434 try:
435 from IPython.parallel import bind_kernel
435 from IPython.parallel import bind_kernel
436 except ImportError:
436 except ImportError:
437 # technically possible, because parallel has higher pyzmq min-version
437 # technically possible, because parallel has higher pyzmq min-version
438 pass
438 pass
439 else:
439 else:
440 bind_kernel()
440 bind_kernel()
441
441
442 try:
442 try:
443 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
443 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
444 except Exception as e:
444 except Exception as e:
445 error("Could not start qtconsole: %r" % e)
445 error("Could not start qtconsole: %r" % e)
446 return
446 return
447
447
448 def safe_unicode(e):
448 def safe_unicode(e):
449 """unicode(e) with various fallbacks. Used for exceptions, which may not be
449 """unicode(e) with various fallbacks. Used for exceptions, which may not be
450 safe to call unicode() on.
450 safe to call unicode() on.
451 """
451 """
452 try:
452 try:
453 return unicode(e)
453 return unicode(e)
454 except UnicodeError:
454 except UnicodeError:
455 pass
455 pass
456
456
457 try:
457 try:
458 return py3compat.str_to_unicode(str(e))
458 return py3compat.str_to_unicode(str(e))
459 except UnicodeError:
459 except UnicodeError:
460 pass
460 pass
461
461
462 try:
462 try:
463 return py3compat.str_to_unicode(repr(e))
463 return py3compat.str_to_unicode(repr(e))
464 except UnicodeError:
464 except UnicodeError:
465 pass
465 pass
466
466
467 return u'Unrecoverably corrupt evalue'
467 return u'Unrecoverably corrupt evalue'
468
468
469
469
470 class ZMQInteractiveShell(InteractiveShell):
470 class ZMQInteractiveShell(InteractiveShell):
471 """A subclass of InteractiveShell for ZMQ."""
471 """A subclass of InteractiveShell for ZMQ."""
472
472
473 displayhook_class = Type(ZMQShellDisplayHook)
473 displayhook_class = Type(ZMQShellDisplayHook)
474 display_pub_class = Type(ZMQDisplayPublisher)
474 display_pub_class = Type(ZMQDisplayPublisher)
475 data_pub_class = Type(ZMQDataPublisher)
475 data_pub_class = Type(ZMQDataPublisher)
476
476
477 # Override the traitlet in the parent class, because there's no point using
477 # Override the traitlet in the parent class, because there's no point using
478 # readline for the kernel. Can be removed when the readline code is moved
478 # readline for the kernel. Can be removed when the readline code is moved
479 # to the terminal frontend.
479 # to the terminal frontend.
480 colors_force = CBool(True)
480 colors_force = CBool(True)
481 readline_use = CBool(False)
481 readline_use = CBool(False)
482 # autoindent has no meaning in a zmqshell, and attempting to enable it
482 # autoindent has no meaning in a zmqshell, and attempting to enable it
483 # will print a warning in the absence of readline.
483 # will print a warning in the absence of readline.
484 autoindent = CBool(False)
484 autoindent = CBool(False)
485
485
486 exiter = Instance(ZMQExitAutocall)
486 exiter = Instance(ZMQExitAutocall)
487 def _exiter_default(self):
487 def _exiter_default(self):
488 return ZMQExitAutocall(self)
488 return ZMQExitAutocall(self)
489
489
490 def _exit_now_changed(self, name, old, new):
490 def _exit_now_changed(self, name, old, new):
491 """stop eventloop when exit_now fires"""
491 """stop eventloop when exit_now fires"""
492 if new:
492 if new:
493 loop = ioloop.IOLoop.instance()
493 loop = ioloop.IOLoop.instance()
494 loop.add_timeout(time.time()+0.1, loop.stop)
494 loop.add_timeout(time.time()+0.1, loop.stop)
495
495
496 keepkernel_on_exit = None
496 keepkernel_on_exit = None
497
497
498 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
498 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
499 # interactive input being read; we provide event loop support in ipkernel
499 # interactive input being read; we provide event loop support in ipkernel
500 from .eventloops import enable_gui
500 from .eventloops import enable_gui
501 enable_gui = staticmethod(enable_gui)
501 enable_gui = staticmethod(enable_gui)
502
502
503 def init_environment(self):
503 def init_environment(self):
504 """Configure the user's environment.
504 """Configure the user's environment.
505
505
506 """
506 """
507 env = os.environ
507 env = os.environ
508 # These two ensure 'ls' produces nice coloring on BSD-derived systems
508 # These two ensure 'ls' produces nice coloring on BSD-derived systems
509 env['TERM'] = 'xterm-color'
509 env['TERM'] = 'xterm-color'
510 env['CLICOLOR'] = '1'
510 env['CLICOLOR'] = '1'
511 # Since normal pagers don't work at all (over pexpect we don't have
511 # Since normal pagers don't work at all (over pexpect we don't have
512 # single-key control of the subprocess), try to disable paging in
512 # single-key control of the subprocess), try to disable paging in
513 # subprocesses as much as possible.
513 # subprocesses as much as possible.
514 env['PAGER'] = 'cat'
514 env['PAGER'] = 'cat'
515 env['GIT_PAGER'] = 'cat'
515 env['GIT_PAGER'] = 'cat'
516
516
517 # And install the payload version of page.
517 # And install the payload version of page.
518 install_payload_page()
518 install_payload_page()
519
519
520 def auto_rewrite_input(self, cmd):
520 def auto_rewrite_input(self, cmd):
521 """Called to show the auto-rewritten input for autocall and friends.
521 """Called to show the auto-rewritten input for autocall and friends.
522
522
523 FIXME: this payload is currently not correctly processed by the
523 FIXME: this payload is currently not correctly processed by the
524 frontend.
524 frontend.
525 """
525 """
526 new = self.prompt_manager.render('rewrite') + cmd
526 new = self.prompt_manager.render('rewrite') + cmd
527 payload = dict(
527 payload = dict(
528 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
528 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
529 transformed_input=new,
529 transformed_input=new,
530 )
530 )
531 self.payload_manager.write_payload(payload)
531 self.payload_manager.write_payload(payload)
532
532
533 def ask_exit(self):
533 def ask_exit(self):
534 """Engage the exit actions."""
534 """Engage the exit actions."""
535 self.exit_now = True
535 self.exit_now = True
536 payload = dict(
536 payload = dict(
537 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
537 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
538 exit=True,
538 exit=True,
539 keepkernel=self.keepkernel_on_exit,
539 keepkernel=self.keepkernel_on_exit,
540 )
540 )
541 self.payload_manager.write_payload(payload)
541 self.payload_manager.write_payload(payload)
542
542
543 def _showtraceback(self, etype, evalue, stb):
543 def _showtraceback(self, etype, evalue, stb):
544
544
545 exc_content = {
545 exc_content = {
546 u'traceback' : stb,
546 u'traceback' : stb,
547 u'ename' : unicode(etype.__name__),
547 u'ename' : unicode(etype.__name__),
548 u'evalue' : safe_unicode(evalue)
548 u'evalue' : safe_unicode(evalue)
549 }
549 }
550
550
551 dh = self.displayhook
551 dh = self.displayhook
552 # Send exception info over pub socket for other clients than the caller
552 # Send exception info over pub socket for other clients than the caller
553 # to pick up
553 # to pick up
554 topic = None
554 topic = None
555 if dh.topic:
555 if dh.topic:
556 topic = dh.topic.replace(b'pyout', b'pyerr')
556 topic = dh.topic.replace(b'pyout', b'pyerr')
557
557
558 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
558 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
559
559
560 # FIXME - Hack: store exception info in shell object. Right now, the
560 # FIXME - Hack: store exception info in shell object. Right now, the
561 # caller is reading this info after the fact, we need to fix this logic
561 # caller is reading this info after the fact, we need to fix this logic
562 # to remove this hack. Even uglier, we need to store the error status
562 # to remove this hack. Even uglier, we need to store the error status
563 # here, because in the main loop, the logic that sets it is being
563 # here, because in the main loop, the logic that sets it is being
564 # skipped because runlines swallows the exceptions.
564 # skipped because runlines swallows the exceptions.
565 exc_content[u'status'] = u'error'
565 exc_content[u'status'] = u'error'
566 self._reply_content = exc_content
566 self._reply_content = exc_content
567 # /FIXME
567 # /FIXME
568
568
569 return exc_content
569 return exc_content
570
570
571 def set_next_input(self, text):
571 def set_next_input(self, text):
572 """Send the specified text to the frontend to be presented at the next
572 """Send the specified text to the frontend to be presented at the next
573 input cell."""
573 input cell."""
574 payload = dict(
574 payload = dict(
575 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
575 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
576 text=text
576 text=text
577 )
577 )
578 self.payload_manager.write_payload(payload)
578 self.payload_manager.write_payload(payload)
579
579
580 #-------------------------------------------------------------------------
580 #-------------------------------------------------------------------------
581 # Things related to magics
581 # Things related to magics
582 #-------------------------------------------------------------------------
582 #-------------------------------------------------------------------------
583
583
584 def init_magics(self):
584 def init_magics(self):
585 super(ZMQInteractiveShell, self).init_magics()
585 super(ZMQInteractiveShell, self).init_magics()
586 self.register_magics(KernelMagics)
586 self.register_magics(KernelMagics)
587 self.magics_manager.register_alias('ed', 'edit')
587 self.magics_manager.register_alias('ed', 'edit')
588
588
589
589
590
590
591 InteractiveShellABC.register(ZMQInteractiveShell)
591 InteractiveShellABC.register(ZMQInteractiveShell)
@@ -1,598 +1,602 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 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2009-2011 The IPython Development Team
18 # Copyright (C) 2009-2011 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 # Stdlib
29 # Stdlib
30 import glob
30 import glob
31 import os
31 import os
32 import os.path as path
32 import os.path as path
33 import signal
33 import signal
34 import sys
34 import sys
35 import subprocess
35 import subprocess
36 import tempfile
36 import tempfile
37 import time
37 import time
38 import warnings
38 import warnings
39
39
40 # Note: monkeypatch!
40 # Note: monkeypatch!
41 # We need to monkeypatch a small problem in nose itself first, before importing
41 # We need to monkeypatch a small problem in nose itself first, before importing
42 # it for actual use. This should get into nose upstream, but its release cycle
42 # it for actual use. This should get into nose upstream, but its release cycle
43 # is slow and we need it for our parametric tests to work correctly.
43 # is slow and we need it for our parametric tests to work correctly.
44 from IPython.testing import nosepatch
44 from IPython.testing import nosepatch
45
45
46 # Monkeypatch extra assert methods into nose.tools if they're not already there.
46 # Monkeypatch extra assert methods into nose.tools if they're not already there.
47 # This can be dropped once we no longer test on Python 2.6
47 # This can be dropped once we no longer test on Python 2.6
48 from IPython.testing import nose_assert_methods
48 from IPython.testing import nose_assert_methods
49
49
50 # Now, proceed to import nose itself
50 # Now, proceed to import nose itself
51 import nose.plugins.builtin
51 import nose.plugins.builtin
52 from nose.plugins.xunit import Xunit
52 from nose.plugins.xunit import Xunit
53 from nose import SkipTest
53 from nose import SkipTest
54 from nose.core import TestProgram
54 from nose.core import TestProgram
55
55
56 # Our own imports
56 # Our own imports
57 from IPython.utils import py3compat
57 from IPython.utils import py3compat
58 from IPython.utils.importstring import import_item
58 from IPython.utils.importstring import import_item
59 from IPython.utils.path import get_ipython_module_path, get_ipython_package_dir
59 from IPython.utils.path import get_ipython_module_path, get_ipython_package_dir
60 from IPython.utils.process import find_cmd, pycmd2argv
60 from IPython.utils.process import find_cmd, pycmd2argv
61 from IPython.utils.sysinfo import sys_info
61 from IPython.utils.sysinfo import sys_info
62 from IPython.utils.tempdir import TemporaryDirectory
62 from IPython.utils.tempdir import TemporaryDirectory
63 from IPython.utils.warn import warn
63 from IPython.utils.warn import warn
64
64
65 from IPython.testing import globalipapp
65 from IPython.testing import globalipapp
66 from IPython.testing.plugin.ipdoctest import IPythonDoctest
66 from IPython.testing.plugin.ipdoctest import IPythonDoctest
67 from IPython.external.decorators import KnownFailure, knownfailureif
67 from IPython.external.decorators import KnownFailure, knownfailureif
68
68
69 pjoin = path.join
69 pjoin = path.join
70
70
71
71
72 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
73 # Globals
73 # Globals
74 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
75
75
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Warnings control
78 # Warnings control
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 # Twisted generates annoying warnings with Python 2.6, as will do other code
81 # Twisted generates annoying warnings with Python 2.6, as will do other code
82 # that imports 'sets' as of today
82 # that imports 'sets' as of today
83 warnings.filterwarnings('ignore', 'the sets module is deprecated',
83 warnings.filterwarnings('ignore', 'the sets module is deprecated',
84 DeprecationWarning )
84 DeprecationWarning )
85
85
86 # This one also comes from Twisted
86 # This one also comes from Twisted
87 warnings.filterwarnings('ignore', 'the sha module is deprecated',
87 warnings.filterwarnings('ignore', 'the sha module is deprecated',
88 DeprecationWarning)
88 DeprecationWarning)
89
89
90 # Wx on Fedora11 spits these out
90 # Wx on Fedora11 spits these out
91 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
91 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
92 UserWarning)
92 UserWarning)
93
93
94 # ------------------------------------------------------------------------------
94 # ------------------------------------------------------------------------------
95 # Monkeypatch Xunit to count known failures as skipped.
95 # Monkeypatch Xunit to count known failures as skipped.
96 # ------------------------------------------------------------------------------
96 # ------------------------------------------------------------------------------
97 def monkeypatch_xunit():
97 def monkeypatch_xunit():
98 try:
98 try:
99 knownfailureif(True)(lambda: None)()
99 knownfailureif(True)(lambda: None)()
100 except Exception as e:
100 except Exception as e:
101 KnownFailureTest = type(e)
101 KnownFailureTest = type(e)
102
102
103 def addError(self, test, err, capt=None):
103 def addError(self, test, err, capt=None):
104 if issubclass(err[0], KnownFailureTest):
104 if issubclass(err[0], KnownFailureTest):
105 err = (SkipTest,) + err[1:]
105 err = (SkipTest,) + err[1:]
106 return self.orig_addError(test, err, capt)
106 return self.orig_addError(test, err, capt)
107
107
108 Xunit.orig_addError = Xunit.addError
108 Xunit.orig_addError = Xunit.addError
109 Xunit.addError = addError
109 Xunit.addError = addError
110
110
111 #-----------------------------------------------------------------------------
111 #-----------------------------------------------------------------------------
112 # Logic for skipping doctests
112 # Logic for skipping doctests
113 #-----------------------------------------------------------------------------
113 #-----------------------------------------------------------------------------
114 def extract_version(mod):
114 def extract_version(mod):
115 return mod.__version__
115 return mod.__version__
116
116
117 def test_for(item, min_version=None, callback=extract_version):
117 def test_for(item, min_version=None, callback=extract_version):
118 """Test to see if item is importable, and optionally check against a minimum
118 """Test to see if item is importable, and optionally check against a minimum
119 version.
119 version.
120
120
121 If min_version is given, the default behavior is to check against the
121 If min_version is given, the default behavior is to check against the
122 `__version__` attribute of the item, but specifying `callback` allows you to
122 `__version__` attribute of the item, but specifying `callback` allows you to
123 extract the value you are interested in. e.g::
123 extract the value you are interested in. e.g::
124
124
125 In [1]: import sys
125 In [1]: import sys
126
126
127 In [2]: from IPython.testing.iptest import test_for
127 In [2]: from IPython.testing.iptest import test_for
128
128
129 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
129 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
130 Out[3]: True
130 Out[3]: True
131
131
132 """
132 """
133 try:
133 try:
134 check = import_item(item)
134 check = import_item(item)
135 except (ImportError, RuntimeError):
135 except (ImportError, RuntimeError):
136 # GTK reports Runtime error if it can't be initialized even if it's
136 # GTK reports Runtime error if it can't be initialized even if it's
137 # importable.
137 # importable.
138 return False
138 return False
139 else:
139 else:
140 if min_version:
140 if min_version:
141 if callback:
141 if callback:
142 # extra processing step to get version to compare
142 # extra processing step to get version to compare
143 check = callback(check)
143 check = callback(check)
144
144
145 return check >= min_version
145 return check >= min_version
146 else:
146 else:
147 return True
147 return True
148
148
149 # Global dict where we can store information on what we have and what we don't
149 # Global dict where we can store information on what we have and what we don't
150 # have available at test run time
150 # have available at test run time
151 have = {}
151 have = {}
152
152
153 have['curses'] = test_for('_curses')
153 have['curses'] = test_for('_curses')
154 have['matplotlib'] = test_for('matplotlib')
154 have['matplotlib'] = test_for('matplotlib')
155 have['numpy'] = test_for('numpy')
155 have['numpy'] = test_for('numpy')
156 have['pexpect'] = test_for('IPython.external.pexpect')
156 have['pexpect'] = test_for('IPython.external.pexpect')
157 have['pymongo'] = test_for('pymongo')
157 have['pymongo'] = test_for('pymongo')
158 have['pygments'] = test_for('pygments')
158 have['pygments'] = test_for('pygments')
159 have['qt'] = test_for('IPython.external.qt')
159 have['qt'] = test_for('IPython.external.qt')
160 have['rpy2'] = test_for('rpy2')
160 have['rpy2'] = test_for('rpy2')
161 have['sqlite3'] = test_for('sqlite3')
161 have['sqlite3'] = test_for('sqlite3')
162 have['cython'] = test_for('Cython')
162 have['cython'] = test_for('Cython')
163 have['oct2py'] = test_for('oct2py')
163 have['oct2py'] = test_for('oct2py')
164 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
164 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
165 have['jinja2'] = test_for('jinja2')
165 have['jinja2'] = test_for('jinja2')
166 have['wx'] = test_for('wx')
166 have['wx'] = test_for('wx')
167 have['wx.aui'] = test_for('wx.aui')
167 have['wx.aui'] = test_for('wx.aui')
168 have['azure'] = test_for('azure')
168 have['azure'] = test_for('azure')
169
169
170 min_zmq = (2,1,11)
170 min_zmq = (2,1,11)
171
171
172 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
172 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
173
173
174 #-----------------------------------------------------------------------------
174 #-----------------------------------------------------------------------------
175 # Functions and classes
175 # Functions and classes
176 #-----------------------------------------------------------------------------
176 #-----------------------------------------------------------------------------
177
177
178 def report():
178 def report():
179 """Return a string with a summary report of test-related variables."""
179 """Return a string with a summary report of test-related variables."""
180
180
181 out = [ sys_info(), '\n']
181 out = [ sys_info(), '\n']
182
182
183 avail = []
183 avail = []
184 not_avail = []
184 not_avail = []
185
185
186 for k, is_avail in have.items():
186 for k, is_avail in have.items():
187 if is_avail:
187 if is_avail:
188 avail.append(k)
188 avail.append(k)
189 else:
189 else:
190 not_avail.append(k)
190 not_avail.append(k)
191
191
192 if avail:
192 if avail:
193 out.append('\nTools and libraries available at test time:\n')
193 out.append('\nTools and libraries available at test time:\n')
194 avail.sort()
194 avail.sort()
195 out.append(' ' + ' '.join(avail)+'\n')
195 out.append(' ' + ' '.join(avail)+'\n')
196
196
197 if not_avail:
197 if not_avail:
198 out.append('\nTools and libraries NOT available at test time:\n')
198 out.append('\nTools and libraries NOT available at test time:\n')
199 not_avail.sort()
199 not_avail.sort()
200 out.append(' ' + ' '.join(not_avail)+'\n')
200 out.append(' ' + ' '.join(not_avail)+'\n')
201
201
202 return ''.join(out)
202 return ''.join(out)
203
203
204
204
205 def make_exclude():
205 def make_exclude():
206 """Make patterns of modules and packages to exclude from testing.
206 """Make patterns of modules and packages to exclude from testing.
207
207
208 For the IPythonDoctest plugin, we need to exclude certain patterns that
208 For the IPythonDoctest plugin, we need to exclude certain patterns that
209 cause testing problems. We should strive to minimize the number of
209 cause testing problems. We should strive to minimize the number of
210 skipped modules, since this means untested code.
210 skipped modules, since this means untested code.
211
211
212 These modules and packages will NOT get scanned by nose at all for tests.
212 These modules and packages will NOT get scanned by nose at all for tests.
213 """
213 """
214 # Simple utility to make IPython paths more readably, we need a lot of
214 # Simple utility to make IPython paths more readably, we need a lot of
215 # these below
215 # these below
216 ipjoin = lambda *paths: pjoin('IPython', *paths)
216 ipjoin = lambda *paths: pjoin('IPython', *paths)
217
217
218 exclusions = [ipjoin('external'),
218 exclusions = [ipjoin('external'),
219 ipjoin('quarantine'),
219 ipjoin('quarantine'),
220 ipjoin('deathrow'),
220 ipjoin('deathrow'),
221 # This guy is probably attic material
221 # This guy is probably attic material
222 ipjoin('testing', 'mkdoctests'),
222 ipjoin('testing', 'mkdoctests'),
223 # Testing inputhook will need a lot of thought, to figure out
223 # Testing inputhook will need a lot of thought, to figure out
224 # how to have tests that don't lock up with the gui event
224 # how to have tests that don't lock up with the gui event
225 # loops in the picture
225 # loops in the picture
226 ipjoin('lib', 'inputhook'),
226 ipjoin('lib', 'inputhook'),
227 # Config files aren't really importable stand-alone
227 # Config files aren't really importable stand-alone
228 ipjoin('config', 'profile'),
228 ipjoin('config', 'profile'),
229 # The notebook 'static' directory contains JS, css and other
229 # The notebook 'static' directory contains JS, css and other
230 # files for web serving. Occasionally projects may put a .py
230 # files for web serving. Occasionally projects may put a .py
231 # file in there (MathJax ships a conf.py), so we might as
231 # file in there (MathJax ships a conf.py), so we might as
232 # well play it safe and skip the whole thing.
232 # well play it safe and skip the whole thing.
233 ipjoin('frontend', 'html', 'notebook', 'static')
233 ipjoin('frontend', 'html', 'notebook', 'static')
234 ]
234 ]
235 if not have['sqlite3']:
235 if not have['sqlite3']:
236 exclusions.append(ipjoin('core', 'tests', 'test_history'))
236 exclusions.append(ipjoin('core', 'tests', 'test_history'))
237 exclusions.append(ipjoin('core', 'history'))
237 exclusions.append(ipjoin('core', 'history'))
238 if not have['wx']:
238 if not have['wx']:
239 exclusions.append(ipjoin('lib', 'inputhookwx'))
239 exclusions.append(ipjoin('lib', 'inputhookwx'))
240
240
241 if 'IPython.kernel.inprocess' not in sys.argv:
242 exclusions.append(ipjoin('kernel', 'inprocess'))
243
241 # FIXME: temporarily disable autoreload tests, as they can produce
244 # FIXME: temporarily disable autoreload tests, as they can produce
242 # spurious failures in subsequent tests (cythonmagic).
245 # spurious failures in subsequent tests (cythonmagic).
243 exclusions.append(ipjoin('extensions', 'autoreload'))
246 exclusions.append(ipjoin('extensions', 'autoreload'))
244 exclusions.append(ipjoin('extensions', 'tests', 'test_autoreload'))
247 exclusions.append(ipjoin('extensions', 'tests', 'test_autoreload'))
245
248
246 # We do this unconditionally, so that the test suite doesn't import
249 # We do this unconditionally, so that the test suite doesn't import
247 # gtk, changing the default encoding and masking some unicode bugs.
250 # gtk, changing the default encoding and masking some unicode bugs.
248 exclusions.append(ipjoin('lib', 'inputhookgtk'))
251 exclusions.append(ipjoin('lib', 'inputhookgtk'))
249 exclusions.append(ipjoin('zmq', 'gui', 'gtkembed'))
252 exclusions.append(ipjoin('kernel', 'zmq', 'gui', 'gtkembed'))
250
253
251 # These have to be skipped on win32 because the use echo, rm, cd, etc.
254 # These have to be skipped on win32 because the use echo, rm, cd, etc.
252 # See ticket https://github.com/ipython/ipython/issues/87
255 # See ticket https://github.com/ipython/ipython/issues/87
253 if sys.platform == 'win32':
256 if sys.platform == 'win32':
254 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
257 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
255 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
258 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
256
259
257 if not have['pexpect']:
260 if not have['pexpect']:
258 exclusions.extend([ipjoin('lib', 'irunner'),
261 exclusions.extend([ipjoin('lib', 'irunner'),
259 ipjoin('lib', 'tests', 'test_irunner'),
262 ipjoin('lib', 'tests', 'test_irunner'),
260 ipjoin('frontend', 'terminal', 'console'),
263 ipjoin('frontend', 'terminal', 'console'),
261 ])
264 ])
262
265
263 if not have['zmq']:
266 if not have['zmq']:
264 exclusions.append(ipjoin('zmq'))
267 exclusions.append(ipjoin('kernel'))
265 exclusions.append(ipjoin('frontend', 'qt'))
268 exclusions.append(ipjoin('frontend', 'qt'))
266 exclusions.append(ipjoin('frontend', 'html'))
269 exclusions.append(ipjoin('frontend', 'html'))
267 exclusions.append(ipjoin('frontend', 'consoleapp.py'))
270 exclusions.append(ipjoin('frontend', 'consoleapp.py'))
268 exclusions.append(ipjoin('frontend', 'terminal', 'console'))
271 exclusions.append(ipjoin('frontend', 'terminal', 'console'))
269 exclusions.append(ipjoin('parallel'))
272 exclusions.append(ipjoin('parallel'))
270 elif not have['qt'] or not have['pygments']:
273 elif not have['qt'] or not have['pygments']:
271 exclusions.append(ipjoin('frontend', 'qt'))
274 exclusions.append(ipjoin('frontend', 'qt'))
272
275
273 if not have['pymongo']:
276 if not have['pymongo']:
274 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
277 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
275 exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb'))
278 exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb'))
276
279
277 if not have['matplotlib']:
280 if not have['matplotlib']:
278 exclusions.extend([ipjoin('core', 'pylabtools'),
281 exclusions.extend([ipjoin('core', 'pylabtools'),
279 ipjoin('core', 'tests', 'test_pylabtools'),
282 ipjoin('core', 'tests', 'test_pylabtools'),
280 ipjoin('zmq', 'pylab'),
283 ipjoin('kernel', 'zmq', 'pylab'),
281 ])
284 ])
282
285
283 if not have['cython']:
286 if not have['cython']:
284 exclusions.extend([ipjoin('extensions', 'cythonmagic')])
287 exclusions.extend([ipjoin('extensions', 'cythonmagic')])
285 exclusions.extend([ipjoin('extensions', 'tests', 'test_cythonmagic')])
288 exclusions.extend([ipjoin('extensions', 'tests', 'test_cythonmagic')])
286
289
287 if not have['oct2py']:
290 if not have['oct2py']:
288 exclusions.extend([ipjoin('extensions', 'octavemagic')])
291 exclusions.extend([ipjoin('extensions', 'octavemagic')])
289 exclusions.extend([ipjoin('extensions', 'tests', 'test_octavemagic')])
292 exclusions.extend([ipjoin('extensions', 'tests', 'test_octavemagic')])
290
293
291 if not have['tornado']:
294 if not have['tornado']:
292 exclusions.append(ipjoin('frontend', 'html'))
295 exclusions.append(ipjoin('frontend', 'html'))
293
296
294 if not have['jinja2']:
297 if not have['jinja2']:
295 exclusions.append(ipjoin('frontend', 'html', 'notebook', 'notebookapp'))
298 exclusions.append(ipjoin('frontend', 'html', 'notebook', 'notebookapp'))
296
299
297 if not have['rpy2'] or not have['numpy']:
300 if not have['rpy2'] or not have['numpy']:
298 exclusions.append(ipjoin('extensions', 'rmagic'))
301 exclusions.append(ipjoin('extensions', 'rmagic'))
299 exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic'))
302 exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic'))
300
303
301 if not have['azure']:
304 if not have['azure']:
302 exclusions.append(ipjoin('frontend', 'html', 'notebook', 'azurenbmanager'))
305 exclusions.append(ipjoin('frontend', 'html', 'notebook', 'azurenbmanager'))
303
306
304 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
307 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
305 if sys.platform == 'win32':
308 if sys.platform == 'win32':
306 exclusions = [s.replace('\\','\\\\') for s in exclusions]
309 exclusions = [s.replace('\\','\\\\') for s in exclusions]
307
310
308 # check for any exclusions that don't seem to exist:
311 # check for any exclusions that don't seem to exist:
309 parent, _ = os.path.split(get_ipython_package_dir())
312 parent, _ = os.path.split(get_ipython_package_dir())
310 for exclusion in exclusions:
313 for exclusion in exclusions:
311 if exclusion.endswith(('deathrow', 'quarantine')):
314 if exclusion.endswith(('deathrow', 'quarantine')):
312 # ignore deathrow/quarantine, which exist in dev, but not install
315 # ignore deathrow/quarantine, which exist in dev, but not install
313 continue
316 continue
314 fullpath = pjoin(parent, exclusion)
317 fullpath = pjoin(parent, exclusion)
315 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
318 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
316 warn("Excluding nonexistent file: %r" % exclusion)
319 warn("Excluding nonexistent file: %r" % exclusion)
317
320
318 return exclusions
321 return exclusions
319
322
320
323
321 class IPTester(object):
324 class IPTester(object):
322 """Call that calls iptest or trial in a subprocess.
325 """Call that calls iptest or trial in a subprocess.
323 """
326 """
324 #: string, name of test runner that will be called
327 #: string, name of test runner that will be called
325 runner = None
328 runner = None
326 #: list, parameters for test runner
329 #: list, parameters for test runner
327 params = None
330 params = None
328 #: list, arguments of system call to be made to call test runner
331 #: list, arguments of system call to be made to call test runner
329 call_args = None
332 call_args = None
330 #: list, subprocesses we start (for cleanup)
333 #: list, subprocesses we start (for cleanup)
331 processes = None
334 processes = None
332 #: str, coverage xml output file
335 #: str, coverage xml output file
333 coverage_xml = None
336 coverage_xml = None
334
337
335 def __init__(self, runner='iptest', params=None):
338 def __init__(self, runner='iptest', params=None):
336 """Create new test runner."""
339 """Create new test runner."""
337 p = os.path
340 p = os.path
338 if runner == 'iptest':
341 if runner == 'iptest':
339 iptest_app = get_ipython_module_path('IPython.testing.iptest')
342 iptest_app = get_ipython_module_path('IPython.testing.iptest')
340 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
343 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
341 else:
344 else:
342 raise Exception('Not a valid test runner: %s' % repr(runner))
345 raise Exception('Not a valid test runner: %s' % repr(runner))
343 if params is None:
346 if params is None:
344 params = []
347 params = []
345 if isinstance(params, str):
348 if isinstance(params, str):
346 params = [params]
349 params = [params]
347 self.params = params
350 self.params = params
348
351
349 # Assemble call
352 # Assemble call
350 self.call_args = self.runner+self.params
353 self.call_args = self.runner+self.params
351
354
352 # Find the section we're testing (IPython.foo)
355 # Find the section we're testing (IPython.foo)
353 for sect in self.params:
356 for sect in self.params:
354 if sect.startswith('IPython'): break
357 if sect.startswith('IPython'): break
355 else:
358 else:
356 raise ValueError("Section not found", self.params)
359 raise ValueError("Section not found", self.params)
357
360
358 if '--with-xunit' in self.call_args:
361 if '--with-xunit' in self.call_args:
359
362
360 self.call_args.append('--xunit-file')
363 self.call_args.append('--xunit-file')
361 # FIXME: when Windows uses subprocess.call, these extra quotes are unnecessary:
364 # FIXME: when Windows uses subprocess.call, these extra quotes are unnecessary:
362 xunit_file = path.abspath(sect+'.xunit.xml')
365 xunit_file = path.abspath(sect+'.xunit.xml')
363 if sys.platform == 'win32':
366 if sys.platform == 'win32':
364 xunit_file = '"%s"' % xunit_file
367 xunit_file = '"%s"' % xunit_file
365 self.call_args.append(xunit_file)
368 self.call_args.append(xunit_file)
366
369
367 if '--with-xml-coverage' in self.call_args:
370 if '--with-xml-coverage' in self.call_args:
368 self.coverage_xml = path.abspath(sect+".coverage.xml")
371 self.coverage_xml = path.abspath(sect+".coverage.xml")
369 self.call_args.remove('--with-xml-coverage')
372 self.call_args.remove('--with-xml-coverage')
370 self.call_args = ["coverage", "run", "--source="+sect] + self.call_args[1:]
373 self.call_args = ["coverage", "run", "--source="+sect] + self.call_args[1:]
371
374
372 # Store anything we start to clean up on deletion
375 # Store anything we start to clean up on deletion
373 self.processes = []
376 self.processes = []
374
377
375 def _run_cmd(self):
378 def _run_cmd(self):
376 with TemporaryDirectory() as IPYTHONDIR:
379 with TemporaryDirectory() as IPYTHONDIR:
377 env = os.environ.copy()
380 env = os.environ.copy()
378 env['IPYTHONDIR'] = IPYTHONDIR
381 env['IPYTHONDIR'] = IPYTHONDIR
379 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
382 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
380 subp = subprocess.Popen(self.call_args, env=env)
383 subp = subprocess.Popen(self.call_args, env=env)
381 self.processes.append(subp)
384 self.processes.append(subp)
382 # If this fails, the process will be left in self.processes and
385 # If this fails, the process will be left in self.processes and
383 # cleaned up later, but if the wait call succeeds, then we can
386 # cleaned up later, but if the wait call succeeds, then we can
384 # clear the stored process.
387 # clear the stored process.
385 retcode = subp.wait()
388 retcode = subp.wait()
386 self.processes.pop()
389 self.processes.pop()
387 return retcode
390 return retcode
388
391
389 def run(self):
392 def run(self):
390 """Run the stored commands"""
393 """Run the stored commands"""
391 try:
394 try:
392 retcode = self._run_cmd()
395 retcode = self._run_cmd()
393 except KeyboardInterrupt:
396 except KeyboardInterrupt:
394 return -signal.SIGINT
397 return -signal.SIGINT
395 except:
398 except:
396 import traceback
399 import traceback
397 traceback.print_exc()
400 traceback.print_exc()
398 return 1 # signal failure
401 return 1 # signal failure
399
402
400 if self.coverage_xml:
403 if self.coverage_xml:
401 subprocess.call(["coverage", "xml", "-o", self.coverage_xml])
404 subprocess.call(["coverage", "xml", "-o", self.coverage_xml])
402 return retcode
405 return retcode
403
406
404 def __del__(self):
407 def __del__(self):
405 """Cleanup on exit by killing any leftover processes."""
408 """Cleanup on exit by killing any leftover processes."""
406 for subp in self.processes:
409 for subp in self.processes:
407 if subp.poll() is not None:
410 if subp.poll() is not None:
408 continue # process is already dead
411 continue # process is already dead
409
412
410 try:
413 try:
411 print('Cleaning up stale PID: %d' % subp.pid)
414 print('Cleaning up stale PID: %d' % subp.pid)
412 subp.kill()
415 subp.kill()
413 except: # (OSError, WindowsError) ?
416 except: # (OSError, WindowsError) ?
414 # This is just a best effort, if we fail or the process was
417 # This is just a best effort, if we fail or the process was
415 # really gone, ignore it.
418 # really gone, ignore it.
416 pass
419 pass
417 else:
420 else:
418 for i in range(10):
421 for i in range(10):
419 if subp.poll() is None:
422 if subp.poll() is None:
420 time.sleep(0.1)
423 time.sleep(0.1)
421 else:
424 else:
422 break
425 break
423
426
424 if subp.poll() is None:
427 if subp.poll() is None:
425 # The process did not die...
428 # The process did not die...
426 print('... failed. Manual cleanup may be required.')
429 print('... failed. Manual cleanup may be required.')
427
430
428 def make_runners(inc_slow=False):
431 def make_runners(inc_slow=False):
429 """Define the top-level packages that need to be tested.
432 """Define the top-level packages that need to be tested.
430 """
433 """
431
434
432 # Packages to be tested via nose, that only depend on the stdlib
435 # Packages to be tested via nose, that only depend on the stdlib
433 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'kernel', 'lib',
436 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
434 'testing', 'utils', 'nbformat', 'inprocess' ]
437 'testing', 'utils', 'nbformat' ]
435
438
436 if have['zmq']:
439 if have['zmq']:
437 nose_pkg_names.append('zmq')
440 nose_pkg_names.append('kernel')
441 nose_pkg_names.append('kernel.inprocess')
438 if inc_slow:
442 if inc_slow:
439 nose_pkg_names.append('parallel')
443 nose_pkg_names.append('parallel')
440
444
441 # For debugging this code, only load quick stuff
445 # For debugging this code, only load quick stuff
442 #nose_pkg_names = ['core', 'extensions'] # dbg
446 #nose_pkg_names = ['core', 'extensions'] # dbg
443
447
444 # Make fully qualified package names prepending 'IPython.' to our name lists
448 # Make fully qualified package names prepending 'IPython.' to our name lists
445 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
449 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
446
450
447 # Make runners
451 # Make runners
448 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
452 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
449
453
450 return runners
454 return runners
451
455
452
456
453 def run_iptest():
457 def run_iptest():
454 """Run the IPython test suite using nose.
458 """Run the IPython test suite using nose.
455
459
456 This function is called when this script is **not** called with the form
460 This function is called when this script is **not** called with the form
457 `iptest all`. It simply calls nose with appropriate command line flags
461 `iptest all`. It simply calls nose with appropriate command line flags
458 and accepts all of the standard nose arguments.
462 and accepts all of the standard nose arguments.
459 """
463 """
460 # Apply our monkeypatch to Xunit
464 # Apply our monkeypatch to Xunit
461 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
465 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
462 monkeypatch_xunit()
466 monkeypatch_xunit()
463
467
464 warnings.filterwarnings('ignore',
468 warnings.filterwarnings('ignore',
465 'This will be removed soon. Use IPython.testing.util instead')
469 'This will be removed soon. Use IPython.testing.util instead')
466
470
467 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
471 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
468
472
469 '--with-ipdoctest',
473 '--with-ipdoctest',
470 '--ipdoctest-tests','--ipdoctest-extension=txt',
474 '--ipdoctest-tests','--ipdoctest-extension=txt',
471
475
472 # We add --exe because of setuptools' imbecility (it
476 # We add --exe because of setuptools' imbecility (it
473 # blindly does chmod +x on ALL files). Nose does the
477 # blindly does chmod +x on ALL files). Nose does the
474 # right thing and it tries to avoid executables,
478 # right thing and it tries to avoid executables,
475 # setuptools unfortunately forces our hand here. This
479 # setuptools unfortunately forces our hand here. This
476 # has been discussed on the distutils list and the
480 # has been discussed on the distutils list and the
477 # setuptools devs refuse to fix this problem!
481 # setuptools devs refuse to fix this problem!
478 '--exe',
482 '--exe',
479 ]
483 ]
480 if '-a' not in argv and '-A' not in argv:
484 if '-a' not in argv and '-A' not in argv:
481 argv = argv + ['-a', '!crash']
485 argv = argv + ['-a', '!crash']
482
486
483 if nose.__version__ >= '0.11':
487 if nose.__version__ >= '0.11':
484 # I don't fully understand why we need this one, but depending on what
488 # I don't fully understand why we need this one, but depending on what
485 # directory the test suite is run from, if we don't give it, 0 tests
489 # directory the test suite is run from, if we don't give it, 0 tests
486 # get run. Specifically, if the test suite is run from the source dir
490 # get run. Specifically, if the test suite is run from the source dir
487 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
491 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
488 # even if the same call done in this directory works fine). It appears
492 # even if the same call done in this directory works fine). It appears
489 # that if the requested package is in the current dir, nose bails early
493 # that if the requested package is in the current dir, nose bails early
490 # by default. Since it's otherwise harmless, leave it in by default
494 # by default. Since it's otherwise harmless, leave it in by default
491 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
495 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
492 argv.append('--traverse-namespace')
496 argv.append('--traverse-namespace')
493
497
494 # use our plugin for doctesting. It will remove the standard doctest plugin
498 # use our plugin for doctesting. It will remove the standard doctest plugin
495 # if it finds it enabled
499 # if it finds it enabled
496 plugins = [IPythonDoctest(make_exclude()), KnownFailure()]
500 plugins = [IPythonDoctest(make_exclude()), KnownFailure()]
497
501
498 # We need a global ipython running in this process, but the special
502 # We need a global ipython running in this process, but the special
499 # in-process group spawns its own IPython kernels, so for *that* group we
503 # in-process group spawns its own IPython kernels, so for *that* group we
500 # must avoid also opening the global one (otherwise there's a conflict of
504 # must avoid also opening the global one (otherwise there's a conflict of
501 # singletons). Ultimately the solution to this problem is to refactor our
505 # singletons). Ultimately the solution to this problem is to refactor our
502 # assumptions about what needs to be a singleton and what doesn't (app
506 # assumptions about what needs to be a singleton and what doesn't (app
503 # objects should, individual shells shouldn't). But for now, this
507 # objects should, individual shells shouldn't). But for now, this
504 # workaround allows the test suite for the inprocess module to complete.
508 # workaround allows the test suite for the inprocess module to complete.
505 if not 'IPython.inprocess' in sys.argv:
509 if not 'IPython.kernel.inprocess' in sys.argv:
506 globalipapp.start_ipython()
510 globalipapp.start_ipython()
507
511
508 # Now nose can run
512 # Now nose can run
509 TestProgram(argv=argv, addplugins=plugins)
513 TestProgram(argv=argv, addplugins=plugins)
510
514
511
515
512 def run_iptestall(inc_slow=False):
516 def run_iptestall(inc_slow=False):
513 """Run the entire IPython test suite by calling nose and trial.
517 """Run the entire IPython test suite by calling nose and trial.
514
518
515 This function constructs :class:`IPTester` instances for all IPython
519 This function constructs :class:`IPTester` instances for all IPython
516 modules and package and then runs each of them. This causes the modules
520 modules and package and then runs each of them. This causes the modules
517 and packages of IPython to be tested each in their own subprocess using
521 and packages of IPython to be tested each in their own subprocess using
518 nose.
522 nose.
519
523
520 Parameters
524 Parameters
521 ----------
525 ----------
522
526
523 inc_slow : bool, optional
527 inc_slow : bool, optional
524 Include slow tests, like IPython.parallel. By default, these tests aren't
528 Include slow tests, like IPython.parallel. By default, these tests aren't
525 run.
529 run.
526 """
530 """
527
531
528 runners = make_runners(inc_slow=inc_slow)
532 runners = make_runners(inc_slow=inc_slow)
529
533
530 # Run the test runners in a temporary dir so we can nuke it when finished
534 # Run the test runners in a temporary dir so we can nuke it when finished
531 # to clean up any junk files left over by accident. This also makes it
535 # to clean up any junk files left over by accident. This also makes it
532 # robust against being run in non-writeable directories by mistake, as the
536 # robust against being run in non-writeable directories by mistake, as the
533 # temp dir will always be user-writeable.
537 # temp dir will always be user-writeable.
534 curdir = os.getcwdu()
538 curdir = os.getcwdu()
535 testdir = tempfile.gettempdir()
539 testdir = tempfile.gettempdir()
536 os.chdir(testdir)
540 os.chdir(testdir)
537
541
538 # Run all test runners, tracking execution time
542 # Run all test runners, tracking execution time
539 failed = []
543 failed = []
540 t_start = time.time()
544 t_start = time.time()
541 try:
545 try:
542 for (name, runner) in runners:
546 for (name, runner) in runners:
543 print('*'*70)
547 print('*'*70)
544 print('IPython test group:',name)
548 print('IPython test group:',name)
545 res = runner.run()
549 res = runner.run()
546 if res:
550 if res:
547 failed.append( (name, runner) )
551 failed.append( (name, runner) )
548 if res == -signal.SIGINT:
552 if res == -signal.SIGINT:
549 print("Interrupted")
553 print("Interrupted")
550 break
554 break
551 finally:
555 finally:
552 os.chdir(curdir)
556 os.chdir(curdir)
553 t_end = time.time()
557 t_end = time.time()
554 t_tests = t_end - t_start
558 t_tests = t_end - t_start
555 nrunners = len(runners)
559 nrunners = len(runners)
556 nfail = len(failed)
560 nfail = len(failed)
557 # summarize results
561 # summarize results
558 print()
562 print()
559 print('*'*70)
563 print('*'*70)
560 print('Test suite completed for system with the following information:')
564 print('Test suite completed for system with the following information:')
561 print(report())
565 print(report())
562 print('Ran %s test groups in %.3fs' % (nrunners, t_tests))
566 print('Ran %s test groups in %.3fs' % (nrunners, t_tests))
563 print()
567 print()
564 print('Status:')
568 print('Status:')
565 if not failed:
569 if not failed:
566 print('OK')
570 print('OK')
567 else:
571 else:
568 # If anything went wrong, point out what command to rerun manually to
572 # If anything went wrong, point out what command to rerun manually to
569 # see the actual errors and individual summary
573 # see the actual errors and individual summary
570 print('ERROR - %s out of %s test groups failed.' % (nfail, nrunners))
574 print('ERROR - %s out of %s test groups failed.' % (nfail, nrunners))
571 for name, failed_runner in failed:
575 for name, failed_runner in failed:
572 print('-'*40)
576 print('-'*40)
573 print('Runner failed:',name)
577 print('Runner failed:',name)
574 print('You may wish to rerun this one individually, with:')
578 print('You may wish to rerun this one individually, with:')
575 failed_call_args = [py3compat.cast_unicode(x) for x in failed_runner.call_args]
579 failed_call_args = [py3compat.cast_unicode(x) for x in failed_runner.call_args]
576 print(u' '.join(failed_call_args))
580 print(u' '.join(failed_call_args))
577 print()
581 print()
578 # Ensure that our exit code indicates failure
582 # Ensure that our exit code indicates failure
579 sys.exit(1)
583 sys.exit(1)
580
584
581
585
582 def main():
586 def main():
583 for arg in sys.argv[1:]:
587 for arg in sys.argv[1:]:
584 if arg.startswith('IPython'):
588 if arg.startswith('IPython'):
585 # This is in-process
589 # This is in-process
586 run_iptest()
590 run_iptest()
587 else:
591 else:
588 if "--all" in sys.argv:
592 if "--all" in sys.argv:
589 sys.argv.remove("--all")
593 sys.argv.remove("--all")
590 inc_slow = True
594 inc_slow = True
591 else:
595 else:
592 inc_slow = False
596 inc_slow = False
593 # This starts subprocesses
597 # This starts subprocesses
594 run_iptestall(inc_slow=inc_slow)
598 run_iptestall(inc_slow=inc_slow)
595
599
596
600
597 if __name__ == '__main__':
601 if __name__ == '__main__':
598 main()
602 main()
General Comments 0
You need to be logged in to leave comments. Login now