##// END OF EJS Templates
Various docs fixes
Thomas Kluyver -
Show More
@@ -1,282 +1,285 b''
1 """Remote Functions and decorators for Views.
1 """Remote Functions and decorators for Views.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 * Min RK
6 * Min RK
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2010-2011 The IPython Development Team
9 # Copyright (C) 2010-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from __future__ import division
19 from __future__ import division
20
20
21 import sys
21 import sys
22 import warnings
22 import warnings
23
23
24 from IPython.external.decorator import decorator
24 from IPython.external.decorator import decorator
25 from IPython.testing.skipdoctest import skip_doctest
25 from IPython.testing.skipdoctest import skip_doctest
26
26
27 from . import map as Map
27 from . import map as Map
28 from .asyncresult import AsyncMapResult
28 from .asyncresult import AsyncMapResult
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Functions and Decorators
31 # Functions and Decorators
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 @skip_doctest
34 @skip_doctest
35 def remote(view, block=None, **flags):
35 def remote(view, block=None, **flags):
36 """Turn a function into a remote function.
36 """Turn a function into a remote function.
37
37
38 This method can be used for map:
38 This method can be used for map:
39
39
40 In [1]: @remote(view,block=True)
40 In [1]: @remote(view,block=True)
41 ...: def func(a):
41 ...: def func(a):
42 ...: pass
42 ...: pass
43 """
43 """
44
44
45 def remote_function(f):
45 def remote_function(f):
46 return RemoteFunction(view, f, block=block, **flags)
46 return RemoteFunction(view, f, block=block, **flags)
47 return remote_function
47 return remote_function
48
48
49 @skip_doctest
49 @skip_doctest
50 def parallel(view, dist='b', block=None, ordered=True, **flags):
50 def parallel(view, dist='b', block=None, ordered=True, **flags):
51 """Turn a function into a parallel remote function.
51 """Turn a function into a parallel remote function.
52
52
53 This method can be used for map:
53 This method can be used for map:
54
54
55 In [1]: @parallel(view, block=True)
55 In [1]: @parallel(view, block=True)
56 ...: def func(a):
56 ...: def func(a):
57 ...: pass
57 ...: pass
58 """
58 """
59
59
60 def parallel_function(f):
60 def parallel_function(f):
61 return ParallelFunction(view, f, dist=dist, block=block, ordered=ordered, **flags)
61 return ParallelFunction(view, f, dist=dist, block=block, ordered=ordered, **flags)
62 return parallel_function
62 return parallel_function
63
63
64 def getname(f):
64 def getname(f):
65 """Get the name of an object.
65 """Get the name of an object.
66
66
67 For use in case of callables that are not functions, and
67 For use in case of callables that are not functions, and
68 thus may not have __name__ defined.
68 thus may not have __name__ defined.
69
69
70 Order: f.__name__ > f.name > str(f)
70 Order: f.__name__ > f.name > str(f)
71 """
71 """
72 try:
72 try:
73 return f.__name__
73 return f.__name__
74 except:
74 except:
75 pass
75 pass
76 try:
76 try:
77 return f.name
77 return f.name
78 except:
78 except:
79 pass
79 pass
80
80
81 return str(f)
81 return str(f)
82
82
83 @decorator
83 @decorator
84 def sync_view_results(f, self, *args, **kwargs):
84 def sync_view_results(f, self, *args, **kwargs):
85 """sync relevant results from self.client to our results attribute.
85 """sync relevant results from self.client to our results attribute.
86
86
87 This is a clone of view.sync_results, but for remote functions
87 This is a clone of view.sync_results, but for remote functions
88 """
88 """
89 view = self.view
89 view = self.view
90 if view._in_sync_results:
90 if view._in_sync_results:
91 return f(self, *args, **kwargs)
91 return f(self, *args, **kwargs)
92 view._in_sync_results = True
92 view._in_sync_results = True
93 try:
93 try:
94 ret = f(self, *args, **kwargs)
94 ret = f(self, *args, **kwargs)
95 finally:
95 finally:
96 view._in_sync_results = False
96 view._in_sync_results = False
97 view._sync_results()
97 view._sync_results()
98 return ret
98 return ret
99
99
100 #--------------------------------------------------------------------------
100 #--------------------------------------------------------------------------
101 # Classes
101 # Classes
102 #--------------------------------------------------------------------------
102 #--------------------------------------------------------------------------
103
103
104 class RemoteFunction(object):
104 class RemoteFunction(object):
105 """Turn an existing function into a remote function.
105 """Turn an existing function into a remote function.
106
106
107 Parameters
107 Parameters
108 ----------
108 ----------
109
109
110 view : View instance
110 view : View instance
111 The view to be used for execution
111 The view to be used for execution
112 f : callable
112 f : callable
113 The function to be wrapped into a remote function
113 The function to be wrapped into a remote function
114 block : bool [default: None]
114 block : bool [default: None]
115 Whether to wait for results or not. The default behavior is
115 Whether to wait for results or not. The default behavior is
116 to use the current `block` attribute of `view`
116 to use the current `block` attribute of `view`
117
117
118 **flags : remaining kwargs are passed to View.temp_flags
118 **flags : remaining kwargs are passed to View.temp_flags
119 """
119 """
120
120
121 view = None # the remote connection
121 view = None # the remote connection
122 func = None # the wrapped function
122 func = None # the wrapped function
123 block = None # whether to block
123 block = None # whether to block
124 flags = None # dict of extra kwargs for temp_flags
124 flags = None # dict of extra kwargs for temp_flags
125
125
126 def __init__(self, view, f, block=None, **flags):
126 def __init__(self, view, f, block=None, **flags):
127 self.view = view
127 self.view = view
128 self.func = f
128 self.func = f
129 self.block=block
129 self.block=block
130 self.flags=flags
130 self.flags=flags
131
131
132 def __call__(self, *args, **kwargs):
132 def __call__(self, *args, **kwargs):
133 block = self.view.block if self.block is None else self.block
133 block = self.view.block if self.block is None else self.block
134 with self.view.temp_flags(block=block, **self.flags):
134 with self.view.temp_flags(block=block, **self.flags):
135 return self.view.apply(self.func, *args, **kwargs)
135 return self.view.apply(self.func, *args, **kwargs)
136
136
137
137
138 class ParallelFunction(RemoteFunction):
138 class ParallelFunction(RemoteFunction):
139 """Class for mapping a function to sequences.
139 """Class for mapping a function to sequences.
140
140
141 This will distribute the sequences according the a mapper, and call
141 This will distribute the sequences according the a mapper, and call
142 the function on each sub-sequence. If called via map, then the function
142 the function on each sub-sequence. If called via map, then the function
143 will be called once on each element, rather that each sub-sequence.
143 will be called once on each element, rather that each sub-sequence.
144
144
145 Parameters
145 Parameters
146 ----------
146 ----------
147
147
148 view : View instance
148 view : View instance
149 The view to be used for execution
149 The view to be used for execution
150 f : callable
150 f : callable
151 The function to be wrapped into a remote function
151 The function to be wrapped into a remote function
152 dist : str [default: 'b']
152 dist : str [default: 'b']
153 The key for which mapObject to use to distribute sequences
153 The key for which mapObject to use to distribute sequences
154 options are:
154 options are:
155 * 'b' : use contiguous chunks in order
155
156 * 'r' : use round-robin striping
156 * 'b' : use contiguous chunks in order
157 * 'r' : use round-robin striping
158
157 block : bool [default: None]
159 block : bool [default: None]
158 Whether to wait for results or not. The default behavior is
160 Whether to wait for results or not. The default behavior is
159 to use the current `block` attribute of `view`
161 to use the current `block` attribute of `view`
160 chunksize : int or None
162 chunksize : int or None
161 The size of chunk to use when breaking up sequences in a load-balanced manner
163 The size of chunk to use when breaking up sequences in a load-balanced manner
162 ordered : bool [default: True]
164 ordered : bool [default: True]
163 Whether the result should be kept in order. If False,
165 Whether the result should be kept in order. If False,
164 results become available as they arrive, regardless of submission order.
166 results become available as they arrive, regardless of submission order.
165 **flags : remaining kwargs are passed to View.temp_flags
167 **flags
168 remaining kwargs are passed to View.temp_flags
166 """
169 """
167
170
168 chunksize = None
171 chunksize = None
169 ordered = None
172 ordered = None
170 mapObject = None
173 mapObject = None
171 _mapping = False
174 _mapping = False
172
175
173 def __init__(self, view, f, dist='b', block=None, chunksize=None, ordered=True, **flags):
176 def __init__(self, view, f, dist='b', block=None, chunksize=None, ordered=True, **flags):
174 super(ParallelFunction, self).__init__(view, f, block=block, **flags)
177 super(ParallelFunction, self).__init__(view, f, block=block, **flags)
175 self.chunksize = chunksize
178 self.chunksize = chunksize
176 self.ordered = ordered
179 self.ordered = ordered
177
180
178 mapClass = Map.dists[dist]
181 mapClass = Map.dists[dist]
179 self.mapObject = mapClass()
182 self.mapObject = mapClass()
180
183
181 @sync_view_results
184 @sync_view_results
182 def __call__(self, *sequences):
185 def __call__(self, *sequences):
183 client = self.view.client
186 client = self.view.client
184
187
185 lens = []
188 lens = []
186 maxlen = minlen = -1
189 maxlen = minlen = -1
187 for i, seq in enumerate(sequences):
190 for i, seq in enumerate(sequences):
188 try:
191 try:
189 n = len(seq)
192 n = len(seq)
190 except Exception:
193 except Exception:
191 seq = list(seq)
194 seq = list(seq)
192 if isinstance(sequences, tuple):
195 if isinstance(sequences, tuple):
193 # can't alter a tuple
196 # can't alter a tuple
194 sequences = list(sequences)
197 sequences = list(sequences)
195 sequences[i] = seq
198 sequences[i] = seq
196 n = len(seq)
199 n = len(seq)
197 if n > maxlen:
200 if n > maxlen:
198 maxlen = n
201 maxlen = n
199 if minlen == -1 or n < minlen:
202 if minlen == -1 or n < minlen:
200 minlen = n
203 minlen = n
201 lens.append(n)
204 lens.append(n)
202
205
203 # check that the length of sequences match
206 # check that the length of sequences match
204 if not self._mapping and minlen != maxlen:
207 if not self._mapping and minlen != maxlen:
205 msg = 'all sequences must have equal length, but have %s' % lens
208 msg = 'all sequences must have equal length, but have %s' % lens
206 raise ValueError(msg)
209 raise ValueError(msg)
207
210
208 balanced = 'Balanced' in self.view.__class__.__name__
211 balanced = 'Balanced' in self.view.__class__.__name__
209 if balanced:
212 if balanced:
210 if self.chunksize:
213 if self.chunksize:
211 nparts = maxlen // self.chunksize + int(maxlen % self.chunksize > 0)
214 nparts = maxlen // self.chunksize + int(maxlen % self.chunksize > 0)
212 else:
215 else:
213 nparts = maxlen
216 nparts = maxlen
214 targets = [None]*nparts
217 targets = [None]*nparts
215 else:
218 else:
216 if self.chunksize:
219 if self.chunksize:
217 warnings.warn("`chunksize` is ignored unless load balancing", UserWarning)
220 warnings.warn("`chunksize` is ignored unless load balancing", UserWarning)
218 # multiplexed:
221 # multiplexed:
219 targets = self.view.targets
222 targets = self.view.targets
220 # 'all' is lazily evaluated at execution time, which is now:
223 # 'all' is lazily evaluated at execution time, which is now:
221 if targets == 'all':
224 if targets == 'all':
222 targets = client._build_targets(targets)[1]
225 targets = client._build_targets(targets)[1]
223 elif isinstance(targets, int):
226 elif isinstance(targets, int):
224 # single-engine view, targets must be iterable
227 # single-engine view, targets must be iterable
225 targets = [targets]
228 targets = [targets]
226 nparts = len(targets)
229 nparts = len(targets)
227
230
228 msg_ids = []
231 msg_ids = []
229 for index, t in enumerate(targets):
232 for index, t in enumerate(targets):
230 args = []
233 args = []
231 for seq in sequences:
234 for seq in sequences:
232 part = self.mapObject.getPartition(seq, index, nparts, maxlen)
235 part = self.mapObject.getPartition(seq, index, nparts, maxlen)
233 args.append(part)
236 args.append(part)
234
237
235 if sum([len(arg) for arg in args]) == 0:
238 if sum([len(arg) for arg in args]) == 0:
236 continue
239 continue
237
240
238 if self._mapping:
241 if self._mapping:
239 if sys.version_info[0] >= 3:
242 if sys.version_info[0] >= 3:
240 f = lambda f, *sequences: list(map(f, *sequences))
243 f = lambda f, *sequences: list(map(f, *sequences))
241 else:
244 else:
242 f = map
245 f = map
243 args = [self.func] + args
246 args = [self.func] + args
244 else:
247 else:
245 f=self.func
248 f=self.func
246
249
247 view = self.view if balanced else client[t]
250 view = self.view if balanced else client[t]
248 with view.temp_flags(block=False, **self.flags):
251 with view.temp_flags(block=False, **self.flags):
249 ar = view.apply(f, *args)
252 ar = view.apply(f, *args)
250
253
251 msg_ids.extend(ar.msg_ids)
254 msg_ids.extend(ar.msg_ids)
252
255
253 r = AsyncMapResult(self.view.client, msg_ids, self.mapObject,
256 r = AsyncMapResult(self.view.client, msg_ids, self.mapObject,
254 fname=getname(self.func),
257 fname=getname(self.func),
255 ordered=self.ordered
258 ordered=self.ordered
256 )
259 )
257
260
258 if self.block:
261 if self.block:
259 try:
262 try:
260 return r.get()
263 return r.get()
261 except KeyboardInterrupt:
264 except KeyboardInterrupt:
262 return r
265 return r
263 else:
266 else:
264 return r
267 return r
265
268
266 def map(self, *sequences):
269 def map(self, *sequences):
267 """call a function on each element of one or more sequence(s) remotely.
270 """call a function on each element of one or more sequence(s) remotely.
268 This should behave very much like the builtin map, but return an AsyncMapResult
271 This should behave very much like the builtin map, but return an AsyncMapResult
269 if self.block is False.
272 if self.block is False.
270
273
271 That means it can take generators (will be cast to lists locally),
274 That means it can take generators (will be cast to lists locally),
272 and mismatched sequence lengths will be padded with None.
275 and mismatched sequence lengths will be padded with None.
273 """
276 """
274 # set _mapping as a flag for use inside self.__call__
277 # set _mapping as a flag for use inside self.__call__
275 self._mapping = True
278 self._mapping = True
276 try:
279 try:
277 ret = self(*sequences)
280 ret = self(*sequences)
278 finally:
281 finally:
279 self._mapping = False
282 self._mapping = False
280 return ret
283 return ret
281
284
282 __all__ = ['remote', 'parallel', 'RemoteFunction', 'ParallelFunction']
285 __all__ = ['remote', 'parallel', 'RemoteFunction', 'ParallelFunction']
@@ -1,1119 +1,1114 b''
1 """Views of remote engines.
1 """Views of remote engines.
2
2
3 Authors:
3 Authors:
4
4
5 * Min RK
5 * Min RK
6 """
6 """
7 from __future__ import print_function
7 from __future__ import print_function
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2010-2011 The IPython Development Team
9 # Copyright (C) 2010-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import imp
19 import imp
20 import sys
20 import sys
21 import warnings
21 import warnings
22 from contextlib import contextmanager
22 from contextlib import contextmanager
23 from types import ModuleType
23 from types import ModuleType
24
24
25 import zmq
25 import zmq
26
26
27 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.utils.traitlets import (
28 from IPython.utils.traitlets import (
29 HasTraits, Any, Bool, List, Dict, Set, Instance, CFloat, Integer
29 HasTraits, Any, Bool, List, Dict, Set, Instance, CFloat, Integer
30 )
30 )
31 from IPython.external.decorator import decorator
31 from IPython.external.decorator import decorator
32
32
33 from IPython.parallel import util
33 from IPython.parallel import util
34 from IPython.parallel.controller.dependency import Dependency, dependent
34 from IPython.parallel.controller.dependency import Dependency, dependent
35 from IPython.utils.py3compat import string_types, iteritems, PY3
35 from IPython.utils.py3compat import string_types, iteritems, PY3
36
36
37 from . import map as Map
37 from . import map as Map
38 from .asyncresult import AsyncResult, AsyncMapResult
38 from .asyncresult import AsyncResult, AsyncMapResult
39 from .remotefunction import ParallelFunction, parallel, remote, getname
39 from .remotefunction import ParallelFunction, parallel, remote, getname
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Decorators
42 # Decorators
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45 @decorator
45 @decorator
46 def save_ids(f, self, *args, **kwargs):
46 def save_ids(f, self, *args, **kwargs):
47 """Keep our history and outstanding attributes up to date after a method call."""
47 """Keep our history and outstanding attributes up to date after a method call."""
48 n_previous = len(self.client.history)
48 n_previous = len(self.client.history)
49 try:
49 try:
50 ret = f(self, *args, **kwargs)
50 ret = f(self, *args, **kwargs)
51 finally:
51 finally:
52 nmsgs = len(self.client.history) - n_previous
52 nmsgs = len(self.client.history) - n_previous
53 msg_ids = self.client.history[-nmsgs:]
53 msg_ids = self.client.history[-nmsgs:]
54 self.history.extend(msg_ids)
54 self.history.extend(msg_ids)
55 self.outstanding.update(msg_ids)
55 self.outstanding.update(msg_ids)
56 return ret
56 return ret
57
57
58 @decorator
58 @decorator
59 def sync_results(f, self, *args, **kwargs):
59 def sync_results(f, self, *args, **kwargs):
60 """sync relevant results from self.client to our results attribute."""
60 """sync relevant results from self.client to our results attribute."""
61 if self._in_sync_results:
61 if self._in_sync_results:
62 return f(self, *args, **kwargs)
62 return f(self, *args, **kwargs)
63 self._in_sync_results = True
63 self._in_sync_results = True
64 try:
64 try:
65 ret = f(self, *args, **kwargs)
65 ret = f(self, *args, **kwargs)
66 finally:
66 finally:
67 self._in_sync_results = False
67 self._in_sync_results = False
68 self._sync_results()
68 self._sync_results()
69 return ret
69 return ret
70
70
71 @decorator
71 @decorator
72 def spin_after(f, self, *args, **kwargs):
72 def spin_after(f, self, *args, **kwargs):
73 """call spin after the method."""
73 """call spin after the method."""
74 ret = f(self, *args, **kwargs)
74 ret = f(self, *args, **kwargs)
75 self.spin()
75 self.spin()
76 return ret
76 return ret
77
77
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79 # Classes
79 # Classes
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81
81
82 @skip_doctest
82 @skip_doctest
83 class View(HasTraits):
83 class View(HasTraits):
84 """Base View class for more convenint apply(f,*args,**kwargs) syntax via attributes.
84 """Base View class for more convenint apply(f,*args,**kwargs) syntax via attributes.
85
85
86 Don't use this class, use subclasses.
86 Don't use this class, use subclasses.
87
87
88 Methods
88 Methods
89 -------
89 -------
90
90
91 spin
91 spin
92 flushes incoming results and registration state changes
92 flushes incoming results and registration state changes
93 control methods spin, and requesting `ids` also ensures up to date
93 control methods spin, and requesting `ids` also ensures up to date
94
94
95 wait
95 wait
96 wait on one or more msg_ids
96 wait on one or more msg_ids
97
97
98 execution methods
98 execution methods
99 apply
99 apply
100 legacy: execute, run
100 legacy: execute, run
101
101
102 data movement
102 data movement
103 push, pull, scatter, gather
103 push, pull, scatter, gather
104
104
105 query methods
105 query methods
106 get_result, queue_status, purge_results, result_status
106 get_result, queue_status, purge_results, result_status
107
107
108 control methods
108 control methods
109 abort, shutdown
109 abort, shutdown
110
110
111 """
111 """
112 # flags
112 # flags
113 block=Bool(False)
113 block=Bool(False)
114 track=Bool(True)
114 track=Bool(True)
115 targets = Any()
115 targets = Any()
116
116
117 history=List()
117 history=List()
118 outstanding = Set()
118 outstanding = Set()
119 results = Dict()
119 results = Dict()
120 client = Instance('IPython.parallel.Client')
120 client = Instance('IPython.parallel.Client')
121
121
122 _socket = Instance('zmq.Socket')
122 _socket = Instance('zmq.Socket')
123 _flag_names = List(['targets', 'block', 'track'])
123 _flag_names = List(['targets', 'block', 'track'])
124 _in_sync_results = Bool(False)
124 _in_sync_results = Bool(False)
125 _targets = Any()
125 _targets = Any()
126 _idents = Any()
126 _idents = Any()
127
127
128 def __init__(self, client=None, socket=None, **flags):
128 def __init__(self, client=None, socket=None, **flags):
129 super(View, self).__init__(client=client, _socket=socket)
129 super(View, self).__init__(client=client, _socket=socket)
130 self.results = client.results
130 self.results = client.results
131 self.block = client.block
131 self.block = client.block
132
132
133 self.set_flags(**flags)
133 self.set_flags(**flags)
134
134
135 assert not self.__class__ is View, "Don't use base View objects, use subclasses"
135 assert not self.__class__ is View, "Don't use base View objects, use subclasses"
136
136
137 def __repr__(self):
137 def __repr__(self):
138 strtargets = str(self.targets)
138 strtargets = str(self.targets)
139 if len(strtargets) > 16:
139 if len(strtargets) > 16:
140 strtargets = strtargets[:12]+'...]'
140 strtargets = strtargets[:12]+'...]'
141 return "<%s %s>"%(self.__class__.__name__, strtargets)
141 return "<%s %s>"%(self.__class__.__name__, strtargets)
142
142
143 def __len__(self):
143 def __len__(self):
144 if isinstance(self.targets, list):
144 if isinstance(self.targets, list):
145 return len(self.targets)
145 return len(self.targets)
146 elif isinstance(self.targets, int):
146 elif isinstance(self.targets, int):
147 return 1
147 return 1
148 else:
148 else:
149 return len(self.client)
149 return len(self.client)
150
150
151 def set_flags(self, **kwargs):
151 def set_flags(self, **kwargs):
152 """set my attribute flags by keyword.
152 """set my attribute flags by keyword.
153
153
154 Views determine behavior with a few attributes (`block`, `track`, etc.).
154 Views determine behavior with a few attributes (`block`, `track`, etc.).
155 These attributes can be set all at once by name with this method.
155 These attributes can be set all at once by name with this method.
156
156
157 Parameters
157 Parameters
158 ----------
158 ----------
159
159
160 block : bool
160 block : bool
161 whether to wait for results
161 whether to wait for results
162 track : bool
162 track : bool
163 whether to create a MessageTracker to allow the user to
163 whether to create a MessageTracker to allow the user to
164 safely edit after arrays and buffers during non-copying
164 safely edit after arrays and buffers during non-copying
165 sends.
165 sends.
166 """
166 """
167 for name, value in iteritems(kwargs):
167 for name, value in iteritems(kwargs):
168 if name not in self._flag_names:
168 if name not in self._flag_names:
169 raise KeyError("Invalid name: %r"%name)
169 raise KeyError("Invalid name: %r"%name)
170 else:
170 else:
171 setattr(self, name, value)
171 setattr(self, name, value)
172
172
173 @contextmanager
173 @contextmanager
174 def temp_flags(self, **kwargs):
174 def temp_flags(self, **kwargs):
175 """temporarily set flags, for use in `with` statements.
175 """temporarily set flags, for use in `with` statements.
176
176
177 See set_flags for permanent setting of flags
177 See set_flags for permanent setting of flags
178
178
179 Examples
179 Examples
180 --------
180 --------
181
181
182 >>> view.track=False
182 >>> view.track=False
183 ...
183 ...
184 >>> with view.temp_flags(track=True):
184 >>> with view.temp_flags(track=True):
185 ... ar = view.apply(dostuff, my_big_array)
185 ... ar = view.apply(dostuff, my_big_array)
186 ... ar.tracker.wait() # wait for send to finish
186 ... ar.tracker.wait() # wait for send to finish
187 >>> view.track
187 >>> view.track
188 False
188 False
189
189
190 """
190 """
191 # preflight: save flags, and set temporaries
191 # preflight: save flags, and set temporaries
192 saved_flags = {}
192 saved_flags = {}
193 for f in self._flag_names:
193 for f in self._flag_names:
194 saved_flags[f] = getattr(self, f)
194 saved_flags[f] = getattr(self, f)
195 self.set_flags(**kwargs)
195 self.set_flags(**kwargs)
196 # yield to the with-statement block
196 # yield to the with-statement block
197 try:
197 try:
198 yield
198 yield
199 finally:
199 finally:
200 # postflight: restore saved flags
200 # postflight: restore saved flags
201 self.set_flags(**saved_flags)
201 self.set_flags(**saved_flags)
202
202
203
203
204 #----------------------------------------------------------------
204 #----------------------------------------------------------------
205 # apply
205 # apply
206 #----------------------------------------------------------------
206 #----------------------------------------------------------------
207
207
208 def _sync_results(self):
208 def _sync_results(self):
209 """to be called by @sync_results decorator
209 """to be called by @sync_results decorator
210
210
211 after submitting any tasks.
211 after submitting any tasks.
212 """
212 """
213 delta = self.outstanding.difference(self.client.outstanding)
213 delta = self.outstanding.difference(self.client.outstanding)
214 completed = self.outstanding.intersection(delta)
214 completed = self.outstanding.intersection(delta)
215 self.outstanding = self.outstanding.difference(completed)
215 self.outstanding = self.outstanding.difference(completed)
216
216
217 @sync_results
217 @sync_results
218 @save_ids
218 @save_ids
219 def _really_apply(self, f, args, kwargs, block=None, **options):
219 def _really_apply(self, f, args, kwargs, block=None, **options):
220 """wrapper for client.send_apply_request"""
220 """wrapper for client.send_apply_request"""
221 raise NotImplementedError("Implement in subclasses")
221 raise NotImplementedError("Implement in subclasses")
222
222
223 def apply(self, f, *args, **kwargs):
223 def apply(self, f, *args, **kwargs):
224 """calls f(*args, **kwargs) on remote engines, returning the result.
224 """calls ``f(*args, **kwargs)`` on remote engines, returning the result.
225
225
226 This method sets all apply flags via this View's attributes.
226 This method sets all apply flags via this View's attributes.
227
227
228 if self.block is False:
228 Returns :class:`~IPython.parallel.client.asyncresult.AsyncResult`
229 returns AsyncResult
229 instance if ``self.block`` is False, otherwise the return value of
230 else:
230 ``f(*args, **kwargs)``.
231 returns actual result of f(*args, **kwargs)
232 """
231 """
233 return self._really_apply(f, args, kwargs)
232 return self._really_apply(f, args, kwargs)
234
233
235 def apply_async(self, f, *args, **kwargs):
234 def apply_async(self, f, *args, **kwargs):
236 """calls f(*args, **kwargs) on remote engines in a nonblocking manner.
235 """calls ``f(*args, **kwargs)`` on remote engines in a nonblocking manner.
237
236
238 returns AsyncResult
237 Returns :class:`~IPython.parallel.client.asyncresult.AsyncResult` instance.
239 """
238 """
240 return self._really_apply(f, args, kwargs, block=False)
239 return self._really_apply(f, args, kwargs, block=False)
241
240
242 @spin_after
241 @spin_after
243 def apply_sync(self, f, *args, **kwargs):
242 def apply_sync(self, f, *args, **kwargs):
244 """calls f(*args, **kwargs) on remote engines in a blocking manner,
243 """calls ``f(*args, **kwargs)`` on remote engines in a blocking manner,
245 returning the result.
244 returning the result.
246
247 returns: actual result of f(*args, **kwargs)
248 """
245 """
249 return self._really_apply(f, args, kwargs, block=True)
246 return self._really_apply(f, args, kwargs, block=True)
250
247
251 #----------------------------------------------------------------
248 #----------------------------------------------------------------
252 # wrappers for client and control methods
249 # wrappers for client and control methods
253 #----------------------------------------------------------------
250 #----------------------------------------------------------------
254 @sync_results
251 @sync_results
255 def spin(self):
252 def spin(self):
256 """spin the client, and sync"""
253 """spin the client, and sync"""
257 self.client.spin()
254 self.client.spin()
258
255
259 @sync_results
256 @sync_results
260 def wait(self, jobs=None, timeout=-1):
257 def wait(self, jobs=None, timeout=-1):
261 """waits on one or more `jobs`, for up to `timeout` seconds.
258 """waits on one or more `jobs`, for up to `timeout` seconds.
262
259
263 Parameters
260 Parameters
264 ----------
261 ----------
265
262
266 jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects
263 jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects
267 ints are indices to self.history
264 ints are indices to self.history
268 strs are msg_ids
265 strs are msg_ids
269 default: wait on all outstanding messages
266 default: wait on all outstanding messages
270 timeout : float
267 timeout : float
271 a time in seconds, after which to give up.
268 a time in seconds, after which to give up.
272 default is -1, which means no timeout
269 default is -1, which means no timeout
273
270
274 Returns
271 Returns
275 -------
272 -------
276
273
277 True : when all msg_ids are done
274 True : when all msg_ids are done
278 False : timeout reached, some msg_ids still outstanding
275 False : timeout reached, some msg_ids still outstanding
279 """
276 """
280 if jobs is None:
277 if jobs is None:
281 jobs = self.history
278 jobs = self.history
282 return self.client.wait(jobs, timeout)
279 return self.client.wait(jobs, timeout)
283
280
284 def abort(self, jobs=None, targets=None, block=None):
281 def abort(self, jobs=None, targets=None, block=None):
285 """Abort jobs on my engines.
282 """Abort jobs on my engines.
286
283
287 Parameters
284 Parameters
288 ----------
285 ----------
289
286
290 jobs : None, str, list of strs, optional
287 jobs : None, str, list of strs, optional
291 if None: abort all jobs.
288 if None: abort all jobs.
292 else: abort specific msg_id(s).
289 else: abort specific msg_id(s).
293 """
290 """
294 block = block if block is not None else self.block
291 block = block if block is not None else self.block
295 targets = targets if targets is not None else self.targets
292 targets = targets if targets is not None else self.targets
296 jobs = jobs if jobs is not None else list(self.outstanding)
293 jobs = jobs if jobs is not None else list(self.outstanding)
297
294
298 return self.client.abort(jobs=jobs, targets=targets, block=block)
295 return self.client.abort(jobs=jobs, targets=targets, block=block)
299
296
300 def queue_status(self, targets=None, verbose=False):
297 def queue_status(self, targets=None, verbose=False):
301 """Fetch the Queue status of my engines"""
298 """Fetch the Queue status of my engines"""
302 targets = targets if targets is not None else self.targets
299 targets = targets if targets is not None else self.targets
303 return self.client.queue_status(targets=targets, verbose=verbose)
300 return self.client.queue_status(targets=targets, verbose=verbose)
304
301
305 def purge_results(self, jobs=[], targets=[]):
302 def purge_results(self, jobs=[], targets=[]):
306 """Instruct the controller to forget specific results."""
303 """Instruct the controller to forget specific results."""
307 if targets is None or targets == 'all':
304 if targets is None or targets == 'all':
308 targets = self.targets
305 targets = self.targets
309 return self.client.purge_results(jobs=jobs, targets=targets)
306 return self.client.purge_results(jobs=jobs, targets=targets)
310
307
311 def shutdown(self, targets=None, restart=False, hub=False, block=None):
308 def shutdown(self, targets=None, restart=False, hub=False, block=None):
312 """Terminates one or more engine processes, optionally including the hub.
309 """Terminates one or more engine processes, optionally including the hub.
313 """
310 """
314 block = self.block if block is None else block
311 block = self.block if block is None else block
315 if targets is None or targets == 'all':
312 if targets is None or targets == 'all':
316 targets = self.targets
313 targets = self.targets
317 return self.client.shutdown(targets=targets, restart=restart, hub=hub, block=block)
314 return self.client.shutdown(targets=targets, restart=restart, hub=hub, block=block)
318
315
319 @spin_after
316 @spin_after
320 def get_result(self, indices_or_msg_ids=None):
317 def get_result(self, indices_or_msg_ids=None):
321 """return one or more results, specified by history index or msg_id.
318 """return one or more results, specified by history index or msg_id.
322
319
323 See client.get_result for details.
320 See :meth:`IPython.parallel.client.client.Client.get_result` for details.
324
325 """
321 """
326
322
327 if indices_or_msg_ids is None:
323 if indices_or_msg_ids is None:
328 indices_or_msg_ids = -1
324 indices_or_msg_ids = -1
329 if isinstance(indices_or_msg_ids, int):
325 if isinstance(indices_or_msg_ids, int):
330 indices_or_msg_ids = self.history[indices_or_msg_ids]
326 indices_or_msg_ids = self.history[indices_or_msg_ids]
331 elif isinstance(indices_or_msg_ids, (list,tuple,set)):
327 elif isinstance(indices_or_msg_ids, (list,tuple,set)):
332 indices_or_msg_ids = list(indices_or_msg_ids)
328 indices_or_msg_ids = list(indices_or_msg_ids)
333 for i,index in enumerate(indices_or_msg_ids):
329 for i,index in enumerate(indices_or_msg_ids):
334 if isinstance(index, int):
330 if isinstance(index, int):
335 indices_or_msg_ids[i] = self.history[index]
331 indices_or_msg_ids[i] = self.history[index]
336 return self.client.get_result(indices_or_msg_ids)
332 return self.client.get_result(indices_or_msg_ids)
337
333
338 #-------------------------------------------------------------------
334 #-------------------------------------------------------------------
339 # Map
335 # Map
340 #-------------------------------------------------------------------
336 #-------------------------------------------------------------------
341
337
342 @sync_results
338 @sync_results
343 def map(self, f, *sequences, **kwargs):
339 def map(self, f, *sequences, **kwargs):
344 """override in subclasses"""
340 """override in subclasses"""
345 raise NotImplementedError
341 raise NotImplementedError
346
342
347 def map_async(self, f, *sequences, **kwargs):
343 def map_async(self, f, *sequences, **kwargs):
348 """Parallel version of builtin `map`, using this view's engines.
344 """Parallel version of builtin :func:`python:map`, using this view's engines.
349
345
350 This is equivalent to map(...block=False)
346 This is equivalent to ``map(...block=False)``.
351
347
352 See `self.map` for details.
348 See `self.map` for details.
353 """
349 """
354 if 'block' in kwargs:
350 if 'block' in kwargs:
355 raise TypeError("map_async doesn't take a `block` keyword argument.")
351 raise TypeError("map_async doesn't take a `block` keyword argument.")
356 kwargs['block'] = False
352 kwargs['block'] = False
357 return self.map(f,*sequences,**kwargs)
353 return self.map(f,*sequences,**kwargs)
358
354
359 def map_sync(self, f, *sequences, **kwargs):
355 def map_sync(self, f, *sequences, **kwargs):
360 """Parallel version of builtin `map`, using this view's engines.
356 """Parallel version of builtin :func:`python:map`, using this view's engines.
361
357
362 This is equivalent to map(...block=True)
358 This is equivalent to ``map(...block=True)``.
363
359
364 See `self.map` for details.
360 See `self.map` for details.
365 """
361 """
366 if 'block' in kwargs:
362 if 'block' in kwargs:
367 raise TypeError("map_sync doesn't take a `block` keyword argument.")
363 raise TypeError("map_sync doesn't take a `block` keyword argument.")
368 kwargs['block'] = True
364 kwargs['block'] = True
369 return self.map(f,*sequences,**kwargs)
365 return self.map(f,*sequences,**kwargs)
370
366
371 def imap(self, f, *sequences, **kwargs):
367 def imap(self, f, *sequences, **kwargs):
372 """Parallel version of `itertools.imap`.
368 """Parallel version of :func:`itertools.imap`.
373
369
374 See `self.map` for details.
370 See `self.map` for details.
375
371
376 """
372 """
377
373
378 return iter(self.map_async(f,*sequences, **kwargs))
374 return iter(self.map_async(f,*sequences, **kwargs))
379
375
380 #-------------------------------------------------------------------
376 #-------------------------------------------------------------------
381 # Decorators
377 # Decorators
382 #-------------------------------------------------------------------
378 #-------------------------------------------------------------------
383
379
384 def remote(self, block=None, **flags):
380 def remote(self, block=None, **flags):
385 """Decorator for making a RemoteFunction"""
381 """Decorator for making a RemoteFunction"""
386 block = self.block if block is None else block
382 block = self.block if block is None else block
387 return remote(self, block=block, **flags)
383 return remote(self, block=block, **flags)
388
384
389 def parallel(self, dist='b', block=None, **flags):
385 def parallel(self, dist='b', block=None, **flags):
390 """Decorator for making a ParallelFunction"""
386 """Decorator for making a ParallelFunction"""
391 block = self.block if block is None else block
387 block = self.block if block is None else block
392 return parallel(self, dist=dist, block=block, **flags)
388 return parallel(self, dist=dist, block=block, **flags)
393
389
394 @skip_doctest
390 @skip_doctest
395 class DirectView(View):
391 class DirectView(View):
396 """Direct Multiplexer View of one or more engines.
392 """Direct Multiplexer View of one or more engines.
397
393
398 These are created via indexed access to a client:
394 These are created via indexed access to a client:
399
395
400 >>> dv_1 = client[1]
396 >>> dv_1 = client[1]
401 >>> dv_all = client[:]
397 >>> dv_all = client[:]
402 >>> dv_even = client[::2]
398 >>> dv_even = client[::2]
403 >>> dv_some = client[1:3]
399 >>> dv_some = client[1:3]
404
400
405 This object provides dictionary access to engine namespaces:
401 This object provides dictionary access to engine namespaces:
406
402
407 # push a=5:
403 # push a=5:
408 >>> dv['a'] = 5
404 >>> dv['a'] = 5
409 # pull 'foo':
405 # pull 'foo':
410 >>> db['foo']
406 >>> db['foo']
411
407
412 """
408 """
413
409
414 def __init__(self, client=None, socket=None, targets=None):
410 def __init__(self, client=None, socket=None, targets=None):
415 super(DirectView, self).__init__(client=client, socket=socket, targets=targets)
411 super(DirectView, self).__init__(client=client, socket=socket, targets=targets)
416
412
417 @property
413 @property
418 def importer(self):
414 def importer(self):
419 """sync_imports(local=True) as a property.
415 """sync_imports(local=True) as a property.
420
416
421 See sync_imports for details.
417 See sync_imports for details.
422
418
423 """
419 """
424 return self.sync_imports(True)
420 return self.sync_imports(True)
425
421
426 @contextmanager
422 @contextmanager
427 def sync_imports(self, local=True, quiet=False):
423 def sync_imports(self, local=True, quiet=False):
428 """Context Manager for performing simultaneous local and remote imports.
424 """Context Manager for performing simultaneous local and remote imports.
429
425
430 'import x as y' will *not* work. The 'as y' part will simply be ignored.
426 'import x as y' will *not* work. The 'as y' part will simply be ignored.
431
427
432 If `local=True`, then the package will also be imported locally.
428 If `local=True`, then the package will also be imported locally.
433
429
434 If `quiet=True`, no output will be produced when attempting remote
430 If `quiet=True`, no output will be produced when attempting remote
435 imports.
431 imports.
436
432
437 Note that remote-only (`local=False`) imports have not been implemented.
433 Note that remote-only (`local=False`) imports have not been implemented.
438
434
439 >>> with view.sync_imports():
435 >>> with view.sync_imports():
440 ... from numpy import recarray
436 ... from numpy import recarray
441 importing recarray from numpy on engine(s)
437 importing recarray from numpy on engine(s)
442
438
443 """
439 """
444 from IPython.utils.py3compat import builtin_mod
440 from IPython.utils.py3compat import builtin_mod
445 local_import = builtin_mod.__import__
441 local_import = builtin_mod.__import__
446 modules = set()
442 modules = set()
447 results = []
443 results = []
448 @util.interactive
444 @util.interactive
449 def remote_import(name, fromlist, level):
445 def remote_import(name, fromlist, level):
450 """the function to be passed to apply, that actually performs the import
446 """the function to be passed to apply, that actually performs the import
451 on the engine, and loads up the user namespace.
447 on the engine, and loads up the user namespace.
452 """
448 """
453 import sys
449 import sys
454 user_ns = globals()
450 user_ns = globals()
455 mod = __import__(name, fromlist=fromlist, level=level)
451 mod = __import__(name, fromlist=fromlist, level=level)
456 if fromlist:
452 if fromlist:
457 for key in fromlist:
453 for key in fromlist:
458 user_ns[key] = getattr(mod, key)
454 user_ns[key] = getattr(mod, key)
459 else:
455 else:
460 user_ns[name] = sys.modules[name]
456 user_ns[name] = sys.modules[name]
461
457
462 def view_import(name, globals={}, locals={}, fromlist=[], level=0):
458 def view_import(name, globals={}, locals={}, fromlist=[], level=0):
463 """the drop-in replacement for __import__, that optionally imports
459 """the drop-in replacement for __import__, that optionally imports
464 locally as well.
460 locally as well.
465 """
461 """
466 # don't override nested imports
462 # don't override nested imports
467 save_import = builtin_mod.__import__
463 save_import = builtin_mod.__import__
468 builtin_mod.__import__ = local_import
464 builtin_mod.__import__ = local_import
469
465
470 if imp.lock_held():
466 if imp.lock_held():
471 # this is a side-effect import, don't do it remotely, or even
467 # this is a side-effect import, don't do it remotely, or even
472 # ignore the local effects
468 # ignore the local effects
473 return local_import(name, globals, locals, fromlist, level)
469 return local_import(name, globals, locals, fromlist, level)
474
470
475 imp.acquire_lock()
471 imp.acquire_lock()
476 if local:
472 if local:
477 mod = local_import(name, globals, locals, fromlist, level)
473 mod = local_import(name, globals, locals, fromlist, level)
478 else:
474 else:
479 raise NotImplementedError("remote-only imports not yet implemented")
475 raise NotImplementedError("remote-only imports not yet implemented")
480 imp.release_lock()
476 imp.release_lock()
481
477
482 key = name+':'+','.join(fromlist or [])
478 key = name+':'+','.join(fromlist or [])
483 if level <= 0 and key not in modules:
479 if level <= 0 and key not in modules:
484 modules.add(key)
480 modules.add(key)
485 if not quiet:
481 if not quiet:
486 if fromlist:
482 if fromlist:
487 print("importing %s from %s on engine(s)"%(','.join(fromlist), name))
483 print("importing %s from %s on engine(s)"%(','.join(fromlist), name))
488 else:
484 else:
489 print("importing %s on engine(s)"%name)
485 print("importing %s on engine(s)"%name)
490 results.append(self.apply_async(remote_import, name, fromlist, level))
486 results.append(self.apply_async(remote_import, name, fromlist, level))
491 # restore override
487 # restore override
492 builtin_mod.__import__ = save_import
488 builtin_mod.__import__ = save_import
493
489
494 return mod
490 return mod
495
491
496 # override __import__
492 # override __import__
497 builtin_mod.__import__ = view_import
493 builtin_mod.__import__ = view_import
498 try:
494 try:
499 # enter the block
495 # enter the block
500 yield
496 yield
501 except ImportError:
497 except ImportError:
502 if local:
498 if local:
503 raise
499 raise
504 else:
500 else:
505 # ignore import errors if not doing local imports
501 # ignore import errors if not doing local imports
506 pass
502 pass
507 finally:
503 finally:
508 # always restore __import__
504 # always restore __import__
509 builtin_mod.__import__ = local_import
505 builtin_mod.__import__ = local_import
510
506
511 for r in results:
507 for r in results:
512 # raise possible remote ImportErrors here
508 # raise possible remote ImportErrors here
513 r.get()
509 r.get()
514
510
515
511
516 @sync_results
512 @sync_results
517 @save_ids
513 @save_ids
518 def _really_apply(self, f, args=None, kwargs=None, targets=None, block=None, track=None):
514 def _really_apply(self, f, args=None, kwargs=None, targets=None, block=None, track=None):
519 """calls f(*args, **kwargs) on remote engines, returning the result.
515 """calls f(*args, **kwargs) on remote engines, returning the result.
520
516
521 This method sets all of `apply`'s flags via this View's attributes.
517 This method sets all of `apply`'s flags via this View's attributes.
522
518
523 Parameters
519 Parameters
524 ----------
520 ----------
525
521
526 f : callable
522 f : callable
527
523
528 args : list [default: empty]
524 args : list [default: empty]
529
525
530 kwargs : dict [default: empty]
526 kwargs : dict [default: empty]
531
527
532 targets : target list [default: self.targets]
528 targets : target list [default: self.targets]
533 where to run
529 where to run
534 block : bool [default: self.block]
530 block : bool [default: self.block]
535 whether to block
531 whether to block
536 track : bool [default: self.track]
532 track : bool [default: self.track]
537 whether to ask zmq to track the message, for safe non-copying sends
533 whether to ask zmq to track the message, for safe non-copying sends
538
534
539 Returns
535 Returns
540 -------
536 -------
541
537
542 if self.block is False:
538 if self.block is False:
543 returns AsyncResult
539 returns AsyncResult
544 else:
540 else:
545 returns actual result of f(*args, **kwargs) on the engine(s)
541 returns actual result of f(*args, **kwargs) on the engine(s)
546 This will be a list of self.targets is also a list (even length 1), or
542 This will be a list of self.targets is also a list (even length 1), or
547 the single result if self.targets is an integer engine id
543 the single result if self.targets is an integer engine id
548 """
544 """
549 args = [] if args is None else args
545 args = [] if args is None else args
550 kwargs = {} if kwargs is None else kwargs
546 kwargs = {} if kwargs is None else kwargs
551 block = self.block if block is None else block
547 block = self.block if block is None else block
552 track = self.track if track is None else track
548 track = self.track if track is None else track
553 targets = self.targets if targets is None else targets
549 targets = self.targets if targets is None else targets
554
550
555 _idents, _targets = self.client._build_targets(targets)
551 _idents, _targets = self.client._build_targets(targets)
556 msg_ids = []
552 msg_ids = []
557 trackers = []
553 trackers = []
558 for ident in _idents:
554 for ident in _idents:
559 msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track,
555 msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track,
560 ident=ident)
556 ident=ident)
561 if track:
557 if track:
562 trackers.append(msg['tracker'])
558 trackers.append(msg['tracker'])
563 msg_ids.append(msg['header']['msg_id'])
559 msg_ids.append(msg['header']['msg_id'])
564 if isinstance(targets, int):
560 if isinstance(targets, int):
565 msg_ids = msg_ids[0]
561 msg_ids = msg_ids[0]
566 tracker = None if track is False else zmq.MessageTracker(*trackers)
562 tracker = None if track is False else zmq.MessageTracker(*trackers)
567 ar = AsyncResult(self.client, msg_ids, fname=getname(f), targets=_targets, tracker=tracker)
563 ar = AsyncResult(self.client, msg_ids, fname=getname(f), targets=_targets, tracker=tracker)
568 if block:
564 if block:
569 try:
565 try:
570 return ar.get()
566 return ar.get()
571 except KeyboardInterrupt:
567 except KeyboardInterrupt:
572 pass
568 pass
573 return ar
569 return ar
574
570
575
571
576 @sync_results
572 @sync_results
577 def map(self, f, *sequences, **kwargs):
573 def map(self, f, *sequences, **kwargs):
578 """view.map(f, *sequences, block=self.block) => list|AsyncMapResult
574 """``view.map(f, *sequences, block=self.block)`` => list|AsyncMapResult
579
575
580 Parallel version of builtin `map`, using this View's `targets`.
576 Parallel version of builtin `map`, using this View's `targets`.
581
577
582 There will be one task per target, so work will be chunked
578 There will be one task per target, so work will be chunked
583 if the sequences are longer than `targets`.
579 if the sequences are longer than `targets`.
584
580
585 Results can be iterated as they are ready, but will become available in chunks.
581 Results can be iterated as they are ready, but will become available in chunks.
586
582
587 Parameters
583 Parameters
588 ----------
584 ----------
589
585
590 f : callable
586 f : callable
591 function to be mapped
587 function to be mapped
592 *sequences: one or more sequences of matching length
588 *sequences: one or more sequences of matching length
593 the sequences to be distributed and passed to `f`
589 the sequences to be distributed and passed to `f`
594 block : bool
590 block : bool
595 whether to wait for the result or not [default self.block]
591 whether to wait for the result or not [default self.block]
596
592
597 Returns
593 Returns
598 -------
594 -------
599
595
600 if block=False:
596
601 AsyncMapResult
597 If block=False
602 An object like AsyncResult, but which reassembles the sequence of results
598 An :class:`~IPython.parallel.client.asyncresult.AsyncMapResult` instance.
603 into a single list. AsyncMapResults can be iterated through before all
599 An object like AsyncResult, but which reassembles the sequence of results
604 results are complete.
600 into a single list. AsyncMapResults can be iterated through before all
605 else:
601 results are complete.
606 list
602 else
607 the result of map(f,*sequences)
603 A list, the result of ``map(f,*sequences)``
608 """
604 """
609
605
610 block = kwargs.pop('block', self.block)
606 block = kwargs.pop('block', self.block)
611 for k in kwargs.keys():
607 for k in kwargs.keys():
612 if k not in ['block', 'track']:
608 if k not in ['block', 'track']:
613 raise TypeError("invalid keyword arg, %r"%k)
609 raise TypeError("invalid keyword arg, %r"%k)
614
610
615 assert len(sequences) > 0, "must have some sequences to map onto!"
611 assert len(sequences) > 0, "must have some sequences to map onto!"
616 pf = ParallelFunction(self, f, block=block, **kwargs)
612 pf = ParallelFunction(self, f, block=block, **kwargs)
617 return pf.map(*sequences)
613 return pf.map(*sequences)
618
614
619 @sync_results
615 @sync_results
620 @save_ids
616 @save_ids
621 def execute(self, code, silent=True, targets=None, block=None):
617 def execute(self, code, silent=True, targets=None, block=None):
622 """Executes `code` on `targets` in blocking or nonblocking manner.
618 """Executes `code` on `targets` in blocking or nonblocking manner.
623
619
624 ``execute`` is always `bound` (affects engine namespace)
620 ``execute`` is always `bound` (affects engine namespace)
625
621
626 Parameters
622 Parameters
627 ----------
623 ----------
628
624
629 code : str
625 code : str
630 the code string to be executed
626 the code string to be executed
631 block : bool
627 block : bool
632 whether or not to wait until done to return
628 whether or not to wait until done to return
633 default: self.block
629 default: self.block
634 """
630 """
635 block = self.block if block is None else block
631 block = self.block if block is None else block
636 targets = self.targets if targets is None else targets
632 targets = self.targets if targets is None else targets
637
633
638 _idents, _targets = self.client._build_targets(targets)
634 _idents, _targets = self.client._build_targets(targets)
639 msg_ids = []
635 msg_ids = []
640 trackers = []
636 trackers = []
641 for ident in _idents:
637 for ident in _idents:
642 msg = self.client.send_execute_request(self._socket, code, silent=silent, ident=ident)
638 msg = self.client.send_execute_request(self._socket, code, silent=silent, ident=ident)
643 msg_ids.append(msg['header']['msg_id'])
639 msg_ids.append(msg['header']['msg_id'])
644 if isinstance(targets, int):
640 if isinstance(targets, int):
645 msg_ids = msg_ids[0]
641 msg_ids = msg_ids[0]
646 ar = AsyncResult(self.client, msg_ids, fname='execute', targets=_targets)
642 ar = AsyncResult(self.client, msg_ids, fname='execute', targets=_targets)
647 if block:
643 if block:
648 try:
644 try:
649 ar.get()
645 ar.get()
650 except KeyboardInterrupt:
646 except KeyboardInterrupt:
651 pass
647 pass
652 return ar
648 return ar
653
649
654 def run(self, filename, targets=None, block=None):
650 def run(self, filename, targets=None, block=None):
655 """Execute contents of `filename` on my engine(s).
651 """Execute contents of `filename` on my engine(s).
656
652
657 This simply reads the contents of the file and calls `execute`.
653 This simply reads the contents of the file and calls `execute`.
658
654
659 Parameters
655 Parameters
660 ----------
656 ----------
661
657
662 filename : str
658 filename : str
663 The path to the file
659 The path to the file
664 targets : int/str/list of ints/strs
660 targets : int/str/list of ints/strs
665 the engines on which to execute
661 the engines on which to execute
666 default : all
662 default : all
667 block : bool
663 block : bool
668 whether or not to wait until done
664 whether or not to wait until done
669 default: self.block
665 default: self.block
670
666
671 """
667 """
672 with open(filename, 'r') as f:
668 with open(filename, 'r') as f:
673 # add newline in case of trailing indented whitespace
669 # add newline in case of trailing indented whitespace
674 # which will cause SyntaxError
670 # which will cause SyntaxError
675 code = f.read()+'\n'
671 code = f.read()+'\n'
676 return self.execute(code, block=block, targets=targets)
672 return self.execute(code, block=block, targets=targets)
677
673
678 def update(self, ns):
674 def update(self, ns):
679 """update remote namespace with dict `ns`
675 """update remote namespace with dict `ns`
680
676
681 See `push` for details.
677 See `push` for details.
682 """
678 """
683 return self.push(ns, block=self.block, track=self.track)
679 return self.push(ns, block=self.block, track=self.track)
684
680
685 def push(self, ns, targets=None, block=None, track=None):
681 def push(self, ns, targets=None, block=None, track=None):
686 """update remote namespace with dict `ns`
682 """update remote namespace with dict `ns`
687
683
688 Parameters
684 Parameters
689 ----------
685 ----------
690
686
691 ns : dict
687 ns : dict
692 dict of keys with which to update engine namespace(s)
688 dict of keys with which to update engine namespace(s)
693 block : bool [default : self.block]
689 block : bool [default : self.block]
694 whether to wait to be notified of engine receipt
690 whether to wait to be notified of engine receipt
695
691
696 """
692 """
697
693
698 block = block if block is not None else self.block
694 block = block if block is not None else self.block
699 track = track if track is not None else self.track
695 track = track if track is not None else self.track
700 targets = targets if targets is not None else self.targets
696 targets = targets if targets is not None else self.targets
701 # applier = self.apply_sync if block else self.apply_async
697 # applier = self.apply_sync if block else self.apply_async
702 if not isinstance(ns, dict):
698 if not isinstance(ns, dict):
703 raise TypeError("Must be a dict, not %s"%type(ns))
699 raise TypeError("Must be a dict, not %s"%type(ns))
704 return self._really_apply(util._push, kwargs=ns, block=block, track=track, targets=targets)
700 return self._really_apply(util._push, kwargs=ns, block=block, track=track, targets=targets)
705
701
706 def get(self, key_s):
702 def get(self, key_s):
707 """get object(s) by `key_s` from remote namespace
703 """get object(s) by `key_s` from remote namespace
708
704
709 see `pull` for details.
705 see `pull` for details.
710 """
706 """
711 # block = block if block is not None else self.block
707 # block = block if block is not None else self.block
712 return self.pull(key_s, block=True)
708 return self.pull(key_s, block=True)
713
709
714 def pull(self, names, targets=None, block=None):
710 def pull(self, names, targets=None, block=None):
715 """get object(s) by `name` from remote namespace
711 """get object(s) by `name` from remote namespace
716
712
717 will return one object if it is a key.
713 will return one object if it is a key.
718 can also take a list of keys, in which case it will return a list of objects.
714 can also take a list of keys, in which case it will return a list of objects.
719 """
715 """
720 block = block if block is not None else self.block
716 block = block if block is not None else self.block
721 targets = targets if targets is not None else self.targets
717 targets = targets if targets is not None else self.targets
722 applier = self.apply_sync if block else self.apply_async
718 applier = self.apply_sync if block else self.apply_async
723 if isinstance(names, string_types):
719 if isinstance(names, string_types):
724 pass
720 pass
725 elif isinstance(names, (list,tuple,set)):
721 elif isinstance(names, (list,tuple,set)):
726 for key in names:
722 for key in names:
727 if not isinstance(key, string_types):
723 if not isinstance(key, string_types):
728 raise TypeError("keys must be str, not type %r"%type(key))
724 raise TypeError("keys must be str, not type %r"%type(key))
729 else:
725 else:
730 raise TypeError("names must be strs, not %r"%names)
726 raise TypeError("names must be strs, not %r"%names)
731 return self._really_apply(util._pull, (names,), block=block, targets=targets)
727 return self._really_apply(util._pull, (names,), block=block, targets=targets)
732
728
733 def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None, track=None):
729 def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None, track=None):
734 """
730 """
735 Partition a Python sequence and send the partitions to a set of engines.
731 Partition a Python sequence and send the partitions to a set of engines.
736 """
732 """
737 block = block if block is not None else self.block
733 block = block if block is not None else self.block
738 track = track if track is not None else self.track
734 track = track if track is not None else self.track
739 targets = targets if targets is not None else self.targets
735 targets = targets if targets is not None else self.targets
740
736
741 # construct integer ID list:
737 # construct integer ID list:
742 targets = self.client._build_targets(targets)[1]
738 targets = self.client._build_targets(targets)[1]
743
739
744 mapObject = Map.dists[dist]()
740 mapObject = Map.dists[dist]()
745 nparts = len(targets)
741 nparts = len(targets)
746 msg_ids = []
742 msg_ids = []
747 trackers = []
743 trackers = []
748 for index, engineid in enumerate(targets):
744 for index, engineid in enumerate(targets):
749 partition = mapObject.getPartition(seq, index, nparts)
745 partition = mapObject.getPartition(seq, index, nparts)
750 if flatten and len(partition) == 1:
746 if flatten and len(partition) == 1:
751 ns = {key: partition[0]}
747 ns = {key: partition[0]}
752 else:
748 else:
753 ns = {key: partition}
749 ns = {key: partition}
754 r = self.push(ns, block=False, track=track, targets=engineid)
750 r = self.push(ns, block=False, track=track, targets=engineid)
755 msg_ids.extend(r.msg_ids)
751 msg_ids.extend(r.msg_ids)
756 if track:
752 if track:
757 trackers.append(r._tracker)
753 trackers.append(r._tracker)
758
754
759 if track:
755 if track:
760 tracker = zmq.MessageTracker(*trackers)
756 tracker = zmq.MessageTracker(*trackers)
761 else:
757 else:
762 tracker = None
758 tracker = None
763
759
764 r = AsyncResult(self.client, msg_ids, fname='scatter', targets=targets, tracker=tracker)
760 r = AsyncResult(self.client, msg_ids, fname='scatter', targets=targets, tracker=tracker)
765 if block:
761 if block:
766 r.wait()
762 r.wait()
767 else:
763 else:
768 return r
764 return r
769
765
770 @sync_results
766 @sync_results
771 @save_ids
767 @save_ids
772 def gather(self, key, dist='b', targets=None, block=None):
768 def gather(self, key, dist='b', targets=None, block=None):
773 """
769 """
774 Gather a partitioned sequence on a set of engines as a single local seq.
770 Gather a partitioned sequence on a set of engines as a single local seq.
775 """
771 """
776 block = block if block is not None else self.block
772 block = block if block is not None else self.block
777 targets = targets if targets is not None else self.targets
773 targets = targets if targets is not None else self.targets
778 mapObject = Map.dists[dist]()
774 mapObject = Map.dists[dist]()
779 msg_ids = []
775 msg_ids = []
780
776
781 # construct integer ID list:
777 # construct integer ID list:
782 targets = self.client._build_targets(targets)[1]
778 targets = self.client._build_targets(targets)[1]
783
779
784 for index, engineid in enumerate(targets):
780 for index, engineid in enumerate(targets):
785 msg_ids.extend(self.pull(key, block=False, targets=engineid).msg_ids)
781 msg_ids.extend(self.pull(key, block=False, targets=engineid).msg_ids)
786
782
787 r = AsyncMapResult(self.client, msg_ids, mapObject, fname='gather')
783 r = AsyncMapResult(self.client, msg_ids, mapObject, fname='gather')
788
784
789 if block:
785 if block:
790 try:
786 try:
791 return r.get()
787 return r.get()
792 except KeyboardInterrupt:
788 except KeyboardInterrupt:
793 pass
789 pass
794 return r
790 return r
795
791
796 def __getitem__(self, key):
792 def __getitem__(self, key):
797 return self.get(key)
793 return self.get(key)
798
794
799 def __setitem__(self,key, value):
795 def __setitem__(self,key, value):
800 self.update({key:value})
796 self.update({key:value})
801
797
802 def clear(self, targets=None, block=None):
798 def clear(self, targets=None, block=None):
803 """Clear the remote namespaces on my engines."""
799 """Clear the remote namespaces on my engines."""
804 block = block if block is not None else self.block
800 block = block if block is not None else self.block
805 targets = targets if targets is not None else self.targets
801 targets = targets if targets is not None else self.targets
806 return self.client.clear(targets=targets, block=block)
802 return self.client.clear(targets=targets, block=block)
807
803
808 #----------------------------------------
804 #----------------------------------------
809 # activate for %px, %autopx, etc. magics
805 # activate for %px, %autopx, etc. magics
810 #----------------------------------------
806 #----------------------------------------
811
807
812 def activate(self, suffix=''):
808 def activate(self, suffix=''):
813 """Activate IPython magics associated with this View
809 """Activate IPython magics associated with this View
814
810
815 Defines the magics `%px, %autopx, %pxresult, %%px, %pxconfig`
811 Defines the magics `%px, %autopx, %pxresult, %%px, %pxconfig`
816
812
817 Parameters
813 Parameters
818 ----------
814 ----------
819
815
820 suffix: str [default: '']
816 suffix: str [default: '']
821 The suffix, if any, for the magics. This allows you to have
817 The suffix, if any, for the magics. This allows you to have
822 multiple views associated with parallel magics at the same time.
818 multiple views associated with parallel magics at the same time.
823
819
824 e.g. ``rc[::2].activate(suffix='_even')`` will give you
820 e.g. ``rc[::2].activate(suffix='_even')`` will give you
825 the magics ``%px_even``, ``%pxresult_even``, etc. for running magics
821 the magics ``%px_even``, ``%pxresult_even``, etc. for running magics
826 on the even engines.
822 on the even engines.
827 """
823 """
828
824
829 from IPython.parallel.client.magics import ParallelMagics
825 from IPython.parallel.client.magics import ParallelMagics
830
826
831 try:
827 try:
832 # This is injected into __builtins__.
828 # This is injected into __builtins__.
833 ip = get_ipython()
829 ip = get_ipython()
834 except NameError:
830 except NameError:
835 print("The IPython parallel magics (%px, etc.) only work within IPython.")
831 print("The IPython parallel magics (%px, etc.) only work within IPython.")
836 return
832 return
837
833
838 M = ParallelMagics(ip, self, suffix)
834 M = ParallelMagics(ip, self, suffix)
839 ip.magics_manager.register(M)
835 ip.magics_manager.register(M)
840
836
841
837
842 @skip_doctest
838 @skip_doctest
843 class LoadBalancedView(View):
839 class LoadBalancedView(View):
844 """An load-balancing View that only executes via the Task scheduler.
840 """An load-balancing View that only executes via the Task scheduler.
845
841
846 Load-balanced views can be created with the client's `view` method:
842 Load-balanced views can be created with the client's `view` method:
847
843
848 >>> v = client.load_balanced_view()
844 >>> v = client.load_balanced_view()
849
845
850 or targets can be specified, to restrict the potential destinations:
846 or targets can be specified, to restrict the potential destinations:
851
847
852 >>> v = client.client.load_balanced_view([1,3])
848 >>> v = client.client.load_balanced_view([1,3])
853
849
854 which would restrict loadbalancing to between engines 1 and 3.
850 which would restrict loadbalancing to between engines 1 and 3.
855
851
856 """
852 """
857
853
858 follow=Any()
854 follow=Any()
859 after=Any()
855 after=Any()
860 timeout=CFloat()
856 timeout=CFloat()
861 retries = Integer(0)
857 retries = Integer(0)
862
858
863 _task_scheme = Any()
859 _task_scheme = Any()
864 _flag_names = List(['targets', 'block', 'track', 'follow', 'after', 'timeout', 'retries'])
860 _flag_names = List(['targets', 'block', 'track', 'follow', 'after', 'timeout', 'retries'])
865
861
866 def __init__(self, client=None, socket=None, **flags):
862 def __init__(self, client=None, socket=None, **flags):
867 super(LoadBalancedView, self).__init__(client=client, socket=socket, **flags)
863 super(LoadBalancedView, self).__init__(client=client, socket=socket, **flags)
868 self._task_scheme=client._task_scheme
864 self._task_scheme=client._task_scheme
869
865
870 def _validate_dependency(self, dep):
866 def _validate_dependency(self, dep):
871 """validate a dependency.
867 """validate a dependency.
872
868
873 For use in `set_flags`.
869 For use in `set_flags`.
874 """
870 """
875 if dep is None or isinstance(dep, string_types + (AsyncResult, Dependency)):
871 if dep is None or isinstance(dep, string_types + (AsyncResult, Dependency)):
876 return True
872 return True
877 elif isinstance(dep, (list,set, tuple)):
873 elif isinstance(dep, (list,set, tuple)):
878 for d in dep:
874 for d in dep:
879 if not isinstance(d, string_types + (AsyncResult,)):
875 if not isinstance(d, string_types + (AsyncResult,)):
880 return False
876 return False
881 elif isinstance(dep, dict):
877 elif isinstance(dep, dict):
882 if set(dep.keys()) != set(Dependency().as_dict().keys()):
878 if set(dep.keys()) != set(Dependency().as_dict().keys()):
883 return False
879 return False
884 if not isinstance(dep['msg_ids'], list):
880 if not isinstance(dep['msg_ids'], list):
885 return False
881 return False
886 for d in dep['msg_ids']:
882 for d in dep['msg_ids']:
887 if not isinstance(d, string_types):
883 if not isinstance(d, string_types):
888 return False
884 return False
889 else:
885 else:
890 return False
886 return False
891
887
892 return True
888 return True
893
889
894 def _render_dependency(self, dep):
890 def _render_dependency(self, dep):
895 """helper for building jsonable dependencies from various input forms."""
891 """helper for building jsonable dependencies from various input forms."""
896 if isinstance(dep, Dependency):
892 if isinstance(dep, Dependency):
897 return dep.as_dict()
893 return dep.as_dict()
898 elif isinstance(dep, AsyncResult):
894 elif isinstance(dep, AsyncResult):
899 return dep.msg_ids
895 return dep.msg_ids
900 elif dep is None:
896 elif dep is None:
901 return []
897 return []
902 else:
898 else:
903 # pass to Dependency constructor
899 # pass to Dependency constructor
904 return list(Dependency(dep))
900 return list(Dependency(dep))
905
901
906 def set_flags(self, **kwargs):
902 def set_flags(self, **kwargs):
907 """set my attribute flags by keyword.
903 """set my attribute flags by keyword.
908
904
909 A View is a wrapper for the Client's apply method, but with attributes
905 A View is a wrapper for the Client's apply method, but with attributes
910 that specify keyword arguments, those attributes can be set by keyword
906 that specify keyword arguments, those attributes can be set by keyword
911 argument with this method.
907 argument with this method.
912
908
913 Parameters
909 Parameters
914 ----------
910 ----------
915
911
916 block : bool
912 block : bool
917 whether to wait for results
913 whether to wait for results
918 track : bool
914 track : bool
919 whether to create a MessageTracker to allow the user to
915 whether to create a MessageTracker to allow the user to
920 safely edit after arrays and buffers during non-copying
916 safely edit after arrays and buffers during non-copying
921 sends.
917 sends.
922
918
923 after : Dependency or collection of msg_ids
919 after : Dependency or collection of msg_ids
924 Only for load-balanced execution (targets=None)
920 Only for load-balanced execution (targets=None)
925 Specify a list of msg_ids as a time-based dependency.
921 Specify a list of msg_ids as a time-based dependency.
926 This job will only be run *after* the dependencies
922 This job will only be run *after* the dependencies
927 have been met.
923 have been met.
928
924
929 follow : Dependency or collection of msg_ids
925 follow : Dependency or collection of msg_ids
930 Only for load-balanced execution (targets=None)
926 Only for load-balanced execution (targets=None)
931 Specify a list of msg_ids as a location-based dependency.
927 Specify a list of msg_ids as a location-based dependency.
932 This job will only be run on an engine where this dependency
928 This job will only be run on an engine where this dependency
933 is met.
929 is met.
934
930
935 timeout : float/int or None
931 timeout : float/int or None
936 Only for load-balanced execution (targets=None)
932 Only for load-balanced execution (targets=None)
937 Specify an amount of time (in seconds) for the scheduler to
933 Specify an amount of time (in seconds) for the scheduler to
938 wait for dependencies to be met before failing with a
934 wait for dependencies to be met before failing with a
939 DependencyTimeout.
935 DependencyTimeout.
940
936
941 retries : int
937 retries : int
942 Number of times a task will be retried on failure.
938 Number of times a task will be retried on failure.
943 """
939 """
944
940
945 super(LoadBalancedView, self).set_flags(**kwargs)
941 super(LoadBalancedView, self).set_flags(**kwargs)
946 for name in ('follow', 'after'):
942 for name in ('follow', 'after'):
947 if name in kwargs:
943 if name in kwargs:
948 value = kwargs[name]
944 value = kwargs[name]
949 if self._validate_dependency(value):
945 if self._validate_dependency(value):
950 setattr(self, name, value)
946 setattr(self, name, value)
951 else:
947 else:
952 raise ValueError("Invalid dependency: %r"%value)
948 raise ValueError("Invalid dependency: %r"%value)
953 if 'timeout' in kwargs:
949 if 'timeout' in kwargs:
954 t = kwargs['timeout']
950 t = kwargs['timeout']
955 if not isinstance(t, (int, float, type(None))):
951 if not isinstance(t, (int, float, type(None))):
956 if (not PY3) and (not isinstance(t, long)):
952 if (not PY3) and (not isinstance(t, long)):
957 raise TypeError("Invalid type for timeout: %r"%type(t))
953 raise TypeError("Invalid type for timeout: %r"%type(t))
958 if t is not None:
954 if t is not None:
959 if t < 0:
955 if t < 0:
960 raise ValueError("Invalid timeout: %s"%t)
956 raise ValueError("Invalid timeout: %s"%t)
961 self.timeout = t
957 self.timeout = t
962
958
963 @sync_results
959 @sync_results
964 @save_ids
960 @save_ids
965 def _really_apply(self, f, args=None, kwargs=None, block=None, track=None,
961 def _really_apply(self, f, args=None, kwargs=None, block=None, track=None,
966 after=None, follow=None, timeout=None,
962 after=None, follow=None, timeout=None,
967 targets=None, retries=None):
963 targets=None, retries=None):
968 """calls f(*args, **kwargs) on a remote engine, returning the result.
964 """calls f(*args, **kwargs) on a remote engine, returning the result.
969
965
970 This method temporarily sets all of `apply`'s flags for a single call.
966 This method temporarily sets all of `apply`'s flags for a single call.
971
967
972 Parameters
968 Parameters
973 ----------
969 ----------
974
970
975 f : callable
971 f : callable
976
972
977 args : list [default: empty]
973 args : list [default: empty]
978
974
979 kwargs : dict [default: empty]
975 kwargs : dict [default: empty]
980
976
981 block : bool [default: self.block]
977 block : bool [default: self.block]
982 whether to block
978 whether to block
983 track : bool [default: self.track]
979 track : bool [default: self.track]
984 whether to ask zmq to track the message, for safe non-copying sends
980 whether to ask zmq to track the message, for safe non-copying sends
985
981
986 !!!!!! TODO: THE REST HERE !!!!
982 !!!!!! TODO: THE REST HERE !!!!
987
983
988 Returns
984 Returns
989 -------
985 -------
990
986
991 if self.block is False:
987 if self.block is False:
992 returns AsyncResult
988 returns AsyncResult
993 else:
989 else:
994 returns actual result of f(*args, **kwargs) on the engine(s)
990 returns actual result of f(*args, **kwargs) on the engine(s)
995 This will be a list of self.targets is also a list (even length 1), or
991 This will be a list of self.targets is also a list (even length 1), or
996 the single result if self.targets is an integer engine id
992 the single result if self.targets is an integer engine id
997 """
993 """
998
994
999 # validate whether we can run
995 # validate whether we can run
1000 if self._socket.closed:
996 if self._socket.closed:
1001 msg = "Task farming is disabled"
997 msg = "Task farming is disabled"
1002 if self._task_scheme == 'pure':
998 if self._task_scheme == 'pure':
1003 msg += " because the pure ZMQ scheduler cannot handle"
999 msg += " because the pure ZMQ scheduler cannot handle"
1004 msg += " disappearing engines."
1000 msg += " disappearing engines."
1005 raise RuntimeError(msg)
1001 raise RuntimeError(msg)
1006
1002
1007 if self._task_scheme == 'pure':
1003 if self._task_scheme == 'pure':
1008 # pure zmq scheme doesn't support extra features
1004 # pure zmq scheme doesn't support extra features
1009 msg = "Pure ZMQ scheduler doesn't support the following flags:"
1005 msg = "Pure ZMQ scheduler doesn't support the following flags:"
1010 "follow, after, retries, targets, timeout"
1006 "follow, after, retries, targets, timeout"
1011 if (follow or after or retries or targets or timeout):
1007 if (follow or after or retries or targets or timeout):
1012 # hard fail on Scheduler flags
1008 # hard fail on Scheduler flags
1013 raise RuntimeError(msg)
1009 raise RuntimeError(msg)
1014 if isinstance(f, dependent):
1010 if isinstance(f, dependent):
1015 # soft warn on functional dependencies
1011 # soft warn on functional dependencies
1016 warnings.warn(msg, RuntimeWarning)
1012 warnings.warn(msg, RuntimeWarning)
1017
1013
1018 # build args
1014 # build args
1019 args = [] if args is None else args
1015 args = [] if args is None else args
1020 kwargs = {} if kwargs is None else kwargs
1016 kwargs = {} if kwargs is None else kwargs
1021 block = self.block if block is None else block
1017 block = self.block if block is None else block
1022 track = self.track if track is None else track
1018 track = self.track if track is None else track
1023 after = self.after if after is None else after
1019 after = self.after if after is None else after
1024 retries = self.retries if retries is None else retries
1020 retries = self.retries if retries is None else retries
1025 follow = self.follow if follow is None else follow
1021 follow = self.follow if follow is None else follow
1026 timeout = self.timeout if timeout is None else timeout
1022 timeout = self.timeout if timeout is None else timeout
1027 targets = self.targets if targets is None else targets
1023 targets = self.targets if targets is None else targets
1028
1024
1029 if not isinstance(retries, int):
1025 if not isinstance(retries, int):
1030 raise TypeError('retries must be int, not %r'%type(retries))
1026 raise TypeError('retries must be int, not %r'%type(retries))
1031
1027
1032 if targets is None:
1028 if targets is None:
1033 idents = []
1029 idents = []
1034 else:
1030 else:
1035 idents = self.client._build_targets(targets)[0]
1031 idents = self.client._build_targets(targets)[0]
1036 # ensure *not* bytes
1032 # ensure *not* bytes
1037 idents = [ ident.decode() for ident in idents ]
1033 idents = [ ident.decode() for ident in idents ]
1038
1034
1039 after = self._render_dependency(after)
1035 after = self._render_dependency(after)
1040 follow = self._render_dependency(follow)
1036 follow = self._render_dependency(follow)
1041 metadata = dict(after=after, follow=follow, timeout=timeout, targets=idents, retries=retries)
1037 metadata = dict(after=after, follow=follow, timeout=timeout, targets=idents, retries=retries)
1042
1038
1043 msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track,
1039 msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track,
1044 metadata=metadata)
1040 metadata=metadata)
1045 tracker = None if track is False else msg['tracker']
1041 tracker = None if track is False else msg['tracker']
1046
1042
1047 ar = AsyncResult(self.client, msg['header']['msg_id'], fname=getname(f), targets=None, tracker=tracker)
1043 ar = AsyncResult(self.client, msg['header']['msg_id'], fname=getname(f), targets=None, tracker=tracker)
1048
1044
1049 if block:
1045 if block:
1050 try:
1046 try:
1051 return ar.get()
1047 return ar.get()
1052 except KeyboardInterrupt:
1048 except KeyboardInterrupt:
1053 pass
1049 pass
1054 return ar
1050 return ar
1055
1051
1056 @sync_results
1052 @sync_results
1057 @save_ids
1053 @save_ids
1058 def map(self, f, *sequences, **kwargs):
1054 def map(self, f, *sequences, **kwargs):
1059 """view.map(f, *sequences, block=self.block, chunksize=1, ordered=True) => list|AsyncMapResult
1055 """``view.map(f, *sequences, block=self.block, chunksize=1, ordered=True)`` => list|AsyncMapResult
1060
1056
1061 Parallel version of builtin `map`, load-balanced by this View.
1057 Parallel version of builtin `map`, load-balanced by this View.
1062
1058
1063 `block`, and `chunksize` can be specified by keyword only.
1059 `block`, and `chunksize` can be specified by keyword only.
1064
1060
1065 Each `chunksize` elements will be a separate task, and will be
1061 Each `chunksize` elements will be a separate task, and will be
1066 load-balanced. This lets individual elements be available for iteration
1062 load-balanced. This lets individual elements be available for iteration
1067 as soon as they arrive.
1063 as soon as they arrive.
1068
1064
1069 Parameters
1065 Parameters
1070 ----------
1066 ----------
1071
1067
1072 f : callable
1068 f : callable
1073 function to be mapped
1069 function to be mapped
1074 *sequences: one or more sequences of matching length
1070 *sequences: one or more sequences of matching length
1075 the sequences to be distributed and passed to `f`
1071 the sequences to be distributed and passed to `f`
1076 block : bool [default self.block]
1072 block : bool [default self.block]
1077 whether to wait for the result or not
1073 whether to wait for the result or not
1078 track : bool
1074 track : bool
1079 whether to create a MessageTracker to allow the user to
1075 whether to create a MessageTracker to allow the user to
1080 safely edit after arrays and buffers during non-copying
1076 safely edit after arrays and buffers during non-copying
1081 sends.
1077 sends.
1082 chunksize : int [default 1]
1078 chunksize : int [default 1]
1083 how many elements should be in each task.
1079 how many elements should be in each task.
1084 ordered : bool [default True]
1080 ordered : bool [default True]
1085 Whether the results should be gathered as they arrive, or enforce
1081 Whether the results should be gathered as they arrive, or enforce
1086 the order of submission.
1082 the order of submission.
1087
1083
1088 Only applies when iterating through AsyncMapResult as results arrive.
1084 Only applies when iterating through AsyncMapResult as results arrive.
1089 Has no effect when block=True.
1085 Has no effect when block=True.
1090
1086
1091 Returns
1087 Returns
1092 -------
1088 -------
1093
1089
1094 if block=False:
1090 if block=False
1095 AsyncMapResult
1091 An :class:`~IPython.parallel.client.asyncresult.AsyncMapResult` instance.
1096 An object like AsyncResult, but which reassembles the sequence of results
1092 An object like AsyncResult, but which reassembles the sequence of results
1097 into a single list. AsyncMapResults can be iterated through before all
1093 into a single list. AsyncMapResults can be iterated through before all
1098 results are complete.
1094 results are complete.
1099 else:
1095 else
1100 the result of map(f,*sequences)
1096 A list, the result of ``map(f,*sequences)``
1101
1102 """
1097 """
1103
1098
1104 # default
1099 # default
1105 block = kwargs.get('block', self.block)
1100 block = kwargs.get('block', self.block)
1106 chunksize = kwargs.get('chunksize', 1)
1101 chunksize = kwargs.get('chunksize', 1)
1107 ordered = kwargs.get('ordered', True)
1102 ordered = kwargs.get('ordered', True)
1108
1103
1109 keyset = set(kwargs.keys())
1104 keyset = set(kwargs.keys())
1110 extra_keys = keyset.difference_update(set(['block', 'chunksize']))
1105 extra_keys = keyset.difference_update(set(['block', 'chunksize']))
1111 if extra_keys:
1106 if extra_keys:
1112 raise TypeError("Invalid kwargs: %s"%list(extra_keys))
1107 raise TypeError("Invalid kwargs: %s"%list(extra_keys))
1113
1108
1114 assert len(sequences) > 0, "must have some sequences to map onto!"
1109 assert len(sequences) > 0, "must have some sequences to map onto!"
1115
1110
1116 pf = ParallelFunction(self, f, block=block, chunksize=chunksize, ordered=ordered)
1111 pf = ParallelFunction(self, f, block=block, chunksize=chunksize, ordered=ordered)
1117 return pf.map(*sequences)
1112 return pf.map(*sequences)
1118
1113
1119 __all__ = ['LoadBalancedView', 'DirectView']
1114 __all__ = ['LoadBalancedView', 'DirectView']
@@ -1,230 +1,229 b''
1 """Dependency utilities
1 """Dependency utilities
2
2
3 Authors:
3 Authors:
4
4
5 * Min RK
5 * Min RK
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2013 The IPython Development Team
8 # Copyright (C) 2013 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 from types import ModuleType
14 from types import ModuleType
15
15
16 from IPython.parallel.client.asyncresult import AsyncResult
16 from IPython.parallel.client.asyncresult import AsyncResult
17 from IPython.parallel.error import UnmetDependency
17 from IPython.parallel.error import UnmetDependency
18 from IPython.parallel.util import interactive
18 from IPython.parallel.util import interactive
19 from IPython.utils import py3compat
19 from IPython.utils import py3compat
20 from IPython.utils.py3compat import string_types
20 from IPython.utils.py3compat import string_types
21 from IPython.utils.pickleutil import can, uncan
21 from IPython.utils.pickleutil import can, uncan
22
22
23 class depend(object):
23 class depend(object):
24 """Dependency decorator, for use with tasks.
24 """Dependency decorator, for use with tasks.
25
25
26 `@depend` lets you define a function for engine dependencies
26 `@depend` lets you define a function for engine dependencies
27 just like you use `apply` for tasks.
27 just like you use `apply` for tasks.
28
28
29
29
30 Examples
30 Examples
31 --------
31 --------
32 ::
32 ::
33
33
34 @depend(df, a,b, c=5)
34 @depend(df, a,b, c=5)
35 def f(m,n,p)
35 def f(m,n,p)
36
36
37 view.apply(f, 1,2,3)
37 view.apply(f, 1,2,3)
38
38
39 will call df(a,b,c=5) on the engine, and if it returns False or
39 will call df(a,b,c=5) on the engine, and if it returns False or
40 raises an UnmetDependency error, then the task will not be run
40 raises an UnmetDependency error, then the task will not be run
41 and another engine will be tried.
41 and another engine will be tried.
42 """
42 """
43 def __init__(self, f, *args, **kwargs):
43 def __init__(self, f, *args, **kwargs):
44 self.f = f
44 self.f = f
45 self.args = args
45 self.args = args
46 self.kwargs = kwargs
46 self.kwargs = kwargs
47
47
48 def __call__(self, f):
48 def __call__(self, f):
49 return dependent(f, self.f, *self.args, **self.kwargs)
49 return dependent(f, self.f, *self.args, **self.kwargs)
50
50
51 class dependent(object):
51 class dependent(object):
52 """A function that depends on another function.
52 """A function that depends on another function.
53 This is an object to prevent the closure used
53 This is an object to prevent the closure used
54 in traditional decorators, which are not picklable.
54 in traditional decorators, which are not picklable.
55 """
55 """
56
56
57 def __init__(self, f, df, *dargs, **dkwargs):
57 def __init__(self, f, df, *dargs, **dkwargs):
58 self.f = f
58 self.f = f
59 name = getattr(f, '__name__', 'f')
59 name = getattr(f, '__name__', 'f')
60 if py3compat.PY3:
60 if py3compat.PY3:
61 self.__name__ = name
61 self.__name__ = name
62 else:
62 else:
63 self.func_name = name
63 self.func_name = name
64 self.df = df
64 self.df = df
65 self.dargs = dargs
65 self.dargs = dargs
66 self.dkwargs = dkwargs
66 self.dkwargs = dkwargs
67
67
68 def check_dependency(self):
68 def check_dependency(self):
69 if self.df(*self.dargs, **self.dkwargs) is False:
69 if self.df(*self.dargs, **self.dkwargs) is False:
70 raise UnmetDependency()
70 raise UnmetDependency()
71
71
72 def __call__(self, *args, **kwargs):
72 def __call__(self, *args, **kwargs):
73 return self.f(*args, **kwargs)
73 return self.f(*args, **kwargs)
74
74
75 if not py3compat.PY3:
75 if not py3compat.PY3:
76 @property
76 @property
77 def __name__(self):
77 def __name__(self):
78 return self.func_name
78 return self.func_name
79
79
80 @interactive
80 @interactive
81 def _require(*modules, **mapping):
81 def _require(*modules, **mapping):
82 """Helper for @require decorator."""
82 """Helper for @require decorator."""
83 from IPython.parallel.error import UnmetDependency
83 from IPython.parallel.error import UnmetDependency
84 from IPython.utils.pickleutil import uncan
84 from IPython.utils.pickleutil import uncan
85 user_ns = globals()
85 user_ns = globals()
86 for name in modules:
86 for name in modules:
87 try:
87 try:
88 exec('import %s' % name, user_ns)
88 exec('import %s' % name, user_ns)
89 except ImportError:
89 except ImportError:
90 raise UnmetDependency(name)
90 raise UnmetDependency(name)
91
91
92 for name, cobj in mapping.items():
92 for name, cobj in mapping.items():
93 user_ns[name] = uncan(cobj, user_ns)
93 user_ns[name] = uncan(cobj, user_ns)
94 return True
94 return True
95
95
96 def require(*objects, **mapping):
96 def require(*objects, **mapping):
97 """Simple decorator for requiring local objects and modules to be available
97 """Simple decorator for requiring local objects and modules to be available
98 when the decorated function is called on the engine.
98 when the decorated function is called on the engine.
99
99
100 Modules specified by name or passed directly will be imported
100 Modules specified by name or passed directly will be imported
101 prior to calling the decorated function.
101 prior to calling the decorated function.
102
102
103 Objects other than modules will be pushed as a part of the task.
103 Objects other than modules will be pushed as a part of the task.
104 Functions can be passed positionally,
104 Functions can be passed positionally,
105 and will be pushed to the engine with their __name__.
105 and will be pushed to the engine with their __name__.
106 Other objects can be passed by keyword arg.
106 Other objects can be passed by keyword arg.
107
107
108 Examples
108 Examples::
109 --------
110
109
111 In [1]: @require('numpy')
110 In [1]: @require('numpy')
112 ...: def norm(a):
111 ...: def norm(a):
113 ...: return numpy.linalg.norm(a,2)
112 ...: return numpy.linalg.norm(a,2)
114
113
115 In [2]: foo = lambda x: x*x
114 In [2]: foo = lambda x: x*x
116 In [3]: @require(foo)
115 In [3]: @require(foo)
117 ...: def bar(a):
116 ...: def bar(a):
118 ...: return foo(1-a)
117 ...: return foo(1-a)
119 """
118 """
120 names = []
119 names = []
121 for obj in objects:
120 for obj in objects:
122 if isinstance(obj, ModuleType):
121 if isinstance(obj, ModuleType):
123 obj = obj.__name__
122 obj = obj.__name__
124
123
125 if isinstance(obj, string_types):
124 if isinstance(obj, string_types):
126 names.append(obj)
125 names.append(obj)
127 elif hasattr(obj, '__name__'):
126 elif hasattr(obj, '__name__'):
128 mapping[obj.__name__] = obj
127 mapping[obj.__name__] = obj
129 else:
128 else:
130 raise TypeError("Objects other than modules and functions "
129 raise TypeError("Objects other than modules and functions "
131 "must be passed by kwarg, but got: %s" % type(obj)
130 "must be passed by kwarg, but got: %s" % type(obj)
132 )
131 )
133
132
134 for name, obj in mapping.items():
133 for name, obj in mapping.items():
135 mapping[name] = can(obj)
134 mapping[name] = can(obj)
136 return depend(_require, *names, **mapping)
135 return depend(_require, *names, **mapping)
137
136
138 class Dependency(set):
137 class Dependency(set):
139 """An object for representing a set of msg_id dependencies.
138 """An object for representing a set of msg_id dependencies.
140
139
141 Subclassed from set().
140 Subclassed from set().
142
141
143 Parameters
142 Parameters
144 ----------
143 ----------
145 dependencies: list/set of msg_ids or AsyncResult objects or output of Dependency.as_dict()
144 dependencies: list/set of msg_ids or AsyncResult objects or output of Dependency.as_dict()
146 The msg_ids to depend on
145 The msg_ids to depend on
147 all : bool [default True]
146 all : bool [default True]
148 Whether the dependency should be considered met when *all* depending tasks have completed
147 Whether the dependency should be considered met when *all* depending tasks have completed
149 or only when *any* have been completed.
148 or only when *any* have been completed.
150 success : bool [default True]
149 success : bool [default True]
151 Whether to consider successes as fulfilling dependencies.
150 Whether to consider successes as fulfilling dependencies.
152 failure : bool [default False]
151 failure : bool [default False]
153 Whether to consider failures as fulfilling dependencies.
152 Whether to consider failures as fulfilling dependencies.
154
153
155 If `all=success=True` and `failure=False`, then the task will fail with an ImpossibleDependency
154 If `all=success=True` and `failure=False`, then the task will fail with an ImpossibleDependency
156 as soon as the first depended-upon task fails.
155 as soon as the first depended-upon task fails.
157 """
156 """
158
157
159 all=True
158 all=True
160 success=True
159 success=True
161 failure=True
160 failure=True
162
161
163 def __init__(self, dependencies=[], all=True, success=True, failure=False):
162 def __init__(self, dependencies=[], all=True, success=True, failure=False):
164 if isinstance(dependencies, dict):
163 if isinstance(dependencies, dict):
165 # load from dict
164 # load from dict
166 all = dependencies.get('all', True)
165 all = dependencies.get('all', True)
167 success = dependencies.get('success', success)
166 success = dependencies.get('success', success)
168 failure = dependencies.get('failure', failure)
167 failure = dependencies.get('failure', failure)
169 dependencies = dependencies.get('dependencies', [])
168 dependencies = dependencies.get('dependencies', [])
170 ids = []
169 ids = []
171
170
172 # extract ids from various sources:
171 # extract ids from various sources:
173 if isinstance(dependencies, string_types + (AsyncResult,)):
172 if isinstance(dependencies, string_types + (AsyncResult,)):
174 dependencies = [dependencies]
173 dependencies = [dependencies]
175 for d in dependencies:
174 for d in dependencies:
176 if isinstance(d, string_types):
175 if isinstance(d, string_types):
177 ids.append(d)
176 ids.append(d)
178 elif isinstance(d, AsyncResult):
177 elif isinstance(d, AsyncResult):
179 ids.extend(d.msg_ids)
178 ids.extend(d.msg_ids)
180 else:
179 else:
181 raise TypeError("invalid dependency type: %r"%type(d))
180 raise TypeError("invalid dependency type: %r"%type(d))
182
181
183 set.__init__(self, ids)
182 set.__init__(self, ids)
184 self.all = all
183 self.all = all
185 if not (success or failure):
184 if not (success or failure):
186 raise ValueError("Must depend on at least one of successes or failures!")
185 raise ValueError("Must depend on at least one of successes or failures!")
187 self.success=success
186 self.success=success
188 self.failure = failure
187 self.failure = failure
189
188
190 def check(self, completed, failed=None):
189 def check(self, completed, failed=None):
191 """check whether our dependencies have been met."""
190 """check whether our dependencies have been met."""
192 if len(self) == 0:
191 if len(self) == 0:
193 return True
192 return True
194 against = set()
193 against = set()
195 if self.success:
194 if self.success:
196 against = completed
195 against = completed
197 if failed is not None and self.failure:
196 if failed is not None and self.failure:
198 against = against.union(failed)
197 against = against.union(failed)
199 if self.all:
198 if self.all:
200 return self.issubset(against)
199 return self.issubset(against)
201 else:
200 else:
202 return not self.isdisjoint(against)
201 return not self.isdisjoint(against)
203
202
204 def unreachable(self, completed, failed=None):
203 def unreachable(self, completed, failed=None):
205 """return whether this dependency has become impossible."""
204 """return whether this dependency has become impossible."""
206 if len(self) == 0:
205 if len(self) == 0:
207 return False
206 return False
208 against = set()
207 against = set()
209 if not self.success:
208 if not self.success:
210 against = completed
209 against = completed
211 if failed is not None and not self.failure:
210 if failed is not None and not self.failure:
212 against = against.union(failed)
211 against = against.union(failed)
213 if self.all:
212 if self.all:
214 return not self.isdisjoint(against)
213 return not self.isdisjoint(against)
215 else:
214 else:
216 return self.issubset(against)
215 return self.issubset(against)
217
216
218
217
219 def as_dict(self):
218 def as_dict(self):
220 """Represent this dependency as a dict. For json compatibility."""
219 """Represent this dependency as a dict. For json compatibility."""
221 return dict(
220 return dict(
222 dependencies=list(self),
221 dependencies=list(self),
223 all=self.all,
222 all=self.all,
224 success=self.success,
223 success=self.success,
225 failure=self.failure
224 failure=self.failure
226 )
225 )
227
226
228
227
229 __all__ = ['depend', 'require', 'dependent', 'Dependency']
228 __all__ = ['depend', 'require', 'dependent', 'Dependency']
230
229
@@ -1,312 +1,317 b''
1 """A Task logger that presents our DB interface,
1 """A Task logger that presents our DB interface,
2 but exists entirely in memory and implemented with dicts.
2 but exists entirely in memory and implemented with dicts.
3
3
4 Authors:
4 Authors:
5
5
6 * Min RK
6 * Min RK
7
7
8
8
9 TaskRecords are dicts of the form:
9 TaskRecords are dicts of the form::
10 {
10
11 'msg_id' : str(uuid),
11 {
12 'client_uuid' : str(uuid),
12 'msg_id' : str(uuid),
13 'engine_uuid' : str(uuid) or None,
13 'client_uuid' : str(uuid),
14 'header' : dict(header),
14 'engine_uuid' : str(uuid) or None,
15 'content': dict(content),
15 'header' : dict(header),
16 'buffers': list(buffers),
16 'content': dict(content),
17 'submitted': datetime,
17 'buffers': list(buffers),
18 'started': datetime or None,
18 'submitted': datetime,
19 'completed': datetime or None,
19 'started': datetime or None,
20 'resubmitted': datetime or None,
20 'completed': datetime or None,
21 'result_header' : dict(header) or None,
21 'resubmitted': datetime or None,
22 'result_content' : dict(content) or None,
22 'result_header' : dict(header) or None,
23 'result_buffers' : list(buffers) or None,
23 'result_content' : dict(content) or None,
24 }
24 'result_buffers' : list(buffers) or None,
25 With this info, many of the special categories of tasks can be defined by query:
25 }
26
26
27 pending: completed is None
27 With this info, many of the special categories of tasks can be defined by query,
28 client's outstanding: client_uuid = uuid && completed is None
28 e.g.:
29 MIA: arrived is None (and completed is None)
29
30 etc.
30 * pending: completed is None
31 * client's outstanding: client_uuid = uuid && completed is None
32 * MIA: arrived is None (and completed is None)
33
34 EngineRecords are dicts of the form::
35
36 {
37 'eid' : int(id),
38 'uuid': str(uuid)
39 }
31
40
32 EngineRecords are dicts of the form:
33 {
34 'eid' : int(id),
35 'uuid': str(uuid)
36 }
37 This may be extended, but is currently.
41 This may be extended, but is currently.
38
42
39 We support a subset of mongodb operators:
43 We support a subset of mongodb operators::
44
40 $lt,$gt,$lte,$gte,$ne,$in,$nin,$all,$mod,$exists
45 $lt,$gt,$lte,$gte,$ne,$in,$nin,$all,$mod,$exists
41 """
46 """
42 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
43 # Copyright (C) 2010-2011 The IPython Development Team
48 # Copyright (C) 2010-2011 The IPython Development Team
44 #
49 #
45 # Distributed under the terms of the BSD License. The full license is in
50 # Distributed under the terms of the BSD License. The full license is in
46 # the file COPYING, distributed as part of this software.
51 # the file COPYING, distributed as part of this software.
47 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
48
53
49 from copy import deepcopy as copy
54 from copy import deepcopy as copy
50 from datetime import datetime
55 from datetime import datetime
51
56
52 from IPython.config.configurable import LoggingConfigurable
57 from IPython.config.configurable import LoggingConfigurable
53
58
54 from IPython.utils.py3compat import iteritems, itervalues
59 from IPython.utils.py3compat import iteritems, itervalues
55 from IPython.utils.traitlets import Dict, Unicode, Integer, Float
60 from IPython.utils.traitlets import Dict, Unicode, Integer, Float
56
61
57 filters = {
62 filters = {
58 '$lt' : lambda a,b: a < b,
63 '$lt' : lambda a,b: a < b,
59 '$gt' : lambda a,b: b > a,
64 '$gt' : lambda a,b: b > a,
60 '$eq' : lambda a,b: a == b,
65 '$eq' : lambda a,b: a == b,
61 '$ne' : lambda a,b: a != b,
66 '$ne' : lambda a,b: a != b,
62 '$lte': lambda a,b: a <= b,
67 '$lte': lambda a,b: a <= b,
63 '$gte': lambda a,b: a >= b,
68 '$gte': lambda a,b: a >= b,
64 '$in' : lambda a,b: a in b,
69 '$in' : lambda a,b: a in b,
65 '$nin': lambda a,b: a not in b,
70 '$nin': lambda a,b: a not in b,
66 '$all': lambda a,b: all([ a in bb for bb in b ]),
71 '$all': lambda a,b: all([ a in bb for bb in b ]),
67 '$mod': lambda a,b: a%b[0] == b[1],
72 '$mod': lambda a,b: a%b[0] == b[1],
68 '$exists' : lambda a,b: (b and a is not None) or (a is None and not b)
73 '$exists' : lambda a,b: (b and a is not None) or (a is None and not b)
69 }
74 }
70
75
71
76
72 class CompositeFilter(object):
77 class CompositeFilter(object):
73 """Composite filter for matching multiple properties."""
78 """Composite filter for matching multiple properties."""
74
79
75 def __init__(self, dikt):
80 def __init__(self, dikt):
76 self.tests = []
81 self.tests = []
77 self.values = []
82 self.values = []
78 for key, value in iteritems(dikt):
83 for key, value in iteritems(dikt):
79 self.tests.append(filters[key])
84 self.tests.append(filters[key])
80 self.values.append(value)
85 self.values.append(value)
81
86
82 def __call__(self, value):
87 def __call__(self, value):
83 for test,check in zip(self.tests, self.values):
88 for test,check in zip(self.tests, self.values):
84 if not test(value, check):
89 if not test(value, check):
85 return False
90 return False
86 return True
91 return True
87
92
88 class BaseDB(LoggingConfigurable):
93 class BaseDB(LoggingConfigurable):
89 """Empty Parent class so traitlets work on DB."""
94 """Empty Parent class so traitlets work on DB."""
90 # base configurable traits:
95 # base configurable traits:
91 session = Unicode("")
96 session = Unicode("")
92
97
93 class DictDB(BaseDB):
98 class DictDB(BaseDB):
94 """Basic in-memory dict-based object for saving Task Records.
99 """Basic in-memory dict-based object for saving Task Records.
95
100
96 This is the first object to present the DB interface
101 This is the first object to present the DB interface
97 for logging tasks out of memory.
102 for logging tasks out of memory.
98
103
99 The interface is based on MongoDB, so adding a MongoDB
104 The interface is based on MongoDB, so adding a MongoDB
100 backend should be straightforward.
105 backend should be straightforward.
101 """
106 """
102
107
103 _records = Dict()
108 _records = Dict()
104 _culled_ids = set() # set of ids which have been culled
109 _culled_ids = set() # set of ids which have been culled
105 _buffer_bytes = Integer(0) # running total of the bytes in the DB
110 _buffer_bytes = Integer(0) # running total of the bytes in the DB
106
111
107 size_limit = Integer(1024**3, config=True,
112 size_limit = Integer(1024**3, config=True,
108 help="""The maximum total size (in bytes) of the buffers stored in the db
113 help="""The maximum total size (in bytes) of the buffers stored in the db
109
114
110 When the db exceeds this size, the oldest records will be culled until
115 When the db exceeds this size, the oldest records will be culled until
111 the total size is under size_limit * (1-cull_fraction).
116 the total size is under size_limit * (1-cull_fraction).
112 default: 1 GB
117 default: 1 GB
113 """
118 """
114 )
119 )
115 record_limit = Integer(1024, config=True,
120 record_limit = Integer(1024, config=True,
116 help="""The maximum number of records in the db
121 help="""The maximum number of records in the db
117
122
118 When the history exceeds this size, the first record_limit * cull_fraction
123 When the history exceeds this size, the first record_limit * cull_fraction
119 records will be culled.
124 records will be culled.
120 """
125 """
121 )
126 )
122 cull_fraction = Float(0.1, config=True,
127 cull_fraction = Float(0.1, config=True,
123 help="""The fraction by which the db should culled when one of the limits is exceeded
128 help="""The fraction by which the db should culled when one of the limits is exceeded
124
129
125 In general, the db size will spend most of its time with a size in the range:
130 In general, the db size will spend most of its time with a size in the range:
126
131
127 [limit * (1-cull_fraction), limit]
132 [limit * (1-cull_fraction), limit]
128
133
129 for each of size_limit and record_limit.
134 for each of size_limit and record_limit.
130 """
135 """
131 )
136 )
132
137
133 def _match_one(self, rec, tests):
138 def _match_one(self, rec, tests):
134 """Check if a specific record matches tests."""
139 """Check if a specific record matches tests."""
135 for key,test in iteritems(tests):
140 for key,test in iteritems(tests):
136 if not test(rec.get(key, None)):
141 if not test(rec.get(key, None)):
137 return False
142 return False
138 return True
143 return True
139
144
140 def _match(self, check):
145 def _match(self, check):
141 """Find all the matches for a check dict."""
146 """Find all the matches for a check dict."""
142 matches = []
147 matches = []
143 tests = {}
148 tests = {}
144 for k,v in iteritems(check):
149 for k,v in iteritems(check):
145 if isinstance(v, dict):
150 if isinstance(v, dict):
146 tests[k] = CompositeFilter(v)
151 tests[k] = CompositeFilter(v)
147 else:
152 else:
148 tests[k] = lambda o: o==v
153 tests[k] = lambda o: o==v
149
154
150 for rec in itervalues(self._records):
155 for rec in itervalues(self._records):
151 if self._match_one(rec, tests):
156 if self._match_one(rec, tests):
152 matches.append(copy(rec))
157 matches.append(copy(rec))
153 return matches
158 return matches
154
159
155 def _extract_subdict(self, rec, keys):
160 def _extract_subdict(self, rec, keys):
156 """extract subdict of keys"""
161 """extract subdict of keys"""
157 d = {}
162 d = {}
158 d['msg_id'] = rec['msg_id']
163 d['msg_id'] = rec['msg_id']
159 for key in keys:
164 for key in keys:
160 d[key] = rec[key]
165 d[key] = rec[key]
161 return copy(d)
166 return copy(d)
162
167
163 # methods for monitoring size / culling history
168 # methods for monitoring size / culling history
164
169
165 def _add_bytes(self, rec):
170 def _add_bytes(self, rec):
166 for key in ('buffers', 'result_buffers'):
171 for key in ('buffers', 'result_buffers'):
167 for buf in rec.get(key) or []:
172 for buf in rec.get(key) or []:
168 self._buffer_bytes += len(buf)
173 self._buffer_bytes += len(buf)
169
174
170 self._maybe_cull()
175 self._maybe_cull()
171
176
172 def _drop_bytes(self, rec):
177 def _drop_bytes(self, rec):
173 for key in ('buffers', 'result_buffers'):
178 for key in ('buffers', 'result_buffers'):
174 for buf in rec.get(key) or []:
179 for buf in rec.get(key) or []:
175 self._buffer_bytes -= len(buf)
180 self._buffer_bytes -= len(buf)
176
181
177 def _cull_oldest(self, n=1):
182 def _cull_oldest(self, n=1):
178 """cull the oldest N records"""
183 """cull the oldest N records"""
179 for msg_id in self.get_history()[:n]:
184 for msg_id in self.get_history()[:n]:
180 self.log.debug("Culling record: %r", msg_id)
185 self.log.debug("Culling record: %r", msg_id)
181 self._culled_ids.add(msg_id)
186 self._culled_ids.add(msg_id)
182 self.drop_record(msg_id)
187 self.drop_record(msg_id)
183
188
184 def _maybe_cull(self):
189 def _maybe_cull(self):
185 # cull by count:
190 # cull by count:
186 if len(self._records) > self.record_limit:
191 if len(self._records) > self.record_limit:
187 to_cull = int(self.cull_fraction * self.record_limit)
192 to_cull = int(self.cull_fraction * self.record_limit)
188 self.log.info("%i records exceeds limit of %i, culling oldest %i",
193 self.log.info("%i records exceeds limit of %i, culling oldest %i",
189 len(self._records), self.record_limit, to_cull
194 len(self._records), self.record_limit, to_cull
190 )
195 )
191 self._cull_oldest(to_cull)
196 self._cull_oldest(to_cull)
192
197
193 # cull by size:
198 # cull by size:
194 if self._buffer_bytes > self.size_limit:
199 if self._buffer_bytes > self.size_limit:
195 limit = self.size_limit * (1 - self.cull_fraction)
200 limit = self.size_limit * (1 - self.cull_fraction)
196
201
197 before = self._buffer_bytes
202 before = self._buffer_bytes
198 before_count = len(self._records)
203 before_count = len(self._records)
199 culled = 0
204 culled = 0
200 while self._buffer_bytes > limit:
205 while self._buffer_bytes > limit:
201 self._cull_oldest(1)
206 self._cull_oldest(1)
202 culled += 1
207 culled += 1
203
208
204 self.log.info("%i records with total buffer size %i exceeds limit: %i. Culled oldest %i records.",
209 self.log.info("%i records with total buffer size %i exceeds limit: %i. Culled oldest %i records.",
205 before_count, before, self.size_limit, culled
210 before_count, before, self.size_limit, culled
206 )
211 )
207
212
208 # public API methods:
213 # public API methods:
209
214
210 def add_record(self, msg_id, rec):
215 def add_record(self, msg_id, rec):
211 """Add a new Task Record, by msg_id."""
216 """Add a new Task Record, by msg_id."""
212 if msg_id in self._records:
217 if msg_id in self._records:
213 raise KeyError("Already have msg_id %r"%(msg_id))
218 raise KeyError("Already have msg_id %r"%(msg_id))
214 self._records[msg_id] = rec
219 self._records[msg_id] = rec
215 self._add_bytes(rec)
220 self._add_bytes(rec)
216 self._maybe_cull()
221 self._maybe_cull()
217
222
218 def get_record(self, msg_id):
223 def get_record(self, msg_id):
219 """Get a specific Task Record, by msg_id."""
224 """Get a specific Task Record, by msg_id."""
220 if msg_id in self._culled_ids:
225 if msg_id in self._culled_ids:
221 raise KeyError("Record %r has been culled for size" % msg_id)
226 raise KeyError("Record %r has been culled for size" % msg_id)
222 if not msg_id in self._records:
227 if not msg_id in self._records:
223 raise KeyError("No such msg_id %r"%(msg_id))
228 raise KeyError("No such msg_id %r"%(msg_id))
224 return copy(self._records[msg_id])
229 return copy(self._records[msg_id])
225
230
226 def update_record(self, msg_id, rec):
231 def update_record(self, msg_id, rec):
227 """Update the data in an existing record."""
232 """Update the data in an existing record."""
228 if msg_id in self._culled_ids:
233 if msg_id in self._culled_ids:
229 raise KeyError("Record %r has been culled for size" % msg_id)
234 raise KeyError("Record %r has been culled for size" % msg_id)
230 _rec = self._records[msg_id]
235 _rec = self._records[msg_id]
231 self._drop_bytes(_rec)
236 self._drop_bytes(_rec)
232 _rec.update(rec)
237 _rec.update(rec)
233 self._add_bytes(_rec)
238 self._add_bytes(_rec)
234
239
235 def drop_matching_records(self, check):
240 def drop_matching_records(self, check):
236 """Remove a record from the DB."""
241 """Remove a record from the DB."""
237 matches = self._match(check)
242 matches = self._match(check)
238 for rec in matches:
243 for rec in matches:
239 self._drop_bytes(rec)
244 self._drop_bytes(rec)
240 del self._records[rec['msg_id']]
245 del self._records[rec['msg_id']]
241
246
242 def drop_record(self, msg_id):
247 def drop_record(self, msg_id):
243 """Remove a record from the DB."""
248 """Remove a record from the DB."""
244 rec = self._records[msg_id]
249 rec = self._records[msg_id]
245 self._drop_bytes(rec)
250 self._drop_bytes(rec)
246 del self._records[msg_id]
251 del self._records[msg_id]
247
252
248 def find_records(self, check, keys=None):
253 def find_records(self, check, keys=None):
249 """Find records matching a query dict, optionally extracting subset of keys.
254 """Find records matching a query dict, optionally extracting subset of keys.
250
255
251 Returns dict keyed by msg_id of matching records.
256 Returns dict keyed by msg_id of matching records.
252
257
253 Parameters
258 Parameters
254 ----------
259 ----------
255
260
256 check: dict
261 check: dict
257 mongodb-style query argument
262 mongodb-style query argument
258 keys: list of strs [optional]
263 keys: list of strs [optional]
259 if specified, the subset of keys to extract. msg_id will *always* be
264 if specified, the subset of keys to extract. msg_id will *always* be
260 included.
265 included.
261 """
266 """
262 matches = self._match(check)
267 matches = self._match(check)
263 if keys:
268 if keys:
264 return [ self._extract_subdict(rec, keys) for rec in matches ]
269 return [ self._extract_subdict(rec, keys) for rec in matches ]
265 else:
270 else:
266 return matches
271 return matches
267
272
268 def get_history(self):
273 def get_history(self):
269 """get all msg_ids, ordered by time submitted."""
274 """get all msg_ids, ordered by time submitted."""
270 msg_ids = self._records.keys()
275 msg_ids = self._records.keys()
271 # Remove any that do not have a submitted timestamp.
276 # Remove any that do not have a submitted timestamp.
272 # This is extremely unlikely to happen,
277 # This is extremely unlikely to happen,
273 # but it seems to come up in some tests on VMs.
278 # but it seems to come up in some tests on VMs.
274 msg_ids = [ m for m in msg_ids if self._records[m]['submitted'] is not None ]
279 msg_ids = [ m for m in msg_ids if self._records[m]['submitted'] is not None ]
275 return sorted(msg_ids, key=lambda m: self._records[m]['submitted'])
280 return sorted(msg_ids, key=lambda m: self._records[m]['submitted'])
276
281
277
282
278 NODATA = KeyError("NoDB backend doesn't store any data. "
283 NODATA = KeyError("NoDB backend doesn't store any data. "
279 "Start the Controller with a DB backend to enable resubmission / result persistence."
284 "Start the Controller with a DB backend to enable resubmission / result persistence."
280 )
285 )
281
286
282
287
283 class NoDB(BaseDB):
288 class NoDB(BaseDB):
284 """A blackhole db backend that actually stores no information.
289 """A blackhole db backend that actually stores no information.
285
290
286 Provides the full DB interface, but raises KeyErrors on any
291 Provides the full DB interface, but raises KeyErrors on any
287 method that tries to access the records. This can be used to
292 method that tries to access the records. This can be used to
288 minimize the memory footprint of the Hub when its record-keeping
293 minimize the memory footprint of the Hub when its record-keeping
289 functionality is not required.
294 functionality is not required.
290 """
295 """
291
296
292 def add_record(self, msg_id, record):
297 def add_record(self, msg_id, record):
293 pass
298 pass
294
299
295 def get_record(self, msg_id):
300 def get_record(self, msg_id):
296 raise NODATA
301 raise NODATA
297
302
298 def update_record(self, msg_id, record):
303 def update_record(self, msg_id, record):
299 pass
304 pass
300
305
301 def drop_matching_records(self, check):
306 def drop_matching_records(self, check):
302 pass
307 pass
303
308
304 def drop_record(self, msg_id):
309 def drop_record(self, msg_id):
305 pass
310 pass
306
311
307 def find_records(self, check, keys=None):
312 def find_records(self, check, keys=None):
308 raise NODATA
313 raise NODATA
309
314
310 def get_history(self):
315 def get_history(self):
311 raise NODATA
316 raise NODATA
312
317
@@ -1,1422 +1,1426 b''
1 """The IPython Controller Hub with 0MQ
1 """The IPython Controller Hub with 0MQ
2 This is the master object that handles connections from engines and clients,
2 This is the master object that handles connections from engines and clients,
3 and monitors traffic through the various queues.
3 and monitors traffic through the various queues.
4
4
5 Authors:
5 Authors:
6
6
7 * Min RK
7 * Min RK
8 """
8 """
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010-2011 The IPython Development Team
10 # Copyright (C) 2010-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 from __future__ import print_function
19 from __future__ import print_function
20
20
21 import json
21 import json
22 import os
22 import os
23 import sys
23 import sys
24 import time
24 import time
25 from datetime import datetime
25 from datetime import datetime
26
26
27 import zmq
27 import zmq
28 from zmq.eventloop import ioloop
28 from zmq.eventloop import ioloop
29 from zmq.eventloop.zmqstream import ZMQStream
29 from zmq.eventloop.zmqstream import ZMQStream
30
30
31 # internal:
31 # internal:
32 from IPython.utils.importstring import import_item
32 from IPython.utils.importstring import import_item
33 from IPython.utils.jsonutil import extract_dates
33 from IPython.utils.jsonutil import extract_dates
34 from IPython.utils.localinterfaces import localhost
34 from IPython.utils.localinterfaces import localhost
35 from IPython.utils.py3compat import cast_bytes, unicode_type, iteritems
35 from IPython.utils.py3compat import cast_bytes, unicode_type, iteritems
36 from IPython.utils.traitlets import (
36 from IPython.utils.traitlets import (
37 HasTraits, Instance, Integer, Unicode, Dict, Set, Tuple, CBytes, DottedObjectName
37 HasTraits, Instance, Integer, Unicode, Dict, Set, Tuple, CBytes, DottedObjectName
38 )
38 )
39
39
40 from IPython.parallel import error, util
40 from IPython.parallel import error, util
41 from IPython.parallel.factory import RegistrationFactory
41 from IPython.parallel.factory import RegistrationFactory
42
42
43 from IPython.kernel.zmq.session import SessionFactory
43 from IPython.kernel.zmq.session import SessionFactory
44
44
45 from .heartmonitor import HeartMonitor
45 from .heartmonitor import HeartMonitor
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Code
48 # Code
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51 def _passer(*args, **kwargs):
51 def _passer(*args, **kwargs):
52 return
52 return
53
53
54 def _printer(*args, **kwargs):
54 def _printer(*args, **kwargs):
55 print (args)
55 print (args)
56 print (kwargs)
56 print (kwargs)
57
57
58 def empty_record():
58 def empty_record():
59 """Return an empty dict with all record keys."""
59 """Return an empty dict with all record keys."""
60 return {
60 return {
61 'msg_id' : None,
61 'msg_id' : None,
62 'header' : None,
62 'header' : None,
63 'metadata' : None,
63 'metadata' : None,
64 'content': None,
64 'content': None,
65 'buffers': None,
65 'buffers': None,
66 'submitted': None,
66 'submitted': None,
67 'client_uuid' : None,
67 'client_uuid' : None,
68 'engine_uuid' : None,
68 'engine_uuid' : None,
69 'started': None,
69 'started': None,
70 'completed': None,
70 'completed': None,
71 'resubmitted': None,
71 'resubmitted': None,
72 'received': None,
72 'received': None,
73 'result_header' : None,
73 'result_header' : None,
74 'result_metadata' : None,
74 'result_metadata' : None,
75 'result_content' : None,
75 'result_content' : None,
76 'result_buffers' : None,
76 'result_buffers' : None,
77 'queue' : None,
77 'queue' : None,
78 'pyin' : None,
78 'pyin' : None,
79 'pyout': None,
79 'pyout': None,
80 'pyerr': None,
80 'pyerr': None,
81 'stdout': '',
81 'stdout': '',
82 'stderr': '',
82 'stderr': '',
83 }
83 }
84
84
85 def init_record(msg):
85 def init_record(msg):
86 """Initialize a TaskRecord based on a request."""
86 """Initialize a TaskRecord based on a request."""
87 header = msg['header']
87 header = msg['header']
88 return {
88 return {
89 'msg_id' : header['msg_id'],
89 'msg_id' : header['msg_id'],
90 'header' : header,
90 'header' : header,
91 'content': msg['content'],
91 'content': msg['content'],
92 'metadata': msg['metadata'],
92 'metadata': msg['metadata'],
93 'buffers': msg['buffers'],
93 'buffers': msg['buffers'],
94 'submitted': header['date'],
94 'submitted': header['date'],
95 'client_uuid' : None,
95 'client_uuid' : None,
96 'engine_uuid' : None,
96 'engine_uuid' : None,
97 'started': None,
97 'started': None,
98 'completed': None,
98 'completed': None,
99 'resubmitted': None,
99 'resubmitted': None,
100 'received': None,
100 'received': None,
101 'result_header' : None,
101 'result_header' : None,
102 'result_metadata': None,
102 'result_metadata': None,
103 'result_content' : None,
103 'result_content' : None,
104 'result_buffers' : None,
104 'result_buffers' : None,
105 'queue' : None,
105 'queue' : None,
106 'pyin' : None,
106 'pyin' : None,
107 'pyout': None,
107 'pyout': None,
108 'pyerr': None,
108 'pyerr': None,
109 'stdout': '',
109 'stdout': '',
110 'stderr': '',
110 'stderr': '',
111 }
111 }
112
112
113
113
114 class EngineConnector(HasTraits):
114 class EngineConnector(HasTraits):
115 """A simple object for accessing the various zmq connections of an object.
115 """A simple object for accessing the various zmq connections of an object.
116 Attributes are:
116 Attributes are:
117 id (int): engine ID
117 id (int): engine ID
118 uuid (unicode): engine UUID
118 uuid (unicode): engine UUID
119 pending: set of msg_ids
119 pending: set of msg_ids
120 stallback: DelayedCallback for stalled registration
120 stallback: DelayedCallback for stalled registration
121 """
121 """
122
122
123 id = Integer(0)
123 id = Integer(0)
124 uuid = Unicode()
124 uuid = Unicode()
125 pending = Set()
125 pending = Set()
126 stallback = Instance(ioloop.DelayedCallback)
126 stallback = Instance(ioloop.DelayedCallback)
127
127
128
128
129 _db_shortcuts = {
129 _db_shortcuts = {
130 'sqlitedb' : 'IPython.parallel.controller.sqlitedb.SQLiteDB',
130 'sqlitedb' : 'IPython.parallel.controller.sqlitedb.SQLiteDB',
131 'mongodb' : 'IPython.parallel.controller.mongodb.MongoDB',
131 'mongodb' : 'IPython.parallel.controller.mongodb.MongoDB',
132 'dictdb' : 'IPython.parallel.controller.dictdb.DictDB',
132 'dictdb' : 'IPython.parallel.controller.dictdb.DictDB',
133 'nodb' : 'IPython.parallel.controller.dictdb.NoDB',
133 'nodb' : 'IPython.parallel.controller.dictdb.NoDB',
134 }
134 }
135
135
136 class HubFactory(RegistrationFactory):
136 class HubFactory(RegistrationFactory):
137 """The Configurable for setting up a Hub."""
137 """The Configurable for setting up a Hub."""
138
138
139 # port-pairs for monitoredqueues:
139 # port-pairs for monitoredqueues:
140 hb = Tuple(Integer,Integer,config=True,
140 hb = Tuple(Integer,Integer,config=True,
141 help="""PUB/ROUTER Port pair for Engine heartbeats""")
141 help="""PUB/ROUTER Port pair for Engine heartbeats""")
142 def _hb_default(self):
142 def _hb_default(self):
143 return tuple(util.select_random_ports(2))
143 return tuple(util.select_random_ports(2))
144
144
145 mux = Tuple(Integer,Integer,config=True,
145 mux = Tuple(Integer,Integer,config=True,
146 help="""Client/Engine Port pair for MUX queue""")
146 help="""Client/Engine Port pair for MUX queue""")
147
147
148 def _mux_default(self):
148 def _mux_default(self):
149 return tuple(util.select_random_ports(2))
149 return tuple(util.select_random_ports(2))
150
150
151 task = Tuple(Integer,Integer,config=True,
151 task = Tuple(Integer,Integer,config=True,
152 help="""Client/Engine Port pair for Task queue""")
152 help="""Client/Engine Port pair for Task queue""")
153 def _task_default(self):
153 def _task_default(self):
154 return tuple(util.select_random_ports(2))
154 return tuple(util.select_random_ports(2))
155
155
156 control = Tuple(Integer,Integer,config=True,
156 control = Tuple(Integer,Integer,config=True,
157 help="""Client/Engine Port pair for Control queue""")
157 help="""Client/Engine Port pair for Control queue""")
158
158
159 def _control_default(self):
159 def _control_default(self):
160 return tuple(util.select_random_ports(2))
160 return tuple(util.select_random_ports(2))
161
161
162 iopub = Tuple(Integer,Integer,config=True,
162 iopub = Tuple(Integer,Integer,config=True,
163 help="""Client/Engine Port pair for IOPub relay""")
163 help="""Client/Engine Port pair for IOPub relay""")
164
164
165 def _iopub_default(self):
165 def _iopub_default(self):
166 return tuple(util.select_random_ports(2))
166 return tuple(util.select_random_ports(2))
167
167
168 # single ports:
168 # single ports:
169 mon_port = Integer(config=True,
169 mon_port = Integer(config=True,
170 help="""Monitor (SUB) port for queue traffic""")
170 help="""Monitor (SUB) port for queue traffic""")
171
171
172 def _mon_port_default(self):
172 def _mon_port_default(self):
173 return util.select_random_ports(1)[0]
173 return util.select_random_ports(1)[0]
174
174
175 notifier_port = Integer(config=True,
175 notifier_port = Integer(config=True,
176 help="""PUB port for sending engine status notifications""")
176 help="""PUB port for sending engine status notifications""")
177
177
178 def _notifier_port_default(self):
178 def _notifier_port_default(self):
179 return util.select_random_ports(1)[0]
179 return util.select_random_ports(1)[0]
180
180
181 engine_ip = Unicode(config=True,
181 engine_ip = Unicode(config=True,
182 help="IP on which to listen for engine connections. [default: loopback]")
182 help="IP on which to listen for engine connections. [default: loopback]")
183 def _engine_ip_default(self):
183 def _engine_ip_default(self):
184 return localhost()
184 return localhost()
185 engine_transport = Unicode('tcp', config=True,
185 engine_transport = Unicode('tcp', config=True,
186 help="0MQ transport for engine connections. [default: tcp]")
186 help="0MQ transport for engine connections. [default: tcp]")
187
187
188 client_ip = Unicode(config=True,
188 client_ip = Unicode(config=True,
189 help="IP on which to listen for client connections. [default: loopback]")
189 help="IP on which to listen for client connections. [default: loopback]")
190 client_transport = Unicode('tcp', config=True,
190 client_transport = Unicode('tcp', config=True,
191 help="0MQ transport for client connections. [default : tcp]")
191 help="0MQ transport for client connections. [default : tcp]")
192
192
193 monitor_ip = Unicode(config=True,
193 monitor_ip = Unicode(config=True,
194 help="IP on which to listen for monitor messages. [default: loopback]")
194 help="IP on which to listen for monitor messages. [default: loopback]")
195 monitor_transport = Unicode('tcp', config=True,
195 monitor_transport = Unicode('tcp', config=True,
196 help="0MQ transport for monitor messages. [default : tcp]")
196 help="0MQ transport for monitor messages. [default : tcp]")
197
197
198 _client_ip_default = _monitor_ip_default = _engine_ip_default
198 _client_ip_default = _monitor_ip_default = _engine_ip_default
199
199
200
200
201 monitor_url = Unicode('')
201 monitor_url = Unicode('')
202
202
203 db_class = DottedObjectName('NoDB',
203 db_class = DottedObjectName('NoDB',
204 config=True, help="""The class to use for the DB backend
204 config=True, help="""The class to use for the DB backend
205
205
206 Options include:
206 Options include:
207
207
208 SQLiteDB: SQLite
208 SQLiteDB: SQLite
209 MongoDB : use MongoDB
209 MongoDB : use MongoDB
210 DictDB : in-memory storage (fastest, but be mindful of memory growth of the Hub)
210 DictDB : in-memory storage (fastest, but be mindful of memory growth of the Hub)
211 NoDB : disable database altogether (default)
211 NoDB : disable database altogether (default)
212
212
213 """)
213 """)
214
214
215 # not configurable
215 # not configurable
216 db = Instance('IPython.parallel.controller.dictdb.BaseDB')
216 db = Instance('IPython.parallel.controller.dictdb.BaseDB')
217 heartmonitor = Instance('IPython.parallel.controller.heartmonitor.HeartMonitor')
217 heartmonitor = Instance('IPython.parallel.controller.heartmonitor.HeartMonitor')
218
218
219 def _ip_changed(self, name, old, new):
219 def _ip_changed(self, name, old, new):
220 self.engine_ip = new
220 self.engine_ip = new
221 self.client_ip = new
221 self.client_ip = new
222 self.monitor_ip = new
222 self.monitor_ip = new
223 self._update_monitor_url()
223 self._update_monitor_url()
224
224
225 def _update_monitor_url(self):
225 def _update_monitor_url(self):
226 self.monitor_url = "%s://%s:%i" % (self.monitor_transport, self.monitor_ip, self.mon_port)
226 self.monitor_url = "%s://%s:%i" % (self.monitor_transport, self.monitor_ip, self.mon_port)
227
227
228 def _transport_changed(self, name, old, new):
228 def _transport_changed(self, name, old, new):
229 self.engine_transport = new
229 self.engine_transport = new
230 self.client_transport = new
230 self.client_transport = new
231 self.monitor_transport = new
231 self.monitor_transport = new
232 self._update_monitor_url()
232 self._update_monitor_url()
233
233
234 def __init__(self, **kwargs):
234 def __init__(self, **kwargs):
235 super(HubFactory, self).__init__(**kwargs)
235 super(HubFactory, self).__init__(**kwargs)
236 self._update_monitor_url()
236 self._update_monitor_url()
237
237
238
238
239 def construct(self):
239 def construct(self):
240 self.init_hub()
240 self.init_hub()
241
241
242 def start(self):
242 def start(self):
243 self.heartmonitor.start()
243 self.heartmonitor.start()
244 self.log.info("Heartmonitor started")
244 self.log.info("Heartmonitor started")
245
245
246 def client_url(self, channel):
246 def client_url(self, channel):
247 """return full zmq url for a named client channel"""
247 """return full zmq url for a named client channel"""
248 return "%s://%s:%i" % (self.client_transport, self.client_ip, self.client_info[channel])
248 return "%s://%s:%i" % (self.client_transport, self.client_ip, self.client_info[channel])
249
249
250 def engine_url(self, channel):
250 def engine_url(self, channel):
251 """return full zmq url for a named engine channel"""
251 """return full zmq url for a named engine channel"""
252 return "%s://%s:%i" % (self.engine_transport, self.engine_ip, self.engine_info[channel])
252 return "%s://%s:%i" % (self.engine_transport, self.engine_ip, self.engine_info[channel])
253
253
254 def init_hub(self):
254 def init_hub(self):
255 """construct Hub object"""
255 """construct Hub object"""
256
256
257 ctx = self.context
257 ctx = self.context
258 loop = self.loop
258 loop = self.loop
259 if 'TaskScheduler.scheme_name' in self.config:
259 if 'TaskScheduler.scheme_name' in self.config:
260 scheme = self.config.TaskScheduler.scheme_name
260 scheme = self.config.TaskScheduler.scheme_name
261 else:
261 else:
262 from .scheduler import TaskScheduler
262 from .scheduler import TaskScheduler
263 scheme = TaskScheduler.scheme_name.get_default_value()
263 scheme = TaskScheduler.scheme_name.get_default_value()
264
264
265 # build connection dicts
265 # build connection dicts
266 engine = self.engine_info = {
266 engine = self.engine_info = {
267 'interface' : "%s://%s" % (self.engine_transport, self.engine_ip),
267 'interface' : "%s://%s" % (self.engine_transport, self.engine_ip),
268 'registration' : self.regport,
268 'registration' : self.regport,
269 'control' : self.control[1],
269 'control' : self.control[1],
270 'mux' : self.mux[1],
270 'mux' : self.mux[1],
271 'hb_ping' : self.hb[0],
271 'hb_ping' : self.hb[0],
272 'hb_pong' : self.hb[1],
272 'hb_pong' : self.hb[1],
273 'task' : self.task[1],
273 'task' : self.task[1],
274 'iopub' : self.iopub[1],
274 'iopub' : self.iopub[1],
275 }
275 }
276
276
277 client = self.client_info = {
277 client = self.client_info = {
278 'interface' : "%s://%s" % (self.client_transport, self.client_ip),
278 'interface' : "%s://%s" % (self.client_transport, self.client_ip),
279 'registration' : self.regport,
279 'registration' : self.regport,
280 'control' : self.control[0],
280 'control' : self.control[0],
281 'mux' : self.mux[0],
281 'mux' : self.mux[0],
282 'task' : self.task[0],
282 'task' : self.task[0],
283 'task_scheme' : scheme,
283 'task_scheme' : scheme,
284 'iopub' : self.iopub[0],
284 'iopub' : self.iopub[0],
285 'notification' : self.notifier_port,
285 'notification' : self.notifier_port,
286 }
286 }
287
287
288 self.log.debug("Hub engine addrs: %s", self.engine_info)
288 self.log.debug("Hub engine addrs: %s", self.engine_info)
289 self.log.debug("Hub client addrs: %s", self.client_info)
289 self.log.debug("Hub client addrs: %s", self.client_info)
290
290
291 # Registrar socket
291 # Registrar socket
292 q = ZMQStream(ctx.socket(zmq.ROUTER), loop)
292 q = ZMQStream(ctx.socket(zmq.ROUTER), loop)
293 util.set_hwm(q, 0)
293 util.set_hwm(q, 0)
294 q.bind(self.client_url('registration'))
294 q.bind(self.client_url('registration'))
295 self.log.info("Hub listening on %s for registration.", self.client_url('registration'))
295 self.log.info("Hub listening on %s for registration.", self.client_url('registration'))
296 if self.client_ip != self.engine_ip:
296 if self.client_ip != self.engine_ip:
297 q.bind(self.engine_url('registration'))
297 q.bind(self.engine_url('registration'))
298 self.log.info("Hub listening on %s for registration.", self.engine_url('registration'))
298 self.log.info("Hub listening on %s for registration.", self.engine_url('registration'))
299
299
300 ### Engine connections ###
300 ### Engine connections ###
301
301
302 # heartbeat
302 # heartbeat
303 hpub = ctx.socket(zmq.PUB)
303 hpub = ctx.socket(zmq.PUB)
304 hpub.bind(self.engine_url('hb_ping'))
304 hpub.bind(self.engine_url('hb_ping'))
305 hrep = ctx.socket(zmq.ROUTER)
305 hrep = ctx.socket(zmq.ROUTER)
306 util.set_hwm(hrep, 0)
306 util.set_hwm(hrep, 0)
307 hrep.bind(self.engine_url('hb_pong'))
307 hrep.bind(self.engine_url('hb_pong'))
308 self.heartmonitor = HeartMonitor(loop=loop, parent=self, log=self.log,
308 self.heartmonitor = HeartMonitor(loop=loop, parent=self, log=self.log,
309 pingstream=ZMQStream(hpub,loop),
309 pingstream=ZMQStream(hpub,loop),
310 pongstream=ZMQStream(hrep,loop)
310 pongstream=ZMQStream(hrep,loop)
311 )
311 )
312
312
313 ### Client connections ###
313 ### Client connections ###
314
314
315 # Notifier socket
315 # Notifier socket
316 n = ZMQStream(ctx.socket(zmq.PUB), loop)
316 n = ZMQStream(ctx.socket(zmq.PUB), loop)
317 n.bind(self.client_url('notification'))
317 n.bind(self.client_url('notification'))
318
318
319 ### build and launch the queues ###
319 ### build and launch the queues ###
320
320
321 # monitor socket
321 # monitor socket
322 sub = ctx.socket(zmq.SUB)
322 sub = ctx.socket(zmq.SUB)
323 sub.setsockopt(zmq.SUBSCRIBE, b"")
323 sub.setsockopt(zmq.SUBSCRIBE, b"")
324 sub.bind(self.monitor_url)
324 sub.bind(self.monitor_url)
325 sub.bind('inproc://monitor')
325 sub.bind('inproc://monitor')
326 sub = ZMQStream(sub, loop)
326 sub = ZMQStream(sub, loop)
327
327
328 # connect the db
328 # connect the db
329 db_class = _db_shortcuts.get(self.db_class.lower(), self.db_class)
329 db_class = _db_shortcuts.get(self.db_class.lower(), self.db_class)
330 self.log.info('Hub using DB backend: %r', (db_class.split('.')[-1]))
330 self.log.info('Hub using DB backend: %r', (db_class.split('.')[-1]))
331 self.db = import_item(str(db_class))(session=self.session.session,
331 self.db = import_item(str(db_class))(session=self.session.session,
332 parent=self, log=self.log)
332 parent=self, log=self.log)
333 time.sleep(.25)
333 time.sleep(.25)
334
334
335 # resubmit stream
335 # resubmit stream
336 r = ZMQStream(ctx.socket(zmq.DEALER), loop)
336 r = ZMQStream(ctx.socket(zmq.DEALER), loop)
337 url = util.disambiguate_url(self.client_url('task'))
337 url = util.disambiguate_url(self.client_url('task'))
338 r.connect(url)
338 r.connect(url)
339
339
340 self.hub = Hub(loop=loop, session=self.session, monitor=sub, heartmonitor=self.heartmonitor,
340 self.hub = Hub(loop=loop, session=self.session, monitor=sub, heartmonitor=self.heartmonitor,
341 query=q, notifier=n, resubmit=r, db=self.db,
341 query=q, notifier=n, resubmit=r, db=self.db,
342 engine_info=self.engine_info, client_info=self.client_info,
342 engine_info=self.engine_info, client_info=self.client_info,
343 log=self.log)
343 log=self.log)
344
344
345
345
346 class Hub(SessionFactory):
346 class Hub(SessionFactory):
347 """The IPython Controller Hub with 0MQ connections
347 """The IPython Controller Hub with 0MQ connections
348
348
349 Parameters
349 Parameters
350 ==========
350 ==========
351 loop: zmq IOLoop instance
351 loop: zmq IOLoop instance
352 session: Session object
352 session: Session object
353 <removed> context: zmq context for creating new connections (?)
353 <removed> context: zmq context for creating new connections (?)
354 queue: ZMQStream for monitoring the command queue (SUB)
354 queue: ZMQStream for monitoring the command queue (SUB)
355 query: ZMQStream for engine registration and client queries requests (ROUTER)
355 query: ZMQStream for engine registration and client queries requests (ROUTER)
356 heartbeat: HeartMonitor object checking the pulse of the engines
356 heartbeat: HeartMonitor object checking the pulse of the engines
357 notifier: ZMQStream for broadcasting engine registration changes (PUB)
357 notifier: ZMQStream for broadcasting engine registration changes (PUB)
358 db: connection to db for out of memory logging of commands
358 db: connection to db for out of memory logging of commands
359 NotImplemented
359 NotImplemented
360 engine_info: dict of zmq connection information for engines to connect
360 engine_info: dict of zmq connection information for engines to connect
361 to the queues.
361 to the queues.
362 client_info: dict of zmq connection information for engines to connect
362 client_info: dict of zmq connection information for engines to connect
363 to the queues.
363 to the queues.
364 """
364 """
365
365
366 engine_state_file = Unicode()
366 engine_state_file = Unicode()
367
367
368 # internal data structures:
368 # internal data structures:
369 ids=Set() # engine IDs
369 ids=Set() # engine IDs
370 keytable=Dict()
370 keytable=Dict()
371 by_ident=Dict()
371 by_ident=Dict()
372 engines=Dict()
372 engines=Dict()
373 clients=Dict()
373 clients=Dict()
374 hearts=Dict()
374 hearts=Dict()
375 pending=Set()
375 pending=Set()
376 queues=Dict() # pending msg_ids keyed by engine_id
376 queues=Dict() # pending msg_ids keyed by engine_id
377 tasks=Dict() # pending msg_ids submitted as tasks, keyed by client_id
377 tasks=Dict() # pending msg_ids submitted as tasks, keyed by client_id
378 completed=Dict() # completed msg_ids keyed by engine_id
378 completed=Dict() # completed msg_ids keyed by engine_id
379 all_completed=Set() # completed msg_ids keyed by engine_id
379 all_completed=Set() # completed msg_ids keyed by engine_id
380 dead_engines=Set() # completed msg_ids keyed by engine_id
380 dead_engines=Set() # completed msg_ids keyed by engine_id
381 unassigned=Set() # set of task msg_ds not yet assigned a destination
381 unassigned=Set() # set of task msg_ds not yet assigned a destination
382 incoming_registrations=Dict()
382 incoming_registrations=Dict()
383 registration_timeout=Integer()
383 registration_timeout=Integer()
384 _idcounter=Integer(0)
384 _idcounter=Integer(0)
385
385
386 # objects from constructor:
386 # objects from constructor:
387 query=Instance(ZMQStream)
387 query=Instance(ZMQStream)
388 monitor=Instance(ZMQStream)
388 monitor=Instance(ZMQStream)
389 notifier=Instance(ZMQStream)
389 notifier=Instance(ZMQStream)
390 resubmit=Instance(ZMQStream)
390 resubmit=Instance(ZMQStream)
391 heartmonitor=Instance(HeartMonitor)
391 heartmonitor=Instance(HeartMonitor)
392 db=Instance(object)
392 db=Instance(object)
393 client_info=Dict()
393 client_info=Dict()
394 engine_info=Dict()
394 engine_info=Dict()
395
395
396
396
397 def __init__(self, **kwargs):
397 def __init__(self, **kwargs):
398 """
398 """
399 # universal:
399 # universal:
400 loop: IOLoop for creating future connections
400 loop: IOLoop for creating future connections
401 session: streamsession for sending serialized data
401 session: streamsession for sending serialized data
402 # engine:
402 # engine:
403 queue: ZMQStream for monitoring queue messages
403 queue: ZMQStream for monitoring queue messages
404 query: ZMQStream for engine+client registration and client requests
404 query: ZMQStream for engine+client registration and client requests
405 heartbeat: HeartMonitor object for tracking engines
405 heartbeat: HeartMonitor object for tracking engines
406 # extra:
406 # extra:
407 db: ZMQStream for db connection (NotImplemented)
407 db: ZMQStream for db connection (NotImplemented)
408 engine_info: zmq address/protocol dict for engine connections
408 engine_info: zmq address/protocol dict for engine connections
409 client_info: zmq address/protocol dict for client connections
409 client_info: zmq address/protocol dict for client connections
410 """
410 """
411
411
412 super(Hub, self).__init__(**kwargs)
412 super(Hub, self).__init__(**kwargs)
413 self.registration_timeout = max(10000, 5*self.heartmonitor.period)
413 self.registration_timeout = max(10000, 5*self.heartmonitor.period)
414
414
415 # register our callbacks
415 # register our callbacks
416 self.query.on_recv(self.dispatch_query)
416 self.query.on_recv(self.dispatch_query)
417 self.monitor.on_recv(self.dispatch_monitor_traffic)
417 self.monitor.on_recv(self.dispatch_monitor_traffic)
418
418
419 self.heartmonitor.add_heart_failure_handler(self.handle_heart_failure)
419 self.heartmonitor.add_heart_failure_handler(self.handle_heart_failure)
420 self.heartmonitor.add_new_heart_handler(self.handle_new_heart)
420 self.heartmonitor.add_new_heart_handler(self.handle_new_heart)
421
421
422 self.monitor_handlers = {b'in' : self.save_queue_request,
422 self.monitor_handlers = {b'in' : self.save_queue_request,
423 b'out': self.save_queue_result,
423 b'out': self.save_queue_result,
424 b'intask': self.save_task_request,
424 b'intask': self.save_task_request,
425 b'outtask': self.save_task_result,
425 b'outtask': self.save_task_result,
426 b'tracktask': self.save_task_destination,
426 b'tracktask': self.save_task_destination,
427 b'incontrol': _passer,
427 b'incontrol': _passer,
428 b'outcontrol': _passer,
428 b'outcontrol': _passer,
429 b'iopub': self.save_iopub_message,
429 b'iopub': self.save_iopub_message,
430 }
430 }
431
431
432 self.query_handlers = {'queue_request': self.queue_status,
432 self.query_handlers = {'queue_request': self.queue_status,
433 'result_request': self.get_results,
433 'result_request': self.get_results,
434 'history_request': self.get_history,
434 'history_request': self.get_history,
435 'db_request': self.db_query,
435 'db_request': self.db_query,
436 'purge_request': self.purge_results,
436 'purge_request': self.purge_results,
437 'load_request': self.check_load,
437 'load_request': self.check_load,
438 'resubmit_request': self.resubmit_task,
438 'resubmit_request': self.resubmit_task,
439 'shutdown_request': self.shutdown_request,
439 'shutdown_request': self.shutdown_request,
440 'registration_request' : self.register_engine,
440 'registration_request' : self.register_engine,
441 'unregistration_request' : self.unregister_engine,
441 'unregistration_request' : self.unregister_engine,
442 'connection_request': self.connection_request,
442 'connection_request': self.connection_request,
443 }
443 }
444
444
445 # ignore resubmit replies
445 # ignore resubmit replies
446 self.resubmit.on_recv(lambda msg: None, copy=False)
446 self.resubmit.on_recv(lambda msg: None, copy=False)
447
447
448 self.log.info("hub::created hub")
448 self.log.info("hub::created hub")
449
449
450 @property
450 @property
451 def _next_id(self):
451 def _next_id(self):
452 """gemerate a new ID.
452 """gemerate a new ID.
453
453
454 No longer reuse old ids, just count from 0."""
454 No longer reuse old ids, just count from 0."""
455 newid = self._idcounter
455 newid = self._idcounter
456 self._idcounter += 1
456 self._idcounter += 1
457 return newid
457 return newid
458 # newid = 0
458 # newid = 0
459 # incoming = [id[0] for id in itervalues(self.incoming_registrations)]
459 # incoming = [id[0] for id in itervalues(self.incoming_registrations)]
460 # # print newid, self.ids, self.incoming_registrations
460 # # print newid, self.ids, self.incoming_registrations
461 # while newid in self.ids or newid in incoming:
461 # while newid in self.ids or newid in incoming:
462 # newid += 1
462 # newid += 1
463 # return newid
463 # return newid
464
464
465 #-----------------------------------------------------------------------------
465 #-----------------------------------------------------------------------------
466 # message validation
466 # message validation
467 #-----------------------------------------------------------------------------
467 #-----------------------------------------------------------------------------
468
468
469 def _validate_targets(self, targets):
469 def _validate_targets(self, targets):
470 """turn any valid targets argument into a list of integer ids"""
470 """turn any valid targets argument into a list of integer ids"""
471 if targets is None:
471 if targets is None:
472 # default to all
472 # default to all
473 return self.ids
473 return self.ids
474
474
475 if isinstance(targets, (int,str,unicode_type)):
475 if isinstance(targets, (int,str,unicode_type)):
476 # only one target specified
476 # only one target specified
477 targets = [targets]
477 targets = [targets]
478 _targets = []
478 _targets = []
479 for t in targets:
479 for t in targets:
480 # map raw identities to ids
480 # map raw identities to ids
481 if isinstance(t, (str,unicode_type)):
481 if isinstance(t, (str,unicode_type)):
482 t = self.by_ident.get(cast_bytes(t), t)
482 t = self.by_ident.get(cast_bytes(t), t)
483 _targets.append(t)
483 _targets.append(t)
484 targets = _targets
484 targets = _targets
485 bad_targets = [ t for t in targets if t not in self.ids ]
485 bad_targets = [ t for t in targets if t not in self.ids ]
486 if bad_targets:
486 if bad_targets:
487 raise IndexError("No Such Engine: %r" % bad_targets)
487 raise IndexError("No Such Engine: %r" % bad_targets)
488 if not targets:
488 if not targets:
489 raise IndexError("No Engines Registered")
489 raise IndexError("No Engines Registered")
490 return targets
490 return targets
491
491
492 #-----------------------------------------------------------------------------
492 #-----------------------------------------------------------------------------
493 # dispatch methods (1 per stream)
493 # dispatch methods (1 per stream)
494 #-----------------------------------------------------------------------------
494 #-----------------------------------------------------------------------------
495
495
496
496
497 @util.log_errors
497 @util.log_errors
498 def dispatch_monitor_traffic(self, msg):
498 def dispatch_monitor_traffic(self, msg):
499 """all ME and Task queue messages come through here, as well as
499 """all ME and Task queue messages come through here, as well as
500 IOPub traffic."""
500 IOPub traffic."""
501 self.log.debug("monitor traffic: %r", msg[0])
501 self.log.debug("monitor traffic: %r", msg[0])
502 switch = msg[0]
502 switch = msg[0]
503 try:
503 try:
504 idents, msg = self.session.feed_identities(msg[1:])
504 idents, msg = self.session.feed_identities(msg[1:])
505 except ValueError:
505 except ValueError:
506 idents=[]
506 idents=[]
507 if not idents:
507 if not idents:
508 self.log.error("Monitor message without topic: %r", msg)
508 self.log.error("Monitor message without topic: %r", msg)
509 return
509 return
510 handler = self.monitor_handlers.get(switch, None)
510 handler = self.monitor_handlers.get(switch, None)
511 if handler is not None:
511 if handler is not None:
512 handler(idents, msg)
512 handler(idents, msg)
513 else:
513 else:
514 self.log.error("Unrecognized monitor topic: %r", switch)
514 self.log.error("Unrecognized monitor topic: %r", switch)
515
515
516
516
517 @util.log_errors
517 @util.log_errors
518 def dispatch_query(self, msg):
518 def dispatch_query(self, msg):
519 """Route registration requests and queries from clients."""
519 """Route registration requests and queries from clients."""
520 try:
520 try:
521 idents, msg = self.session.feed_identities(msg)
521 idents, msg = self.session.feed_identities(msg)
522 except ValueError:
522 except ValueError:
523 idents = []
523 idents = []
524 if not idents:
524 if not idents:
525 self.log.error("Bad Query Message: %r", msg)
525 self.log.error("Bad Query Message: %r", msg)
526 return
526 return
527 client_id = idents[0]
527 client_id = idents[0]
528 try:
528 try:
529 msg = self.session.unserialize(msg, content=True)
529 msg = self.session.unserialize(msg, content=True)
530 except Exception:
530 except Exception:
531 content = error.wrap_exception()
531 content = error.wrap_exception()
532 self.log.error("Bad Query Message: %r", msg, exc_info=True)
532 self.log.error("Bad Query Message: %r", msg, exc_info=True)
533 self.session.send(self.query, "hub_error", ident=client_id,
533 self.session.send(self.query, "hub_error", ident=client_id,
534 content=content)
534 content=content)
535 return
535 return
536 # print client_id, header, parent, content
536 # print client_id, header, parent, content
537 #switch on message type:
537 #switch on message type:
538 msg_type = msg['header']['msg_type']
538 msg_type = msg['header']['msg_type']
539 self.log.info("client::client %r requested %r", client_id, msg_type)
539 self.log.info("client::client %r requested %r", client_id, msg_type)
540 handler = self.query_handlers.get(msg_type, None)
540 handler = self.query_handlers.get(msg_type, None)
541 try:
541 try:
542 assert handler is not None, "Bad Message Type: %r" % msg_type
542 assert handler is not None, "Bad Message Type: %r" % msg_type
543 except:
543 except:
544 content = error.wrap_exception()
544 content = error.wrap_exception()
545 self.log.error("Bad Message Type: %r", msg_type, exc_info=True)
545 self.log.error("Bad Message Type: %r", msg_type, exc_info=True)
546 self.session.send(self.query, "hub_error", ident=client_id,
546 self.session.send(self.query, "hub_error", ident=client_id,
547 content=content)
547 content=content)
548 return
548 return
549
549
550 else:
550 else:
551 handler(idents, msg)
551 handler(idents, msg)
552
552
553 def dispatch_db(self, msg):
553 def dispatch_db(self, msg):
554 """"""
554 """"""
555 raise NotImplementedError
555 raise NotImplementedError
556
556
557 #---------------------------------------------------------------------------
557 #---------------------------------------------------------------------------
558 # handler methods (1 per event)
558 # handler methods (1 per event)
559 #---------------------------------------------------------------------------
559 #---------------------------------------------------------------------------
560
560
561 #----------------------- Heartbeat --------------------------------------
561 #----------------------- Heartbeat --------------------------------------
562
562
563 def handle_new_heart(self, heart):
563 def handle_new_heart(self, heart):
564 """handler to attach to heartbeater.
564 """handler to attach to heartbeater.
565 Called when a new heart starts to beat.
565 Called when a new heart starts to beat.
566 Triggers completion of registration."""
566 Triggers completion of registration."""
567 self.log.debug("heartbeat::handle_new_heart(%r)", heart)
567 self.log.debug("heartbeat::handle_new_heart(%r)", heart)
568 if heart not in self.incoming_registrations:
568 if heart not in self.incoming_registrations:
569 self.log.info("heartbeat::ignoring new heart: %r", heart)
569 self.log.info("heartbeat::ignoring new heart: %r", heart)
570 else:
570 else:
571 self.finish_registration(heart)
571 self.finish_registration(heart)
572
572
573
573
574 def handle_heart_failure(self, heart):
574 def handle_heart_failure(self, heart):
575 """handler to attach to heartbeater.
575 """handler to attach to heartbeater.
576 called when a previously registered heart fails to respond to beat request.
576 called when a previously registered heart fails to respond to beat request.
577 triggers unregistration"""
577 triggers unregistration"""
578 self.log.debug("heartbeat::handle_heart_failure(%r)", heart)
578 self.log.debug("heartbeat::handle_heart_failure(%r)", heart)
579 eid = self.hearts.get(heart, None)
579 eid = self.hearts.get(heart, None)
580 uuid = self.engines[eid].uuid
580 uuid = self.engines[eid].uuid
581 if eid is None or self.keytable[eid] in self.dead_engines:
581 if eid is None or self.keytable[eid] in self.dead_engines:
582 self.log.info("heartbeat::ignoring heart failure %r (not an engine or already dead)", heart)
582 self.log.info("heartbeat::ignoring heart failure %r (not an engine or already dead)", heart)
583 else:
583 else:
584 self.unregister_engine(heart, dict(content=dict(id=eid, queue=uuid)))
584 self.unregister_engine(heart, dict(content=dict(id=eid, queue=uuid)))
585
585
586 #----------------------- MUX Queue Traffic ------------------------------
586 #----------------------- MUX Queue Traffic ------------------------------
587
587
588 def save_queue_request(self, idents, msg):
588 def save_queue_request(self, idents, msg):
589 if len(idents) < 2:
589 if len(idents) < 2:
590 self.log.error("invalid identity prefix: %r", idents)
590 self.log.error("invalid identity prefix: %r", idents)
591 return
591 return
592 queue_id, client_id = idents[:2]
592 queue_id, client_id = idents[:2]
593 try:
593 try:
594 msg = self.session.unserialize(msg)
594 msg = self.session.unserialize(msg)
595 except Exception:
595 except Exception:
596 self.log.error("queue::client %r sent invalid message to %r: %r", client_id, queue_id, msg, exc_info=True)
596 self.log.error("queue::client %r sent invalid message to %r: %r", client_id, queue_id, msg, exc_info=True)
597 return
597 return
598
598
599 eid = self.by_ident.get(queue_id, None)
599 eid = self.by_ident.get(queue_id, None)
600 if eid is None:
600 if eid is None:
601 self.log.error("queue::target %r not registered", queue_id)
601 self.log.error("queue::target %r not registered", queue_id)
602 self.log.debug("queue:: valid are: %r", self.by_ident.keys())
602 self.log.debug("queue:: valid are: %r", self.by_ident.keys())
603 return
603 return
604 record = init_record(msg)
604 record = init_record(msg)
605 msg_id = record['msg_id']
605 msg_id = record['msg_id']
606 self.log.info("queue::client %r submitted request %r to %s", client_id, msg_id, eid)
606 self.log.info("queue::client %r submitted request %r to %s", client_id, msg_id, eid)
607 # Unicode in records
607 # Unicode in records
608 record['engine_uuid'] = queue_id.decode('ascii')
608 record['engine_uuid'] = queue_id.decode('ascii')
609 record['client_uuid'] = msg['header']['session']
609 record['client_uuid'] = msg['header']['session']
610 record['queue'] = 'mux'
610 record['queue'] = 'mux'
611
611
612 try:
612 try:
613 # it's posible iopub arrived first:
613 # it's posible iopub arrived first:
614 existing = self.db.get_record(msg_id)
614 existing = self.db.get_record(msg_id)
615 for key,evalue in iteritems(existing):
615 for key,evalue in iteritems(existing):
616 rvalue = record.get(key, None)
616 rvalue = record.get(key, None)
617 if evalue and rvalue and evalue != rvalue:
617 if evalue and rvalue and evalue != rvalue:
618 self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue)
618 self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue)
619 elif evalue and not rvalue:
619 elif evalue and not rvalue:
620 record[key] = evalue
620 record[key] = evalue
621 try:
621 try:
622 self.db.update_record(msg_id, record)
622 self.db.update_record(msg_id, record)
623 except Exception:
623 except Exception:
624 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
624 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
625 except KeyError:
625 except KeyError:
626 try:
626 try:
627 self.db.add_record(msg_id, record)
627 self.db.add_record(msg_id, record)
628 except Exception:
628 except Exception:
629 self.log.error("DB Error adding record %r", msg_id, exc_info=True)
629 self.log.error("DB Error adding record %r", msg_id, exc_info=True)
630
630
631
631
632 self.pending.add(msg_id)
632 self.pending.add(msg_id)
633 self.queues[eid].append(msg_id)
633 self.queues[eid].append(msg_id)
634
634
635 def save_queue_result(self, idents, msg):
635 def save_queue_result(self, idents, msg):
636 if len(idents) < 2:
636 if len(idents) < 2:
637 self.log.error("invalid identity prefix: %r", idents)
637 self.log.error("invalid identity prefix: %r", idents)
638 return
638 return
639
639
640 client_id, queue_id = idents[:2]
640 client_id, queue_id = idents[:2]
641 try:
641 try:
642 msg = self.session.unserialize(msg)
642 msg = self.session.unserialize(msg)
643 except Exception:
643 except Exception:
644 self.log.error("queue::engine %r sent invalid message to %r: %r",
644 self.log.error("queue::engine %r sent invalid message to %r: %r",
645 queue_id, client_id, msg, exc_info=True)
645 queue_id, client_id, msg, exc_info=True)
646 return
646 return
647
647
648 eid = self.by_ident.get(queue_id, None)
648 eid = self.by_ident.get(queue_id, None)
649 if eid is None:
649 if eid is None:
650 self.log.error("queue::unknown engine %r is sending a reply: ", queue_id)
650 self.log.error("queue::unknown engine %r is sending a reply: ", queue_id)
651 return
651 return
652
652
653 parent = msg['parent_header']
653 parent = msg['parent_header']
654 if not parent:
654 if not parent:
655 return
655 return
656 msg_id = parent['msg_id']
656 msg_id = parent['msg_id']
657 if msg_id in self.pending:
657 if msg_id in self.pending:
658 self.pending.remove(msg_id)
658 self.pending.remove(msg_id)
659 self.all_completed.add(msg_id)
659 self.all_completed.add(msg_id)
660 self.queues[eid].remove(msg_id)
660 self.queues[eid].remove(msg_id)
661 self.completed[eid].append(msg_id)
661 self.completed[eid].append(msg_id)
662 self.log.info("queue::request %r completed on %s", msg_id, eid)
662 self.log.info("queue::request %r completed on %s", msg_id, eid)
663 elif msg_id not in self.all_completed:
663 elif msg_id not in self.all_completed:
664 # it could be a result from a dead engine that died before delivering the
664 # it could be a result from a dead engine that died before delivering the
665 # result
665 # result
666 self.log.warn("queue:: unknown msg finished %r", msg_id)
666 self.log.warn("queue:: unknown msg finished %r", msg_id)
667 return
667 return
668 # update record anyway, because the unregistration could have been premature
668 # update record anyway, because the unregistration could have been premature
669 rheader = msg['header']
669 rheader = msg['header']
670 md = msg['metadata']
670 md = msg['metadata']
671 completed = rheader['date']
671 completed = rheader['date']
672 started = md.get('started', None)
672 started = md.get('started', None)
673 result = {
673 result = {
674 'result_header' : rheader,
674 'result_header' : rheader,
675 'result_metadata': md,
675 'result_metadata': md,
676 'result_content': msg['content'],
676 'result_content': msg['content'],
677 'received': datetime.now(),
677 'received': datetime.now(),
678 'started' : started,
678 'started' : started,
679 'completed' : completed
679 'completed' : completed
680 }
680 }
681
681
682 result['result_buffers'] = msg['buffers']
682 result['result_buffers'] = msg['buffers']
683 try:
683 try:
684 self.db.update_record(msg_id, result)
684 self.db.update_record(msg_id, result)
685 except Exception:
685 except Exception:
686 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
686 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
687
687
688
688
689 #--------------------- Task Queue Traffic ------------------------------
689 #--------------------- Task Queue Traffic ------------------------------
690
690
691 def save_task_request(self, idents, msg):
691 def save_task_request(self, idents, msg):
692 """Save the submission of a task."""
692 """Save the submission of a task."""
693 client_id = idents[0]
693 client_id = idents[0]
694
694
695 try:
695 try:
696 msg = self.session.unserialize(msg)
696 msg = self.session.unserialize(msg)
697 except Exception:
697 except Exception:
698 self.log.error("task::client %r sent invalid task message: %r",
698 self.log.error("task::client %r sent invalid task message: %r",
699 client_id, msg, exc_info=True)
699 client_id, msg, exc_info=True)
700 return
700 return
701 record = init_record(msg)
701 record = init_record(msg)
702
702
703 record['client_uuid'] = msg['header']['session']
703 record['client_uuid'] = msg['header']['session']
704 record['queue'] = 'task'
704 record['queue'] = 'task'
705 header = msg['header']
705 header = msg['header']
706 msg_id = header['msg_id']
706 msg_id = header['msg_id']
707 self.pending.add(msg_id)
707 self.pending.add(msg_id)
708 self.unassigned.add(msg_id)
708 self.unassigned.add(msg_id)
709 try:
709 try:
710 # it's posible iopub arrived first:
710 # it's posible iopub arrived first:
711 existing = self.db.get_record(msg_id)
711 existing = self.db.get_record(msg_id)
712 if existing['resubmitted']:
712 if existing['resubmitted']:
713 for key in ('submitted', 'client_uuid', 'buffers'):
713 for key in ('submitted', 'client_uuid', 'buffers'):
714 # don't clobber these keys on resubmit
714 # don't clobber these keys on resubmit
715 # submitted and client_uuid should be different
715 # submitted and client_uuid should be different
716 # and buffers might be big, and shouldn't have changed
716 # and buffers might be big, and shouldn't have changed
717 record.pop(key)
717 record.pop(key)
718 # still check content,header which should not change
718 # still check content,header which should not change
719 # but are not expensive to compare as buffers
719 # but are not expensive to compare as buffers
720
720
721 for key,evalue in iteritems(existing):
721 for key,evalue in iteritems(existing):
722 if key.endswith('buffers'):
722 if key.endswith('buffers'):
723 # don't compare buffers
723 # don't compare buffers
724 continue
724 continue
725 rvalue = record.get(key, None)
725 rvalue = record.get(key, None)
726 if evalue and rvalue and evalue != rvalue:
726 if evalue and rvalue and evalue != rvalue:
727 self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue)
727 self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue)
728 elif evalue and not rvalue:
728 elif evalue and not rvalue:
729 record[key] = evalue
729 record[key] = evalue
730 try:
730 try:
731 self.db.update_record(msg_id, record)
731 self.db.update_record(msg_id, record)
732 except Exception:
732 except Exception:
733 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
733 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
734 except KeyError:
734 except KeyError:
735 try:
735 try:
736 self.db.add_record(msg_id, record)
736 self.db.add_record(msg_id, record)
737 except Exception:
737 except Exception:
738 self.log.error("DB Error adding record %r", msg_id, exc_info=True)
738 self.log.error("DB Error adding record %r", msg_id, exc_info=True)
739 except Exception:
739 except Exception:
740 self.log.error("DB Error saving task request %r", msg_id, exc_info=True)
740 self.log.error("DB Error saving task request %r", msg_id, exc_info=True)
741
741
742 def save_task_result(self, idents, msg):
742 def save_task_result(self, idents, msg):
743 """save the result of a completed task."""
743 """save the result of a completed task."""
744 client_id = idents[0]
744 client_id = idents[0]
745 try:
745 try:
746 msg = self.session.unserialize(msg)
746 msg = self.session.unserialize(msg)
747 except Exception:
747 except Exception:
748 self.log.error("task::invalid task result message send to %r: %r",
748 self.log.error("task::invalid task result message send to %r: %r",
749 client_id, msg, exc_info=True)
749 client_id, msg, exc_info=True)
750 return
750 return
751
751
752 parent = msg['parent_header']
752 parent = msg['parent_header']
753 if not parent:
753 if not parent:
754 # print msg
754 # print msg
755 self.log.warn("Task %r had no parent!", msg)
755 self.log.warn("Task %r had no parent!", msg)
756 return
756 return
757 msg_id = parent['msg_id']
757 msg_id = parent['msg_id']
758 if msg_id in self.unassigned:
758 if msg_id in self.unassigned:
759 self.unassigned.remove(msg_id)
759 self.unassigned.remove(msg_id)
760
760
761 header = msg['header']
761 header = msg['header']
762 md = msg['metadata']
762 md = msg['metadata']
763 engine_uuid = md.get('engine', u'')
763 engine_uuid = md.get('engine', u'')
764 eid = self.by_ident.get(cast_bytes(engine_uuid), None)
764 eid = self.by_ident.get(cast_bytes(engine_uuid), None)
765
765
766 status = md.get('status', None)
766 status = md.get('status', None)
767
767
768 if msg_id in self.pending:
768 if msg_id in self.pending:
769 self.log.info("task::task %r finished on %s", msg_id, eid)
769 self.log.info("task::task %r finished on %s", msg_id, eid)
770 self.pending.remove(msg_id)
770 self.pending.remove(msg_id)
771 self.all_completed.add(msg_id)
771 self.all_completed.add(msg_id)
772 if eid is not None:
772 if eid is not None:
773 if status != 'aborted':
773 if status != 'aborted':
774 self.completed[eid].append(msg_id)
774 self.completed[eid].append(msg_id)
775 if msg_id in self.tasks[eid]:
775 if msg_id in self.tasks[eid]:
776 self.tasks[eid].remove(msg_id)
776 self.tasks[eid].remove(msg_id)
777 completed = header['date']
777 completed = header['date']
778 started = md.get('started', None)
778 started = md.get('started', None)
779 result = {
779 result = {
780 'result_header' : header,
780 'result_header' : header,
781 'result_metadata': msg['metadata'],
781 'result_metadata': msg['metadata'],
782 'result_content': msg['content'],
782 'result_content': msg['content'],
783 'started' : started,
783 'started' : started,
784 'completed' : completed,
784 'completed' : completed,
785 'received' : datetime.now(),
785 'received' : datetime.now(),
786 'engine_uuid': engine_uuid,
786 'engine_uuid': engine_uuid,
787 }
787 }
788
788
789 result['result_buffers'] = msg['buffers']
789 result['result_buffers'] = msg['buffers']
790 try:
790 try:
791 self.db.update_record(msg_id, result)
791 self.db.update_record(msg_id, result)
792 except Exception:
792 except Exception:
793 self.log.error("DB Error saving task request %r", msg_id, exc_info=True)
793 self.log.error("DB Error saving task request %r", msg_id, exc_info=True)
794
794
795 else:
795 else:
796 self.log.debug("task::unknown task %r finished", msg_id)
796 self.log.debug("task::unknown task %r finished", msg_id)
797
797
798 def save_task_destination(self, idents, msg):
798 def save_task_destination(self, idents, msg):
799 try:
799 try:
800 msg = self.session.unserialize(msg, content=True)
800 msg = self.session.unserialize(msg, content=True)
801 except Exception:
801 except Exception:
802 self.log.error("task::invalid task tracking message", exc_info=True)
802 self.log.error("task::invalid task tracking message", exc_info=True)
803 return
803 return
804 content = msg['content']
804 content = msg['content']
805 # print (content)
805 # print (content)
806 msg_id = content['msg_id']
806 msg_id = content['msg_id']
807 engine_uuid = content['engine_id']
807 engine_uuid = content['engine_id']
808 eid = self.by_ident[cast_bytes(engine_uuid)]
808 eid = self.by_ident[cast_bytes(engine_uuid)]
809
809
810 self.log.info("task::task %r arrived on %r", msg_id, eid)
810 self.log.info("task::task %r arrived on %r", msg_id, eid)
811 if msg_id in self.unassigned:
811 if msg_id in self.unassigned:
812 self.unassigned.remove(msg_id)
812 self.unassigned.remove(msg_id)
813 # else:
813 # else:
814 # self.log.debug("task::task %r not listed as MIA?!"%(msg_id))
814 # self.log.debug("task::task %r not listed as MIA?!"%(msg_id))
815
815
816 self.tasks[eid].append(msg_id)
816 self.tasks[eid].append(msg_id)
817 # self.pending[msg_id][1].update(received=datetime.now(),engine=(eid,engine_uuid))
817 # self.pending[msg_id][1].update(received=datetime.now(),engine=(eid,engine_uuid))
818 try:
818 try:
819 self.db.update_record(msg_id, dict(engine_uuid=engine_uuid))
819 self.db.update_record(msg_id, dict(engine_uuid=engine_uuid))
820 except Exception:
820 except Exception:
821 self.log.error("DB Error saving task destination %r", msg_id, exc_info=True)
821 self.log.error("DB Error saving task destination %r", msg_id, exc_info=True)
822
822
823
823
824 def mia_task_request(self, idents, msg):
824 def mia_task_request(self, idents, msg):
825 raise NotImplementedError
825 raise NotImplementedError
826 client_id = idents[0]
826 client_id = idents[0]
827 # content = dict(mia=self.mia,status='ok')
827 # content = dict(mia=self.mia,status='ok')
828 # self.session.send('mia_reply', content=content, idents=client_id)
828 # self.session.send('mia_reply', content=content, idents=client_id)
829
829
830
830
831 #--------------------- IOPub Traffic ------------------------------
831 #--------------------- IOPub Traffic ------------------------------
832
832
833 def save_iopub_message(self, topics, msg):
833 def save_iopub_message(self, topics, msg):
834 """save an iopub message into the db"""
834 """save an iopub message into the db"""
835 # print (topics)
835 # print (topics)
836 try:
836 try:
837 msg = self.session.unserialize(msg, content=True)
837 msg = self.session.unserialize(msg, content=True)
838 except Exception:
838 except Exception:
839 self.log.error("iopub::invalid IOPub message", exc_info=True)
839 self.log.error("iopub::invalid IOPub message", exc_info=True)
840 return
840 return
841
841
842 parent = msg['parent_header']
842 parent = msg['parent_header']
843 if not parent:
843 if not parent:
844 self.log.warn("iopub::IOPub message lacks parent: %r", msg)
844 self.log.warn("iopub::IOPub message lacks parent: %r", msg)
845 return
845 return
846 msg_id = parent['msg_id']
846 msg_id = parent['msg_id']
847 msg_type = msg['header']['msg_type']
847 msg_type = msg['header']['msg_type']
848 content = msg['content']
848 content = msg['content']
849
849
850 # ensure msg_id is in db
850 # ensure msg_id is in db
851 try:
851 try:
852 rec = self.db.get_record(msg_id)
852 rec = self.db.get_record(msg_id)
853 except KeyError:
853 except KeyError:
854 rec = empty_record()
854 rec = empty_record()
855 rec['msg_id'] = msg_id
855 rec['msg_id'] = msg_id
856 self.db.add_record(msg_id, rec)
856 self.db.add_record(msg_id, rec)
857 # stream
857 # stream
858 d = {}
858 d = {}
859 if msg_type == 'stream':
859 if msg_type == 'stream':
860 name = content['name']
860 name = content['name']
861 s = rec[name] or ''
861 s = rec[name] or ''
862 d[name] = s + content['data']
862 d[name] = s + content['data']
863
863
864 elif msg_type == 'pyerr':
864 elif msg_type == 'pyerr':
865 d['pyerr'] = content
865 d['pyerr'] = content
866 elif msg_type == 'pyin':
866 elif msg_type == 'pyin':
867 d['pyin'] = content['code']
867 d['pyin'] = content['code']
868 elif msg_type in ('display_data', 'pyout'):
868 elif msg_type in ('display_data', 'pyout'):
869 d[msg_type] = content
869 d[msg_type] = content
870 elif msg_type == 'status':
870 elif msg_type == 'status':
871 pass
871 pass
872 elif msg_type == 'data_pub':
872 elif msg_type == 'data_pub':
873 self.log.info("ignored data_pub message for %s" % msg_id)
873 self.log.info("ignored data_pub message for %s" % msg_id)
874 else:
874 else:
875 self.log.warn("unhandled iopub msg_type: %r", msg_type)
875 self.log.warn("unhandled iopub msg_type: %r", msg_type)
876
876
877 if not d:
877 if not d:
878 return
878 return
879
879
880 try:
880 try:
881 self.db.update_record(msg_id, d)
881 self.db.update_record(msg_id, d)
882 except Exception:
882 except Exception:
883 self.log.error("DB Error saving iopub message %r", msg_id, exc_info=True)
883 self.log.error("DB Error saving iopub message %r", msg_id, exc_info=True)
884
884
885
885
886
886
887 #-------------------------------------------------------------------------
887 #-------------------------------------------------------------------------
888 # Registration requests
888 # Registration requests
889 #-------------------------------------------------------------------------
889 #-------------------------------------------------------------------------
890
890
891 def connection_request(self, client_id, msg):
891 def connection_request(self, client_id, msg):
892 """Reply with connection addresses for clients."""
892 """Reply with connection addresses for clients."""
893 self.log.info("client::client %r connected", client_id)
893 self.log.info("client::client %r connected", client_id)
894 content = dict(status='ok')
894 content = dict(status='ok')
895 jsonable = {}
895 jsonable = {}
896 for k,v in iteritems(self.keytable):
896 for k,v in iteritems(self.keytable):
897 if v not in self.dead_engines:
897 if v not in self.dead_engines:
898 jsonable[str(k)] = v
898 jsonable[str(k)] = v
899 content['engines'] = jsonable
899 content['engines'] = jsonable
900 self.session.send(self.query, 'connection_reply', content, parent=msg, ident=client_id)
900 self.session.send(self.query, 'connection_reply', content, parent=msg, ident=client_id)
901
901
902 def register_engine(self, reg, msg):
902 def register_engine(self, reg, msg):
903 """Register a new engine."""
903 """Register a new engine."""
904 content = msg['content']
904 content = msg['content']
905 try:
905 try:
906 uuid = content['uuid']
906 uuid = content['uuid']
907 except KeyError:
907 except KeyError:
908 self.log.error("registration::queue not specified", exc_info=True)
908 self.log.error("registration::queue not specified", exc_info=True)
909 return
909 return
910
910
911 eid = self._next_id
911 eid = self._next_id
912
912
913 self.log.debug("registration::register_engine(%i, %r)", eid, uuid)
913 self.log.debug("registration::register_engine(%i, %r)", eid, uuid)
914
914
915 content = dict(id=eid,status='ok',hb_period=self.heartmonitor.period)
915 content = dict(id=eid,status='ok',hb_period=self.heartmonitor.period)
916 # check if requesting available IDs:
916 # check if requesting available IDs:
917 if cast_bytes(uuid) in self.by_ident:
917 if cast_bytes(uuid) in self.by_ident:
918 try:
918 try:
919 raise KeyError("uuid %r in use" % uuid)
919 raise KeyError("uuid %r in use" % uuid)
920 except:
920 except:
921 content = error.wrap_exception()
921 content = error.wrap_exception()
922 self.log.error("uuid %r in use", uuid, exc_info=True)
922 self.log.error("uuid %r in use", uuid, exc_info=True)
923 else:
923 else:
924 for h, ec in iteritems(self.incoming_registrations):
924 for h, ec in iteritems(self.incoming_registrations):
925 if uuid == h:
925 if uuid == h:
926 try:
926 try:
927 raise KeyError("heart_id %r in use" % uuid)
927 raise KeyError("heart_id %r in use" % uuid)
928 except:
928 except:
929 self.log.error("heart_id %r in use", uuid, exc_info=True)
929 self.log.error("heart_id %r in use", uuid, exc_info=True)
930 content = error.wrap_exception()
930 content = error.wrap_exception()
931 break
931 break
932 elif uuid == ec.uuid:
932 elif uuid == ec.uuid:
933 try:
933 try:
934 raise KeyError("uuid %r in use" % uuid)
934 raise KeyError("uuid %r in use" % uuid)
935 except:
935 except:
936 self.log.error("uuid %r in use", uuid, exc_info=True)
936 self.log.error("uuid %r in use", uuid, exc_info=True)
937 content = error.wrap_exception()
937 content = error.wrap_exception()
938 break
938 break
939
939
940 msg = self.session.send(self.query, "registration_reply",
940 msg = self.session.send(self.query, "registration_reply",
941 content=content,
941 content=content,
942 ident=reg)
942 ident=reg)
943
943
944 heart = cast_bytes(uuid)
944 heart = cast_bytes(uuid)
945
945
946 if content['status'] == 'ok':
946 if content['status'] == 'ok':
947 if heart in self.heartmonitor.hearts:
947 if heart in self.heartmonitor.hearts:
948 # already beating
948 # already beating
949 self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid)
949 self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid)
950 self.finish_registration(heart)
950 self.finish_registration(heart)
951 else:
951 else:
952 purge = lambda : self._purge_stalled_registration(heart)
952 purge = lambda : self._purge_stalled_registration(heart)
953 dc = ioloop.DelayedCallback(purge, self.registration_timeout, self.loop)
953 dc = ioloop.DelayedCallback(purge, self.registration_timeout, self.loop)
954 dc.start()
954 dc.start()
955 self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid,stallback=dc)
955 self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid,stallback=dc)
956 else:
956 else:
957 self.log.error("registration::registration %i failed: %r", eid, content['evalue'])
957 self.log.error("registration::registration %i failed: %r", eid, content['evalue'])
958
958
959 return eid
959 return eid
960
960
961 def unregister_engine(self, ident, msg):
961 def unregister_engine(self, ident, msg):
962 """Unregister an engine that explicitly requested to leave."""
962 """Unregister an engine that explicitly requested to leave."""
963 try:
963 try:
964 eid = msg['content']['id']
964 eid = msg['content']['id']
965 except:
965 except:
966 self.log.error("registration::bad engine id for unregistration: %r", ident, exc_info=True)
966 self.log.error("registration::bad engine id for unregistration: %r", ident, exc_info=True)
967 return
967 return
968 self.log.info("registration::unregister_engine(%r)", eid)
968 self.log.info("registration::unregister_engine(%r)", eid)
969 # print (eid)
969 # print (eid)
970 uuid = self.keytable[eid]
970 uuid = self.keytable[eid]
971 content=dict(id=eid, uuid=uuid)
971 content=dict(id=eid, uuid=uuid)
972 self.dead_engines.add(uuid)
972 self.dead_engines.add(uuid)
973 # self.ids.remove(eid)
973 # self.ids.remove(eid)
974 # uuid = self.keytable.pop(eid)
974 # uuid = self.keytable.pop(eid)
975 #
975 #
976 # ec = self.engines.pop(eid)
976 # ec = self.engines.pop(eid)
977 # self.hearts.pop(ec.heartbeat)
977 # self.hearts.pop(ec.heartbeat)
978 # self.by_ident.pop(ec.queue)
978 # self.by_ident.pop(ec.queue)
979 # self.completed.pop(eid)
979 # self.completed.pop(eid)
980 handleit = lambda : self._handle_stranded_msgs(eid, uuid)
980 handleit = lambda : self._handle_stranded_msgs(eid, uuid)
981 dc = ioloop.DelayedCallback(handleit, self.registration_timeout, self.loop)
981 dc = ioloop.DelayedCallback(handleit, self.registration_timeout, self.loop)
982 dc.start()
982 dc.start()
983 ############## TODO: HANDLE IT ################
983 ############## TODO: HANDLE IT ################
984
984
985 self._save_engine_state()
985 self._save_engine_state()
986
986
987 if self.notifier:
987 if self.notifier:
988 self.session.send(self.notifier, "unregistration_notification", content=content)
988 self.session.send(self.notifier, "unregistration_notification", content=content)
989
989
990 def _handle_stranded_msgs(self, eid, uuid):
990 def _handle_stranded_msgs(self, eid, uuid):
991 """Handle messages known to be on an engine when the engine unregisters.
991 """Handle messages known to be on an engine when the engine unregisters.
992
992
993 It is possible that this will fire prematurely - that is, an engine will
993 It is possible that this will fire prematurely - that is, an engine will
994 go down after completing a result, and the client will be notified
994 go down after completing a result, and the client will be notified
995 that the result failed and later receive the actual result.
995 that the result failed and later receive the actual result.
996 """
996 """
997
997
998 outstanding = self.queues[eid]
998 outstanding = self.queues[eid]
999
999
1000 for msg_id in outstanding:
1000 for msg_id in outstanding:
1001 self.pending.remove(msg_id)
1001 self.pending.remove(msg_id)
1002 self.all_completed.add(msg_id)
1002 self.all_completed.add(msg_id)
1003 try:
1003 try:
1004 raise error.EngineError("Engine %r died while running task %r" % (eid, msg_id))
1004 raise error.EngineError("Engine %r died while running task %r" % (eid, msg_id))
1005 except:
1005 except:
1006 content = error.wrap_exception()
1006 content = error.wrap_exception()
1007 # build a fake header:
1007 # build a fake header:
1008 header = {}
1008 header = {}
1009 header['engine'] = uuid
1009 header['engine'] = uuid
1010 header['date'] = datetime.now()
1010 header['date'] = datetime.now()
1011 rec = dict(result_content=content, result_header=header, result_buffers=[])
1011 rec = dict(result_content=content, result_header=header, result_buffers=[])
1012 rec['completed'] = header['date']
1012 rec['completed'] = header['date']
1013 rec['engine_uuid'] = uuid
1013 rec['engine_uuid'] = uuid
1014 try:
1014 try:
1015 self.db.update_record(msg_id, rec)
1015 self.db.update_record(msg_id, rec)
1016 except Exception:
1016 except Exception:
1017 self.log.error("DB Error handling stranded msg %r", msg_id, exc_info=True)
1017 self.log.error("DB Error handling stranded msg %r", msg_id, exc_info=True)
1018
1018
1019
1019
1020 def finish_registration(self, heart):
1020 def finish_registration(self, heart):
1021 """Second half of engine registration, called after our HeartMonitor
1021 """Second half of engine registration, called after our HeartMonitor
1022 has received a beat from the Engine's Heart."""
1022 has received a beat from the Engine's Heart."""
1023 try:
1023 try:
1024 ec = self.incoming_registrations.pop(heart)
1024 ec = self.incoming_registrations.pop(heart)
1025 except KeyError:
1025 except KeyError:
1026 self.log.error("registration::tried to finish nonexistant registration", exc_info=True)
1026 self.log.error("registration::tried to finish nonexistant registration", exc_info=True)
1027 return
1027 return
1028 self.log.info("registration::finished registering engine %i:%s", ec.id, ec.uuid)
1028 self.log.info("registration::finished registering engine %i:%s", ec.id, ec.uuid)
1029 if ec.stallback is not None:
1029 if ec.stallback is not None:
1030 ec.stallback.stop()
1030 ec.stallback.stop()
1031 eid = ec.id
1031 eid = ec.id
1032 self.ids.add(eid)
1032 self.ids.add(eid)
1033 self.keytable[eid] = ec.uuid
1033 self.keytable[eid] = ec.uuid
1034 self.engines[eid] = ec
1034 self.engines[eid] = ec
1035 self.by_ident[cast_bytes(ec.uuid)] = ec.id
1035 self.by_ident[cast_bytes(ec.uuid)] = ec.id
1036 self.queues[eid] = list()
1036 self.queues[eid] = list()
1037 self.tasks[eid] = list()
1037 self.tasks[eid] = list()
1038 self.completed[eid] = list()
1038 self.completed[eid] = list()
1039 self.hearts[heart] = eid
1039 self.hearts[heart] = eid
1040 content = dict(id=eid, uuid=self.engines[eid].uuid)
1040 content = dict(id=eid, uuid=self.engines[eid].uuid)
1041 if self.notifier:
1041 if self.notifier:
1042 self.session.send(self.notifier, "registration_notification", content=content)
1042 self.session.send(self.notifier, "registration_notification", content=content)
1043 self.log.info("engine::Engine Connected: %i", eid)
1043 self.log.info("engine::Engine Connected: %i", eid)
1044
1044
1045 self._save_engine_state()
1045 self._save_engine_state()
1046
1046
1047 def _purge_stalled_registration(self, heart):
1047 def _purge_stalled_registration(self, heart):
1048 if heart in self.incoming_registrations:
1048 if heart in self.incoming_registrations:
1049 ec = self.incoming_registrations.pop(heart)
1049 ec = self.incoming_registrations.pop(heart)
1050 self.log.info("registration::purging stalled registration: %i", ec.id)
1050 self.log.info("registration::purging stalled registration: %i", ec.id)
1051 else:
1051 else:
1052 pass
1052 pass
1053
1053
1054 #-------------------------------------------------------------------------
1054 #-------------------------------------------------------------------------
1055 # Engine State
1055 # Engine State
1056 #-------------------------------------------------------------------------
1056 #-------------------------------------------------------------------------
1057
1057
1058
1058
1059 def _cleanup_engine_state_file(self):
1059 def _cleanup_engine_state_file(self):
1060 """cleanup engine state mapping"""
1060 """cleanup engine state mapping"""
1061
1061
1062 if os.path.exists(self.engine_state_file):
1062 if os.path.exists(self.engine_state_file):
1063 self.log.debug("cleaning up engine state: %s", self.engine_state_file)
1063 self.log.debug("cleaning up engine state: %s", self.engine_state_file)
1064 try:
1064 try:
1065 os.remove(self.engine_state_file)
1065 os.remove(self.engine_state_file)
1066 except IOError:
1066 except IOError:
1067 self.log.error("Couldn't cleanup file: %s", self.engine_state_file, exc_info=True)
1067 self.log.error("Couldn't cleanup file: %s", self.engine_state_file, exc_info=True)
1068
1068
1069
1069
1070 def _save_engine_state(self):
1070 def _save_engine_state(self):
1071 """save engine mapping to JSON file"""
1071 """save engine mapping to JSON file"""
1072 if not self.engine_state_file:
1072 if not self.engine_state_file:
1073 return
1073 return
1074 self.log.debug("save engine state to %s" % self.engine_state_file)
1074 self.log.debug("save engine state to %s" % self.engine_state_file)
1075 state = {}
1075 state = {}
1076 engines = {}
1076 engines = {}
1077 for eid, ec in iteritems(self.engines):
1077 for eid, ec in iteritems(self.engines):
1078 if ec.uuid not in self.dead_engines:
1078 if ec.uuid not in self.dead_engines:
1079 engines[eid] = ec.uuid
1079 engines[eid] = ec.uuid
1080
1080
1081 state['engines'] = engines
1081 state['engines'] = engines
1082
1082
1083 state['next_id'] = self._idcounter
1083 state['next_id'] = self._idcounter
1084
1084
1085 with open(self.engine_state_file, 'w') as f:
1085 with open(self.engine_state_file, 'w') as f:
1086 json.dump(state, f)
1086 json.dump(state, f)
1087
1087
1088
1088
1089 def _load_engine_state(self):
1089 def _load_engine_state(self):
1090 """load engine mapping from JSON file"""
1090 """load engine mapping from JSON file"""
1091 if not os.path.exists(self.engine_state_file):
1091 if not os.path.exists(self.engine_state_file):
1092 return
1092 return
1093
1093
1094 self.log.info("loading engine state from %s" % self.engine_state_file)
1094 self.log.info("loading engine state from %s" % self.engine_state_file)
1095
1095
1096 with open(self.engine_state_file) as f:
1096 with open(self.engine_state_file) as f:
1097 state = json.load(f)
1097 state = json.load(f)
1098
1098
1099 save_notifier = self.notifier
1099 save_notifier = self.notifier
1100 self.notifier = None
1100 self.notifier = None
1101 for eid, uuid in iteritems(state['engines']):
1101 for eid, uuid in iteritems(state['engines']):
1102 heart = uuid.encode('ascii')
1102 heart = uuid.encode('ascii')
1103 # start with this heart as current and beating:
1103 # start with this heart as current and beating:
1104 self.heartmonitor.responses.add(heart)
1104 self.heartmonitor.responses.add(heart)
1105 self.heartmonitor.hearts.add(heart)
1105 self.heartmonitor.hearts.add(heart)
1106
1106
1107 self.incoming_registrations[heart] = EngineConnector(id=int(eid), uuid=uuid)
1107 self.incoming_registrations[heart] = EngineConnector(id=int(eid), uuid=uuid)
1108 self.finish_registration(heart)
1108 self.finish_registration(heart)
1109
1109
1110 self.notifier = save_notifier
1110 self.notifier = save_notifier
1111
1111
1112 self._idcounter = state['next_id']
1112 self._idcounter = state['next_id']
1113
1113
1114 #-------------------------------------------------------------------------
1114 #-------------------------------------------------------------------------
1115 # Client Requests
1115 # Client Requests
1116 #-------------------------------------------------------------------------
1116 #-------------------------------------------------------------------------
1117
1117
1118 def shutdown_request(self, client_id, msg):
1118 def shutdown_request(self, client_id, msg):
1119 """handle shutdown request."""
1119 """handle shutdown request."""
1120 self.session.send(self.query, 'shutdown_reply', content={'status': 'ok'}, ident=client_id)
1120 self.session.send(self.query, 'shutdown_reply', content={'status': 'ok'}, ident=client_id)
1121 # also notify other clients of shutdown
1121 # also notify other clients of shutdown
1122 self.session.send(self.notifier, 'shutdown_notice', content={'status': 'ok'})
1122 self.session.send(self.notifier, 'shutdown_notice', content={'status': 'ok'})
1123 dc = ioloop.DelayedCallback(lambda : self._shutdown(), 1000, self.loop)
1123 dc = ioloop.DelayedCallback(lambda : self._shutdown(), 1000, self.loop)
1124 dc.start()
1124 dc.start()
1125
1125
1126 def _shutdown(self):
1126 def _shutdown(self):
1127 self.log.info("hub::hub shutting down.")
1127 self.log.info("hub::hub shutting down.")
1128 time.sleep(0.1)
1128 time.sleep(0.1)
1129 sys.exit(0)
1129 sys.exit(0)
1130
1130
1131
1131
1132 def check_load(self, client_id, msg):
1132 def check_load(self, client_id, msg):
1133 content = msg['content']
1133 content = msg['content']
1134 try:
1134 try:
1135 targets = content['targets']
1135 targets = content['targets']
1136 targets = self._validate_targets(targets)
1136 targets = self._validate_targets(targets)
1137 except:
1137 except:
1138 content = error.wrap_exception()
1138 content = error.wrap_exception()
1139 self.session.send(self.query, "hub_error",
1139 self.session.send(self.query, "hub_error",
1140 content=content, ident=client_id)
1140 content=content, ident=client_id)
1141 return
1141 return
1142
1142
1143 content = dict(status='ok')
1143 content = dict(status='ok')
1144 # loads = {}
1144 # loads = {}
1145 for t in targets:
1145 for t in targets:
1146 content[bytes(t)] = len(self.queues[t])+len(self.tasks[t])
1146 content[bytes(t)] = len(self.queues[t])+len(self.tasks[t])
1147 self.session.send(self.query, "load_reply", content=content, ident=client_id)
1147 self.session.send(self.query, "load_reply", content=content, ident=client_id)
1148
1148
1149
1149
1150 def queue_status(self, client_id, msg):
1150 def queue_status(self, client_id, msg):
1151 """Return the Queue status of one or more targets.
1151 """Return the Queue status of one or more targets.
1152 if verbose: return the msg_ids
1152
1153 else: return len of each type.
1153 If verbose, return the msg_ids, else return len of each type.
1154 keys: queue (pending MUX jobs)
1154
1155 tasks (pending Task jobs)
1155 Keys:
1156 completed (finished jobs from both queues)"""
1156
1157 * queue (pending MUX jobs)
1158 * tasks (pending Task jobs)
1159 * completed (finished jobs from both queues)
1160 """
1157 content = msg['content']
1161 content = msg['content']
1158 targets = content['targets']
1162 targets = content['targets']
1159 try:
1163 try:
1160 targets = self._validate_targets(targets)
1164 targets = self._validate_targets(targets)
1161 except:
1165 except:
1162 content = error.wrap_exception()
1166 content = error.wrap_exception()
1163 self.session.send(self.query, "hub_error",
1167 self.session.send(self.query, "hub_error",
1164 content=content, ident=client_id)
1168 content=content, ident=client_id)
1165 return
1169 return
1166 verbose = content.get('verbose', False)
1170 verbose = content.get('verbose', False)
1167 content = dict(status='ok')
1171 content = dict(status='ok')
1168 for t in targets:
1172 for t in targets:
1169 queue = self.queues[t]
1173 queue = self.queues[t]
1170 completed = self.completed[t]
1174 completed = self.completed[t]
1171 tasks = self.tasks[t]
1175 tasks = self.tasks[t]
1172 if not verbose:
1176 if not verbose:
1173 queue = len(queue)
1177 queue = len(queue)
1174 completed = len(completed)
1178 completed = len(completed)
1175 tasks = len(tasks)
1179 tasks = len(tasks)
1176 content[str(t)] = {'queue': queue, 'completed': completed , 'tasks': tasks}
1180 content[str(t)] = {'queue': queue, 'completed': completed , 'tasks': tasks}
1177 content['unassigned'] = list(self.unassigned) if verbose else len(self.unassigned)
1181 content['unassigned'] = list(self.unassigned) if verbose else len(self.unassigned)
1178 # print (content)
1182 # print (content)
1179 self.session.send(self.query, "queue_reply", content=content, ident=client_id)
1183 self.session.send(self.query, "queue_reply", content=content, ident=client_id)
1180
1184
1181 def purge_results(self, client_id, msg):
1185 def purge_results(self, client_id, msg):
1182 """Purge results from memory. This method is more valuable before we move
1186 """Purge results from memory. This method is more valuable before we move
1183 to a DB based message storage mechanism."""
1187 to a DB based message storage mechanism."""
1184 content = msg['content']
1188 content = msg['content']
1185 self.log.info("Dropping records with %s", content)
1189 self.log.info("Dropping records with %s", content)
1186 msg_ids = content.get('msg_ids', [])
1190 msg_ids = content.get('msg_ids', [])
1187 reply = dict(status='ok')
1191 reply = dict(status='ok')
1188 if msg_ids == 'all':
1192 if msg_ids == 'all':
1189 try:
1193 try:
1190 self.db.drop_matching_records(dict(completed={'$ne':None}))
1194 self.db.drop_matching_records(dict(completed={'$ne':None}))
1191 except Exception:
1195 except Exception:
1192 reply = error.wrap_exception()
1196 reply = error.wrap_exception()
1193 else:
1197 else:
1194 pending = [m for m in msg_ids if (m in self.pending)]
1198 pending = [m for m in msg_ids if (m in self.pending)]
1195 if pending:
1199 if pending:
1196 try:
1200 try:
1197 raise IndexError("msg pending: %r" % pending[0])
1201 raise IndexError("msg pending: %r" % pending[0])
1198 except:
1202 except:
1199 reply = error.wrap_exception()
1203 reply = error.wrap_exception()
1200 else:
1204 else:
1201 try:
1205 try:
1202 self.db.drop_matching_records(dict(msg_id={'$in':msg_ids}))
1206 self.db.drop_matching_records(dict(msg_id={'$in':msg_ids}))
1203 except Exception:
1207 except Exception:
1204 reply = error.wrap_exception()
1208 reply = error.wrap_exception()
1205
1209
1206 if reply['status'] == 'ok':
1210 if reply['status'] == 'ok':
1207 eids = content.get('engine_ids', [])
1211 eids = content.get('engine_ids', [])
1208 for eid in eids:
1212 for eid in eids:
1209 if eid not in self.engines:
1213 if eid not in self.engines:
1210 try:
1214 try:
1211 raise IndexError("No such engine: %i" % eid)
1215 raise IndexError("No such engine: %i" % eid)
1212 except:
1216 except:
1213 reply = error.wrap_exception()
1217 reply = error.wrap_exception()
1214 break
1218 break
1215 uid = self.engines[eid].uuid
1219 uid = self.engines[eid].uuid
1216 try:
1220 try:
1217 self.db.drop_matching_records(dict(engine_uuid=uid, completed={'$ne':None}))
1221 self.db.drop_matching_records(dict(engine_uuid=uid, completed={'$ne':None}))
1218 except Exception:
1222 except Exception:
1219 reply = error.wrap_exception()
1223 reply = error.wrap_exception()
1220 break
1224 break
1221
1225
1222 self.session.send(self.query, 'purge_reply', content=reply, ident=client_id)
1226 self.session.send(self.query, 'purge_reply', content=reply, ident=client_id)
1223
1227
1224 def resubmit_task(self, client_id, msg):
1228 def resubmit_task(self, client_id, msg):
1225 """Resubmit one or more tasks."""
1229 """Resubmit one or more tasks."""
1226 def finish(reply):
1230 def finish(reply):
1227 self.session.send(self.query, 'resubmit_reply', content=reply, ident=client_id)
1231 self.session.send(self.query, 'resubmit_reply', content=reply, ident=client_id)
1228
1232
1229 content = msg['content']
1233 content = msg['content']
1230 msg_ids = content['msg_ids']
1234 msg_ids = content['msg_ids']
1231 reply = dict(status='ok')
1235 reply = dict(status='ok')
1232 try:
1236 try:
1233 records = self.db.find_records({'msg_id' : {'$in' : msg_ids}}, keys=[
1237 records = self.db.find_records({'msg_id' : {'$in' : msg_ids}}, keys=[
1234 'header', 'content', 'buffers'])
1238 'header', 'content', 'buffers'])
1235 except Exception:
1239 except Exception:
1236 self.log.error('db::db error finding tasks to resubmit', exc_info=True)
1240 self.log.error('db::db error finding tasks to resubmit', exc_info=True)
1237 return finish(error.wrap_exception())
1241 return finish(error.wrap_exception())
1238
1242
1239 # validate msg_ids
1243 # validate msg_ids
1240 found_ids = [ rec['msg_id'] for rec in records ]
1244 found_ids = [ rec['msg_id'] for rec in records ]
1241 pending_ids = [ msg_id for msg_id in found_ids if msg_id in self.pending ]
1245 pending_ids = [ msg_id for msg_id in found_ids if msg_id in self.pending ]
1242 if len(records) > len(msg_ids):
1246 if len(records) > len(msg_ids):
1243 try:
1247 try:
1244 raise RuntimeError("DB appears to be in an inconsistent state."
1248 raise RuntimeError("DB appears to be in an inconsistent state."
1245 "More matching records were found than should exist")
1249 "More matching records were found than should exist")
1246 except Exception:
1250 except Exception:
1247 return finish(error.wrap_exception())
1251 return finish(error.wrap_exception())
1248 elif len(records) < len(msg_ids):
1252 elif len(records) < len(msg_ids):
1249 missing = [ m for m in msg_ids if m not in found_ids ]
1253 missing = [ m for m in msg_ids if m not in found_ids ]
1250 try:
1254 try:
1251 raise KeyError("No such msg(s): %r" % missing)
1255 raise KeyError("No such msg(s): %r" % missing)
1252 except KeyError:
1256 except KeyError:
1253 return finish(error.wrap_exception())
1257 return finish(error.wrap_exception())
1254 elif pending_ids:
1258 elif pending_ids:
1255 pass
1259 pass
1256 # no need to raise on resubmit of pending task, now that we
1260 # no need to raise on resubmit of pending task, now that we
1257 # resubmit under new ID, but do we want to raise anyway?
1261 # resubmit under new ID, but do we want to raise anyway?
1258 # msg_id = invalid_ids[0]
1262 # msg_id = invalid_ids[0]
1259 # try:
1263 # try:
1260 # raise ValueError("Task(s) %r appears to be inflight" % )
1264 # raise ValueError("Task(s) %r appears to be inflight" % )
1261 # except Exception:
1265 # except Exception:
1262 # return finish(error.wrap_exception())
1266 # return finish(error.wrap_exception())
1263
1267
1264 # mapping of original IDs to resubmitted IDs
1268 # mapping of original IDs to resubmitted IDs
1265 resubmitted = {}
1269 resubmitted = {}
1266
1270
1267 # send the messages
1271 # send the messages
1268 for rec in records:
1272 for rec in records:
1269 header = rec['header']
1273 header = rec['header']
1270 msg = self.session.msg(header['msg_type'], parent=header)
1274 msg = self.session.msg(header['msg_type'], parent=header)
1271 msg_id = msg['msg_id']
1275 msg_id = msg['msg_id']
1272 msg['content'] = rec['content']
1276 msg['content'] = rec['content']
1273
1277
1274 # use the old header, but update msg_id and timestamp
1278 # use the old header, but update msg_id and timestamp
1275 fresh = msg['header']
1279 fresh = msg['header']
1276 header['msg_id'] = fresh['msg_id']
1280 header['msg_id'] = fresh['msg_id']
1277 header['date'] = fresh['date']
1281 header['date'] = fresh['date']
1278 msg['header'] = header
1282 msg['header'] = header
1279
1283
1280 self.session.send(self.resubmit, msg, buffers=rec['buffers'])
1284 self.session.send(self.resubmit, msg, buffers=rec['buffers'])
1281
1285
1282 resubmitted[rec['msg_id']] = msg_id
1286 resubmitted[rec['msg_id']] = msg_id
1283 self.pending.add(msg_id)
1287 self.pending.add(msg_id)
1284 msg['buffers'] = rec['buffers']
1288 msg['buffers'] = rec['buffers']
1285 try:
1289 try:
1286 self.db.add_record(msg_id, init_record(msg))
1290 self.db.add_record(msg_id, init_record(msg))
1287 except Exception:
1291 except Exception:
1288 self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True)
1292 self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True)
1289 return finish(error.wrap_exception())
1293 return finish(error.wrap_exception())
1290
1294
1291 finish(dict(status='ok', resubmitted=resubmitted))
1295 finish(dict(status='ok', resubmitted=resubmitted))
1292
1296
1293 # store the new IDs in the Task DB
1297 # store the new IDs in the Task DB
1294 for msg_id, resubmit_id in iteritems(resubmitted):
1298 for msg_id, resubmit_id in iteritems(resubmitted):
1295 try:
1299 try:
1296 self.db.update_record(msg_id, {'resubmitted' : resubmit_id})
1300 self.db.update_record(msg_id, {'resubmitted' : resubmit_id})
1297 except Exception:
1301 except Exception:
1298 self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True)
1302 self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True)
1299
1303
1300
1304
1301 def _extract_record(self, rec):
1305 def _extract_record(self, rec):
1302 """decompose a TaskRecord dict into subsection of reply for get_result"""
1306 """decompose a TaskRecord dict into subsection of reply for get_result"""
1303 io_dict = {}
1307 io_dict = {}
1304 for key in ('pyin', 'pyout', 'pyerr', 'stdout', 'stderr'):
1308 for key in ('pyin', 'pyout', 'pyerr', 'stdout', 'stderr'):
1305 io_dict[key] = rec[key]
1309 io_dict[key] = rec[key]
1306 content = {
1310 content = {
1307 'header': rec['header'],
1311 'header': rec['header'],
1308 'metadata': rec['metadata'],
1312 'metadata': rec['metadata'],
1309 'result_metadata': rec['result_metadata'],
1313 'result_metadata': rec['result_metadata'],
1310 'result_header' : rec['result_header'],
1314 'result_header' : rec['result_header'],
1311 'result_content': rec['result_content'],
1315 'result_content': rec['result_content'],
1312 'received' : rec['received'],
1316 'received' : rec['received'],
1313 'io' : io_dict,
1317 'io' : io_dict,
1314 }
1318 }
1315 if rec['result_buffers']:
1319 if rec['result_buffers']:
1316 buffers = list(map(bytes, rec['result_buffers']))
1320 buffers = list(map(bytes, rec['result_buffers']))
1317 else:
1321 else:
1318 buffers = []
1322 buffers = []
1319
1323
1320 return content, buffers
1324 return content, buffers
1321
1325
1322 def get_results(self, client_id, msg):
1326 def get_results(self, client_id, msg):
1323 """Get the result of 1 or more messages."""
1327 """Get the result of 1 or more messages."""
1324 content = msg['content']
1328 content = msg['content']
1325 msg_ids = sorted(set(content['msg_ids']))
1329 msg_ids = sorted(set(content['msg_ids']))
1326 statusonly = content.get('status_only', False)
1330 statusonly = content.get('status_only', False)
1327 pending = []
1331 pending = []
1328 completed = []
1332 completed = []
1329 content = dict(status='ok')
1333 content = dict(status='ok')
1330 content['pending'] = pending
1334 content['pending'] = pending
1331 content['completed'] = completed
1335 content['completed'] = completed
1332 buffers = []
1336 buffers = []
1333 if not statusonly:
1337 if not statusonly:
1334 try:
1338 try:
1335 matches = self.db.find_records(dict(msg_id={'$in':msg_ids}))
1339 matches = self.db.find_records(dict(msg_id={'$in':msg_ids}))
1336 # turn match list into dict, for faster lookup
1340 # turn match list into dict, for faster lookup
1337 records = {}
1341 records = {}
1338 for rec in matches:
1342 for rec in matches:
1339 records[rec['msg_id']] = rec
1343 records[rec['msg_id']] = rec
1340 except Exception:
1344 except Exception:
1341 content = error.wrap_exception()
1345 content = error.wrap_exception()
1342 self.session.send(self.query, "result_reply", content=content,
1346 self.session.send(self.query, "result_reply", content=content,
1343 parent=msg, ident=client_id)
1347 parent=msg, ident=client_id)
1344 return
1348 return
1345 else:
1349 else:
1346 records = {}
1350 records = {}
1347 for msg_id in msg_ids:
1351 for msg_id in msg_ids:
1348 if msg_id in self.pending:
1352 if msg_id in self.pending:
1349 pending.append(msg_id)
1353 pending.append(msg_id)
1350 elif msg_id in self.all_completed:
1354 elif msg_id in self.all_completed:
1351 completed.append(msg_id)
1355 completed.append(msg_id)
1352 if not statusonly:
1356 if not statusonly:
1353 c,bufs = self._extract_record(records[msg_id])
1357 c,bufs = self._extract_record(records[msg_id])
1354 content[msg_id] = c
1358 content[msg_id] = c
1355 buffers.extend(bufs)
1359 buffers.extend(bufs)
1356 elif msg_id in records:
1360 elif msg_id in records:
1357 if rec['completed']:
1361 if rec['completed']:
1358 completed.append(msg_id)
1362 completed.append(msg_id)
1359 c,bufs = self._extract_record(records[msg_id])
1363 c,bufs = self._extract_record(records[msg_id])
1360 content[msg_id] = c
1364 content[msg_id] = c
1361 buffers.extend(bufs)
1365 buffers.extend(bufs)
1362 else:
1366 else:
1363 pending.append(msg_id)
1367 pending.append(msg_id)
1364 else:
1368 else:
1365 try:
1369 try:
1366 raise KeyError('No such message: '+msg_id)
1370 raise KeyError('No such message: '+msg_id)
1367 except:
1371 except:
1368 content = error.wrap_exception()
1372 content = error.wrap_exception()
1369 break
1373 break
1370 self.session.send(self.query, "result_reply", content=content,
1374 self.session.send(self.query, "result_reply", content=content,
1371 parent=msg, ident=client_id,
1375 parent=msg, ident=client_id,
1372 buffers=buffers)
1376 buffers=buffers)
1373
1377
1374 def get_history(self, client_id, msg):
1378 def get_history(self, client_id, msg):
1375 """Get a list of all msg_ids in our DB records"""
1379 """Get a list of all msg_ids in our DB records"""
1376 try:
1380 try:
1377 msg_ids = self.db.get_history()
1381 msg_ids = self.db.get_history()
1378 except Exception as e:
1382 except Exception as e:
1379 content = error.wrap_exception()
1383 content = error.wrap_exception()
1380 else:
1384 else:
1381 content = dict(status='ok', history=msg_ids)
1385 content = dict(status='ok', history=msg_ids)
1382
1386
1383 self.session.send(self.query, "history_reply", content=content,
1387 self.session.send(self.query, "history_reply", content=content,
1384 parent=msg, ident=client_id)
1388 parent=msg, ident=client_id)
1385
1389
1386 def db_query(self, client_id, msg):
1390 def db_query(self, client_id, msg):
1387 """Perform a raw query on the task record database."""
1391 """Perform a raw query on the task record database."""
1388 content = msg['content']
1392 content = msg['content']
1389 query = extract_dates(content.get('query', {}))
1393 query = extract_dates(content.get('query', {}))
1390 keys = content.get('keys', None)
1394 keys = content.get('keys', None)
1391 buffers = []
1395 buffers = []
1392 empty = list()
1396 empty = list()
1393 try:
1397 try:
1394 records = self.db.find_records(query, keys)
1398 records = self.db.find_records(query, keys)
1395 except Exception as e:
1399 except Exception as e:
1396 content = error.wrap_exception()
1400 content = error.wrap_exception()
1397 else:
1401 else:
1398 # extract buffers from reply content:
1402 # extract buffers from reply content:
1399 if keys is not None:
1403 if keys is not None:
1400 buffer_lens = [] if 'buffers' in keys else None
1404 buffer_lens = [] if 'buffers' in keys else None
1401 result_buffer_lens = [] if 'result_buffers' in keys else None
1405 result_buffer_lens = [] if 'result_buffers' in keys else None
1402 else:
1406 else:
1403 buffer_lens = None
1407 buffer_lens = None
1404 result_buffer_lens = None
1408 result_buffer_lens = None
1405
1409
1406 for rec in records:
1410 for rec in records:
1407 # buffers may be None, so double check
1411 # buffers may be None, so double check
1408 b = rec.pop('buffers', empty) or empty
1412 b = rec.pop('buffers', empty) or empty
1409 if buffer_lens is not None:
1413 if buffer_lens is not None:
1410 buffer_lens.append(len(b))
1414 buffer_lens.append(len(b))
1411 buffers.extend(b)
1415 buffers.extend(b)
1412 rb = rec.pop('result_buffers', empty) or empty
1416 rb = rec.pop('result_buffers', empty) or empty
1413 if result_buffer_lens is not None:
1417 if result_buffer_lens is not None:
1414 result_buffer_lens.append(len(rb))
1418 result_buffer_lens.append(len(rb))
1415 buffers.extend(rb)
1419 buffers.extend(rb)
1416 content = dict(status='ok', records=records, buffer_lens=buffer_lens,
1420 content = dict(status='ok', records=records, buffer_lens=buffer_lens,
1417 result_buffer_lens=result_buffer_lens)
1421 result_buffer_lens=result_buffer_lens)
1418 # self.log.debug (content)
1422 # self.log.debug (content)
1419 self.session.send(self.query, "db_reply", content=content,
1423 self.session.send(self.query, "db_reply", content=content,
1420 parent=msg, ident=client_id,
1424 parent=msg, ident=client_id,
1421 buffers=buffers)
1425 buffers=buffers)
1422
1426
@@ -1,369 +1,370 b''
1 """some generic utilities for dealing with classes, urls, and serialization
1 """some generic utilities for dealing with classes, urls, and serialization
2
2
3 Authors:
3 Authors:
4
4
5 * Min RK
5 * Min RK
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2010-2011 The IPython Development Team
8 # Copyright (C) 2010-2011 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 # Standard library imports.
18 # Standard library imports.
19 import logging
19 import logging
20 import os
20 import os
21 import re
21 import re
22 import stat
22 import stat
23 import socket
23 import socket
24 import sys
24 import sys
25 from signal import signal, SIGINT, SIGABRT, SIGTERM
25 from signal import signal, SIGINT, SIGABRT, SIGTERM
26 try:
26 try:
27 from signal import SIGKILL
27 from signal import SIGKILL
28 except ImportError:
28 except ImportError:
29 SIGKILL=None
29 SIGKILL=None
30
30
31 try:
31 try:
32 import cPickle
32 import cPickle
33 pickle = cPickle
33 pickle = cPickle
34 except:
34 except:
35 cPickle = None
35 cPickle = None
36 import pickle
36 import pickle
37
37
38 # System library imports
38 # System library imports
39 import zmq
39 import zmq
40 from zmq.log import handlers
40 from zmq.log import handlers
41
41
42 from IPython.external.decorator import decorator
42 from IPython.external.decorator import decorator
43
43
44 # IPython imports
44 # IPython imports
45 from IPython.config.application import Application
45 from IPython.config.application import Application
46 from IPython.utils.localinterfaces import localhost, is_public_ip, public_ips
46 from IPython.utils.localinterfaces import localhost, is_public_ip, public_ips
47 from IPython.utils.py3compat import string_types, iteritems, itervalues
47 from IPython.utils.py3compat import string_types, iteritems, itervalues
48 from IPython.kernel.zmq.log import EnginePUBHandler
48 from IPython.kernel.zmq.log import EnginePUBHandler
49 from IPython.kernel.zmq.serialize import (
49 from IPython.kernel.zmq.serialize import (
50 unserialize_object, serialize_object, pack_apply_message, unpack_apply_message
50 unserialize_object, serialize_object, pack_apply_message, unpack_apply_message
51 )
51 )
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Classes
54 # Classes
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 class Namespace(dict):
57 class Namespace(dict):
58 """Subclass of dict for attribute access to keys."""
58 """Subclass of dict for attribute access to keys."""
59
59
60 def __getattr__(self, key):
60 def __getattr__(self, key):
61 """getattr aliased to getitem"""
61 """getattr aliased to getitem"""
62 if key in self:
62 if key in self:
63 return self[key]
63 return self[key]
64 else:
64 else:
65 raise NameError(key)
65 raise NameError(key)
66
66
67 def __setattr__(self, key, value):
67 def __setattr__(self, key, value):
68 """setattr aliased to setitem, with strict"""
68 """setattr aliased to setitem, with strict"""
69 if hasattr(dict, key):
69 if hasattr(dict, key):
70 raise KeyError("Cannot override dict keys %r"%key)
70 raise KeyError("Cannot override dict keys %r"%key)
71 self[key] = value
71 self[key] = value
72
72
73
73
74 class ReverseDict(dict):
74 class ReverseDict(dict):
75 """simple double-keyed subset of dict methods."""
75 """simple double-keyed subset of dict methods."""
76
76
77 def __init__(self, *args, **kwargs):
77 def __init__(self, *args, **kwargs):
78 dict.__init__(self, *args, **kwargs)
78 dict.__init__(self, *args, **kwargs)
79 self._reverse = dict()
79 self._reverse = dict()
80 for key, value in iteritems(self):
80 for key, value in iteritems(self):
81 self._reverse[value] = key
81 self._reverse[value] = key
82
82
83 def __getitem__(self, key):
83 def __getitem__(self, key):
84 try:
84 try:
85 return dict.__getitem__(self, key)
85 return dict.__getitem__(self, key)
86 except KeyError:
86 except KeyError:
87 return self._reverse[key]
87 return self._reverse[key]
88
88
89 def __setitem__(self, key, value):
89 def __setitem__(self, key, value):
90 if key in self._reverse:
90 if key in self._reverse:
91 raise KeyError("Can't have key %r on both sides!"%key)
91 raise KeyError("Can't have key %r on both sides!"%key)
92 dict.__setitem__(self, key, value)
92 dict.__setitem__(self, key, value)
93 self._reverse[value] = key
93 self._reverse[value] = key
94
94
95 def pop(self, key):
95 def pop(self, key):
96 value = dict.pop(self, key)
96 value = dict.pop(self, key)
97 self._reverse.pop(value)
97 self._reverse.pop(value)
98 return value
98 return value
99
99
100 def get(self, key, default=None):
100 def get(self, key, default=None):
101 try:
101 try:
102 return self[key]
102 return self[key]
103 except KeyError:
103 except KeyError:
104 return default
104 return default
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # Functions
107 # Functions
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110 @decorator
110 @decorator
111 def log_errors(f, self, *args, **kwargs):
111 def log_errors(f, self, *args, **kwargs):
112 """decorator to log unhandled exceptions raised in a method.
112 """decorator to log unhandled exceptions raised in a method.
113
113
114 For use wrapping on_recv callbacks, so that exceptions
114 For use wrapping on_recv callbacks, so that exceptions
115 do not cause the stream to be closed.
115 do not cause the stream to be closed.
116 """
116 """
117 try:
117 try:
118 return f(self, *args, **kwargs)
118 return f(self, *args, **kwargs)
119 except Exception:
119 except Exception:
120 self.log.error("Uncaught exception in %r" % f, exc_info=True)
120 self.log.error("Uncaught exception in %r" % f, exc_info=True)
121
121
122
122
123 def is_url(url):
123 def is_url(url):
124 """boolean check for whether a string is a zmq url"""
124 """boolean check for whether a string is a zmq url"""
125 if '://' not in url:
125 if '://' not in url:
126 return False
126 return False
127 proto, addr = url.split('://', 1)
127 proto, addr = url.split('://', 1)
128 if proto.lower() not in ['tcp','pgm','epgm','ipc','inproc']:
128 if proto.lower() not in ['tcp','pgm','epgm','ipc','inproc']:
129 return False
129 return False
130 return True
130 return True
131
131
132 def validate_url(url):
132 def validate_url(url):
133 """validate a url for zeromq"""
133 """validate a url for zeromq"""
134 if not isinstance(url, string_types):
134 if not isinstance(url, string_types):
135 raise TypeError("url must be a string, not %r"%type(url))
135 raise TypeError("url must be a string, not %r"%type(url))
136 url = url.lower()
136 url = url.lower()
137
137
138 proto_addr = url.split('://')
138 proto_addr = url.split('://')
139 assert len(proto_addr) == 2, 'Invalid url: %r'%url
139 assert len(proto_addr) == 2, 'Invalid url: %r'%url
140 proto, addr = proto_addr
140 proto, addr = proto_addr
141 assert proto in ['tcp','pgm','epgm','ipc','inproc'], "Invalid protocol: %r"%proto
141 assert proto in ['tcp','pgm','epgm','ipc','inproc'], "Invalid protocol: %r"%proto
142
142
143 # domain pattern adapted from http://www.regexlib.com/REDetails.aspx?regexp_id=391
143 # domain pattern adapted from http://www.regexlib.com/REDetails.aspx?regexp_id=391
144 # author: Remi Sabourin
144 # author: Remi Sabourin
145 pat = re.compile(r'^([\w\d]([\w\d\-]{0,61}[\w\d])?\.)*[\w\d]([\w\d\-]{0,61}[\w\d])?$')
145 pat = re.compile(r'^([\w\d]([\w\d\-]{0,61}[\w\d])?\.)*[\w\d]([\w\d\-]{0,61}[\w\d])?$')
146
146
147 if proto == 'tcp':
147 if proto == 'tcp':
148 lis = addr.split(':')
148 lis = addr.split(':')
149 assert len(lis) == 2, 'Invalid url: %r'%url
149 assert len(lis) == 2, 'Invalid url: %r'%url
150 addr,s_port = lis
150 addr,s_port = lis
151 try:
151 try:
152 port = int(s_port)
152 port = int(s_port)
153 except ValueError:
153 except ValueError:
154 raise AssertionError("Invalid port %r in url: %r"%(port, url))
154 raise AssertionError("Invalid port %r in url: %r"%(port, url))
155
155
156 assert addr == '*' or pat.match(addr) is not None, 'Invalid url: %r'%url
156 assert addr == '*' or pat.match(addr) is not None, 'Invalid url: %r'%url
157
157
158 else:
158 else:
159 # only validate tcp urls currently
159 # only validate tcp urls currently
160 pass
160 pass
161
161
162 return True
162 return True
163
163
164
164
165 def validate_url_container(container):
165 def validate_url_container(container):
166 """validate a potentially nested collection of urls."""
166 """validate a potentially nested collection of urls."""
167 if isinstance(container, string_types):
167 if isinstance(container, string_types):
168 url = container
168 url = container
169 return validate_url(url)
169 return validate_url(url)
170 elif isinstance(container, dict):
170 elif isinstance(container, dict):
171 container = itervalues(container)
171 container = itervalues(container)
172
172
173 for element in container:
173 for element in container:
174 validate_url_container(element)
174 validate_url_container(element)
175
175
176
176
177 def split_url(url):
177 def split_url(url):
178 """split a zmq url (tcp://ip:port) into ('tcp','ip','port')."""
178 """split a zmq url (tcp://ip:port) into ('tcp','ip','port')."""
179 proto_addr = url.split('://')
179 proto_addr = url.split('://')
180 assert len(proto_addr) == 2, 'Invalid url: %r'%url
180 assert len(proto_addr) == 2, 'Invalid url: %r'%url
181 proto, addr = proto_addr
181 proto, addr = proto_addr
182 lis = addr.split(':')
182 lis = addr.split(':')
183 assert len(lis) == 2, 'Invalid url: %r'%url
183 assert len(lis) == 2, 'Invalid url: %r'%url
184 addr,s_port = lis
184 addr,s_port = lis
185 return proto,addr,s_port
185 return proto,addr,s_port
186
186
187 def disambiguate_ip_address(ip, location=None):
187 def disambiguate_ip_address(ip, location=None):
188 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
188 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
189 ones, based on the location (default interpretation of location is localhost)."""
189 ones, based on the location (default interpretation of location is localhost)."""
190 if ip in ('0.0.0.0', '*'):
190 if ip in ('0.0.0.0', '*'):
191 if location is None or is_public_ip(location) or not public_ips():
191 if location is None or is_public_ip(location) or not public_ips():
192 # If location is unspecified or cannot be determined, assume local
192 # If location is unspecified or cannot be determined, assume local
193 ip = localhost()
193 ip = localhost()
194 elif location:
194 elif location:
195 return location
195 return location
196 return ip
196 return ip
197
197
198 def disambiguate_url(url, location=None):
198 def disambiguate_url(url, location=None):
199 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
199 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
200 ones, based on the location (default interpretation is localhost).
200 ones, based on the location (default interpretation is localhost).
201
201
202 This is for zeromq urls, such as tcp://*:10101."""
202 This is for zeromq urls, such as ``tcp://*:10101``.
203 """
203 try:
204 try:
204 proto,ip,port = split_url(url)
205 proto,ip,port = split_url(url)
205 except AssertionError:
206 except AssertionError:
206 # probably not tcp url; could be ipc, etc.
207 # probably not tcp url; could be ipc, etc.
207 return url
208 return url
208
209
209 ip = disambiguate_ip_address(ip,location)
210 ip = disambiguate_ip_address(ip,location)
210
211
211 return "%s://%s:%s"%(proto,ip,port)
212 return "%s://%s:%s"%(proto,ip,port)
212
213
213
214
214 #--------------------------------------------------------------------------
215 #--------------------------------------------------------------------------
215 # helpers for implementing old MEC API via view.apply
216 # helpers for implementing old MEC API via view.apply
216 #--------------------------------------------------------------------------
217 #--------------------------------------------------------------------------
217
218
218 def interactive(f):
219 def interactive(f):
219 """decorator for making functions appear as interactively defined.
220 """decorator for making functions appear as interactively defined.
220 This results in the function being linked to the user_ns as globals()
221 This results in the function being linked to the user_ns as globals()
221 instead of the module globals().
222 instead of the module globals().
222 """
223 """
223 f.__module__ = '__main__'
224 f.__module__ = '__main__'
224 return f
225 return f
225
226
226 @interactive
227 @interactive
227 def _push(**ns):
228 def _push(**ns):
228 """helper method for implementing `client.push` via `client.apply`"""
229 """helper method for implementing `client.push` via `client.apply`"""
229 user_ns = globals()
230 user_ns = globals()
230 tmp = '_IP_PUSH_TMP_'
231 tmp = '_IP_PUSH_TMP_'
231 while tmp in user_ns:
232 while tmp in user_ns:
232 tmp = tmp + '_'
233 tmp = tmp + '_'
233 try:
234 try:
234 for name, value in ns.items():
235 for name, value in ns.items():
235 user_ns[tmp] = value
236 user_ns[tmp] = value
236 exec("%s = %s" % (name, tmp), user_ns)
237 exec("%s = %s" % (name, tmp), user_ns)
237 finally:
238 finally:
238 user_ns.pop(tmp, None)
239 user_ns.pop(tmp, None)
239
240
240 @interactive
241 @interactive
241 def _pull(keys):
242 def _pull(keys):
242 """helper method for implementing `client.pull` via `client.apply`"""
243 """helper method for implementing `client.pull` via `client.apply`"""
243 if isinstance(keys, (list,tuple, set)):
244 if isinstance(keys, (list,tuple, set)):
244 return [eval(key, globals()) for key in keys]
245 return [eval(key, globals()) for key in keys]
245 else:
246 else:
246 return eval(keys, globals())
247 return eval(keys, globals())
247
248
248 @interactive
249 @interactive
249 def _execute(code):
250 def _execute(code):
250 """helper method for implementing `client.execute` via `client.apply`"""
251 """helper method for implementing `client.execute` via `client.apply`"""
251 exec(code, globals())
252 exec(code, globals())
252
253
253 #--------------------------------------------------------------------------
254 #--------------------------------------------------------------------------
254 # extra process management utilities
255 # extra process management utilities
255 #--------------------------------------------------------------------------
256 #--------------------------------------------------------------------------
256
257
257 _random_ports = set()
258 _random_ports = set()
258
259
259 def select_random_ports(n):
260 def select_random_ports(n):
260 """Selects and return n random ports that are available."""
261 """Selects and return n random ports that are available."""
261 ports = []
262 ports = []
262 for i in range(n):
263 for i in range(n):
263 sock = socket.socket()
264 sock = socket.socket()
264 sock.bind(('', 0))
265 sock.bind(('', 0))
265 while sock.getsockname()[1] in _random_ports:
266 while sock.getsockname()[1] in _random_ports:
266 sock.close()
267 sock.close()
267 sock = socket.socket()
268 sock = socket.socket()
268 sock.bind(('', 0))
269 sock.bind(('', 0))
269 ports.append(sock)
270 ports.append(sock)
270 for i, sock in enumerate(ports):
271 for i, sock in enumerate(ports):
271 port = sock.getsockname()[1]
272 port = sock.getsockname()[1]
272 sock.close()
273 sock.close()
273 ports[i] = port
274 ports[i] = port
274 _random_ports.add(port)
275 _random_ports.add(port)
275 return ports
276 return ports
276
277
277 def signal_children(children):
278 def signal_children(children):
278 """Relay interupt/term signals to children, for more solid process cleanup."""
279 """Relay interupt/term signals to children, for more solid process cleanup."""
279 def terminate_children(sig, frame):
280 def terminate_children(sig, frame):
280 log = Application.instance().log
281 log = Application.instance().log
281 log.critical("Got signal %i, terminating children..."%sig)
282 log.critical("Got signal %i, terminating children..."%sig)
282 for child in children:
283 for child in children:
283 child.terminate()
284 child.terminate()
284
285
285 sys.exit(sig != SIGINT)
286 sys.exit(sig != SIGINT)
286 # sys.exit(sig)
287 # sys.exit(sig)
287 for sig in (SIGINT, SIGABRT, SIGTERM):
288 for sig in (SIGINT, SIGABRT, SIGTERM):
288 signal(sig, terminate_children)
289 signal(sig, terminate_children)
289
290
290 def generate_exec_key(keyfile):
291 def generate_exec_key(keyfile):
291 import uuid
292 import uuid
292 newkey = str(uuid.uuid4())
293 newkey = str(uuid.uuid4())
293 with open(keyfile, 'w') as f:
294 with open(keyfile, 'w') as f:
294 # f.write('ipython-key ')
295 # f.write('ipython-key ')
295 f.write(newkey+'\n')
296 f.write(newkey+'\n')
296 # set user-only RW permissions (0600)
297 # set user-only RW permissions (0600)
297 # this will have no effect on Windows
298 # this will have no effect on Windows
298 os.chmod(keyfile, stat.S_IRUSR|stat.S_IWUSR)
299 os.chmod(keyfile, stat.S_IRUSR|stat.S_IWUSR)
299
300
300
301
301 def integer_loglevel(loglevel):
302 def integer_loglevel(loglevel):
302 try:
303 try:
303 loglevel = int(loglevel)
304 loglevel = int(loglevel)
304 except ValueError:
305 except ValueError:
305 if isinstance(loglevel, str):
306 if isinstance(loglevel, str):
306 loglevel = getattr(logging, loglevel)
307 loglevel = getattr(logging, loglevel)
307 return loglevel
308 return loglevel
308
309
309 def connect_logger(logname, context, iface, root="ip", loglevel=logging.DEBUG):
310 def connect_logger(logname, context, iface, root="ip", loglevel=logging.DEBUG):
310 logger = logging.getLogger(logname)
311 logger = logging.getLogger(logname)
311 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
312 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
312 # don't add a second PUBHandler
313 # don't add a second PUBHandler
313 return
314 return
314 loglevel = integer_loglevel(loglevel)
315 loglevel = integer_loglevel(loglevel)
315 lsock = context.socket(zmq.PUB)
316 lsock = context.socket(zmq.PUB)
316 lsock.connect(iface)
317 lsock.connect(iface)
317 handler = handlers.PUBHandler(lsock)
318 handler = handlers.PUBHandler(lsock)
318 handler.setLevel(loglevel)
319 handler.setLevel(loglevel)
319 handler.root_topic = root
320 handler.root_topic = root
320 logger.addHandler(handler)
321 logger.addHandler(handler)
321 logger.setLevel(loglevel)
322 logger.setLevel(loglevel)
322
323
323 def connect_engine_logger(context, iface, engine, loglevel=logging.DEBUG):
324 def connect_engine_logger(context, iface, engine, loglevel=logging.DEBUG):
324 logger = logging.getLogger()
325 logger = logging.getLogger()
325 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
326 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
326 # don't add a second PUBHandler
327 # don't add a second PUBHandler
327 return
328 return
328 loglevel = integer_loglevel(loglevel)
329 loglevel = integer_loglevel(loglevel)
329 lsock = context.socket(zmq.PUB)
330 lsock = context.socket(zmq.PUB)
330 lsock.connect(iface)
331 lsock.connect(iface)
331 handler = EnginePUBHandler(engine, lsock)
332 handler = EnginePUBHandler(engine, lsock)
332 handler.setLevel(loglevel)
333 handler.setLevel(loglevel)
333 logger.addHandler(handler)
334 logger.addHandler(handler)
334 logger.setLevel(loglevel)
335 logger.setLevel(loglevel)
335 return logger
336 return logger
336
337
337 def local_logger(logname, loglevel=logging.DEBUG):
338 def local_logger(logname, loglevel=logging.DEBUG):
338 loglevel = integer_loglevel(loglevel)
339 loglevel = integer_loglevel(loglevel)
339 logger = logging.getLogger(logname)
340 logger = logging.getLogger(logname)
340 if any([isinstance(h, logging.StreamHandler) for h in logger.handlers]):
341 if any([isinstance(h, logging.StreamHandler) for h in logger.handlers]):
341 # don't add a second StreamHandler
342 # don't add a second StreamHandler
342 return
343 return
343 handler = logging.StreamHandler()
344 handler = logging.StreamHandler()
344 handler.setLevel(loglevel)
345 handler.setLevel(loglevel)
345 formatter = logging.Formatter("%(asctime)s.%(msecs).03d [%(name)s] %(message)s",
346 formatter = logging.Formatter("%(asctime)s.%(msecs).03d [%(name)s] %(message)s",
346 datefmt="%Y-%m-%d %H:%M:%S")
347 datefmt="%Y-%m-%d %H:%M:%S")
347 handler.setFormatter(formatter)
348 handler.setFormatter(formatter)
348
349
349 logger.addHandler(handler)
350 logger.addHandler(handler)
350 logger.setLevel(loglevel)
351 logger.setLevel(loglevel)
351 return logger
352 return logger
352
353
353 def set_hwm(sock, hwm=0):
354 def set_hwm(sock, hwm=0):
354 """set zmq High Water Mark on a socket
355 """set zmq High Water Mark on a socket
355
356
356 in a way that always works for various pyzmq / libzmq versions.
357 in a way that always works for various pyzmq / libzmq versions.
357 """
358 """
358 import zmq
359 import zmq
359
360
360 for key in ('HWM', 'SNDHWM', 'RCVHWM'):
361 for key in ('HWM', 'SNDHWM', 'RCVHWM'):
361 opt = getattr(zmq, key, None)
362 opt = getattr(zmq, key, None)
362 if opt is None:
363 if opt is None:
363 continue
364 continue
364 try:
365 try:
365 sock.setsockopt(opt, hwm)
366 sock.setsockopt(opt, hwm)
366 except zmq.ZMQError:
367 except zmq.ZMQError:
367 pass
368 pass
368
369
369 No newline at end of file
370
@@ -1,692 +1,691 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Subclass of InteractiveShell for terminal based frontends."""
2 """Subclass of InteractiveShell for terminal based frontends."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
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 import bdb
18 import bdb
19 import os
19 import os
20 import sys
20 import sys
21
21
22 from IPython.core.error import TryNext, UsageError
22 from IPython.core.error import TryNext, UsageError
23 from IPython.core.usage import interactive_usage, default_banner
23 from IPython.core.usage import interactive_usage, default_banner
24 from IPython.core.inputsplitter import IPythonInputSplitter
24 from IPython.core.inputsplitter import IPythonInputSplitter
25 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
25 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
26 from IPython.core.magic import Magics, magics_class, line_magic
26 from IPython.core.magic import Magics, magics_class, line_magic
27 from IPython.lib.clipboard import ClipboardEmpty
27 from IPython.lib.clipboard import ClipboardEmpty
28 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.utils.encoding import get_stream_enc
29 from IPython.utils.encoding import get_stream_enc
30 from IPython.utils import py3compat
30 from IPython.utils import py3compat
31 from IPython.utils.terminal import toggle_set_term_title, set_term_title
31 from IPython.utils.terminal import toggle_set_term_title, set_term_title
32 from IPython.utils.process import abbrev_cwd
32 from IPython.utils.process import abbrev_cwd
33 from IPython.utils.warn import warn, error
33 from IPython.utils.warn import warn, error
34 from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes
34 from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes
35 from IPython.utils.traitlets import Integer, CBool, Unicode
35 from IPython.utils.traitlets import Integer, CBool, Unicode
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Utilities
38 # Utilities
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 def get_default_editor():
41 def get_default_editor():
42 try:
42 try:
43 ed = os.environ['EDITOR']
43 ed = os.environ['EDITOR']
44 except KeyError:
44 except KeyError:
45 if os.name == 'posix':
45 if os.name == 'posix':
46 ed = 'vi' # the only one guaranteed to be there!
46 ed = 'vi' # the only one guaranteed to be there!
47 else:
47 else:
48 ed = 'notepad' # same in Windows!
48 ed = 'notepad' # same in Windows!
49 return ed
49 return ed
50
50
51
51
52 def get_pasted_lines(sentinel, l_input=py3compat.input):
52 def get_pasted_lines(sentinel, l_input=py3compat.input):
53 """ Yield pasted lines until the user enters the given sentinel value.
53 """ Yield pasted lines until the user enters the given sentinel value.
54 """
54 """
55 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
55 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
56 % sentinel)
56 % sentinel)
57 while True:
57 while True:
58 try:
58 try:
59 l = l_input(':')
59 l = l_input(':')
60 if l == sentinel:
60 if l == sentinel:
61 return
61 return
62 else:
62 else:
63 yield l
63 yield l
64 except EOFError:
64 except EOFError:
65 print('<EOF>')
65 print('<EOF>')
66 return
66 return
67
67
68
68
69 #------------------------------------------------------------------------
69 #------------------------------------------------------------------------
70 # Terminal-specific magics
70 # Terminal-specific magics
71 #------------------------------------------------------------------------
71 #------------------------------------------------------------------------
72
72
73 @magics_class
73 @magics_class
74 class TerminalMagics(Magics):
74 class TerminalMagics(Magics):
75 def __init__(self, shell):
75 def __init__(self, shell):
76 super(TerminalMagics, self).__init__(shell)
76 super(TerminalMagics, self).__init__(shell)
77 self.input_splitter = IPythonInputSplitter()
77 self.input_splitter = IPythonInputSplitter()
78
78
79 def store_or_execute(self, block, name):
79 def store_or_execute(self, block, name):
80 """ Execute a block, or store it in a variable, per the user's request.
80 """ Execute a block, or store it in a variable, per the user's request.
81 """
81 """
82 if name:
82 if name:
83 # If storing it for further editing
83 # If storing it for further editing
84 self.shell.user_ns[name] = SList(block.splitlines())
84 self.shell.user_ns[name] = SList(block.splitlines())
85 print("Block assigned to '%s'" % name)
85 print("Block assigned to '%s'" % name)
86 else:
86 else:
87 b = self.preclean_input(block)
87 b = self.preclean_input(block)
88 self.shell.user_ns['pasted_block'] = b
88 self.shell.user_ns['pasted_block'] = b
89 self.shell.using_paste_magics = True
89 self.shell.using_paste_magics = True
90 try:
90 try:
91 self.shell.run_cell(b)
91 self.shell.run_cell(b)
92 finally:
92 finally:
93 self.shell.using_paste_magics = False
93 self.shell.using_paste_magics = False
94
94
95 def preclean_input(self, block):
95 def preclean_input(self, block):
96 lines = block.splitlines()
96 lines = block.splitlines()
97 while lines and not lines[0].strip():
97 while lines and not lines[0].strip():
98 lines = lines[1:]
98 lines = lines[1:]
99 return strip_email_quotes('\n'.join(lines))
99 return strip_email_quotes('\n'.join(lines))
100
100
101 def rerun_pasted(self, name='pasted_block'):
101 def rerun_pasted(self, name='pasted_block'):
102 """ Rerun a previously pasted command.
102 """ Rerun a previously pasted command.
103 """
103 """
104 b = self.shell.user_ns.get(name)
104 b = self.shell.user_ns.get(name)
105
105
106 # Sanity checks
106 # Sanity checks
107 if b is None:
107 if b is None:
108 raise UsageError('No previous pasted block available')
108 raise UsageError('No previous pasted block available')
109 if not isinstance(b, py3compat.string_types):
109 if not isinstance(b, py3compat.string_types):
110 raise UsageError(
110 raise UsageError(
111 "Variable 'pasted_block' is not a string, can't execute")
111 "Variable 'pasted_block' is not a string, can't execute")
112
112
113 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
113 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
114 self.shell.run_cell(b)
114 self.shell.run_cell(b)
115
115
116 @line_magic
116 @line_magic
117 def autoindent(self, parameter_s = ''):
117 def autoindent(self, parameter_s = ''):
118 """Toggle autoindent on/off (if available)."""
118 """Toggle autoindent on/off (if available)."""
119
119
120 self.shell.set_autoindent()
120 self.shell.set_autoindent()
121 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
121 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
122
122
123 @skip_doctest
123 @skip_doctest
124 @line_magic
124 @line_magic
125 def cpaste(self, parameter_s=''):
125 def cpaste(self, parameter_s=''):
126 """Paste & execute a pre-formatted code block from clipboard.
126 """Paste & execute a pre-formatted code block from clipboard.
127
127
128 You must terminate the block with '--' (two minus-signs) or Ctrl-D
128 You must terminate the block with '--' (two minus-signs) or Ctrl-D
129 alone on the line. You can also provide your own sentinel with '%paste
129 alone on the line. You can also provide your own sentinel with '%paste
130 -s %%' ('%%' is the new sentinel for this operation)
130 -s %%' ('%%' is the new sentinel for this operation)
131
131
132 The block is dedented prior to execution to enable execution of method
132 The block is dedented prior to execution to enable execution of method
133 definitions. '>' and '+' characters at the beginning of a line are
133 definitions. '>' and '+' characters at the beginning of a line are
134 ignored, to allow pasting directly from e-mails, diff files and
134 ignored, to allow pasting directly from e-mails, diff files and
135 doctests (the '...' continuation prompt is also stripped). The
135 doctests (the '...' continuation prompt is also stripped). The
136 executed block is also assigned to variable named 'pasted_block' for
136 executed block is also assigned to variable named 'pasted_block' for
137 later editing with '%edit pasted_block'.
137 later editing with '%edit pasted_block'.
138
138
139 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
139 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
140 This assigns the pasted block to variable 'foo' as string, without
140 This assigns the pasted block to variable 'foo' as string, without
141 dedenting or executing it (preceding >>> and + is still stripped)
141 dedenting or executing it (preceding >>> and + is still stripped)
142
142
143 '%cpaste -r' re-executes the block previously entered by cpaste.
143 '%cpaste -r' re-executes the block previously entered by cpaste.
144
144
145 Do not be alarmed by garbled output on Windows (it's a readline bug).
145 Do not be alarmed by garbled output on Windows (it's a readline bug).
146 Just press enter and type -- (and press enter again) and the block
146 Just press enter and type -- (and press enter again) and the block
147 will be what was just pasted.
147 will be what was just pasted.
148
148
149 IPython statements (magics, shell escapes) are not supported (yet).
149 IPython statements (magics, shell escapes) are not supported (yet).
150
150
151 See also
151 See also
152 --------
152 --------
153 paste: automatically pull code from clipboard.
153 paste: automatically pull code from clipboard.
154
154
155 Examples
155 Examples
156 --------
156 --------
157 ::
157 ::
158
158
159 In [8]: %cpaste
159 In [8]: %cpaste
160 Pasting code; enter '--' alone on the line to stop.
160 Pasting code; enter '--' alone on the line to stop.
161 :>>> a = ["world!", "Hello"]
161 :>>> a = ["world!", "Hello"]
162 :>>> print " ".join(sorted(a))
162 :>>> print " ".join(sorted(a))
163 :--
163 :--
164 Hello world!
164 Hello world!
165 """
165 """
166 opts, name = self.parse_options(parameter_s, 'rs:', mode='string')
166 opts, name = self.parse_options(parameter_s, 'rs:', mode='string')
167 if 'r' in opts:
167 if 'r' in opts:
168 self.rerun_pasted()
168 self.rerun_pasted()
169 return
169 return
170
170
171 sentinel = opts.get('s', '--')
171 sentinel = opts.get('s', '--')
172 block = '\n'.join(get_pasted_lines(sentinel))
172 block = '\n'.join(get_pasted_lines(sentinel))
173 self.store_or_execute(block, name)
173 self.store_or_execute(block, name)
174
174
175 @line_magic
175 @line_magic
176 def paste(self, parameter_s=''):
176 def paste(self, parameter_s=''):
177 """Paste & execute a pre-formatted code block from clipboard.
177 """Paste & execute a pre-formatted code block from clipboard.
178
178
179 The text is pulled directly from the clipboard without user
179 The text is pulled directly from the clipboard without user
180 intervention and printed back on the screen before execution (unless
180 intervention and printed back on the screen before execution (unless
181 the -q flag is given to force quiet mode).
181 the -q flag is given to force quiet mode).
182
182
183 The block is dedented prior to execution to enable execution of method
183 The block is dedented prior to execution to enable execution of method
184 definitions. '>' and '+' characters at the beginning of a line are
184 definitions. '>' and '+' characters at the beginning of a line are
185 ignored, to allow pasting directly from e-mails, diff files and
185 ignored, to allow pasting directly from e-mails, diff files and
186 doctests (the '...' continuation prompt is also stripped). The
186 doctests (the '...' continuation prompt is also stripped). The
187 executed block is also assigned to variable named 'pasted_block' for
187 executed block is also assigned to variable named 'pasted_block' for
188 later editing with '%edit pasted_block'.
188 later editing with '%edit pasted_block'.
189
189
190 You can also pass a variable name as an argument, e.g. '%paste foo'.
190 You can also pass a variable name as an argument, e.g. '%paste foo'.
191 This assigns the pasted block to variable 'foo' as string, without
191 This assigns the pasted block to variable 'foo' as string, without
192 executing it (preceding >>> and + is still stripped).
192 executing it (preceding >>> and + is still stripped).
193
193
194 Options:
194 Options:
195
195
196 -r: re-executes the block previously entered by cpaste.
196 -r: re-executes the block previously entered by cpaste.
197
197
198 -q: quiet mode: do not echo the pasted text back to the terminal.
198 -q: quiet mode: do not echo the pasted text back to the terminal.
199
199
200 IPython statements (magics, shell escapes) are not supported (yet).
200 IPython statements (magics, shell escapes) are not supported (yet).
201
201
202 See also
202 See also
203 --------
203 --------
204 cpaste: manually paste code into terminal until you mark its end.
204 cpaste: manually paste code into terminal until you mark its end.
205 """
205 """
206 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
206 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
207 if 'r' in opts:
207 if 'r' in opts:
208 self.rerun_pasted()
208 self.rerun_pasted()
209 return
209 return
210 try:
210 try:
211 block = self.shell.hooks.clipboard_get()
211 block = self.shell.hooks.clipboard_get()
212 except TryNext as clipboard_exc:
212 except TryNext as clipboard_exc:
213 message = getattr(clipboard_exc, 'args')
213 message = getattr(clipboard_exc, 'args')
214 if message:
214 if message:
215 error(message[0])
215 error(message[0])
216 else:
216 else:
217 error('Could not get text from the clipboard.')
217 error('Could not get text from the clipboard.')
218 return
218 return
219 except ClipboardEmpty:
219 except ClipboardEmpty:
220 raise UsageError("The clipboard appears to be empty")
220 raise UsageError("The clipboard appears to be empty")
221
221
222 # By default, echo back to terminal unless quiet mode is requested
222 # By default, echo back to terminal unless quiet mode is requested
223 if 'q' not in opts:
223 if 'q' not in opts:
224 write = self.shell.write
224 write = self.shell.write
225 write(self.shell.pycolorize(block))
225 write(self.shell.pycolorize(block))
226 if not block.endswith('\n'):
226 if not block.endswith('\n'):
227 write('\n')
227 write('\n')
228 write("## -- End pasted text --\n")
228 write("## -- End pasted text --\n")
229
229
230 self.store_or_execute(block, name)
230 self.store_or_execute(block, name)
231
231
232 # Class-level: add a '%cls' magic only on Windows
232 # Class-level: add a '%cls' magic only on Windows
233 if sys.platform == 'win32':
233 if sys.platform == 'win32':
234 @line_magic
234 @line_magic
235 def cls(self, s):
235 def cls(self, s):
236 """Clear screen.
236 """Clear screen.
237 """
237 """
238 os.system("cls")
238 os.system("cls")
239
239
240 #-----------------------------------------------------------------------------
240 #-----------------------------------------------------------------------------
241 # Main class
241 # Main class
242 #-----------------------------------------------------------------------------
242 #-----------------------------------------------------------------------------
243
243
244 class TerminalInteractiveShell(InteractiveShell):
244 class TerminalInteractiveShell(InteractiveShell):
245
245
246 autoedit_syntax = CBool(False, config=True,
246 autoedit_syntax = CBool(False, config=True,
247 help="auto editing of files with syntax errors.")
247 help="auto editing of files with syntax errors.")
248 banner = Unicode('')
248 banner = Unicode('')
249 banner1 = Unicode(default_banner, config=True,
249 banner1 = Unicode(default_banner, config=True,
250 help="""The part of the banner to be printed before the profile"""
250 help="""The part of the banner to be printed before the profile"""
251 )
251 )
252 banner2 = Unicode('', config=True,
252 banner2 = Unicode('', config=True,
253 help="""The part of the banner to be printed after the profile"""
253 help="""The part of the banner to be printed after the profile"""
254 )
254 )
255 confirm_exit = CBool(True, config=True,
255 confirm_exit = CBool(True, config=True,
256 help="""
256 help="""
257 Set to confirm when you try to exit IPython with an EOF (Control-D
257 Set to confirm when you try to exit IPython with an EOF (Control-D
258 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
258 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
259 you can force a direct exit without any confirmation.""",
259 you can force a direct exit without any confirmation.""",
260 )
260 )
261 # This display_banner only controls whether or not self.show_banner()
261 # This display_banner only controls whether or not self.show_banner()
262 # is called when mainloop/interact are called. The default is False
262 # is called when mainloop/interact are called. The default is False
263 # because for the terminal based application, the banner behavior
263 # because for the terminal based application, the banner behavior
264 # is controlled by Global.display_banner, which IPythonApp looks at
264 # is controlled by Global.display_banner, which IPythonApp looks at
265 # to determine if *it* should call show_banner() by hand or not.
265 # to determine if *it* should call show_banner() by hand or not.
266 display_banner = CBool(False) # This isn't configurable!
266 display_banner = CBool(False) # This isn't configurable!
267 embedded = CBool(False)
267 embedded = CBool(False)
268 embedded_active = CBool(False)
268 embedded_active = CBool(False)
269 editor = Unicode(get_default_editor(), config=True,
269 editor = Unicode(get_default_editor(), config=True,
270 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
270 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
271 )
271 )
272 pager = Unicode('less', config=True,
272 pager = Unicode('less', config=True,
273 help="The shell program to be used for paging.")
273 help="The shell program to be used for paging.")
274
274
275 screen_length = Integer(0, config=True,
275 screen_length = Integer(0, config=True,
276 help=
276 help=
277 """Number of lines of your screen, used to control printing of very
277 """Number of lines of your screen, used to control printing of very
278 long strings. Strings longer than this number of lines will be sent
278 long strings. Strings longer than this number of lines will be sent
279 through a pager instead of directly printed. The default value for
279 through a pager instead of directly printed. The default value for
280 this is 0, which means IPython will auto-detect your screen size every
280 this is 0, which means IPython will auto-detect your screen size every
281 time it needs to print certain potentially long strings (this doesn't
281 time it needs to print certain potentially long strings (this doesn't
282 change the behavior of the 'print' keyword, it's only triggered
282 change the behavior of the 'print' keyword, it's only triggered
283 internally). If for some reason this isn't working well (it needs
283 internally). If for some reason this isn't working well (it needs
284 curses support), specify it yourself. Otherwise don't change the
284 curses support), specify it yourself. Otherwise don't change the
285 default.""",
285 default.""",
286 )
286 )
287 term_title = CBool(False, config=True,
287 term_title = CBool(False, config=True,
288 help="Enable auto setting the terminal title."
288 help="Enable auto setting the terminal title."
289 )
289 )
290
290
291 # This `using_paste_magics` is used to detect whether the code is being
291 # This `using_paste_magics` is used to detect whether the code is being
292 # executed via paste magics functions
292 # executed via paste magics functions
293 using_paste_magics = CBool(False)
293 using_paste_magics = CBool(False)
294
294
295 # In the terminal, GUI control is done via PyOS_InputHook
295 # In the terminal, GUI control is done via PyOS_InputHook
296 @staticmethod
296 @staticmethod
297 def enable_gui(gui=None, app=None):
297 def enable_gui(gui=None, app=None):
298 """Switch amongst GUI input hooks by name.
298 """Switch amongst GUI input hooks by name.
299 """
299 """
300 # Deferred import
300 # Deferred import
301 from IPython.lib.inputhook import enable_gui as real_enable_gui
301 from IPython.lib.inputhook import enable_gui as real_enable_gui
302 try:
302 try:
303 return real_enable_gui(gui, app)
303 return real_enable_gui(gui, app)
304 except ValueError as e:
304 except ValueError as e:
305 raise UsageError("%s" % e)
305 raise UsageError("%s" % e)
306
306
307 def __init__(self, config=None, ipython_dir=None, profile_dir=None,
307 def __init__(self, config=None, ipython_dir=None, profile_dir=None,
308 user_ns=None, user_module=None, custom_exceptions=((),None),
308 user_ns=None, user_module=None, custom_exceptions=((),None),
309 usage=None, banner1=None, banner2=None, display_banner=None,
309 usage=None, banner1=None, banner2=None, display_banner=None,
310 **kwargs):
310 **kwargs):
311
311
312 super(TerminalInteractiveShell, self).__init__(
312 super(TerminalInteractiveShell, self).__init__(
313 config=config, ipython_dir=ipython_dir, profile_dir=profile_dir, user_ns=user_ns,
313 config=config, ipython_dir=ipython_dir, profile_dir=profile_dir, user_ns=user_ns,
314 user_module=user_module, custom_exceptions=custom_exceptions,
314 user_module=user_module, custom_exceptions=custom_exceptions,
315 **kwargs
315 **kwargs
316 )
316 )
317 # use os.system instead of utils.process.system by default,
317 # use os.system instead of utils.process.system by default,
318 # because piped system doesn't make sense in the Terminal:
318 # because piped system doesn't make sense in the Terminal:
319 self.system = self.system_raw
319 self.system = self.system_raw
320
320
321 self.init_term_title()
321 self.init_term_title()
322 self.init_usage(usage)
322 self.init_usage(usage)
323 self.init_banner(banner1, banner2, display_banner)
323 self.init_banner(banner1, banner2, display_banner)
324
324
325 #-------------------------------------------------------------------------
325 #-------------------------------------------------------------------------
326 # Overrides of init stages
326 # Overrides of init stages
327 #-------------------------------------------------------------------------
327 #-------------------------------------------------------------------------
328
328
329 def init_display_formatter(self):
329 def init_display_formatter(self):
330 super(TerminalInteractiveShell, self).init_display_formatter()
330 super(TerminalInteractiveShell, self).init_display_formatter()
331 # terminal only supports plaintext
331 # terminal only supports plaintext
332 self.display_formatter.active_types = ['text/plain']
332 self.display_formatter.active_types = ['text/plain']
333
333
334 #-------------------------------------------------------------------------
334 #-------------------------------------------------------------------------
335 # Things related to the terminal
335 # Things related to the terminal
336 #-------------------------------------------------------------------------
336 #-------------------------------------------------------------------------
337
337
338 @property
338 @property
339 def usable_screen_length(self):
339 def usable_screen_length(self):
340 if self.screen_length == 0:
340 if self.screen_length == 0:
341 return 0
341 return 0
342 else:
342 else:
343 num_lines_bot = self.separate_in.count('\n')+1
343 num_lines_bot = self.separate_in.count('\n')+1
344 return self.screen_length - num_lines_bot
344 return self.screen_length - num_lines_bot
345
345
346 def init_term_title(self):
346 def init_term_title(self):
347 # Enable or disable the terminal title.
347 # Enable or disable the terminal title.
348 if self.term_title:
348 if self.term_title:
349 toggle_set_term_title(True)
349 toggle_set_term_title(True)
350 set_term_title('IPython: ' + abbrev_cwd())
350 set_term_title('IPython: ' + abbrev_cwd())
351 else:
351 else:
352 toggle_set_term_title(False)
352 toggle_set_term_title(False)
353
353
354 #-------------------------------------------------------------------------
354 #-------------------------------------------------------------------------
355 # Things related to aliases
355 # Things related to aliases
356 #-------------------------------------------------------------------------
356 #-------------------------------------------------------------------------
357
357
358 def init_alias(self):
358 def init_alias(self):
359 # The parent class defines aliases that can be safely used with any
359 # The parent class defines aliases that can be safely used with any
360 # frontend.
360 # frontend.
361 super(TerminalInteractiveShell, self).init_alias()
361 super(TerminalInteractiveShell, self).init_alias()
362
362
363 # Now define aliases that only make sense on the terminal, because they
363 # Now define aliases that only make sense on the terminal, because they
364 # need direct access to the console in a way that we can't emulate in
364 # need direct access to the console in a way that we can't emulate in
365 # GUI or web frontend
365 # GUI or web frontend
366 if os.name == 'posix':
366 if os.name == 'posix':
367 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
367 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
368 ('man', 'man')]
368 ('man', 'man')]
369 elif os.name == 'nt':
369 elif os.name == 'nt':
370 aliases = [('cls', 'cls')]
370 aliases = [('cls', 'cls')]
371
371
372
372
373 for name, cmd in aliases:
373 for name, cmd in aliases:
374 self.alias_manager.soft_define_alias(name, cmd)
374 self.alias_manager.soft_define_alias(name, cmd)
375
375
376 #-------------------------------------------------------------------------
376 #-------------------------------------------------------------------------
377 # Things related to the banner and usage
377 # Things related to the banner and usage
378 #-------------------------------------------------------------------------
378 #-------------------------------------------------------------------------
379
379
380 def _banner1_changed(self):
380 def _banner1_changed(self):
381 self.compute_banner()
381 self.compute_banner()
382
382
383 def _banner2_changed(self):
383 def _banner2_changed(self):
384 self.compute_banner()
384 self.compute_banner()
385
385
386 def _term_title_changed(self, name, new_value):
386 def _term_title_changed(self, name, new_value):
387 self.init_term_title()
387 self.init_term_title()
388
388
389 def init_banner(self, banner1, banner2, display_banner):
389 def init_banner(self, banner1, banner2, display_banner):
390 if banner1 is not None:
390 if banner1 is not None:
391 self.banner1 = banner1
391 self.banner1 = banner1
392 if banner2 is not None:
392 if banner2 is not None:
393 self.banner2 = banner2
393 self.banner2 = banner2
394 if display_banner is not None:
394 if display_banner is not None:
395 self.display_banner = display_banner
395 self.display_banner = display_banner
396 self.compute_banner()
396 self.compute_banner()
397
397
398 def show_banner(self, banner=None):
398 def show_banner(self, banner=None):
399 if banner is None:
399 if banner is None:
400 banner = self.banner
400 banner = self.banner
401 self.write(banner)
401 self.write(banner)
402
402
403 def compute_banner(self):
403 def compute_banner(self):
404 self.banner = self.banner1
404 self.banner = self.banner1
405 if self.profile and self.profile != 'default':
405 if self.profile and self.profile != 'default':
406 self.banner += '\nIPython profile: %s\n' % self.profile
406 self.banner += '\nIPython profile: %s\n' % self.profile
407 if self.banner2:
407 if self.banner2:
408 self.banner += '\n' + self.banner2
408 self.banner += '\n' + self.banner2
409
409
410 def init_usage(self, usage=None):
410 def init_usage(self, usage=None):
411 if usage is None:
411 if usage is None:
412 self.usage = interactive_usage
412 self.usage = interactive_usage
413 else:
413 else:
414 self.usage = usage
414 self.usage = usage
415
415
416 #-------------------------------------------------------------------------
416 #-------------------------------------------------------------------------
417 # Mainloop and code execution logic
417 # Mainloop and code execution logic
418 #-------------------------------------------------------------------------
418 #-------------------------------------------------------------------------
419
419
420 def mainloop(self, display_banner=None):
420 def mainloop(self, display_banner=None):
421 """Start the mainloop.
421 """Start the mainloop.
422
422
423 If an optional banner argument is given, it will override the
423 If an optional banner argument is given, it will override the
424 internally created default banner.
424 internally created default banner.
425 """
425 """
426
426
427 with self.builtin_trap, self.display_trap:
427 with self.builtin_trap, self.display_trap:
428
428
429 while 1:
429 while 1:
430 try:
430 try:
431 self.interact(display_banner=display_banner)
431 self.interact(display_banner=display_banner)
432 #self.interact_with_readline()
432 #self.interact_with_readline()
433 # XXX for testing of a readline-decoupled repl loop, call
433 # XXX for testing of a readline-decoupled repl loop, call
434 # interact_with_readline above
434 # interact_with_readline above
435 break
435 break
436 except KeyboardInterrupt:
436 except KeyboardInterrupt:
437 # this should not be necessary, but KeyboardInterrupt
437 # this should not be necessary, but KeyboardInterrupt
438 # handling seems rather unpredictable...
438 # handling seems rather unpredictable...
439 self.write("\nKeyboardInterrupt in interact()\n")
439 self.write("\nKeyboardInterrupt in interact()\n")
440
440
441 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
441 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
442 """Store multiple lines as a single entry in history"""
442 """Store multiple lines as a single entry in history"""
443
443
444 # do nothing without readline or disabled multiline
444 # do nothing without readline or disabled multiline
445 if not self.has_readline or not self.multiline_history:
445 if not self.has_readline or not self.multiline_history:
446 return hlen_before_cell
446 return hlen_before_cell
447
447
448 # windows rl has no remove_history_item
448 # windows rl has no remove_history_item
449 if not hasattr(self.readline, "remove_history_item"):
449 if not hasattr(self.readline, "remove_history_item"):
450 return hlen_before_cell
450 return hlen_before_cell
451
451
452 # skip empty cells
452 # skip empty cells
453 if not source_raw.rstrip():
453 if not source_raw.rstrip():
454 return hlen_before_cell
454 return hlen_before_cell
455
455
456 # nothing changed do nothing, e.g. when rl removes consecutive dups
456 # nothing changed do nothing, e.g. when rl removes consecutive dups
457 hlen = self.readline.get_current_history_length()
457 hlen = self.readline.get_current_history_length()
458 if hlen == hlen_before_cell:
458 if hlen == hlen_before_cell:
459 return hlen_before_cell
459 return hlen_before_cell
460
460
461 for i in range(hlen - hlen_before_cell):
461 for i in range(hlen - hlen_before_cell):
462 self.readline.remove_history_item(hlen - i - 1)
462 self.readline.remove_history_item(hlen - i - 1)
463 stdin_encoding = get_stream_enc(sys.stdin, 'utf-8')
463 stdin_encoding = get_stream_enc(sys.stdin, 'utf-8')
464 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
464 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
465 stdin_encoding))
465 stdin_encoding))
466 return self.readline.get_current_history_length()
466 return self.readline.get_current_history_length()
467
467
468 def interact(self, display_banner=None):
468 def interact(self, display_banner=None):
469 """Closely emulate the interactive Python console."""
469 """Closely emulate the interactive Python console."""
470
470
471 # batch run -> do not interact
471 # batch run -> do not interact
472 if self.exit_now:
472 if self.exit_now:
473 return
473 return
474
474
475 if display_banner is None:
475 if display_banner is None:
476 display_banner = self.display_banner
476 display_banner = self.display_banner
477
477
478 if isinstance(display_banner, py3compat.string_types):
478 if isinstance(display_banner, py3compat.string_types):
479 self.show_banner(display_banner)
479 self.show_banner(display_banner)
480 elif display_banner:
480 elif display_banner:
481 self.show_banner()
481 self.show_banner()
482
482
483 more = False
483 more = False
484
484
485 if self.has_readline:
485 if self.has_readline:
486 self.readline_startup_hook(self.pre_readline)
486 self.readline_startup_hook(self.pre_readline)
487 hlen_b4_cell = self.readline.get_current_history_length()
487 hlen_b4_cell = self.readline.get_current_history_length()
488 else:
488 else:
489 hlen_b4_cell = 0
489 hlen_b4_cell = 0
490 # exit_now is set by a call to %Exit or %Quit, through the
490 # exit_now is set by a call to %Exit or %Quit, through the
491 # ask_exit callback.
491 # ask_exit callback.
492
492
493 while not self.exit_now:
493 while not self.exit_now:
494 self.hooks.pre_prompt_hook()
494 self.hooks.pre_prompt_hook()
495 if more:
495 if more:
496 try:
496 try:
497 prompt = self.prompt_manager.render('in2')
497 prompt = self.prompt_manager.render('in2')
498 except:
498 except:
499 self.showtraceback()
499 self.showtraceback()
500 if self.autoindent:
500 if self.autoindent:
501 self.rl_do_indent = True
501 self.rl_do_indent = True
502
502
503 else:
503 else:
504 try:
504 try:
505 prompt = self.separate_in + self.prompt_manager.render('in')
505 prompt = self.separate_in + self.prompt_manager.render('in')
506 except:
506 except:
507 self.showtraceback()
507 self.showtraceback()
508 try:
508 try:
509 line = self.raw_input(prompt)
509 line = self.raw_input(prompt)
510 if self.exit_now:
510 if self.exit_now:
511 # quick exit on sys.std[in|out] close
511 # quick exit on sys.std[in|out] close
512 break
512 break
513 if self.autoindent:
513 if self.autoindent:
514 self.rl_do_indent = False
514 self.rl_do_indent = False
515
515
516 except KeyboardInterrupt:
516 except KeyboardInterrupt:
517 #double-guard against keyboardinterrupts during kbdint handling
517 #double-guard against keyboardinterrupts during kbdint handling
518 try:
518 try:
519 self.write('\nKeyboardInterrupt\n')
519 self.write('\nKeyboardInterrupt\n')
520 source_raw = self.input_splitter.source_raw_reset()[1]
520 source_raw = self.input_splitter.source_raw_reset()[1]
521 hlen_b4_cell = \
521 hlen_b4_cell = \
522 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
522 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
523 more = False
523 more = False
524 except KeyboardInterrupt:
524 except KeyboardInterrupt:
525 pass
525 pass
526 except EOFError:
526 except EOFError:
527 if self.autoindent:
527 if self.autoindent:
528 self.rl_do_indent = False
528 self.rl_do_indent = False
529 if self.has_readline:
529 if self.has_readline:
530 self.readline_startup_hook(None)
530 self.readline_startup_hook(None)
531 self.write('\n')
531 self.write('\n')
532 self.exit()
532 self.exit()
533 except bdb.BdbQuit:
533 except bdb.BdbQuit:
534 warn('The Python debugger has exited with a BdbQuit exception.\n'
534 warn('The Python debugger has exited with a BdbQuit exception.\n'
535 'Because of how pdb handles the stack, it is impossible\n'
535 'Because of how pdb handles the stack, it is impossible\n'
536 'for IPython to properly format this particular exception.\n'
536 'for IPython to properly format this particular exception.\n'
537 'IPython will resume normal operation.')
537 'IPython will resume normal operation.')
538 except:
538 except:
539 # exceptions here are VERY RARE, but they can be triggered
539 # exceptions here are VERY RARE, but they can be triggered
540 # asynchronously by signal handlers, for example.
540 # asynchronously by signal handlers, for example.
541 self.showtraceback()
541 self.showtraceback()
542 else:
542 else:
543 self.input_splitter.push(line)
543 self.input_splitter.push(line)
544 more = self.input_splitter.push_accepts_more()
544 more = self.input_splitter.push_accepts_more()
545 if (self.SyntaxTB.last_syntax_error and
545 if (self.SyntaxTB.last_syntax_error and
546 self.autoedit_syntax):
546 self.autoedit_syntax):
547 self.edit_syntax_error()
547 self.edit_syntax_error()
548 if not more:
548 if not more:
549 source_raw = self.input_splitter.source_raw_reset()[1]
549 source_raw = self.input_splitter.source_raw_reset()[1]
550 self.run_cell(source_raw, store_history=True)
550 self.run_cell(source_raw, store_history=True)
551 hlen_b4_cell = \
551 hlen_b4_cell = \
552 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
552 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
553
553
554 # Turn off the exit flag, so the mainloop can be restarted if desired
554 # Turn off the exit flag, so the mainloop can be restarted if desired
555 self.exit_now = False
555 self.exit_now = False
556
556
557 def raw_input(self, prompt=''):
557 def raw_input(self, prompt=''):
558 """Write a prompt and read a line.
558 """Write a prompt and read a line.
559
559
560 The returned line does not include the trailing newline.
560 The returned line does not include the trailing newline.
561 When the user enters the EOF key sequence, EOFError is raised.
561 When the user enters the EOF key sequence, EOFError is raised.
562
562
563 Optional inputs:
563 Parameters
564 ----------
564
565
565 - prompt(''): a string to be printed to prompt the user.
566 prompt : str, optional
566
567 A string to be printed to prompt the user.
567 - continue_prompt(False): whether this line is the first one or a
568 continuation in a sequence of inputs.
569 """
568 """
570 # Code run by the user may have modified the readline completer state.
569 # Code run by the user may have modified the readline completer state.
571 # We must ensure that our completer is back in place.
570 # We must ensure that our completer is back in place.
572
571
573 if self.has_readline:
572 if self.has_readline:
574 self.set_readline_completer()
573 self.set_readline_completer()
575
574
576 # raw_input expects str, but we pass it unicode sometimes
575 # raw_input expects str, but we pass it unicode sometimes
577 prompt = py3compat.cast_bytes_py2(prompt)
576 prompt = py3compat.cast_bytes_py2(prompt)
578
577
579 try:
578 try:
580 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
579 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
581 except ValueError:
580 except ValueError:
582 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
581 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
583 " or sys.stdout.close()!\nExiting IPython!\n")
582 " or sys.stdout.close()!\nExiting IPython!\n")
584 self.ask_exit()
583 self.ask_exit()
585 return ""
584 return ""
586
585
587 # Try to be reasonably smart about not re-indenting pasted input more
586 # Try to be reasonably smart about not re-indenting pasted input more
588 # than necessary. We do this by trimming out the auto-indent initial
587 # than necessary. We do this by trimming out the auto-indent initial
589 # spaces, if the user's actual input started itself with whitespace.
588 # spaces, if the user's actual input started itself with whitespace.
590 if self.autoindent:
589 if self.autoindent:
591 if num_ini_spaces(line) > self.indent_current_nsp:
590 if num_ini_spaces(line) > self.indent_current_nsp:
592 line = line[self.indent_current_nsp:]
591 line = line[self.indent_current_nsp:]
593 self.indent_current_nsp = 0
592 self.indent_current_nsp = 0
594
593
595 return line
594 return line
596
595
597 #-------------------------------------------------------------------------
596 #-------------------------------------------------------------------------
598 # Methods to support auto-editing of SyntaxErrors.
597 # Methods to support auto-editing of SyntaxErrors.
599 #-------------------------------------------------------------------------
598 #-------------------------------------------------------------------------
600
599
601 def edit_syntax_error(self):
600 def edit_syntax_error(self):
602 """The bottom half of the syntax error handler called in the main loop.
601 """The bottom half of the syntax error handler called in the main loop.
603
602
604 Loop until syntax error is fixed or user cancels.
603 Loop until syntax error is fixed or user cancels.
605 """
604 """
606
605
607 while self.SyntaxTB.last_syntax_error:
606 while self.SyntaxTB.last_syntax_error:
608 # copy and clear last_syntax_error
607 # copy and clear last_syntax_error
609 err = self.SyntaxTB.clear_err_state()
608 err = self.SyntaxTB.clear_err_state()
610 if not self._should_recompile(err):
609 if not self._should_recompile(err):
611 return
610 return
612 try:
611 try:
613 # may set last_syntax_error again if a SyntaxError is raised
612 # may set last_syntax_error again if a SyntaxError is raised
614 self.safe_execfile(err.filename,self.user_ns)
613 self.safe_execfile(err.filename,self.user_ns)
615 except:
614 except:
616 self.showtraceback()
615 self.showtraceback()
617 else:
616 else:
618 try:
617 try:
619 f = open(err.filename)
618 f = open(err.filename)
620 try:
619 try:
621 # This should be inside a display_trap block and I
620 # This should be inside a display_trap block and I
622 # think it is.
621 # think it is.
623 sys.displayhook(f.read())
622 sys.displayhook(f.read())
624 finally:
623 finally:
625 f.close()
624 f.close()
626 except:
625 except:
627 self.showtraceback()
626 self.showtraceback()
628
627
629 def _should_recompile(self,e):
628 def _should_recompile(self,e):
630 """Utility routine for edit_syntax_error"""
629 """Utility routine for edit_syntax_error"""
631
630
632 if e.filename in ('<ipython console>','<input>','<string>',
631 if e.filename in ('<ipython console>','<input>','<string>',
633 '<console>','<BackgroundJob compilation>',
632 '<console>','<BackgroundJob compilation>',
634 None):
633 None):
635
634
636 return False
635 return False
637 try:
636 try:
638 if (self.autoedit_syntax and
637 if (self.autoedit_syntax and
639 not self.ask_yes_no('Return to editor to correct syntax error? '
638 not self.ask_yes_no('Return to editor to correct syntax error? '
640 '[Y/n] ','y')):
639 '[Y/n] ','y')):
641 return False
640 return False
642 except EOFError:
641 except EOFError:
643 return False
642 return False
644
643
645 def int0(x):
644 def int0(x):
646 try:
645 try:
647 return int(x)
646 return int(x)
648 except TypeError:
647 except TypeError:
649 return 0
648 return 0
650 # always pass integer line and offset values to editor hook
649 # always pass integer line and offset values to editor hook
651 try:
650 try:
652 self.hooks.fix_error_editor(e.filename,
651 self.hooks.fix_error_editor(e.filename,
653 int0(e.lineno),int0(e.offset),e.msg)
652 int0(e.lineno),int0(e.offset),e.msg)
654 except TryNext:
653 except TryNext:
655 warn('Could not open editor')
654 warn('Could not open editor')
656 return False
655 return False
657 return True
656 return True
658
657
659 #-------------------------------------------------------------------------
658 #-------------------------------------------------------------------------
660 # Things related to exiting
659 # Things related to exiting
661 #-------------------------------------------------------------------------
660 #-------------------------------------------------------------------------
662
661
663 def ask_exit(self):
662 def ask_exit(self):
664 """ Ask the shell to exit. Can be overiden and used as a callback. """
663 """ Ask the shell to exit. Can be overiden and used as a callback. """
665 self.exit_now = True
664 self.exit_now = True
666
665
667 def exit(self):
666 def exit(self):
668 """Handle interactive exit.
667 """Handle interactive exit.
669
668
670 This method calls the ask_exit callback."""
669 This method calls the ask_exit callback."""
671 if self.confirm_exit:
670 if self.confirm_exit:
672 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
671 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
673 self.ask_exit()
672 self.ask_exit()
674 else:
673 else:
675 self.ask_exit()
674 self.ask_exit()
676
675
677 #-------------------------------------------------------------------------
676 #-------------------------------------------------------------------------
678 # Things related to magics
677 # Things related to magics
679 #-------------------------------------------------------------------------
678 #-------------------------------------------------------------------------
680
679
681 def init_magics(self):
680 def init_magics(self):
682 super(TerminalInteractiveShell, self).init_magics()
681 super(TerminalInteractiveShell, self).init_magics()
683 self.register_magics(TerminalMagics)
682 self.register_magics(TerminalMagics)
684
683
685 def showindentationerror(self):
684 def showindentationerror(self):
686 super(TerminalInteractiveShell, self).showindentationerror()
685 super(TerminalInteractiveShell, self).showindentationerror()
687 if not self.using_paste_magics:
686 if not self.using_paste_magics:
688 print("If you want to paste code into IPython, try the "
687 print("If you want to paste code into IPython, try the "
689 "%paste and %cpaste magic functions.")
688 "%paste and %cpaste magic functions.")
690
689
691
690
692 InteractiveShellABC.register(TerminalInteractiveShell)
691 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -1,382 +1,383 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Decorators for labeling test objects.
2 """Decorators for labeling test objects.
3
3
4 Decorators that merely return a modified version of the original function
4 Decorators that merely return a modified version of the original function
5 object are straightforward. Decorators that return a new function object need
5 object are straightforward. Decorators that return a new function object need
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 decorator, in order to preserve metadata such as function name, setup and
7 decorator, in order to preserve metadata such as function name, setup and
8 teardown functions and so on - see nose.tools for more information.
8 teardown functions and so on - see nose.tools for more information.
9
9
10 This module provides a set of useful decorators meant to be ready to use in
10 This module provides a set of useful decorators meant to be ready to use in
11 your own tests. See the bottom of the file for the ready-made ones, and if you
11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 find yourself writing a new one that may be of generic use, add it here.
12 find yourself writing a new one that may be of generic use, add it here.
13
13
14 Included decorators:
14 Included decorators:
15
15
16
16
17 Lightweight testing that remains unittest-compatible.
17 Lightweight testing that remains unittest-compatible.
18
18
19 - An @as_unittest decorator can be used to tag any normal parameter-less
19 - An @as_unittest decorator can be used to tag any normal parameter-less
20 function as a unittest TestCase. Then, both nose and normal unittest will
20 function as a unittest TestCase. Then, both nose and normal unittest will
21 recognize it as such. This will make it easier to migrate away from Nose if
21 recognize it as such. This will make it easier to migrate away from Nose if
22 we ever need/want to while maintaining very lightweight tests.
22 we ever need/want to while maintaining very lightweight tests.
23
23
24 NOTE: This file contains IPython-specific decorators. Using the machinery in
24 NOTE: This file contains IPython-specific decorators. Using the machinery in
25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
26 available, OR use equivalent code in IPython.external._decorators, which
26 available, OR use equivalent code in IPython.external._decorators, which
27 we've copied verbatim from numpy.
27 we've copied verbatim from numpy.
28
28
29 Authors
29 Authors
30 -------
30 -------
31
31
32 - Fernando Perez <Fernando.Perez@berkeley.edu>
32 - Fernando Perez <Fernando.Perez@berkeley.edu>
33 """
33 """
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Copyright (C) 2009-2011 The IPython Development Team
36 # Copyright (C) 2009-2011 The IPython Development Team
37 #
37 #
38 # Distributed under the terms of the BSD License. The full license is in
38 # Distributed under the terms of the BSD License. The full license is in
39 # the file COPYING, distributed as part of this software.
39 # the file COPYING, distributed as part of this software.
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Imports
43 # Imports
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 # Stdlib imports
46 # Stdlib imports
47 import sys
47 import sys
48 import os
48 import os
49 import tempfile
49 import tempfile
50 import unittest
50 import unittest
51
51
52 # Third-party imports
52 # Third-party imports
53
53
54 # This is Michele Simionato's decorator module, kept verbatim.
54 # This is Michele Simionato's decorator module, kept verbatim.
55 from IPython.external.decorator import decorator
55 from IPython.external.decorator import decorator
56
56
57 # Expose the unittest-driven decorators
57 # Expose the unittest-driven decorators
58 from .ipunittest import ipdoctest, ipdocstring
58 from .ipunittest import ipdoctest, ipdocstring
59
59
60 # Grab the numpy-specific decorators which we keep in a file that we
60 # Grab the numpy-specific decorators which we keep in a file that we
61 # occasionally update from upstream: decorators.py is a copy of
61 # occasionally update from upstream: decorators.py is a copy of
62 # numpy.testing.decorators, we expose all of it here.
62 # numpy.testing.decorators, we expose all of it here.
63 from IPython.external.decorators import *
63 from IPython.external.decorators import *
64
64
65 # For onlyif_cmd_exists decorator
65 # For onlyif_cmd_exists decorator
66 from IPython.utils.process import is_cmd_found
66 from IPython.utils.process import is_cmd_found
67 from IPython.utils.py3compat import string_types
67 from IPython.utils.py3compat import string_types
68
68
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70 # Classes and functions
70 # Classes and functions
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72
72
73 # Simple example of the basic idea
73 # Simple example of the basic idea
74 def as_unittest(func):
74 def as_unittest(func):
75 """Decorator to make a simple function into a normal test via unittest."""
75 """Decorator to make a simple function into a normal test via unittest."""
76 class Tester(unittest.TestCase):
76 class Tester(unittest.TestCase):
77 def test(self):
77 def test(self):
78 func()
78 func()
79
79
80 Tester.__name__ = func.__name__
80 Tester.__name__ = func.__name__
81
81
82 return Tester
82 return Tester
83
83
84 # Utility functions
84 # Utility functions
85
85
86 def apply_wrapper(wrapper,func):
86 def apply_wrapper(wrapper,func):
87 """Apply a wrapper to a function for decoration.
87 """Apply a wrapper to a function for decoration.
88
88
89 This mixes Michele Simionato's decorator tool with nose's make_decorator,
89 This mixes Michele Simionato's decorator tool with nose's make_decorator,
90 to apply a wrapper in a decorator so that all nose attributes, as well as
90 to apply a wrapper in a decorator so that all nose attributes, as well as
91 function signature and other properties, survive the decoration cleanly.
91 function signature and other properties, survive the decoration cleanly.
92 This will ensure that wrapped functions can still be well introspected via
92 This will ensure that wrapped functions can still be well introspected via
93 IPython, for example.
93 IPython, for example.
94 """
94 """
95 import nose.tools
95 import nose.tools
96
96
97 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
97 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
98
98
99
99
100 def make_label_dec(label,ds=None):
100 def make_label_dec(label,ds=None):
101 """Factory function to create a decorator that applies one or more labels.
101 """Factory function to create a decorator that applies one or more labels.
102
102
103 Parameters
103 Parameters
104 ----------
104 ----------
105 label : string or sequence
105 label : string or sequence
106 One or more labels that will be applied by the decorator to the functions
106 One or more labels that will be applied by the decorator to the functions
107 it decorates. Labels are attributes of the decorated function with their
107 it decorates. Labels are attributes of the decorated function with their
108 value set to True.
108 value set to True.
109
109
110 ds : string
110 ds : string
111 An optional docstring for the resulting decorator. If not given, a
111 An optional docstring for the resulting decorator. If not given, a
112 default docstring is auto-generated.
112 default docstring is auto-generated.
113
113
114 Returns
114 Returns
115 -------
115 -------
116 A decorator.
116 A decorator.
117
117
118 Examples
118 Examples
119 --------
119 --------
120
120
121 A simple labeling decorator:
121 A simple labeling decorator:
122
122
123 >>> slow = make_label_dec('slow')
123 >>> slow = make_label_dec('slow')
124 >>> slow.__doc__
124 >>> slow.__doc__
125 "Labels a test as 'slow'."
125 "Labels a test as 'slow'."
126
126
127 And one that uses multiple labels and a custom docstring:
127 And one that uses multiple labels and a custom docstring:
128
128
129 >>> rare = make_label_dec(['slow','hard'],
129 >>> rare = make_label_dec(['slow','hard'],
130 ... "Mix labels 'slow' and 'hard' for rare tests.")
130 ... "Mix labels 'slow' and 'hard' for rare tests.")
131 >>> rare.__doc__
131 >>> rare.__doc__
132 "Mix labels 'slow' and 'hard' for rare tests."
132 "Mix labels 'slow' and 'hard' for rare tests."
133
133
134 Now, let's test using this one:
134 Now, let's test using this one:
135 >>> @rare
135 >>> @rare
136 ... def f(): pass
136 ... def f(): pass
137 ...
137 ...
138 >>>
138 >>>
139 >>> f.slow
139 >>> f.slow
140 True
140 True
141 >>> f.hard
141 >>> f.hard
142 True
142 True
143 """
143 """
144
144
145 if isinstance(label, string_types):
145 if isinstance(label, string_types):
146 labels = [label]
146 labels = [label]
147 else:
147 else:
148 labels = label
148 labels = label
149
149
150 # Validate that the given label(s) are OK for use in setattr() by doing a
150 # Validate that the given label(s) are OK for use in setattr() by doing a
151 # dry run on a dummy function.
151 # dry run on a dummy function.
152 tmp = lambda : None
152 tmp = lambda : None
153 for label in labels:
153 for label in labels:
154 setattr(tmp,label,True)
154 setattr(tmp,label,True)
155
155
156 # This is the actual decorator we'll return
156 # This is the actual decorator we'll return
157 def decor(f):
157 def decor(f):
158 for label in labels:
158 for label in labels:
159 setattr(f,label,True)
159 setattr(f,label,True)
160 return f
160 return f
161
161
162 # Apply the user's docstring, or autogenerate a basic one
162 # Apply the user's docstring, or autogenerate a basic one
163 if ds is None:
163 if ds is None:
164 ds = "Labels a test as %r." % label
164 ds = "Labels a test as %r." % label
165 decor.__doc__ = ds
165 decor.__doc__ = ds
166
166
167 return decor
167 return decor
168
168
169
169
170 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
170 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
171 # preserve function metadata better and allows the skip condition to be a
171 # preserve function metadata better and allows the skip condition to be a
172 # callable.
172 # callable.
173 def skipif(skip_condition, msg=None):
173 def skipif(skip_condition, msg=None):
174 ''' Make function raise SkipTest exception if skip_condition is true
174 ''' Make function raise SkipTest exception if skip_condition is true
175
175
176 Parameters
176 Parameters
177 ----------
177 ----------
178 skip_condition : bool or callable.
178
179 Flag to determine whether to skip test. If the condition is a
179 skip_condition : bool or callable
180 callable, it is used at runtime to dynamically make the decision. This
180 Flag to determine whether to skip test. If the condition is a
181 is useful for tests that may require costly imports, to delay the cost
181 callable, it is used at runtime to dynamically make the decision. This
182 until the test suite is actually executed.
182 is useful for tests that may require costly imports, to delay the cost
183 until the test suite is actually executed.
183 msg : string
184 msg : string
184 Message to give on raising a SkipTest exception
185 Message to give on raising a SkipTest exception.
185
186
186 Returns
187 Returns
187 -------
188 -------
188 decorator : function
189 decorator : function
189 Decorator, which, when applied to a function, causes SkipTest
190 Decorator, which, when applied to a function, causes SkipTest
190 to be raised when the skip_condition was True, and the function
191 to be raised when the skip_condition was True, and the function
191 to be called normally otherwise.
192 to be called normally otherwise.
192
193
193 Notes
194 Notes
194 -----
195 -----
195 You will see from the code that we had to further decorate the
196 You will see from the code that we had to further decorate the
196 decorator with the nose.tools.make_decorator function in order to
197 decorator with the nose.tools.make_decorator function in order to
197 transmit function name, and various other metadata.
198 transmit function name, and various other metadata.
198 '''
199 '''
199
200
200 def skip_decorator(f):
201 def skip_decorator(f):
201 # Local import to avoid a hard nose dependency and only incur the
202 # Local import to avoid a hard nose dependency and only incur the
202 # import time overhead at actual test-time.
203 # import time overhead at actual test-time.
203 import nose
204 import nose
204
205
205 # Allow for both boolean or callable skip conditions.
206 # Allow for both boolean or callable skip conditions.
206 if callable(skip_condition):
207 if callable(skip_condition):
207 skip_val = skip_condition
208 skip_val = skip_condition
208 else:
209 else:
209 skip_val = lambda : skip_condition
210 skip_val = lambda : skip_condition
210
211
211 def get_msg(func,msg=None):
212 def get_msg(func,msg=None):
212 """Skip message with information about function being skipped."""
213 """Skip message with information about function being skipped."""
213 if msg is None: out = 'Test skipped due to test condition.'
214 if msg is None: out = 'Test skipped due to test condition.'
214 else: out = msg
215 else: out = msg
215 return "Skipping test: %s. %s" % (func.__name__,out)
216 return "Skipping test: %s. %s" % (func.__name__,out)
216
217
217 # We need to define *two* skippers because Python doesn't allow both
218 # We need to define *two* skippers because Python doesn't allow both
218 # return with value and yield inside the same function.
219 # return with value and yield inside the same function.
219 def skipper_func(*args, **kwargs):
220 def skipper_func(*args, **kwargs):
220 """Skipper for normal test functions."""
221 """Skipper for normal test functions."""
221 if skip_val():
222 if skip_val():
222 raise nose.SkipTest(get_msg(f,msg))
223 raise nose.SkipTest(get_msg(f,msg))
223 else:
224 else:
224 return f(*args, **kwargs)
225 return f(*args, **kwargs)
225
226
226 def skipper_gen(*args, **kwargs):
227 def skipper_gen(*args, **kwargs):
227 """Skipper for test generators."""
228 """Skipper for test generators."""
228 if skip_val():
229 if skip_val():
229 raise nose.SkipTest(get_msg(f,msg))
230 raise nose.SkipTest(get_msg(f,msg))
230 else:
231 else:
231 for x in f(*args, **kwargs):
232 for x in f(*args, **kwargs):
232 yield x
233 yield x
233
234
234 # Choose the right skipper to use when building the actual generator.
235 # Choose the right skipper to use when building the actual generator.
235 if nose.util.isgenerator(f):
236 if nose.util.isgenerator(f):
236 skipper = skipper_gen
237 skipper = skipper_gen
237 else:
238 else:
238 skipper = skipper_func
239 skipper = skipper_func
239
240
240 return nose.tools.make_decorator(f)(skipper)
241 return nose.tools.make_decorator(f)(skipper)
241
242
242 return skip_decorator
243 return skip_decorator
243
244
244 # A version with the condition set to true, common case just to attach a message
245 # A version with the condition set to true, common case just to attach a message
245 # to a skip decorator
246 # to a skip decorator
246 def skip(msg=None):
247 def skip(msg=None):
247 """Decorator factory - mark a test function for skipping from test suite.
248 """Decorator factory - mark a test function for skipping from test suite.
248
249
249 Parameters
250 Parameters
250 ----------
251 ----------
251 msg : string
252 msg : string
252 Optional message to be added.
253 Optional message to be added.
253
254
254 Returns
255 Returns
255 -------
256 -------
256 decorator : function
257 decorator : function
257 Decorator, which, when applied to a function, causes SkipTest
258 Decorator, which, when applied to a function, causes SkipTest
258 to be raised, with the optional message added.
259 to be raised, with the optional message added.
259 """
260 """
260
261
261 return skipif(True,msg)
262 return skipif(True,msg)
262
263
263
264
264 def onlyif(condition, msg):
265 def onlyif(condition, msg):
265 """The reverse from skipif, see skipif for details."""
266 """The reverse from skipif, see skipif for details."""
266
267
267 if callable(condition):
268 if callable(condition):
268 skip_condition = lambda : not condition()
269 skip_condition = lambda : not condition()
269 else:
270 else:
270 skip_condition = lambda : not condition
271 skip_condition = lambda : not condition
271
272
272 return skipif(skip_condition, msg)
273 return skipif(skip_condition, msg)
273
274
274 #-----------------------------------------------------------------------------
275 #-----------------------------------------------------------------------------
275 # Utility functions for decorators
276 # Utility functions for decorators
276 def module_not_available(module):
277 def module_not_available(module):
277 """Can module be imported? Returns true if module does NOT import.
278 """Can module be imported? Returns true if module does NOT import.
278
279
279 This is used to make a decorator to skip tests that require module to be
280 This is used to make a decorator to skip tests that require module to be
280 available, but delay the 'import numpy' to test execution time.
281 available, but delay the 'import numpy' to test execution time.
281 """
282 """
282 try:
283 try:
283 mod = __import__(module)
284 mod = __import__(module)
284 mod_not_avail = False
285 mod_not_avail = False
285 except ImportError:
286 except ImportError:
286 mod_not_avail = True
287 mod_not_avail = True
287
288
288 return mod_not_avail
289 return mod_not_avail
289
290
290
291
291 def decorated_dummy(dec, name):
292 def decorated_dummy(dec, name):
292 """Return a dummy function decorated with dec, with the given name.
293 """Return a dummy function decorated with dec, with the given name.
293
294
294 Examples
295 Examples
295 --------
296 --------
296 import IPython.testing.decorators as dec
297 import IPython.testing.decorators as dec
297 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
298 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
298 """
299 """
299 dummy = lambda: None
300 dummy = lambda: None
300 dummy.__name__ = name
301 dummy.__name__ = name
301 return dec(dummy)
302 return dec(dummy)
302
303
303 #-----------------------------------------------------------------------------
304 #-----------------------------------------------------------------------------
304 # Decorators for public use
305 # Decorators for public use
305
306
306 # Decorators to skip certain tests on specific platforms.
307 # Decorators to skip certain tests on specific platforms.
307 skip_win32 = skipif(sys.platform == 'win32',
308 skip_win32 = skipif(sys.platform == 'win32',
308 "This test does not run under Windows")
309 "This test does not run under Windows")
309 skip_linux = skipif(sys.platform.startswith('linux'),
310 skip_linux = skipif(sys.platform.startswith('linux'),
310 "This test does not run under Linux")
311 "This test does not run under Linux")
311 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
312 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
312
313
313
314
314 # Decorators to skip tests if not on specific platforms.
315 # Decorators to skip tests if not on specific platforms.
315 skip_if_not_win32 = skipif(sys.platform != 'win32',
316 skip_if_not_win32 = skipif(sys.platform != 'win32',
316 "This test only runs under Windows")
317 "This test only runs under Windows")
317 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
318 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
318 "This test only runs under Linux")
319 "This test only runs under Linux")
319 skip_if_not_osx = skipif(sys.platform != 'darwin',
320 skip_if_not_osx = skipif(sys.platform != 'darwin',
320 "This test only runs under OSX")
321 "This test only runs under OSX")
321
322
322
323
323 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
324 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
324 os.environ.get('DISPLAY', '') == '')
325 os.environ.get('DISPLAY', '') == '')
325 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
326 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
326
327
327 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
328 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
328
329
329 # not a decorator itself, returns a dummy function to be used as setup
330 # not a decorator itself, returns a dummy function to be used as setup
330 def skip_file_no_x11(name):
331 def skip_file_no_x11(name):
331 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
332 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
332
333
333 # Other skip decorators
334 # Other skip decorators
334
335
335 # generic skip without module
336 # generic skip without module
336 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
337 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
337
338
338 skipif_not_numpy = skip_without('numpy')
339 skipif_not_numpy = skip_without('numpy')
339
340
340 skipif_not_matplotlib = skip_without('matplotlib')
341 skipif_not_matplotlib = skip_without('matplotlib')
341
342
342 skipif_not_sympy = skip_without('sympy')
343 skipif_not_sympy = skip_without('sympy')
343
344
344 skip_known_failure = knownfailureif(True,'This test is known to fail')
345 skip_known_failure = knownfailureif(True,'This test is known to fail')
345
346
346 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
347 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
347 'This test is known to fail on Python 3.')
348 'This test is known to fail on Python 3.')
348
349
349 # A null 'decorator', useful to make more readable code that needs to pick
350 # A null 'decorator', useful to make more readable code that needs to pick
350 # between different decorators based on OS or other conditions
351 # between different decorators based on OS or other conditions
351 null_deco = lambda f: f
352 null_deco = lambda f: f
352
353
353 # Some tests only run where we can use unicode paths. Note that we can't just
354 # Some tests only run where we can use unicode paths. Note that we can't just
354 # check os.path.supports_unicode_filenames, which is always False on Linux.
355 # check os.path.supports_unicode_filenames, which is always False on Linux.
355 try:
356 try:
356 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
357 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
357 except UnicodeEncodeError:
358 except UnicodeEncodeError:
358 unicode_paths = False
359 unicode_paths = False
359 else:
360 else:
360 unicode_paths = True
361 unicode_paths = True
361 f.close()
362 f.close()
362
363
363 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
364 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
364 "where we can use unicode in filenames."))
365 "where we can use unicode in filenames."))
365
366
366
367
367 def onlyif_cmds_exist(*commands):
368 def onlyif_cmds_exist(*commands):
368 """
369 """
369 Decorator to skip test when at least one of `commands` is not found.
370 Decorator to skip test when at least one of `commands` is not found.
370 """
371 """
371 for cmd in commands:
372 for cmd in commands:
372 try:
373 try:
373 if not is_cmd_found(cmd):
374 if not is_cmd_found(cmd):
374 return skip("This test runs only if command '{0}' "
375 return skip("This test runs only if command '{0}' "
375 "is installed".format(cmd))
376 "is installed".format(cmd))
376 except ImportError as e:
377 except ImportError as e:
377 # is_cmd_found uses pywin32 on windows, which might not be available
378 # is_cmd_found uses pywin32 on windows, which might not be available
378 if sys.platform == 'win32' and 'pywin32' in str(e):
379 if sys.platform == 'win32' and 'pywin32' in str(e):
379 return skip("This test runs only if pywin32 and command '{0}' "
380 return skip("This test runs only if pywin32 and command '{0}' "
380 "is installed".format(cmd))
381 "is installed".format(cmd))
381 raise e
382 raise e
382 return null_deco
383 return null_deco
@@ -1,621 +1,621 b''
1 .. _issues_list_012:
1 .. _issues_list_012:
2
2
3 Issues closed in the 0.12 development cycle
3 Issues closed in the 0.12 development cycle
4 ===========================================
4 ===========================================
5
5
6 Issues closed in 0.12.1
6 Issues closed in 0.12.1
7 -----------------------
7 -----------------------
8
8
9 GitHub stats for bugfix release 0.12.1 (12/28/2011-04/16/2012), backporting
9 GitHub stats for bugfix release 0.12.1 (12/28/2011-04/16/2012), backporting
10 pull requests from 0.13.
10 pull requests from 0.13.
11
11
12 We closed a total of 71 issues: 44 pull requests and 27 issues; this is the
12 We closed a total of 71 issues: 44 pull requests and 27 issues; this is the
13 full list (generated with the script `tools/github_stats.py`).
13 full list (generated with the script `tools/github_stats.py`).
14
14
15 This list is automatically generated, and may be incomplete:
15 This list is automatically generated, and may be incomplete:
16
16
17 Pull Requests (44):
17 Pull Requests (44):
18
18
19 * :ghpull:`1175`: core.completer: Clean up excessive and unused code.
19 * :ghpull:`1175`: core.completer: Clean up excessive and unused code.
20 * :ghpull:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush
20 * :ghpull:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush
21 * :ghpull:`1190`: Fix link to Chris Fonnesbeck blog post about 0.11 highlights.
21 * :ghpull:`1190`: Fix link to Chris Fonnesbeck blog post about 0.11 highlights.
22 * :ghpull:`1196`: docs: looks like a file path might have been accidentally pasted in the middle of a word
22 * :ghpull:`1196`: docs: looks like a file path might have been accidentally pasted in the middle of a word
23 * :ghpull:`1206`: don't preserve fixConsole output in json
23 * :ghpull:`1206`: don't preserve fixConsole output in json
24 * :ghpull:`1207`: fix loadpy duplicating newlines
24 * :ghpull:`1207`: fix loadpy duplicating newlines
25 * :ghpull:`1213`: BUG: Minor typo in history_console_widget.py
25 * :ghpull:`1213`: BUG: Minor typo in history_console_widget.py
26 * :ghpull:`1218`: Added -q option to %prun for suppression of the output, along with editing the dochelp string.
26 * :ghpull:`1218`: Added -q option to %prun for suppression of the output, along with editing the dochelp string.
27 * :ghpull:`1222`: allow Reference as callable in map/apply
27 * :ghpull:`1222`: allow Reference as callable in map/apply
28 * :ghpull:`1229`: Fix display of SyntaxError in Python 3
28 * :ghpull:`1229`: Fix display of SyntaxError in Python 3
29 * :ghpull:`1246`: Skip tests that require X, when importing pylab results in RuntimeError.
29 * :ghpull:`1246`: Skip tests that require X, when importing pylab results in RuntimeError.
30 * :ghpull:`1253`: set auto_create flag for notebook apps
30 * :ghpull:`1253`: set auto_create flag for notebook apps
31 * :ghpull:`1257`: use self.kernel_manager_class in qtconsoleapp
31 * :ghpull:`1257`: use self.kernel_manager_class in qtconsoleapp
32 * :ghpull:`1262`: Heartbeat no longer shares the app's Context
32 * :ghpull:`1262`: Heartbeat no longer shares the app's Context
33 * :ghpull:`1283`: HeartMonitor.period should be an Integer
33 * :ghpull:`1283`: HeartMonitor.period should be an Integer
34 * :ghpull:`1284`: a fix for GH 1269
34 * :ghpull:`1284`: a fix for GH 1269
35 * :ghpull:`1289`: Make autoreload extension work on Python 3.
35 * :ghpull:`1289`: Make autoreload extension work on Python 3.
36 * :ghpull:`1306`: Fix %prun input parsing for escaped characters (closes #1302)
36 * :ghpull:`1306`: Fix %prun input parsing for escaped characters (closes #1302)
37 * :ghpull:`1312`: minor heartbeat tweaks
37 * :ghpull:`1312`: minor heartbeat tweaks
38 * :ghpull:`1318`: make Ctrl-D in qtconsole act same as in terminal (ready to merge)
38 * :ghpull:`1318`: make Ctrl-D in qtconsole act same as in terminal (ready to merge)
39 * :ghpull:`1341`: Don't attempt to tokenize binary files for tracebacks
39 * :ghpull:`1341`: Don't attempt to tokenize binary files for tracebacks
40 * :ghpull:`1353`: Save notebook as script using unicode file handle.
40 * :ghpull:`1353`: Save notebook as script using unicode file handle.
41 * :ghpull:`1363`: Fix some minor color/style config issues in the qtconsole
41 * :ghpull:`1363`: Fix some minor color/style config issues in the qtconsole
42 * :ghpull:`1364`: avoid jsonlib returning Decimal
42 * :ghpull:`1364`: avoid jsonlib returning Decimal
43 * :ghpull:`1369`: load header with engine id when engine dies in TaskScheduler
43 * :ghpull:`1369`: load header with engine id when engine dies in TaskScheduler
44 * :ghpull:`1370`: allow draft76 websockets (Safari)
44 * :ghpull:`1370`: allow draft76 websockets (Safari)
45 * :ghpull:`1374`: remove calls to meaningless ZMQStream.on_err
45 * :ghpull:`1374`: remove calls to meaningless ZMQStream.on_err
46 * :ghpull:`1377`: Saving non-ascii history
46 * :ghpull:`1377`: Saving non-ascii history
47 * :ghpull:`1396`: Fix for %tb magic.
47 * :ghpull:`1396`: Fix for %tb magic.
48 * :ghpull:`1402`: fix symlinked /home issue for FreeBSD
48 * :ghpull:`1402`: fix symlinked /home issue for FreeBSD
49 * :ghpull:`1413`: get_home_dir expands symlinks, adjust test accordingly
49 * :ghpull:`1413`: get_home_dir expands symlinks, adjust test accordingly
50 * :ghpull:`1414`: ignore errors in shell.var_expand
50 * :ghpull:`1414`: ignore errors in shell.var_expand
51 * :ghpull:`1430`: Fix for tornado check for tornado < 1.1.0
51 * :ghpull:`1430`: Fix for tornado check for tornado < 1.1.0
52 * :ghpull:`1445`: Don't build sphinx docs for sdists
52 * :ghpull:`1445`: Don't build sphinx docs for sdists
53 * :ghpull:`1463`: Fix completion when importing modules in the cwd.
53 * :ghpull:`1463`: Fix completion when importing modules in the cwd.
54 * :ghpull:`1477`: fix dangling `buffer` in IPython.parallel.util
54 * :ghpull:`1477`: fix dangling `buffer` in IPython.parallel.util
55 * :ghpull:`1495`: BUG: Fix pretty-printing for overzealous objects
55 * :ghpull:`1495`: BUG: Fix pretty-printing for overzealous objects
56 * :ghpull:`1496`: BUG: LBYL when clearing the output history on shutdown.
56 * :ghpull:`1496`: BUG: LBYL when clearing the output history on shutdown.
57 * :ghpull:`1514`: DOC: Fix references to IPython.lib.pretty instead of the old location
57 * :ghpull:`1514`: DOC: Fix references to IPython.lib.pretty instead of the old location
58 * :ghpull:`1517`: Fix indentation bug in IPython/lib/pretty.py
58 * :ghpull:`1517`: Fix indentation bug in IPython/lib/pretty.py
59 * :ghpull:`1538`: store git commit hash in utils._sysinfo instead of hidden data file
59 * :ghpull:`1538`: store git commit hash in utils._sysinfo instead of hidden data file
60 * :ghpull:`1599`: Fix for %run -d in Python 3
60 * :ghpull:`1599`: Fix for %run -d in Python 3
61 * :ghpull:`1602`: Fix %env for Python 3
61 * :ghpull:`1602`: Fix %env for Python 3
62 * :ghpull:`1607`: cleanup sqlitedb temporary db file after tests
62 * :ghpull:`1607`: cleanup sqlitedb temporary db file after tests
63
63
64 Issues (27):
64 Issues (27):
65
65
66 * :ghissue:`676`: IPython.embed() from ipython crashes twice on exit
66 * :ghissue:`676`: IPython.embed() from ipython crashes twice on exit
67 * :ghissue:`846`: Autoreload extension doesn't work with Python 3.2
67 * :ghissue:`846`: Autoreload extension doesn't work with Python 3.2
68 * :ghissue:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush
68 * :ghissue:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush
69 * :ghissue:`1191`: profile/startup files not executed with "notebook"
69 * :ghissue:`1191`: profile/startup files not executed with "notebook"
70 * :ghissue:`1197`: Interactive shell trying to: from ... import history
70 * :ghissue:`1197`: Interactive shell trying to: from ... import history
71 * :ghissue:`1198`: Kernel Has Died error in Notebook
71 * :ghissue:`1198`: Kernel Has Died error in Notebook
72 * :ghissue:`1201`: %env magic fails with Python 3.2
72 * :ghissue:`1201`: %env magic fails with Python 3.2
73 * :ghissue:`1204`: double newline from %loadpy in python notebook (at least on mac)
73 * :ghissue:`1204`: double newline from %loadpy in python notebook (at least on mac)
74 * :ghissue:`1208`: should dv.sync_import print failed imports ?
74 * :ghissue:`1208`: should dv.sync_import print failed imports ?
75 * :ghissue:`1225`: SyntaxError display broken in Python 3
75 * :ghissue:`1225`: SyntaxError display broken in Python 3
76 * :ghissue:`1232`: Dead kernel loop
76 * :ghissue:`1232`: Dead kernel loop
77 * :ghissue:`1241`: When our debugger class is used standalone `_oh` key errors are thrown
77 * :ghissue:`1241`: When our debugger class is used standalone `_oh` key errors are thrown
78 * :ghissue:`1254`: typo in notebooklist.js breaks links
78 * :ghissue:`1254`: typo in notebooklist.js breaks links
79 * :ghissue:`1260`: heartbeat failure on long gil-holding operation
79 * :ghissue:`1260`: heartbeat failure on long gil-holding operation
80 * :ghissue:`1268`: notebook %reset magic fails with StdinNotImplementedError
80 * :ghissue:`1268`: notebook %reset magic fails with StdinNotImplementedError
81 * :ghissue:`1269`: Another strange input handling error
81 * :ghissue:`1269`: Another strange input handling error
82 * :ghissue:`1281`: in Hub: registration_timeout must be an integer, but heartmonitor.period is CFloat
82 * :ghissue:`1281`: in Hub: registration_timeout must be an integer, but heartmonitor.period is CFloat
83 * :ghissue:`1302`: Input parsing with %prun clobbers escapes
83 * :ghissue:`1302`: Input parsing with %prun clobbers escapes
84 * :ghissue:`1304`: controller/server load can disrupt heartbeat
84 * :ghissue:`1304`: controller/server load can disrupt heartbeat
85 * :ghissue:`1317`: Very slow traceback construction from Cython extension
85 * :ghissue:`1317`: Very slow traceback construction from Cython extension
86 * :ghissue:`1345`: notebook can't save unicode as script
86 * :ghissue:`1345`: notebook can't save unicode as script
87 * :ghissue:`1375`: %history -g -f file encoding issue
87 * :ghissue:`1375`: %history -g -f file encoding issue
88 * :ghissue:`1401`: numpy arrays cannot be used with View.apply() in Python 3
88 * :ghissue:`1401`: numpy arrays cannot be used with View.apply() in Python 3
89 * :ghissue:`1408`: test_get_home_dir_3 failed on Mac OS X
89 * :ghissue:`1408`: test_get_home_dir_3 failed on Mac OS X
90 * :ghissue:`1412`: Input parsing issue with %prun
90 * :ghissue:`1412`: Input parsing issue with %prun
91 * :ghissue:`1421`: ipython32 %run -d breaks with NameError name 'execfile' is not defined
91 * :ghissue:`1421`: ipython32 %run -d breaks with NameError name 'execfile' is not defined
92 * :ghissue:`1484`: unhide .git_commit_info.ini
92 * :ghissue:`1484`: unhide .git_commit_info.ini
93
93
94
94
95 Issues closed in 0.12
95 Issues closed in 0.12
96 ---------------------
96 ---------------------
97
97
98 In this cycle, from August 1 to December 28 2011, we closed a total of 515
98 In this cycle, from August 1 to December 28 2011, we closed a total of 515
99 issues, 257 pull requests and 258 regular issues; this is the full list
99 issues, 257 pull requests and 258 regular issues; this is the full list
100 (generated with the script `tools/github_stats.py`).
100 (generated with the script `tools/github_stats.py`).
101
101
102 Pull requests (257):
102 Pull requests (257):
103
103
104 * `1174 <https://github.com/ipython/ipython/issues/1174>`_: Remove %install_default_config and %install_profiles
104 * `1174 <https://github.com/ipython/ipython/issues/1174>`_: Remove %install_default_config and %install_profiles
105 * `1178 <https://github.com/ipython/ipython/issues/1178>`_: Correct string type casting in pinfo.
105 * `1178 <https://github.com/ipython/ipython/issues/1178>`_: Correct string type casting in pinfo.
106 * `1096 <https://github.com/ipython/ipython/issues/1096>`_: Show class init and call tooltips in notebook
106 * `1096 <https://github.com/ipython/ipython/issues/1096>`_: Show class init and call tooltips in notebook
107 * `1176 <https://github.com/ipython/ipython/issues/1176>`_: Modifications to profile list
107 * `1176 <https://github.com/ipython/ipython/issues/1176>`_: Modifications to profile list
108 * `1173 <https://github.com/ipython/ipython/issues/1173>`_: don't load gui/pylab in console frontend
108 * `1173 <https://github.com/ipython/ipython/issues/1173>`_: don't load gui/pylab in console frontend
109 * `1168 <https://github.com/ipython/ipython/issues/1168>`_: Add --script flag as shorthand for notebook save_script option.
109 * `1168 <https://github.com/ipython/ipython/issues/1168>`_: Add --script flag as shorthand for notebook save_script option.
110 * `1165 <https://github.com/ipython/ipython/issues/1165>`_: encode image_tag as utf8 in [x]html export
110 * `1165 <https://github.com/ipython/ipython/issues/1165>`_: encode image_tag as utf8 in [x]html export
111 * `1161 <https://github.com/ipython/ipython/issues/1161>`_: Allow %loadpy to load remote URLs that don't end in .py
111 * `1161 <https://github.com/ipython/ipython/issues/1161>`_: Allow %loadpy to load remote URLs that don't end in .py
112 * `1158 <https://github.com/ipython/ipython/issues/1158>`_: Add coding header when notebook exported to .py file.
112 * `1158 <https://github.com/ipython/ipython/issues/1158>`_: Add coding header when notebook exported to .py file.
113 * `1160 <https://github.com/ipython/ipython/issues/1160>`_: don't ignore ctrl-C during `%gui qt`
113 * `1160 <https://github.com/ipython/ipython/issues/1160>`_: don't ignore ctrl-C during `%gui qt`
114 * `1159 <https://github.com/ipython/ipython/issues/1159>`_: Add encoding header to Python files downloaded from notebooks.
114 * `1159 <https://github.com/ipython/ipython/issues/1159>`_: Add encoding header to Python files downloaded from notebooks.
115 * `1155 <https://github.com/ipython/ipython/issues/1155>`_: minor post-execute fixes (#1154)
115 * `1155 <https://github.com/ipython/ipython/issues/1155>`_: minor post-execute fixes (#1154)
116 * `1153 <https://github.com/ipython/ipython/issues/1153>`_: Pager tearing bug
116 * `1153 <https://github.com/ipython/ipython/issues/1153>`_: Pager tearing bug
117 * `1152 <https://github.com/ipython/ipython/issues/1152>`_: Add support for displaying maptlotlib axes directly.
117 * `1152 <https://github.com/ipython/ipython/issues/1152>`_: Add support for displaying maptlotlib axes directly.
118 * `1079 <https://github.com/ipython/ipython/issues/1079>`_: Login/out button cleanups
118 * `1079 <https://github.com/ipython/ipython/issues/1079>`_: Login/out button cleanups
119 * `1151 <https://github.com/ipython/ipython/issues/1151>`_: allow access to user_ns in prompt_manager
119 * `1151 <https://github.com/ipython/ipython/issues/1151>`_: allow access to user_ns in prompt_manager
120 * `1120 <https://github.com/ipython/ipython/issues/1120>`_: updated vim-ipython (pending)
120 * `1120 <https://github.com/ipython/ipython/issues/1120>`_: updated vim-ipython (pending)
121 * `1150 <https://github.com/ipython/ipython/issues/1150>`_: BUG: Scrolling pager in vsplit on Mac OSX tears.
121 * `1150 <https://github.com/ipython/ipython/issues/1150>`_: BUG: Scrolling pager in vsplit on Mac OSX tears.
122 * `1149 <https://github.com/ipython/ipython/issues/1149>`_: #1148 (win32 arg_split)
122 * `1149 <https://github.com/ipython/ipython/issues/1149>`_: #1148 (win32 arg_split)
123 * `1147 <https://github.com/ipython/ipython/issues/1147>`_: Put qtconsole forground when launching
123 * `1147 <https://github.com/ipython/ipython/issues/1147>`_: Put qtconsole forground when launching
124 * `1146 <https://github.com/ipython/ipython/issues/1146>`_: allow saving notebook.py next to notebook.ipynb
124 * `1146 <https://github.com/ipython/ipython/issues/1146>`_: allow saving notebook.py next to notebook.ipynb
125 * `1128 <https://github.com/ipython/ipython/issues/1128>`_: fix pylab StartMenu item
125 * `1128 <https://github.com/ipython/ipython/issues/1128>`_: fix pylab StartMenu item
126 * `1140 <https://github.com/ipython/ipython/issues/1140>`_: Namespaces for embedding
126 * `1140 <https://github.com/ipython/ipython/issues/1140>`_: Namespaces for embedding
127 * `1132 <https://github.com/ipython/ipython/issues/1132>`_: [notebook] read-only: disable name field
127 * `1132 <https://github.com/ipython/ipython/issues/1132>`_: [notebook] read-only: disable name field
128 * `1125 <https://github.com/ipython/ipython/issues/1125>`_: notebook : update logo
128 * `1125 <https://github.com/ipython/ipython/issues/1125>`_: notebook : update logo
129 * `1135 <https://github.com/ipython/ipython/issues/1135>`_: allow customized template and static file paths for the notebook web app
129 * `1135 <https://github.com/ipython/ipython/issues/1135>`_: allow customized template and static file paths for the notebook web app
130 * `1122 <https://github.com/ipython/ipython/issues/1122>`_: BUG: Issue #755 qt IPythonWidget.execute_file fails if filename contains...
130 * `1122 <https://github.com/ipython/ipython/issues/1122>`_: BUG: Issue #755 qt IPythonWidget.execute_file fails if filename contains...
131 * `1137 <https://github.com/ipython/ipython/issues/1137>`_: rename MPIExecLaunchers to MPILaunchers
131 * `1137 <https://github.com/ipython/ipython/issues/1137>`_: rename MPIExecLaunchers to MPILaunchers
132 * `1130 <https://github.com/ipython/ipython/issues/1130>`_: optionally ignore shlex's ValueError in arg_split
132 * `1130 <https://github.com/ipython/ipython/issues/1130>`_: optionally ignore shlex's ValueError in arg_split
133 * `1116 <https://github.com/ipython/ipython/issues/1116>`_: Shlex unicode
133 * `1116 <https://github.com/ipython/ipython/issues/1116>`_: Shlex unicode
134 * `1073 <https://github.com/ipython/ipython/issues/1073>`_: Storemagic plugin
134 * `1073 <https://github.com/ipython/ipython/issues/1073>`_: Storemagic plugin
135 * `1143 <https://github.com/ipython/ipython/issues/1143>`_: Add post_install script to create start menu entries in Python 3
135 * `1143 <https://github.com/ipython/ipython/issues/1143>`_: Add post_install script to create start menu entries in Python 3
136 * `1138 <https://github.com/ipython/ipython/issues/1138>`_: Fix tests to work when ~/.config/ipython contains a symlink.
136 * `1138 <https://github.com/ipython/ipython/issues/1138>`_: Fix tests to work when ~/.config/ipython contains a symlink.
137 * `1121 <https://github.com/ipython/ipython/issues/1121>`_: Don't transform function calls on IPyAutocall objects
137 * `1121 <https://github.com/ipython/ipython/issues/1121>`_: Don't transform function calls on IPyAutocall objects
138 * `1118 <https://github.com/ipython/ipython/issues/1118>`_: protect CRLF from carriage-return action
138 * `1118 <https://github.com/ipython/ipython/issues/1118>`_: protect CRLF from carriage-return action
139 * `1105 <https://github.com/ipython/ipython/issues/1105>`_: Fix for prompts containing newlines.
139 * `1105 <https://github.com/ipython/ipython/issues/1105>`_: Fix for prompts containing newlines.
140 * `1126 <https://github.com/ipython/ipython/issues/1126>`_: Totally remove pager when read only (notebook)
140 * `1126 <https://github.com/ipython/ipython/issues/1126>`_: Totally remove pager when read only (notebook)
141 * `1091 <https://github.com/ipython/ipython/issues/1091>`_: qtconsole : allow copy with shortcut in pager
141 * `1091 <https://github.com/ipython/ipython/issues/1091>`_: qtconsole : allow copy with shortcut in pager
142 * `1114 <https://github.com/ipython/ipython/issues/1114>`_: fix magics history in two-process ipython console
142 * `1114 <https://github.com/ipython/ipython/issues/1114>`_: fix magics history in two-process ipython console
143 * `1113 <https://github.com/ipython/ipython/issues/1113>`_: Fixing #1112 removing failing asserts for test_carriage_return and test_...
143 * `1113 <https://github.com/ipython/ipython/issues/1113>`_: Fixing #1112 removing failing asserts for test_carriage_return and test_beep
144 * `1089 <https://github.com/ipython/ipython/issues/1089>`_: Support carriage return ('\r') and beep ('\b') characters in the qtconsole
144 * `1089 <https://github.com/ipython/ipython/issues/1089>`_: Support carriage return ('\r') and beep ('\b') characters in the qtconsole
145 * `1108 <https://github.com/ipython/ipython/issues/1108>`_: Completer usability 2 (rebased of pr #1082)
145 * `1108 <https://github.com/ipython/ipython/issues/1108>`_: Completer usability 2 (rebased of pr #1082)
146 * `864 <https://github.com/ipython/ipython/issues/864>`_: Two-process terminal frontend (ipython core branch)
146 * `864 <https://github.com/ipython/ipython/issues/864>`_: Two-process terminal frontend (ipython core branch)
147 * `1082 <https://github.com/ipython/ipython/issues/1082>`_: usability and cross browser compat for completer
147 * `1082 <https://github.com/ipython/ipython/issues/1082>`_: usability and cross browser compat for completer
148 * `1053 <https://github.com/ipython/ipython/issues/1053>`_: minor improvements to text placement in qtconsole
148 * `1053 <https://github.com/ipython/ipython/issues/1053>`_: minor improvements to text placement in qtconsole
149 * `1106 <https://github.com/ipython/ipython/issues/1106>`_: Fix display of errors in compiled code on Python 3
149 * `1106 <https://github.com/ipython/ipython/issues/1106>`_: Fix display of errors in compiled code on Python 3
150 * `1077 <https://github.com/ipython/ipython/issues/1077>`_: allow the notebook to run without MathJax
150 * `1077 <https://github.com/ipython/ipython/issues/1077>`_: allow the notebook to run without MathJax
151 * `1072 <https://github.com/ipython/ipython/issues/1072>`_: If object has a getdoc() method, override its normal docstring.
151 * `1072 <https://github.com/ipython/ipython/issues/1072>`_: If object has a getdoc() method, override its normal docstring.
152 * `1059 <https://github.com/ipython/ipython/issues/1059>`_: Switch to simple `__IPYTHON__` global
152 * `1059 <https://github.com/ipython/ipython/issues/1059>`_: Switch to simple `__IPYTHON__` global
153 * `1070 <https://github.com/ipython/ipython/issues/1070>`_: Execution count after SyntaxError
153 * `1070 <https://github.com/ipython/ipython/issues/1070>`_: Execution count after SyntaxError
154 * `1098 <https://github.com/ipython/ipython/issues/1098>`_: notebook: config section UI
154 * `1098 <https://github.com/ipython/ipython/issues/1098>`_: notebook: config section UI
155 * `1101 <https://github.com/ipython/ipython/issues/1101>`_: workaround spawnb missing from pexpect.__all__
155 * `1101 <https://github.com/ipython/ipython/issues/1101>`_: workaround spawnb missing from pexpect.__all__
156 * `1097 <https://github.com/ipython/ipython/issues/1097>`_: typo, should fix #1095
156 * `1097 <https://github.com/ipython/ipython/issues/1097>`_: typo, should fix #1095
157 * `1099 <https://github.com/ipython/ipython/issues/1099>`_: qtconsole export xhtml/utf8
157 * `1099 <https://github.com/ipython/ipython/issues/1099>`_: qtconsole export xhtml/utf8
158 * `1083 <https://github.com/ipython/ipython/issues/1083>`_: Prompts
158 * `1083 <https://github.com/ipython/ipython/issues/1083>`_: Prompts
159 * `1081 <https://github.com/ipython/ipython/issues/1081>`_: Fix wildcard search for updated namespaces
159 * `1081 <https://github.com/ipython/ipython/issues/1081>`_: Fix wildcard search for updated namespaces
160 * `1084 <https://github.com/ipython/ipython/issues/1084>`_: write busy in notebook window title...
160 * `1084 <https://github.com/ipython/ipython/issues/1084>`_: write busy in notebook window title...
161 * `1078 <https://github.com/ipython/ipython/issues/1078>`_: PromptManager fixes
161 * `1078 <https://github.com/ipython/ipython/issues/1078>`_: PromptManager fixes
162 * `1064 <https://github.com/ipython/ipython/issues/1064>`_: Win32 shlex
162 * `1064 <https://github.com/ipython/ipython/issues/1064>`_: Win32 shlex
163 * `1069 <https://github.com/ipython/ipython/issues/1069>`_: As you type completer, fix on Firefox
163 * `1069 <https://github.com/ipython/ipython/issues/1069>`_: As you type completer, fix on Firefox
164 * `1039 <https://github.com/ipython/ipython/issues/1039>`_: Base of an as you type completer.
164 * `1039 <https://github.com/ipython/ipython/issues/1039>`_: Base of an as you type completer.
165 * `1065 <https://github.com/ipython/ipython/issues/1065>`_: Qtconsole fix racecondition
165 * `1065 <https://github.com/ipython/ipython/issues/1065>`_: Qtconsole fix racecondition
166 * `507 <https://github.com/ipython/ipython/issues/507>`_: Prompt manager
166 * `507 <https://github.com/ipython/ipython/issues/507>`_: Prompt manager
167 * `1056 <https://github.com/ipython/ipython/issues/1056>`_: Warning in code. qtconsole ssh -X
167 * `1056 <https://github.com/ipython/ipython/issues/1056>`_: Warning in code. qtconsole ssh -X
168 * `1036 <https://github.com/ipython/ipython/issues/1036>`_: Clean up javascript based on js2-mode feedback.
168 * `1036 <https://github.com/ipython/ipython/issues/1036>`_: Clean up javascript based on js2-mode feedback.
169 * `1052 <https://github.com/ipython/ipython/issues/1052>`_: Pylab fix
169 * `1052 <https://github.com/ipython/ipython/issues/1052>`_: Pylab fix
170 * `648 <https://github.com/ipython/ipython/issues/648>`_: Usermod
170 * `648 <https://github.com/ipython/ipython/issues/648>`_: Usermod
171 * `969 <https://github.com/ipython/ipython/issues/969>`_: Pexpect-u
171 * `969 <https://github.com/ipython/ipython/issues/969>`_: Pexpect-u
172 * `1007 <https://github.com/ipython/ipython/issues/1007>`_: Fix paste/cpaste bug and refactor/cleanup that code a lot.
172 * `1007 <https://github.com/ipython/ipython/issues/1007>`_: Fix paste/cpaste bug and refactor/cleanup that code a lot.
173 * `506 <https://github.com/ipython/ipython/issues/506>`_: make ENTER on a previous input field replace current input buffer
173 * `506 <https://github.com/ipython/ipython/issues/506>`_: make ENTER on a previous input field replace current input buffer
174 * `1040 <https://github.com/ipython/ipython/issues/1040>`_: json/jsonapi cleanup
174 * `1040 <https://github.com/ipython/ipython/issues/1040>`_: json/jsonapi cleanup
175 * `1042 <https://github.com/ipython/ipython/issues/1042>`_: fix firefox (windows) break line on empty prompt number
175 * `1042 <https://github.com/ipython/ipython/issues/1042>`_: fix firefox (windows) break line on empty prompt number
176 * `1015 <https://github.com/ipython/ipython/issues/1015>`_: emacs freezes when tab is hit in ipython with latest python-mode
176 * `1015 <https://github.com/ipython/ipython/issues/1015>`_: emacs freezes when tab is hit in ipython with latest python-mode
177 * `1023 <https://github.com/ipython/ipython/issues/1023>`_: flush stdout/stderr at the end of kernel init
177 * `1023 <https://github.com/ipython/ipython/issues/1023>`_: flush stdout/stderr at the end of kernel init
178 * `956 <https://github.com/ipython/ipython/issues/956>`_: Generate "All magics..." menu live
178 * `956 <https://github.com/ipython/ipython/issues/956>`_: Generate "All magics..." menu live
179 * `1038 <https://github.com/ipython/ipython/issues/1038>`_: Notebook: don't change cell when selecting code using shift+up/down.
179 * `1038 <https://github.com/ipython/ipython/issues/1038>`_: Notebook: don't change cell when selecting code using shift+up/down.
180 * `987 <https://github.com/ipython/ipython/issues/987>`_: Add Tooltip to notebook.
180 * `987 <https://github.com/ipython/ipython/issues/987>`_: Add Tooltip to notebook.
181 * `1028 <https://github.com/ipython/ipython/issues/1028>`_: Cleaner minimum version comparison
181 * `1028 <https://github.com/ipython/ipython/issues/1028>`_: Cleaner minimum version comparison
182 * `998 <https://github.com/ipython/ipython/issues/998>`_: defer to stdlib for path.get_home_dir()
182 * `998 <https://github.com/ipython/ipython/issues/998>`_: defer to stdlib for path.get_home_dir()
183 * `1033 <https://github.com/ipython/ipython/issues/1033>`_: update copyright to 2011/20xx-2011
183 * `1033 <https://github.com/ipython/ipython/issues/1033>`_: update copyright to 2011/20xx-2011
184 * `1032 <https://github.com/ipython/ipython/issues/1032>`_: Intercept <esc> avoid closing websocket on Firefox
184 * `1032 <https://github.com/ipython/ipython/issues/1032>`_: Intercept <esc> avoid closing websocket on Firefox
185 * `1030 <https://github.com/ipython/ipython/issues/1030>`_: use pyzmq tools where appropriate
185 * `1030 <https://github.com/ipython/ipython/issues/1030>`_: use pyzmq tools where appropriate
186 * `1029 <https://github.com/ipython/ipython/issues/1029>`_: Restore pspersistence, including %store magic, as an extension.
186 * `1029 <https://github.com/ipython/ipython/issues/1029>`_: Restore pspersistence, including %store magic, as an extension.
187 * `1025 <https://github.com/ipython/ipython/issues/1025>`_: Dollar escape
187 * `1025 <https://github.com/ipython/ipython/issues/1025>`_: Dollar escape
188 * `999 <https://github.com/ipython/ipython/issues/999>`_: Fix issue #880 - more useful message to user when %paste fails
188 * `999 <https://github.com/ipython/ipython/issues/999>`_: Fix issue #880 - more useful message to user when %paste fails
189 * `938 <https://github.com/ipython/ipython/issues/938>`_: changes to get ipython.el to work with the latest python-mode.el
189 * `938 <https://github.com/ipython/ipython/issues/938>`_: changes to get ipython.el to work with the latest python-mode.el
190 * `1012 <https://github.com/ipython/ipython/issues/1012>`_: Add logout button.
190 * `1012 <https://github.com/ipython/ipython/issues/1012>`_: Add logout button.
191 * `1020 <https://github.com/ipython/ipython/issues/1020>`_: Dollar formatter for ! shell calls
191 * `1020 <https://github.com/ipython/ipython/issues/1020>`_: Dollar formatter for ! shell calls
192 * `1019 <https://github.com/ipython/ipython/issues/1019>`_: Use repr() to make quoted strings
192 * `1019 <https://github.com/ipython/ipython/issues/1019>`_: Use repr() to make quoted strings
193 * `1008 <https://github.com/ipython/ipython/issues/1008>`_: don't use crash_handler by default
193 * `1008 <https://github.com/ipython/ipython/issues/1008>`_: don't use crash_handler by default
194 * `1003 <https://github.com/ipython/ipython/issues/1003>`_: Drop consecutive duplicates when refilling readline history
194 * `1003 <https://github.com/ipython/ipython/issues/1003>`_: Drop consecutive duplicates when refilling readline history
195 * `997 <https://github.com/ipython/ipython/issues/997>`_: don't unregister interrupted post-exec functions
195 * `997 <https://github.com/ipython/ipython/issues/997>`_: don't unregister interrupted post-exec functions
196 * `996 <https://github.com/ipython/ipython/issues/996>`_: add Integer traitlet
196 * `996 <https://github.com/ipython/ipython/issues/996>`_: add Integer traitlet
197 * `1016 <https://github.com/ipython/ipython/issues/1016>`_: Fix password hashing for Python 3
197 * `1016 <https://github.com/ipython/ipython/issues/1016>`_: Fix password hashing for Python 3
198 * `1014 <https://github.com/ipython/ipython/issues/1014>`_: escape minus signs in manpages
198 * `1014 <https://github.com/ipython/ipython/issues/1014>`_: escape minus signs in manpages
199 * `1013 <https://github.com/ipython/ipython/issues/1013>`_: [NumPyExampleDocstring] link was pointing to raw file
199 * `1013 <https://github.com/ipython/ipython/issues/1013>`_: [NumPyExampleDocstring] link was pointing to raw file
200 * `1011 <https://github.com/ipython/ipython/issues/1011>`_: Add hashed password support.
200 * `1011 <https://github.com/ipython/ipython/issues/1011>`_: Add hashed password support.
201 * `1005 <https://github.com/ipython/ipython/issues/1005>`_: Quick fix for os.system requiring str parameter
201 * `1005 <https://github.com/ipython/ipython/issues/1005>`_: Quick fix for os.system requiring str parameter
202 * `994 <https://github.com/ipython/ipython/issues/994>`_: Allow latex formulas in HTML output
202 * `994 <https://github.com/ipython/ipython/issues/994>`_: Allow latex formulas in HTML output
203 * `955 <https://github.com/ipython/ipython/issues/955>`_: Websocket Adjustments
203 * `955 <https://github.com/ipython/ipython/issues/955>`_: Websocket Adjustments
204 * `979 <https://github.com/ipython/ipython/issues/979>`_: use system_raw in terminal, even on Windows
204 * `979 <https://github.com/ipython/ipython/issues/979>`_: use system_raw in terminal, even on Windows
205 * `989 <https://github.com/ipython/ipython/issues/989>`_: fix arguments for commands in _process_posix
205 * `989 <https://github.com/ipython/ipython/issues/989>`_: fix arguments for commands in _process_posix
206 * `991 <https://github.com/ipython/ipython/issues/991>`_: Show traceback, continuing to start kernel if pylab init fails
206 * `991 <https://github.com/ipython/ipython/issues/991>`_: Show traceback, continuing to start kernel if pylab init fails
207 * `981 <https://github.com/ipython/ipython/issues/981>`_: Split likely multiline text when writing JSON notebooks
207 * `981 <https://github.com/ipython/ipython/issues/981>`_: Split likely multiline text when writing JSON notebooks
208 * `957 <https://github.com/ipython/ipython/issues/957>`_: allow change of png DPI in inline backend
208 * `957 <https://github.com/ipython/ipython/issues/957>`_: allow change of png DPI in inline backend
209 * `968 <https://github.com/ipython/ipython/issues/968>`_: add wantDirectory to ipdoctest, so that directories will be checked for e
209 * `968 <https://github.com/ipython/ipython/issues/968>`_: add wantDirectory to ipdoctest, so that directories will be checked for e
210 * `984 <https://github.com/ipython/ipython/issues/984>`_: Do not expose variables defined at startup to %who etc.
210 * `984 <https://github.com/ipython/ipython/issues/984>`_: Do not expose variables defined at startup to %who etc.
211 * `985 <https://github.com/ipython/ipython/issues/985>`_: Fixes for parallel code on Python 3
211 * `985 <https://github.com/ipython/ipython/issues/985>`_: Fixes for parallel code on Python 3
212 * `963 <https://github.com/ipython/ipython/issues/963>`_: disable calltips in PySide < 1.0.7 to prevent segfault
212 * `963 <https://github.com/ipython/ipython/issues/963>`_: disable calltips in PySide < 1.0.7 to prevent segfault
213 * `976 <https://github.com/ipython/ipython/issues/976>`_: Getting started on what's new
213 * `976 <https://github.com/ipython/ipython/issues/976>`_: Getting started on what's new
214 * `929 <https://github.com/ipython/ipython/issues/929>`_: Multiline history
214 * `929 <https://github.com/ipython/ipython/issues/929>`_: Multiline history
215 * `964 <https://github.com/ipython/ipython/issues/964>`_: Default profile
215 * `964 <https://github.com/ipython/ipython/issues/964>`_: Default profile
216 * `961 <https://github.com/ipython/ipython/issues/961>`_: Disable the pager for the test suite
216 * `961 <https://github.com/ipython/ipython/issues/961>`_: Disable the pager for the test suite
217 * `953 <https://github.com/ipython/ipython/issues/953>`_: Physics extension
217 * `953 <https://github.com/ipython/ipython/issues/953>`_: Physics extension
218 * `950 <https://github.com/ipython/ipython/issues/950>`_: Add directory for startup files
218 * `950 <https://github.com/ipython/ipython/issues/950>`_: Add directory for startup files
219 * `940 <https://github.com/ipython/ipython/issues/940>`_: allow setting HistoryManager.hist_file with config
219 * `940 <https://github.com/ipython/ipython/issues/940>`_: allow setting HistoryManager.hist_file with config
220 * `948 <https://github.com/ipython/ipython/issues/948>`_: Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16.
220 * `948 <https://github.com/ipython/ipython/issues/948>`_: Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16.
221 * `916 <https://github.com/ipython/ipython/issues/916>`_: Run p ( https://github.com/ipython/ipython/pull/901 )
221 * `916 <https://github.com/ipython/ipython/issues/916>`_: Run p ( https://github.com/ipython/ipython/pull/901 )
222 * `923 <https://github.com/ipython/ipython/issues/923>`_: %config magic
222 * `923 <https://github.com/ipython/ipython/issues/923>`_: %config magic
223 * `920 <https://github.com/ipython/ipython/issues/920>`_: unordered iteration of AsyncMapResults (+ a couple fixes)
223 * `920 <https://github.com/ipython/ipython/issues/920>`_: unordered iteration of AsyncMapResults (+ a couple fixes)
224 * `941 <https://github.com/ipython/ipython/issues/941>`_: Follow-up to 387dcd6a, `_rl.__doc__` is `None` with pyreadline
224 * `941 <https://github.com/ipython/ipython/issues/941>`_: Follow-up to 387dcd6a, `_rl.__doc__` is `None` with pyreadline
225 * `931 <https://github.com/ipython/ipython/issues/931>`_: read-only notebook mode
225 * `931 <https://github.com/ipython/ipython/issues/931>`_: read-only notebook mode
226 * `921 <https://github.com/ipython/ipython/issues/921>`_: Show invalid config message on TraitErrors during init
226 * `921 <https://github.com/ipython/ipython/issues/921>`_: Show invalid config message on TraitErrors during init
227 * `815 <https://github.com/ipython/ipython/issues/815>`_: Fix #481 using custom qt4 input hook
227 * `815 <https://github.com/ipython/ipython/issues/815>`_: Fix #481 using custom qt4 input hook
228 * `936 <https://github.com/ipython/ipython/issues/936>`_: Start webbrowser in a thread. Prevents lockup with Chrome.
228 * `936 <https://github.com/ipython/ipython/issues/936>`_: Start webbrowser in a thread. Prevents lockup with Chrome.
229 * `937 <https://github.com/ipython/ipython/issues/937>`_: add dirty trick for readline import on OSX
229 * `937 <https://github.com/ipython/ipython/issues/937>`_: add dirty trick for readline import on OSX
230 * `913 <https://github.com/ipython/ipython/issues/913>`_: Py3 tests2
230 * `913 <https://github.com/ipython/ipython/issues/913>`_: Py3 tests2
231 * `933 <https://github.com/ipython/ipython/issues/933>`_: Cancel in qt console closeevent should trigger event.ignore()
231 * `933 <https://github.com/ipython/ipython/issues/933>`_: Cancel in qt console closeevent should trigger event.ignore()
232 * `930 <https://github.com/ipython/ipython/issues/930>`_: read-only notebook mode
232 * `930 <https://github.com/ipython/ipython/issues/930>`_: read-only notebook mode
233 * `910 <https://github.com/ipython/ipython/issues/910>`_: Make import checks more explicit in %whos
233 * `910 <https://github.com/ipython/ipython/issues/910>`_: Make import checks more explicit in %whos
234 * `926 <https://github.com/ipython/ipython/issues/926>`_: reincarnate -V cmdline option
234 * `926 <https://github.com/ipython/ipython/issues/926>`_: reincarnate -V cmdline option
235 * `928 <https://github.com/ipython/ipython/issues/928>`_: BUG: Set context for font size change shortcuts in ConsoleWidget
235 * `928 <https://github.com/ipython/ipython/issues/928>`_: BUG: Set context for font size change shortcuts in ConsoleWidget
236 * `901 <https://github.com/ipython/ipython/issues/901>`_: - There is a bug when running the profiler in the magic command (prun) with python3
236 * `901 <https://github.com/ipython/ipython/issues/901>`_: - There is a bug when running the profiler in the magic command (prun) with python3
237 * `912 <https://github.com/ipython/ipython/issues/912>`_: Add magic for cls on windows. Fix for #181.
237 * `912 <https://github.com/ipython/ipython/issues/912>`_: Add magic for cls on windows. Fix for #181.
238 * `905 <https://github.com/ipython/ipython/issues/905>`_: enable %gui/%pylab magics in the Kernel
238 * `905 <https://github.com/ipython/ipython/issues/905>`_: enable %gui/%pylab magics in the Kernel
239 * `909 <https://github.com/ipython/ipython/issues/909>`_: Allow IPython to run without sqlite3
239 * `909 <https://github.com/ipython/ipython/issues/909>`_: Allow IPython to run without sqlite3
240 * `887 <https://github.com/ipython/ipython/issues/887>`_: Qtconsole menu
240 * `887 <https://github.com/ipython/ipython/issues/887>`_: Qtconsole menu
241 * `895 <https://github.com/ipython/ipython/issues/895>`_: notebook download implies save
241 * `895 <https://github.com/ipython/ipython/issues/895>`_: notebook download implies save
242 * `896 <https://github.com/ipython/ipython/issues/896>`_: Execfile
242 * `896 <https://github.com/ipython/ipython/issues/896>`_: Execfile
243 * `899 <https://github.com/ipython/ipython/issues/899>`_: Brian's Notebook work
243 * `899 <https://github.com/ipython/ipython/issues/899>`_: Brian's Notebook work
244 * `892 <https://github.com/ipython/ipython/issues/892>`_: don't close figures every cycle with inline matplotlib backend
244 * `892 <https://github.com/ipython/ipython/issues/892>`_: don't close figures every cycle with inline matplotlib backend
245 * `893 <https://github.com/ipython/ipython/issues/893>`_: Adding clear_output to kernel and HTML notebook
245 * `893 <https://github.com/ipython/ipython/issues/893>`_: Adding clear_output to kernel and HTML notebook
246 * `789 <https://github.com/ipython/ipython/issues/789>`_: Adding clear_output to kernel and HTML notebook.
246 * `789 <https://github.com/ipython/ipython/issues/789>`_: Adding clear_output to kernel and HTML notebook.
247 * `898 <https://github.com/ipython/ipython/issues/898>`_: Don't pass unicode sys.argv with %run or `ipython script.py`
247 * `898 <https://github.com/ipython/ipython/issues/898>`_: Don't pass unicode sys.argv with %run or `ipython script.py`
248 * `897 <https://github.com/ipython/ipython/issues/897>`_: Add tooltips to the notebook via 'title' attr.
248 * `897 <https://github.com/ipython/ipython/issues/897>`_: Add tooltips to the notebook via 'title' attr.
249 * `877 <https://github.com/ipython/ipython/issues/877>`_: partial fix for issue #678
249 * `877 <https://github.com/ipython/ipython/issues/877>`_: partial fix for issue #678
250 * `838 <https://github.com/ipython/ipython/issues/838>`_: reenable multiline history for terminals
250 * `838 <https://github.com/ipython/ipython/issues/838>`_: reenable multiline history for terminals
251 * `872 <https://github.com/ipython/ipython/issues/872>`_: The constructor of Client() checks for AssertionError in validate_url to open a file instead of connection to a URL if it fails.
251 * `872 <https://github.com/ipython/ipython/issues/872>`_: The constructor of Client() checks for AssertionError in validate_url to open a file instead of connection to a URL if it fails.
252 * `884 <https://github.com/ipython/ipython/issues/884>`_: Notebook usability fixes
252 * `884 <https://github.com/ipython/ipython/issues/884>`_: Notebook usability fixes
253 * `883 <https://github.com/ipython/ipython/issues/883>`_: User notification if notebook saving fails
253 * `883 <https://github.com/ipython/ipython/issues/883>`_: User notification if notebook saving fails
254 * `889 <https://github.com/ipython/ipython/issues/889>`_: Add drop_by_id method to shell, to remove variables added by extensions.
254 * `889 <https://github.com/ipython/ipython/issues/889>`_: Add drop_by_id method to shell, to remove variables added by extensions.
255 * `891 <https://github.com/ipython/ipython/issues/891>`_: Ability to open the notebook in a browser when it starts
255 * `891 <https://github.com/ipython/ipython/issues/891>`_: Ability to open the notebook in a browser when it starts
256 * `813 <https://github.com/ipython/ipython/issues/813>`_: Create menu bar for qtconsole
256 * `813 <https://github.com/ipython/ipython/issues/813>`_: Create menu bar for qtconsole
257 * `876 <https://github.com/ipython/ipython/issues/876>`_: protect IPython from bad custom exception handlers
257 * `876 <https://github.com/ipython/ipython/issues/876>`_: protect IPython from bad custom exception handlers
258 * `856 <https://github.com/ipython/ipython/issues/856>`_: Backgroundjobs
258 * `856 <https://github.com/ipython/ipython/issues/856>`_: Backgroundjobs
259 * `868 <https://github.com/ipython/ipython/issues/868>`_: Warn user if MathJax can't be fetched from notebook closes #744
259 * `868 <https://github.com/ipython/ipython/issues/868>`_: Warn user if MathJax can't be fetched from notebook closes #744
260 * `878 <https://github.com/ipython/ipython/issues/878>`_: store_history=False default for run_cell
260 * `878 <https://github.com/ipython/ipython/issues/878>`_: store_history=False default for run_cell
261 * `824 <https://github.com/ipython/ipython/issues/824>`_: History access
261 * `824 <https://github.com/ipython/ipython/issues/824>`_: History access
262 * `850 <https://github.com/ipython/ipython/issues/850>`_: Update codemirror to 2.15 and make the code internally more version-agnostic
262 * `850 <https://github.com/ipython/ipython/issues/850>`_: Update codemirror to 2.15 and make the code internally more version-agnostic
263 * `861 <https://github.com/ipython/ipython/issues/861>`_: Fix for issue #56
263 * `861 <https://github.com/ipython/ipython/issues/861>`_: Fix for issue #56
264 * `819 <https://github.com/ipython/ipython/issues/819>`_: Adding -m option to %run, similar to -m for python interpreter.
264 * `819 <https://github.com/ipython/ipython/issues/819>`_: Adding -m option to %run, similar to -m for python interpreter.
265 * `855 <https://github.com/ipython/ipython/issues/855>`_: promote aliases and flags, to ensure they have priority over config files
265 * `855 <https://github.com/ipython/ipython/issues/855>`_: promote aliases and flags, to ensure they have priority over config files
266 * `862 <https://github.com/ipython/ipython/issues/862>`_: BUG: Completion widget position and pager focus.
266 * `862 <https://github.com/ipython/ipython/issues/862>`_: BUG: Completion widget position and pager focus.
267 * `847 <https://github.com/ipython/ipython/issues/847>`_: Allow connection to kernels by files
267 * `847 <https://github.com/ipython/ipython/issues/847>`_: Allow connection to kernels by files
268 * `708 <https://github.com/ipython/ipython/issues/708>`_: Two-process terminal frontend
268 * `708 <https://github.com/ipython/ipython/issues/708>`_: Two-process terminal frontend
269 * `857 <https://github.com/ipython/ipython/issues/857>`_: make sdist flags work again (e.g. --manifest-only)
269 * `857 <https://github.com/ipython/ipython/issues/857>`_: make sdist flags work again (e.g. --manifest-only)
270 * `835 <https://github.com/ipython/ipython/issues/835>`_: Add Tab key to list of keys that scroll down the paging widget.
270 * `835 <https://github.com/ipython/ipython/issues/835>`_: Add Tab key to list of keys that scroll down the paging widget.
271 * `859 <https://github.com/ipython/ipython/issues/859>`_: Fix for issue #800
271 * `859 <https://github.com/ipython/ipython/issues/859>`_: Fix for issue #800
272 * `848 <https://github.com/ipython/ipython/issues/848>`_: Python3 setup.py install failiure
272 * `848 <https://github.com/ipython/ipython/issues/848>`_: Python3 setup.py install failiure
273 * `845 <https://github.com/ipython/ipython/issues/845>`_: Tests on Python 3
273 * `845 <https://github.com/ipython/ipython/issues/845>`_: Tests on Python 3
274 * `802 <https://github.com/ipython/ipython/issues/802>`_: DOC: extensions: add documentation for the bundled extensions
274 * `802 <https://github.com/ipython/ipython/issues/802>`_: DOC: extensions: add documentation for the bundled extensions
275 * `830 <https://github.com/ipython/ipython/issues/830>`_: contiguous stdout/stderr in notebook
275 * `830 <https://github.com/ipython/ipython/issues/830>`_: contiguous stdout/stderr in notebook
276 * `761 <https://github.com/ipython/ipython/issues/761>`_: Windows: test runner fails if repo path (e.g. home dir) contains spaces
276 * `761 <https://github.com/ipython/ipython/issues/761>`_: Windows: test runner fails if repo path (e.g. home dir) contains spaces
277 * `801 <https://github.com/ipython/ipython/issues/801>`_: Py3 notebook
277 * `801 <https://github.com/ipython/ipython/issues/801>`_: Py3 notebook
278 * `809 <https://github.com/ipython/ipython/issues/809>`_: use CFRunLoop directly in `ipython kernel --pylab osx`
278 * `809 <https://github.com/ipython/ipython/issues/809>`_: use CFRunLoop directly in `ipython kernel --pylab osx`
279 * `841 <https://github.com/ipython/ipython/issues/841>`_: updated old scipy.org links, other minor doc fixes
279 * `841 <https://github.com/ipython/ipython/issues/841>`_: updated old scipy.org links, other minor doc fixes
280 * `837 <https://github.com/ipython/ipython/issues/837>`_: remove all trailling spaces
280 * `837 <https://github.com/ipython/ipython/issues/837>`_: remove all trailling spaces
281 * `834 <https://github.com/ipython/ipython/issues/834>`_: Issue https://github.com/ipython/ipython/issues/832 resolution
281 * `834 <https://github.com/ipython/ipython/issues/834>`_: Issue https://github.com/ipython/ipython/issues/832 resolution
282 * `746 <https://github.com/ipython/ipython/issues/746>`_: ENH: extensions: port autoreload to current API
282 * `746 <https://github.com/ipython/ipython/issues/746>`_: ENH: extensions: port autoreload to current API
283 * `828 <https://github.com/ipython/ipython/issues/828>`_: fixed permissions (sub-modules should not be executable) + added shebang for run_ipy_in_profiler.py
283 * `828 <https://github.com/ipython/ipython/issues/828>`_: fixed permissions (sub-modules should not be executable) + added shebang for run_ipy_in_profiler.py
284 * `798 <https://github.com/ipython/ipython/issues/798>`_: pexpect & Python 3
284 * `798 <https://github.com/ipython/ipython/issues/798>`_: pexpect & Python 3
285 * `804 <https://github.com/ipython/ipython/issues/804>`_: Magic 'range' crash if greater than len(input_hist)
285 * `804 <https://github.com/ipython/ipython/issues/804>`_: Magic 'range' crash if greater than len(input_hist)
286 * `821 <https://github.com/ipython/ipython/issues/821>`_: update tornado dependency to 2.1
286 * `821 <https://github.com/ipython/ipython/issues/821>`_: update tornado dependency to 2.1
287 * `807 <https://github.com/ipython/ipython/issues/807>`_: Faciliate ssh tunnel sharing by announcing ports
287 * `807 <https://github.com/ipython/ipython/issues/807>`_: Faciliate ssh tunnel sharing by announcing ports
288 * `795 <https://github.com/ipython/ipython/issues/795>`_: Add cluster-id for multiple cluster instances per profile
288 * `795 <https://github.com/ipython/ipython/issues/795>`_: Add cluster-id for multiple cluster instances per profile
289 * `742 <https://github.com/ipython/ipython/issues/742>`_: Glut
289 * `742 <https://github.com/ipython/ipython/issues/742>`_: Glut
290 * `668 <https://github.com/ipython/ipython/issues/668>`_: Greedy completer
290 * `668 <https://github.com/ipython/ipython/issues/668>`_: Greedy completer
291 * `776 <https://github.com/ipython/ipython/issues/776>`_: Reworking qtconsole shortcut, add fullscreen
291 * `776 <https://github.com/ipython/ipython/issues/776>`_: Reworking qtconsole shortcut, add fullscreen
292 * `790 <https://github.com/ipython/ipython/issues/790>`_: TST: add future unicode_literals test (#786)
292 * `790 <https://github.com/ipython/ipython/issues/790>`_: TST: add future unicode_literals test (#786)
293 * `775 <https://github.com/ipython/ipython/issues/775>`_: redirect_in/redirect_out should be constrained to windows only
293 * `775 <https://github.com/ipython/ipython/issues/775>`_: redirect_in/redirect_out should be constrained to windows only
294 * `793 <https://github.com/ipython/ipython/issues/793>`_: Don't use readline in the ZMQShell
294 * `793 <https://github.com/ipython/ipython/issues/793>`_: Don't use readline in the ZMQShell
295 * `743 <https://github.com/ipython/ipython/issues/743>`_: Pyglet
295 * `743 <https://github.com/ipython/ipython/issues/743>`_: Pyglet
296 * `774 <https://github.com/ipython/ipython/issues/774>`_: basic/initial .mailmap for nice shortlog summaries
296 * `774 <https://github.com/ipython/ipython/issues/774>`_: basic/initial .mailmap for nice shortlog summaries
297 * `770 <https://github.com/ipython/ipython/issues/770>`_: #769 (reopened)
297 * `770 <https://github.com/ipython/ipython/issues/770>`_: #769 (reopened)
298 * `784 <https://github.com/ipython/ipython/issues/784>`_: Parse user code to AST using compiler flags.
298 * `784 <https://github.com/ipython/ipython/issues/784>`_: Parse user code to AST using compiler flags.
299 * `783 <https://github.com/ipython/ipython/issues/783>`_: always use StringIO, never cStringIO
299 * `783 <https://github.com/ipython/ipython/issues/783>`_: always use StringIO, never cStringIO
300 * `782 <https://github.com/ipython/ipython/issues/782>`_: flush stdout/stderr on displayhook call
300 * `782 <https://github.com/ipython/ipython/issues/782>`_: flush stdout/stderr on displayhook call
301 * `622 <https://github.com/ipython/ipython/issues/622>`_: Make pylab import all configurable
301 * `622 <https://github.com/ipython/ipython/issues/622>`_: Make pylab import all configurable
302 * `745 <https://github.com/ipython/ipython/issues/745>`_: Don't assume history requests succeed in qtconsole
302 * `745 <https://github.com/ipython/ipython/issues/745>`_: Don't assume history requests succeed in qtconsole
303 * `725 <https://github.com/ipython/ipython/issues/725>`_: don't assume cursor.selectedText() is a string
303 * `725 <https://github.com/ipython/ipython/issues/725>`_: don't assume cursor.selectedText() is a string
304 * `778 <https://github.com/ipython/ipython/issues/778>`_: don't override execfile on Python 2
304 * `778 <https://github.com/ipython/ipython/issues/778>`_: don't override execfile on Python 2
305 * `663 <https://github.com/ipython/ipython/issues/663>`_: Python 3 compatilibility work
305 * `663 <https://github.com/ipython/ipython/issues/663>`_: Python 3 compatilibility work
306 * `762 <https://github.com/ipython/ipython/issues/762>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes
306 * `762 <https://github.com/ipython/ipython/issues/762>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes
307 * `763 <https://github.com/ipython/ipython/issues/763>`_: Set context for shortcuts in ConsoleWidget
307 * `763 <https://github.com/ipython/ipython/issues/763>`_: Set context for shortcuts in ConsoleWidget
308 * `722 <https://github.com/ipython/ipython/issues/722>`_: PyPy compatibility
308 * `722 <https://github.com/ipython/ipython/issues/722>`_: PyPy compatibility
309 * `757 <https://github.com/ipython/ipython/issues/757>`_: ipython.el is broken in 0.11
309 * `757 <https://github.com/ipython/ipython/issues/757>`_: ipython.el is broken in 0.11
310 * `764 <https://github.com/ipython/ipython/issues/764>`_: fix "--colors=<color>" option in py-python-command-args.
310 * `764 <https://github.com/ipython/ipython/issues/764>`_: fix "--colors=<color>" option in py-python-command-args.
311 * `758 <https://github.com/ipython/ipython/issues/758>`_: use ROUTER/DEALER socket names instead of XREP/XREQ
311 * `758 <https://github.com/ipython/ipython/issues/758>`_: use ROUTER/DEALER socket names instead of XREP/XREQ
312 * `736 <https://github.com/ipython/ipython/issues/736>`_: enh: added authentication ability for webapp
312 * `736 <https://github.com/ipython/ipython/issues/736>`_: enh: added authentication ability for webapp
313 * `748 <https://github.com/ipython/ipython/issues/748>`_: Check for tornado before running frontend.html tests.
313 * `748 <https://github.com/ipython/ipython/issues/748>`_: Check for tornado before running frontend.html tests.
314 * `754 <https://github.com/ipython/ipython/issues/754>`_: restore msg_id/msg_type aliases in top level of msg dict
314 * `754 <https://github.com/ipython/ipython/issues/754>`_: restore msg_id/msg_type aliases in top level of msg dict
315 * `769 <https://github.com/ipython/ipython/issues/769>`_: Don't treat bytes objects as json-safe
315 * `769 <https://github.com/ipython/ipython/issues/769>`_: Don't treat bytes objects as json-safe
316 * `753 <https://github.com/ipython/ipython/issues/753>`_: DOC: msg['msg_type'] removed
316 * `753 <https://github.com/ipython/ipython/issues/753>`_: DOC: msg['msg_type'] removed
317 * `766 <https://github.com/ipython/ipython/issues/766>`_: fix "--colors=<color>" option in py-python-command-args.
317 * `766 <https://github.com/ipython/ipython/issues/766>`_: fix "--colors=<color>" option in py-python-command-args.
318 * `765 <https://github.com/ipython/ipython/issues/765>`_: fix "--colors=<color>" option in py-python-command-args.
318 * `765 <https://github.com/ipython/ipython/issues/765>`_: fix "--colors=<color>" option in py-python-command-args.
319 * `741 <https://github.com/ipython/ipython/issues/741>`_: Run PyOs_InputHook in pager to keep plot windows interactive.
319 * `741 <https://github.com/ipython/ipython/issues/741>`_: Run PyOs_InputHook in pager to keep plot windows interactive.
320 * `664 <https://github.com/ipython/ipython/issues/664>`_: Remove ipythonrc references from documentation
320 * `664 <https://github.com/ipython/ipython/issues/664>`_: Remove ipythonrc references from documentation
321 * `750 <https://github.com/ipython/ipython/issues/750>`_: Tiny doc fixes
321 * `750 <https://github.com/ipython/ipython/issues/750>`_: Tiny doc fixes
322 * `433 <https://github.com/ipython/ipython/issues/433>`_: ZMQ terminal frontend
322 * `433 <https://github.com/ipython/ipython/issues/433>`_: ZMQ terminal frontend
323 * `734 <https://github.com/ipython/ipython/issues/734>`_: Allow %magic argument filenames with spaces to be specified with quotes under win32
323 * `734 <https://github.com/ipython/ipython/issues/734>`_: Allow %magic argument filenames with spaces to be specified with quotes under win32
324 * `731 <https://github.com/ipython/ipython/issues/731>`_: respect encoding of display data from urls
324 * `731 <https://github.com/ipython/ipython/issues/731>`_: respect encoding of display data from urls
325 * `730 <https://github.com/ipython/ipython/issues/730>`_: doc improvements for running notebook via secure protocol
325 * `730 <https://github.com/ipython/ipython/issues/730>`_: doc improvements for running notebook via secure protocol
326 * `729 <https://github.com/ipython/ipython/issues/729>`_: use null char to start markdown cell placeholder
326 * `729 <https://github.com/ipython/ipython/issues/729>`_: use null char to start markdown cell placeholder
327 * `727 <https://github.com/ipython/ipython/issues/727>`_: Minor fixes to the htmlnotebook
327 * `727 <https://github.com/ipython/ipython/issues/727>`_: Minor fixes to the htmlnotebook
328 * `726 <https://github.com/ipython/ipython/issues/726>`_: use bundled argparse if system argparse is < 1.1
328 * `726 <https://github.com/ipython/ipython/issues/726>`_: use bundled argparse if system argparse is < 1.1
329 * `705 <https://github.com/ipython/ipython/issues/705>`_: Htmlnotebook
329 * `705 <https://github.com/ipython/ipython/issues/705>`_: Htmlnotebook
330 * `723 <https://github.com/ipython/ipython/issues/723>`_: Add 'import time' to IPython/parallel/apps/launcher.py as time.sleep is called without time being imported
330 * `723 <https://github.com/ipython/ipython/issues/723>`_: Add 'import time' to IPython/parallel/apps/launcher.py as time.sleep is called without time being imported
331 * `714 <https://github.com/ipython/ipython/issues/714>`_: Install mathjax for offline use
331 * `714 <https://github.com/ipython/ipython/issues/714>`_: Install mathjax for offline use
332 * `718 <https://github.com/ipython/ipython/issues/718>`_: Underline keyboard shortcut characters on appropriate buttons
332 * `718 <https://github.com/ipython/ipython/issues/718>`_: Underline keyboard shortcut characters on appropriate buttons
333 * `717 <https://github.com/ipython/ipython/issues/717>`_: Add source highlighting to markdown snippets
333 * `717 <https://github.com/ipython/ipython/issues/717>`_: Add source highlighting to markdown snippets
334 * `716 <https://github.com/ipython/ipython/issues/716>`_: update EvalFormatter to allow arbitrary expressions
334 * `716 <https://github.com/ipython/ipython/issues/716>`_: update EvalFormatter to allow arbitrary expressions
335 * `712 <https://github.com/ipython/ipython/issues/712>`_: Reset execution counter after cache is cleared
335 * `712 <https://github.com/ipython/ipython/issues/712>`_: Reset execution counter after cache is cleared
336 * `713 <https://github.com/ipython/ipython/issues/713>`_: Align colons in html notebook help dialog
336 * `713 <https://github.com/ipython/ipython/issues/713>`_: Align colons in html notebook help dialog
337 * `709 <https://github.com/ipython/ipython/issues/709>`_: Allow usage of '.' in notebook names
337 * `709 <https://github.com/ipython/ipython/issues/709>`_: Allow usage of '.' in notebook names
338 * `706 <https://github.com/ipython/ipython/issues/706>`_: Implement static publishing of HTML notebook
338 * `706 <https://github.com/ipython/ipython/issues/706>`_: Implement static publishing of HTML notebook
339 * `674 <https://github.com/ipython/ipython/issues/674>`_: use argparse to parse aliases & flags
339 * `674 <https://github.com/ipython/ipython/issues/674>`_: use argparse to parse aliases & flags
340 * `679 <https://github.com/ipython/ipython/issues/679>`_: HistoryManager.get_session_info()
340 * `679 <https://github.com/ipython/ipython/issues/679>`_: HistoryManager.get_session_info()
341 * `696 <https://github.com/ipython/ipython/issues/696>`_: Fix columnize bug, where tab completion with very long filenames would crash Qt console
341 * `696 <https://github.com/ipython/ipython/issues/696>`_: Fix columnize bug, where tab completion with very long filenames would crash Qt console
342 * `686 <https://github.com/ipython/ipython/issues/686>`_: add ssh tunnel support to qtconsole
342 * `686 <https://github.com/ipython/ipython/issues/686>`_: add ssh tunnel support to qtconsole
343 * `685 <https://github.com/ipython/ipython/issues/685>`_: Add SSH tunneling to engines
343 * `685 <https://github.com/ipython/ipython/issues/685>`_: Add SSH tunneling to engines
344 * `384 <https://github.com/ipython/ipython/issues/384>`_: Allow pickling objects defined interactively.
344 * `384 <https://github.com/ipython/ipython/issues/384>`_: Allow pickling objects defined interactively.
345 * `647 <https://github.com/ipython/ipython/issues/647>`_: My fix rpmlint
345 * `647 <https://github.com/ipython/ipython/issues/647>`_: My fix rpmlint
346 * `587 <https://github.com/ipython/ipython/issues/587>`_: don't special case for py3k+numpy
346 * `587 <https://github.com/ipython/ipython/issues/587>`_: don't special case for py3k+numpy
347 * `703 <https://github.com/ipython/ipython/issues/703>`_: make config-loading debug messages more explicit
347 * `703 <https://github.com/ipython/ipython/issues/703>`_: make config-loading debug messages more explicit
348 * `699 <https://github.com/ipython/ipython/issues/699>`_: make calltips configurable in qtconsole
348 * `699 <https://github.com/ipython/ipython/issues/699>`_: make calltips configurable in qtconsole
349 * `666 <https://github.com/ipython/ipython/issues/666>`_: parallel tests & extra readline escapes
349 * `666 <https://github.com/ipython/ipython/issues/666>`_: parallel tests & extra readline escapes
350 * `683 <https://github.com/ipython/ipython/issues/683>`_: BF - allow nose with-doctest setting in environment
350 * `683 <https://github.com/ipython/ipython/issues/683>`_: BF - allow nose with-doctest setting in environment
351 * `689 <https://github.com/ipython/ipython/issues/689>`_: Protect ipkernel from bad messages
351 * `689 <https://github.com/ipython/ipython/issues/689>`_: Protect ipkernel from bad messages
352 * `702 <https://github.com/ipython/ipython/issues/702>`_: Prevent ipython.py launcher from being imported.
352 * `702 <https://github.com/ipython/ipython/issues/702>`_: Prevent ipython.py launcher from being imported.
353 * `701 <https://github.com/ipython/ipython/issues/701>`_: Prevent ipython.py from being imported by accident
353 * `701 <https://github.com/ipython/ipython/issues/701>`_: Prevent ipython.py from being imported by accident
354 * `670 <https://github.com/ipython/ipython/issues/670>`_: check for writable dirs, not just existence, in utils.path
354 * `670 <https://github.com/ipython/ipython/issues/670>`_: check for writable dirs, not just existence, in utils.path
355 * `579 <https://github.com/ipython/ipython/issues/579>`_: Sessionwork
355 * `579 <https://github.com/ipython/ipython/issues/579>`_: Sessionwork
356 * `687 <https://github.com/ipython/ipython/issues/687>`_: add `ipython kernel` for starting just a kernel
356 * `687 <https://github.com/ipython/ipython/issues/687>`_: add `ipython kernel` for starting just a kernel
357 * `627 <https://github.com/ipython/ipython/issues/627>`_: Qt Console history search
357 * `627 <https://github.com/ipython/ipython/issues/627>`_: Qt Console history search
358 * `646 <https://github.com/ipython/ipython/issues/646>`_: Generate package list automatically in find_packages
358 * `646 <https://github.com/ipython/ipython/issues/646>`_: Generate package list automatically in find_packages
359 * `660 <https://github.com/ipython/ipython/issues/660>`_: i658
359 * `660 <https://github.com/ipython/ipython/issues/660>`_: i658
360 * `659 <https://github.com/ipython/ipython/issues/659>`_: don't crash on bad config files
360 * `659 <https://github.com/ipython/ipython/issues/659>`_: don't crash on bad config files
361
361
362 Regular issues (258):
362 Regular issues (258):
363
363
364 * `1177 <https://github.com/ipython/ipython/issues/1177>`_: UnicodeDecodeError in py3compat from "xlrd??"
364 * `1177 <https://github.com/ipython/ipython/issues/1177>`_: UnicodeDecodeError in py3compat from "xlrd??"
365 * `1094 <https://github.com/ipython/ipython/issues/1094>`_: Tooltip doesn't show constructor docstrings
365 * `1094 <https://github.com/ipython/ipython/issues/1094>`_: Tooltip doesn't show constructor docstrings
366 * `1170 <https://github.com/ipython/ipython/issues/1170>`_: double pylab greeting with c.InteractiveShellApp.pylab = "tk" in zmqconsole
366 * `1170 <https://github.com/ipython/ipython/issues/1170>`_: double pylab greeting with c.InteractiveShellApp.pylab = "tk" in zmqconsole
367 * `1166 <https://github.com/ipython/ipython/issues/1166>`_: E-mail cpaste broken
367 * `1166 <https://github.com/ipython/ipython/issues/1166>`_: E-mail cpaste broken
368 * `1164 <https://github.com/ipython/ipython/issues/1164>`_: IPython qtconsole (0.12) can't export to html with external png
368 * `1164 <https://github.com/ipython/ipython/issues/1164>`_: IPython qtconsole (0.12) can't export to html with external png
369 * `1103 <https://github.com/ipython/ipython/issues/1103>`_: %loadpy should cut out encoding declaration
369 * `1103 <https://github.com/ipython/ipython/issues/1103>`_: %loadpy should cut out encoding declaration
370 * `1156 <https://github.com/ipython/ipython/issues/1156>`_: Notebooks downloaded as Python files require a header stating the encoding
370 * `1156 <https://github.com/ipython/ipython/issues/1156>`_: Notebooks downloaded as Python files require a header stating the encoding
371 * `1157 <https://github.com/ipython/ipython/issues/1157>`_: Ctrl-C not working when GUI/pylab integration is active
371 * `1157 <https://github.com/ipython/ipython/issues/1157>`_: Ctrl-C not working when GUI/pylab integration is active
372 * `1154 <https://github.com/ipython/ipython/issues/1154>`_: We should be less aggressive in de-registering post-execution functions
372 * `1154 <https://github.com/ipython/ipython/issues/1154>`_: We should be less aggressive in de-registering post-execution functions
373 * `1134 <https://github.com/ipython/ipython/issues/1134>`_: "select-all, kill" leaves qtconsole in unusable state
373 * `1134 <https://github.com/ipython/ipython/issues/1134>`_: "select-all, kill" leaves qtconsole in unusable state
374 * `1148 <https://github.com/ipython/ipython/issues/1148>`_: A lot of testerrors
374 * `1148 <https://github.com/ipython/ipython/issues/1148>`_: A lot of testerrors
375 * `803 <https://github.com/ipython/ipython/issues/803>`_: Make doctests work with Python 3
375 * `803 <https://github.com/ipython/ipython/issues/803>`_: Make doctests work with Python 3
376 * `1119 <https://github.com/ipython/ipython/issues/1119>`_: Start menu shortcuts not created in Python 3
376 * `1119 <https://github.com/ipython/ipython/issues/1119>`_: Start menu shortcuts not created in Python 3
377 * `1136 <https://github.com/ipython/ipython/issues/1136>`_: The embedding machinery ignores user_ns
377 * `1136 <https://github.com/ipython/ipython/issues/1136>`_: The embedding machinery ignores user_ns
378 * `607 <https://github.com/ipython/ipython/issues/607>`_: Use the new IPython logo/font in the notebook header
378 * `607 <https://github.com/ipython/ipython/issues/607>`_: Use the new IPython logo/font in the notebook header
379 * `755 <https://github.com/ipython/ipython/issues/755>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes
379 * `755 <https://github.com/ipython/ipython/issues/755>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes
380 * `1115 <https://github.com/ipython/ipython/issues/1115>`_: shlex_split should return unicode
380 * `1115 <https://github.com/ipython/ipython/issues/1115>`_: shlex_split should return unicode
381 * `1109 <https://github.com/ipython/ipython/issues/1109>`_: timeit with string ending in space gives "ValueError: No closing quotation"
381 * `1109 <https://github.com/ipython/ipython/issues/1109>`_: timeit with string ending in space gives "ValueError: No closing quotation"
382 * `1142 <https://github.com/ipython/ipython/issues/1142>`_: Install problems
382 * `1142 <https://github.com/ipython/ipython/issues/1142>`_: Install problems
383 * `700 <https://github.com/ipython/ipython/issues/700>`_: Some SVG images render incorrectly in htmlnotebook
383 * `700 <https://github.com/ipython/ipython/issues/700>`_: Some SVG images render incorrectly in htmlnotebook
384 * `1117 <https://github.com/ipython/ipython/issues/1117>`_: quit() doesn't work in terminal
384 * `1117 <https://github.com/ipython/ipython/issues/1117>`_: quit() doesn't work in terminal
385 * `1111 <https://github.com/ipython/ipython/issues/1111>`_: ls broken after merge of #1089
385 * `1111 <https://github.com/ipython/ipython/issues/1111>`_: ls broken after merge of #1089
386 * `1104 <https://github.com/ipython/ipython/issues/1104>`_: Prompt spacing weird
386 * `1104 <https://github.com/ipython/ipython/issues/1104>`_: Prompt spacing weird
387 * `1124 <https://github.com/ipython/ipython/issues/1124>`_: Seg Fault 11 when calling PySide using "run" command
387 * `1124 <https://github.com/ipython/ipython/issues/1124>`_: Seg Fault 11 when calling PySide using "run" command
388 * `1088 <https://github.com/ipython/ipython/issues/1088>`_: QtConsole : can't copy from pager
388 * `1088 <https://github.com/ipython/ipython/issues/1088>`_: QtConsole : can't copy from pager
389 * `568 <https://github.com/ipython/ipython/issues/568>`_: Test error and failure in IPython.core on windows
389 * `568 <https://github.com/ipython/ipython/issues/568>`_: Test error and failure in IPython.core on windows
390 * `1112 <https://github.com/ipython/ipython/issues/1112>`_: testfailure in IPython.frontend on windows
390 * `1112 <https://github.com/ipython/ipython/issues/1112>`_: testfailure in IPython.frontend on windows
391 * `1102 <https://github.com/ipython/ipython/issues/1102>`_: magic in IPythonDemo fails when not located at top of demo file
391 * `1102 <https://github.com/ipython/ipython/issues/1102>`_: magic in IPythonDemo fails when not located at top of demo file
392 * `629 <https://github.com/ipython/ipython/issues/629>`_: \r and \b in qtconsole don't behave as expected
392 * `629 <https://github.com/ipython/ipython/issues/629>`_: \r and \b in qtconsole don't behave as expected
393 * `1080 <https://github.com/ipython/ipython/issues/1080>`_: Notebook: tab completion should close on "("
393 * `1080 <https://github.com/ipython/ipython/issues/1080>`_: Notebook: tab completion should close on "("
394 * `973 <https://github.com/ipython/ipython/issues/973>`_: Qt Console close dialog and on-top Qt Console
394 * `973 <https://github.com/ipython/ipython/issues/973>`_: Qt Console close dialog and on-top Qt Console
395 * `1087 <https://github.com/ipython/ipython/issues/1087>`_: QtConsole xhtml/Svg export broken ?
395 * `1087 <https://github.com/ipython/ipython/issues/1087>`_: QtConsole xhtml/Svg export broken ?
396 * `1067 <https://github.com/ipython/ipython/issues/1067>`_: Parallel test suite hangs on Python 3
396 * `1067 <https://github.com/ipython/ipython/issues/1067>`_: Parallel test suite hangs on Python 3
397 * `1018 <https://github.com/ipython/ipython/issues/1018>`_: Local mathjax breaks install
397 * `1018 <https://github.com/ipython/ipython/issues/1018>`_: Local mathjax breaks install
398 * `993 <https://github.com/ipython/ipython/issues/993>`_: `raw_input` redirection to foreign kernels is extremely brittle
398 * `993 <https://github.com/ipython/ipython/issues/993>`_: `raw_input` redirection to foreign kernels is extremely brittle
399 * `1100 <https://github.com/ipython/ipython/issues/1100>`_: ipython3 traceback unicode issue from extensions
399 * `1100 <https://github.com/ipython/ipython/issues/1100>`_: ipython3 traceback unicode issue from extensions
400 * `1071 <https://github.com/ipython/ipython/issues/1071>`_: Large html-notebooks hang on load on a slow machine
400 * `1071 <https://github.com/ipython/ipython/issues/1071>`_: Large html-notebooks hang on load on a slow machine
401 * `89 <https://github.com/ipython/ipython/issues/89>`_: %pdoc np.ma.compress shows docstring twice
401 * `89 <https://github.com/ipython/ipython/issues/89>`_: %pdoc np.ma.compress shows docstring twice
402 * `22 <https://github.com/ipython/ipython/issues/22>`_: Include improvements from anythingipython.el
402 * `22 <https://github.com/ipython/ipython/issues/22>`_: Include improvements from anythingipython.el
403 * `633 <https://github.com/ipython/ipython/issues/633>`_: Execution count & SyntaxError
403 * `633 <https://github.com/ipython/ipython/issues/633>`_: Execution count & SyntaxError
404 * `1095 <https://github.com/ipython/ipython/issues/1095>`_: Uncaught TypeError: Object has no method 'remove_and_cancell_tooltip'
404 * `1095 <https://github.com/ipython/ipython/issues/1095>`_: Uncaught TypeError: Object has no method 'remove_and_cancell_tooltip'
405 * `1075 <https://github.com/ipython/ipython/issues/1075>`_: We're ignoring prompt customizations
405 * `1075 <https://github.com/ipython/ipython/issues/1075>`_: We're ignoring prompt customizations
406 * `1086 <https://github.com/ipython/ipython/issues/1086>`_: Can't open qtconsole from outside source tree
406 * `1086 <https://github.com/ipython/ipython/issues/1086>`_: Can't open qtconsole from outside source tree
407 * `1076 <https://github.com/ipython/ipython/issues/1076>`_: namespace changes broke `foo.*bar*?` syntax
407 * `1076 <https://github.com/ipython/ipython/issues/1076>`_: namespace changes broke `foo.*bar*?` syntax
408 * `1074 <https://github.com/ipython/ipython/issues/1074>`_: pprinting old-style class objects fails (TypeError: 'tuple' object is not callable)
408 * `1074 <https://github.com/ipython/ipython/issues/1074>`_: pprinting old-style class objects fails (TypeError: 'tuple' object is not callable)
409 * `1063 <https://github.com/ipython/ipython/issues/1063>`_: IPython.utils test error due to missing unicodedata module
409 * `1063 <https://github.com/ipython/ipython/issues/1063>`_: IPython.utils test error due to missing unicodedata module
410 * `592 <https://github.com/ipython/ipython/issues/592>`_: Bug in argument parsing for %run
410 * `592 <https://github.com/ipython/ipython/issues/592>`_: Bug in argument parsing for %run
411 * `378 <https://github.com/ipython/ipython/issues/378>`_: Windows path escape issues
411 * `378 <https://github.com/ipython/ipython/issues/378>`_: Windows path escape issues
412 * `1068 <https://github.com/ipython/ipython/issues/1068>`_: Notebook tab completion broken in Firefox
412 * `1068 <https://github.com/ipython/ipython/issues/1068>`_: Notebook tab completion broken in Firefox
413 * `75 <https://github.com/ipython/ipython/issues/75>`_: No tab completion after "/
413 * `75 <https://github.com/ipython/ipython/issues/75>`_: No tab completion after "/
414 * `103 <https://github.com/ipython/ipython/issues/103>`_: customizable cpaste
414 * `103 <https://github.com/ipython/ipython/issues/103>`_: customizable cpaste
415 * `324 <https://github.com/ipython/ipython/issues/324>`_: Remove code in IPython.testing that is not being used
415 * `324 <https://github.com/ipython/ipython/issues/324>`_: Remove code in IPython.testing that is not being used
416 * `131 <https://github.com/ipython/ipython/issues/131>`_: Global variables not seen by cprofile.run()
416 * `131 <https://github.com/ipython/ipython/issues/131>`_: Global variables not seen by cprofile.run()
417 * `851 <https://github.com/ipython/ipython/issues/851>`_: IPython shell swallows exceptions in certain circumstances
417 * `851 <https://github.com/ipython/ipython/issues/851>`_: IPython shell swallows exceptions in certain circumstances
418 * `882 <https://github.com/ipython/ipython/issues/882>`_: ipython freezes at start if IPYTHONDIR is on an NFS mount
418 * `882 <https://github.com/ipython/ipython/issues/882>`_: ipython freezes at start if IPYTHONDIR is on an NFS mount
419 * `1057 <https://github.com/ipython/ipython/issues/1057>`_: Blocker: Qt console broken after "all magics" menu became dynamic
419 * `1057 <https://github.com/ipython/ipython/issues/1057>`_: Blocker: Qt console broken after "all magics" menu became dynamic
420 * `1027 <https://github.com/ipython/ipython/issues/1027>`_: ipython does not like white space at end of file
420 * `1027 <https://github.com/ipython/ipython/issues/1027>`_: ipython does not like white space at end of file
421 * `1058 <https://github.com/ipython/ipython/issues/1058>`_: New bug: Notebook asks for confirmation to leave even saved pages.
421 * `1058 <https://github.com/ipython/ipython/issues/1058>`_: New bug: Notebook asks for confirmation to leave even saved pages.
422 * `1061 <https://github.com/ipython/ipython/issues/1061>`_: rep (magic recall) under pypy
422 * `1061 <https://github.com/ipython/ipython/issues/1061>`_: rep (magic recall) under pypy
423 * `1047 <https://github.com/ipython/ipython/issues/1047>`_: Document the notebook format
423 * `1047 <https://github.com/ipython/ipython/issues/1047>`_: Document the notebook format
424 * `102 <https://github.com/ipython/ipython/issues/102>`_: Properties accessed twice for classes defined interactively
424 * `102 <https://github.com/ipython/ipython/issues/102>`_: Properties accessed twice for classes defined interactively
425 * `16 <https://github.com/ipython/ipython/issues/16>`_: %store raises exception when storing compiled regex
425 * `16 <https://github.com/ipython/ipython/issues/16>`_: %store raises exception when storing compiled regex
426 * `67 <https://github.com/ipython/ipython/issues/67>`_: tab expansion should only take one directory level at the time
426 * `67 <https://github.com/ipython/ipython/issues/67>`_: tab expansion should only take one directory level at the time
427 * `62 <https://github.com/ipython/ipython/issues/62>`_: Global variables undefined in interactive use of embedded ipython shell
427 * `62 <https://github.com/ipython/ipython/issues/62>`_: Global variables undefined in interactive use of embedded ipython shell
428 * `57 <https://github.com/ipython/ipython/issues/57>`_: debugging with ipython does not work well outside ipython
428 * `57 <https://github.com/ipython/ipython/issues/57>`_: debugging with ipython does not work well outside ipython
429 * `38 <https://github.com/ipython/ipython/issues/38>`_: Line entry edge case error
429 * `38 <https://github.com/ipython/ipython/issues/38>`_: Line entry edge case error
430 * `980 <https://github.com/ipython/ipython/issues/980>`_: Update parallel docs for new parallel architecture
430 * `980 <https://github.com/ipython/ipython/issues/980>`_: Update parallel docs for new parallel architecture
431 * `1017 <https://github.com/ipython/ipython/issues/1017>`_: Add small example about ipcluster/ssh startup
431 * `1017 <https://github.com/ipython/ipython/issues/1017>`_: Add small example about ipcluster/ssh startup
432 * `1041 <https://github.com/ipython/ipython/issues/1041>`_: Proxy Issues
432 * `1041 <https://github.com/ipython/ipython/issues/1041>`_: Proxy Issues
433 * `967 <https://github.com/ipython/ipython/issues/967>`_: KernelManagers don't use zmq eventloop properly
433 * `967 <https://github.com/ipython/ipython/issues/967>`_: KernelManagers don't use zmq eventloop properly
434 * `1055 <https://github.com/ipython/ipython/issues/1055>`_: "All Magics" display on Ubuntu
434 * `1055 <https://github.com/ipython/ipython/issues/1055>`_: "All Magics" display on Ubuntu
435 * `1054 <https://github.com/ipython/ipython/issues/1054>`_: ipython explodes on syntax error
435 * `1054 <https://github.com/ipython/ipython/issues/1054>`_: ipython explodes on syntax error
436 * `1051 <https://github.com/ipython/ipython/issues/1051>`_: ipython3 set_next_input() failure
436 * `1051 <https://github.com/ipython/ipython/issues/1051>`_: ipython3 set_next_input() failure
437 * `693 <https://github.com/ipython/ipython/issues/693>`_: "run -i" no longer works after %reset in terminal
437 * `693 <https://github.com/ipython/ipython/issues/693>`_: "run -i" no longer works after %reset in terminal
438 * `29 <https://github.com/ipython/ipython/issues/29>`_: cPickle works in standard interpreter, but not in IPython
438 * `29 <https://github.com/ipython/ipython/issues/29>`_: cPickle works in standard interpreter, but not in IPython
439 * `1050 <https://github.com/ipython/ipython/issues/1050>`_: ipython3 broken by commit 8bb887c8c2c447bf7
439 * `1050 <https://github.com/ipython/ipython/issues/1050>`_: ipython3 broken by commit 8bb887c8c2c447bf7
440 * `1048 <https://github.com/ipython/ipython/issues/1048>`_: Update docs on notebook password
440 * `1048 <https://github.com/ipython/ipython/issues/1048>`_: Update docs on notebook password
441 * `1046 <https://github.com/ipython/ipython/issues/1046>`_: Searies of questions/issues?
441 * `1046 <https://github.com/ipython/ipython/issues/1046>`_: Searies of questions/issues?
442 * `1045 <https://github.com/ipython/ipython/issues/1045>`_: crash when exiting - previously launched embedded sub-shell
442 * `1045 <https://github.com/ipython/ipython/issues/1045>`_: crash when exiting - previously launched embedded sub-shell
443 * `1043 <https://github.com/ipython/ipython/issues/1043>`_: pylab doesn't work in qtconsole
443 * `1043 <https://github.com/ipython/ipython/issues/1043>`_: pylab doesn't work in qtconsole
444 * `1044 <https://github.com/ipython/ipython/issues/1044>`_: run -p doesn't work in python 3
444 * `1044 <https://github.com/ipython/ipython/issues/1044>`_: run -p doesn't work in python 3
445 * `1010 <https://github.com/ipython/ipython/issues/1010>`_: emacs freezes when ipython-complete is called
445 * `1010 <https://github.com/ipython/ipython/issues/1010>`_: emacs freezes when ipython-complete is called
446 * `82 <https://github.com/ipython/ipython/issues/82>`_: Update devel docs with discussion about good changelogs
446 * `82 <https://github.com/ipython/ipython/issues/82>`_: Update devel docs with discussion about good changelogs
447 * `116 <https://github.com/ipython/ipython/issues/116>`_: Update release management scipts and release.revision for git
447 * `116 <https://github.com/ipython/ipython/issues/116>`_: Update release management scipts and release.revision for git
448 * `1022 <https://github.com/ipython/ipython/issues/1022>`_: Pylab banner shows up with first cell to execute
448 * `1022 <https://github.com/ipython/ipython/issues/1022>`_: Pylab banner shows up with first cell to execute
449 * `787 <https://github.com/ipython/ipython/issues/787>`_: Keyboard selection of multiple lines in the notebook behaves inconsistently
449 * `787 <https://github.com/ipython/ipython/issues/787>`_: Keyboard selection of multiple lines in the notebook behaves inconsistently
450 * `1037 <https://github.com/ipython/ipython/issues/1037>`_: notepad + jsonlib: TypeError: Only whitespace may be used for indentation.
450 * `1037 <https://github.com/ipython/ipython/issues/1037>`_: notepad + jsonlib: TypeError: Only whitespace may be used for indentation.
451 * `970 <https://github.com/ipython/ipython/issues/970>`_: Default home not writable, %HOME% does not help (windows)
451 * `970 <https://github.com/ipython/ipython/issues/970>`_: Default home not writable, %HOME% does not help (windows)
452 * `747 <https://github.com/ipython/ipython/issues/747>`_: HOMESHARE not a good choice for "writable homedir" on Windows
452 * `747 <https://github.com/ipython/ipython/issues/747>`_: HOMESHARE not a good choice for "writable homedir" on Windows
453 * `810 <https://github.com/ipython/ipython/issues/810>`_: cleanup utils.path.get_home_dir
453 * `810 <https://github.com/ipython/ipython/issues/810>`_: cleanup utils.path.get_home_dir
454 * `2 <https://github.com/ipython/ipython/issues/2>`_: Fix the copyright statement in source code files to be accurate
454 * `2 <https://github.com/ipython/ipython/issues/2>`_: Fix the copyright statement in source code files to be accurate
455 * `1031 <https://github.com/ipython/ipython/issues/1031>`_: <esc> on Firefox crash websocket
455 * `1031 <https://github.com/ipython/ipython/issues/1031>`_: <esc> on Firefox crash websocket
456 * `684 <https://github.com/ipython/ipython/issues/684>`_: %Store eliminated in configuration and magic commands in 0.11
456 * `684 <https://github.com/ipython/ipython/issues/684>`_: %Store eliminated in configuration and magic commands in 0.11
457 * `1026 <https://github.com/ipython/ipython/issues/1026>`_: BUG: wrong default parameter in ask_yes_no
457 * `1026 <https://github.com/ipython/ipython/issues/1026>`_: BUG: wrong default parameter in ask_yes_no
458 * `880 <https://github.com/ipython/ipython/issues/880>`_: Better error message if %paste fails
458 * `880 <https://github.com/ipython/ipython/issues/880>`_: Better error message if %paste fails
459 * `1024 <https://github.com/ipython/ipython/issues/1024>`_: autopx magic broken
459 * `1024 <https://github.com/ipython/ipython/issues/1024>`_: autopx magic broken
460 * `822 <https://github.com/ipython/ipython/issues/822>`_: Unicode bug in Itpl when expanding shell variables in syscalls with !
460 * `822 <https://github.com/ipython/ipython/issues/822>`_: Unicode bug in Itpl when expanding shell variables in syscalls with !
461 * `1009 <https://github.com/ipython/ipython/issues/1009>`_: Windows: regression in cd magic handling of paths
461 * `1009 <https://github.com/ipython/ipython/issues/1009>`_: Windows: regression in cd magic handling of paths
462 * `833 <https://github.com/ipython/ipython/issues/833>`_: Crash python with matplotlib and unequal length arrays
462 * `833 <https://github.com/ipython/ipython/issues/833>`_: Crash python with matplotlib and unequal length arrays
463 * `695 <https://github.com/ipython/ipython/issues/695>`_: Crash handler initialization is too aggressive
463 * `695 <https://github.com/ipython/ipython/issues/695>`_: Crash handler initialization is too aggressive
464 * `1000 <https://github.com/ipython/ipython/issues/1000>`_: Remove duplicates when refilling readline history
464 * `1000 <https://github.com/ipython/ipython/issues/1000>`_: Remove duplicates when refilling readline history
465 * `992 <https://github.com/ipython/ipython/issues/992>`_: Interrupting certain matplotlib operations leaves the inline backend 'wedged'
465 * `992 <https://github.com/ipython/ipython/issues/992>`_: Interrupting certain matplotlib operations leaves the inline backend 'wedged'
466 * `942 <https://github.com/ipython/ipython/issues/942>`_: number traits should cast if value doesn't change
466 * `942 <https://github.com/ipython/ipython/issues/942>`_: number traits should cast if value doesn't change
467 * `1006 <https://github.com/ipython/ipython/issues/1006>`_: ls crashes when run on a UNC path or with non-ascii args
467 * `1006 <https://github.com/ipython/ipython/issues/1006>`_: ls crashes when run on a UNC path or with non-ascii args
468 * `944 <https://github.com/ipython/ipython/issues/944>`_: Decide the default image format for inline figures: SVG or PNG?
468 * `944 <https://github.com/ipython/ipython/issues/944>`_: Decide the default image format for inline figures: SVG or PNG?
469 * `842 <https://github.com/ipython/ipython/issues/842>`_: Python 3 on Windows (pyreadline) - expected an object with the buffer interface
469 * `842 <https://github.com/ipython/ipython/issues/842>`_: Python 3 on Windows (pyreadline) - expected an object with the buffer interface
470 * `1002 <https://github.com/ipython/ipython/issues/1002>`_: ImportError due to incorrect version checking
470 * `1002 <https://github.com/ipython/ipython/issues/1002>`_: ImportError due to incorrect version checking
471 * `1001 <https://github.com/ipython/ipython/issues/1001>`_: Ipython "source" command?
471 * `1001 <https://github.com/ipython/ipython/issues/1001>`_: Ipython "source" command?
472 * `954 <https://github.com/ipython/ipython/issues/954>`_: IPython embed doesn't respect namespaces
472 * `954 <https://github.com/ipython/ipython/issues/954>`_: IPython embed doesn't respect namespaces
473 * `681 <https://github.com/ipython/ipython/issues/681>`_: pdb freezes inside qtconsole
473 * `681 <https://github.com/ipython/ipython/issues/681>`_: pdb freezes inside qtconsole
474 * `698 <https://github.com/ipython/ipython/issues/698>`_: crash report "TypeError: can only concatenate list (not "unicode") to list"
474 * `698 <https://github.com/ipython/ipython/issues/698>`_: crash report "TypeError: can only concatenate list (not "unicode") to list"
475 * `978 <https://github.com/ipython/ipython/issues/978>`_: ipython 0.11 buffers external command output till the cmd is done
475 * `978 <https://github.com/ipython/ipython/issues/978>`_: ipython 0.11 buffers external command output till the cmd is done
476 * `952 <https://github.com/ipython/ipython/issues/952>`_: Need user-facing warning in the browser if websocket connection fails
476 * `952 <https://github.com/ipython/ipython/issues/952>`_: Need user-facing warning in the browser if websocket connection fails
477 * `988 <https://github.com/ipython/ipython/issues/988>`_: Error using idlsave
477 * `988 <https://github.com/ipython/ipython/issues/988>`_: Error using idlsave
478 * `990 <https://github.com/ipython/ipython/issues/990>`_: ipython notebook - kernel dies if matplotlib is not installed
478 * `990 <https://github.com/ipython/ipython/issues/990>`_: ipython notebook - kernel dies if matplotlib is not installed
479 * `752 <https://github.com/ipython/ipython/issues/752>`_: Matplotlib figures showed only once in notebook
479 * `752 <https://github.com/ipython/ipython/issues/752>`_: Matplotlib figures showed only once in notebook
480 * `54 <https://github.com/ipython/ipython/issues/54>`_: Exception hook should be optional for embedding IPython in GUIs
480 * `54 <https://github.com/ipython/ipython/issues/54>`_: Exception hook should be optional for embedding IPython in GUIs
481 * `918 <https://github.com/ipython/ipython/issues/918>`_: IPython.frontend tests fail without tornado
481 * `918 <https://github.com/ipython/ipython/issues/918>`_: IPython.frontend tests fail without tornado
482 * `986 <https://github.com/ipython/ipython/issues/986>`_: Views created with c.direct_view() fail
482 * `986 <https://github.com/ipython/ipython/issues/986>`_: Views created with c.direct_view() fail
483 * `697 <https://github.com/ipython/ipython/issues/697>`_: Filter out from %who names loaded at initialization time
483 * `697 <https://github.com/ipython/ipython/issues/697>`_: Filter out from %who names loaded at initialization time
484 * `932 <https://github.com/ipython/ipython/issues/932>`_: IPython 0.11 quickref card has superfluous "%recall and"
484 * `932 <https://github.com/ipython/ipython/issues/932>`_: IPython 0.11 quickref card has superfluous "%recall and"
485 * `982 <https://github.com/ipython/ipython/issues/982>`_: png files with executable permissions
485 * `982 <https://github.com/ipython/ipython/issues/982>`_: png files with executable permissions
486 * `914 <https://github.com/ipython/ipython/issues/914>`_: Simpler system for running code after InteractiveShell is initialised
486 * `914 <https://github.com/ipython/ipython/issues/914>`_: Simpler system for running code after InteractiveShell is initialised
487 * `911 <https://github.com/ipython/ipython/issues/911>`_: ipython crashes on startup if readline is missing
487 * `911 <https://github.com/ipython/ipython/issues/911>`_: ipython crashes on startup if readline is missing
488 * `971 <https://github.com/ipython/ipython/issues/971>`_: bookmarks created in 0.11 are corrupt in 0.12
488 * `971 <https://github.com/ipython/ipython/issues/971>`_: bookmarks created in 0.11 are corrupt in 0.12
489 * `974 <https://github.com/ipython/ipython/issues/974>`_: object feature tab-completion crash
489 * `974 <https://github.com/ipython/ipython/issues/974>`_: object feature tab-completion crash
490 * `939 <https://github.com/ipython/ipython/issues/939>`_: ZMQShell always uses default profile
490 * `939 <https://github.com/ipython/ipython/issues/939>`_: ZMQShell always uses default profile
491 * `946 <https://github.com/ipython/ipython/issues/946>`_: Multi-tab Close action should offer option to leave all kernels alone
491 * `946 <https://github.com/ipython/ipython/issues/946>`_: Multi-tab Close action should offer option to leave all kernels alone
492 * `949 <https://github.com/ipython/ipython/issues/949>`_: Test suite must not require any manual interaction
492 * `949 <https://github.com/ipython/ipython/issues/949>`_: Test suite must not require any manual interaction
493 * `643 <https://github.com/ipython/ipython/issues/643>`_: enable gui eventloop integration in ipkernel
493 * `643 <https://github.com/ipython/ipython/issues/643>`_: enable gui eventloop integration in ipkernel
494 * `965 <https://github.com/ipython/ipython/issues/965>`_: ipython is crashed without launch.(python3.2)
494 * `965 <https://github.com/ipython/ipython/issues/965>`_: ipython is crashed without launch.(python3.2)
495 * `958 <https://github.com/ipython/ipython/issues/958>`_: Can't use os X clipboard on with qtconsole
495 * `958 <https://github.com/ipython/ipython/issues/958>`_: Can't use os X clipboard on with qtconsole
496 * `962 <https://github.com/ipython/ipython/issues/962>`_: Don't require tornado in the tests
496 * `962 <https://github.com/ipython/ipython/issues/962>`_: Don't require tornado in the tests
497 * `960 <https://github.com/ipython/ipython/issues/960>`_: crash on syntax error on Windows XP
497 * `960 <https://github.com/ipython/ipython/issues/960>`_: crash on syntax error on Windows XP
498 * `934 <https://github.com/ipython/ipython/issues/934>`_: The latest ipython branch doesn't work in Chrome
498 * `934 <https://github.com/ipython/ipython/issues/934>`_: The latest ipython branch doesn't work in Chrome
499 * `870 <https://github.com/ipython/ipython/issues/870>`_: zmq version detection
499 * `870 <https://github.com/ipython/ipython/issues/870>`_: zmq version detection
500 * `943 <https://github.com/ipython/ipython/issues/943>`_: HISTIGNORE for IPython
500 * `943 <https://github.com/ipython/ipython/issues/943>`_: HISTIGNORE for IPython
501 * `947 <https://github.com/ipython/ipython/issues/947>`_: qtconsole segfaults at startup
501 * `947 <https://github.com/ipython/ipython/issues/947>`_: qtconsole segfaults at startup
502 * `903 <https://github.com/ipython/ipython/issues/903>`_: Expose a magic to control config of the inline pylab backend
502 * `903 <https://github.com/ipython/ipython/issues/903>`_: Expose a magic to control config of the inline pylab backend
503 * `908 <https://github.com/ipython/ipython/issues/908>`_: bad user config shouldn't crash IPython
503 * `908 <https://github.com/ipython/ipython/issues/908>`_: bad user config shouldn't crash IPython
504 * `935 <https://github.com/ipython/ipython/issues/935>`_: Typing `break` causes IPython to crash.
504 * `935 <https://github.com/ipython/ipython/issues/935>`_: Typing `break` causes IPython to crash.
505 * `869 <https://github.com/ipython/ipython/issues/869>`_: Tab completion of `~/` shows no output post 0.10.x
505 * `869 <https://github.com/ipython/ipython/issues/869>`_: Tab completion of `~/` shows no output post 0.10.x
506 * `904 <https://github.com/ipython/ipython/issues/904>`_: whos under pypy1.6
506 * `904 <https://github.com/ipython/ipython/issues/904>`_: whos under pypy1.6
507 * `773 <https://github.com/ipython/ipython/issues/773>`_: check_security_dir() and check_pid_dir() fail on network filesystem
507 * `773 <https://github.com/ipython/ipython/issues/773>`_: check_security_dir() and check_pid_dir() fail on network filesystem
508 * `915 <https://github.com/ipython/ipython/issues/915>`_: OS X Lion Terminal.app line wrap problem
508 * `915 <https://github.com/ipython/ipython/issues/915>`_: OS X Lion Terminal.app line wrap problem
509 * `886 <https://github.com/ipython/ipython/issues/886>`_: Notebook kernel crash when specifying --notebook-dir on commandline
509 * `886 <https://github.com/ipython/ipython/issues/886>`_: Notebook kernel crash when specifying --notebook-dir on commandline
510 * `636 <https://github.com/ipython/ipython/issues/636>`_: debugger.py: pydb broken
510 * `636 <https://github.com/ipython/ipython/issues/636>`_: debugger.py: pydb broken
511 * `808 <https://github.com/ipython/ipython/issues/808>`_: Ctrl+C during %reset confirm message crash Qtconsole
511 * `808 <https://github.com/ipython/ipython/issues/808>`_: Ctrl+C during %reset confirm message crash Qtconsole
512 * `927 <https://github.com/ipython/ipython/issues/927>`_: Using return outside a function crashes ipython
512 * `927 <https://github.com/ipython/ipython/issues/927>`_: Using return outside a function crashes ipython
513 * `919 <https://github.com/ipython/ipython/issues/919>`_: Pop-up segfault when moving cursor out of qtconsole window
513 * `919 <https://github.com/ipython/ipython/issues/919>`_: Pop-up segfault when moving cursor out of qtconsole window
514 * `181 <https://github.com/ipython/ipython/issues/181>`_: cls command does not work on windows
514 * `181 <https://github.com/ipython/ipython/issues/181>`_: cls command does not work on windows
515 * `917 <https://github.com/ipython/ipython/issues/917>`_: documentation typos
515 * `917 <https://github.com/ipython/ipython/issues/917>`_: documentation typos
516 * `818 <https://github.com/ipython/ipython/issues/818>`_: %run does not work with non-ascii characeters in path
516 * `818 <https://github.com/ipython/ipython/issues/818>`_: %run does not work with non-ascii characeters in path
517 * `907 <https://github.com/ipython/ipython/issues/907>`_: Errors in custom completer functions can crash IPython
517 * `907 <https://github.com/ipython/ipython/issues/907>`_: Errors in custom completer functions can crash IPython
518 * `867 <https://github.com/ipython/ipython/issues/867>`_: doc: notebook password authentication howto
518 * `867 <https://github.com/ipython/ipython/issues/867>`_: doc: notebook password authentication howto
519 * `211 <https://github.com/ipython/ipython/issues/211>`_: paste command not working
519 * `211 <https://github.com/ipython/ipython/issues/211>`_: paste command not working
520 * `900 <https://github.com/ipython/ipython/issues/900>`_: Tab key should insert 4 spaces in qt console
520 * `900 <https://github.com/ipython/ipython/issues/900>`_: Tab key should insert 4 spaces in qt console
521 * `513 <https://github.com/ipython/ipython/issues/513>`_: [Qt console] cannot insert new lines into console functions using tab
521 * `513 <https://github.com/ipython/ipython/issues/513>`_: [Qt console] cannot insert new lines into console functions using tab
522 * `906 <https://github.com/ipython/ipython/issues/906>`_: qtconsoleapp 'parse_command_line' doen't like --existing anymore
522 * `906 <https://github.com/ipython/ipython/issues/906>`_: qtconsoleapp 'parse_command_line' doen't like --existing anymore
523 * `638 <https://github.com/ipython/ipython/issues/638>`_: Qt console --pylab=inline and getfigs(), etc.
523 * `638 <https://github.com/ipython/ipython/issues/638>`_: Qt console --pylab=inline and getfigs(), etc.
524 * `710 <https://github.com/ipython/ipython/issues/710>`_: unwanted unicode passed to args
524 * `710 <https://github.com/ipython/ipython/issues/710>`_: unwanted unicode passed to args
525 * `436 <https://github.com/ipython/ipython/issues/436>`_: Users should see tooltips for all buttons in the notebook UI
525 * `436 <https://github.com/ipython/ipython/issues/436>`_: Users should see tooltips for all buttons in the notebook UI
526 * `207 <https://github.com/ipython/ipython/issues/207>`_: ipython crashes if atexit handler raises exception
526 * `207 <https://github.com/ipython/ipython/issues/207>`_: ipython crashes if atexit handler raises exception
527 * `692 <https://github.com/ipython/ipython/issues/692>`_: use of Tracer() when debugging works but gives error messages
527 * `692 <https://github.com/ipython/ipython/issues/692>`_: use of Tracer() when debugging works but gives error messages
528 * `690 <https://github.com/ipython/ipython/issues/690>`_: debugger does not print error message by default in 0.11
528 * `690 <https://github.com/ipython/ipython/issues/690>`_: debugger does not print error message by default in 0.11
529 * `571 <https://github.com/ipython/ipython/issues/571>`_: history of multiline entries
529 * `571 <https://github.com/ipython/ipython/issues/571>`_: history of multiline entries
530 * `749 <https://github.com/ipython/ipython/issues/749>`_: IPython.parallel test failure under Windows 7 and XP
530 * `749 <https://github.com/ipython/ipython/issues/749>`_: IPython.parallel test failure under Windows 7 and XP
531 * `890 <https://github.com/ipython/ipython/issues/890>`_: ipclusterapp.py - helep
531 * `890 <https://github.com/ipython/ipython/issues/890>`_: ipclusterapp.py - helep
532 * `885 <https://github.com/ipython/ipython/issues/885>`_: `ws-hostname` alias not recognized by notebook
532 * `885 <https://github.com/ipython/ipython/issues/885>`_: `ws-hostname` alias not recognized by notebook
533 * `881 <https://github.com/ipython/ipython/issues/881>`_: Missing manual.pdf?
533 * `881 <https://github.com/ipython/ipython/issues/881>`_: Missing manual.pdf?
534 * `744 <https://github.com/ipython/ipython/issues/744>`_: cannot create notebook in offline mode if mathjax not installed
534 * `744 <https://github.com/ipython/ipython/issues/744>`_: cannot create notebook in offline mode if mathjax not installed
535 * `865 <https://github.com/ipython/ipython/issues/865>`_: Make tracebacks from %paste show the code
535 * `865 <https://github.com/ipython/ipython/issues/865>`_: Make tracebacks from %paste show the code
536 * `535 <https://github.com/ipython/ipython/issues/535>`_: exception unicode handling in %run is faulty in qtconsole
536 * `535 <https://github.com/ipython/ipython/issues/535>`_: exception unicode handling in %run is faulty in qtconsole
537 * `817 <https://github.com/ipython/ipython/issues/817>`_: iPython crashed
537 * `817 <https://github.com/ipython/ipython/issues/817>`_: iPython crashed
538 * `799 <https://github.com/ipython/ipython/issues/799>`_: %edit magic not working on windows xp in qtconsole
538 * `799 <https://github.com/ipython/ipython/issues/799>`_: %edit magic not working on windows xp in qtconsole
539 * `732 <https://github.com/ipython/ipython/issues/732>`_: QTConsole wrongly promotes the index of the input line on which user presses Enter
539 * `732 <https://github.com/ipython/ipython/issues/732>`_: QTConsole wrongly promotes the index of the input line on which user presses Enter
540 * `662 <https://github.com/ipython/ipython/issues/662>`_: ipython test failures on Mac OS X Lion
540 * `662 <https://github.com/ipython/ipython/issues/662>`_: ipython test failures on Mac OS X Lion
541 * `650 <https://github.com/ipython/ipython/issues/650>`_: Handle bad config files better
541 * `650 <https://github.com/ipython/ipython/issues/650>`_: Handle bad config files better
542 * `829 <https://github.com/ipython/ipython/issues/829>`_: We should not insert new lines after all print statements in the notebook
542 * `829 <https://github.com/ipython/ipython/issues/829>`_: We should not insert new lines after all print statements in the notebook
543 * `874 <https://github.com/ipython/ipython/issues/874>`_: ipython-qtconsole: pyzmq Version Comparison
543 * `874 <https://github.com/ipython/ipython/issues/874>`_: ipython-qtconsole: pyzmq Version Comparison
544 * `640 <https://github.com/ipython/ipython/issues/640>`_: matplotlib macosx windows don't respond in qtconsole
544 * `640 <https://github.com/ipython/ipython/issues/640>`_: matplotlib macosx windows don't respond in qtconsole
545 * `624 <https://github.com/ipython/ipython/issues/624>`_: ipython intermittently segfaults when figure is closed (Mac OS X)
545 * `624 <https://github.com/ipython/ipython/issues/624>`_: ipython intermittently segfaults when figure is closed (Mac OS X)
546 * `871 <https://github.com/ipython/ipython/issues/871>`_: Notebook crashes if a profile is used
546 * `871 <https://github.com/ipython/ipython/issues/871>`_: Notebook crashes if a profile is used
547 * `56 <https://github.com/ipython/ipython/issues/56>`_: Have %cpaste accept also Ctrl-D as a termination marker
547 * `56 <https://github.com/ipython/ipython/issues/56>`_: Have %cpaste accept also Ctrl-D as a termination marker
548 * `849 <https://github.com/ipython/ipython/issues/849>`_: Command line options to not override profile options
548 * `849 <https://github.com/ipython/ipython/issues/849>`_: Command line options to not override profile options
549 * `806 <https://github.com/ipython/ipython/issues/806>`_: Provide single-port connection to kernels
549 * `806 <https://github.com/ipython/ipython/issues/806>`_: Provide single-port connection to kernels
550 * `691 <https://github.com/ipython/ipython/issues/691>`_: [wishlist] Automatically find existing kernel
550 * `691 <https://github.com/ipython/ipython/issues/691>`_: [wishlist] Automatically find existing kernel
551 * `688 <https://github.com/ipython/ipython/issues/688>`_: local security vulnerability: all ports visible to any local user.
551 * `688 <https://github.com/ipython/ipython/issues/688>`_: local security vulnerability: all ports visible to any local user.
552 * `866 <https://github.com/ipython/ipython/issues/866>`_: DistributionNotFound on running ipython 0.11 on Windows XP x86
552 * `866 <https://github.com/ipython/ipython/issues/866>`_: DistributionNotFound on running ipython 0.11 on Windows XP x86
553 * `673 <https://github.com/ipython/ipython/issues/673>`_: raw_input appears to be round-robin for qtconsole
553 * `673 <https://github.com/ipython/ipython/issues/673>`_: raw_input appears to be round-robin for qtconsole
554 * `863 <https://github.com/ipython/ipython/issues/863>`_: Graceful degradation when home directory not writable
554 * `863 <https://github.com/ipython/ipython/issues/863>`_: Graceful degradation when home directory not writable
555 * `800 <https://github.com/ipython/ipython/issues/800>`_: Timing scripts with run -t -N <N> fails on report output
555 * `800 <https://github.com/ipython/ipython/issues/800>`_: Timing scripts with run -t -N <N> fails on report output
556 * `858 <https://github.com/ipython/ipython/issues/858>`_: Typing 'continue' makes ipython0.11 crash
556 * `858 <https://github.com/ipython/ipython/issues/858>`_: Typing 'continue' makes ipython0.11 crash
557 * `840 <https://github.com/ipython/ipython/issues/840>`_: all processes run on one CPU core
557 * `840 <https://github.com/ipython/ipython/issues/840>`_: all processes run on one CPU core
558 * `843 <https://github.com/ipython/ipython/issues/843>`_: "import braces" crashes ipython
558 * `843 <https://github.com/ipython/ipython/issues/843>`_: "import braces" crashes ipython
559 * `836 <https://github.com/ipython/ipython/issues/836>`_: Strange Output after IPython Install
559 * `836 <https://github.com/ipython/ipython/issues/836>`_: Strange Output after IPython Install
560 * `839 <https://github.com/ipython/ipython/issues/839>`_: Qtconsole segfaults when mouse exits window with active tooltip
560 * `839 <https://github.com/ipython/ipython/issues/839>`_: Qtconsole segfaults when mouse exits window with active tooltip
561 * `827 <https://github.com/ipython/ipython/issues/827>`_: Add support for checking several limits before running task on engine
561 * `827 <https://github.com/ipython/ipython/issues/827>`_: Add support for checking several limits before running task on engine
562 * `826 <https://github.com/ipython/ipython/issues/826>`_: Add support for creation of parallel task when no engine is running
562 * `826 <https://github.com/ipython/ipython/issues/826>`_: Add support for creation of parallel task when no engine is running
563 * `832 <https://github.com/ipython/ipython/issues/832>`_: Improve error message for %logstop
563 * `832 <https://github.com/ipython/ipython/issues/832>`_: Improve error message for %logstop
564 * `831 <https://github.com/ipython/ipython/issues/831>`_: %logstart in read-only directory forbid any further command
564 * `831 <https://github.com/ipython/ipython/issues/831>`_: %logstart in read-only directory forbid any further command
565 * `814 <https://github.com/ipython/ipython/issues/814>`_: ipython does not start -- DistributionNotFound
565 * `814 <https://github.com/ipython/ipython/issues/814>`_: ipython does not start -- DistributionNotFound
566 * `794 <https://github.com/ipython/ipython/issues/794>`_: Allow >1 controller per profile
566 * `794 <https://github.com/ipython/ipython/issues/794>`_: Allow >1 controller per profile
567 * `820 <https://github.com/ipython/ipython/issues/820>`_: Tab Completion feature
567 * `820 <https://github.com/ipython/ipython/issues/820>`_: Tab Completion feature
568 * `812 <https://github.com/ipython/ipython/issues/812>`_: Qt console crashes on Ubuntu 11.10
568 * `812 <https://github.com/ipython/ipython/issues/812>`_: Qt console crashes on Ubuntu 11.10
569 * `816 <https://github.com/ipython/ipython/issues/816>`_: Import error using Python 2.7 and dateutil2.0 No module named _thread
569 * `816 <https://github.com/ipython/ipython/issues/816>`_: Import error using Python 2.7 and dateutil2.0 No module named _thread
570 * `756 <https://github.com/ipython/ipython/issues/756>`_: qtconsole Windows fails to print error message for '%run nonexistent_file'
570 * `756 <https://github.com/ipython/ipython/issues/756>`_: qtconsole Windows fails to print error message for '%run nonexistent_file'
571 * `651 <https://github.com/ipython/ipython/issues/651>`_: Completion doesn't work on element of a list
571 * `651 <https://github.com/ipython/ipython/issues/651>`_: Completion doesn't work on element of a list
572 * `617 <https://github.com/ipython/ipython/issues/617>`_: [qtconsole] %hist doesn't show anything in qtconsole
572 * `617 <https://github.com/ipython/ipython/issues/617>`_: [qtconsole] %hist doesn't show anything in qtconsole
573 * `786 <https://github.com/ipython/ipython/issues/786>`_: from __future__ import unicode_literals does not work
573 * `786 <https://github.com/ipython/ipython/issues/786>`_: from __future__ import unicode_literals does not work
574 * `779 <https://github.com/ipython/ipython/issues/779>`_: Using irunner from virtual evn uses systemwide ipython
574 * `779 <https://github.com/ipython/ipython/issues/779>`_: Using irunner from virtual evn uses systemwide ipython
575 * `768 <https://github.com/ipython/ipython/issues/768>`_: codepage handling of output from scripts and shellcommands are not handled properly by qtconsole
575 * `768 <https://github.com/ipython/ipython/issues/768>`_: codepage handling of output from scripts and shellcommands are not handled properly by qtconsole
576 * `785 <https://github.com/ipython/ipython/issues/785>`_: Don't strip leading whitespace in repr() in notebook
576 * `785 <https://github.com/ipython/ipython/issues/785>`_: Don't strip leading whitespace in repr() in notebook
577 * `737 <https://github.com/ipython/ipython/issues/737>`_: in pickleshare.py line52 should be "if not os.path.isdir(self.root):"?
577 * `737 <https://github.com/ipython/ipython/issues/737>`_: in pickleshare.py line52 should be "if not os.path.isdir(self.root):"?
578 * `738 <https://github.com/ipython/ipython/issues/738>`_: in ipthon_win_post_install.py line 38
578 * `738 <https://github.com/ipython/ipython/issues/738>`_: in ipthon_win_post_install.py line 38
579 * `777 <https://github.com/ipython/ipython/issues/777>`_: print(…, sep=…) raises SyntaxError
579 * `777 <https://github.com/ipython/ipython/issues/777>`_: print(…, sep=…) raises SyntaxError
580 * `728 <https://github.com/ipython/ipython/issues/728>`_: ipcontroller crash with MPI
580 * `728 <https://github.com/ipython/ipython/issues/728>`_: ipcontroller crash with MPI
581 * `780 <https://github.com/ipython/ipython/issues/780>`_: qtconsole Out value prints before the print statements that precede it
581 * `780 <https://github.com/ipython/ipython/issues/780>`_: qtconsole Out value prints before the print statements that precede it
582 * `632 <https://github.com/ipython/ipython/issues/632>`_: IPython Crash Report (0.10.2)
582 * `632 <https://github.com/ipython/ipython/issues/632>`_: IPython Crash Report (0.10.2)
583 * `253 <https://github.com/ipython/ipython/issues/253>`_: Unable to install ipython on windows
583 * `253 <https://github.com/ipython/ipython/issues/253>`_: Unable to install ipython on windows
584 * `80 <https://github.com/ipython/ipython/issues/80>`_: Split IPClusterApp into multiple Application subclasses for each subcommand
584 * `80 <https://github.com/ipython/ipython/issues/80>`_: Split IPClusterApp into multiple Application subclasses for each subcommand
585 * `34 <https://github.com/ipython/ipython/issues/34>`_: non-blocking pendingResult partial results
585 * `34 <https://github.com/ipython/ipython/issues/34>`_: non-blocking pendingResult partial results
586 * `739 <https://github.com/ipython/ipython/issues/739>`_: Tests fail if tornado not installed
586 * `739 <https://github.com/ipython/ipython/issues/739>`_: Tests fail if tornado not installed
587 * `719 <https://github.com/ipython/ipython/issues/719>`_: Better support Pypy
587 * `719 <https://github.com/ipython/ipython/issues/719>`_: Better support Pypy
588 * `667 <https://github.com/ipython/ipython/issues/667>`_: qtconsole problem with default pylab profile
588 * `667 <https://github.com/ipython/ipython/issues/667>`_: qtconsole problem with default pylab profile
589 * `661 <https://github.com/ipython/ipython/issues/661>`_: ipythonrc referenced in magic command in 0.11
589 * `661 <https://github.com/ipython/ipython/issues/661>`_: ipythonrc referenced in magic command in 0.11
590 * `665 <https://github.com/ipython/ipython/issues/665>`_: Source introspection with ?? is broken
590 * `665 <https://github.com/ipython/ipython/issues/665>`_: Source introspection with ?? is broken
591 * `724 <https://github.com/ipython/ipython/issues/724>`_: crash - ipython qtconsole, %quickref
591 * `724 <https://github.com/ipython/ipython/issues/724>`_: crash - ipython qtconsole, %quickref
592 * `655 <https://github.com/ipython/ipython/issues/655>`_: ipython with qtconsole crashes
592 * `655 <https://github.com/ipython/ipython/issues/655>`_: ipython with qtconsole crashes
593 * `593 <https://github.com/ipython/ipython/issues/593>`_: HTML Notebook Prompt can be deleted . . .
593 * `593 <https://github.com/ipython/ipython/issues/593>`_: HTML Notebook Prompt can be deleted . . .
594 * `563 <https://github.com/ipython/ipython/issues/563>`_: use argparse instead of kvloader for flags&aliases
594 * `563 <https://github.com/ipython/ipython/issues/563>`_: use argparse instead of kvloader for flags&aliases
595 * `751 <https://github.com/ipython/ipython/issues/751>`_: Tornado version greater than 2.0 needed for firefox 6
595 * `751 <https://github.com/ipython/ipython/issues/751>`_: Tornado version greater than 2.0 needed for firefox 6
596 * `720 <https://github.com/ipython/ipython/issues/720>`_: Crash report when importing easter egg
596 * `720 <https://github.com/ipython/ipython/issues/720>`_: Crash report when importing easter egg
597 * `740 <https://github.com/ipython/ipython/issues/740>`_: Ctrl-Enter clears line in notebook
597 * `740 <https://github.com/ipython/ipython/issues/740>`_: Ctrl-Enter clears line in notebook
598 * `772 <https://github.com/ipython/ipython/issues/772>`_: ipengine fails on Windows with "XXX lineno: 355, opcode: 0"
598 * `772 <https://github.com/ipython/ipython/issues/772>`_: ipengine fails on Windows with "XXX lineno: 355, opcode: 0"
599 * `771 <https://github.com/ipython/ipython/issues/771>`_: Add python 3 tag to setup.py
599 * `771 <https://github.com/ipython/ipython/issues/771>`_: Add python 3 tag to setup.py
600 * `767 <https://github.com/ipython/ipython/issues/767>`_: non-ascii in __doc__ string crashes qtconsole kernel when showing tooltip
600 * `767 <https://github.com/ipython/ipython/issues/767>`_: non-ascii in __doc__ string crashes qtconsole kernel when showing tooltip
601 * `733 <https://github.com/ipython/ipython/issues/733>`_: In Windows, %run fails to strip quotes from filename
601 * `733 <https://github.com/ipython/ipython/issues/733>`_: In Windows, %run fails to strip quotes from filename
602 * `721 <https://github.com/ipython/ipython/issues/721>`_: no completion in emacs by ipython(ipython.el)
602 * `721 <https://github.com/ipython/ipython/issues/721>`_: no completion in emacs by ipython(ipython.el)
603 * `669 <https://github.com/ipython/ipython/issues/669>`_: Do not accept an ipython_dir that's not writeable
603 * `669 <https://github.com/ipython/ipython/issues/669>`_: Do not accept an ipython_dir that's not writeable
604 * `711 <https://github.com/ipython/ipython/issues/711>`_: segfault on mac os x
604 * `711 <https://github.com/ipython/ipython/issues/711>`_: segfault on mac os x
605 * `500 <https://github.com/ipython/ipython/issues/500>`_: "RuntimeError: Cannot change input buffer during execution" in console_widget.py
605 * `500 <https://github.com/ipython/ipython/issues/500>`_: "RuntimeError: Cannot change input buffer during execution" in console_widget.py
606 * `707 <https://github.com/ipython/ipython/issues/707>`_: Copy and paste keyboard shortcuts do not work in Qt Console on OS X
606 * `707 <https://github.com/ipython/ipython/issues/707>`_: Copy and paste keyboard shortcuts do not work in Qt Console on OS X
607 * `478 <https://github.com/ipython/ipython/issues/478>`_: PyZMQ's use of memoryviews breaks reconstruction of numpy arrays
607 * `478 <https://github.com/ipython/ipython/issues/478>`_: PyZMQ's use of memoryviews breaks reconstruction of numpy arrays
608 * `694 <https://github.com/ipython/ipython/issues/694>`_: Turning off callout tips in qtconsole
608 * `694 <https://github.com/ipython/ipython/issues/694>`_: Turning off callout tips in qtconsole
609 * `704 <https://github.com/ipython/ipython/issues/704>`_: return kills IPython
609 * `704 <https://github.com/ipython/ipython/issues/704>`_: return kills IPython
610 * `442 <https://github.com/ipython/ipython/issues/442>`_: Users should have intelligent autoindenting in the notebook
610 * `442 <https://github.com/ipython/ipython/issues/442>`_: Users should have intelligent autoindenting in the notebook
611 * `615 <https://github.com/ipython/ipython/issues/615>`_: Wireframe and implement a project dashboard page
611 * `615 <https://github.com/ipython/ipython/issues/615>`_: Wireframe and implement a project dashboard page
612 * `614 <https://github.com/ipython/ipython/issues/614>`_: Wireframe and implement a notebook dashboard page
612 * `614 <https://github.com/ipython/ipython/issues/614>`_: Wireframe and implement a notebook dashboard page
613 * `606 <https://github.com/ipython/ipython/issues/606>`_: Users should be able to use the notebook to import/export a notebook to .py or .rst
613 * `606 <https://github.com/ipython/ipython/issues/606>`_: Users should be able to use the notebook to import/export a notebook to .py or .rst
614 * `604 <https://github.com/ipython/ipython/issues/604>`_: A user should be able to leave a kernel running in the notebook and reconnect
614 * `604 <https://github.com/ipython/ipython/issues/604>`_: A user should be able to leave a kernel running in the notebook and reconnect
615 * `298 <https://github.com/ipython/ipython/issues/298>`_: Users should be able to save a notebook and then later reload it
615 * `298 <https://github.com/ipython/ipython/issues/298>`_: Users should be able to save a notebook and then later reload it
616 * `649 <https://github.com/ipython/ipython/issues/649>`_: ipython qtconsole (v0.11): setting "c.IPythonWidget.in_prompt = '>>> ' crashes
616 * `649 <https://github.com/ipython/ipython/issues/649>`_: ipython qtconsole (v0.11): setting "c.IPythonWidget.in_prompt = '>>> ' crashes
617 * `672 <https://github.com/ipython/ipython/issues/672>`_: What happened to Exit?
617 * `672 <https://github.com/ipython/ipython/issues/672>`_: What happened to Exit?
618 * `658 <https://github.com/ipython/ipython/issues/658>`_: Put the InteractiveShellApp section first in the auto-generated config files
618 * `658 <https://github.com/ipython/ipython/issues/658>`_: Put the InteractiveShellApp section first in the auto-generated config files
619 * `656 <https://github.com/ipython/ipython/issues/656>`_: [suggestion] dependency checking for pyqt for Windows installer
619 * `656 <https://github.com/ipython/ipython/issues/656>`_: [suggestion] dependency checking for pyqt for Windows installer
620 * `654 <https://github.com/ipython/ipython/issues/654>`_: broken documentation link on download page
620 * `654 <https://github.com/ipython/ipython/issues/654>`_: broken documentation link on download page
621 * `653 <https://github.com/ipython/ipython/issues/653>`_: Test failures in IPython.parallel
621 * `653 <https://github.com/ipython/ipython/issues/653>`_: Test failures in IPython.parallel
@@ -1,1784 +1,1784 b''
1 .. _issues_list_100:
1 .. _issues_list_100:
2
2
3 Issues closed in the 1.0 development cycle
3 Issues closed in the 1.0 development cycle
4 ==========================================
4 ==========================================
5
5
6 Issues closed in 1.1
6 Issues closed in 1.1
7 --------------------
7 --------------------
8
8
9 GitHub stats for 2013/08/08 - 2013/09/09 (since 1.0)
9 GitHub stats for 2013/08/08 - 2013/09/09 (since 1.0)
10
10
11 These lists are automatically generated, and may be incomplete or contain duplicates.
11 These lists are automatically generated, and may be incomplete or contain duplicates.
12
12
13 The following 25 authors contributed 337 commits.
13 The following 25 authors contributed 337 commits.
14
14
15 * Benjamin Ragan-Kelley
15 * Benjamin Ragan-Kelley
16 * Bing Xia
16 * Bing Xia
17 * Bradley M. Froehle
17 * Bradley M. Froehle
18 * Brian E. Granger
18 * Brian E. Granger
19 * DamiΓ‘n Avila
19 * DamiΓ‘n Avila
20 * dhirschfeld
20 * dhirschfeld
21 * Dražen Lučanin
21 * Dražen Lučanin
22 * gmbecker
22 * gmbecker
23 * Jake Vanderplas
23 * Jake Vanderplas
24 * Jason Grout
24 * Jason Grout
25 * Jonathan Frederic
25 * Jonathan Frederic
26 * Kevin Burke
26 * Kevin Burke
27 * Kyle Kelley
27 * Kyle Kelley
28 * Matt Henderson
28 * Matt Henderson
29 * Matthew Brett
29 * Matthew Brett
30 * Matthias Bussonnier
30 * Matthias Bussonnier
31 * Pankaj Pandey
31 * Pankaj Pandey
32 * Paul Ivanov
32 * Paul Ivanov
33 * rossant
33 * rossant
34 * Samuel Ainsworth
34 * Samuel Ainsworth
35 * Stephan Rave
35 * Stephan Rave
36 * stonebig
36 * stonebig
37 * Thomas Kluyver
37 * Thomas Kluyver
38 * Yaroslav Halchenko
38 * Yaroslav Halchenko
39 * Zachary Sailer
39 * Zachary Sailer
40
40
41
41
42 We closed a total of 76 issues, 58 pull requests and 18 regular issues;
42 We closed a total of 76 issues, 58 pull requests and 18 regular issues;
43 this is the full list (generated with the script :file:`tools/github_stats.py`):
43 this is the full list (generated with the script :file:`tools/github_stats.py`):
44
44
45 Pull Requests (58):
45 Pull Requests (58):
46
46
47 * :ghpull:`4188`: Allow user_ns trait to be None
47 * :ghpull:`4188`: Allow user_ns trait to be None
48 * :ghpull:`4189`: always fire LOCAL_IPS.extend(PUBLIC_IPS)
48 * :ghpull:`4189`: always fire LOCAL_IPS.extend(PUBLIC_IPS)
49 * :ghpull:`4174`: various issues in markdown and rst templates
49 * :ghpull:`4174`: various issues in markdown and rst templates
50 * :ghpull:`4178`: add missing data_javascript
50 * :ghpull:`4178`: add missing data_javascript
51 * :ghpull:`4181`: nbconvert: Fix, sphinx template not removing new lines from headers
51 * :ghpull:`4181`: nbconvert: Fix, sphinx template not removing new lines from headers
52 * :ghpull:`4043`: don't 'restore_bytes' in from_JSON
52 * :ghpull:`4043`: don't 'restore_bytes' in from_JSON
53 * :ghpull:`4163`: Fix for incorrect default encoding on Windows.
53 * :ghpull:`4163`: Fix for incorrect default encoding on Windows.
54 * :ghpull:`4136`: catch javascript errors in any output
54 * :ghpull:`4136`: catch javascript errors in any output
55 * :ghpull:`4171`: add nbconvert config file when creating profiles
55 * :ghpull:`4171`: add nbconvert config file when creating profiles
56 * :ghpull:`4125`: Basic exercise of `ipython [subcommand] -h` and help-all
56 * :ghpull:`4125`: Basic exercise of `ipython [subcommand] -h` and help-all
57 * :ghpull:`4085`: nbconvert: Fix sphinx preprocessor date format string for Windows
57 * :ghpull:`4085`: nbconvert: Fix sphinx preprocessor date format string for Windows
58 * :ghpull:`4159`: don't split `.cell` and `div.cell` CSS
58 * :ghpull:`4159`: don't split `.cell` and `div.cell` CSS
59 * :ghpull:`4158`: generate choices for `--gui` configurable from real mapping
59 * :ghpull:`4158`: generate choices for `--gui` configurable from real mapping
60 * :ghpull:`4065`: do not include specific css in embedable one
60 * :ghpull:`4065`: do not include specific css in embedable one
61 * :ghpull:`4092`: nbconvert: Fix for unicode html headers, Windows + Python 2.x
61 * :ghpull:`4092`: nbconvert: Fix for unicode html headers, Windows + Python 2.x
62 * :ghpull:`4074`: close Client sockets if connection fails
62 * :ghpull:`4074`: close Client sockets if connection fails
63 * :ghpull:`4064`: Store default codemirror mode in only 1 place
63 * :ghpull:`4064`: Store default codemirror mode in only 1 place
64 * :ghpull:`4104`: Add way to install MathJax to a particular profile
64 * :ghpull:`4104`: Add way to install MathJax to a particular profile
65 * :ghpull:`4144`: help_end transformer shouldn't pick up ? in multiline string
65 * :ghpull:`4144`: help_end transformer shouldn't pick up ? in multiline string
66 * :ghpull:`4143`: update example custom.js
66 * :ghpull:`4143`: update example custom.js
67 * :ghpull:`4142`: DOC: unwrap openssl line in public_server doc
67 * :ghpull:`4142`: DOC: unwrap openssl line in public_server doc
68 * :ghpull:`4141`: add files with a separate `add` call in backport_pr
68 * :ghpull:`4141`: add files with a separate `add` call in backport_pr
69 * :ghpull:`4137`: Restore autorestore option for storemagic
69 * :ghpull:`4137`: Restore autorestore option for storemagic
70 * :ghpull:`4098`: pass profile-dir instead of profile name to Kernel
70 * :ghpull:`4098`: pass profile-dir instead of profile name to Kernel
71 * :ghpull:`4120`: support `input` in Python 2 kernels
71 * :ghpull:`4120`: support `input` in Python 2 kernels
72 * :ghpull:`4088`: nbconvert: Fix coalescestreams line with incorrect nesting causing strange behavior
72 * :ghpull:`4088`: nbconvert: Fix coalescestreams line with incorrect nesting causing strange behavior
73 * :ghpull:`4060`: only strip continuation prompts if regular prompts seen first
73 * :ghpull:`4060`: only strip continuation prompts if regular prompts seen first
74 * :ghpull:`4132`: Fixed name error bug in function safe_unicode in module py3compat.
74 * :ghpull:`4132`: Fixed name error bug in function safe_unicode in module py3compat.
75 * :ghpull:`4121`: move test_kernel from IPython.zmq to IPython.kernel
75 * :ghpull:`4121`: move test_kernel from IPython.zmq to IPython.kernel
76 * :ghpull:`4118`: ZMQ heartbeat channel: catch EINTR exceptions and continue.
76 * :ghpull:`4118`: ZMQ heartbeat channel: catch EINTR exceptions and continue.
77 * :ghpull:`4054`: use unicode for HTML export
77 * :ghpull:`4054`: use unicode for HTML export
78 * :ghpull:`4106`: fix a couple of default block values
78 * :ghpull:`4106`: fix a couple of default block values
79 * :ghpull:`4115`: Update docs on declaring a magic function
79 * :ghpull:`4115`: Update docs on declaring a magic function
80 * :ghpull:`4101`: restore accidentally removed EngineError
80 * :ghpull:`4101`: restore accidentally removed EngineError
81 * :ghpull:`4096`: minor docs changes
81 * :ghpull:`4096`: minor docs changes
82 * :ghpull:`4056`: respect `pylab_import_all` when `--pylab` specified at the command-line
82 * :ghpull:`4056`: respect `pylab_import_all` when `--pylab` specified at the command-line
83 * :ghpull:`4091`: Make Qt console banner configurable
83 * :ghpull:`4091`: Make Qt console banner configurable
84 * :ghpull:`4086`: fix missing errno import
84 * :ghpull:`4086`: fix missing errno import
85 * :ghpull:`4030`: exclude `.git` in MANIFEST.in
85 * :ghpull:`4030`: exclude `.git` in MANIFEST.in
86 * :ghpull:`4047`: Use istype() when checking if canned object is a dict
86 * :ghpull:`4047`: Use istype() when checking if canned object is a dict
87 * :ghpull:`4031`: don't close_fds on Windows
87 * :ghpull:`4031`: don't close_fds on Windows
88 * :ghpull:`4029`: bson.Binary moved
88 * :ghpull:`4029`: bson.Binary moved
89 * :ghpull:`4035`: Fixed custom jinja2 templates being ignored when setting template_path
89 * :ghpull:`4035`: Fixed custom jinja2 templates being ignored when setting template_path
90 * :ghpull:`4026`: small doc fix in nbconvert
90 * :ghpull:`4026`: small doc fix in nbconvert
91 * :ghpull:`4016`: Fix IPython.start_* functions
91 * :ghpull:`4016`: Fix IPython.start_* functions
92 * :ghpull:`4021`: Fix parallel.client.View map() on numpy arrays
92 * :ghpull:`4021`: Fix parallel.client.View map() on numpy arrays
93 * :ghpull:`4022`: DOC: fix links to matplotlib, notebook docs
93 * :ghpull:`4022`: DOC: fix links to matplotlib, notebook docs
94 * :ghpull:`4018`: Fix warning when running IPython.kernel tests
94 * :ghpull:`4018`: Fix warning when running IPython.kernel tests
95 * :ghpull:`4019`: Test skipping without unicode paths
95 * :ghpull:`4019`: Test skipping without unicode paths
96 * :ghpull:`4008`: Transform code before %prun/%%prun runs
96 * :ghpull:`4008`: Transform code before %prun/%%prun runs
97 * :ghpull:`4014`: Fix typo in ipapp
97 * :ghpull:`4014`: Fix typo in ipapp
98 * :ghpull:`3987`: get files list in backport_pr
98 * :ghpull:`3987`: get files list in backport_pr
99 * :ghpull:`3974`: nbconvert: Fix app tests on Window7 w/ Python 3.3
99 * :ghpull:`3974`: nbconvert: Fix app tests on Window7 w/ Python 3.3
100 * :ghpull:`3978`: fix `--existing` with non-localhost IP
100 * :ghpull:`3978`: fix `--existing` with non-localhost IP
101 * :ghpull:`3939`: minor checkpoint cleanup
101 * :ghpull:`3939`: minor checkpoint cleanup
102 * :ghpull:`3981`: BF: fix nbconvert rst input prompt spacing
102 * :ghpull:`3981`: BF: fix nbconvert rst input prompt spacing
103 * :ghpull:`3960`: Don't make sphinx a dependency for importing nbconvert
103 * :ghpull:`3960`: Don't make sphinx a dependency for importing nbconvert
104 * :ghpull:`3973`: logging.Formatter is not new-style in 2.6
104 * :ghpull:`3973`: logging.Formatter is not new-style in 2.6
105
105
106 Issues (18):
106 Issues (18):
107
107
108 * :ghissue:`4024`: nbconvert markdown issues
108 * :ghissue:`4024`: nbconvert markdown issues
109 * :ghissue:`4095`: Catch js error in append html in stream/pyerr
109 * :ghissue:`4095`: Catch js error in append html in stream/pyerr
110 * :ghissue:`4156`: Specifying --gui=tk at the command line
110 * :ghissue:`4156`: Specifying --gui=tk at the command line
111 * :ghissue:`3818`: nbconvert can't handle Heading with Chinese characters on Japanese Windows OS.
111 * :ghissue:`3818`: nbconvert can't handle Heading with Chinese characters on Japanese Windows OS.
112 * :ghissue:`4134`: multi-line parser fails on ''' in comment, qtconsole and notebook.
112 * :ghissue:`4134`: multi-line parser fails on ''' in comment, qtconsole and notebook.
113 * :ghissue:`3998`: sample custom.js needs to be updated
113 * :ghissue:`3998`: sample custom.js needs to be updated
114 * :ghissue:`4078`: StoreMagic.autorestore not working in 1.0.0
114 * :ghissue:`4078`: StoreMagic.autorestore not working in 1.0.0
115 * :ghissue:`3990`: Buitlin `input` doesn't work over zmq
115 * :ghissue:`3990`: Buitlin `input` doesn't work over zmq
116 * :ghissue:`4015`: nbconvert fails to convert all the content of a notebook
116 * :ghissue:`4015`: nbconvert fails to convert all the content of a notebook
117 * :ghissue:`4059`: Issues with Ellipsis literal in Python 3
117 * :ghissue:`4059`: Issues with Ellipsis literal in Python 3
118 * :ghissue:`4103`: Wrong default argument of DirectView.clear
118 * :ghissue:`4103`: Wrong default argument of DirectView.clear
119 * :ghissue:`4100`: parallel.client.client references undefined error.EngineError
119 * :ghissue:`4100`: parallel.client.client references undefined error.EngineError
120 * :ghissue:`4005`: IPython.start_kernel doesn't work.
120 * :ghissue:`4005`: IPython.start_kernel doesn't work.
121 * :ghissue:`4020`: IPython parallel map fails on numpy arrays
121 * :ghissue:`4020`: IPython parallel map fails on numpy arrays
122 * :ghissue:`3945`: nbconvert: commandline tests fail Win7x64 Py3.3
122 * :ghissue:`3945`: nbconvert: commandline tests fail Win7x64 Py3.3
123 * :ghissue:`3977`: unable to complete remote connections for two-process
123 * :ghissue:`3977`: unable to complete remote connections for two-process
124 * :ghissue:`3980`: nbconvert rst output lacks needed blank lines
124 * :ghissue:`3980`: nbconvert rst output lacks needed blank lines
125 * :ghissue:`3968`: TypeError: super() argument 1 must be type, not classobj (Python 2.6.6)
125 * :ghissue:`3968`: TypeError: super() argument 1 must be type, not classobj (Python 2.6.6)
126
126
127 Issues closed in 1.0
127 Issues closed in 1.0
128 --------------------
128 --------------------
129
129
130 GitHub stats for 2012/06/30 - 2013/08/08 (since 0.13)
130 GitHub stats for 2012/06/30 - 2013/08/08 (since 0.13)
131
131
132 These lists are automatically generated, and may be incomplete or contain duplicates.
132 These lists are automatically generated, and may be incomplete or contain duplicates.
133
133
134 The following 155 authors contributed 4258 commits.
134 The following 155 authors contributed 4258 commits.
135
135
136 * Aaron Meurer
136 * Aaron Meurer
137 * Adam Davis
137 * Adam Davis
138 * Ahmet Bakan
138 * Ahmet Bakan
139 * Alberto Valverde
139 * Alberto Valverde
140 * Allen Riddell
140 * Allen Riddell
141 * Anders HovmΓΆller
141 * Anders HovmΓΆller
142 * Andrea Bedini
142 * Andrea Bedini
143 * Andrew Spiers
143 * Andrew Spiers
144 * Andrew Vandever
144 * Andrew Vandever
145 * Anthony Scopatz
145 * Anthony Scopatz
146 * Anton Akhmerov
146 * Anton Akhmerov
147 * Anton I. Sipos
147 * Anton I. Sipos
148 * Antony Lee
148 * Antony Lee
149 * Aron Ahmadia
149 * Aron Ahmadia
150 * Benedikt Sauer
150 * Benedikt Sauer
151 * Benjamin Jones
151 * Benjamin Jones
152 * Benjamin Ragan-Kelley
152 * Benjamin Ragan-Kelley
153 * Benjie Chen
153 * Benjie Chen
154 * Boris de Laage
154 * Boris de Laage
155 * Brad Reisfeld
155 * Brad Reisfeld
156 * Bradley M. Froehle
156 * Bradley M. Froehle
157 * Brian E. Granger
157 * Brian E. Granger
158 * Cameron Bates
158 * Cameron Bates
159 * Cavendish McKay
159 * Cavendish McKay
160 * chapmanb
160 * chapmanb
161 * Chris Beaumont
161 * Chris Beaumont
162 * Chris Laumann
162 * Chris Laumann
163 * Christoph Gohlke
163 * Christoph Gohlke
164 * codebraker
164 * codebraker
165 * codespaced
165 * codespaced
166 * Corran Webster
166 * Corran Webster
167 * DamianHeard
167 * DamianHeard
168 * DamiΓ‘n Avila
168 * DamiΓ‘n Avila
169 * Dan Kilman
169 * Dan Kilman
170 * Dan McDougall
170 * Dan McDougall
171 * Danny Staple
171 * Danny Staple
172 * David Hirschfeld
172 * David Hirschfeld
173 * David P. Sanders
173 * David P. Sanders
174 * David Warde-Farley
174 * David Warde-Farley
175 * David Wolever
175 * David Wolever
176 * David Wyde
176 * David Wyde
177 * debjan
177 * debjan
178 * Diane Trout
178 * Diane Trout
179 * dkua
179 * dkua
180 * Dominik Dabrowski
180 * Dominik Dabrowski
181 * Donald Curtis
181 * Donald Curtis
182 * Dražen Lučanin
182 * Dražen Lučanin
183 * drevicko
183 * drevicko
184 * Eric O. LEBIGOT
184 * Eric O. LEBIGOT
185 * Erik M. Bray
185 * Erik M. Bray
186 * Erik Tollerud
186 * Erik Tollerud
187 * Eugene Van den Bulke
187 * Eugene Van den Bulke
188 * Evan Patterson
188 * Evan Patterson
189 * Fernando Perez
189 * Fernando Perez
190 * Francesco Montesano
190 * Francesco Montesano
191 * Frank Murphy
191 * Frank Murphy
192 * Greg Caporaso
192 * Greg Caporaso
193 * Guy Haskin Fernald
193 * Guy Haskin Fernald
194 * guziy
194 * guziy
195 * Hans Meine
195 * Hans Meine
196 * Harry Moreno
196 * Harry Moreno
197 * henryiii
197 * henryiii
198 * Ivan Djokic
198 * Ivan Djokic
199 * Jack Feser
199 * Jack Feser
200 * Jake Vanderplas
200 * Jake Vanderplas
201 * jakobgager
201 * jakobgager
202 * James Booth
202 * James Booth
203 * Jan Schulz
203 * Jan Schulz
204 * Jason Grout
204 * Jason Grout
205 * Jeff Knisley
205 * Jeff Knisley
206 * Jens Hedegaard Nielsen
206 * Jens Hedegaard Nielsen
207 * jeremiahbuddha
207 * jeremiahbuddha
208 * Jerry Fowler
208 * Jerry Fowler
209 * Jessica B. Hamrick
209 * Jessica B. Hamrick
210 * Jez Ng
210 * Jez Ng
211 * John Zwinck
211 * John Zwinck
212 * Jonathan Frederic
212 * Jonathan Frederic
213 * Jonathan Taylor
213 * Jonathan Taylor
214 * Joon Ro
214 * Joon Ro
215 * Joseph Lansdowne
215 * Joseph Lansdowne
216 * Juergen Hasch
216 * Juergen Hasch
217 * Julian Taylor
217 * Julian Taylor
218 * Jussi Sainio
218 * Jussi Sainio
219 * JΓΆrgen Stenarson
219 * JΓΆrgen Stenarson
220 * kevin
220 * kevin
221 * klonuo
221 * klonuo
222 * Konrad Hinsen
222 * Konrad Hinsen
223 * Kyle Kelley
223 * Kyle Kelley
224 * Lars Solberg
224 * Lars Solberg
225 * Lessandro Mariano
225 * Lessandro Mariano
226 * Mark Sienkiewicz at STScI
226 * Mark Sienkiewicz at STScI
227 * Martijn Vermaat
227 * Martijn Vermaat
228 * Martin Spacek
228 * Martin Spacek
229 * Matthias Bussonnier
229 * Matthias Bussonnier
230 * Maxim Grechkin
230 * Maxim Grechkin
231 * Maximilian Albert
231 * Maximilian Albert
232 * MercuryRising
232 * MercuryRising
233 * Michael Droettboom
233 * Michael Droettboom
234 * Michael Shuffett
234 * Michael Shuffett
235 * MichaΕ‚ GΓ³rny
235 * MichaΕ‚ GΓ³rny
236 * Mikhail Korobov
236 * Mikhail Korobov
237 * mr.Shu
237 * mr.Shu
238 * Nathan Goldbaum
238 * Nathan Goldbaum
239 * ocefpaf
239 * ocefpaf
240 * Ohad Ravid
240 * Ohad Ravid
241 * Olivier Grisel
241 * Olivier Grisel
242 * Olivier Verdier
242 * Olivier Verdier
243 * Owen Healy
243 * Owen Healy
244 * Pankaj Pandey
244 * Pankaj Pandey
245 * Paul Ivanov
245 * Paul Ivanov
246 * Pawel Jasinski
246 * Pawel Jasinski
247 * Pietro Berkes
247 * Pietro Berkes
248 * Piti Ongmongkolkul
248 * Piti Ongmongkolkul
249 * Puneeth Chaganti
249 * Puneeth Chaganti
250 * Rich Wareham
250 * Rich Wareham
251 * Richard Everson
251 * Richard Everson
252 * Rick Lupton
252 * Rick Lupton
253 * Rob Young
253 * Rob Young
254 * Robert Kern
254 * Robert Kern
255 * Robert Marchman
255 * Robert Marchman
256 * Robert McGibbon
256 * Robert McGibbon
257 * Rui Pereira
257 * Rui Pereira
258 * Rustam Safin
258 * Rustam Safin
259 * Ryan May
259 * Ryan May
260 * s8weber
260 * s8weber
261 * Samuel Ainsworth
261 * Samuel Ainsworth
262 * Sean Vig
262 * Sean Vig
263 * Siyu Zhang
263 * Siyu Zhang
264 * Skylar Saveland
264 * Skylar Saveland
265 * slojo404
265 * slojo404
266 * smithj1
266 * smithj1
267 * Stefan Karpinski
267 * Stefan Karpinski
268 * Stefan van der Walt
268 * Stefan van der Walt
269 * Steven Silvester
269 * Steven Silvester
270 * Takafumi Arakaki
270 * Takafumi Arakaki
271 * Takeshi Kanmae
271 * Takeshi Kanmae
272 * tcmulcahy
272 * tcmulcahy
273 * teegaar
273 * teegaar
274 * Thomas Kluyver
274 * Thomas Kluyver
275 * Thomas Robitaille
275 * Thomas Robitaille
276 * Thomas Spura
276 * Thomas Spura
277 * Thomas Weißschuh
277 * Thomas Weißschuh
278 * Timothy O'Donnell
278 * Timothy O'Donnell
279 * Tom Dimiduk
279 * Tom Dimiduk
280 * ugurthemaster
280 * ugurthemaster
281 * urielshaolin
281 * urielshaolin
282 * v923z
282 * v923z
283 * Valentin Haenel
283 * Valentin Haenel
284 * Victor Zverovich
284 * Victor Zverovich
285 * W. Trevor King
285 * W. Trevor King
286 * y-p
286 * y-p
287 * Yoav Ram
287 * Yoav Ram
288 * Zbigniew JΔ™drzejewski-Szmek
288 * Zbigniew JΔ™drzejewski-Szmek
289 * ZoltΓ‘n VΓΆrΓΆs
289 * ZoltΓ‘n VΓΆrΓΆs
290
290
291
291
292 We closed a total of 1484 issues, 793 pull requests and 691 regular issues;
292 We closed a total of 1484 issues, 793 pull requests and 691 regular issues;
293 this is the full list (generated with the script
293 this is the full list (generated with the script
294 :file:`tools/github_stats.py`):
294 :file:`tools/github_stats.py`):
295
295
296 Pull Requests (793):
296 Pull Requests (793):
297
297
298 * :ghpull:`3958`: doc update
298 * :ghpull:`3958`: doc update
299 * :ghpull:`3965`: Fix ansi color code for background yellow
299 * :ghpull:`3965`: Fix ansi color code for background yellow
300 * :ghpull:`3964`: Fix casing of message.
300 * :ghpull:`3964`: Fix casing of message.
301 * :ghpull:`3942`: Pass on install docs
301 * :ghpull:`3942`: Pass on install docs
302 * :ghpull:`3962`: exclude IPython.lib.kernel in iptest
302 * :ghpull:`3962`: exclude IPython.lib.kernel in iptest
303 * :ghpull:`3961`: Longpath test fix
303 * :ghpull:`3961`: Longpath test fix
304 * :ghpull:`3905`: Remove references to 0.11 and 0.12 from config/overview.rst
304 * :ghpull:`3905`: Remove references to 0.11 and 0.12 from config/overview.rst
305 * :ghpull:`3951`: nbconvert: fixed latex characters not escaped properly in nbconvert
305 * :ghpull:`3951`: nbconvert: fixed latex characters not escaped properly in nbconvert
306 * :ghpull:`3949`: log fatal error when PDF conversion fails
306 * :ghpull:`3949`: log fatal error when PDF conversion fails
307 * :ghpull:`3947`: nbconvert: Make writer & post-processor aliases case insensitive.
307 * :ghpull:`3947`: nbconvert: Make writer & post-processor aliases case insensitive.
308 * :ghpull:`3938`: Recompile css.
308 * :ghpull:`3938`: Recompile css.
309 * :ghpull:`3948`: sphinx and PDF tweaks
309 * :ghpull:`3948`: sphinx and PDF tweaks
310 * :ghpull:`3943`: nbconvert: Serve post-processor Windows fix
310 * :ghpull:`3943`: nbconvert: Serve post-processor Windows fix
311 * :ghpull:`3934`: nbconvert: fix logic of verbose flag in PDF post processor
311 * :ghpull:`3934`: nbconvert: fix logic of verbose flag in PDF post processor
312 * :ghpull:`3929`: swallow enter event in rename dialog
312 * :ghpull:`3929`: swallow enter event in rename dialog
313 * :ghpull:`3924`: nbconvert: Backport fixes
313 * :ghpull:`3924`: nbconvert: Backport fixes
314 * :ghpull:`3925`: Replace --pylab flag with --matplotlib in usage
314 * :ghpull:`3925`: Replace --pylab flag with --matplotlib in usage
315 * :ghpull:`3910`: Added explicit error message for missing configuration arguments.
315 * :ghpull:`3910`: Added explicit error message for missing configuration arguments.
316 * :ghpull:`3913`: grffile to support spaces in notebook names
316 * :ghpull:`3913`: grffile to support spaces in notebook names
317 * :ghpull:`3918`: added check_for_tornado, closes #3916
317 * :ghpull:`3918`: added check_for_tornado, closes #3916
318 * :ghpull:`3917`: change docs/examples refs to be just examples
318 * :ghpull:`3917`: change docs/examples refs to be just examples
319 * :ghpull:`3908`: what's new tweaks
319 * :ghpull:`3908`: what's new tweaks
320 * :ghpull:`3896`: two column quickhelp dialog, closes #3895
320 * :ghpull:`3896`: two column quickhelp dialog, closes #3895
321 * :ghpull:`3911`: explicitly load python mode before IPython mode
321 * :ghpull:`3911`: explicitly load python mode before IPython mode
322 * :ghpull:`3901`: don't force . relative path, fix #3897
322 * :ghpull:`3901`: don't force . relative path, fix #3897
323 * :ghpull:`3891`: fix #3889
323 * :ghpull:`3891`: fix #3889
324 * :ghpull:`3892`: Fix documentation of Kernel.stop_channels
324 * :ghpull:`3892`: Fix documentation of Kernel.stop_channels
325 * :ghpull:`3888`: posixify paths for Windows latex
325 * :ghpull:`3888`: posixify paths for Windows latex
326 * :ghpull:`3882`: quick fix for #3881
326 * :ghpull:`3882`: quick fix for #3881
327 * :ghpull:`3877`: don't use `shell=True` in PDF export
327 * :ghpull:`3877`: don't use `shell=True` in PDF export
328 * :ghpull:`3878`: minor template loading cleanup
328 * :ghpull:`3878`: minor template loading cleanup
329 * :ghpull:`3855`: nbconvert: Filter tests
329 * :ghpull:`3855`: nbconvert: Filter tests
330 * :ghpull:`3879`: finish 3870
330 * :ghpull:`3879`: finish 3870
331 * :ghpull:`3870`: Fix for converting notebooks that contain unicode characters.
331 * :ghpull:`3870`: Fix for converting notebooks that contain unicode characters.
332 * :ghpull:`3876`: Update parallel_winhpc.rst
332 * :ghpull:`3876`: Update parallel_winhpc.rst
333 * :ghpull:`3872`: removing vim-ipython, since it has it's own repo
333 * :ghpull:`3872`: removing vim-ipython, since it has it's own repo
334 * :ghpull:`3871`: updating docs
334 * :ghpull:`3871`: updating docs
335 * :ghpull:`3873`: remove old examples
335 * :ghpull:`3873`: remove old examples
336 * :ghpull:`3868`: update CodeMirror component to 3.15
336 * :ghpull:`3868`: update CodeMirror component to 3.15
337 * :ghpull:`3865`: Escape filename for pdflatex in nbconvert
337 * :ghpull:`3865`: Escape filename for pdflatex in nbconvert
338 * :ghpull:`3861`: remove old external.js
338 * :ghpull:`3861`: remove old external.js
339 * :ghpull:`3864`: add keyboard shortcut to docs
339 * :ghpull:`3864`: add keyboard shortcut to docs
340 * :ghpull:`3834`: This PR fixes a few issues with nbconvert tests
340 * :ghpull:`3834`: This PR fixes a few issues with nbconvert tests
341 * :ghpull:`3840`: prevent profile_dir from being undefined
341 * :ghpull:`3840`: prevent profile_dir from being undefined
342 * :ghpull:`3859`: Add "An Afternoon Hack" to docs
342 * :ghpull:`3859`: Add "An Afternoon Hack" to docs
343 * :ghpull:`3854`: Catch errors filling readline history on startup
343 * :ghpull:`3854`: Catch errors filling readline history on startup
344 * :ghpull:`3857`: Delete extra auto
344 * :ghpull:`3857`: Delete extra auto
345 * :ghpull:`3845`: nbconvert: Serve from original build directory
345 * :ghpull:`3845`: nbconvert: Serve from original build directory
346 * :ghpull:`3846`: Add basic logging to nbconvert
346 * :ghpull:`3846`: Add basic logging to nbconvert
347 * :ghpull:`3850`: add missing store_history key to Notebook execute_requests
347 * :ghpull:`3850`: add missing store_history key to Notebook execute_requests
348 * :ghpull:`3844`: update payload source
348 * :ghpull:`3844`: update payload source
349 * :ghpull:`3830`: mention metadata / display_data similarity in pyout spec
349 * :ghpull:`3830`: mention metadata / display_data similarity in pyout spec
350 * :ghpull:`3848`: fix incorrect `empty-docstring`
350 * :ghpull:`3848`: fix incorrect `empty-docstring`
351 * :ghpull:`3836`: Parse markdown correctly when mathjax is disabled
351 * :ghpull:`3836`: Parse markdown correctly when mathjax is disabled
352 * :ghpull:`3849`: skip a failing test on windows
352 * :ghpull:`3849`: skip a failing test on windows
353 * :ghpull:`3828`: signature_scheme lives in Session
353 * :ghpull:`3828`: signature_scheme lives in Session
354 * :ghpull:`3831`: update nbconvert doc with new CLI
354 * :ghpull:`3831`: update nbconvert doc with new CLI
355 * :ghpull:`3822`: add output flag to nbconvert
355 * :ghpull:`3822`: add output flag to nbconvert
356 * :ghpull:`3780`: Added serving the output directory if html-based format are selected.
356 * :ghpull:`3780`: Added serving the output directory if html-based format are selected.
357 * :ghpull:`3764`: Cleanup nbconvert templates
357 * :ghpull:`3764`: Cleanup nbconvert templates
358 * :ghpull:`3829`: remove now-duplicate 'this is dev' note
358 * :ghpull:`3829`: remove now-duplicate 'this is dev' note
359 * :ghpull:`3814`: add `ConsoleWidget.execute_on_complete_input` flag
359 * :ghpull:`3814`: add `ConsoleWidget.execute_on_complete_input` flag
360 * :ghpull:`3826`: try rtfd
360 * :ghpull:`3826`: try rtfd
361 * :ghpull:`3821`: add sphinx prolog
361 * :ghpull:`3821`: add sphinx prolog
362 * :ghpull:`3817`: relax timeouts in terminal console and tests
362 * :ghpull:`3817`: relax timeouts in terminal console and tests
363 * :ghpull:`3825`: fix more tests that fail when pandoc is missing
363 * :ghpull:`3825`: fix more tests that fail when pandoc is missing
364 * :ghpull:`3824`: don't set target on internal markdown links
364 * :ghpull:`3824`: don't set target on internal markdown links
365 * :ghpull:`3816`: s/pylab/matplotlib in docs
365 * :ghpull:`3816`: s/pylab/matplotlib in docs
366 * :ghpull:`3812`: Describe differences between start_ipython and embed
366 * :ghpull:`3812`: Describe differences between start_ipython and embed
367 * :ghpull:`3805`: Print View has been removed
367 * :ghpull:`3805`: Print View has been removed
368 * :ghpull:`3820`: Make it clear that 1.0 is not released yet
368 * :ghpull:`3820`: Make it clear that 1.0 is not released yet
369 * :ghpull:`3784`: nbconvert: Export flavors & PDF writer (ipy dev meeting)
369 * :ghpull:`3784`: nbconvert: Export flavors & PDF writer (ipy dev meeting)
370 * :ghpull:`3800`: semantic-versionify version number for non-releases
370 * :ghpull:`3800`: semantic-versionify version number for non-releases
371 * :ghpull:`3802`: Documentation .txt to .rst
371 * :ghpull:`3802`: Documentation .txt to .rst
372 * :ghpull:`3765`: cleanup terminal console iopub handling
372 * :ghpull:`3765`: cleanup terminal console iopub handling
373 * :ghpull:`3720`: Fix for #3719
373 * :ghpull:`3720`: Fix for #3719
374 * :ghpull:`3787`: re-raise KeyboardInterrupt in raw_input
374 * :ghpull:`3787`: re-raise KeyboardInterrupt in raw_input
375 * :ghpull:`3770`: Organizing reveal's templates.
375 * :ghpull:`3770`: Organizing reveal's templates.
376 * :ghpull:`3751`: Use link(2) when possible in nbconvert
376 * :ghpull:`3751`: Use link(2) when possible in nbconvert
377 * :ghpull:`3792`: skip tests that require pandoc
377 * :ghpull:`3792`: skip tests that require pandoc
378 * :ghpull:`3782`: add Importing Notebooks example
378 * :ghpull:`3782`: add Importing Notebooks example
379 * :ghpull:`3752`: nbconvert: Add cwd to sys.path
379 * :ghpull:`3752`: nbconvert: Add cwd to sys.path
380 * :ghpull:`3789`: fix raw_input in qtconsole
380 * :ghpull:`3789`: fix raw_input in qtconsole
381 * :ghpull:`3756`: document the wire protocol
381 * :ghpull:`3756`: document the wire protocol
382 * :ghpull:`3749`: convert IPython syntax to Python syntax in nbconvert python template
382 * :ghpull:`3749`: convert IPython syntax to Python syntax in nbconvert python template
383 * :ghpull:`3793`: Closes #3788
383 * :ghpull:`3793`: Closes #3788
384 * :ghpull:`3794`: Change logo link to ipython.org
384 * :ghpull:`3794`: Change logo link to ipython.org
385 * :ghpull:`3746`: Raise a named exception when pandoc is missing
385 * :ghpull:`3746`: Raise a named exception when pandoc is missing
386 * :ghpull:`3781`: comply with the message spec in the notebook
386 * :ghpull:`3781`: comply with the message spec in the notebook
387 * :ghpull:`3779`: remove bad `if logged_in` preventing new-notebook without login
387 * :ghpull:`3779`: remove bad `if logged_in` preventing new-notebook without login
388 * :ghpull:`3743`: remove notebook read-only view
388 * :ghpull:`3743`: remove notebook read-only view
389 * :ghpull:`3732`: add delay to autosave in beforeunload
389 * :ghpull:`3732`: add delay to autosave in beforeunload
390 * :ghpull:`3761`: Added rm_math_space to markdown cells in the basichtml.tpl to be rendered ok by mathjax after the nbconvertion.
390 * :ghpull:`3761`: Added rm_math_space to markdown cells in the basichtml.tpl to be rendered ok by mathjax after the nbconvertion.
391 * :ghpull:`3758`: nbconvert: Filter names cleanup
391 * :ghpull:`3758`: nbconvert: Filter names cleanup
392 * :ghpull:`3769`: Add configurability to tabcompletion timeout
392 * :ghpull:`3769`: Add configurability to tabcompletion timeout
393 * :ghpull:`3771`: Update px pylab test to match new output of pylab
393 * :ghpull:`3771`: Update px pylab test to match new output of pylab
394 * :ghpull:`3741`: better message when notebook format is not supported
394 * :ghpull:`3741`: better message when notebook format is not supported
395 * :ghpull:`3753`: document Ctrl-C not working in ipython kernel
395 * :ghpull:`3753`: document Ctrl-C not working in ipython kernel
396 * :ghpull:`3766`: handle empty metadata in pyout messages more gracefully.
396 * :ghpull:`3766`: handle empty metadata in pyout messages more gracefully.
397 * :ghpull:`3736`: my attempt to fix #3735
397 * :ghpull:`3736`: my attempt to fix #3735
398 * :ghpull:`3759`: nbconvert: Provide a more useful error for invalid use case.
398 * :ghpull:`3759`: nbconvert: Provide a more useful error for invalid use case.
399 * :ghpull:`3760`: nbconvert: Allow notebook filenames without their extensions
399 * :ghpull:`3760`: nbconvert: Allow notebook filenames without their extensions
400 * :ghpull:`3750`: nbconvert: Add cwd to default templates search path.
400 * :ghpull:`3750`: nbconvert: Add cwd to default templates search path.
401 * :ghpull:`3748`: Update nbconvert docs
401 * :ghpull:`3748`: Update nbconvert docs
402 * :ghpull:`3734`: Nbconvert: Export extracted files into `nbname_files` subdirectory
402 * :ghpull:`3734`: Nbconvert: Export extracted files into `nbname_files` subdirectory
403 * :ghpull:`3733`: Nicer message when pandoc is missing, closes #3730
403 * :ghpull:`3733`: Nicer message when pandoc is missing, closes #3730
404 * :ghpull:`3722`: fix two failing test in IPython.lib
404 * :ghpull:`3722`: fix two failing test in IPython.lib
405 * :ghpull:`3704`: Start what's new for 1.0
405 * :ghpull:`3704`: Start what's new for 1.0
406 * :ghpull:`3705`: Complete rewrite of IPython Notebook documentation: docs/source/interactive/htmlnotebook.txt
406 * :ghpull:`3705`: Complete rewrite of IPython Notebook documentation: docs/source/interactive/htmlnotebook.txt
407 * :ghpull:`3709`: Docs cleanup
407 * :ghpull:`3709`: Docs cleanup
408 * :ghpull:`3716`: raw_input fixes for kernel restarts
408 * :ghpull:`3716`: raw_input fixes for kernel restarts
409 * :ghpull:`3683`: use `%matplotlib` in example notebooks
409 * :ghpull:`3683`: use `%matplotlib` in example notebooks
410 * :ghpull:`3686`: remove quarantine
410 * :ghpull:`3686`: remove quarantine
411 * :ghpull:`3699`: svg2pdf unicode fix
411 * :ghpull:`3699`: svg2pdf unicode fix
412 * :ghpull:`3695`: fix SVG2PDF
412 * :ghpull:`3695`: fix SVG2PDF
413 * :ghpull:`3685`: fix Pager.detach
413 * :ghpull:`3685`: fix Pager.detach
414 * :ghpull:`3675`: document new dependencies
414 * :ghpull:`3675`: document new dependencies
415 * :ghpull:`3690`: Fixing some css minors in full_html and reveal.
415 * :ghpull:`3690`: Fixing some css minors in full_html and reveal.
416 * :ghpull:`3671`: nbconvert tests
416 * :ghpull:`3671`: nbconvert tests
417 * :ghpull:`3692`: Fix rename notebook - show error with invalid name
417 * :ghpull:`3692`: Fix rename notebook - show error with invalid name
418 * :ghpull:`3409`: Prevent qtconsole frontend freeze on lots of output.
418 * :ghpull:`3409`: Prevent qtconsole frontend freeze on lots of output.
419 * :ghpull:`3660`: refocus active cell on dialog close
419 * :ghpull:`3660`: refocus active cell on dialog close
420 * :ghpull:`3598`: Statelessify mathjaxutils
420 * :ghpull:`3598`: Statelessify mathjaxutils
421 * :ghpull:`3673`: enable comment/uncomment selection
421 * :ghpull:`3673`: enable comment/uncomment selection
422 * :ghpull:`3677`: remove special-case in get_home_dir for frozen dists
422 * :ghpull:`3677`: remove special-case in get_home_dir for frozen dists
423 * :ghpull:`3674`: add CONTRIBUTING.md
423 * :ghpull:`3674`: add CONTRIBUTING.md
424 * :ghpull:`3670`: use Popen command list for ipexec
424 * :ghpull:`3670`: use Popen command list for ipexec
425 * :ghpull:`3568`: pylab import adjustments
425 * :ghpull:`3568`: pylab import adjustments
426 * :ghpull:`3559`: add create.Cell and delete.Cell js events
426 * :ghpull:`3559`: add create.Cell and delete.Cell js events
427 * :ghpull:`3606`: push cell magic to the head of the transformer line
427 * :ghpull:`3606`: push cell magic to the head of the transformer line
428 * :ghpull:`3607`: NbConvert: Writers, No YAML, and stuff...
428 * :ghpull:`3607`: NbConvert: Writers, No YAML, and stuff...
429 * :ghpull:`3665`: Pywin32 skips
429 * :ghpull:`3665`: Pywin32 skips
430 * :ghpull:`3669`: set default client_class for QtKernelManager
430 * :ghpull:`3669`: set default client_class for QtKernelManager
431 * :ghpull:`3662`: add strip_encoding_cookie transformer
431 * :ghpull:`3662`: add strip_encoding_cookie transformer
432 * :ghpull:`3641`: increase patience for slow kernel startup in tests
432 * :ghpull:`3641`: increase patience for slow kernel startup in tests
433 * :ghpull:`3651`: remove a bunch of unused `default_config_file` assignments
433 * :ghpull:`3651`: remove a bunch of unused `default_config_file` assignments
434 * :ghpull:`3630`: CSS adjustments
434 * :ghpull:`3630`: CSS adjustments
435 * :ghpull:`3645`: Don't require HistoryManager to have a shell
435 * :ghpull:`3645`: Don't require HistoryManager to have a shell
436 * :ghpull:`3643`: don't assume tested ipython is on the PATH
436 * :ghpull:`3643`: don't assume tested ipython is on the PATH
437 * :ghpull:`3654`: fix single-result AsyncResults
437 * :ghpull:`3654`: fix single-result AsyncResults
438 * :ghpull:`3601`: Markdown in heading cells (take 2)
438 * :ghpull:`3601`: Markdown in heading cells (take 2)
439 * :ghpull:`3652`: Remove old `docs/examples`
439 * :ghpull:`3652`: Remove old `docs/examples`
440 * :ghpull:`3621`: catch any exception appending output
440 * :ghpull:`3621`: catch any exception appending output
441 * :ghpull:`3585`: don't blacklist builtin names
441 * :ghpull:`3585`: don't blacklist builtin names
442 * :ghpull:`3647`: Fix `frontend` deprecation warnings in several examples
442 * :ghpull:`3647`: Fix `frontend` deprecation warnings in several examples
443 * :ghpull:`3649`: fix AsyncResult.get_dict for single result
443 * :ghpull:`3649`: fix AsyncResult.get_dict for single result
444 * :ghpull:`3648`: Fix store magic test
444 * :ghpull:`3648`: Fix store magic test
445 * :ghpull:`3650`: Fix, config_file_name was ignored
445 * :ghpull:`3650`: Fix, config_file_name was ignored
446 * :ghpull:`3640`: Gcf.get_active() can return None
446 * :ghpull:`3640`: Gcf.get_active() can return None
447 * :ghpull:`3571`: Added shorcuts to split cell, merge cell above and merge cell below.
447 * :ghpull:`3571`: Added shorcuts to split cell, merge cell above and merge cell below.
448 * :ghpull:`3635`: Added missing slash to print-pdf call.
448 * :ghpull:`3635`: Added missing slash to print-pdf call.
449 * :ghpull:`3487`: Drop patch for compatibility with pyreadline 1.5
449 * :ghpull:`3487`: Drop patch for compatibility with pyreadline 1.5
450 * :ghpull:`3338`: Allow filename with extension in find_cmd in Windows.
450 * :ghpull:`3338`: Allow filename with extension in find_cmd in Windows.
451 * :ghpull:`3628`: Fix test for Python 3 on Windows.
451 * :ghpull:`3628`: Fix test for Python 3 on Windows.
452 * :ghpull:`3642`: Fix typo in docs
452 * :ghpull:`3642`: Fix typo in docs
453 * :ghpull:`3627`: use DEFAULT_STATIC_FILES_PATH in a test instead of package dir
453 * :ghpull:`3627`: use DEFAULT_STATIC_FILES_PATH in a test instead of package dir
454 * :ghpull:`3624`: fix some unicode in zmqhandlers
454 * :ghpull:`3624`: fix some unicode in zmqhandlers
455 * :ghpull:`3460`: Set calling program to UNKNOWN, when argv not in sys
455 * :ghpull:`3460`: Set calling program to UNKNOWN, when argv not in sys
456 * :ghpull:`3632`: Set calling program to UNKNOWN, when argv not in sys (take #2)
456 * :ghpull:`3632`: Set calling program to UNKNOWN, when argv not in sys (take #2)
457 * :ghpull:`3629`: Use new entry point for python -m IPython
457 * :ghpull:`3629`: Use new entry point for python -m IPython
458 * :ghpull:`3626`: passing cell to showInPager, closes #3625
458 * :ghpull:`3626`: passing cell to showInPager, closes #3625
459 * :ghpull:`3618`: expand terminal color support
459 * :ghpull:`3618`: expand terminal color support
460 * :ghpull:`3623`: raise UsageError for unsupported GUI backends
460 * :ghpull:`3623`: raise UsageError for unsupported GUI backends
461 * :ghpull:`3071`: Add magic function %drun to run code in debugger
461 * :ghpull:`3071`: Add magic function %drun to run code in debugger
462 * :ghpull:`3608`: a nicer error message when using %pylab magic
462 * :ghpull:`3608`: a nicer error message when using %pylab magic
463 * :ghpull:`3592`: add extra_config_file
463 * :ghpull:`3592`: add extra_config_file
464 * :ghpull:`3612`: updated .mailmap
464 * :ghpull:`3612`: updated .mailmap
465 * :ghpull:`3616`: Add examples for interactive use of MPI.
465 * :ghpull:`3616`: Add examples for interactive use of MPI.
466 * :ghpull:`3615`: fix regular expression for ANSI escapes
466 * :ghpull:`3615`: fix regular expression for ANSI escapes
467 * :ghpull:`3586`: Corrected a typo in the format string for strftime the sphinx.py transformer of nbconvert
467 * :ghpull:`3586`: Corrected a typo in the format string for strftime the sphinx.py transformer of nbconvert
468 * :ghpull:`3611`: check for markdown no longer needed, closes #3610
468 * :ghpull:`3611`: check for markdown no longer needed, closes #3610
469 * :ghpull:`3555`: Simplify caching of modules with %run
469 * :ghpull:`3555`: Simplify caching of modules with %run
470 * :ghpull:`3583`: notebook small things
470 * :ghpull:`3583`: notebook small things
471 * :ghpull:`3594`: Fix duplicate completion in notebook
471 * :ghpull:`3594`: Fix duplicate completion in notebook
472 * :ghpull:`3600`: parallel: Improved logging for errors during BatchSystemLauncher.stop
472 * :ghpull:`3600`: parallel: Improved logging for errors during BatchSystemLauncher.stop
473 * :ghpull:`3595`: Revert "allow markdown in heading cells"
473 * :ghpull:`3595`: Revert "allow markdown in heading cells"
474 * :ghpull:`3538`: add IPython.start_ipython
474 * :ghpull:`3538`: add IPython.start_ipython
475 * :ghpull:`3562`: Allow custom nbconvert template loaders
475 * :ghpull:`3562`: Allow custom nbconvert template loaders
476 * :ghpull:`3582`: pandoc adjustments
476 * :ghpull:`3582`: pandoc adjustments
477 * :ghpull:`3560`: Remove max_msg_size
477 * :ghpull:`3560`: Remove max_msg_size
478 * :ghpull:`3591`: Refer to Setuptools instead of Distribute
478 * :ghpull:`3591`: Refer to Setuptools instead of Distribute
479 * :ghpull:`3590`: IPython.sphinxext needs an __init__.py
479 * :ghpull:`3590`: IPython.sphinxext needs an __init__.py
480 * :ghpull:`3581`: Added the possibility to read a custom.css file for tweaking the final html in full_html and reveal templates.
480 * :ghpull:`3581`: Added the possibility to read a custom.css file for tweaking the final html in full_html and reveal templates.
481 * :ghpull:`3576`: Added support for markdown in heading cells when they are nbconverted.
481 * :ghpull:`3576`: Added support for markdown in heading cells when they are nbconverted.
482 * :ghpull:`3575`: tweak `run -d` message to 'continue execution'
482 * :ghpull:`3575`: tweak `run -d` message to 'continue execution'
483 * :ghpull:`3569`: add PYTHONSTARTUP to startup files
483 * :ghpull:`3569`: add PYTHONSTARTUP to startup files
484 * :ghpull:`3567`: Trigger a single event on js app initilized
484 * :ghpull:`3567`: Trigger a single event on js app initilized
485 * :ghpull:`3565`: style.min.css shoudl always exist...
485 * :ghpull:`3565`: style.min.css shoudl always exist...
486 * :ghpull:`3531`: allow markdown in heading cells
486 * :ghpull:`3531`: allow markdown in heading cells
487 * :ghpull:`3577`: Simplify codemirror ipython-mode
487 * :ghpull:`3577`: Simplify codemirror ipython-mode
488 * :ghpull:`3495`: Simplified regexp, and suggestions for clearer regexps.
488 * :ghpull:`3495`: Simplified regexp, and suggestions for clearer regexps.
489 * :ghpull:`3578`: Use adjustbox to specify figure size in nbconvert -> latex
489 * :ghpull:`3578`: Use adjustbox to specify figure size in nbconvert -> latex
490 * :ghpull:`3572`: Skip import irunner test on Windows.
490 * :ghpull:`3572`: Skip import irunner test on Windows.
491 * :ghpull:`3574`: correct static path for CM modes autoload
491 * :ghpull:`3574`: correct static path for CM modes autoload
492 * :ghpull:`3558`: Add IPython.sphinxext
492 * :ghpull:`3558`: Add IPython.sphinxext
493 * :ghpull:`3561`: mention double-control-C to stop notebook server
493 * :ghpull:`3561`: mention double-control-C to stop notebook server
494 * :ghpull:`3566`: fix event names
494 * :ghpull:`3566`: fix event names
495 * :ghpull:`3564`: Remove trivial nbconvert example
495 * :ghpull:`3564`: Remove trivial nbconvert example
496 * :ghpull:`3540`: allow cython cache dir to be deleted
496 * :ghpull:`3540`: allow cython cache dir to be deleted
497 * :ghpull:`3527`: cleanup stale, unused exceptions in parallel.error
497 * :ghpull:`3527`: cleanup stale, unused exceptions in parallel.error
498 * :ghpull:`3529`: ensure raw_input returns str in zmq shell
498 * :ghpull:`3529`: ensure raw_input returns str in zmq shell
499 * :ghpull:`3541`: respect image size metadata in qtconsole
499 * :ghpull:`3541`: respect image size metadata in qtconsole
500 * :ghpull:`3550`: Fixing issue preventing the correct read of images by full_html and reveal exporters.
500 * :ghpull:`3550`: Fixing issue preventing the correct read of images by full_html and reveal exporters.
501 * :ghpull:`3557`: open markdown links in new tabs
501 * :ghpull:`3557`: open markdown links in new tabs
502 * :ghpull:`3556`: remove mention of nonexistent `_margv` in macro
502 * :ghpull:`3556`: remove mention of nonexistent `_margv` in macro
503 * :ghpull:`3552`: set overflow-x: hidden on Firefox only
503 * :ghpull:`3552`: set overflow-x: hidden on Firefox only
504 * :ghpull:`3554`: Fix missing import os in latex exporter.
504 * :ghpull:`3554`: Fix missing import os in latex exporter.
505 * :ghpull:`3546`: Don't hardcode **latex** posix paths in nbconvert
505 * :ghpull:`3546`: Don't hardcode **latex** posix paths in nbconvert
506 * :ghpull:`3551`: fix path prefix in nbconvert
506 * :ghpull:`3551`: fix path prefix in nbconvert
507 * :ghpull:`3533`: Use a CDN to get reveal.js library.
507 * :ghpull:`3533`: Use a CDN to get reveal.js library.
508 * :ghpull:`3498`: When a notebook is written to file, name the metadata name u''.
508 * :ghpull:`3498`: When a notebook is written to file, name the metadata name u''.
509 * :ghpull:`3548`: Change to standard save icon in Notebook toolbar
509 * :ghpull:`3548`: Change to standard save icon in Notebook toolbar
510 * :ghpull:`3539`: Don't hardcode posix paths in nbconvert
510 * :ghpull:`3539`: Don't hardcode posix paths in nbconvert
511 * :ghpull:`3508`: notebook supports raw_input and %debug now
511 * :ghpull:`3508`: notebook supports raw_input and %debug now
512 * :ghpull:`3526`: ensure 'default' is first in cluster profile list
512 * :ghpull:`3526`: ensure 'default' is first in cluster profile list
513 * :ghpull:`3525`: basic timezone info
513 * :ghpull:`3525`: basic timezone info
514 * :ghpull:`3532`: include nbconvert templates in installation
514 * :ghpull:`3532`: include nbconvert templates in installation
515 * :ghpull:`3515`: update CodeMirror component to 3.14
515 * :ghpull:`3515`: update CodeMirror component to 3.14
516 * :ghpull:`3513`: add 'No Checkpoints' to Revert menu
516 * :ghpull:`3513`: add 'No Checkpoints' to Revert menu
517 * :ghpull:`3536`: format positions are required in Python 2.6.x
517 * :ghpull:`3536`: format positions are required in Python 2.6.x
518 * :ghpull:`3521`: Nbconvert fix, silent fail if template doesn't exist
518 * :ghpull:`3521`: Nbconvert fix, silent fail if template doesn't exist
519 * :ghpull:`3530`: update %store magic docstring
519 * :ghpull:`3530`: update %store magic docstring
520 * :ghpull:`3528`: fix local mathjax with custom base_project_url
520 * :ghpull:`3528`: fix local mathjax with custom base_project_url
521 * :ghpull:`3518`: Clear up unused imports
521 * :ghpull:`3518`: Clear up unused imports
522 * :ghpull:`3506`: %store -r restores saved aliases and directory history, as well as variables
522 * :ghpull:`3506`: %store -r restores saved aliases and directory history, as well as variables
523 * :ghpull:`3516`: make css highlight style configurable
523 * :ghpull:`3516`: make css highlight style configurable
524 * :ghpull:`3523`: Exclude frontend shim from docs build
524 * :ghpull:`3523`: Exclude frontend shim from docs build
525 * :ghpull:`3514`: use bootstrap `disabled` instead of `ui-state-disabled`
525 * :ghpull:`3514`: use bootstrap `disabled` instead of `ui-state-disabled`
526 * :ghpull:`3520`: Added relative import of RevealExporter to __init__.py inside exporters module
526 * :ghpull:`3520`: Added relative import of RevealExporter to __init__.py inside exporters module
527 * :ghpull:`3507`: fix HTML capitalization in nbconvert exporter classes
527 * :ghpull:`3507`: fix HTML capitalization in nbconvert exporter classes
528 * :ghpull:`3512`: fix nbconvert filter validation
528 * :ghpull:`3512`: fix nbconvert filter validation
529 * :ghpull:`3511`: Get Tracer working after ipapi.get replaced with get_ipython
529 * :ghpull:`3511`: Get Tracer working after ipapi.get replaced with get_ipython
530 * :ghpull:`3510`: use `window.onbeforeunload=` for nav-away warning
530 * :ghpull:`3510`: use `window.onbeforeunload=` for nav-away warning
531 * :ghpull:`3504`: don't use parent=self in handlers
531 * :ghpull:`3504`: don't use parent=self in handlers
532 * :ghpull:`3500`: Merge nbconvert into IPython
532 * :ghpull:`3500`: Merge nbconvert into IPython
533 * :ghpull:`3478`: restore "unsaved changes" warning on unload
533 * :ghpull:`3478`: restore "unsaved changes" warning on unload
534 * :ghpull:`3493`: add a dialog when the kernel is auto-restarted
534 * :ghpull:`3493`: add a dialog when the kernel is auto-restarted
535 * :ghpull:`3488`: Add test suite for autoreload extension
535 * :ghpull:`3488`: Add test suite for autoreload extension
536 * :ghpull:`3484`: Catch some pathological cases inside oinspect
536 * :ghpull:`3484`: Catch some pathological cases inside oinspect
537 * :ghpull:`3481`: Display R errors without Python traceback
537 * :ghpull:`3481`: Display R errors without Python traceback
538 * :ghpull:`3468`: fix `%magic` output
538 * :ghpull:`3468`: fix `%magic` output
539 * :ghpull:`3430`: add parent to Configurable
539 * :ghpull:`3430`: add parent to Configurable
540 * :ghpull:`3491`: Remove unexpected keyword parameter to remove_kernel
540 * :ghpull:`3491`: Remove unexpected keyword parameter to remove_kernel
541 * :ghpull:`3485`: SymPy has changed its recommended way to initialize printing
541 * :ghpull:`3485`: SymPy has changed its recommended way to initialize printing
542 * :ghpull:`3486`: Add test for non-ascii characters in docstrings
542 * :ghpull:`3486`: Add test for non-ascii characters in docstrings
543 * :ghpull:`3483`: Inputtransformer: Allow classic prompts without space
543 * :ghpull:`3483`: Inputtransformer: Allow classic prompts without space
544 * :ghpull:`3482`: Use an absolute path to iptest, because the tests are not always run from $IPYTHONDIR.
544 * :ghpull:`3482`: Use an absolute path to iptest, because the tests are not always run from $IPYTHONDIR.
545 * :ghpull:`3381`: enable 2x (retina) display
545 * :ghpull:`3381`: enable 2x (retina) display
546 * :ghpull:`3450`: Flatten IPython.frontend
546 * :ghpull:`3450`: Flatten IPython.frontend
547 * :ghpull:`3477`: pass config to subapps
547 * :ghpull:`3477`: pass config to subapps
548 * :ghpull:`3466`: Kernel fails to start when username has non-ascii characters
548 * :ghpull:`3466`: Kernel fails to start when username has non-ascii characters
549 * :ghpull:`3465`: Add HTCondor bindings to IPython.parallel
549 * :ghpull:`3465`: Add HTCondor bindings to IPython.parallel
550 * :ghpull:`3463`: fix typo, closes #3462
550 * :ghpull:`3463`: fix typo, closes #3462
551 * :ghpull:`3456`: Notice for users who disable javascript
551 * :ghpull:`3456`: Notice for users who disable javascript
552 * :ghpull:`3453`: fix cell execution in firefox, closes #3447
552 * :ghpull:`3453`: fix cell execution in firefox, closes #3447
553 * :ghpull:`3393`: [WIP] bootstrapify
553 * :ghpull:`3393`: [WIP] bootstrapify
554 * :ghpull:`3440`: Fix installing mathjax from downloaded file via command line
554 * :ghpull:`3440`: Fix installing mathjax from downloaded file via command line
555 * :ghpull:`3431`: Provide means for starting the Qt console maximized and with the menu bar hidden
555 * :ghpull:`3431`: Provide means for starting the Qt console maximized and with the menu bar hidden
556 * :ghpull:`3425`: base IPClusterApp inherits from BaseIPythonApp
556 * :ghpull:`3425`: base IPClusterApp inherits from BaseIPythonApp
557 * :ghpull:`3433`: Update IPython\external\path\__init__.py
557 * :ghpull:`3433`: Update IPython\external\path\__init__.py
558 * :ghpull:`3298`: Some fixes in IPython Sphinx directive
558 * :ghpull:`3298`: Some fixes in IPython Sphinx directive
559 * :ghpull:`3428`: process escapes in mathjax
559 * :ghpull:`3428`: process escapes in mathjax
560 * :ghpull:`3420`: thansk -> thanks
560 * :ghpull:`3420`: thansk -> thanks
561 * :ghpull:`3416`: Fix doc: "principle" not "principal"
561 * :ghpull:`3416`: Fix doc: "principle" not "principal"
562 * :ghpull:`3413`: more unique filename for test
562 * :ghpull:`3413`: more unique filename for test
563 * :ghpull:`3364`: Inject requirejs in notebook and start using it.
563 * :ghpull:`3364`: Inject requirejs in notebook and start using it.
564 * :ghpull:`3390`: Fix %paste with blank lines
564 * :ghpull:`3390`: Fix %paste with blank lines
565 * :ghpull:`3403`: fix creating config objects from dicts
565 * :ghpull:`3403`: fix creating config objects from dicts
566 * :ghpull:`3401`: rollback #3358
566 * :ghpull:`3401`: rollback #3358
567 * :ghpull:`3373`: make cookie_secret configurable
567 * :ghpull:`3373`: make cookie_secret configurable
568 * :ghpull:`3307`: switch default ws_url logic to js side
568 * :ghpull:`3307`: switch default ws_url logic to js side
569 * :ghpull:`3392`: Restore anchor link on h2-h6
569 * :ghpull:`3392`: Restore anchor link on h2-h6
570 * :ghpull:`3369`: Use different treshold for (auto)scroll in output
570 * :ghpull:`3369`: Use different treshold for (auto)scroll in output
571 * :ghpull:`3370`: normalize unicode notebook filenames
571 * :ghpull:`3370`: normalize unicode notebook filenames
572 * :ghpull:`3372`: base default cookie name on request host+port
572 * :ghpull:`3372`: base default cookie name on request host+port
573 * :ghpull:`3378`: disable CodeMirror drag/drop on Safari
573 * :ghpull:`3378`: disable CodeMirror drag/drop on Safari
574 * :ghpull:`3358`: workaround spurious CodeMirror scrollbars
574 * :ghpull:`3358`: workaround spurious CodeMirror scrollbars
575 * :ghpull:`3371`: make setting the notebook dirty flag an event
575 * :ghpull:`3371`: make setting the notebook dirty flag an event
576 * :ghpull:`3366`: remove long-dead zmq frontend.py and completer.py
576 * :ghpull:`3366`: remove long-dead zmq frontend.py and completer.py
577 * :ghpull:`3382`: cull Session digest history
577 * :ghpull:`3382`: cull Session digest history
578 * :ghpull:`3330`: Fix get_ipython_dir when $HOME is /
578 * :ghpull:`3330`: Fix get_ipython_dir when $HOME is /
579 * :ghpull:`3319`: IPEP 13: user-expressions and user-variables
579 * :ghpull:`3319`: IPEP 13: user-expressions and user-variables
580 * :ghpull:`3384`: comments in tools/gitwash_dumper.py changed (''' to """)
580 * :ghpull:`3384`: comments in tools/gitwash_dumper.py changed (''' to """)
581 * :ghpull:`3387`: Make submodule checks work under Python 3.
581 * :ghpull:`3387`: Make submodule checks work under Python 3.
582 * :ghpull:`3357`: move anchor-link off of heading text
582 * :ghpull:`3357`: move anchor-link off of heading text
583 * :ghpull:`3351`: start basic tests of ipcluster Launchers
583 * :ghpull:`3351`: start basic tests of ipcluster Launchers
584 * :ghpull:`3377`: allow class.__module__ to be None
584 * :ghpull:`3377`: allow class.__module__ to be None
585 * :ghpull:`3340`: skip submodule check in package managers
585 * :ghpull:`3340`: skip submodule check in package managers
586 * :ghpull:`3328`: decode subprocess output in launchers
586 * :ghpull:`3328`: decode subprocess output in launchers
587 * :ghpull:`3368`: Reenable bracket matching
587 * :ghpull:`3368`: Reenable bracket matching
588 * :ghpull:`3356`: Mpr fixes
588 * :ghpull:`3356`: Mpr fixes
589 * :ghpull:`3336`: Use new input transformation API in %time magic
589 * :ghpull:`3336`: Use new input transformation API in %time magic
590 * :ghpull:`3325`: Organize the JS and less files by component.
590 * :ghpull:`3325`: Organize the JS and less files by component.
591 * :ghpull:`3342`: fix test_find_cmd_python
591 * :ghpull:`3342`: fix test_find_cmd_python
592 * :ghpull:`3354`: catch socket.error in utils.localinterfaces
592 * :ghpull:`3354`: catch socket.error in utils.localinterfaces
593 * :ghpull:`3341`: fix default cluster count
593 * :ghpull:`3341`: fix default cluster count
594 * :ghpull:`3286`: don't use `get_ipython` from builtins in library code
594 * :ghpull:`3286`: don't use `get_ipython` from builtins in library code
595 * :ghpull:`3333`: notebookapp: add missing whitespace to warnings
595 * :ghpull:`3333`: notebookapp: add missing whitespace to warnings
596 * :ghpull:`3323`: Strip prompts even if the prompt isn't present on the first line.
596 * :ghpull:`3323`: Strip prompts even if the prompt isn't present on the first line.
597 * :ghpull:`3321`: Reorganize the python/server side of the notebook
597 * :ghpull:`3321`: Reorganize the python/server side of the notebook
598 * :ghpull:`3320`: define `__file__` in config files
598 * :ghpull:`3320`: define `__file__` in config files
599 * :ghpull:`3317`: rename `%%file` to `%%writefile`
599 * :ghpull:`3317`: rename `%%file` to `%%writefile`
600 * :ghpull:`3304`: set unlimited HWM for all relay devices
600 * :ghpull:`3304`: set unlimited HWM for all relay devices
601 * :ghpull:`3315`: Update Sympy_printing extension load
601 * :ghpull:`3315`: Update Sympy_printing extension load
602 * :ghpull:`3310`: further clarify Image docstring
602 * :ghpull:`3310`: further clarify Image docstring
603 * :ghpull:`3285`: load extensions in builtin trap
603 * :ghpull:`3285`: load extensions in builtin trap
604 * :ghpull:`3308`: Speed up AsyncResult._wait_for_outputs(0)
604 * :ghpull:`3308`: Speed up AsyncResult._wait_for_outputs(0)
605 * :ghpull:`3294`: fix callbacks as optional in js kernel.execute
605 * :ghpull:`3294`: fix callbacks as optional in js kernel.execute
606 * :ghpull:`3276`: Fix: "python ABS/PATH/TO/ipython.py" fails
606 * :ghpull:`3276`: Fix: "python ABS/PATH/TO/ipython.py" fails
607 * :ghpull:`3301`: allow python3 tests without python installed
607 * :ghpull:`3301`: allow python3 tests without python installed
608 * :ghpull:`3282`: allow view.map to work with a few more things
608 * :ghpull:`3282`: allow view.map to work with a few more things
609 * :ghpull:`3284`: remove `ipython.py` entry point
609 * :ghpull:`3284`: remove `ipython.py` entry point
610 * :ghpull:`3281`: fix ignored IOPub messages with no parent
610 * :ghpull:`3281`: fix ignored IOPub messages with no parent
611 * :ghpull:`3275`: improve submodule messages / git hooks
611 * :ghpull:`3275`: improve submodule messages / git hooks
612 * :ghpull:`3239`: Allow "x" icon and esc key to close pager in notebook
612 * :ghpull:`3239`: Allow "x" icon and esc key to close pager in notebook
613 * :ghpull:`3290`: Improved heartbeat controller to engine monitoring for long running tasks
613 * :ghpull:`3290`: Improved heartbeat controller to engine monitoring for long running tasks
614 * :ghpull:`3142`: Better error message when CWD doesn't exist on startup
614 * :ghpull:`3142`: Better error message when CWD doesn't exist on startup
615 * :ghpull:`3066`: Add support for relative import to %run -m (fixes #2727)
615 * :ghpull:`3066`: Add support for relative import to %run -m (fixes #2727)
616 * :ghpull:`3269`: protect highlight.js against unknown languages
616 * :ghpull:`3269`: protect highlight.js against unknown languages
617 * :ghpull:`3267`: add missing return
617 * :ghpull:`3267`: add missing return
618 * :ghpull:`3101`: use marked / highlight.js instead of pagedown and prettify
618 * :ghpull:`3101`: use marked / highlight.js instead of pagedown and prettify
619 * :ghpull:`3264`: use https url for submodule
619 * :ghpull:`3264`: use https url for submodule
620 * :ghpull:`3263`: fix set_last_checkpoint when no checkpoint
620 * :ghpull:`3263`: fix set_last_checkpoint when no checkpoint
621 * :ghpull:`3258`: Fix submodule location in setup.py
621 * :ghpull:`3258`: Fix submodule location in setup.py
622 * :ghpull:`3254`: fix a few URLs from previous PR
622 * :ghpull:`3254`: fix a few URLs from previous PR
623 * :ghpull:`3240`: remove js components from the repo
623 * :ghpull:`3240`: remove js components from the repo
624 * :ghpull:`3158`: IPEP 15: autosave the notebook
624 * :ghpull:`3158`: IPEP 15: autosave the notebook
625 * :ghpull:`3252`: move images out of _static folder into _images
625 * :ghpull:`3252`: move images out of _static folder into _images
626 * :ghpull:`3251`: Fix for cell magics in Qt console
626 * :ghpull:`3251`: Fix for cell magics in Qt console
627 * :ghpull:`3250`: Added a simple __html__() method to the HTML class
627 * :ghpull:`3250`: Added a simple __html__() method to the HTML class
628 * :ghpull:`3249`: remove copy of sphinx inheritance_diagram.py
628 * :ghpull:`3249`: remove copy of sphinx inheritance_diagram.py
629 * :ghpull:`3235`: Remove the unused print notebook view
629 * :ghpull:`3235`: Remove the unused print notebook view
630 * :ghpull:`3238`: Improve the design of the tab completion UI
630 * :ghpull:`3238`: Improve the design of the tab completion UI
631 * :ghpull:`3242`: Make changes of Application.log_format effective
631 * :ghpull:`3242`: Make changes of Application.log_format effective
632 * :ghpull:`3219`: Workaround so only one CTRL-C is required for a new prompt in --gui=qt
632 * :ghpull:`3219`: Workaround so only one CTRL-C is required for a new prompt in --gui=qt
633 * :ghpull:`3190`: allow formatters to specify metadata
633 * :ghpull:`3190`: allow formatters to specify metadata
634 * :ghpull:`3231`: improve discovery of public IPs
634 * :ghpull:`3231`: improve discovery of public IPs
635 * :ghpull:`3233`: check prefixes for swallowing kernel args
635 * :ghpull:`3233`: check prefixes for swallowing kernel args
636 * :ghpull:`3234`: Removing old autogrow JS code.
636 * :ghpull:`3234`: Removing old autogrow JS code.
637 * :ghpull:`3232`: Update to CodeMirror 3 and start to ship our components
637 * :ghpull:`3232`: Update to CodeMirror 3 and start to ship our components
638 * :ghpull:`3229`: The HTML output type accidentally got removed from the OutputArea.
638 * :ghpull:`3229`: The HTML output type accidentally got removed from the OutputArea.
639 * :ghpull:`3228`: Typo in IPython.Parallel documentation
639 * :ghpull:`3228`: Typo in IPython.Parallel documentation
640 * :ghpull:`3226`: Text in rename dialog was way too big - making it <p>.
640 * :ghpull:`3226`: Text in rename dialog was way too big - making it <p>.
641 * :ghpull:`3225`: Removing old restuctured text handler and web service.
641 * :ghpull:`3225`: Removing old restuctured text handler and web service.
642 * :ghpull:`3222`: make BlockingKernelClient the default Client
642 * :ghpull:`3222`: make BlockingKernelClient the default Client
643 * :ghpull:`3223`: add missing mathjax_url to new settings dict
643 * :ghpull:`3223`: add missing mathjax_url to new settings dict
644 * :ghpull:`3089`: add stdin to the notebook
644 * :ghpull:`3089`: add stdin to the notebook
645 * :ghpull:`3221`: Remove references to HTMLCell (dead code)
645 * :ghpull:`3221`: Remove references to HTMLCell (dead code)
646 * :ghpull:`3205`: add ignored *args to HasTraits constructor
646 * :ghpull:`3205`: add ignored ``*args`` to HasTraits constructor
647 * :ghpull:`3088`: cleanup IPython handler settings
647 * :ghpull:`3088`: cleanup IPython handler settings
648 * :ghpull:`3201`: use much faster regexp for ansi coloring
648 * :ghpull:`3201`: use much faster regexp for ansi coloring
649 * :ghpull:`3220`: avoid race condition in profile creation
649 * :ghpull:`3220`: avoid race condition in profile creation
650 * :ghpull:`3011`: IPEP 12: add KernelClient
650 * :ghpull:`3011`: IPEP 12: add KernelClient
651 * :ghpull:`3217`: informative error when trying to load directories
651 * :ghpull:`3217`: informative error when trying to load directories
652 * :ghpull:`3174`: Simple class
652 * :ghpull:`3174`: Simple class
653 * :ghpull:`2979`: CM configurable Take 2
653 * :ghpull:`2979`: CM configurable Take 2
654 * :ghpull:`3215`: Updates storemagic extension to allow for specifying variable name to load
654 * :ghpull:`3215`: Updates storemagic extension to allow for specifying variable name to load
655 * :ghpull:`3181`: backport If-Modified-Since fix from tornado
655 * :ghpull:`3181`: backport If-Modified-Since fix from tornado
656 * :ghpull:`3200`: IFrame (VimeoVideo, ScribdDocument, ...)
656 * :ghpull:`3200`: IFrame (VimeoVideo, ScribdDocument, ...)
657 * :ghpull:`3186`: Fix small inconsistency in nbconvert: etype -> ename
657 * :ghpull:`3186`: Fix small inconsistency in nbconvert: etype -> ename
658 * :ghpull:`3212`: Fix issue #2563, "core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation"
658 * :ghpull:`3212`: Fix issue #2563, "core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation"
659 * :ghpull:`3211`: Fix inheritance_diagram Sphinx extension for Sphinx 1.2
659 * :ghpull:`3211`: Fix inheritance_diagram Sphinx extension for Sphinx 1.2
660 * :ghpull:`3208`: Update link to extensions index
660 * :ghpull:`3208`: Update link to extensions index
661 * :ghpull:`3203`: Separate InputSplitter for transforming whole cells
661 * :ghpull:`3203`: Separate InputSplitter for transforming whole cells
662 * :ghpull:`3189`: Improve completer
662 * :ghpull:`3189`: Improve completer
663 * :ghpull:`3194`: finish up PR #3116
663 * :ghpull:`3194`: finish up PR #3116
664 * :ghpull:`3188`: Add new keycodes
664 * :ghpull:`3188`: Add new keycodes
665 * :ghpull:`2695`: Key the root modules cache by sys.path entries.
665 * :ghpull:`2695`: Key the root modules cache by sys.path entries.
666 * :ghpull:`3182`: clarify %%file docstring
666 * :ghpull:`3182`: clarify %%file docstring
667 * :ghpull:`3163`: BUG: Fix the set and frozenset pretty printer to handle the empty case correctly
667 * :ghpull:`3163`: BUG: Fix the set and frozenset pretty printer to handle the empty case correctly
668 * :ghpull:`3180`: better UsageError for cell magic with no body
668 * :ghpull:`3180`: better UsageError for cell magic with no body
669 * :ghpull:`3184`: Cython cache
669 * :ghpull:`3184`: Cython cache
670 * :ghpull:`3175`: Added missing s
670 * :ghpull:`3175`: Added missing s
671 * :ghpull:`3173`: Little bits of documentation cleanup
671 * :ghpull:`3173`: Little bits of documentation cleanup
672 * :ghpull:`2635`: Improve Windows start menu shortcuts (#2)
672 * :ghpull:`2635`: Improve Windows start menu shortcuts (#2)
673 * :ghpull:`3172`: Add missing import in IPython parallel magics example
673 * :ghpull:`3172`: Add missing import in IPython parallel magics example
674 * :ghpull:`3170`: default application logger shouldn't propagate
674 * :ghpull:`3170`: default application logger shouldn't propagate
675 * :ghpull:`3159`: Autocompletion for zsh
675 * :ghpull:`3159`: Autocompletion for zsh
676 * :ghpull:`3105`: move DEFAULT_STATIC_FILES_PATH to IPython.html
676 * :ghpull:`3105`: move DEFAULT_STATIC_FILES_PATH to IPython.html
677 * :ghpull:`3144`: minor bower tweaks
677 * :ghpull:`3144`: minor bower tweaks
678 * :ghpull:`3141`: Default color output for ls on OSX
678 * :ghpull:`3141`: Default color output for ls on OSX
679 * :ghpull:`3137`: fix dot syntax error in inheritance diagram
679 * :ghpull:`3137`: fix dot syntax error in inheritance diagram
680 * :ghpull:`3072`: raise UnsupportedOperation on iostream.fileno()
680 * :ghpull:`3072`: raise UnsupportedOperation on iostream.fileno()
681 * :ghpull:`3147`: Notebook support for a reverse proxy which handles SSL
681 * :ghpull:`3147`: Notebook support for a reverse proxy which handles SSL
682 * :ghpull:`3152`: make qtconsole size at startup configurable
682 * :ghpull:`3152`: make qtconsole size at startup configurable
683 * :ghpull:`3162`: adding stream kwarg to current.new_output
683 * :ghpull:`3162`: adding stream kwarg to current.new_output
684 * :ghpull:`2981`: IPEP 10: kernel side filtering of display formats
684 * :ghpull:`2981`: IPEP 10: kernel side filtering of display formats
685 * :ghpull:`3058`: add redirect handler for notebooks by name
685 * :ghpull:`3058`: add redirect handler for notebooks by name
686 * :ghpull:`3041`: support non-modules in @require
686 * :ghpull:`3041`: support non-modules in @require
687 * :ghpull:`2447`: Stateful line transformers
687 * :ghpull:`2447`: Stateful line transformers
688 * :ghpull:`3108`: fix some O(N) and O(N^2) operations in parallel.map
688 * :ghpull:`3108`: fix some O(N) and O(N^2) operations in parallel.map
689 * :ghpull:`2791`: forward stdout from forked processes
689 * :ghpull:`2791`: forward stdout from forked processes
690 * :ghpull:`3157`: use Python 3-style for pretty-printed sets
690 * :ghpull:`3157`: use Python 3-style for pretty-printed sets
691 * :ghpull:`3148`: closes #3045, #3123 for tornado < version 3.0
691 * :ghpull:`3148`: closes #3045, #3123 for tornado < version 3.0
692 * :ghpull:`3143`: minor heading-link tweaks
692 * :ghpull:`3143`: minor heading-link tweaks
693 * :ghpull:`3136`: Strip useless ANSI escape codes in notebook
693 * :ghpull:`3136`: Strip useless ANSI escape codes in notebook
694 * :ghpull:`3126`: Prevent errors when pressing arrow keys in an empty notebook
694 * :ghpull:`3126`: Prevent errors when pressing arrow keys in an empty notebook
695 * :ghpull:`3135`: quick dev installation instructions
695 * :ghpull:`3135`: quick dev installation instructions
696 * :ghpull:`2889`: Push pandas dataframes to R magic
696 * :ghpull:`2889`: Push pandas dataframes to R magic
697 * :ghpull:`3068`: Don't monkeypatch doctest during IPython startup.
697 * :ghpull:`3068`: Don't monkeypatch doctest during IPython startup.
698 * :ghpull:`3133`: fix argparse version check
698 * :ghpull:`3133`: fix argparse version check
699 * :ghpull:`3102`: set `spellcheck=false` in CodeCell inputarea
699 * :ghpull:`3102`: set `spellcheck=false` in CodeCell inputarea
700 * :ghpull:`3064`: add anchors to heading cells
700 * :ghpull:`3064`: add anchors to heading cells
701 * :ghpull:`3097`: PyQt 4.10: use self._document = self.document()
701 * :ghpull:`3097`: PyQt 4.10: use self._document = self.document()
702 * :ghpull:`3117`: propagate automagic change to shell
702 * :ghpull:`3117`: propagate automagic change to shell
703 * :ghpull:`3118`: don't give up on weird os names
703 * :ghpull:`3118`: don't give up on weird os names
704 * :ghpull:`3115`: Fix example
704 * :ghpull:`3115`: Fix example
705 * :ghpull:`2640`: fix quarantine/ipy_editors.py
705 * :ghpull:`2640`: fix quarantine/ipy_editors.py
706 * :ghpull:`3070`: Add info make target that was missing in old Sphinx
706 * :ghpull:`3070`: Add info make target that was missing in old Sphinx
707 * :ghpull:`3082`: A few small patches to image handling
707 * :ghpull:`3082`: A few small patches to image handling
708 * :ghpull:`3078`: fix regular expression for detecting links in stdout
708 * :ghpull:`3078`: fix regular expression for detecting links in stdout
709 * :ghpull:`3054`: restore default behavior for automatic cluster size
709 * :ghpull:`3054`: restore default behavior for automatic cluster size
710 * :ghpull:`3073`: fix ipython usage text
710 * :ghpull:`3073`: fix ipython usage text
711 * :ghpull:`3083`: fix DisplayMagics.html docstring
711 * :ghpull:`3083`: fix DisplayMagics.html docstring
712 * :ghpull:`3080`: noted sub_channel being renamed to iopub_channel
712 * :ghpull:`3080`: noted sub_channel being renamed to iopub_channel
713 * :ghpull:`3079`: actually use IPKernelApp.kernel_class
713 * :ghpull:`3079`: actually use IPKernelApp.kernel_class
714 * :ghpull:`3076`: Improve notebook.js documentation
714 * :ghpull:`3076`: Improve notebook.js documentation
715 * :ghpull:`3063`: add missing `%%html` magic
715 * :ghpull:`3063`: add missing `%%html` magic
716 * :ghpull:`3075`: check for SIGUSR1 before using it, closes #3074
716 * :ghpull:`3075`: check for SIGUSR1 before using it, closes #3074
717 * :ghpull:`3051`: add width:100% to vbox for webkit / FF consistency
717 * :ghpull:`3051`: add width:100% to vbox for webkit / FF consistency
718 * :ghpull:`2999`: increase registration timeout
718 * :ghpull:`2999`: increase registration timeout
719 * :ghpull:`2997`: fix DictDB default size limit
719 * :ghpull:`2997`: fix DictDB default size limit
720 * :ghpull:`3033`: on resume, print server info again
720 * :ghpull:`3033`: on resume, print server info again
721 * :ghpull:`3062`: test double pyximport
721 * :ghpull:`3062`: test double pyximport
722 * :ghpull:`3046`: cast kernel cwd to bytes on Python 2 on Windows
722 * :ghpull:`3046`: cast kernel cwd to bytes on Python 2 on Windows
723 * :ghpull:`3038`: remove xml from notebook magic docstrings
723 * :ghpull:`3038`: remove xml from notebook magic docstrings
724 * :ghpull:`3032`: fix time format to international time format
724 * :ghpull:`3032`: fix time format to international time format
725 * :ghpull:`3022`: Fix test for Windows
725 * :ghpull:`3022`: Fix test for Windows
726 * :ghpull:`3024`: changed instances of 'outout' to 'output' in alt texts
726 * :ghpull:`3024`: changed instances of 'outout' to 'output' in alt texts
727 * :ghpull:`3013`: py3 workaround for reload in cythonmagic
727 * :ghpull:`3013`: py3 workaround for reload in cythonmagic
728 * :ghpull:`2961`: time magic: shorten unnecessary output on windows
728 * :ghpull:`2961`: time magic: shorten unnecessary output on windows
729 * :ghpull:`2987`: fix local files examples in markdown
729 * :ghpull:`2987`: fix local files examples in markdown
730 * :ghpull:`2998`: fix css in .output_area pre
730 * :ghpull:`2998`: fix css in .output_area pre
731 * :ghpull:`3003`: add $include /etc/inputrc to suggested ~/.inputrc
731 * :ghpull:`3003`: add $include /etc/inputrc to suggested ~/.inputrc
732 * :ghpull:`2957`: Refactor qt import logic. Fixes #2955
732 * :ghpull:`2957`: Refactor qt import logic. Fixes #2955
733 * :ghpull:`2994`: expanduser on %%file targets
733 * :ghpull:`2994`: expanduser on %%file targets
734 * :ghpull:`2983`: fix run-all (that-> this)
734 * :ghpull:`2983`: fix run-all (that-> this)
735 * :ghpull:`2964`: fix count when testing composite error output
735 * :ghpull:`2964`: fix count when testing composite error output
736 * :ghpull:`2967`: shows entire session history when only startsess is given
736 * :ghpull:`2967`: shows entire session history when only startsess is given
737 * :ghpull:`2942`: Move CM IPython theme out of codemirror folder
737 * :ghpull:`2942`: Move CM IPython theme out of codemirror folder
738 * :ghpull:`2929`: Cleanup cell insertion
738 * :ghpull:`2929`: Cleanup cell insertion
739 * :ghpull:`2933`: Minordocupdate
739 * :ghpull:`2933`: Minordocupdate
740 * :ghpull:`2968`: fix notebook deletion.
740 * :ghpull:`2968`: fix notebook deletion.
741 * :ghpull:`2966`: Added assert msg to extract_hist_ranges()
741 * :ghpull:`2966`: Added assert msg to extract_hist_ranges()
742 * :ghpull:`2959`: Add command to trim the history database.
742 * :ghpull:`2959`: Add command to trim the history database.
743 * :ghpull:`2681`: Don't enable pylab mode, when matplotlib is not importable
743 * :ghpull:`2681`: Don't enable pylab mode, when matplotlib is not importable
744 * :ghpull:`2901`: Fix inputhook_wx on osx
744 * :ghpull:`2901`: Fix inputhook_wx on osx
745 * :ghpull:`2871`: truncate potentially long CompositeErrors
745 * :ghpull:`2871`: truncate potentially long CompositeErrors
746 * :ghpull:`2951`: use istype on lists/tuples
746 * :ghpull:`2951`: use istype on lists/tuples
747 * :ghpull:`2946`: fix qtconsole history logic for end-of-line
747 * :ghpull:`2946`: fix qtconsole history logic for end-of-line
748 * :ghpull:`2954`: fix logic for append_javascript
748 * :ghpull:`2954`: fix logic for append_javascript
749 * :ghpull:`2941`: fix baseUrl
749 * :ghpull:`2941`: fix baseUrl
750 * :ghpull:`2903`: Specify toggle value on cell line number
750 * :ghpull:`2903`: Specify toggle value on cell line number
751 * :ghpull:`2911`: display order in output area configurable
751 * :ghpull:`2911`: display order in output area configurable
752 * :ghpull:`2897`: Dont rely on BaseProjectUrl data in body tag
752 * :ghpull:`2897`: Dont rely on BaseProjectUrl data in body tag
753 * :ghpull:`2894`: Cm configurable
753 * :ghpull:`2894`: Cm configurable
754 * :ghpull:`2927`: next release will be 1.0
754 * :ghpull:`2927`: next release will be 1.0
755 * :ghpull:`2932`: Simplify using notebook static files from external code
755 * :ghpull:`2932`: Simplify using notebook static files from external code
756 * :ghpull:`2915`: added small config section to notebook docs page
756 * :ghpull:`2915`: added small config section to notebook docs page
757 * :ghpull:`2924`: safe_run_module: Silence SystemExit codes 0 and None.
757 * :ghpull:`2924`: safe_run_module: Silence SystemExit codes 0 and None.
758 * :ghpull:`2906`: Unpatch/Monkey patch CM
758 * :ghpull:`2906`: Unpatch/Monkey patch CM
759 * :ghpull:`2921`: add menu item for undo delete cell
759 * :ghpull:`2921`: add menu item for undo delete cell
760 * :ghpull:`2917`: Don't add logging handler if one already exists.
760 * :ghpull:`2917`: Don't add logging handler if one already exists.
761 * :ghpull:`2910`: Respect DB_IP and DB_PORT in mongodb tests
761 * :ghpull:`2910`: Respect DB_IP and DB_PORT in mongodb tests
762 * :ghpull:`2926`: Don't die if stderr/stdout do not support set_parent() #2925
762 * :ghpull:`2926`: Don't die if stderr/stdout do not support set_parent() #2925
763 * :ghpull:`2885`: get monospace pager back
763 * :ghpull:`2885`: get monospace pager back
764 * :ghpull:`2876`: fix celltoolbar layout on FF
764 * :ghpull:`2876`: fix celltoolbar layout on FF
765 * :ghpull:`2904`: Skip remaining IPC test on Windows
765 * :ghpull:`2904`: Skip remaining IPC test on Windows
766 * :ghpull:`2908`: fix last remaining KernelApp reference
766 * :ghpull:`2908`: fix last remaining KernelApp reference
767 * :ghpull:`2905`: fix a few remaining KernelApp/IPKernelApp changes
767 * :ghpull:`2905`: fix a few remaining KernelApp/IPKernelApp changes
768 * :ghpull:`2900`: Don't assume test case for %time will finish in 0 time
768 * :ghpull:`2900`: Don't assume test case for %time will finish in 0 time
769 * :ghpull:`2893`: exclude fabfile from tests
769 * :ghpull:`2893`: exclude fabfile from tests
770 * :ghpull:`2884`: Correct import for kernelmanager on Windows
770 * :ghpull:`2884`: Correct import for kernelmanager on Windows
771 * :ghpull:`2882`: Utils cleanup
771 * :ghpull:`2882`: Utils cleanup
772 * :ghpull:`2883`: Don't call ast.fix_missing_locations unless the AST could have been modified
772 * :ghpull:`2883`: Don't call ast.fix_missing_locations unless the AST could have been modified
773 * :ghpull:`2855`: time(it) magic: Implement minutes/hour formatting and "%%time" cell magic
773 * :ghpull:`2855`: time(it) magic: Implement minutes/hour formatting and "%%time" cell magic
774 * :ghpull:`2874`: Empty cell warnings
774 * :ghpull:`2874`: Empty cell warnings
775 * :ghpull:`2819`: tweak history prefix search (up/^p) in qtconsole
775 * :ghpull:`2819`: tweak history prefix search (up/^p) in qtconsole
776 * :ghpull:`2868`: Import performance
776 * :ghpull:`2868`: Import performance
777 * :ghpull:`2877`: minor css fixes
777 * :ghpull:`2877`: minor css fixes
778 * :ghpull:`2880`: update examples docs with kernel move
778 * :ghpull:`2880`: update examples docs with kernel move
779 * :ghpull:`2878`: Pass host environment on to kernel
779 * :ghpull:`2878`: Pass host environment on to kernel
780 * :ghpull:`2599`: func_kw_complete for builtin and cython with embededsignature=True using docstring
780 * :ghpull:`2599`: func_kw_complete for builtin and cython with embededsignature=True using docstring
781 * :ghpull:`2792`: Add key "unique" to history_request protocol
781 * :ghpull:`2792`: Add key "unique" to history_request protocol
782 * :ghpull:`2872`: fix payload keys
782 * :ghpull:`2872`: fix payload keys
783 * :ghpull:`2869`: Fixing styling of toolbar selects on FF.
783 * :ghpull:`2869`: Fixing styling of toolbar selects on FF.
784 * :ghpull:`2708`: Less css
784 * :ghpull:`2708`: Less css
785 * :ghpull:`2854`: Move kernel code into IPython.kernel
785 * :ghpull:`2854`: Move kernel code into IPython.kernel
786 * :ghpull:`2864`: Fix %run -t -N<N> TypeError
786 * :ghpull:`2864`: Fix %run -t -N<N> TypeError
787 * :ghpull:`2852`: future pyzmq compatibility
787 * :ghpull:`2852`: future pyzmq compatibility
788 * :ghpull:`2863`: whatsnew/version0.9.txt: Fix '~./ipython' -> '~/.ipython' typo
788 * :ghpull:`2863`: whatsnew/version0.9.txt: Fix '~./ipython' -> '~/.ipython' typo
789 * :ghpull:`2861`: add missing KernelManager to ConsoleApp class list
789 * :ghpull:`2861`: add missing KernelManager to ConsoleApp class list
790 * :ghpull:`2850`: Consolidate host IP detection in utils.localinterfaces
790 * :ghpull:`2850`: Consolidate host IP detection in utils.localinterfaces
791 * :ghpull:`2859`: Correct docstring of ipython.py
791 * :ghpull:`2859`: Correct docstring of ipython.py
792 * :ghpull:`2831`: avoid string version comparisons in external.qt
792 * :ghpull:`2831`: avoid string version comparisons in external.qt
793 * :ghpull:`2844`: this should address the failure in #2732
793 * :ghpull:`2844`: this should address the failure in #2732
794 * :ghpull:`2849`: utils/data: Use list comprehension for uniq_stable()
794 * :ghpull:`2849`: utils/data: Use list comprehension for uniq_stable()
795 * :ghpull:`2839`: add jinja to install docs / setup.py
795 * :ghpull:`2839`: add jinja to install docs / setup.py
796 * :ghpull:`2841`: Miscellaneous docs fixes
796 * :ghpull:`2841`: Miscellaneous docs fixes
797 * :ghpull:`2811`: Still more KernelManager cleanup
797 * :ghpull:`2811`: Still more KernelManager cleanup
798 * :ghpull:`2820`: add '=' to greedy completer delims
798 * :ghpull:`2820`: add '=' to greedy completer delims
799 * :ghpull:`2818`: log user tracebacks in the kernel (INFO-level)
799 * :ghpull:`2818`: log user tracebacks in the kernel (INFO-level)
800 * :ghpull:`2828`: Clean up notebook Javascript
800 * :ghpull:`2828`: Clean up notebook Javascript
801 * :ghpull:`2829`: avoid comparison error in dictdb hub history
801 * :ghpull:`2829`: avoid comparison error in dictdb hub history
802 * :ghpull:`2830`: BUG: Opening parenthesis after non-callable raises ValueError
802 * :ghpull:`2830`: BUG: Opening parenthesis after non-callable raises ValueError
803 * :ghpull:`2718`: try to fallback to pysqlite2.dbapi2 as sqlite3 in core.history
803 * :ghpull:`2718`: try to fallback to pysqlite2.dbapi2 as sqlite3 in core.history
804 * :ghpull:`2816`: in %edit, don't save "last_call" unless last call succeeded
804 * :ghpull:`2816`: in %edit, don't save "last_call" unless last call succeeded
805 * :ghpull:`2817`: change ol format order
805 * :ghpull:`2817`: change ol format order
806 * :ghpull:`2537`: Organize example notebooks
806 * :ghpull:`2537`: Organize example notebooks
807 * :ghpull:`2815`: update release/authors
807 * :ghpull:`2815`: update release/authors
808 * :ghpull:`2808`: improve patience for slow Hub in client tests
808 * :ghpull:`2808`: improve patience for slow Hub in client tests
809 * :ghpull:`2812`: remove nonfunctional `-la` short arg in cython magic
809 * :ghpull:`2812`: remove nonfunctional `-la` short arg in cython magic
810 * :ghpull:`2810`: remove dead utils.upgradedir
810 * :ghpull:`2810`: remove dead utils.upgradedir
811 * :ghpull:`1671`: __future__ environments
811 * :ghpull:`1671`: __future__ environments
812 * :ghpull:`2804`: skip ipc tests on Windows
812 * :ghpull:`2804`: skip ipc tests on Windows
813 * :ghpull:`2789`: Fixing styling issues with CellToolbar.
813 * :ghpull:`2789`: Fixing styling issues with CellToolbar.
814 * :ghpull:`2805`: fix KeyError creating ZMQStreams in notebook
814 * :ghpull:`2805`: fix KeyError creating ZMQStreams in notebook
815 * :ghpull:`2775`: General cleanup of kernel manager code.
815 * :ghpull:`2775`: General cleanup of kernel manager code.
816 * :ghpull:`2340`: Initial Code to reduce parallel.Client caching
816 * :ghpull:`2340`: Initial Code to reduce parallel.Client caching
817 * :ghpull:`2799`: Exit code
817 * :ghpull:`2799`: Exit code
818 * :ghpull:`2800`: use `type(obj) is cls` as switch when canning
818 * :ghpull:`2800`: use `type(obj) is cls` as switch when canning
819 * :ghpull:`2801`: Fix a breakpoint bug
819 * :ghpull:`2801`: Fix a breakpoint bug
820 * :ghpull:`2795`: Remove outdated code from extensions.autoreload
820 * :ghpull:`2795`: Remove outdated code from extensions.autoreload
821 * :ghpull:`2796`: P3K: fix cookie parsing under Python 3.x (+ duplicate import is removed)
821 * :ghpull:`2796`: P3K: fix cookie parsing under Python 3.x (+ duplicate import is removed)
822 * :ghpull:`2724`: In-process kernel support (take 3)
822 * :ghpull:`2724`: In-process kernel support (take 3)
823 * :ghpull:`2687`: [WIP] Metaui slideshow
823 * :ghpull:`2687`: [WIP] Metaui slideshow
824 * :ghpull:`2788`: Chrome frame awareness
824 * :ghpull:`2788`: Chrome frame awareness
825 * :ghpull:`2649`: Add version_request/reply messaging protocol
825 * :ghpull:`2649`: Add version_request/reply messaging protocol
826 * :ghpull:`2753`: add `%%px --local` for local execution
826 * :ghpull:`2753`: add `%%px --local` for local execution
827 * :ghpull:`2783`: Prefilter shouldn't touch execution_count
827 * :ghpull:`2783`: Prefilter shouldn't touch execution_count
828 * :ghpull:`2333`: UI For Metadata
828 * :ghpull:`2333`: UI For Metadata
829 * :ghpull:`2396`: create a ipynbv3 json schema and a validator
829 * :ghpull:`2396`: create a ipynbv3 json schema and a validator
830 * :ghpull:`2757`: check for complete pyside presence before trying to import
830 * :ghpull:`2757`: check for complete pyside presence before trying to import
831 * :ghpull:`2782`: Allow the %run magic with '-b' to specify a file.
831 * :ghpull:`2782`: Allow the %run magic with '-b' to specify a file.
832 * :ghpull:`2778`: P3K: fix DeprecationWarning under Python 3.x
832 * :ghpull:`2778`: P3K: fix DeprecationWarning under Python 3.x
833 * :ghpull:`2776`: remove non-functional View.kill method
833 * :ghpull:`2776`: remove non-functional View.kill method
834 * :ghpull:`2755`: can interactively defined classes
834 * :ghpull:`2755`: can interactively defined classes
835 * :ghpull:`2774`: Removing unused code in the notebook MappingKernelManager.
835 * :ghpull:`2774`: Removing unused code in the notebook MappingKernelManager.
836 * :ghpull:`2773`: Fixed minor typo causing AttributeError to be thrown.
836 * :ghpull:`2773`: Fixed minor typo causing AttributeError to be thrown.
837 * :ghpull:`2609`: Add 'unique' option to history_request messaging protocol
837 * :ghpull:`2609`: Add 'unique' option to history_request messaging protocol
838 * :ghpull:`2769`: Allow shutdown when no engines are registered
838 * :ghpull:`2769`: Allow shutdown when no engines are registered
839 * :ghpull:`2766`: Define __file__ when we %edit a real file.
839 * :ghpull:`2766`: Define __file__ when we %edit a real file.
840 * :ghpull:`2476`: allow %edit <variable> to work when interactively defined
840 * :ghpull:`2476`: allow %edit <variable> to work when interactively defined
841 * :ghpull:`2763`: Reset readline delimiters after loading rmagic.
841 * :ghpull:`2763`: Reset readline delimiters after loading rmagic.
842 * :ghpull:`2460`: Better handling of `__file__` when running scripts.
842 * :ghpull:`2460`: Better handling of `__file__` when running scripts.
843 * :ghpull:`2617`: Fix for `units` argument. Adds a `res` argument.
843 * :ghpull:`2617`: Fix for `units` argument. Adds a `res` argument.
844 * :ghpull:`2738`: Unicode content crashes the pager (console)
844 * :ghpull:`2738`: Unicode content crashes the pager (console)
845 * :ghpull:`2749`: Tell Travis CI to test on Python 3.3 as well
845 * :ghpull:`2749`: Tell Travis CI to test on Python 3.3 as well
846 * :ghpull:`2744`: Don't show 'try %paste' message while using magics
846 * :ghpull:`2744`: Don't show 'try %paste' message while using magics
847 * :ghpull:`2728`: shift tab for tooltip
847 * :ghpull:`2728`: shift tab for tooltip
848 * :ghpull:`2741`: Add note to `%cython` Black-Scholes example warning of missing erf.
848 * :ghpull:`2741`: Add note to `%cython` Black-Scholes example warning of missing erf.
849 * :ghpull:`2743`: BUG: Octavemagic inline plots not working on Windows: Fixed
849 * :ghpull:`2743`: BUG: Octavemagic inline plots not working on Windows: Fixed
850 * :ghpull:`2740`: Following #2737 this error is now a name error
850 * :ghpull:`2740`: Following #2737 this error is now a name error
851 * :ghpull:`2737`: Rmagic: error message when moving an non-existant variable from python to R
851 * :ghpull:`2737`: Rmagic: error message when moving an non-existant variable from python to R
852 * :ghpull:`2723`: diverse fixes for project url
852 * :ghpull:`2723`: diverse fixes for project url
853 * :ghpull:`2731`: %Rpush: Look for variables in the local scope first.
853 * :ghpull:`2731`: %Rpush: Look for variables in the local scope first.
854 * :ghpull:`2544`: Infinite loop when multiple debuggers have been attached.
854 * :ghpull:`2544`: Infinite loop when multiple debuggers have been attached.
855 * :ghpull:`2726`: Add qthelp docs creation
855 * :ghpull:`2726`: Add qthelp docs creation
856 * :ghpull:`2730`: added blockquote CSS
856 * :ghpull:`2730`: added blockquote CSS
857 * :ghpull:`2729`: Fix Read the doc build, Again
857 * :ghpull:`2729`: Fix Read the doc build, Again
858 * :ghpull:`2446`: [alternate 2267] Offline mathjax
858 * :ghpull:`2446`: [alternate 2267] Offline mathjax
859 * :ghpull:`2716`: remove unexisting headings level
859 * :ghpull:`2716`: remove unexisting headings level
860 * :ghpull:`2717`: One liner to fix debugger printing stack traces when lines of context are larger than source.
860 * :ghpull:`2717`: One liner to fix debugger printing stack traces when lines of context are larger than source.
861 * :ghpull:`2713`: Doc bugfix: user_ns is not an attribute of Magic objects.
861 * :ghpull:`2713`: Doc bugfix: user_ns is not an attribute of Magic objects.
862 * :ghpull:`2690`: Fix 'import '... completion for py3 & egg files.
862 * :ghpull:`2690`: Fix 'import '... completion for py3 & egg files.
863 * :ghpull:`2691`: Document OpenMP in %%cython magic
863 * :ghpull:`2691`: Document OpenMP in %%cython magic
864 * :ghpull:`2699`: fix jinja2 rendering for password protected notebooks
864 * :ghpull:`2699`: fix jinja2 rendering for password protected notebooks
865 * :ghpull:`2700`: Skip notebook testing if jinja2 is not available.
865 * :ghpull:`2700`: Skip notebook testing if jinja2 is not available.
866 * :ghpull:`2692`: Add %%cython magics to generated documentation.
866 * :ghpull:`2692`: Add %%cython magics to generated documentation.
867 * :ghpull:`2685`: Fix pretty print of types when `__module__` is not available.
867 * :ghpull:`2685`: Fix pretty print of types when `__module__` is not available.
868 * :ghpull:`2686`: Fix tox.ini
868 * :ghpull:`2686`: Fix tox.ini
869 * :ghpull:`2604`: Backslashes are misinterpreted as escape-sequences by the R-interpreter.
869 * :ghpull:`2604`: Backslashes are misinterpreted as escape-sequences by the R-interpreter.
870 * :ghpull:`2689`: fix error in doc (arg->kwarg) and pep-8
870 * :ghpull:`2689`: fix error in doc (arg->kwarg) and pep-8
871 * :ghpull:`2683`: for downloads, replaced window.open with window.location.assign
871 * :ghpull:`2683`: for downloads, replaced window.open with window.location.assign
872 * :ghpull:`2659`: small bugs in js are fixed
872 * :ghpull:`2659`: small bugs in js are fixed
873 * :ghpull:`2363`: Refactor notebook templates to use Jinja2
873 * :ghpull:`2363`: Refactor notebook templates to use Jinja2
874 * :ghpull:`2662`: qtconsole: wrap argument list in tooltip to match width of text body
874 * :ghpull:`2662`: qtconsole: wrap argument list in tooltip to match width of text body
875 * :ghpull:`2328`: addition of classes to generate a link or list of links from files local to the IPython HTML notebook
875 * :ghpull:`2328`: addition of classes to generate a link or list of links from files local to the IPython HTML notebook
876 * :ghpull:`2668`: pylab_not_importable: Catch all exceptions, not just RuntimeErrors.
876 * :ghpull:`2668`: pylab_not_importable: Catch all exceptions, not just RuntimeErrors.
877 * :ghpull:`2663`: Fix issue #2660: parsing of help and version arguments
877 * :ghpull:`2663`: Fix issue #2660: parsing of help and version arguments
878 * :ghpull:`2656`: Fix irunner tests when $PYTHONSTARTUP is set
878 * :ghpull:`2656`: Fix irunner tests when $PYTHONSTARTUP is set
879 * :ghpull:`2312`: Add bracket matching to code cells in notebook
879 * :ghpull:`2312`: Add bracket matching to code cells in notebook
880 * :ghpull:`2571`: Start to document Javascript
880 * :ghpull:`2571`: Start to document Javascript
881 * :ghpull:`2641`: undefinied that -> this
881 * :ghpull:`2641`: undefinied that -> this
882 * :ghpull:`2638`: Fix %paste in Python 3 on Mac
882 * :ghpull:`2638`: Fix %paste in Python 3 on Mac
883 * :ghpull:`2301`: Ast transfomers
883 * :ghpull:`2301`: Ast transfomers
884 * :ghpull:`2616`: Revamp API docs
884 * :ghpull:`2616`: Revamp API docs
885 * :ghpull:`2572`: Make 'Paste Above' the default paste behavior.
885 * :ghpull:`2572`: Make 'Paste Above' the default paste behavior.
886 * :ghpull:`2574`: Fix #2244
886 * :ghpull:`2574`: Fix #2244
887 * :ghpull:`2582`: Fix displaying history when output cache is disabled.
887 * :ghpull:`2582`: Fix displaying history when output cache is disabled.
888 * :ghpull:`2591`: Fix for Issue #2584
888 * :ghpull:`2591`: Fix for Issue #2584
889 * :ghpull:`2526`: Don't kill paramiko tunnels when receiving ^C
889 * :ghpull:`2526`: Don't kill paramiko tunnels when receiving ^C
890 * :ghpull:`2559`: Add psource, pfile, pinfo2 commands to ipdb.
890 * :ghpull:`2559`: Add psource, pfile, pinfo2 commands to ipdb.
891 * :ghpull:`2546`: use 4 Pythons to build 4 Windows installers
891 * :ghpull:`2546`: use 4 Pythons to build 4 Windows installers
892 * :ghpull:`2561`: Fix display of plain text containing multiple carriage returns before line feed
892 * :ghpull:`2561`: Fix display of plain text containing multiple carriage returns before line feed
893 * :ghpull:`2549`: Add a simple 'undo' for cell deletion.
893 * :ghpull:`2549`: Add a simple 'undo' for cell deletion.
894 * :ghpull:`2525`: Add event to kernel execution/shell reply.
894 * :ghpull:`2525`: Add event to kernel execution/shell reply.
895 * :ghpull:`2554`: Avoid stopping in ipdb until we reach the main script.
895 * :ghpull:`2554`: Avoid stopping in ipdb until we reach the main script.
896 * :ghpull:`2404`: Option to limit search result in history magic command
896 * :ghpull:`2404`: Option to limit search result in history magic command
897 * :ghpull:`2294`: inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication
897 * :ghpull:`2294`: inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication
898 * :ghpull:`2233`: Refactored Drag and Drop Support in Qt Console
898 * :ghpull:`2233`: Refactored Drag and Drop Support in Qt Console
899 * :ghpull:`1747`: switch between hsplit and vsplit paging (request for feedback)
899 * :ghpull:`1747`: switch between hsplit and vsplit paging (request for feedback)
900 * :ghpull:`2530`: Adding time offsets to the video
900 * :ghpull:`2530`: Adding time offsets to the video
901 * :ghpull:`2542`: Allow starting IPython as `python -m IPython`.
901 * :ghpull:`2542`: Allow starting IPython as `python -m IPython`.
902 * :ghpull:`2534`: Do not unescape backslashes in Windows (shellglob)
902 * :ghpull:`2534`: Do not unescape backslashes in Windows (shellglob)
903 * :ghpull:`2517`: Improved MathJax, bug fixes
903 * :ghpull:`2517`: Improved MathJax, bug fixes
904 * :ghpull:`2511`: trigger default remote_profile_dir when profile_dir is set
904 * :ghpull:`2511`: trigger default remote_profile_dir when profile_dir is set
905 * :ghpull:`2491`: color is supported in ironpython
905 * :ghpull:`2491`: color is supported in ironpython
906 * :ghpull:`2462`: Track which extensions are loaded
906 * :ghpull:`2462`: Track which extensions are loaded
907 * :ghpull:`2464`: Locate URLs in text output and convert them to hyperlinks.
907 * :ghpull:`2464`: Locate URLs in text output and convert them to hyperlinks.
908 * :ghpull:`2490`: add ZMQInteractiveShell to IPEngineApp class list
908 * :ghpull:`2490`: add ZMQInteractiveShell to IPEngineApp class list
909 * :ghpull:`2498`: Don't catch tab press when something selected
909 * :ghpull:`2498`: Don't catch tab press when something selected
910 * :ghpull:`2527`: Run All Above and Run All Below
910 * :ghpull:`2527`: Run All Above and Run All Below
911 * :ghpull:`2513`: add GitHub uploads to release script
911 * :ghpull:`2513`: add GitHub uploads to release script
912 * :ghpull:`2529`: Windows aware tests for shellglob
912 * :ghpull:`2529`: Windows aware tests for shellglob
913 * :ghpull:`2478`: Fix doctest_run_option_parser for Windows
913 * :ghpull:`2478`: Fix doctest_run_option_parser for Windows
914 * :ghpull:`2519`: clear In[ ] prompt numbers again
914 * :ghpull:`2519`: clear In[ ] prompt numbers again
915 * :ghpull:`2467`: Clickable links
915 * :ghpull:`2467`: Clickable links
916 * :ghpull:`2500`: Add `encoding` attribute to `OutStream` class.
916 * :ghpull:`2500`: Add `encoding` attribute to `OutStream` class.
917 * :ghpull:`2349`: ENH: added StackExchange-style MathJax filtering
917 * :ghpull:`2349`: ENH: added StackExchange-style MathJax filtering
918 * :ghpull:`2503`: Fix traceback handling of SyntaxErrors without line numbers.
918 * :ghpull:`2503`: Fix traceback handling of SyntaxErrors without line numbers.
919 * :ghpull:`2492`: add missing 'qtconsole' extras_require
919 * :ghpull:`2492`: add missing 'qtconsole' extras_require
920 * :ghpull:`2480`: Add deprecation warnings for sympyprinting
920 * :ghpull:`2480`: Add deprecation warnings for sympyprinting
921 * :ghpull:`2334`: Make the ipengine monitor the ipcontroller heartbeat and die if the ipcontroller goes down
921 * :ghpull:`2334`: Make the ipengine monitor the ipcontroller heartbeat and die if the ipcontroller goes down
922 * :ghpull:`2479`: use new _winapi instead of removed _subprocess
922 * :ghpull:`2479`: use new _winapi instead of removed _subprocess
923 * :ghpull:`2474`: fix bootstrap name conflicts
923 * :ghpull:`2474`: fix bootstrap name conflicts
924 * :ghpull:`2469`: Treat __init__.pyc same as __init__.py in module_list
924 * :ghpull:`2469`: Treat __init__.pyc same as __init__.py in module_list
925 * :ghpull:`2165`: Add -g option to %run to glob expand arguments
925 * :ghpull:`2165`: Add -g option to %run to glob expand arguments
926 * :ghpull:`2468`: Tell git to ignore __pycache__ directories.
926 * :ghpull:`2468`: Tell git to ignore __pycache__ directories.
927 * :ghpull:`2421`: Some notebook tweaks.
927 * :ghpull:`2421`: Some notebook tweaks.
928 * :ghpull:`2291`: Remove old plugin system
928 * :ghpull:`2291`: Remove old plugin system
929 * :ghpull:`2127`: Ability to build toolbar in JS
929 * :ghpull:`2127`: Ability to build toolbar in JS
930 * :ghpull:`2445`: changes for ironpython
930 * :ghpull:`2445`: changes for ironpython
931 * :ghpull:`2420`: Pass ipython_dir to __init__() method of TerminalInteractiveShell's superclass.
931 * :ghpull:`2420`: Pass ipython_dir to __init__() method of TerminalInteractiveShell's superclass.
932 * :ghpull:`2432`: Revert #1831, the `__file__` injection in safe_execfile / safe_execfile_ipy.
932 * :ghpull:`2432`: Revert #1831, the `__file__` injection in safe_execfile / safe_execfile_ipy.
933 * :ghpull:`2216`: Autochange highlight with cell magics
933 * :ghpull:`2216`: Autochange highlight with cell magics
934 * :ghpull:`1946`: Add image message handler in ZMQTerminalInteractiveShell
934 * :ghpull:`1946`: Add image message handler in ZMQTerminalInteractiveShell
935 * :ghpull:`2424`: skip find_cmd when setting up script magics
935 * :ghpull:`2424`: skip find_cmd when setting up script magics
936 * :ghpull:`2389`: Catch sqlite DatabaseErrors in more places when reading the history database
936 * :ghpull:`2389`: Catch sqlite DatabaseErrors in more places when reading the history database
937 * :ghpull:`2395`: Don't catch ImportError when trying to unpack module functions
937 * :ghpull:`2395`: Don't catch ImportError when trying to unpack module functions
938 * :ghpull:`1868`: enable IPC transport for kernels
938 * :ghpull:`1868`: enable IPC transport for kernels
939 * :ghpull:`2437`: don't let log cleanup prevent engine start
939 * :ghpull:`2437`: don't let log cleanup prevent engine start
940 * :ghpull:`2441`: `sys.maxsize` is the maximum length of a container.
940 * :ghpull:`2441`: `sys.maxsize` is the maximum length of a container.
941 * :ghpull:`2442`: allow iptest to be interrupted
941 * :ghpull:`2442`: allow iptest to be interrupted
942 * :ghpull:`2240`: fix message built for engine dying during task
942 * :ghpull:`2240`: fix message built for engine dying during task
943 * :ghpull:`2369`: Block until kernel termination after sending a kill signal
943 * :ghpull:`2369`: Block until kernel termination after sending a kill signal
944 * :ghpull:`2439`: Py3k: Octal (0777 -> 0o777)
944 * :ghpull:`2439`: Py3k: Octal (0777 -> 0o777)
945 * :ghpull:`2326`: Detachable pager in notebook.
945 * :ghpull:`2326`: Detachable pager in notebook.
946 * :ghpull:`2377`: Fix installation of man pages in Python 3
946 * :ghpull:`2377`: Fix installation of man pages in Python 3
947 * :ghpull:`2407`: add IPython version to message headers
947 * :ghpull:`2407`: add IPython version to message headers
948 * :ghpull:`2408`: Fix Issue #2366
948 * :ghpull:`2408`: Fix Issue #2366
949 * :ghpull:`2405`: clarify TaskScheduler.hwm doc
949 * :ghpull:`2405`: clarify TaskScheduler.hwm doc
950 * :ghpull:`2399`: IndentationError display
950 * :ghpull:`2399`: IndentationError display
951 * :ghpull:`2400`: Add scroll_to_cell(cell_number) to the notebook
951 * :ghpull:`2400`: Add scroll_to_cell(cell_number) to the notebook
952 * :ghpull:`2401`: unmock read-the-docs modules
952 * :ghpull:`2401`: unmock read-the-docs modules
953 * :ghpull:`2311`: always perform requested trait assignments
953 * :ghpull:`2311`: always perform requested trait assignments
954 * :ghpull:`2393`: New option `n` to limit history search hits
954 * :ghpull:`2393`: New option `n` to limit history search hits
955 * :ghpull:`2386`: Adapt inline backend to changes in matplotlib
955 * :ghpull:`2386`: Adapt inline backend to changes in matplotlib
956 * :ghpull:`2392`: Remove suspicious double quote
956 * :ghpull:`2392`: Remove suspicious double quote
957 * :ghpull:`2387`: Added -L library search path to cythonmagic cell magic
957 * :ghpull:`2387`: Added -L library search path to cythonmagic cell magic
958 * :ghpull:`2370`: qtconsole: Create a prompt newline by inserting a new block (w/o formatting)
958 * :ghpull:`2370`: qtconsole: Create a prompt newline by inserting a new block (w/o formatting)
959 * :ghpull:`1715`: Fix for #1688, traceback-unicode issue
959 * :ghpull:`1715`: Fix for #1688, traceback-unicode issue
960 * :ghpull:`2378`: use Singleton.instance() for embed() instead of manual global
960 * :ghpull:`2378`: use Singleton.instance() for embed() instead of manual global
961 * :ghpull:`2373`: fix missing imports in core.interactiveshell
961 * :ghpull:`2373`: fix missing imports in core.interactiveshell
962 * :ghpull:`2368`: remove notification widget leftover
962 * :ghpull:`2368`: remove notification widget leftover
963 * :ghpull:`2327`: Parallel: Support get/set of nested objects in view (e.g. dv['a.b'])
963 * :ghpull:`2327`: Parallel: Support get/set of nested objects in view (e.g. dv['a.b'])
964 * :ghpull:`2362`: Clean up ProgressBar class in example notebook
964 * :ghpull:`2362`: Clean up ProgressBar class in example notebook
965 * :ghpull:`2346`: Extra xterm identification in set_term_title
965 * :ghpull:`2346`: Extra xterm identification in set_term_title
966 * :ghpull:`2352`: Notebook: Store the username in a cookie whose name is unique.
966 * :ghpull:`2352`: Notebook: Store the username in a cookie whose name is unique.
967 * :ghpull:`2358`: add backport_pr to tools
967 * :ghpull:`2358`: add backport_pr to tools
968 * :ghpull:`2365`: fix names of notebooks for download/save
968 * :ghpull:`2365`: fix names of notebooks for download/save
969 * :ghpull:`2364`: make clients use 'location' properly (fixes #2361)
969 * :ghpull:`2364`: make clients use 'location' properly (fixes #2361)
970 * :ghpull:`2354`: Refactor notebook templates to use Jinja2
970 * :ghpull:`2354`: Refactor notebook templates to use Jinja2
971 * :ghpull:`2339`: add bash completion example
971 * :ghpull:`2339`: add bash completion example
972 * :ghpull:`2345`: Remove references to 'version' no longer in argparse. Github issue #2343.
972 * :ghpull:`2345`: Remove references to 'version' no longer in argparse. Github issue #2343.
973 * :ghpull:`2347`: adjust division error message checking to account for Python 3
973 * :ghpull:`2347`: adjust division error message checking to account for Python 3
974 * :ghpull:`2305`: RemoteError._render_traceback_ calls self.render_traceback
974 * :ghpull:`2305`: RemoteError._render_traceback_ calls self.render_traceback
975 * :ghpull:`2338`: Normalize line endings for ipexec_validate, fix for #2315.
975 * :ghpull:`2338`: Normalize line endings for ipexec_validate, fix for #2315.
976 * :ghpull:`2192`: Introduce Notification Area
976 * :ghpull:`2192`: Introduce Notification Area
977 * :ghpull:`2329`: Better error messages for common magic commands.
977 * :ghpull:`2329`: Better error messages for common magic commands.
978 * :ghpull:`2337`: ENH: added StackExchange-style MathJax filtering
978 * :ghpull:`2337`: ENH: added StackExchange-style MathJax filtering
979 * :ghpull:`2331`: update css for qtconsole in doc
979 * :ghpull:`2331`: update css for qtconsole in doc
980 * :ghpull:`2317`: adding cluster_id to parallel.Client.__init__
980 * :ghpull:`2317`: adding cluster_id to parallel.Client.__init__
981 * :ghpull:`2130`: Add -l option to %R magic to allow passing in of local namespace
981 * :ghpull:`2130`: Add -l option to %R magic to allow passing in of local namespace
982 * :ghpull:`2196`: Fix for bad command line argument to latex
982 * :ghpull:`2196`: Fix for bad command line argument to latex
983 * :ghpull:`2300`: bug fix: was crashing when sqlite3 is not installed
983 * :ghpull:`2300`: bug fix: was crashing when sqlite3 is not installed
984 * :ghpull:`2184`: Expose store_history to execute_request messages.
984 * :ghpull:`2184`: Expose store_history to execute_request messages.
985 * :ghpull:`2308`: Add welcome_message option to enable_pylab
985 * :ghpull:`2308`: Add welcome_message option to enable_pylab
986 * :ghpull:`2302`: Fix variable expansion on 'self'
986 * :ghpull:`2302`: Fix variable expansion on 'self'
987 * :ghpull:`2299`: Remove code from prefilter that duplicates functionality in inputsplitter
987 * :ghpull:`2299`: Remove code from prefilter that duplicates functionality in inputsplitter
988 * :ghpull:`2295`: allow pip install from github repository directly
988 * :ghpull:`2295`: allow pip install from github repository directly
989 * :ghpull:`2280`: fix SSH passwordless check for OpenSSH
989 * :ghpull:`2280`: fix SSH passwordless check for OpenSSH
990 * :ghpull:`2290`: nbmanager
990 * :ghpull:`2290`: nbmanager
991 * :ghpull:`2288`: s/assertEquals/assertEqual (again)
991 * :ghpull:`2288`: s/assertEquals/assertEqual (again)
992 * :ghpull:`2287`: Removed outdated dev docs.
992 * :ghpull:`2287`: Removed outdated dev docs.
993 * :ghpull:`2218`: Use redirect for new notebooks
993 * :ghpull:`2218`: Use redirect for new notebooks
994 * :ghpull:`2277`: nb: up/down arrow keys move to begin/end of line at top/bottom of cell
994 * :ghpull:`2277`: nb: up/down arrow keys move to begin/end of line at top/bottom of cell
995 * :ghpull:`2045`: Refactoring notebook managers and adding Azure backed storage.
995 * :ghpull:`2045`: Refactoring notebook managers and adding Azure backed storage.
996 * :ghpull:`2271`: use display instead of send_figure in inline backend hooks
996 * :ghpull:`2271`: use display instead of send_figure in inline backend hooks
997 * :ghpull:`2278`: allow disabling SQLite history
997 * :ghpull:`2278`: allow disabling SQLite history
998 * :ghpull:`2225`: Add "--annotate" option to `%%cython` magic.
998 * :ghpull:`2225`: Add "--annotate" option to `%%cython` magic.
999 * :ghpull:`2246`: serialize individual args/kwargs rather than the containers
999 * :ghpull:`2246`: serialize individual args/kwargs rather than the containers
1000 * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching.
1000 * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching.
1001 * :ghpull:`2270`: SSHLauncher tweaks
1001 * :ghpull:`2270`: SSHLauncher tweaks
1002 * :ghpull:`2269`: add missing location when disambiguating controller IP
1002 * :ghpull:`2269`: add missing location when disambiguating controller IP
1003 * :ghpull:`2263`: Allow docs to build on http://readthedocs.org/
1003 * :ghpull:`2263`: Allow docs to build on http://readthedocs.org/
1004 * :ghpull:`2256`: Adding data publication example notebook.
1004 * :ghpull:`2256`: Adding data publication example notebook.
1005 * :ghpull:`2255`: better flush iopub with AsyncResults
1005 * :ghpull:`2255`: better flush iopub with AsyncResults
1006 * :ghpull:`2261`: Fix: longest_substr([]) -> ''
1006 * :ghpull:`2261`: Fix: longest_substr([]) -> ''
1007 * :ghpull:`2260`: fix mpr again
1007 * :ghpull:`2260`: fix mpr again
1008 * :ghpull:`2242`: Document globbing in `%history -g <pattern>`.
1008 * :ghpull:`2242`: Document globbing in `%history -g <pattern>`.
1009 * :ghpull:`2250`: fix html in notebook example
1009 * :ghpull:`2250`: fix html in notebook example
1010 * :ghpull:`2245`: Fix regression in embed() from pull-request #2096.
1010 * :ghpull:`2245`: Fix regression in embed() from pull-request #2096.
1011 * :ghpull:`2248`: track sha of master in test_pr messages
1011 * :ghpull:`2248`: track sha of master in test_pr messages
1012 * :ghpull:`2238`: Fast tests
1012 * :ghpull:`2238`: Fast tests
1013 * :ghpull:`2211`: add data publication message
1013 * :ghpull:`2211`: add data publication message
1014 * :ghpull:`2236`: minor test_pr tweaks
1014 * :ghpull:`2236`: minor test_pr tweaks
1015 * :ghpull:`2231`: Improve Image format validation and add html width,height
1015 * :ghpull:`2231`: Improve Image format validation and add html width,height
1016 * :ghpull:`2232`: Reapply monkeypatch to inspect.findsource()
1016 * :ghpull:`2232`: Reapply monkeypatch to inspect.findsource()
1017 * :ghpull:`2235`: remove spurious print statement from setupbase.py
1017 * :ghpull:`2235`: remove spurious print statement from setupbase.py
1018 * :ghpull:`2222`: adjust how canning deals with import strings
1018 * :ghpull:`2222`: adjust how canning deals with import strings
1019 * :ghpull:`2224`: fix css typo
1019 * :ghpull:`2224`: fix css typo
1020 * :ghpull:`2223`: Custom tracebacks
1020 * :ghpull:`2223`: Custom tracebacks
1021 * :ghpull:`2214`: use KernelApp.exec_lines/files in IPEngineApp
1021 * :ghpull:`2214`: use KernelApp.exec_lines/files in IPEngineApp
1022 * :ghpull:`2199`: Wrap JS published by %%javascript in try/catch
1022 * :ghpull:`2199`: Wrap JS published by %%javascript in try/catch
1023 * :ghpull:`2212`: catch errors in markdown javascript
1023 * :ghpull:`2212`: catch errors in markdown javascript
1024 * :ghpull:`2190`: Update code mirror 2.22 to 2.32
1024 * :ghpull:`2190`: Update code mirror 2.22 to 2.32
1025 * :ghpull:`2200`: documentation build broken in bb429da5b
1025 * :ghpull:`2200`: documentation build broken in bb429da5b
1026 * :ghpull:`2194`: clean nan/inf in json_clean
1026 * :ghpull:`2194`: clean nan/inf in json_clean
1027 * :ghpull:`2198`: fix mpr for earlier git version
1027 * :ghpull:`2198`: fix mpr for earlier git version
1028 * :ghpull:`2175`: add FileFindHandler for Notebook static files
1028 * :ghpull:`2175`: add FileFindHandler for Notebook static files
1029 * :ghpull:`1990`: can func_defaults
1029 * :ghpull:`1990`: can func_defaults
1030 * :ghpull:`2069`: start improving serialization in parallel code
1030 * :ghpull:`2069`: start improving serialization in parallel code
1031 * :ghpull:`2202`: Create a unique & temporary IPYTHONDIR for each testing group.
1031 * :ghpull:`2202`: Create a unique & temporary IPYTHONDIR for each testing group.
1032 * :ghpull:`2204`: Work around lack of os.kill in win32.
1032 * :ghpull:`2204`: Work around lack of os.kill in win32.
1033 * :ghpull:`2148`: win32 iptest: Use subprocess.Popen() instead of os.system().
1033 * :ghpull:`2148`: win32 iptest: Use subprocess.Popen() instead of os.system().
1034 * :ghpull:`2179`: Pylab switch
1034 * :ghpull:`2179`: Pylab switch
1035 * :ghpull:`2124`: Add an API for registering magic aliases.
1035 * :ghpull:`2124`: Add an API for registering magic aliases.
1036 * :ghpull:`2169`: ipdb: pdef, pdoc, pinfo magics all broken
1036 * :ghpull:`2169`: ipdb: pdef, pdoc, pinfo magics all broken
1037 * :ghpull:`2174`: Ensure consistent indentation in `%magic`.
1037 * :ghpull:`2174`: Ensure consistent indentation in `%magic`.
1038 * :ghpull:`1930`: add size-limiting to the DictDB backend
1038 * :ghpull:`1930`: add size-limiting to the DictDB backend
1039 * :ghpull:`2189`: Fix IPython.lib.latextools for Python 3
1039 * :ghpull:`2189`: Fix IPython.lib.latextools for Python 3
1040 * :ghpull:`2186`: removed references to h5py dependence in octave magic documentation
1040 * :ghpull:`2186`: removed references to h5py dependence in octave magic documentation
1041 * :ghpull:`2183`: Include the kernel object in the event object passed to kernel events
1041 * :ghpull:`2183`: Include the kernel object in the event object passed to kernel events
1042 * :ghpull:`2185`: added test for %store, fixed storemagic
1042 * :ghpull:`2185`: added test for %store, fixed storemagic
1043 * :ghpull:`2138`: Use breqn.sty in dvipng backend if possible
1043 * :ghpull:`2138`: Use breqn.sty in dvipng backend if possible
1044 * :ghpull:`2182`: handle undefined param in notebooklist
1044 * :ghpull:`2182`: handle undefined param in notebooklist
1045 * :ghpull:`1831`: fix #1814 set __file__ when running .ipy files
1045 * :ghpull:`1831`: fix #1814 set __file__ when running .ipy files
1046 * :ghpull:`2051`: Add a metadata attribute to messages
1046 * :ghpull:`2051`: Add a metadata attribute to messages
1047 * :ghpull:`1471`: simplify IPython.parallel connections and enable Controller Resume
1047 * :ghpull:`1471`: simplify IPython.parallel connections and enable Controller Resume
1048 * :ghpull:`2181`: add %%javascript, %%svg, and %%latex display magics
1048 * :ghpull:`2181`: add %%javascript, %%svg, and %%latex display magics
1049 * :ghpull:`2116`: different images in 00_notebook-tour
1049 * :ghpull:`2116`: different images in 00_notebook-tour
1050 * :ghpull:`2092`: %prun: Restore `stats.stream` after running `print_stream`.
1050 * :ghpull:`2092`: %prun: Restore `stats.stream` after running `print_stream`.
1051 * :ghpull:`2159`: show message on notebook list if server is unreachable
1051 * :ghpull:`2159`: show message on notebook list if server is unreachable
1052 * :ghpull:`2176`: fix git mpr
1052 * :ghpull:`2176`: fix git mpr
1053 * :ghpull:`2152`: [qtconsole] Namespace not empty at startup
1053 * :ghpull:`2152`: [qtconsole] Namespace not empty at startup
1054 * :ghpull:`2177`: remove numpy install from travis/tox scripts
1054 * :ghpull:`2177`: remove numpy install from travis/tox scripts
1055 * :ghpull:`2090`: New keybinding for code cell execution + cell insertion
1055 * :ghpull:`2090`: New keybinding for code cell execution + cell insertion
1056 * :ghpull:`2160`: Updating the parallel options pricing example
1056 * :ghpull:`2160`: Updating the parallel options pricing example
1057 * :ghpull:`2168`: expand line in cell magics
1057 * :ghpull:`2168`: expand line in cell magics
1058 * :ghpull:`2170`: Fix tab completion with IPython.embed_kernel().
1058 * :ghpull:`2170`: Fix tab completion with IPython.embed_kernel().
1059 * :ghpull:`2096`: embed(): Default to the future compiler flags of the calling frame.
1059 * :ghpull:`2096`: embed(): Default to the future compiler flags of the calling frame.
1060 * :ghpull:`2163`: fix 'remote_profie_dir' typo in SSH launchers
1060 * :ghpull:`2163`: fix 'remote_profie_dir' typo in SSH launchers
1061 * :ghpull:`2158`: [2to3 compat ] Tuple params in func defs
1061 * :ghpull:`2158`: [2to3 compat ] Tuple params in func defs
1062 * :ghpull:`2089`: Fix unittest DeprecationWarnings
1062 * :ghpull:`2089`: Fix unittest DeprecationWarnings
1063 * :ghpull:`2142`: Refactor test_pr.py
1063 * :ghpull:`2142`: Refactor test_pr.py
1064 * :ghpull:`2140`: 2to3: Apply `has_key` fixer.
1064 * :ghpull:`2140`: 2to3: Apply `has_key` fixer.
1065 * :ghpull:`2131`: Add option append (-a) to %save
1065 * :ghpull:`2131`: Add option append (-a) to %save
1066 * :ghpull:`2117`: use explicit url in notebook example
1066 * :ghpull:`2117`: use explicit url in notebook example
1067 * :ghpull:`2133`: Tell git that *.py files contain Python code, for use in word-diffs.
1067 * :ghpull:`2133`: Tell git that ``*.py`` files contain Python code, for use in word-diffs.
1068 * :ghpull:`2134`: Apply 2to3 `next` fix.
1068 * :ghpull:`2134`: Apply 2to3 `next` fix.
1069 * :ghpull:`2126`: ipcluster broken with any batch launcher (PBS/LSF/SGE)
1069 * :ghpull:`2126`: ipcluster broken with any batch launcher (PBS/LSF/SGE)
1070 * :ghpull:`2104`: Windows make file for Sphinx documentation
1070 * :ghpull:`2104`: Windows make file for Sphinx documentation
1071 * :ghpull:`2074`: Make BG color of inline plot configurable
1071 * :ghpull:`2074`: Make BG color of inline plot configurable
1072 * :ghpull:`2123`: BUG: Look up the `_repr_pretty_` method on the class within the MRO rath...
1072 * :ghpull:`2123`: BUG: Look up the `_repr_pretty_` method on the class within the MRO rath...
1073 * :ghpull:`2100`: [in progress] python 2 and 3 compatibility without 2to3, second try
1073 * :ghpull:`2100`: [in progress] python 2 and 3 compatibility without 2to3, second try
1074 * :ghpull:`2128`: open notebook copy in different tabs
1074 * :ghpull:`2128`: open notebook copy in different tabs
1075 * :ghpull:`2073`: allows password and prefix for notebook
1075 * :ghpull:`2073`: allows password and prefix for notebook
1076 * :ghpull:`1993`: Print View
1076 * :ghpull:`1993`: Print View
1077 * :ghpull:`2086`: re-aliad %ed to %edit in qtconsole
1077 * :ghpull:`2086`: re-aliad %ed to %edit in qtconsole
1078 * :ghpull:`2110`: Fixes and improvements to the input splitter
1078 * :ghpull:`2110`: Fixes and improvements to the input splitter
1079 * :ghpull:`2101`: fix completer deletting newline
1079 * :ghpull:`2101`: fix completer deletting newline
1080 * :ghpull:`2102`: Fix logging on interactive shell.
1080 * :ghpull:`2102`: Fix logging on interactive shell.
1081 * :ghpull:`2088`: Fix (some) Python 3.2 ResourceWarnings
1081 * :ghpull:`2088`: Fix (some) Python 3.2 ResourceWarnings
1082 * :ghpull:`2064`: conform to pep 3110
1082 * :ghpull:`2064`: conform to pep 3110
1083 * :ghpull:`2076`: Skip notebook 'static' dir in test suite.
1083 * :ghpull:`2076`: Skip notebook 'static' dir in test suite.
1084 * :ghpull:`2063`: Remove umlauts so py3 installations on LANG=C systems succeed.
1084 * :ghpull:`2063`: Remove umlauts so py3 installations on LANG=C systems succeed.
1085 * :ghpull:`2068`: record sysinfo in sdist
1085 * :ghpull:`2068`: record sysinfo in sdist
1086 * :ghpull:`2067`: update tools/release_windows.py
1086 * :ghpull:`2067`: update tools/release_windows.py
1087 * :ghpull:`2065`: Fix parentheses typo
1087 * :ghpull:`2065`: Fix parentheses typo
1088 * :ghpull:`2062`: Remove duplicates and auto-generated files from repo.
1088 * :ghpull:`2062`: Remove duplicates and auto-generated files from repo.
1089 * :ghpull:`2061`: use explicit tuple in exception
1089 * :ghpull:`2061`: use explicit tuple in exception
1090 * :ghpull:`2060`: change minus to \- or \(hy in manpages
1090 * :ghpull:`2060`: change minus to \- or \(hy in manpages
1091
1091
1092 Issues (691):
1092 Issues (691):
1093
1093
1094 * :ghissue:`3940`: Install process documentation overhaul
1094 * :ghissue:`3940`: Install process documentation overhaul
1095 * :ghissue:`3946`: The PDF option for `--post` should work with lowercase
1095 * :ghissue:`3946`: The PDF option for `--post` should work with lowercase
1096 * :ghissue:`3957`: Notebook help page broken in Firefox
1096 * :ghissue:`3957`: Notebook help page broken in Firefox
1097 * :ghissue:`3894`: nbconvert test failure
1097 * :ghissue:`3894`: nbconvert test failure
1098 * :ghissue:`3887`: 1.0.0a1 shows blank screen in both firefox and chrome (windows 7)
1098 * :ghissue:`3887`: 1.0.0a1 shows blank screen in both firefox and chrome (windows 7)
1099 * :ghissue:`3703`: `nbconvert`: Output options -- names and documentataion
1099 * :ghissue:`3703`: `nbconvert`: Output options -- names and documentataion
1100 * :ghissue:`3931`: Tab completion not working during debugging in the notebook
1100 * :ghissue:`3931`: Tab completion not working during debugging in the notebook
1101 * :ghissue:`3936`: Ipcluster plugin is not working with Ipython 1.0dev
1101 * :ghissue:`3936`: Ipcluster plugin is not working with Ipython 1.0dev
1102 * :ghissue:`3941`: IPython Notebook kernel crash on Win7x64
1102 * :ghissue:`3941`: IPython Notebook kernel crash on Win7x64
1103 * :ghissue:`3926`: Ending Notebook renaming dialog with return creates new-line
1103 * :ghissue:`3926`: Ending Notebook renaming dialog with return creates new-line
1104 * :ghissue:`3932`: Incorrect empty docstring
1104 * :ghissue:`3932`: Incorrect empty docstring
1105 * :ghissue:`3928`: Passing variables to script from the workspace
1105 * :ghissue:`3928`: Passing variables to script from the workspace
1106 * :ghissue:`3774`: Notebooks with spaces in their names breaks nbconvert latex graphics
1106 * :ghissue:`3774`: Notebooks with spaces in their names breaks nbconvert latex graphics
1107 * :ghissue:`3916`: tornado needs its own check
1107 * :ghissue:`3916`: tornado needs its own check
1108 * :ghissue:`3915`: Link to Parallel examples "found on GitHub" broken in docs
1108 * :ghissue:`3915`: Link to Parallel examples "found on GitHub" broken in docs
1109 * :ghissue:`3895`: Keyboard shortcuts box in notebook doesn't fit the screen
1109 * :ghissue:`3895`: Keyboard shortcuts box in notebook doesn't fit the screen
1110 * :ghissue:`3912`: IPython.utils fails automated test for RC1 1.0.0
1110 * :ghissue:`3912`: IPython.utils fails automated test for RC1 1.0.0
1111 * :ghissue:`3636`: Code cell missing highlight on load
1111 * :ghissue:`3636`: Code cell missing highlight on load
1112 * :ghissue:`3897`: under Windows, "ipython3 nbconvert "C:/blabla/first_try.ipynb" --to latex --post PDF" POST processing action fails because of a bad parameter
1112 * :ghissue:`3897`: under Windows, "ipython3 nbconvert "C:/blabla/first_try.ipynb" --to latex --post PDF" POST processing action fails because of a bad parameter
1113 * :ghissue:`3900`: python3 install syntax errors (OS X 10.8.4)
1113 * :ghissue:`3900`: python3 install syntax errors (OS X 10.8.4)
1114 * :ghissue:`3899`: nbconvert to latex fails on notebooks with spaces in file name
1114 * :ghissue:`3899`: nbconvert to latex fails on notebooks with spaces in file name
1115 * :ghissue:`3881`: Temporary Working Directory Test Fails
1115 * :ghissue:`3881`: Temporary Working Directory Test Fails
1116 * :ghissue:`2750`: A way to freeze code cells in the notebook
1116 * :ghissue:`2750`: A way to freeze code cells in the notebook
1117 * :ghissue:`3893`: Resize Local Image Files in Notebook doesn't work
1117 * :ghissue:`3893`: Resize Local Image Files in Notebook doesn't work
1118 * :ghissue:`3823`: nbconvert on windows: tex and paths
1118 * :ghissue:`3823`: nbconvert on windows: tex and paths
1119 * :ghissue:`3885`: under Windows, "ipython3 nbconvert "C:/blabla/first_try.ipynb" --to latex" write "\" instead of "/" to reference file path in the .tex file
1119 * :ghissue:`3885`: under Windows, "ipython3 nbconvert "C:/blabla/first_try.ipynb" --to latex" write "\" instead of "/" to reference file path in the .tex file
1120 * :ghissue:`3889`: test_qt fails due to assertion error 'qt4' != 'qt'
1120 * :ghissue:`3889`: test_qt fails due to assertion error 'qt4' != 'qt'
1121 * :ghissue:`3890`: double post, disregard this issue
1121 * :ghissue:`3890`: double post, disregard this issue
1122 * :ghissue:`3689`: nbconvert, remaining tests
1122 * :ghissue:`3689`: nbconvert, remaining tests
1123 * :ghissue:`3874`: Up/Down keys don't work to "Search previous command history" (besides Ctrl-p/Ctrl-n)
1123 * :ghissue:`3874`: Up/Down keys don't work to "Search previous command history" (besides Ctrl-p/Ctrl-n)
1124 * :ghissue:`3853`: CodeMirror locks up in the notebook
1124 * :ghissue:`3853`: CodeMirror locks up in the notebook
1125 * :ghissue:`3862`: can only connect to an ipcluster started with v1.0.0-dev (master branch) using an older ipython (v0.13.2), but cannot connect using ipython (v1.0.0-dev)
1125 * :ghissue:`3862`: can only connect to an ipcluster started with v1.0.0-dev (master branch) using an older ipython (v0.13.2), but cannot connect using ipython (v1.0.0-dev)
1126 * :ghissue:`3869`: custom css not working.
1126 * :ghissue:`3869`: custom css not working.
1127 * :ghissue:`2960`: Keyboard shortcuts
1127 * :ghissue:`2960`: Keyboard shortcuts
1128 * :ghissue:`3795`: ipcontroller process goes to 100% CPU, ignores connection requests
1128 * :ghissue:`3795`: ipcontroller process goes to 100% CPU, ignores connection requests
1129 * :ghissue:`3553`: Ipython and pylab crashes in windows and canopy
1129 * :ghissue:`3553`: Ipython and pylab crashes in windows and canopy
1130 * :ghissue:`3837`: Cannot set custom mathjax url, crash notebook server.
1130 * :ghissue:`3837`: Cannot set custom mathjax url, crash notebook server.
1131 * :ghissue:`3808`: "Naming" releases ?
1131 * :ghissue:`3808`: "Naming" releases ?
1132 * :ghissue:`2431`: TypeError: must be string without null bytes, not str
1132 * :ghissue:`2431`: TypeError: must be string without null bytes, not str
1133 * :ghissue:`3856`: `?` at end of comment causes line to execute
1133 * :ghissue:`3856`: `?` at end of comment causes line to execute
1134 * :ghissue:`3731`: nbconvert: add logging for the different steps of nbconvert
1134 * :ghissue:`3731`: nbconvert: add logging for the different steps of nbconvert
1135 * :ghissue:`3835`: Markdown cells do not render correctly when mathjax is disabled
1135 * :ghissue:`3835`: Markdown cells do not render correctly when mathjax is disabled
1136 * :ghissue:`3843`: nbconvert to rst: leftover "In[ ]"
1136 * :ghissue:`3843`: nbconvert to rst: leftover "In[ ]"
1137 * :ghissue:`3799`: nbconvert: Ability to specify name of output file
1137 * :ghissue:`3799`: nbconvert: Ability to specify name of output file
1138 * :ghissue:`3726`: Document when IPython.start_ipython() should be used versus IPython.embed()
1138 * :ghissue:`3726`: Document when IPython.start_ipython() should be used versus IPython.embed()
1139 * :ghissue:`3778`: Add no more readonly view in what's new
1139 * :ghissue:`3778`: Add no more readonly view in what's new
1140 * :ghissue:`3754`: No Print View in Notebook in 1.0dev
1140 * :ghissue:`3754`: No Print View in Notebook in 1.0dev
1141 * :ghissue:`3798`: IPython 0.12.1 Crashes on autocompleting sqlalchemy.func.row_number properties
1141 * :ghissue:`3798`: IPython 0.12.1 Crashes on autocompleting sqlalchemy.func.row_number properties
1142 * :ghissue:`3811`: Opening notebook directly from the command line with multi-directory support installed
1142 * :ghissue:`3811`: Opening notebook directly from the command line with multi-directory support installed
1143 * :ghissue:`3775`: Annoying behavior when clicking on cell after execution (Ctrl+Enter)
1143 * :ghissue:`3775`: Annoying behavior when clicking on cell after execution (Ctrl+Enter)
1144 * :ghissue:`3809`: Possible to add some bpython features?
1144 * :ghissue:`3809`: Possible to add some bpython features?
1145 * :ghissue:`3810`: Printing the contents of an image file messes up shell text
1145 * :ghissue:`3810`: Printing the contents of an image file messes up shell text
1146 * :ghissue:`3702`: `nbconvert`: Default help message should be that of --help
1146 * :ghissue:`3702`: `nbconvert`: Default help message should be that of --help
1147 * :ghissue:`3735`: Nbconvert 1.0.0a1 does not take into account the pdf extensions in graphs
1147 * :ghissue:`3735`: Nbconvert 1.0.0a1 does not take into account the pdf extensions in graphs
1148 * :ghissue:`3719`: Bad strftime format, for windows, in nbconvert exporter
1148 * :ghissue:`3719`: Bad strftime format, for windows, in nbconvert exporter
1149 * :ghissue:`3786`: Zmq errors appearing with `Ctrl-C` in console/qtconsole
1149 * :ghissue:`3786`: Zmq errors appearing with `Ctrl-C` in console/qtconsole
1150 * :ghissue:`3019`: disappearing scrollbar on tooltip in Chrome 24 on Ubuntu 12.04
1150 * :ghissue:`3019`: disappearing scrollbar on tooltip in Chrome 24 on Ubuntu 12.04
1151 * :ghissue:`3785`: ipdb completely broken in Qt console
1151 * :ghissue:`3785`: ipdb completely broken in Qt console
1152 * :ghissue:`3796`: Document the meaning of milestone/issues-tags for users.
1152 * :ghissue:`3796`: Document the meaning of milestone/issues-tags for users.
1153 * :ghissue:`3788`: Do not auto show tooltip if docstring empty.
1153 * :ghissue:`3788`: Do not auto show tooltip if docstring empty.
1154 * :ghissue:`1366`: [Web page] No link to front page from documentation
1154 * :ghissue:`1366`: [Web page] No link to front page from documentation
1155 * :ghissue:`3739`: nbconvert (to slideshow) misses some of the math in markdown cells
1155 * :ghissue:`3739`: nbconvert (to slideshow) misses some of the math in markdown cells
1156 * :ghissue:`3768`: increase and make timeout configurable in console completion.
1156 * :ghissue:`3768`: increase and make timeout configurable in console completion.
1157 * :ghissue:`3724`: ipcluster only running on one cpu
1157 * :ghissue:`3724`: ipcluster only running on one cpu
1158 * :ghissue:`1592`: better message for unsupported nbformat
1158 * :ghissue:`1592`: better message for unsupported nbformat
1159 * :ghissue:`2049`: Can not stop "ipython kernel" on windows
1159 * :ghissue:`2049`: Can not stop "ipython kernel" on windows
1160 * :ghissue:`3757`: Need direct entry point to given notebook
1160 * :ghissue:`3757`: Need direct entry point to given notebook
1161 * :ghissue:`3745`: ImportError: cannot import name check_linecache_ipython
1161 * :ghissue:`3745`: ImportError: cannot import name check_linecache_ipython
1162 * :ghissue:`3701`: `nbconvert`: Final output file should be in same directory as input file
1162 * :ghissue:`3701`: `nbconvert`: Final output file should be in same directory as input file
1163 * :ghissue:`3738`: history -o works but history with -n produces identical results
1163 * :ghissue:`3738`: history -o works but history with -n produces identical results
1164 * :ghissue:`3740`: error when attempting to run 'make' in docs directory
1164 * :ghissue:`3740`: error when attempting to run 'make' in docs directory
1165 * :ghissue:`3737`: ipython nbconvert crashes with ValueError: Invalid format string.
1165 * :ghissue:`3737`: ipython nbconvert crashes with ValueError: Invalid format string.
1166 * :ghissue:`3730`: nbconvert: unhelpful error when pandoc isn't installed
1166 * :ghissue:`3730`: nbconvert: unhelpful error when pandoc isn't installed
1167 * :ghissue:`3718`: markdown cell cursor misaligned in notebook
1167 * :ghissue:`3718`: markdown cell cursor misaligned in notebook
1168 * :ghissue:`3710`: mutiple input fields for %debug in the notebook after resetting the kernel
1168 * :ghissue:`3710`: mutiple input fields for %debug in the notebook after resetting the kernel
1169 * :ghissue:`3713`: PyCharm has problems with IPython working inside PyPy created by virtualenv
1169 * :ghissue:`3713`: PyCharm has problems with IPython working inside PyPy created by virtualenv
1170 * :ghissue:`3712`: Code completion: Complete on dictionary keys
1170 * :ghissue:`3712`: Code completion: Complete on dictionary keys
1171 * :ghissue:`3680`: --pylab and --matplotlib flag
1171 * :ghissue:`3680`: --pylab and --matplotlib flag
1172 * :ghissue:`3698`: nbconvert: Unicode error with minus sign
1172 * :ghissue:`3698`: nbconvert: Unicode error with minus sign
1173 * :ghissue:`3693`: nbconvert does not process SVGs into PDFs
1173 * :ghissue:`3693`: nbconvert does not process SVGs into PDFs
1174 * :ghissue:`3688`: nbconvert, figures not extracting with Python 3.x
1174 * :ghissue:`3688`: nbconvert, figures not extracting with Python 3.x
1175 * :ghissue:`3542`: note new dependencies in docs / setup.py
1175 * :ghissue:`3542`: note new dependencies in docs / setup.py
1176 * :ghissue:`2556`: [pagedown] do not target_blank anchor link
1176 * :ghissue:`2556`: [pagedown] do not target_blank anchor link
1177 * :ghissue:`3684`: bad message when %pylab fails due import *other* than matplotlib
1177 * :ghissue:`3684`: bad message when %pylab fails due import *other* than matplotlib
1178 * :ghissue:`3682`: ipython notebook pylab inline import_all=False
1178 * :ghissue:`3682`: ipython notebook pylab inline import_all=False
1179 * :ghissue:`3596`: MathjaxUtils race condition?
1179 * :ghissue:`3596`: MathjaxUtils race condition?
1180 * :ghissue:`1540`: Comment/uncomment selection in notebook
1180 * :ghissue:`1540`: Comment/uncomment selection in notebook
1181 * :ghissue:`2702`: frozen setup: permission denied for default ipython_dir
1181 * :ghissue:`2702`: frozen setup: permission denied for default ipython_dir
1182 * :ghissue:`3672`: allow_none on Number-like traits.
1182 * :ghissue:`3672`: allow_none on Number-like traits.
1183 * :ghissue:`2411`: add CONTRIBUTING.md
1183 * :ghissue:`2411`: add CONTRIBUTING.md
1184 * :ghissue:`481`: IPython terminal issue with Qt4Agg on XP SP3
1184 * :ghissue:`481`: IPython terminal issue with Qt4Agg on XP SP3
1185 * :ghissue:`2664`: How to preserve user variables from import clashing?
1185 * :ghissue:`2664`: How to preserve user variables from import clashing?
1186 * :ghissue:`3436`: enable_pylab(import_all=False) still imports np
1186 * :ghissue:`3436`: enable_pylab(import_all=False) still imports np
1187 * :ghissue:`2630`: lib.pylabtools.figsize : NameError when using Qt4Agg backend and %pylab magic.
1187 * :ghissue:`2630`: lib.pylabtools.figsize : NameError when using Qt4Agg backend and %pylab magic.
1188 * :ghissue:`3154`: Notebook: no event triggered when a Cell is created
1188 * :ghissue:`3154`: Notebook: no event triggered when a Cell is created
1189 * :ghissue:`3579`: Nbconvert: SVG are not transformed to PDF anymore
1189 * :ghissue:`3579`: Nbconvert: SVG are not transformed to PDF anymore
1190 * :ghissue:`3604`: MathJax rendering problem in `%%latex` cell
1190 * :ghissue:`3604`: MathJax rendering problem in `%%latex` cell
1191 * :ghissue:`3668`: AttributeError: 'BlockingKernelClient' object has no attribute 'started_channels'
1191 * :ghissue:`3668`: AttributeError: 'BlockingKernelClient' object has no attribute 'started_channels'
1192 * :ghissue:`3245`: SyntaxError: encoding declaration in Unicode string
1192 * :ghissue:`3245`: SyntaxError: encoding declaration in Unicode string
1193 * :ghissue:`3639`: %pylab inline in IPYTHON notebook throws "RuntimeError: Cannot activate multiple GUI eventloops"
1193 * :ghissue:`3639`: %pylab inline in IPYTHON notebook throws "RuntimeError: Cannot activate multiple GUI eventloops"
1194 * :ghissue:`3663`: frontend deprecation warnings
1194 * :ghissue:`3663`: frontend deprecation warnings
1195 * :ghissue:`3661`: run -m not behaving like python -m
1195 * :ghissue:`3661`: run -m not behaving like python -m
1196 * :ghissue:`3597`: re-do PR #3531 - allow markdown in Header cell
1196 * :ghissue:`3597`: re-do PR #3531 - allow markdown in Header cell
1197 * :ghissue:`3053`: Markdown in header cells is not rendered
1197 * :ghissue:`3053`: Markdown in header cells is not rendered
1198 * :ghissue:`3655`: IPython finding its way into pasted strings.
1198 * :ghissue:`3655`: IPython finding its way into pasted strings.
1199 * :ghissue:`3620`: uncaught errors in HTML output
1199 * :ghissue:`3620`: uncaught errors in HTML output
1200 * :ghissue:`3646`: get_dict() error
1200 * :ghissue:`3646`: get_dict() error
1201 * :ghissue:`3004`: `%load_ext rmagic` fails when legacy ipy_user_conf.py is installed (in ipython 0.13.1 / OSX 10.8)
1201 * :ghissue:`3004`: `%load_ext rmagic` fails when legacy ipy_user_conf.py is installed (in ipython 0.13.1 / OSX 10.8)
1202 * :ghissue:`3638`: setp() issue in ipython notebook with figure references
1202 * :ghissue:`3638`: setp() issue in ipython notebook with figure references
1203 * :ghissue:`3634`: nbconvert reveal to pdf conversion ignores styling, prints only a single page.
1203 * :ghissue:`3634`: nbconvert reveal to pdf conversion ignores styling, prints only a single page.
1204 * :ghissue:`1307`: Remove pyreadline workarounds, we now require pyreadline >= 1.7.1
1204 * :ghissue:`1307`: Remove pyreadline workarounds, we now require pyreadline >= 1.7.1
1205 * :ghissue:`3316`: find_cmd test failure on Windows
1205 * :ghissue:`3316`: find_cmd test failure on Windows
1206 * :ghissue:`3494`: input() in notebook doesn't work in Python 3
1206 * :ghissue:`3494`: input() in notebook doesn't work in Python 3
1207 * :ghissue:`3427`: Deprecate `$` as mathjax delimiter
1207 * :ghissue:`3427`: Deprecate `$` as mathjax delimiter
1208 * :ghissue:`3625`: Pager does not open from button
1208 * :ghissue:`3625`: Pager does not open from button
1209 * :ghissue:`3149`: Miscellaneous small nbconvert feedback
1209 * :ghissue:`3149`: Miscellaneous small nbconvert feedback
1210 * :ghissue:`3617`: 256 color escapes support
1210 * :ghissue:`3617`: 256 color escapes support
1211 * :ghissue:`3609`: %pylab inline blows up for single process ipython
1211 * :ghissue:`3609`: %pylab inline blows up for single process ipython
1212 * :ghissue:`2934`: Publish the Interactive MPI Demo Notebook
1212 * :ghissue:`2934`: Publish the Interactive MPI Demo Notebook
1213 * :ghissue:`3614`: ansi escapes broken in master (ls --color)
1213 * :ghissue:`3614`: ansi escapes broken in master (ls --color)
1214 * :ghissue:`3610`: If you don't have markdown, python setup.py install says no pygments
1214 * :ghissue:`3610`: If you don't have markdown, python setup.py install says no pygments
1215 * :ghissue:`3547`: %run modules clobber each other
1215 * :ghissue:`3547`: %run modules clobber each other
1216 * :ghissue:`3602`: import_item fails when one tries to use DottedObjectName instead of a string
1216 * :ghissue:`3602`: import_item fails when one tries to use DottedObjectName instead of a string
1217 * :ghissue:`3563`: Duplicate tab completions in the notebook
1217 * :ghissue:`3563`: Duplicate tab completions in the notebook
1218 * :ghissue:`3599`: Problems trying to run IPython on python3 without installing...
1218 * :ghissue:`3599`: Problems trying to run IPython on python3 without installing...
1219 * :ghissue:`2937`: too long completion in notebook
1219 * :ghissue:`2937`: too long completion in notebook
1220 * :ghissue:`3479`: Write empty name for the notebooks
1220 * :ghissue:`3479`: Write empty name for the notebooks
1221 * :ghissue:`3505`: nbconvert: Failure in specifying user filter
1221 * :ghissue:`3505`: nbconvert: Failure in specifying user filter
1222 * :ghissue:`1537`: think a bit about namespaces
1222 * :ghissue:`1537`: think a bit about namespaces
1223 * :ghissue:`3124`: Long multiline strings in Notebook
1223 * :ghissue:`3124`: Long multiline strings in Notebook
1224 * :ghissue:`3464`: run -d message unclear
1224 * :ghissue:`3464`: run -d message unclear
1225 * :ghissue:`2706`: IPython 0.13.1 ignoring $PYTHONSTARTUP
1225 * :ghissue:`2706`: IPython 0.13.1 ignoring $PYTHONSTARTUP
1226 * :ghissue:`3587`: LaTeX escaping bug in nbconvert when exporting to HTML
1226 * :ghissue:`3587`: LaTeX escaping bug in nbconvert when exporting to HTML
1227 * :ghissue:`3213`: Long running notebook died with a coredump
1227 * :ghissue:`3213`: Long running notebook died with a coredump
1228 * :ghissue:`3580`: Running ipython with pypy on windows
1228 * :ghissue:`3580`: Running ipython with pypy on windows
1229 * :ghissue:`3573`: custom.js not working
1229 * :ghissue:`3573`: custom.js not working
1230 * :ghissue:`3544`: IPython.lib test failure on Windows
1230 * :ghissue:`3544`: IPython.lib test failure on Windows
1231 * :ghissue:`3352`: Install Sphinx extensions
1231 * :ghissue:`3352`: Install Sphinx extensions
1232 * :ghissue:`2971`: [notebook]user needs to press ctrl-c twice to stop notebook server should be put into terminal window
1232 * :ghissue:`2971`: [notebook]user needs to press ctrl-c twice to stop notebook server should be put into terminal window
1233 * :ghissue:`2413`: ipython3 qtconsole fails to install: ipython 0.13 has no such extra feature 'qtconsole'
1233 * :ghissue:`2413`: ipython3 qtconsole fails to install: ipython 0.13 has no such extra feature 'qtconsole'
1234 * :ghissue:`2618`: documentation is incorrect for install process
1234 * :ghissue:`2618`: documentation is incorrect for install process
1235 * :ghissue:`2595`: mac 10.8 qtconsole export history
1235 * :ghissue:`2595`: mac 10.8 qtconsole export history
1236 * :ghissue:`2586`: cannot store aliases
1236 * :ghissue:`2586`: cannot store aliases
1237 * :ghissue:`2714`: ipython qtconsole print unittest messages in console instead his own window.
1237 * :ghissue:`2714`: ipython qtconsole print unittest messages in console instead his own window.
1238 * :ghissue:`2669`: cython magic failing to work with openmp.
1238 * :ghissue:`2669`: cython magic failing to work with openmp.
1239 * :ghissue:`3256`: Vagrant pandas instance of iPython Notebook does not respect additional plotting arguments
1239 * :ghissue:`3256`: Vagrant pandas instance of iPython Notebook does not respect additional plotting arguments
1240 * :ghissue:`3010`: cython magic fail if cache dir is deleted while in session
1240 * :ghissue:`3010`: cython magic fail if cache dir is deleted while in session
1241 * :ghissue:`2044`: prune unused names from parallel.error
1241 * :ghissue:`2044`: prune unused names from parallel.error
1242 * :ghissue:`1145`: Online help utility broken in QtConsole
1242 * :ghissue:`1145`: Online help utility broken in QtConsole
1243 * :ghissue:`3439`: Markdown links no longer open in new window (with change from pagedown to marked)
1243 * :ghissue:`3439`: Markdown links no longer open in new window (with change from pagedown to marked)
1244 * :ghissue:`3476`: _margv for macros seems to be missing
1244 * :ghissue:`3476`: _margv for macros seems to be missing
1245 * :ghissue:`3499`: Add reveal.js library (version 2.4.0) inside IPython
1245 * :ghissue:`3499`: Add reveal.js library (version 2.4.0) inside IPython
1246 * :ghissue:`2771`: Wiki Migration to GitHub
1246 * :ghissue:`2771`: Wiki Migration to GitHub
1247 * :ghissue:`2887`: ipcontroller purging some engines during connect
1247 * :ghissue:`2887`: ipcontroller purging some engines during connect
1248 * :ghissue:`626`: Enable Resuming Controller
1248 * :ghissue:`626`: Enable Resuming Controller
1249 * :ghissue:`2824`: Kernel restarting after message "Kernel XXXX failed to respond to heartbeat"
1249 * :ghissue:`2824`: Kernel restarting after message "Kernel XXXX failed to respond to heartbeat"
1250 * :ghissue:`2823`: %%cython magic gives ImportError: dlopen(long_file_name.so, 2): image not found
1250 * :ghissue:`2823`: %%cython magic gives ImportError: dlopen(long_file_name.so, 2): image not found
1251 * :ghissue:`2891`: In IPython for Python 3, system site-packages comes before user site-packages
1251 * :ghissue:`2891`: In IPython for Python 3, system site-packages comes before user site-packages
1252 * :ghissue:`2928`: Add magic "watch" function (example)
1252 * :ghissue:`2928`: Add magic "watch" function (example)
1253 * :ghissue:`2931`: Problem rendering pandas dataframe in Firefox for Windows
1253 * :ghissue:`2931`: Problem rendering pandas dataframe in Firefox for Windows
1254 * :ghissue:`2939`: [notebook] Figure legend not shown in inline backend if ouside the box of the axes
1254 * :ghissue:`2939`: [notebook] Figure legend not shown in inline backend if ouside the box of the axes
1255 * :ghissue:`2972`: [notebook] in Markdown mode, press Enter key at the end of <some http link>, the next line is indented unexpectly
1255 * :ghissue:`2972`: [notebook] in Markdown mode, press Enter key at the end of <some http link>, the next line is indented unexpectly
1256 * :ghissue:`3069`: Instructions for installing IPython notebook on Windows
1256 * :ghissue:`3069`: Instructions for installing IPython notebook on Windows
1257 * :ghissue:`3444`: Encoding problem: cannot use if user's name is not ascii?
1257 * :ghissue:`3444`: Encoding problem: cannot use if user's name is not ascii?
1258 * :ghissue:`3335`: Reenable bracket matching
1258 * :ghissue:`3335`: Reenable bracket matching
1259 * :ghissue:`3386`: Magic %paste not working in Python 3.3.2. TypeError: Type str doesn't support the buffer API
1259 * :ghissue:`3386`: Magic %paste not working in Python 3.3.2. TypeError: Type str doesn't support the buffer API
1260 * :ghissue:`3543`: Exception shutting down kernel from notebook dashboard (0.13.1)
1260 * :ghissue:`3543`: Exception shutting down kernel from notebook dashboard (0.13.1)
1261 * :ghissue:`3549`: Codecell size changes with selection
1261 * :ghissue:`3549`: Codecell size changes with selection
1262 * :ghissue:`3445`: Adding newlines in %%latex cell
1262 * :ghissue:`3445`: Adding newlines in %%latex cell
1263 * :ghissue:`3237`: [notebook] Can't close a notebook without errors
1263 * :ghissue:`3237`: [notebook] Can't close a notebook without errors
1264 * :ghissue:`2916`: colon invokes auto(un)indent in markdown cells
1264 * :ghissue:`2916`: colon invokes auto(un)indent in markdown cells
1265 * :ghissue:`2167`: Indent and dedent in htmlnotebook
1265 * :ghissue:`2167`: Indent and dedent in htmlnotebook
1266 * :ghissue:`3545`: Notebook save button icon not clear
1266 * :ghissue:`3545`: Notebook save button icon not clear
1267 * :ghissue:`3534`: nbconvert incompatible with Windows?
1267 * :ghissue:`3534`: nbconvert incompatible with Windows?
1268 * :ghissue:`3489`: Update example notebook that raw_input is allowed
1268 * :ghissue:`3489`: Update example notebook that raw_input is allowed
1269 * :ghissue:`3396`: Notebook checkpoint time is displayed an hour out
1269 * :ghissue:`3396`: Notebook checkpoint time is displayed an hour out
1270 * :ghissue:`3261`: Empty revert to checkpoint menu if no checkpoint...
1270 * :ghissue:`3261`: Empty revert to checkpoint menu if no checkpoint...
1271 * :ghissue:`2984`: "print" magic does not work in Python 3
1271 * :ghissue:`2984`: "print" magic does not work in Python 3
1272 * :ghissue:`3524`: Issues with pyzmq and ipython on EPD update
1272 * :ghissue:`3524`: Issues with pyzmq and ipython on EPD update
1273 * :ghissue:`2434`: %store magic not auto-restoring
1273 * :ghissue:`2434`: %store magic not auto-restoring
1274 * :ghissue:`2720`: base_url and static path
1274 * :ghissue:`2720`: base_url and static path
1275 * :ghissue:`2234`: Update various low resolution graphics for retina displays
1275 * :ghissue:`2234`: Update various low resolution graphics for retina displays
1276 * :ghissue:`2842`: Remember passwords for pw-protected notebooks
1276 * :ghissue:`2842`: Remember passwords for pw-protected notebooks
1277 * :ghissue:`3244`: qtconsole: ValueError('close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr',)
1277 * :ghissue:`3244`: qtconsole: ValueError('close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr',)
1278 * :ghissue:`2215`: AsyncResult.wait(0) can hang waiting for the client to get results?
1278 * :ghissue:`2215`: AsyncResult.wait(0) can hang waiting for the client to get results?
1279 * :ghissue:`2268`: provide mean to retrieve static data path
1279 * :ghissue:`2268`: provide mean to retrieve static data path
1280 * :ghissue:`1905`: Expose UI for worksheets within each notebook
1280 * :ghissue:`1905`: Expose UI for worksheets within each notebook
1281 * :ghissue:`2380`: Qt inputhook prevents modal dialog boxes from displaying
1281 * :ghissue:`2380`: Qt inputhook prevents modal dialog boxes from displaying
1282 * :ghissue:`3185`: prettify on double //
1282 * :ghissue:`3185`: prettify on double //
1283 * :ghissue:`2821`: Test failure: IPython.parallel.tests.test_client.test_resubmit_header
1283 * :ghissue:`2821`: Test failure: IPython.parallel.tests.test_client.test_resubmit_header
1284 * :ghissue:`2475`: [Notebook] Line is deindented when typing eg a colon in markdown mode
1284 * :ghissue:`2475`: [Notebook] Line is deindented when typing eg a colon in markdown mode
1285 * :ghissue:`2470`: Do not destroy valid notebooks
1285 * :ghissue:`2470`: Do not destroy valid notebooks
1286 * :ghissue:`860`: Allow the standalone export of a notebook to HTML
1286 * :ghissue:`860`: Allow the standalone export of a notebook to HTML
1287 * :ghissue:`2652`: notebook with qt backend crashes at save image location popup
1287 * :ghissue:`2652`: notebook with qt backend crashes at save image location popup
1288 * :ghissue:`1587`: Improve kernel restarting in the notebook
1288 * :ghissue:`1587`: Improve kernel restarting in the notebook
1289 * :ghissue:`2710`: Saving a plot in Mac OS X backend crashes IPython
1289 * :ghissue:`2710`: Saving a plot in Mac OS X backend crashes IPython
1290 * :ghissue:`2596`: notebook "Last saved:" is misleading on file opening.
1290 * :ghissue:`2596`: notebook "Last saved:" is misleading on file opening.
1291 * :ghissue:`2671`: TypeError :NoneType when executed "ipython qtconsole" in windows console
1291 * :ghissue:`2671`: TypeError :NoneType when executed "ipython qtconsole" in windows console
1292 * :ghissue:`2703`: Notebook scrolling breaks after pager is shown
1292 * :ghissue:`2703`: Notebook scrolling breaks after pager is shown
1293 * :ghissue:`2803`: KernelManager and KernelClient should be two separate objects
1293 * :ghissue:`2803`: KernelManager and KernelClient should be two separate objects
1294 * :ghissue:`2693`: TerminalIPythonApp configuration fails without ipython_config.py
1294 * :ghissue:`2693`: TerminalIPythonApp configuration fails without ipython_config.py
1295 * :ghissue:`2531`: IPython 0.13.1 python 2 32-bit installer includes 64-bit ipython*.exe launchers in the scripts folder
1295 * :ghissue:`2531`: IPython 0.13.1 python 2 32-bit installer includes 64-bit ipython*.exe launchers in the scripts folder
1296 * :ghissue:`2520`: Control-C kills port forwarding
1296 * :ghissue:`2520`: Control-C kills port forwarding
1297 * :ghissue:`2279`: Setting `__file__` to None breaks Mayavi import
1297 * :ghissue:`2279`: Setting `__file__` to None breaks Mayavi import
1298 * :ghissue:`2161`: When logged into notebook, long titles are incorrectly positioned
1298 * :ghissue:`2161`: When logged into notebook, long titles are incorrectly positioned
1299 * :ghissue:`1292`: Notebook, Print view should not be editable...
1299 * :ghissue:`1292`: Notebook, Print view should not be editable...
1300 * :ghissue:`1731`: test parallel launchers
1300 * :ghissue:`1731`: test parallel launchers
1301 * :ghissue:`3227`: Improve documentation of ipcontroller and possible BUG
1301 * :ghissue:`3227`: Improve documentation of ipcontroller and possible BUG
1302 * :ghissue:`2896`: IPController very unstable
1302 * :ghissue:`2896`: IPController very unstable
1303 * :ghissue:`3517`: documentation build broken in head
1303 * :ghissue:`3517`: documentation build broken in head
1304 * :ghissue:`3522`: UnicodeDecodeError: 'ascii' codec can't decode byte on Pycharm on Windows
1304 * :ghissue:`3522`: UnicodeDecodeError: 'ascii' codec can't decode byte on Pycharm on Windows
1305 * :ghissue:`3448`: Please include MathJax fonts with IPython Notebook
1305 * :ghissue:`3448`: Please include MathJax fonts with IPython Notebook
1306 * :ghissue:`3519`: IPython Parallel map mysteriously turns pandas Series into numpy ndarray
1306 * :ghissue:`3519`: IPython Parallel map mysteriously turns pandas Series into numpy ndarray
1307 * :ghissue:`3345`: IPython embedded shells ask if I want to exit, but I set confirm_exit = False
1307 * :ghissue:`3345`: IPython embedded shells ask if I want to exit, but I set confirm_exit = False
1308 * :ghissue:`3509`: IPython won't close without asking "Are you sure?" in Firefox
1308 * :ghissue:`3509`: IPython won't close without asking "Are you sure?" in Firefox
1309 * :ghissue:`3471`: Notebook jinja2/markupsafe depedencies in manual
1309 * :ghissue:`3471`: Notebook jinja2/markupsafe depedencies in manual
1310 * :ghissue:`3502`: Notebook broken in master
1310 * :ghissue:`3502`: Notebook broken in master
1311 * :ghissue:`3302`: autoreload does not work in ipython 0.13.x, python 3.3
1311 * :ghissue:`3302`: autoreload does not work in ipython 0.13.x, python 3.3
1312 * :ghissue:`3475`: no warning when leaving/closing notebook on master without saved changes
1312 * :ghissue:`3475`: no warning when leaving/closing notebook on master without saved changes
1313 * :ghissue:`3490`: No obvious feedback when kernel crashes
1313 * :ghissue:`3490`: No obvious feedback when kernel crashes
1314 * :ghissue:`1912`: Move all autoreload tests to their own group
1314 * :ghissue:`1912`: Move all autoreload tests to their own group
1315 * :ghissue:`2577`: sh.py and ipython for python 3.3
1315 * :ghissue:`2577`: sh.py and ipython for python 3.3
1316 * :ghissue:`3467`: %magic doesn't work
1316 * :ghissue:`3467`: %magic doesn't work
1317 * :ghissue:`3501`: Editing markdown cells that wrap has off-by-one errors in cursor positioning
1317 * :ghissue:`3501`: Editing markdown cells that wrap has off-by-one errors in cursor positioning
1318 * :ghissue:`3492`: IPython for Python3
1318 * :ghissue:`3492`: IPython for Python3
1319 * :ghissue:`3474`: unexpected keyword argument to remove_kernel
1319 * :ghissue:`3474`: unexpected keyword argument to remove_kernel
1320 * :ghissue:`2283`: TypeError when using '?' after a string in a %logstart session
1320 * :ghissue:`2283`: TypeError when using '?' after a string in a %logstart session
1321 * :ghissue:`2787`: rmagic and pandas DataFrame
1321 * :ghissue:`2787`: rmagic and pandas DataFrame
1322 * :ghissue:`2605`: Ellipsis literal triggers AttributeError
1322 * :ghissue:`2605`: Ellipsis literal triggers AttributeError
1323 * :ghissue:`1179`: Test unicode source in pinfo
1323 * :ghissue:`1179`: Test unicode source in pinfo
1324 * :ghissue:`2055`: drop Python 3.1 support
1324 * :ghissue:`2055`: drop Python 3.1 support
1325 * :ghissue:`2293`: IPEP 2: Input transformations
1325 * :ghissue:`2293`: IPEP 2: Input transformations
1326 * :ghissue:`2790`: %paste and %cpaste not removing "..." lines
1326 * :ghissue:`2790`: %paste and %cpaste not removing "..." lines
1327 * :ghissue:`3480`: Testing fails because iptest.py cannot be found
1327 * :ghissue:`3480`: Testing fails because iptest.py cannot be found
1328 * :ghissue:`2580`: will not run within PIL build directory
1328 * :ghissue:`2580`: will not run within PIL build directory
1329 * :ghissue:`2797`: RMagic, Dataframe Conversion Problem
1329 * :ghissue:`2797`: RMagic, Dataframe Conversion Problem
1330 * :ghissue:`2838`: Empty lines disappear from triple-quoted literals.
1330 * :ghissue:`2838`: Empty lines disappear from triple-quoted literals.
1331 * :ghissue:`3050`: Broken link on IPython.core.display page
1331 * :ghissue:`3050`: Broken link on IPython.core.display page
1332 * :ghissue:`3473`: Config not passed down to subcommands
1332 * :ghissue:`3473`: Config not passed down to subcommands
1333 * :ghissue:`3462`: Setting log_format in config file results in error (and no format changes)
1333 * :ghissue:`3462`: Setting log_format in config file results in error (and no format changes)
1334 * :ghissue:`3311`: Notebook (occasionally) not working on windows (Sophos AV)
1334 * :ghissue:`3311`: Notebook (occasionally) not working on windows (Sophos AV)
1335 * :ghissue:`3461`: Cursor positioning off by a character in auto-wrapped lines
1335 * :ghissue:`3461`: Cursor positioning off by a character in auto-wrapped lines
1336 * :ghissue:`3454`: _repr_html_ error
1336 * :ghissue:`3454`: _repr_html_ error
1337 * :ghissue:`3457`: Space in long Paragraph Markdown cell with Chinese or Japanese
1337 * :ghissue:`3457`: Space in long Paragraph Markdown cell with Chinese or Japanese
1338 * :ghissue:`3447`: Run Cell Does not Work
1338 * :ghissue:`3447`: Run Cell Does not Work
1339 * :ghissue:`1373`: Last lines in long cells are hidden
1339 * :ghissue:`1373`: Last lines in long cells are hidden
1340 * :ghissue:`1504`: Revisit serialization in IPython.parallel
1340 * :ghissue:`1504`: Revisit serialization in IPython.parallel
1341 * :ghissue:`1459`: Can't connect to 2 HTTPS notebook servers on the same host
1341 * :ghissue:`1459`: Can't connect to 2 HTTPS notebook servers on the same host
1342 * :ghissue:`678`: Input prompt stripping broken with multiline data structures
1342 * :ghissue:`678`: Input prompt stripping broken with multiline data structures
1343 * :ghissue:`3001`: IPython.notebook.dirty flag is not set when a cell has unsaved changes
1343 * :ghissue:`3001`: IPython.notebook.dirty flag is not set when a cell has unsaved changes
1344 * :ghissue:`3077`: Multiprocessing semantics in parallel.view.map
1344 * :ghissue:`3077`: Multiprocessing semantics in parallel.view.map
1345 * :ghissue:`3056`: links across notebooks
1345 * :ghissue:`3056`: links across notebooks
1346 * :ghissue:`3120`: Tornado 3.0
1346 * :ghissue:`3120`: Tornado 3.0
1347 * :ghissue:`3156`: update pretty to use Python 3 style for sets
1347 * :ghissue:`3156`: update pretty to use Python 3 style for sets
1348 * :ghissue:`3197`: Can't escape multiple dollar signs in a markdown cell
1348 * :ghissue:`3197`: Can't escape multiple dollar signs in a markdown cell
1349 * :ghissue:`3309`: `Image()` signature/doc improvements
1349 * :ghissue:`3309`: `Image()` signature/doc improvements
1350 * :ghissue:`3415`: Bug in IPython/external/path/__init__.py
1350 * :ghissue:`3415`: Bug in IPython/external/path/__init__.py
1351 * :ghissue:`3446`: Feature suggestion: Download matplotlib figure to client browser
1351 * :ghissue:`3446`: Feature suggestion: Download matplotlib figure to client browser
1352 * :ghissue:`3295`: autoexported notebooks: only export explicitly marked cells
1352 * :ghissue:`3295`: autoexported notebooks: only export explicitly marked cells
1353 * :ghissue:`3442`: Notebook: Summary table extracted from markdown headers
1353 * :ghissue:`3442`: Notebook: Summary table extracted from markdown headers
1354 * :ghissue:`3438`: Zooming notebook in chrome is broken in master
1354 * :ghissue:`3438`: Zooming notebook in chrome is broken in master
1355 * :ghissue:`1378`: Implement autosave in notebook
1355 * :ghissue:`1378`: Implement autosave in notebook
1356 * :ghissue:`3437`: Highlighting matching parentheses
1356 * :ghissue:`3437`: Highlighting matching parentheses
1357 * :ghissue:`3435`: module search segfault
1357 * :ghissue:`3435`: module search segfault
1358 * :ghissue:`3424`: ipcluster --version
1358 * :ghissue:`3424`: ipcluster --version
1359 * :ghissue:`3434`: 0.13.2 Ipython/genutils.py doesn't exist
1359 * :ghissue:`3434`: 0.13.2 Ipython/genutils.py doesn't exist
1360 * :ghissue:`3426`: Feature request: Save by cell and not by line #: IPython %save magic
1360 * :ghissue:`3426`: Feature request: Save by cell and not by line #: IPython %save magic
1361 * :ghissue:`3412`: Non Responsive Kernel: Running a Django development server from an IPython Notebook
1361 * :ghissue:`3412`: Non Responsive Kernel: Running a Django development server from an IPython Notebook
1362 * :ghissue:`3408`: Save cell toolbar and slide type metadata in notebooks
1362 * :ghissue:`3408`: Save cell toolbar and slide type metadata in notebooks
1363 * :ghissue:`3246`: %paste regression with blank lines
1363 * :ghissue:`3246`: %paste regression with blank lines
1364 * :ghissue:`3404`: Weird error with $variable and grep in command line magic (!command)
1364 * :ghissue:`3404`: Weird error with $variable and grep in command line magic (!command)
1365 * :ghissue:`3405`: Key auto-completion in dictionaries?
1365 * :ghissue:`3405`: Key auto-completion in dictionaries?
1366 * :ghissue:`3259`: Codemirror linenumber css broken
1366 * :ghissue:`3259`: Codemirror linenumber css broken
1367 * :ghissue:`3397`: Vertical text misalignment in Markdown cells
1367 * :ghissue:`3397`: Vertical text misalignment in Markdown cells
1368 * :ghissue:`3391`: Revert #3358 once fix integrated into CM
1368 * :ghissue:`3391`: Revert #3358 once fix integrated into CM
1369 * :ghissue:`3360`: Error 500 while saving IPython notebook
1369 * :ghissue:`3360`: Error 500 while saving IPython notebook
1370 * :ghissue:`3375`: Frequent Safari/Webkit crashes
1370 * :ghissue:`3375`: Frequent Safari/Webkit crashes
1371 * :ghissue:`3365`: zmq frontend
1371 * :ghissue:`3365`: zmq frontend
1372 * :ghissue:`2654`: User_expression issues
1372 * :ghissue:`2654`: User_expression issues
1373 * :ghissue:`3389`: Store history as plain text
1373 * :ghissue:`3389`: Store history as plain text
1374 * :ghissue:`3388`: Ipython parallel: open TCP connection created for each result returned from engine
1374 * :ghissue:`3388`: Ipython parallel: open TCP connection created for each result returned from engine
1375 * :ghissue:`3385`: setup.py failure on Python 3
1375 * :ghissue:`3385`: setup.py failure on Python 3
1376 * :ghissue:`3376`: Setting `__module__` to None breaks pretty printing
1376 * :ghissue:`3376`: Setting `__module__` to None breaks pretty printing
1377 * :ghissue:`3374`: ipython qtconsole does not display the prompt on OSX
1377 * :ghissue:`3374`: ipython qtconsole does not display the prompt on OSX
1378 * :ghissue:`3380`: simple call to kernel
1378 * :ghissue:`3380`: simple call to kernel
1379 * :ghissue:`3379`: TaskRecord key 'started' not set
1379 * :ghissue:`3379`: TaskRecord key 'started' not set
1380 * :ghissue:`3241`: notebook conection time out
1380 * :ghissue:`3241`: notebook conection time out
1381 * :ghissue:`3334`: magic interpreter interpretes non magic commands?
1381 * :ghissue:`3334`: magic interpreter interpretes non magic commands?
1382 * :ghissue:`3326`: python3.3: Type error when launching SGE cluster in IPython notebook
1382 * :ghissue:`3326`: python3.3: Type error when launching SGE cluster in IPython notebook
1383 * :ghissue:`3349`: pip3 doesn't run 2to3?
1383 * :ghissue:`3349`: pip3 doesn't run 2to3?
1384 * :ghissue:`3347`: Longlist support in ipdb
1384 * :ghissue:`3347`: Longlist support in ipdb
1385 * :ghissue:`3343`: Make pip install / easy_install faster
1385 * :ghissue:`3343`: Make pip install / easy_install faster
1386 * :ghissue:`3337`: git submodules broke nightly PPA builds
1386 * :ghissue:`3337`: git submodules broke nightly PPA builds
1387 * :ghissue:`3206`: Copy/Paste Regression in QtConsole
1387 * :ghissue:`3206`: Copy/Paste Regression in QtConsole
1388 * :ghissue:`3329`: Buggy linewrap in Mac OSX Terminal (Mountain Lion)
1388 * :ghissue:`3329`: Buggy linewrap in Mac OSX Terminal (Mountain Lion)
1389 * :ghissue:`3327`: Qt version check broken
1389 * :ghissue:`3327`: Qt version check broken
1390 * :ghissue:`3303`: parallel tasks never finish under heavy load
1390 * :ghissue:`3303`: parallel tasks never finish under heavy load
1391 * :ghissue:`1381`: '\\' for equation continuations require an extra '\' in markdown cells
1391 * :ghissue:`1381`: '\\' for equation continuations require an extra '\' in markdown cells
1392 * :ghissue:`3314`: Error launching iPython
1392 * :ghissue:`3314`: Error launching iPython
1393 * :ghissue:`3306`: Test failure when running on a Vagrant VM
1393 * :ghissue:`3306`: Test failure when running on a Vagrant VM
1394 * :ghissue:`3280`: IPython.utils.process.getoutput returns stderr
1394 * :ghissue:`3280`: IPython.utils.process.getoutput returns stderr
1395 * :ghissue:`3299`: variables named _ or __ exhibit incorrect behavior
1395 * :ghissue:`3299`: variables named _ or __ exhibit incorrect behavior
1396 * :ghissue:`3196`: add an "x" or similar to htmlnotebook pager
1396 * :ghissue:`3196`: add an "x" or similar to htmlnotebook pager
1397 * :ghissue:`3293`: Several 404 errors for js files Firefox
1397 * :ghissue:`3293`: Several 404 errors for js files Firefox
1398 * :ghissue:`3292`: syntax highlighting in chrome on OSX 10.8.3
1398 * :ghissue:`3292`: syntax highlighting in chrome on OSX 10.8.3
1399 * :ghissue:`3288`: Latest dev version hangs on page load
1399 * :ghissue:`3288`: Latest dev version hangs on page load
1400 * :ghissue:`3283`: ipython dev retains directory information after directory change
1400 * :ghissue:`3283`: ipython dev retains directory information after directory change
1401 * :ghissue:`3279`: custom.css is not overridden in the dev IPython (1.0)
1401 * :ghissue:`3279`: custom.css is not overridden in the dev IPython (1.0)
1402 * :ghissue:`2727`: %run -m doesn't support relative imports
1402 * :ghissue:`2727`: %run -m doesn't support relative imports
1403 * :ghissue:`3268`: GFM triple backquote and unknown language
1403 * :ghissue:`3268`: GFM triple backquote and unknown language
1404 * :ghissue:`3273`: Suppressing all plot related outputs
1404 * :ghissue:`3273`: Suppressing all plot related outputs
1405 * :ghissue:`3272`: Backspace while completing load previous page
1405 * :ghissue:`3272`: Backspace while completing load previous page
1406 * :ghissue:`3260`: Js error in savewidget
1406 * :ghissue:`3260`: Js error in savewidget
1407 * :ghissue:`3247`: scrollbar in notebook when not needed?
1407 * :ghissue:`3247`: scrollbar in notebook when not needed?
1408 * :ghissue:`3243`: notebook: option to view json source from browser
1408 * :ghissue:`3243`: notebook: option to view json source from browser
1409 * :ghissue:`3265`: 404 errors when running IPython 1.0dev
1409 * :ghissue:`3265`: 404 errors when running IPython 1.0dev
1410 * :ghissue:`3257`: setup.py not finding submodules
1410 * :ghissue:`3257`: setup.py not finding submodules
1411 * :ghissue:`3253`: Incorrect Qt and PySide version comparison
1411 * :ghissue:`3253`: Incorrect Qt and PySide version comparison
1412 * :ghissue:`3248`: Cell magics broken in Qt console
1412 * :ghissue:`3248`: Cell magics broken in Qt console
1413 * :ghissue:`3012`: Problems with the less based style.min.css
1413 * :ghissue:`3012`: Problems with the less based style.min.css
1414 * :ghissue:`2390`: Image width/height don't work in embedded images
1414 * :ghissue:`2390`: Image width/height don't work in embedded images
1415 * :ghissue:`3236`: cannot set TerminalIPythonApp.log_format
1415 * :ghissue:`3236`: cannot set TerminalIPythonApp.log_format
1416 * :ghissue:`3214`: notebook kernel dies if started with invalid parameter
1416 * :ghissue:`3214`: notebook kernel dies if started with invalid parameter
1417 * :ghissue:`2980`: Remove HTMLCell ?
1417 * :ghissue:`2980`: Remove HTMLCell ?
1418 * :ghissue:`3128`: qtconsole hangs on importing pylab (using X forwarding)
1418 * :ghissue:`3128`: qtconsole hangs on importing pylab (using X forwarding)
1419 * :ghissue:`3198`: Hitting recursive depth causing all notebook pages to hang
1419 * :ghissue:`3198`: Hitting recursive depth causing all notebook pages to hang
1420 * :ghissue:`3218`: race conditions in profile directory creation
1420 * :ghissue:`3218`: race conditions in profile directory creation
1421 * :ghissue:`3177`: OverflowError execption in handlers.py
1421 * :ghissue:`3177`: OverflowError execption in handlers.py
1422 * :ghissue:`2563`: core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation
1422 * :ghissue:`2563`: core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation
1423 * :ghissue:`3207`: [Feature] folders for ipython notebook dashboard
1423 * :ghissue:`3207`: [Feature] folders for ipython notebook dashboard
1424 * :ghissue:`3178`: cell magics do not work with empty lines after #2447
1424 * :ghissue:`3178`: cell magics do not work with empty lines after #2447
1425 * :ghissue:`3204`: Default plot() colors unsuitable for red-green colorblind users
1425 * :ghissue:`3204`: Default plot() colors unsuitable for red-green colorblind users
1426 * :ghissue:`1789`: :\n/*foo turns into :\n*(foo) in triple-quoted strings.
1426 * :ghissue:`1789`: ``:\n/*foo`` turns into ``:\n*(foo)`` in triple-quoted strings.
1427 * :ghissue:`3202`: File cell magic fails with blank lines
1427 * :ghissue:`3202`: File cell magic fails with blank lines
1428 * :ghissue:`3199`: %%cython -a stopped working?
1428 * :ghissue:`3199`: %%cython -a stopped working?
1429 * :ghissue:`2688`: obsolete imports in import autocompletion
1429 * :ghissue:`2688`: obsolete imports in import autocompletion
1430 * :ghissue:`3192`: Python2, Unhandled exception, __builtin__.True = False
1430 * :ghissue:`3192`: Python2, Unhandled exception, __builtin__.True = False
1431 * :ghissue:`3179`: script magic error message loop
1431 * :ghissue:`3179`: script magic error message loop
1432 * :ghissue:`3009`: use XDG_CACHE_HOME for cython objects
1432 * :ghissue:`3009`: use XDG_CACHE_HOME for cython objects
1433 * :ghissue:`3059`: Bugs in 00_notebook_tour example.
1433 * :ghissue:`3059`: Bugs in 00_notebook_tour example.
1434 * :ghissue:`3104`: Integrate a javascript file manager into the notebook front end
1434 * :ghissue:`3104`: Integrate a javascript file manager into the notebook front end
1435 * :ghissue:`3176`: Particular equation not rendering (notebook)
1435 * :ghissue:`3176`: Particular equation not rendering (notebook)
1436 * :ghissue:`1133`: [notebook] readonly and upload files/UI
1436 * :ghissue:`1133`: [notebook] readonly and upload files/UI
1437 * :ghissue:`2975`: [notebook] python file and cell toolbar
1437 * :ghissue:`2975`: [notebook] python file and cell toolbar
1438 * :ghissue:`3017`: SciPy.weave broken in IPython notebook/ qtconsole
1438 * :ghissue:`3017`: SciPy.weave broken in IPython notebook/ qtconsole
1439 * :ghissue:`3161`: paste macro not reading spaces correctly
1439 * :ghissue:`3161`: paste macro not reading spaces correctly
1440 * :ghissue:`2835`: %paste not working on WinXpSP3/ipython-0.13.1.py2-win32-PROPER.exe/python27
1440 * :ghissue:`2835`: %paste not working on WinXpSP3/ipython-0.13.1.py2-win32-PROPER.exe/python27
1441 * :ghissue:`2628`: Make transformers work for lines following decorators
1441 * :ghissue:`2628`: Make transformers work for lines following decorators
1442 * :ghissue:`2612`: Multiline String containing ":\n?foo\n" confuses interpreter to replace ?foo with get_ipython().magic(u'pinfo foo')
1442 * :ghissue:`2612`: Multiline String containing ":\n?foo\n" confuses interpreter to replace ?foo with get_ipython().magic(u'pinfo foo')
1443 * :ghissue:`2539`: Request: Enable cell magics inside of .ipy scripts
1443 * :ghissue:`2539`: Request: Enable cell magics inside of .ipy scripts
1444 * :ghissue:`2507`: Multiline string does not work (includes `...`) with doctest type input in IPython notebook
1444 * :ghissue:`2507`: Multiline string does not work (includes `...`) with doctest type input in IPython notebook
1445 * :ghissue:`2164`: Request: Line breaks in line magic command
1445 * :ghissue:`2164`: Request: Line breaks in line magic command
1446 * :ghissue:`3106`: poor parallel performance with many jobs
1446 * :ghissue:`3106`: poor parallel performance with many jobs
1447 * :ghissue:`2438`: print inside multiprocessing crashes Ipython kernel
1447 * :ghissue:`2438`: print inside multiprocessing crashes Ipython kernel
1448 * :ghissue:`3155`: Bad md5 hash for package 0.13.2
1448 * :ghissue:`3155`: Bad md5 hash for package 0.13.2
1449 * :ghissue:`3045`: [Notebook] Ipython Kernel does not start if disconnected from internet(/network?)
1449 * :ghissue:`3045`: [Notebook] Ipython Kernel does not start if disconnected from internet(/network?)
1450 * :ghissue:`3146`: Using celery in python 3.3
1450 * :ghissue:`3146`: Using celery in python 3.3
1451 * :ghissue:`3145`: The notebook viewer is down
1451 * :ghissue:`3145`: The notebook viewer is down
1452 * :ghissue:`2385`: grep --color not working well with notebook
1452 * :ghissue:`2385`: grep --color not working well with notebook
1453 * :ghissue:`3131`: Quickly install from source in a clean virtualenv?
1453 * :ghissue:`3131`: Quickly install from source in a clean virtualenv?
1454 * :ghissue:`3139`: Rolling log for ipython
1454 * :ghissue:`3139`: Rolling log for ipython
1455 * :ghissue:`3127`: notebook with pylab=inline appears to call figure.draw twice
1455 * :ghissue:`3127`: notebook with pylab=inline appears to call figure.draw twice
1456 * :ghissue:`3129`: Walking up and down the call stack
1456 * :ghissue:`3129`: Walking up and down the call stack
1457 * :ghissue:`3123`: Notebook crashed if unplugged ethernet cable
1457 * :ghissue:`3123`: Notebook crashed if unplugged ethernet cable
1458 * :ghissue:`3121`: NB should use normalize.css? was #3049
1458 * :ghissue:`3121`: NB should use normalize.css? was #3049
1459 * :ghissue:`3087`: Disable spellchecking in notebook
1459 * :ghissue:`3087`: Disable spellchecking in notebook
1460 * :ghissue:`3084`: ipython pyqt 4.10 incompatibilty, QTextBlockUserData
1460 * :ghissue:`3084`: ipython pyqt 4.10 incompatibilty, QTextBlockUserData
1461 * :ghissue:`3113`: Fails to install under Jython 2.7 beta
1461 * :ghissue:`3113`: Fails to install under Jython 2.7 beta
1462 * :ghissue:`3110`: Render of h4 headers is not correct in notebook (error in renderedhtml.css)
1462 * :ghissue:`3110`: Render of h4 headers is not correct in notebook (error in renderedhtml.css)
1463 * :ghissue:`3109`: BUG: read_csv: dtype={'id' : np.str}: Datatype not understood
1463 * :ghissue:`3109`: BUG: read_csv: dtype={'id' : np.str}: Datatype not understood
1464 * :ghissue:`3107`: Autocompletion of object attributes in arrays
1464 * :ghissue:`3107`: Autocompletion of object attributes in arrays
1465 * :ghissue:`3103`: Reset locale setting in qtconsole
1465 * :ghissue:`3103`: Reset locale setting in qtconsole
1466 * :ghissue:`3090`: python3.3 Entry Point not found
1466 * :ghissue:`3090`: python3.3 Entry Point not found
1467 * :ghissue:`3081`: UnicodeDecodeError when using Image(data="some.jpeg")
1467 * :ghissue:`3081`: UnicodeDecodeError when using Image(data="some.jpeg")
1468 * :ghissue:`2834`: url regexp only finds one link
1468 * :ghissue:`2834`: url regexp only finds one link
1469 * :ghissue:`3091`: qtconsole breaks doctest.testmod() in Python 3.3
1469 * :ghissue:`3091`: qtconsole breaks doctest.testmod() in Python 3.3
1470 * :ghissue:`3074`: SIGUSR1 not available on Windows
1470 * :ghissue:`3074`: SIGUSR1 not available on Windows
1471 * :ghissue:`2996`: registration::purging stalled registration high occurrence in small clusters
1471 * :ghissue:`2996`: registration::purging stalled registration high occurrence in small clusters
1472 * :ghissue:`3065`: diff-ability of notebooks
1472 * :ghissue:`3065`: diff-ability of notebooks
1473 * :ghissue:`3067`: Crash with pygit2
1473 * :ghissue:`3067`: Crash with pygit2
1474 * :ghissue:`3061`: Bug handling Ellipsis
1474 * :ghissue:`3061`: Bug handling Ellipsis
1475 * :ghissue:`3049`: NB css inconsistent behavior between ff and webkit
1475 * :ghissue:`3049`: NB css inconsistent behavior between ff and webkit
1476 * :ghissue:`3039`: unicode errors when opening a new notebook
1476 * :ghissue:`3039`: unicode errors when opening a new notebook
1477 * :ghissue:`3048`: Installning ipython qtConsole should be easyer att Windows
1477 * :ghissue:`3048`: Installning ipython qtConsole should be easyer att Windows
1478 * :ghissue:`3042`: Profile creation fails on 0.13.2 branch
1478 * :ghissue:`3042`: Profile creation fails on 0.13.2 branch
1479 * :ghissue:`3035`: docstring typo/inconsistency: mention of an xml notebook format?
1479 * :ghissue:`3035`: docstring typo/inconsistency: mention of an xml notebook format?
1480 * :ghissue:`3031`: HDF5 library segfault (possibly due to mismatching headers?)
1480 * :ghissue:`3031`: HDF5 library segfault (possibly due to mismatching headers?)
1481 * :ghissue:`2991`: In notebook importing sympy closes ipython kernel
1481 * :ghissue:`2991`: In notebook importing sympy closes ipython kernel
1482 * :ghissue:`3027`: f.__globals__ causes an error in Python 3.3
1482 * :ghissue:`3027`: f.__globals__ causes an error in Python 3.3
1483 * :ghissue:`3020`: Failing test test_interactiveshell.TestAstTransform on Windows
1483 * :ghissue:`3020`: Failing test test_interactiveshell.TestAstTransform on Windows
1484 * :ghissue:`3023`: alt text for "click to expand output" has typo in alt text
1484 * :ghissue:`3023`: alt text for "click to expand output" has typo in alt text
1485 * :ghissue:`2963`: %history to print all input history of a previous session when line range is omitted
1485 * :ghissue:`2963`: %history to print all input history of a previous session when line range is omitted
1486 * :ghissue:`3018`: IPython installed within virtualenv. WARNING "Please install IPython inside the virtualtenv"
1486 * :ghissue:`3018`: IPython installed within virtualenv. WARNING "Please install IPython inside the virtualtenv"
1487 * :ghissue:`2484`: Completion in Emacs *Python* buffer causes prompt to be increased.
1487 * :ghissue:`2484`: Completion in Emacs *Python* buffer causes prompt to be increased.
1488 * :ghissue:`3014`: Ctrl-C finishes notebook immediately
1488 * :ghissue:`3014`: Ctrl-C finishes notebook immediately
1489 * :ghissue:`3007`: cython_pyximport reload broken in python3
1489 * :ghissue:`3007`: cython_pyximport reload broken in python3
1490 * :ghissue:`2955`: Incompatible Qt imports when running inprocess_qtconsole
1490 * :ghissue:`2955`: Incompatible Qt imports when running inprocess_qtconsole
1491 * :ghissue:`3006`: [IPython 0.13.1] The check of PyQt version is wrong
1491 * :ghissue:`3006`: [IPython 0.13.1] The check of PyQt version is wrong
1492 * :ghissue:`3005`: Renaming a notebook to an existing notebook name overwrites the other file
1492 * :ghissue:`3005`: Renaming a notebook to an existing notebook name overwrites the other file
1493 * :ghissue:`2940`: Abort trap in IPython Notebook after installing matplotlib
1493 * :ghissue:`2940`: Abort trap in IPython Notebook after installing matplotlib
1494 * :ghissue:`3000`: issue #3000
1494 * :ghissue:`3000`: issue #3000
1495 * :ghissue:`2995`: ipython_directive.py fails on multiline when prompt number < 100
1495 * :ghissue:`2995`: ipython_directive.py fails on multiline when prompt number < 100
1496 * :ghissue:`2993`: File magic (%%file) does not work with paths beginning with tilde (e.g., ~/anaconda/stuff.txt)
1496 * :ghissue:`2993`: File magic (%%file) does not work with paths beginning with tilde (e.g., ~/anaconda/stuff.txt)
1497 * :ghissue:`2992`: Cell-based input for console and qt frontends?
1497 * :ghissue:`2992`: Cell-based input for console and qt frontends?
1498 * :ghissue:`2425`: Liaise with Spyder devs to integrate newer IPython
1498 * :ghissue:`2425`: Liaise with Spyder devs to integrate newer IPython
1499 * :ghissue:`2986`: requesting help in a loop can damage a notebook
1499 * :ghissue:`2986`: requesting help in a loop can damage a notebook
1500 * :ghissue:`2978`: v1.0-dev build errors on Arch with Python 3.
1500 * :ghissue:`2978`: v1.0-dev build errors on Arch with Python 3.
1501 * :ghissue:`2557`: [refactor] Insert_cell_at_index()
1501 * :ghissue:`2557`: [refactor] Insert_cell_at_index()
1502 * :ghissue:`2969`: ipython command does not work in terminal
1502 * :ghissue:`2969`: ipython command does not work in terminal
1503 * :ghissue:`2762`: OSX wxPython (osx_cocoa, 64bit) command "%gui wx" blocks the interpreter
1503 * :ghissue:`2762`: OSX wxPython (osx_cocoa, 64bit) command "%gui wx" blocks the interpreter
1504 * :ghissue:`2956`: Silent importing of submodules differs from standard Python3.2 interpreter's behavior
1504 * :ghissue:`2956`: Silent importing of submodules differs from standard Python3.2 interpreter's behavior
1505 * :ghissue:`2943`: Up arrow key history search gets stuck in QTConsole
1505 * :ghissue:`2943`: Up arrow key history search gets stuck in QTConsole
1506 * :ghissue:`2953`: using 'nonlocal' declaration in global scope causes ipython3 crash
1506 * :ghissue:`2953`: using 'nonlocal' declaration in global scope causes ipython3 crash
1507 * :ghissue:`2952`: qtconsole ignores exec_lines
1507 * :ghissue:`2952`: qtconsole ignores exec_lines
1508 * :ghissue:`2949`: ipython crashes due to atexit()
1508 * :ghissue:`2949`: ipython crashes due to atexit()
1509 * :ghissue:`2947`: From rmagic to an R console
1509 * :ghissue:`2947`: From rmagic to an R console
1510 * :ghissue:`2938`: docstring pane not showing in notebook
1510 * :ghissue:`2938`: docstring pane not showing in notebook
1511 * :ghissue:`2936`: Tornado assumes invalid signature for parse_qs on Python 3.1
1511 * :ghissue:`2936`: Tornado assumes invalid signature for parse_qs on Python 3.1
1512 * :ghissue:`2935`: unable to find python after easy_install / pip install
1512 * :ghissue:`2935`: unable to find python after easy_install / pip install
1513 * :ghissue:`2920`: Add undo-cell deletion menu
1513 * :ghissue:`2920`: Add undo-cell deletion menu
1514 * :ghissue:`2914`: BUG:saving a modified .py file after loading a module kills the kernel
1514 * :ghissue:`2914`: BUG:saving a modified .py file after loading a module kills the kernel
1515 * :ghissue:`2925`: BUG: kernel dies if user sets sys.stderr or sys.stdout to a file object
1515 * :ghissue:`2925`: BUG: kernel dies if user sets sys.stderr or sys.stdout to a file object
1516 * :ghissue:`2909`: LaTeX sometimes fails to render in markdown cells with some curly bracket + underscore combinations
1516 * :ghissue:`2909`: LaTeX sometimes fails to render in markdown cells with some curly bracket + underscore combinations
1517 * :ghissue:`2898`: Skip ipc tests on Windows
1517 * :ghissue:`2898`: Skip ipc tests on Windows
1518 * :ghissue:`2902`: ActiveState attempt to build ipython 0.12.1 for python 3.2.2 for Mac OS failed
1518 * :ghissue:`2902`: ActiveState attempt to build ipython 0.12.1 for python 3.2.2 for Mac OS failed
1519 * :ghissue:`2899`: Test failure in IPython.core.tests.test_magic.test_time
1519 * :ghissue:`2899`: Test failure in IPython.core.tests.test_magic.test_time
1520 * :ghissue:`2890`: Test failure when fabric not installed
1520 * :ghissue:`2890`: Test failure when fabric not installed
1521 * :ghissue:`2892`: IPython tab completion bug for paths
1521 * :ghissue:`2892`: IPython tab completion bug for paths
1522 * :ghissue:`1340`: Allow input cells to be collapsed
1522 * :ghissue:`1340`: Allow input cells to be collapsed
1523 * :ghissue:`2881`: ? command in notebook does not show help in Safari
1523 * :ghissue:`2881`: ? command in notebook does not show help in Safari
1524 * :ghissue:`2751`: %%timeit should use minutes to format running time in long running cells
1524 * :ghissue:`2751`: %%timeit should use minutes to format running time in long running cells
1525 * :ghissue:`2879`: When importing a module with a wrong name, ipython crashes
1525 * :ghissue:`2879`: When importing a module with a wrong name, ipython crashes
1526 * :ghissue:`2862`: %%timeit should warn of empty contents
1526 * :ghissue:`2862`: %%timeit should warn of empty contents
1527 * :ghissue:`2485`: History navigation breaks in qtconsole
1527 * :ghissue:`2485`: History navigation breaks in qtconsole
1528 * :ghissue:`2785`: gevent input hook
1528 * :ghissue:`2785`: gevent input hook
1529 * :ghissue:`2843`: Sliently running code in clipboard (with paste, cpaste and variants)
1529 * :ghissue:`2843`: Sliently running code in clipboard (with paste, cpaste and variants)
1530 * :ghissue:`2784`: %run -t -N<N> error
1530 * :ghissue:`2784`: %run -t -N<N> error
1531 * :ghissue:`2732`: Test failure with FileLinks class on Windows
1531 * :ghissue:`2732`: Test failure with FileLinks class on Windows
1532 * :ghissue:`2860`: ipython help notebook -> KeyError: 'KernelManager'
1532 * :ghissue:`2860`: ipython help notebook -> KeyError: 'KernelManager'
1533 * :ghissue:`2858`: Where is the installed `ipython` script?
1533 * :ghissue:`2858`: Where is the installed `ipython` script?
1534 * :ghissue:`2856`: Edit code entered from ipython in external editor
1534 * :ghissue:`2856`: Edit code entered from ipython in external editor
1535 * :ghissue:`2722`: IPC transport option not taking effect ?
1535 * :ghissue:`2722`: IPC transport option not taking effect ?
1536 * :ghissue:`2473`: Better error messages in ipengine/ipcontroller
1536 * :ghissue:`2473`: Better error messages in ipengine/ipcontroller
1537 * :ghissue:`2836`: Cannot send builtin module definitions to IP engines
1537 * :ghissue:`2836`: Cannot send builtin module definitions to IP engines
1538 * :ghissue:`2833`: Any reason not to use super() ?
1538 * :ghissue:`2833`: Any reason not to use super() ?
1539 * :ghissue:`2781`: Cannot interrupt infinite loops in the notebook
1539 * :ghissue:`2781`: Cannot interrupt infinite loops in the notebook
1540 * :ghissue:`2150`: clippath_demo.py in matplotlib example does not work with inline backend
1540 * :ghissue:`2150`: clippath_demo.py in matplotlib example does not work with inline backend
1541 * :ghissue:`2634`: Numbered list in notebook markdown cell renders with Roman numerals instead of numbers
1541 * :ghissue:`2634`: Numbered list in notebook markdown cell renders with Roman numerals instead of numbers
1542 * :ghissue:`2230`: IPython crashing during startup with "AttributeError: 'NoneType' object has no attribute 'rstrip'"
1542 * :ghissue:`2230`: IPython crashing during startup with "AttributeError: 'NoneType' object has no attribute 'rstrip'"
1543 * :ghissue:`2483`: nbviewer bug? with multi-file gists
1543 * :ghissue:`2483`: nbviewer bug? with multi-file gists
1544 * :ghissue:`2466`: mistyping `ed -p` breaks `ed -p`
1544 * :ghissue:`2466`: mistyping `ed -p` breaks `ed -p`
1545 * :ghissue:`2477`: Glob expansion tests fail on Windows
1545 * :ghissue:`2477`: Glob expansion tests fail on Windows
1546 * :ghissue:`2622`: doc issue: notebooks that ship with Ipython .13 are written for python 2.x
1546 * :ghissue:`2622`: doc issue: notebooks that ship with Ipython .13 are written for python 2.x
1547 * :ghissue:`2626`: Add "Cell -> Run All Keep Going" for notebooks
1547 * :ghissue:`2626`: Add "Cell -> Run All Keep Going" for notebooks
1548 * :ghissue:`1223`: Show last modification date of each notebook
1548 * :ghissue:`1223`: Show last modification date of each notebook
1549 * :ghissue:`2621`: user request: put link to example notebooks in Dashboard
1549 * :ghissue:`2621`: user request: put link to example notebooks in Dashboard
1550 * :ghissue:`2564`: grid blanks plots in ipython pylab inline mode (interactive)
1550 * :ghissue:`2564`: grid blanks plots in ipython pylab inline mode (interactive)
1551 * :ghissue:`2532`: Django shell (IPython) gives NameError on dict comprehensions
1551 * :ghissue:`2532`: Django shell (IPython) gives NameError on dict comprehensions
1552 * :ghissue:`2188`: ipython crashes on ctrl-c
1552 * :ghissue:`2188`: ipython crashes on ctrl-c
1553 * :ghissue:`2391`: Request: nbformat API to load/save without changing version
1553 * :ghissue:`2391`: Request: nbformat API to load/save without changing version
1554 * :ghissue:`2355`: Restart kernel message even though kernel is perfectly alive
1554 * :ghissue:`2355`: Restart kernel message even though kernel is perfectly alive
1555 * :ghissue:`2306`: Garbled input text after reverse search on Mac OS X
1555 * :ghissue:`2306`: Garbled input text after reverse search on Mac OS X
1556 * :ghissue:`2297`: ipdb with separate kernel/client pushing stdout to kernel process only
1556 * :ghissue:`2297`: ipdb with separate kernel/client pushing stdout to kernel process only
1557 * :ghissue:`2180`: Have [kernel busy] overridden only by [kernel idle]
1557 * :ghissue:`2180`: Have [kernel busy] overridden only by [kernel idle]
1558 * :ghissue:`1188`: Pylab with OSX backend keyboard focus issue and hang
1558 * :ghissue:`1188`: Pylab with OSX backend keyboard focus issue and hang
1559 * :ghissue:`2107`: test_octavemagic.py[everything] fails
1559 * :ghissue:`2107`: test_octavemagic.py[everything] fails
1560 * :ghissue:`1212`: Better understand/document browser compatibility
1560 * :ghissue:`1212`: Better understand/document browser compatibility
1561 * :ghissue:`1585`: Refactor notebook templates to use Jinja2 and make each page a separate directory
1561 * :ghissue:`1585`: Refactor notebook templates to use Jinja2 and make each page a separate directory
1562 * :ghissue:`1443`: xticks scaling factor partially obscured with qtconsole and inline plotting
1562 * :ghissue:`1443`: xticks scaling factor partially obscured with qtconsole and inline plotting
1563 * :ghissue:`1209`: can't make %result work as in doc.
1563 * :ghissue:`1209`: can't make %result work as in doc.
1564 * :ghissue:`1200`: IPython 0.12 Windows install fails on Vista
1564 * :ghissue:`1200`: IPython 0.12 Windows install fails on Vista
1565 * :ghissue:`1127`: Interactive test scripts for Qt/nb issues
1565 * :ghissue:`1127`: Interactive test scripts for Qt/nb issues
1566 * :ghissue:`959`: Matplotlib figures hide
1566 * :ghissue:`959`: Matplotlib figures hide
1567 * :ghissue:`2071`: win32 installer issue on Windows XP
1567 * :ghissue:`2071`: win32 installer issue on Windows XP
1568 * :ghissue:`2610`: ZMQInteractiveShell.colors being ignored
1568 * :ghissue:`2610`: ZMQInteractiveShell.colors being ignored
1569 * :ghissue:`2505`: Markdown Cell incorrectly highlighting after "<"
1569 * :ghissue:`2505`: Markdown Cell incorrectly highlighting after "<"
1570 * :ghissue:`165`: Installer fails to create Start Menu entries on Windows
1570 * :ghissue:`165`: Installer fails to create Start Menu entries on Windows
1571 * :ghissue:`2356`: failing traceback in terminal ipython for first exception
1571 * :ghissue:`2356`: failing traceback in terminal ipython for first exception
1572 * :ghissue:`2145`: Have dashboad show when server disconect
1572 * :ghissue:`2145`: Have dashboad show when server disconect
1573 * :ghissue:`2098`: Do not crash on kernel shutdow if json file is missing
1573 * :ghissue:`2098`: Do not crash on kernel shutdow if json file is missing
1574 * :ghissue:`2813`: Offline MathJax is broken on 0.14dev
1574 * :ghissue:`2813`: Offline MathJax is broken on 0.14dev
1575 * :ghissue:`2807`: Test failure: IPython.parallel.tests.test_client.TestClient.test_purge_everything
1575 * :ghissue:`2807`: Test failure: IPython.parallel.tests.test_client.TestClient.test_purge_everything
1576 * :ghissue:`2486`: Readline's history search in ipython console does not clear properly after cancellation with Ctrl+C
1576 * :ghissue:`2486`: Readline's history search in ipython console does not clear properly after cancellation with Ctrl+C
1577 * :ghissue:`2709`: Cython -la doesn't work
1577 * :ghissue:`2709`: Cython -la doesn't work
1578 * :ghissue:`2767`: What is IPython.utils.upgradedir ?
1578 * :ghissue:`2767`: What is IPython.utils.upgradedir ?
1579 * :ghissue:`2210`: Placing matplotlib legend outside axis bounds causes inline display to clip it
1579 * :ghissue:`2210`: Placing matplotlib legend outside axis bounds causes inline display to clip it
1580 * :ghissue:`2553`: IPython Notebooks not robust against client failures
1580 * :ghissue:`2553`: IPython Notebooks not robust against client failures
1581 * :ghissue:`2536`: ImageDraw in Ipython notebook not drawing lines
1581 * :ghissue:`2536`: ImageDraw in Ipython notebook not drawing lines
1582 * :ghissue:`2264`: Feature request: Versioning messaging protocol
1582 * :ghissue:`2264`: Feature request: Versioning messaging protocol
1583 * :ghissue:`2589`: Creation of ~300+ MPI-spawned engines causes instability in ipcluster
1583 * :ghissue:`2589`: Creation of ~300+ MPI-spawned engines causes instability in ipcluster
1584 * :ghissue:`2672`: notebook: inline option without pylab
1584 * :ghissue:`2672`: notebook: inline option without pylab
1585 * :ghissue:`2673`: Indefinite Articles & Traitlets
1585 * :ghissue:`2673`: Indefinite Articles & Traitlets
1586 * :ghissue:`2705`: Notebook crashes Safari with select and drag
1586 * :ghissue:`2705`: Notebook crashes Safari with select and drag
1587 * :ghissue:`2721`: dreload kills ipython when it hits zmq
1587 * :ghissue:`2721`: dreload kills ipython when it hits zmq
1588 * :ghissue:`2806`: ipython.parallel doesn't discover globals under Python 3.3
1588 * :ghissue:`2806`: ipython.parallel doesn't discover globals under Python 3.3
1589 * :ghissue:`2794`: _exit_code behaves differently in terminal vs ZMQ frontends
1589 * :ghissue:`2794`: _exit_code behaves differently in terminal vs ZMQ frontends
1590 * :ghissue:`2793`: IPython.parallel issue with pushing pandas TimeSeries
1590 * :ghissue:`2793`: IPython.parallel issue with pushing pandas TimeSeries
1591 * :ghissue:`1085`: In process kernel for Qt frontend
1591 * :ghissue:`1085`: In process kernel for Qt frontend
1592 * :ghissue:`2760`: IndexError: list index out of range with Python 3.2
1592 * :ghissue:`2760`: IndexError: list index out of range with Python 3.2
1593 * :ghissue:`2780`: Save and load notebooks from github
1593 * :ghissue:`2780`: Save and load notebooks from github
1594 * :ghissue:`2772`: AttributeError: 'Client' object has no attribute 'kill'
1594 * :ghissue:`2772`: AttributeError: 'Client' object has no attribute 'kill'
1595 * :ghissue:`2754`: Fail to send class definitions from interactive session to engines namespaces
1595 * :ghissue:`2754`: Fail to send class definitions from interactive session to engines namespaces
1596 * :ghissue:`2764`: TypeError while using 'cd'
1596 * :ghissue:`2764`: TypeError while using 'cd'
1597 * :ghissue:`2765`: name '__file__' is not defined
1597 * :ghissue:`2765`: name '__file__' is not defined
1598 * :ghissue:`2540`: Wrap tooltip if line exceeds threshold?
1598 * :ghissue:`2540`: Wrap tooltip if line exceeds threshold?
1599 * :ghissue:`2394`: Startup error on ipython qtconsole (version 0.13 and 0.14-dev
1599 * :ghissue:`2394`: Startup error on ipython qtconsole (version 0.13 and 0.14-dev
1600 * :ghissue:`2440`: IPEP 4: Python 3 Compatibility
1600 * :ghissue:`2440`: IPEP 4: Python 3 Compatibility
1601 * :ghissue:`1814`: __file__ is not defined when file end with .ipy
1601 * :ghissue:`1814`: __file__ is not defined when file end with .ipy
1602 * :ghissue:`2759`: R magic extension interferes with tab completion
1602 * :ghissue:`2759`: R magic extension interferes with tab completion
1603 * :ghissue:`2615`: Small change needed to rmagic extension.
1603 * :ghissue:`2615`: Small change needed to rmagic extension.
1604 * :ghissue:`2748`: collapse parts of a html notebook
1604 * :ghissue:`2748`: collapse parts of a html notebook
1605 * :ghissue:`1661`: %paste still bugs about IndentationError and says to use %paste
1605 * :ghissue:`1661`: %paste still bugs about IndentationError and says to use %paste
1606 * :ghissue:`2742`: Octavemagic fails to deliver inline images in IPython (on Windows)
1606 * :ghissue:`2742`: Octavemagic fails to deliver inline images in IPython (on Windows)
1607 * :ghissue:`2739`: wiki.ipython.org contaminated with prescription drug spam
1607 * :ghissue:`2739`: wiki.ipython.org contaminated with prescription drug spam
1608 * :ghissue:`2588`: Link error while executing code from cython example notebook
1608 * :ghissue:`2588`: Link error while executing code from cython example notebook
1609 * :ghissue:`2550`: Rpush magic doesn't find local variables and doesn't support comma separated lists of variables
1609 * :ghissue:`2550`: Rpush magic doesn't find local variables and doesn't support comma separated lists of variables
1610 * :ghissue:`2675`: Markdown/html blockquote need css.
1610 * :ghissue:`2675`: Markdown/html blockquote need css.
1611 * :ghissue:`2419`: TerminalInteractiveShell.__init__() ignores value of ipython_dir argument
1611 * :ghissue:`2419`: TerminalInteractiveShell.__init__() ignores value of ipython_dir argument
1612 * :ghissue:`1523`: Better LaTeX printing in the qtconsole with the sympy profile
1612 * :ghissue:`1523`: Better LaTeX printing in the qtconsole with the sympy profile
1613 * :ghissue:`2719`: ipython fails with `pkg_resources.DistributionNotFound: ipython==0.13`
1613 * :ghissue:`2719`: ipython fails with `pkg_resources.DistributionNotFound: ipython==0.13`
1614 * :ghissue:`2715`: url crashes nbviewer.ipython.org
1614 * :ghissue:`2715`: url crashes nbviewer.ipython.org
1615 * :ghissue:`2555`: "import" module completion on MacOSX
1615 * :ghissue:`2555`: "import" module completion on MacOSX
1616 * :ghissue:`2707`: Problem installing the new version of IPython in Windows
1616 * :ghissue:`2707`: Problem installing the new version of IPython in Windows
1617 * :ghissue:`2696`: SymPy magic bug in IPython Notebook
1617 * :ghissue:`2696`: SymPy magic bug in IPython Notebook
1618 * :ghissue:`2684`: pretty print broken for types created with PyType_FromSpec
1618 * :ghissue:`2684`: pretty print broken for types created with PyType_FromSpec
1619 * :ghissue:`2533`: rmagic breaks on Windows
1619 * :ghissue:`2533`: rmagic breaks on Windows
1620 * :ghissue:`2661`: Qtconsole tooltip is too wide when the function has many arguments
1620 * :ghissue:`2661`: Qtconsole tooltip is too wide when the function has many arguments
1621 * :ghissue:`2679`: ipython3 qtconsole via Homebrew on Mac OS X 10.8 - pyqt/pyside import error
1621 * :ghissue:`2679`: ipython3 qtconsole via Homebrew on Mac OS X 10.8 - pyqt/pyside import error
1622 * :ghissue:`2646`: pylab_not_importable
1622 * :ghissue:`2646`: pylab_not_importable
1623 * :ghissue:`2587`: cython magic pops 2 CLI windows upon execution on Windows
1623 * :ghissue:`2587`: cython magic pops 2 CLI windows upon execution on Windows
1624 * :ghissue:`2660`: Certain arguments (-h, --help, --version) never passed to scripts run with ipython
1624 * :ghissue:`2660`: Certain arguments (-h, --help, --version) never passed to scripts run with ipython
1625 * :ghissue:`2665`: Missing docs for rmagic and some other extensions
1625 * :ghissue:`2665`: Missing docs for rmagic and some other extensions
1626 * :ghissue:`2611`: Travis wants to drop 3.1 support
1626 * :ghissue:`2611`: Travis wants to drop 3.1 support
1627 * :ghissue:`2658`: Incorrect parsing of raw multiline strings
1627 * :ghissue:`2658`: Incorrect parsing of raw multiline strings
1628 * :ghissue:`2655`: Test fails if `from __future__ import print_function` in .pythonrc.py
1628 * :ghissue:`2655`: Test fails if `from __future__ import print_function` in .pythonrc.py
1629 * :ghissue:`2651`: nonlocal with no existing variable produces too many errors
1629 * :ghissue:`2651`: nonlocal with no existing variable produces too many errors
1630 * :ghissue:`2645`: python3 is a pain (minor unicode bug)
1630 * :ghissue:`2645`: python3 is a pain (minor unicode bug)
1631 * :ghissue:`2637`: %paste in Python 3 on Mac doesn't work
1631 * :ghissue:`2637`: %paste in Python 3 on Mac doesn't work
1632 * :ghissue:`2624`: Error on launching IPython on Win 7 and Python 2.7.3
1632 * :ghissue:`2624`: Error on launching IPython on Win 7 and Python 2.7.3
1633 * :ghissue:`2608`: disk IO activity on cursor press
1633 * :ghissue:`2608`: disk IO activity on cursor press
1634 * :ghissue:`1275`: Markdown parses LaTeX math symbols as its formatting syntax in notebook
1634 * :ghissue:`1275`: Markdown parses LaTeX math symbols as its formatting syntax in notebook
1635 * :ghissue:`2613`: display(Math(...)) doesn't render \tau correctly
1635 * :ghissue:`2613`: display(Math(...)) doesn't render \tau correctly
1636 * :ghissue:`925`: Tab-completion in Qt console needn't use pager
1636 * :ghissue:`925`: Tab-completion in Qt console needn't use pager
1637 * :ghissue:`2607`: %load_ext sympy.interactive.ipythonprinting dammaging output
1637 * :ghissue:`2607`: %load_ext sympy.interactive.ipythonprinting dammaging output
1638 * :ghissue:`2593`: Toolbar button to open qtconsole from notebook
1638 * :ghissue:`2593`: Toolbar button to open qtconsole from notebook
1639 * :ghissue:`2602`: IPython html documentation for downloading
1639 * :ghissue:`2602`: IPython html documentation for downloading
1640 * :ghissue:`2598`: ipython notebook --pylab=inline replaces built-in any()
1640 * :ghissue:`2598`: ipython notebook --pylab=inline replaces built-in any()
1641 * :ghissue:`2244`: small issue: wrong printout
1641 * :ghissue:`2244`: small issue: wrong printout
1642 * :ghissue:`2590`: add easier way to execute scripts in the current directory
1642 * :ghissue:`2590`: add easier way to execute scripts in the current directory
1643 * :ghissue:`2581`: %hist does not work when InteractiveShell.cache_size = 0
1643 * :ghissue:`2581`: %hist does not work when InteractiveShell.cache_size = 0
1644 * :ghissue:`2584`: No file COPYING
1644 * :ghissue:`2584`: No file COPYING
1645 * :ghissue:`2578`: AttributeError: 'module' object has no attribute 'TestCase'
1645 * :ghissue:`2578`: AttributeError: 'module' object has no attribute 'TestCase'
1646 * :ghissue:`2576`: One of my notebooks won't load any more -- is there a maximum notebook size?
1646 * :ghissue:`2576`: One of my notebooks won't load any more -- is there a maximum notebook size?
1647 * :ghissue:`2560`: Notebook output is invisible when printing strings with \r\r\n line endings
1647 * :ghissue:`2560`: Notebook output is invisible when printing strings with \r\r\n line endings
1648 * :ghissue:`2566`: if pyside partially present ipython qtconsole fails to load even if pyqt4 present
1648 * :ghissue:`2566`: if pyside partially present ipython qtconsole fails to load even if pyqt4 present
1649 * :ghissue:`1308`: ipython qtconsole --ssh=server --existing ... hangs
1649 * :ghissue:`1308`: ipython qtconsole --ssh=server --existing ... hangs
1650 * :ghissue:`1679`: List command doesn't work in ipdb debugger the first time
1650 * :ghissue:`1679`: List command doesn't work in ipdb debugger the first time
1651 * :ghissue:`2545`: pypi win32 installer creates 64bit executibles
1651 * :ghissue:`2545`: pypi win32 installer creates 64bit executibles
1652 * :ghissue:`2080`: Event loop issues with IPython 0.12 and PyQt4 (QDialog.exec_ and more)
1652 * :ghissue:`2080`: Event loop issues with IPython 0.12 and PyQt4 (``QDialog.exec_`` and more)
1653 * :ghissue:`2541`: Allow `python -m IPython`
1653 * :ghissue:`2541`: Allow `python -m IPython`
1654 * :ghissue:`2508`: subplots_adjust() does not work correctly in ipython notebook
1654 * :ghissue:`2508`: subplots_adjust() does not work correctly in ipython notebook
1655 * :ghissue:`2289`: Incorrect mathjax rendering of certain arrays of equations
1655 * :ghissue:`2289`: Incorrect mathjax rendering of certain arrays of equations
1656 * :ghissue:`2487`: Selecting and indenting
1656 * :ghissue:`2487`: Selecting and indenting
1657 * :ghissue:`2521`: more fine-grained 'run' controls, such as 'run from here' and 'run until here'
1657 * :ghissue:`2521`: more fine-grained 'run' controls, such as 'run from here' and 'run until here'
1658 * :ghissue:`2535`: Funny bounding box when plot with text
1658 * :ghissue:`2535`: Funny bounding box when plot with text
1659 * :ghissue:`2523`: History not working
1659 * :ghissue:`2523`: History not working
1660 * :ghissue:`2514`: Issue with zooming in qtconsole
1660 * :ghissue:`2514`: Issue with zooming in qtconsole
1661 * :ghissue:`2220`: No sys.stdout.encoding in kernel based IPython
1661 * :ghissue:`2220`: No sys.stdout.encoding in kernel based IPython
1662 * :ghissue:`2512`: ERROR: Internal Python error in the inspect module.
1662 * :ghissue:`2512`: ERROR: Internal Python error in the inspect module.
1663 * :ghissue:`2496`: Function passwd does not work in QtConsole
1663 * :ghissue:`2496`: Function passwd does not work in QtConsole
1664 * :ghissue:`1453`: make engines reconnect/die when controller was restarted
1664 * :ghissue:`1453`: make engines reconnect/die when controller was restarted
1665 * :ghissue:`2481`: ipython notebook -- clicking in a code cell's output moves the screen to the top of the code cell
1665 * :ghissue:`2481`: ipython notebook -- clicking in a code cell's output moves the screen to the top of the code cell
1666 * :ghissue:`2488`: Undesired plot outputs in Notebook inline mode
1666 * :ghissue:`2488`: Undesired plot outputs in Notebook inline mode
1667 * :ghissue:`2482`: ipython notebook -- download may not get the latest notebook
1667 * :ghissue:`2482`: ipython notebook -- download may not get the latest notebook
1668 * :ghissue:`2471`: _subprocess module removed in Python 3.3
1668 * :ghissue:`2471`: _subprocess module removed in Python 3.3
1669 * :ghissue:`2374`: Issues with man pages
1669 * :ghissue:`2374`: Issues with man pages
1670 * :ghissue:`2316`: parallel.Client.__init__ should take cluster_id kwarg
1670 * :ghissue:`2316`: parallel.Client.__init__ should take cluster_id kwarg
1671 * :ghissue:`2457`: Can a R library wrapper be created with Rmagic?
1671 * :ghissue:`2457`: Can a R library wrapper be created with Rmagic?
1672 * :ghissue:`1575`: Fallback frontend for console when connecting pylab=inlnie -enabled kernel?
1672 * :ghissue:`1575`: Fallback frontend for console when connecting pylab=inlnie -enabled kernel?
1673 * :ghissue:`2097`: Do not crash if history db is corrupted
1673 * :ghissue:`2097`: Do not crash if history db is corrupted
1674 * :ghissue:`2435`: ipengines fail if clean_logs enabled
1674 * :ghissue:`2435`: ipengines fail if clean_logs enabled
1675 * :ghissue:`2429`: Using warnings.warn() results in TypeError
1675 * :ghissue:`2429`: Using warnings.warn() results in TypeError
1676 * :ghissue:`2422`: Multiprocessing in ipython notebook kernel crash
1676 * :ghissue:`2422`: Multiprocessing in ipython notebook kernel crash
1677 * :ghissue:`2426`: ipython crashes with the following message. I do not what went wrong. Can you help me identify the problem?
1677 * :ghissue:`2426`: ipython crashes with the following message. I do not what went wrong. Can you help me identify the problem?
1678 * :ghissue:`2423`: Docs typo?
1678 * :ghissue:`2423`: Docs typo?
1679 * :ghissue:`2257`: pip install -e fails
1679 * :ghissue:`2257`: pip install -e fails
1680 * :ghissue:`2418`: rmagic can't run R's read.csv on data files with NA data
1680 * :ghissue:`2418`: rmagic can't run R's read.csv on data files with NA data
1681 * :ghissue:`2417`: HTML notebook: Backspace sometimes deletes multiple characters
1681 * :ghissue:`2417`: HTML notebook: Backspace sometimes deletes multiple characters
1682 * :ghissue:`2275`: notebook: "Down_Arrow" on last line of cell should move to end of line
1682 * :ghissue:`2275`: notebook: "Down_Arrow" on last line of cell should move to end of line
1683 * :ghissue:`2414`: 0.13.1 does not work with current EPD 7.3-2
1683 * :ghissue:`2414`: 0.13.1 does not work with current EPD 7.3-2
1684 * :ghissue:`2409`: there is a redundant None
1684 * :ghissue:`2409`: there is a redundant None
1685 * :ghissue:`2410`: Use /usr/bin/python3 instead of /usr/bin/python
1685 * :ghissue:`2410`: Use /usr/bin/python3 instead of /usr/bin/python
1686 * :ghissue:`2366`: Notebook Dashboard --notebook-dir and fullpath
1686 * :ghissue:`2366`: Notebook Dashboard --notebook-dir and fullpath
1687 * :ghissue:`2406`: Inability to get docstring in debugger
1687 * :ghissue:`2406`: Inability to get docstring in debugger
1688 * :ghissue:`2398`: Show line number for IndentationErrors
1688 * :ghissue:`2398`: Show line number for IndentationErrors
1689 * :ghissue:`2314`: HTML lists seem to interfere with the QtConsole display
1689 * :ghissue:`2314`: HTML lists seem to interfere with the QtConsole display
1690 * :ghissue:`1688`: unicode exception when using %run with failing script
1690 * :ghissue:`1688`: unicode exception when using %run with failing script
1691 * :ghissue:`1884`: IPython.embed changes color on error
1691 * :ghissue:`1884`: IPython.embed changes color on error
1692 * :ghissue:`2381`: %time doesn't work for multiline statements
1692 * :ghissue:`2381`: %time doesn't work for multiline statements
1693 * :ghissue:`1435`: Add size keywords in Image class
1693 * :ghissue:`1435`: Add size keywords in Image class
1694 * :ghissue:`2372`: interactiveshell.py misses urllib and io_open imports
1694 * :ghissue:`2372`: interactiveshell.py misses urllib and io_open imports
1695 * :ghissue:`2371`: iPython not working
1695 * :ghissue:`2371`: iPython not working
1696 * :ghissue:`2367`: Tab expansion moves to next cell in notebook
1696 * :ghissue:`2367`: Tab expansion moves to next cell in notebook
1697 * :ghissue:`2359`: nbviever alters the order of print and display() output
1697 * :ghissue:`2359`: nbviever alters the order of print and display() output
1698 * :ghissue:`2227`: print name for IPython Notebooks has become uninformative
1698 * :ghissue:`2227`: print name for IPython Notebooks has become uninformative
1699 * :ghissue:`2361`: client doesn't use connection file's 'location' in disambiguating 'interface'
1699 * :ghissue:`2361`: client doesn't use connection file's 'location' in disambiguating 'interface'
1700 * :ghissue:`2357`: failing traceback in terminal ipython for first exception
1700 * :ghissue:`2357`: failing traceback in terminal ipython for first exception
1701 * :ghissue:`2343`: Installing in a python 3.3b2 or python 3.3rc1 virtual environment.
1701 * :ghissue:`2343`: Installing in a python 3.3b2 or python 3.3rc1 virtual environment.
1702 * :ghissue:`2315`: Failure in test: "Test we're not loading modules on startup that we shouldn't."
1702 * :ghissue:`2315`: Failure in test: "Test we're not loading modules on startup that we shouldn't."
1703 * :ghissue:`2351`: Multiple Notebook Apps: cookies not port specific, clash with each other
1703 * :ghissue:`2351`: Multiple Notebook Apps: cookies not port specific, clash with each other
1704 * :ghissue:`2350`: running unittest from qtconsole prints output to terminal
1704 * :ghissue:`2350`: running unittest from qtconsole prints output to terminal
1705 * :ghissue:`2303`: remote tracebacks broken since 952d0d6 (PR #2223)
1705 * :ghissue:`2303`: remote tracebacks broken since 952d0d6 (PR #2223)
1706 * :ghissue:`2330`: qtconsole does not hightlight tab-completion suggestion with custom stylesheet
1706 * :ghissue:`2330`: qtconsole does not hightlight tab-completion suggestion with custom stylesheet
1707 * :ghissue:`2325`: Parsing Tex formula fails in Notebook
1707 * :ghissue:`2325`: Parsing Tex formula fails in Notebook
1708 * :ghissue:`2324`: Parsing Tex formula fails
1708 * :ghissue:`2324`: Parsing Tex formula fails
1709 * :ghissue:`1474`: Add argument to `run -n` for custom namespace
1709 * :ghissue:`1474`: Add argument to `run -n` for custom namespace
1710 * :ghissue:`2318`: C-m n/p don't work in Markdown cells in the notebook
1710 * :ghissue:`2318`: C-m n/p don't work in Markdown cells in the notebook
1711 * :ghissue:`2309`: time.time() in ipython notebook producing impossible results
1711 * :ghissue:`2309`: time.time() in ipython notebook producing impossible results
1712 * :ghissue:`2307`: schedule tasks on newly arrived engines
1712 * :ghissue:`2307`: schedule tasks on newly arrived engines
1713 * :ghissue:`2313`: Allow Notebook HTML/JS to send messages to Python code
1713 * :ghissue:`2313`: Allow Notebook HTML/JS to send messages to Python code
1714 * :ghissue:`2304`: ipengine throws KeyError: url
1714 * :ghissue:`2304`: ipengine throws KeyError: url
1715 * :ghissue:`1878`: shell access using ! will not fill class or function scope vars
1715 * :ghissue:`1878`: shell access using ! will not fill class or function scope vars
1716 * :ghissue:`2253`: %paste does not retrieve clipboard contents under screen/tmux on OS X
1716 * :ghissue:`2253`: %paste does not retrieve clipboard contents under screen/tmux on OS X
1717 * :ghissue:`1510`: Add-on (or Monkey-patch) infrastructure for HTML notebook
1717 * :ghissue:`1510`: Add-on (or Monkey-patch) infrastructure for HTML notebook
1718 * :ghissue:`2273`: triple quote and %s at beginning of line with %paste
1718 * :ghissue:`2273`: triple quote and %s at beginning of line with %paste
1719 * :ghissue:`2243`: Regression in .embed()
1719 * :ghissue:`2243`: Regression in .embed()
1720 * :ghissue:`2266`: SSH passwordless check with OpenSSH checks for the wrong thing
1720 * :ghissue:`2266`: SSH passwordless check with OpenSSH checks for the wrong thing
1721 * :ghissue:`2217`: Change NewNotebook handler to use 30x redirect
1721 * :ghissue:`2217`: Change NewNotebook handler to use 30x redirect
1722 * :ghissue:`2276`: config option for disabling history store
1722 * :ghissue:`2276`: config option for disabling history store
1723 * :ghissue:`2239`: can't use parallel.Reference in view.map
1723 * :ghissue:`2239`: can't use parallel.Reference in view.map
1724 * :ghissue:`2272`: Sympy piecewise messed up rendering
1724 * :ghissue:`2272`: Sympy piecewise messed up rendering
1725 * :ghissue:`2252`: %paste throws an exception with empty clipboard
1725 * :ghissue:`2252`: %paste throws an exception with empty clipboard
1726 * :ghissue:`2259`: git-mpr is currently broken
1726 * :ghissue:`2259`: git-mpr is currently broken
1727 * :ghissue:`2247`: Variable expansion in shell commands should work in substrings
1727 * :ghissue:`2247`: Variable expansion in shell commands should work in substrings
1728 * :ghissue:`2026`: Run 'fast' tests only
1728 * :ghissue:`2026`: Run 'fast' tests only
1729 * :ghissue:`2241`: read a list of notebooks on server and bring into browser only notebook
1729 * :ghissue:`2241`: read a list of notebooks on server and bring into browser only notebook
1730 * :ghissue:`2237`: please put python and text editor in the web only ipython
1730 * :ghissue:`2237`: please put python and text editor in the web only ipython
1731 * :ghissue:`2053`: Improvements to the IPython.display.Image object
1731 * :ghissue:`2053`: Improvements to the IPython.display.Image object
1732 * :ghissue:`1456`: ERROR: Internal Python error in the inspect module.
1732 * :ghissue:`1456`: ERROR: Internal Python error in the inspect module.
1733 * :ghissue:`2221`: Avoid importing from IPython.parallel in core
1733 * :ghissue:`2221`: Avoid importing from IPython.parallel in core
1734 * :ghissue:`2213`: Can't trigger startup code in Engines
1734 * :ghissue:`2213`: Can't trigger startup code in Engines
1735 * :ghissue:`1464`: Strange behavior for backspace with lines ending with more than 4 spaces in notebook
1735 * :ghissue:`1464`: Strange behavior for backspace with lines ending with more than 4 spaces in notebook
1736 * :ghissue:`2187`: NaN in object_info_reply JSON causes parse error
1736 * :ghissue:`2187`: NaN in object_info_reply JSON causes parse error
1737 * :ghissue:`214`: system command requiring administrative privileges
1737 * :ghissue:`214`: system command requiring administrative privileges
1738 * :ghissue:`2195`: Unknown option `no-edit` in git-mpr
1738 * :ghissue:`2195`: Unknown option `no-edit` in git-mpr
1739 * :ghissue:`2201`: Add documentation build to tools/test_pr.py
1739 * :ghissue:`2201`: Add documentation build to tools/test_pr.py
1740 * :ghissue:`2205`: Command-line option for default Notebook output collapsing behavior
1740 * :ghissue:`2205`: Command-line option for default Notebook output collapsing behavior
1741 * :ghissue:`1927`: toggle between inline and floating figures
1741 * :ghissue:`1927`: toggle between inline and floating figures
1742 * :ghissue:`2171`: Can't start StarCluster after upgrading to IPython 0.13
1742 * :ghissue:`2171`: Can't start StarCluster after upgrading to IPython 0.13
1743 * :ghissue:`2173`: oct2py v >= 0.3.1 doesn't need h5py anymore
1743 * :ghissue:`2173`: oct2py v >= 0.3.1 doesn't need h5py anymore
1744 * :ghissue:`2099`: storemagic needs to use self.shell
1744 * :ghissue:`2099`: storemagic needs to use self.shell
1745 * :ghissue:`2166`: DirectView map_sync() with Lambdas Using Generators
1745 * :ghissue:`2166`: DirectView map_sync() with Lambdas Using Generators
1746 * :ghissue:`2091`: Unable to use print_stats after %prun -r in notebook
1746 * :ghissue:`2091`: Unable to use print_stats after %prun -r in notebook
1747 * :ghissue:`2132`: Add fail-over for pastebin
1747 * :ghissue:`2132`: Add fail-over for pastebin
1748 * :ghissue:`2156`: Make it possible to install ipython without nasty gui dependencies
1748 * :ghissue:`2156`: Make it possible to install ipython without nasty gui dependencies
1749 * :ghissue:`2154`: Scrolled long output should be off in print view by default
1749 * :ghissue:`2154`: Scrolled long output should be off in print view by default
1750 * :ghissue:`2162`: Tab completion does not work with IPython.embed_kernel()
1750 * :ghissue:`2162`: Tab completion does not work with IPython.embed_kernel()
1751 * :ghissue:`2157`: iPython 0.13 / github-master cannot create logfile from scratch
1751 * :ghissue:`2157`: iPython 0.13 / github-master cannot create logfile from scratch
1752 * :ghissue:`2151`: missing newline when a magic is called from the qtconsole menu
1752 * :ghissue:`2151`: missing newline when a magic is called from the qtconsole menu
1753 * :ghissue:`2139`: 00_notebook_tour Image example broken on master
1753 * :ghissue:`2139`: 00_notebook_tour Image example broken on master
1754 * :ghissue:`2143`: Add a %%cython_annotate magic
1754 * :ghissue:`2143`: Add a %%cython_annotate magic
1755 * :ghissue:`2135`: Running IPython from terminal
1755 * :ghissue:`2135`: Running IPython from terminal
1756 * :ghissue:`2093`: Makefile for building Sphinx documentation on Windows
1756 * :ghissue:`2093`: Makefile for building Sphinx documentation on Windows
1757 * :ghissue:`2122`: Bug in pretty printing
1757 * :ghissue:`2122`: Bug in pretty printing
1758 * :ghissue:`2120`: Notebook "Make a Copy..." keeps opening duplicates in the same tab
1758 * :ghissue:`2120`: Notebook "Make a Copy..." keeps opening duplicates in the same tab
1759 * :ghissue:`1997`: password cannot be used with url prefix
1759 * :ghissue:`1997`: password cannot be used with url prefix
1760 * :ghissue:`2129`: help/doc displayed multiple times if requested in loop
1760 * :ghissue:`2129`: help/doc displayed multiple times if requested in loop
1761 * :ghissue:`2121`: ipdb does not support input history in qtconsole
1761 * :ghissue:`2121`: ipdb does not support input history in qtconsole
1762 * :ghissue:`2114`: %logstart doesn't log
1762 * :ghissue:`2114`: %logstart doesn't log
1763 * :ghissue:`2085`: %ed magic fails in qtconsole
1763 * :ghissue:`2085`: %ed magic fails in qtconsole
1764 * :ghissue:`2119`: iPython fails to run on MacOS Lion
1764 * :ghissue:`2119`: iPython fails to run on MacOS Lion
1765 * :ghissue:`2052`: %pylab inline magic does not work on windows
1765 * :ghissue:`2052`: %pylab inline magic does not work on windows
1766 * :ghissue:`2111`: Ipython won't start on W7
1766 * :ghissue:`2111`: Ipython won't start on W7
1767 * :ghissue:`2112`: Strange internal traceback
1767 * :ghissue:`2112`: Strange internal traceback
1768 * :ghissue:`2108`: Backslash (\) at the end of the line behavior different from default Python
1768 * :ghissue:`2108`: Backslash (\) at the end of the line behavior different from default Python
1769 * :ghissue:`1425`: Ampersands can't be typed sometimes in notebook cells
1769 * :ghissue:`1425`: Ampersands can't be typed sometimes in notebook cells
1770 * :ghissue:`1513`: Add expand/collapse support for long output elements like stdout and tracebacks
1770 * :ghissue:`1513`: Add expand/collapse support for long output elements like stdout and tracebacks
1771 * :ghissue:`2087`: error when starting ipython
1771 * :ghissue:`2087`: error when starting ipython
1772 * :ghissue:`2103`: Ability to run notebook file from commandline
1772 * :ghissue:`2103`: Ability to run notebook file from commandline
1773 * :ghissue:`2082`: Qt Console output spacing
1773 * :ghissue:`2082`: Qt Console output spacing
1774 * :ghissue:`2083`: Test failures with Python 3.2 and PYTHONWARNINGS="d"
1774 * :ghissue:`2083`: Test failures with Python 3.2 and PYTHONWARNINGS="d"
1775 * :ghissue:`2094`: about inline
1775 * :ghissue:`2094`: about inline
1776 * :ghissue:`2077`: Starting IPython3 on the terminal
1776 * :ghissue:`2077`: Starting IPython3 on the terminal
1777 * :ghissue:`1760`: easy_install ipython fails on py3.2-win32
1777 * :ghissue:`1760`: easy_install ipython fails on py3.2-win32
1778 * :ghissue:`2075`: Local Mathjax install causes iptest3 error under python3
1778 * :ghissue:`2075`: Local Mathjax install causes iptest3 error under python3
1779 * :ghissue:`2057`: setup fails for python3 with LANG=C
1779 * :ghissue:`2057`: setup fails for python3 with LANG=C
1780 * :ghissue:`2070`: shebang on Windows
1780 * :ghissue:`2070`: shebang on Windows
1781 * :ghissue:`2054`: sys_info missing git hash in sdists
1781 * :ghissue:`2054`: sys_info missing git hash in sdists
1782 * :ghissue:`2059`: duplicate and modified files in documentation
1782 * :ghissue:`2059`: duplicate and modified files in documentation
1783 * :ghissue:`2056`: except-shadows-builtin osm.py:687
1783 * :ghissue:`2056`: except-shadows-builtin osm.py:687
1784 * :ghissue:`2058`: hyphen-used-as-minus-sign in manpages
1784 * :ghissue:`2058`: hyphen-used-as-minus-sign in manpages
General Comments 0
You need to be logged in to leave comments. Login now