##// END OF EJS Templates
Various docs fixes
Thomas Kluyver -
Show More
@@ -1,282 +1,285 b''
1 1 """Remote Functions and decorators for Views.
2 2
3 3 Authors:
4 4
5 5 * Brian Granger
6 6 * Min RK
7 7 """
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2010-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from __future__ import division
20 20
21 21 import sys
22 22 import warnings
23 23
24 24 from IPython.external.decorator import decorator
25 25 from IPython.testing.skipdoctest import skip_doctest
26 26
27 27 from . import map as Map
28 28 from .asyncresult import AsyncMapResult
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Functions and Decorators
32 32 #-----------------------------------------------------------------------------
33 33
34 34 @skip_doctest
35 35 def remote(view, block=None, **flags):
36 36 """Turn a function into a remote function.
37 37
38 38 This method can be used for map:
39 39
40 40 In [1]: @remote(view,block=True)
41 41 ...: def func(a):
42 42 ...: pass
43 43 """
44 44
45 45 def remote_function(f):
46 46 return RemoteFunction(view, f, block=block, **flags)
47 47 return remote_function
48 48
49 49 @skip_doctest
50 50 def parallel(view, dist='b', block=None, ordered=True, **flags):
51 51 """Turn a function into a parallel remote function.
52 52
53 53 This method can be used for map:
54 54
55 55 In [1]: @parallel(view, block=True)
56 56 ...: def func(a):
57 57 ...: pass
58 58 """
59 59
60 60 def parallel_function(f):
61 61 return ParallelFunction(view, f, dist=dist, block=block, ordered=ordered, **flags)
62 62 return parallel_function
63 63
64 64 def getname(f):
65 65 """Get the name of an object.
66 66
67 67 For use in case of callables that are not functions, and
68 68 thus may not have __name__ defined.
69 69
70 70 Order: f.__name__ > f.name > str(f)
71 71 """
72 72 try:
73 73 return f.__name__
74 74 except:
75 75 pass
76 76 try:
77 77 return f.name
78 78 except:
79 79 pass
80 80
81 81 return str(f)
82 82
83 83 @decorator
84 84 def sync_view_results(f, self, *args, **kwargs):
85 85 """sync relevant results from self.client to our results attribute.
86 86
87 87 This is a clone of view.sync_results, but for remote functions
88 88 """
89 89 view = self.view
90 90 if view._in_sync_results:
91 91 return f(self, *args, **kwargs)
92 92 view._in_sync_results = True
93 93 try:
94 94 ret = f(self, *args, **kwargs)
95 95 finally:
96 96 view._in_sync_results = False
97 97 view._sync_results()
98 98 return ret
99 99
100 100 #--------------------------------------------------------------------------
101 101 # Classes
102 102 #--------------------------------------------------------------------------
103 103
104 104 class RemoteFunction(object):
105 105 """Turn an existing function into a remote function.
106 106
107 107 Parameters
108 108 ----------
109 109
110 110 view : View instance
111 111 The view to be used for execution
112 112 f : callable
113 113 The function to be wrapped into a remote function
114 114 block : bool [default: None]
115 115 Whether to wait for results or not. The default behavior is
116 116 to use the current `block` attribute of `view`
117 117
118 118 **flags : remaining kwargs are passed to View.temp_flags
119 119 """
120 120
121 121 view = None # the remote connection
122 122 func = None # the wrapped function
123 123 block = None # whether to block
124 124 flags = None # dict of extra kwargs for temp_flags
125 125
126 126 def __init__(self, view, f, block=None, **flags):
127 127 self.view = view
128 128 self.func = f
129 129 self.block=block
130 130 self.flags=flags
131 131
132 132 def __call__(self, *args, **kwargs):
133 133 block = self.view.block if self.block is None else self.block
134 134 with self.view.temp_flags(block=block, **self.flags):
135 135 return self.view.apply(self.func, *args, **kwargs)
136 136
137 137
138 138 class ParallelFunction(RemoteFunction):
139 139 """Class for mapping a function to sequences.
140 140
141 141 This will distribute the sequences according the a mapper, and call
142 142 the function on each sub-sequence. If called via map, then the function
143 143 will be called once on each element, rather that each sub-sequence.
144 144
145 145 Parameters
146 146 ----------
147 147
148 148 view : View instance
149 149 The view to be used for execution
150 150 f : callable
151 151 The function to be wrapped into a remote function
152 152 dist : str [default: 'b']
153 153 The key for which mapObject to use to distribute sequences
154 154 options are:
155 * 'b' : use contiguous chunks in order
156 * 'r' : use round-robin striping
155
156 * 'b' : use contiguous chunks in order
157 * 'r' : use round-robin striping
158
157 159 block : bool [default: None]
158 160 Whether to wait for results or not. The default behavior is
159 161 to use the current `block` attribute of `view`
160 162 chunksize : int or None
161 163 The size of chunk to use when breaking up sequences in a load-balanced manner
162 164 ordered : bool [default: True]
163 165 Whether the result should be kept in order. If False,
164 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 171 chunksize = None
169 172 ordered = None
170 173 mapObject = None
171 174 _mapping = False
172 175
173 176 def __init__(self, view, f, dist='b', block=None, chunksize=None, ordered=True, **flags):
174 177 super(ParallelFunction, self).__init__(view, f, block=block, **flags)
175 178 self.chunksize = chunksize
176 179 self.ordered = ordered
177 180
178 181 mapClass = Map.dists[dist]
179 182 self.mapObject = mapClass()
180 183
181 184 @sync_view_results
182 185 def __call__(self, *sequences):
183 186 client = self.view.client
184 187
185 188 lens = []
186 189 maxlen = minlen = -1
187 190 for i, seq in enumerate(sequences):
188 191 try:
189 192 n = len(seq)
190 193 except Exception:
191 194 seq = list(seq)
192 195 if isinstance(sequences, tuple):
193 196 # can't alter a tuple
194 197 sequences = list(sequences)
195 198 sequences[i] = seq
196 199 n = len(seq)
197 200 if n > maxlen:
198 201 maxlen = n
199 202 if minlen == -1 or n < minlen:
200 203 minlen = n
201 204 lens.append(n)
202 205
203 206 # check that the length of sequences match
204 207 if not self._mapping and minlen != maxlen:
205 208 msg = 'all sequences must have equal length, but have %s' % lens
206 209 raise ValueError(msg)
207 210
208 211 balanced = 'Balanced' in self.view.__class__.__name__
209 212 if balanced:
210 213 if self.chunksize:
211 214 nparts = maxlen // self.chunksize + int(maxlen % self.chunksize > 0)
212 215 else:
213 216 nparts = maxlen
214 217 targets = [None]*nparts
215 218 else:
216 219 if self.chunksize:
217 220 warnings.warn("`chunksize` is ignored unless load balancing", UserWarning)
218 221 # multiplexed:
219 222 targets = self.view.targets
220 223 # 'all' is lazily evaluated at execution time, which is now:
221 224 if targets == 'all':
222 225 targets = client._build_targets(targets)[1]
223 226 elif isinstance(targets, int):
224 227 # single-engine view, targets must be iterable
225 228 targets = [targets]
226 229 nparts = len(targets)
227 230
228 231 msg_ids = []
229 232 for index, t in enumerate(targets):
230 233 args = []
231 234 for seq in sequences:
232 235 part = self.mapObject.getPartition(seq, index, nparts, maxlen)
233 236 args.append(part)
234 237
235 238 if sum([len(arg) for arg in args]) == 0:
236 239 continue
237 240
238 241 if self._mapping:
239 242 if sys.version_info[0] >= 3:
240 243 f = lambda f, *sequences: list(map(f, *sequences))
241 244 else:
242 245 f = map
243 246 args = [self.func] + args
244 247 else:
245 248 f=self.func
246 249
247 250 view = self.view if balanced else client[t]
248 251 with view.temp_flags(block=False, **self.flags):
249 252 ar = view.apply(f, *args)
250 253
251 254 msg_ids.extend(ar.msg_ids)
252 255
253 256 r = AsyncMapResult(self.view.client, msg_ids, self.mapObject,
254 257 fname=getname(self.func),
255 258 ordered=self.ordered
256 259 )
257 260
258 261 if self.block:
259 262 try:
260 263 return r.get()
261 264 except KeyboardInterrupt:
262 265 return r
263 266 else:
264 267 return r
265 268
266 269 def map(self, *sequences):
267 270 """call a function on each element of one or more sequence(s) remotely.
268 271 This should behave very much like the builtin map, but return an AsyncMapResult
269 272 if self.block is False.
270 273
271 274 That means it can take generators (will be cast to lists locally),
272 275 and mismatched sequence lengths will be padded with None.
273 276 """
274 277 # set _mapping as a flag for use inside self.__call__
275 278 self._mapping = True
276 279 try:
277 280 ret = self(*sequences)
278 281 finally:
279 282 self._mapping = False
280 283 return ret
281 284
282 285 __all__ = ['remote', 'parallel', 'RemoteFunction', 'ParallelFunction']
@@ -1,1119 +1,1114 b''
1 1 """Views of remote engines.
2 2
3 3 Authors:
4 4
5 5 * Min RK
6 6 """
7 7 from __future__ import print_function
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2010-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 import imp
20 20 import sys
21 21 import warnings
22 22 from contextlib import contextmanager
23 23 from types import ModuleType
24 24
25 25 import zmq
26 26
27 27 from IPython.testing.skipdoctest import skip_doctest
28 28 from IPython.utils.traitlets import (
29 29 HasTraits, Any, Bool, List, Dict, Set, Instance, CFloat, Integer
30 30 )
31 31 from IPython.external.decorator import decorator
32 32
33 33 from IPython.parallel import util
34 34 from IPython.parallel.controller.dependency import Dependency, dependent
35 35 from IPython.utils.py3compat import string_types, iteritems, PY3
36 36
37 37 from . import map as Map
38 38 from .asyncresult import AsyncResult, AsyncMapResult
39 39 from .remotefunction import ParallelFunction, parallel, remote, getname
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Decorators
43 43 #-----------------------------------------------------------------------------
44 44
45 45 @decorator
46 46 def save_ids(f, self, *args, **kwargs):
47 47 """Keep our history and outstanding attributes up to date after a method call."""
48 48 n_previous = len(self.client.history)
49 49 try:
50 50 ret = f(self, *args, **kwargs)
51 51 finally:
52 52 nmsgs = len(self.client.history) - n_previous
53 53 msg_ids = self.client.history[-nmsgs:]
54 54 self.history.extend(msg_ids)
55 55 self.outstanding.update(msg_ids)
56 56 return ret
57 57
58 58 @decorator
59 59 def sync_results(f, self, *args, **kwargs):
60 60 """sync relevant results from self.client to our results attribute."""
61 61 if self._in_sync_results:
62 62 return f(self, *args, **kwargs)
63 63 self._in_sync_results = True
64 64 try:
65 65 ret = f(self, *args, **kwargs)
66 66 finally:
67 67 self._in_sync_results = False
68 68 self._sync_results()
69 69 return ret
70 70
71 71 @decorator
72 72 def spin_after(f, self, *args, **kwargs):
73 73 """call spin after the method."""
74 74 ret = f(self, *args, **kwargs)
75 75 self.spin()
76 76 return ret
77 77
78 78 #-----------------------------------------------------------------------------
79 79 # Classes
80 80 #-----------------------------------------------------------------------------
81 81
82 82 @skip_doctest
83 83 class View(HasTraits):
84 84 """Base View class for more convenint apply(f,*args,**kwargs) syntax via attributes.
85 85
86 86 Don't use this class, use subclasses.
87 87
88 88 Methods
89 89 -------
90 90
91 91 spin
92 92 flushes incoming results and registration state changes
93 93 control methods spin, and requesting `ids` also ensures up to date
94 94
95 95 wait
96 96 wait on one or more msg_ids
97 97
98 98 execution methods
99 99 apply
100 100 legacy: execute, run
101 101
102 102 data movement
103 103 push, pull, scatter, gather
104 104
105 105 query methods
106 106 get_result, queue_status, purge_results, result_status
107 107
108 108 control methods
109 109 abort, shutdown
110 110
111 111 """
112 112 # flags
113 113 block=Bool(False)
114 114 track=Bool(True)
115 115 targets = Any()
116 116
117 117 history=List()
118 118 outstanding = Set()
119 119 results = Dict()
120 120 client = Instance('IPython.parallel.Client')
121 121
122 122 _socket = Instance('zmq.Socket')
123 123 _flag_names = List(['targets', 'block', 'track'])
124 124 _in_sync_results = Bool(False)
125 125 _targets = Any()
126 126 _idents = Any()
127 127
128 128 def __init__(self, client=None, socket=None, **flags):
129 129 super(View, self).__init__(client=client, _socket=socket)
130 130 self.results = client.results
131 131 self.block = client.block
132 132
133 133 self.set_flags(**flags)
134 134
135 135 assert not self.__class__ is View, "Don't use base View objects, use subclasses"
136 136
137 137 def __repr__(self):
138 138 strtargets = str(self.targets)
139 139 if len(strtargets) > 16:
140 140 strtargets = strtargets[:12]+'...]'
141 141 return "<%s %s>"%(self.__class__.__name__, strtargets)
142 142
143 143 def __len__(self):
144 144 if isinstance(self.targets, list):
145 145 return len(self.targets)
146 146 elif isinstance(self.targets, int):
147 147 return 1
148 148 else:
149 149 return len(self.client)
150 150
151 151 def set_flags(self, **kwargs):
152 152 """set my attribute flags by keyword.
153 153
154 154 Views determine behavior with a few attributes (`block`, `track`, etc.).
155 155 These attributes can be set all at once by name with this method.
156 156
157 157 Parameters
158 158 ----------
159 159
160 160 block : bool
161 161 whether to wait for results
162 162 track : bool
163 163 whether to create a MessageTracker to allow the user to
164 164 safely edit after arrays and buffers during non-copying
165 165 sends.
166 166 """
167 167 for name, value in iteritems(kwargs):
168 168 if name not in self._flag_names:
169 169 raise KeyError("Invalid name: %r"%name)
170 170 else:
171 171 setattr(self, name, value)
172 172
173 173 @contextmanager
174 174 def temp_flags(self, **kwargs):
175 175 """temporarily set flags, for use in `with` statements.
176 176
177 177 See set_flags for permanent setting of flags
178 178
179 179 Examples
180 180 --------
181 181
182 182 >>> view.track=False
183 183 ...
184 184 >>> with view.temp_flags(track=True):
185 185 ... ar = view.apply(dostuff, my_big_array)
186 186 ... ar.tracker.wait() # wait for send to finish
187 187 >>> view.track
188 188 False
189 189
190 190 """
191 191 # preflight: save flags, and set temporaries
192 192 saved_flags = {}
193 193 for f in self._flag_names:
194 194 saved_flags[f] = getattr(self, f)
195 195 self.set_flags(**kwargs)
196 196 # yield to the with-statement block
197 197 try:
198 198 yield
199 199 finally:
200 200 # postflight: restore saved flags
201 201 self.set_flags(**saved_flags)
202 202
203 203
204 204 #----------------------------------------------------------------
205 205 # apply
206 206 #----------------------------------------------------------------
207 207
208 208 def _sync_results(self):
209 209 """to be called by @sync_results decorator
210 210
211 211 after submitting any tasks.
212 212 """
213 213 delta = self.outstanding.difference(self.client.outstanding)
214 214 completed = self.outstanding.intersection(delta)
215 215 self.outstanding = self.outstanding.difference(completed)
216 216
217 217 @sync_results
218 218 @save_ids
219 219 def _really_apply(self, f, args, kwargs, block=None, **options):
220 220 """wrapper for client.send_apply_request"""
221 221 raise NotImplementedError("Implement in subclasses")
222 222
223 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 226 This method sets all apply flags via this View's attributes.
227 227
228 if self.block is False:
229 returns AsyncResult
230 else:
231 returns actual result of f(*args, **kwargs)
228 Returns :class:`~IPython.parallel.client.asyncresult.AsyncResult`
229 instance if ``self.block`` is False, otherwise the return value of
230 ``f(*args, **kwargs)``.
232 231 """
233 232 return self._really_apply(f, args, kwargs)
234 233
235 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 239 return self._really_apply(f, args, kwargs, block=False)
241 240
242 241 @spin_after
243 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 244 returning the result.
246
247 returns: actual result of f(*args, **kwargs)
248 245 """
249 246 return self._really_apply(f, args, kwargs, block=True)
250 247
251 248 #----------------------------------------------------------------
252 249 # wrappers for client and control methods
253 250 #----------------------------------------------------------------
254 251 @sync_results
255 252 def spin(self):
256 253 """spin the client, and sync"""
257 254 self.client.spin()
258 255
259 256 @sync_results
260 257 def wait(self, jobs=None, timeout=-1):
261 258 """waits on one or more `jobs`, for up to `timeout` seconds.
262 259
263 260 Parameters
264 261 ----------
265 262
266 263 jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects
267 264 ints are indices to self.history
268 265 strs are msg_ids
269 266 default: wait on all outstanding messages
270 267 timeout : float
271 268 a time in seconds, after which to give up.
272 269 default is -1, which means no timeout
273 270
274 271 Returns
275 272 -------
276 273
277 274 True : when all msg_ids are done
278 275 False : timeout reached, some msg_ids still outstanding
279 276 """
280 277 if jobs is None:
281 278 jobs = self.history
282 279 return self.client.wait(jobs, timeout)
283 280
284 281 def abort(self, jobs=None, targets=None, block=None):
285 282 """Abort jobs on my engines.
286 283
287 284 Parameters
288 285 ----------
289 286
290 287 jobs : None, str, list of strs, optional
291 288 if None: abort all jobs.
292 289 else: abort specific msg_id(s).
293 290 """
294 291 block = block if block is not None else self.block
295 292 targets = targets if targets is not None else self.targets
296 293 jobs = jobs if jobs is not None else list(self.outstanding)
297 294
298 295 return self.client.abort(jobs=jobs, targets=targets, block=block)
299 296
300 297 def queue_status(self, targets=None, verbose=False):
301 298 """Fetch the Queue status of my engines"""
302 299 targets = targets if targets is not None else self.targets
303 300 return self.client.queue_status(targets=targets, verbose=verbose)
304 301
305 302 def purge_results(self, jobs=[], targets=[]):
306 303 """Instruct the controller to forget specific results."""
307 304 if targets is None or targets == 'all':
308 305 targets = self.targets
309 306 return self.client.purge_results(jobs=jobs, targets=targets)
310 307
311 308 def shutdown(self, targets=None, restart=False, hub=False, block=None):
312 309 """Terminates one or more engine processes, optionally including the hub.
313 310 """
314 311 block = self.block if block is None else block
315 312 if targets is None or targets == 'all':
316 313 targets = self.targets
317 314 return self.client.shutdown(targets=targets, restart=restart, hub=hub, block=block)
318 315
319 316 @spin_after
320 317 def get_result(self, indices_or_msg_ids=None):
321 318 """return one or more results, specified by history index or msg_id.
322 319
323 See client.get_result for details.
324
320 See :meth:`IPython.parallel.client.client.Client.get_result` for details.
325 321 """
326 322
327 323 if indices_or_msg_ids is None:
328 324 indices_or_msg_ids = -1
329 325 if isinstance(indices_or_msg_ids, int):
330 326 indices_or_msg_ids = self.history[indices_or_msg_ids]
331 327 elif isinstance(indices_or_msg_ids, (list,tuple,set)):
332 328 indices_or_msg_ids = list(indices_or_msg_ids)
333 329 for i,index in enumerate(indices_or_msg_ids):
334 330 if isinstance(index, int):
335 331 indices_or_msg_ids[i] = self.history[index]
336 332 return self.client.get_result(indices_or_msg_ids)
337 333
338 334 #-------------------------------------------------------------------
339 335 # Map
340 336 #-------------------------------------------------------------------
341 337
342 338 @sync_results
343 339 def map(self, f, *sequences, **kwargs):
344 340 """override in subclasses"""
345 341 raise NotImplementedError
346 342
347 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 348 See `self.map` for details.
353 349 """
354 350 if 'block' in kwargs:
355 351 raise TypeError("map_async doesn't take a `block` keyword argument.")
356 352 kwargs['block'] = False
357 353 return self.map(f,*sequences,**kwargs)
358 354
359 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 360 See `self.map` for details.
365 361 """
366 362 if 'block' in kwargs:
367 363 raise TypeError("map_sync doesn't take a `block` keyword argument.")
368 364 kwargs['block'] = True
369 365 return self.map(f,*sequences,**kwargs)
370 366
371 367 def imap(self, f, *sequences, **kwargs):
372 """Parallel version of `itertools.imap`.
368 """Parallel version of :func:`itertools.imap`.
373 369
374 370 See `self.map` for details.
375 371
376 372 """
377 373
378 374 return iter(self.map_async(f,*sequences, **kwargs))
379 375
380 376 #-------------------------------------------------------------------
381 377 # Decorators
382 378 #-------------------------------------------------------------------
383 379
384 380 def remote(self, block=None, **flags):
385 381 """Decorator for making a RemoteFunction"""
386 382 block = self.block if block is None else block
387 383 return remote(self, block=block, **flags)
388 384
389 385 def parallel(self, dist='b', block=None, **flags):
390 386 """Decorator for making a ParallelFunction"""
391 387 block = self.block if block is None else block
392 388 return parallel(self, dist=dist, block=block, **flags)
393 389
394 390 @skip_doctest
395 391 class DirectView(View):
396 392 """Direct Multiplexer View of one or more engines.
397 393
398 394 These are created via indexed access to a client:
399 395
400 396 >>> dv_1 = client[1]
401 397 >>> dv_all = client[:]
402 398 >>> dv_even = client[::2]
403 399 >>> dv_some = client[1:3]
404 400
405 401 This object provides dictionary access to engine namespaces:
406 402
407 403 # push a=5:
408 404 >>> dv['a'] = 5
409 405 # pull 'foo':
410 406 >>> db['foo']
411 407
412 408 """
413 409
414 410 def __init__(self, client=None, socket=None, targets=None):
415 411 super(DirectView, self).__init__(client=client, socket=socket, targets=targets)
416 412
417 413 @property
418 414 def importer(self):
419 415 """sync_imports(local=True) as a property.
420 416
421 417 See sync_imports for details.
422 418
423 419 """
424 420 return self.sync_imports(True)
425 421
426 422 @contextmanager
427 423 def sync_imports(self, local=True, quiet=False):
428 424 """Context Manager for performing simultaneous local and remote imports.
429 425
430 426 'import x as y' will *not* work. The 'as y' part will simply be ignored.
431 427
432 428 If `local=True`, then the package will also be imported locally.
433 429
434 430 If `quiet=True`, no output will be produced when attempting remote
435 431 imports.
436 432
437 433 Note that remote-only (`local=False`) imports have not been implemented.
438 434
439 435 >>> with view.sync_imports():
440 436 ... from numpy import recarray
441 437 importing recarray from numpy on engine(s)
442 438
443 439 """
444 440 from IPython.utils.py3compat import builtin_mod
445 441 local_import = builtin_mod.__import__
446 442 modules = set()
447 443 results = []
448 444 @util.interactive
449 445 def remote_import(name, fromlist, level):
450 446 """the function to be passed to apply, that actually performs the import
451 447 on the engine, and loads up the user namespace.
452 448 """
453 449 import sys
454 450 user_ns = globals()
455 451 mod = __import__(name, fromlist=fromlist, level=level)
456 452 if fromlist:
457 453 for key in fromlist:
458 454 user_ns[key] = getattr(mod, key)
459 455 else:
460 456 user_ns[name] = sys.modules[name]
461 457
462 458 def view_import(name, globals={}, locals={}, fromlist=[], level=0):
463 459 """the drop-in replacement for __import__, that optionally imports
464 460 locally as well.
465 461 """
466 462 # don't override nested imports
467 463 save_import = builtin_mod.__import__
468 464 builtin_mod.__import__ = local_import
469 465
470 466 if imp.lock_held():
471 467 # this is a side-effect import, don't do it remotely, or even
472 468 # ignore the local effects
473 469 return local_import(name, globals, locals, fromlist, level)
474 470
475 471 imp.acquire_lock()
476 472 if local:
477 473 mod = local_import(name, globals, locals, fromlist, level)
478 474 else:
479 475 raise NotImplementedError("remote-only imports not yet implemented")
480 476 imp.release_lock()
481 477
482 478 key = name+':'+','.join(fromlist or [])
483 479 if level <= 0 and key not in modules:
484 480 modules.add(key)
485 481 if not quiet:
486 482 if fromlist:
487 483 print("importing %s from %s on engine(s)"%(','.join(fromlist), name))
488 484 else:
489 485 print("importing %s on engine(s)"%name)
490 486 results.append(self.apply_async(remote_import, name, fromlist, level))
491 487 # restore override
492 488 builtin_mod.__import__ = save_import
493 489
494 490 return mod
495 491
496 492 # override __import__
497 493 builtin_mod.__import__ = view_import
498 494 try:
499 495 # enter the block
500 496 yield
501 497 except ImportError:
502 498 if local:
503 499 raise
504 500 else:
505 501 # ignore import errors if not doing local imports
506 502 pass
507 503 finally:
508 504 # always restore __import__
509 505 builtin_mod.__import__ = local_import
510 506
511 507 for r in results:
512 508 # raise possible remote ImportErrors here
513 509 r.get()
514 510
515 511
516 512 @sync_results
517 513 @save_ids
518 514 def _really_apply(self, f, args=None, kwargs=None, targets=None, block=None, track=None):
519 515 """calls f(*args, **kwargs) on remote engines, returning the result.
520 516
521 517 This method sets all of `apply`'s flags via this View's attributes.
522 518
523 519 Parameters
524 520 ----------
525 521
526 522 f : callable
527 523
528 524 args : list [default: empty]
529 525
530 526 kwargs : dict [default: empty]
531 527
532 528 targets : target list [default: self.targets]
533 529 where to run
534 530 block : bool [default: self.block]
535 531 whether to block
536 532 track : bool [default: self.track]
537 533 whether to ask zmq to track the message, for safe non-copying sends
538 534
539 535 Returns
540 536 -------
541 537
542 538 if self.block is False:
543 539 returns AsyncResult
544 540 else:
545 541 returns actual result of f(*args, **kwargs) on the engine(s)
546 542 This will be a list of self.targets is also a list (even length 1), or
547 543 the single result if self.targets is an integer engine id
548 544 """
549 545 args = [] if args is None else args
550 546 kwargs = {} if kwargs is None else kwargs
551 547 block = self.block if block is None else block
552 548 track = self.track if track is None else track
553 549 targets = self.targets if targets is None else targets
554 550
555 551 _idents, _targets = self.client._build_targets(targets)
556 552 msg_ids = []
557 553 trackers = []
558 554 for ident in _idents:
559 555 msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track,
560 556 ident=ident)
561 557 if track:
562 558 trackers.append(msg['tracker'])
563 559 msg_ids.append(msg['header']['msg_id'])
564 560 if isinstance(targets, int):
565 561 msg_ids = msg_ids[0]
566 562 tracker = None if track is False else zmq.MessageTracker(*trackers)
567 563 ar = AsyncResult(self.client, msg_ids, fname=getname(f), targets=_targets, tracker=tracker)
568 564 if block:
569 565 try:
570 566 return ar.get()
571 567 except KeyboardInterrupt:
572 568 pass
573 569 return ar
574 570
575 571
576 572 @sync_results
577 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 576 Parallel version of builtin `map`, using this View's `targets`.
581 577
582 578 There will be one task per target, so work will be chunked
583 579 if the sequences are longer than `targets`.
584 580
585 581 Results can be iterated as they are ready, but will become available in chunks.
586 582
587 583 Parameters
588 584 ----------
589 585
590 586 f : callable
591 587 function to be mapped
592 588 *sequences: one or more sequences of matching length
593 589 the sequences to be distributed and passed to `f`
594 590 block : bool
595 591 whether to wait for the result or not [default self.block]
596 592
597 593 Returns
598 594 -------
599 595
600 if block=False:
601 AsyncMapResult
602 An object like AsyncResult, but which reassembles the sequence of results
603 into a single list. AsyncMapResults can be iterated through before all
604 results are complete.
605 else:
606 list
607 the result of map(f,*sequences)
596
597 If block=False
598 An :class:`~IPython.parallel.client.asyncresult.AsyncMapResult` instance.
599 An object like AsyncResult, but which reassembles the sequence of results
600 into a single list. AsyncMapResults can be iterated through before all
601 results are complete.
602 else
603 A list, the result of ``map(f,*sequences)``
608 604 """
609 605
610 606 block = kwargs.pop('block', self.block)
611 607 for k in kwargs.keys():
612 608 if k not in ['block', 'track']:
613 609 raise TypeError("invalid keyword arg, %r"%k)
614 610
615 611 assert len(sequences) > 0, "must have some sequences to map onto!"
616 612 pf = ParallelFunction(self, f, block=block, **kwargs)
617 613 return pf.map(*sequences)
618 614
619 615 @sync_results
620 616 @save_ids
621 617 def execute(self, code, silent=True, targets=None, block=None):
622 618 """Executes `code` on `targets` in blocking or nonblocking manner.
623 619
624 620 ``execute`` is always `bound` (affects engine namespace)
625 621
626 622 Parameters
627 623 ----------
628 624
629 625 code : str
630 626 the code string to be executed
631 627 block : bool
632 628 whether or not to wait until done to return
633 629 default: self.block
634 630 """
635 631 block = self.block if block is None else block
636 632 targets = self.targets if targets is None else targets
637 633
638 634 _idents, _targets = self.client._build_targets(targets)
639 635 msg_ids = []
640 636 trackers = []
641 637 for ident in _idents:
642 638 msg = self.client.send_execute_request(self._socket, code, silent=silent, ident=ident)
643 639 msg_ids.append(msg['header']['msg_id'])
644 640 if isinstance(targets, int):
645 641 msg_ids = msg_ids[0]
646 642 ar = AsyncResult(self.client, msg_ids, fname='execute', targets=_targets)
647 643 if block:
648 644 try:
649 645 ar.get()
650 646 except KeyboardInterrupt:
651 647 pass
652 648 return ar
653 649
654 650 def run(self, filename, targets=None, block=None):
655 651 """Execute contents of `filename` on my engine(s).
656 652
657 653 This simply reads the contents of the file and calls `execute`.
658 654
659 655 Parameters
660 656 ----------
661 657
662 658 filename : str
663 659 The path to the file
664 660 targets : int/str/list of ints/strs
665 661 the engines on which to execute
666 662 default : all
667 663 block : bool
668 664 whether or not to wait until done
669 665 default: self.block
670 666
671 667 """
672 668 with open(filename, 'r') as f:
673 669 # add newline in case of trailing indented whitespace
674 670 # which will cause SyntaxError
675 671 code = f.read()+'\n'
676 672 return self.execute(code, block=block, targets=targets)
677 673
678 674 def update(self, ns):
679 675 """update remote namespace with dict `ns`
680 676
681 677 See `push` for details.
682 678 """
683 679 return self.push(ns, block=self.block, track=self.track)
684 680
685 681 def push(self, ns, targets=None, block=None, track=None):
686 682 """update remote namespace with dict `ns`
687 683
688 684 Parameters
689 685 ----------
690 686
691 687 ns : dict
692 688 dict of keys with which to update engine namespace(s)
693 689 block : bool [default : self.block]
694 690 whether to wait to be notified of engine receipt
695 691
696 692 """
697 693
698 694 block = block if block is not None else self.block
699 695 track = track if track is not None else self.track
700 696 targets = targets if targets is not None else self.targets
701 697 # applier = self.apply_sync if block else self.apply_async
702 698 if not isinstance(ns, dict):
703 699 raise TypeError("Must be a dict, not %s"%type(ns))
704 700 return self._really_apply(util._push, kwargs=ns, block=block, track=track, targets=targets)
705 701
706 702 def get(self, key_s):
707 703 """get object(s) by `key_s` from remote namespace
708 704
709 705 see `pull` for details.
710 706 """
711 707 # block = block if block is not None else self.block
712 708 return self.pull(key_s, block=True)
713 709
714 710 def pull(self, names, targets=None, block=None):
715 711 """get object(s) by `name` from remote namespace
716 712
717 713 will return one object if it is a key.
718 714 can also take a list of keys, in which case it will return a list of objects.
719 715 """
720 716 block = block if block is not None else self.block
721 717 targets = targets if targets is not None else self.targets
722 718 applier = self.apply_sync if block else self.apply_async
723 719 if isinstance(names, string_types):
724 720 pass
725 721 elif isinstance(names, (list,tuple,set)):
726 722 for key in names:
727 723 if not isinstance(key, string_types):
728 724 raise TypeError("keys must be str, not type %r"%type(key))
729 725 else:
730 726 raise TypeError("names must be strs, not %r"%names)
731 727 return self._really_apply(util._pull, (names,), block=block, targets=targets)
732 728
733 729 def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None, track=None):
734 730 """
735 731 Partition a Python sequence and send the partitions to a set of engines.
736 732 """
737 733 block = block if block is not None else self.block
738 734 track = track if track is not None else self.track
739 735 targets = targets if targets is not None else self.targets
740 736
741 737 # construct integer ID list:
742 738 targets = self.client._build_targets(targets)[1]
743 739
744 740 mapObject = Map.dists[dist]()
745 741 nparts = len(targets)
746 742 msg_ids = []
747 743 trackers = []
748 744 for index, engineid in enumerate(targets):
749 745 partition = mapObject.getPartition(seq, index, nparts)
750 746 if flatten and len(partition) == 1:
751 747 ns = {key: partition[0]}
752 748 else:
753 749 ns = {key: partition}
754 750 r = self.push(ns, block=False, track=track, targets=engineid)
755 751 msg_ids.extend(r.msg_ids)
756 752 if track:
757 753 trackers.append(r._tracker)
758 754
759 755 if track:
760 756 tracker = zmq.MessageTracker(*trackers)
761 757 else:
762 758 tracker = None
763 759
764 760 r = AsyncResult(self.client, msg_ids, fname='scatter', targets=targets, tracker=tracker)
765 761 if block:
766 762 r.wait()
767 763 else:
768 764 return r
769 765
770 766 @sync_results
771 767 @save_ids
772 768 def gather(self, key, dist='b', targets=None, block=None):
773 769 """
774 770 Gather a partitioned sequence on a set of engines as a single local seq.
775 771 """
776 772 block = block if block is not None else self.block
777 773 targets = targets if targets is not None else self.targets
778 774 mapObject = Map.dists[dist]()
779 775 msg_ids = []
780 776
781 777 # construct integer ID list:
782 778 targets = self.client._build_targets(targets)[1]
783 779
784 780 for index, engineid in enumerate(targets):
785 781 msg_ids.extend(self.pull(key, block=False, targets=engineid).msg_ids)
786 782
787 783 r = AsyncMapResult(self.client, msg_ids, mapObject, fname='gather')
788 784
789 785 if block:
790 786 try:
791 787 return r.get()
792 788 except KeyboardInterrupt:
793 789 pass
794 790 return r
795 791
796 792 def __getitem__(self, key):
797 793 return self.get(key)
798 794
799 795 def __setitem__(self,key, value):
800 796 self.update({key:value})
801 797
802 798 def clear(self, targets=None, block=None):
803 799 """Clear the remote namespaces on my engines."""
804 800 block = block if block is not None else self.block
805 801 targets = targets if targets is not None else self.targets
806 802 return self.client.clear(targets=targets, block=block)
807 803
808 804 #----------------------------------------
809 805 # activate for %px, %autopx, etc. magics
810 806 #----------------------------------------
811 807
812 808 def activate(self, suffix=''):
813 809 """Activate IPython magics associated with this View
814 810
815 811 Defines the magics `%px, %autopx, %pxresult, %%px, %pxconfig`
816 812
817 813 Parameters
818 814 ----------
819 815
820 816 suffix: str [default: '']
821 817 The suffix, if any, for the magics. This allows you to have
822 818 multiple views associated with parallel magics at the same time.
823 819
824 820 e.g. ``rc[::2].activate(suffix='_even')`` will give you
825 821 the magics ``%px_even``, ``%pxresult_even``, etc. for running magics
826 822 on the even engines.
827 823 """
828 824
829 825 from IPython.parallel.client.magics import ParallelMagics
830 826
831 827 try:
832 828 # This is injected into __builtins__.
833 829 ip = get_ipython()
834 830 except NameError:
835 831 print("The IPython parallel magics (%px, etc.) only work within IPython.")
836 832 return
837 833
838 834 M = ParallelMagics(ip, self, suffix)
839 835 ip.magics_manager.register(M)
840 836
841 837
842 838 @skip_doctest
843 839 class LoadBalancedView(View):
844 840 """An load-balancing View that only executes via the Task scheduler.
845 841
846 842 Load-balanced views can be created with the client's `view` method:
847 843
848 844 >>> v = client.load_balanced_view()
849 845
850 846 or targets can be specified, to restrict the potential destinations:
851 847
852 848 >>> v = client.client.load_balanced_view([1,3])
853 849
854 850 which would restrict loadbalancing to between engines 1 and 3.
855 851
856 852 """
857 853
858 854 follow=Any()
859 855 after=Any()
860 856 timeout=CFloat()
861 857 retries = Integer(0)
862 858
863 859 _task_scheme = Any()
864 860 _flag_names = List(['targets', 'block', 'track', 'follow', 'after', 'timeout', 'retries'])
865 861
866 862 def __init__(self, client=None, socket=None, **flags):
867 863 super(LoadBalancedView, self).__init__(client=client, socket=socket, **flags)
868 864 self._task_scheme=client._task_scheme
869 865
870 866 def _validate_dependency(self, dep):
871 867 """validate a dependency.
872 868
873 869 For use in `set_flags`.
874 870 """
875 871 if dep is None or isinstance(dep, string_types + (AsyncResult, Dependency)):
876 872 return True
877 873 elif isinstance(dep, (list,set, tuple)):
878 874 for d in dep:
879 875 if not isinstance(d, string_types + (AsyncResult,)):
880 876 return False
881 877 elif isinstance(dep, dict):
882 878 if set(dep.keys()) != set(Dependency().as_dict().keys()):
883 879 return False
884 880 if not isinstance(dep['msg_ids'], list):
885 881 return False
886 882 for d in dep['msg_ids']:
887 883 if not isinstance(d, string_types):
888 884 return False
889 885 else:
890 886 return False
891 887
892 888 return True
893 889
894 890 def _render_dependency(self, dep):
895 891 """helper for building jsonable dependencies from various input forms."""
896 892 if isinstance(dep, Dependency):
897 893 return dep.as_dict()
898 894 elif isinstance(dep, AsyncResult):
899 895 return dep.msg_ids
900 896 elif dep is None:
901 897 return []
902 898 else:
903 899 # pass to Dependency constructor
904 900 return list(Dependency(dep))
905 901
906 902 def set_flags(self, **kwargs):
907 903 """set my attribute flags by keyword.
908 904
909 905 A View is a wrapper for the Client's apply method, but with attributes
910 906 that specify keyword arguments, those attributes can be set by keyword
911 907 argument with this method.
912 908
913 909 Parameters
914 910 ----------
915 911
916 912 block : bool
917 913 whether to wait for results
918 914 track : bool
919 915 whether to create a MessageTracker to allow the user to
920 916 safely edit after arrays and buffers during non-copying
921 917 sends.
922 918
923 919 after : Dependency or collection of msg_ids
924 920 Only for load-balanced execution (targets=None)
925 921 Specify a list of msg_ids as a time-based dependency.
926 922 This job will only be run *after* the dependencies
927 923 have been met.
928 924
929 925 follow : Dependency or collection of msg_ids
930 926 Only for load-balanced execution (targets=None)
931 927 Specify a list of msg_ids as a location-based dependency.
932 928 This job will only be run on an engine where this dependency
933 929 is met.
934 930
935 931 timeout : float/int or None
936 932 Only for load-balanced execution (targets=None)
937 933 Specify an amount of time (in seconds) for the scheduler to
938 934 wait for dependencies to be met before failing with a
939 935 DependencyTimeout.
940 936
941 937 retries : int
942 938 Number of times a task will be retried on failure.
943 939 """
944 940
945 941 super(LoadBalancedView, self).set_flags(**kwargs)
946 942 for name in ('follow', 'after'):
947 943 if name in kwargs:
948 944 value = kwargs[name]
949 945 if self._validate_dependency(value):
950 946 setattr(self, name, value)
951 947 else:
952 948 raise ValueError("Invalid dependency: %r"%value)
953 949 if 'timeout' in kwargs:
954 950 t = kwargs['timeout']
955 951 if not isinstance(t, (int, float, type(None))):
956 952 if (not PY3) and (not isinstance(t, long)):
957 953 raise TypeError("Invalid type for timeout: %r"%type(t))
958 954 if t is not None:
959 955 if t < 0:
960 956 raise ValueError("Invalid timeout: %s"%t)
961 957 self.timeout = t
962 958
963 959 @sync_results
964 960 @save_ids
965 961 def _really_apply(self, f, args=None, kwargs=None, block=None, track=None,
966 962 after=None, follow=None, timeout=None,
967 963 targets=None, retries=None):
968 964 """calls f(*args, **kwargs) on a remote engine, returning the result.
969 965
970 966 This method temporarily sets all of `apply`'s flags for a single call.
971 967
972 968 Parameters
973 969 ----------
974 970
975 971 f : callable
976 972
977 973 args : list [default: empty]
978 974
979 975 kwargs : dict [default: empty]
980 976
981 977 block : bool [default: self.block]
982 978 whether to block
983 979 track : bool [default: self.track]
984 980 whether to ask zmq to track the message, for safe non-copying sends
985 981
986 982 !!!!!! TODO: THE REST HERE !!!!
987 983
988 984 Returns
989 985 -------
990 986
991 987 if self.block is False:
992 988 returns AsyncResult
993 989 else:
994 990 returns actual result of f(*args, **kwargs) on the engine(s)
995 991 This will be a list of self.targets is also a list (even length 1), or
996 992 the single result if self.targets is an integer engine id
997 993 """
998 994
999 995 # validate whether we can run
1000 996 if self._socket.closed:
1001 997 msg = "Task farming is disabled"
1002 998 if self._task_scheme == 'pure':
1003 999 msg += " because the pure ZMQ scheduler cannot handle"
1004 1000 msg += " disappearing engines."
1005 1001 raise RuntimeError(msg)
1006 1002
1007 1003 if self._task_scheme == 'pure':
1008 1004 # pure zmq scheme doesn't support extra features
1009 1005 msg = "Pure ZMQ scheduler doesn't support the following flags:"
1010 1006 "follow, after, retries, targets, timeout"
1011 1007 if (follow or after or retries or targets or timeout):
1012 1008 # hard fail on Scheduler flags
1013 1009 raise RuntimeError(msg)
1014 1010 if isinstance(f, dependent):
1015 1011 # soft warn on functional dependencies
1016 1012 warnings.warn(msg, RuntimeWarning)
1017 1013
1018 1014 # build args
1019 1015 args = [] if args is None else args
1020 1016 kwargs = {} if kwargs is None else kwargs
1021 1017 block = self.block if block is None else block
1022 1018 track = self.track if track is None else track
1023 1019 after = self.after if after is None else after
1024 1020 retries = self.retries if retries is None else retries
1025 1021 follow = self.follow if follow is None else follow
1026 1022 timeout = self.timeout if timeout is None else timeout
1027 1023 targets = self.targets if targets is None else targets
1028 1024
1029 1025 if not isinstance(retries, int):
1030 1026 raise TypeError('retries must be int, not %r'%type(retries))
1031 1027
1032 1028 if targets is None:
1033 1029 idents = []
1034 1030 else:
1035 1031 idents = self.client._build_targets(targets)[0]
1036 1032 # ensure *not* bytes
1037 1033 idents = [ ident.decode() for ident in idents ]
1038 1034
1039 1035 after = self._render_dependency(after)
1040 1036 follow = self._render_dependency(follow)
1041 1037 metadata = dict(after=after, follow=follow, timeout=timeout, targets=idents, retries=retries)
1042 1038
1043 1039 msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track,
1044 1040 metadata=metadata)
1045 1041 tracker = None if track is False else msg['tracker']
1046 1042
1047 1043 ar = AsyncResult(self.client, msg['header']['msg_id'], fname=getname(f), targets=None, tracker=tracker)
1048 1044
1049 1045 if block:
1050 1046 try:
1051 1047 return ar.get()
1052 1048 except KeyboardInterrupt:
1053 1049 pass
1054 1050 return ar
1055 1051
1056 1052 @sync_results
1057 1053 @save_ids
1058 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 1057 Parallel version of builtin `map`, load-balanced by this View.
1062 1058
1063 1059 `block`, and `chunksize` can be specified by keyword only.
1064 1060
1065 1061 Each `chunksize` elements will be a separate task, and will be
1066 1062 load-balanced. This lets individual elements be available for iteration
1067 1063 as soon as they arrive.
1068 1064
1069 1065 Parameters
1070 1066 ----------
1071 1067
1072 1068 f : callable
1073 1069 function to be mapped
1074 1070 *sequences: one or more sequences of matching length
1075 1071 the sequences to be distributed and passed to `f`
1076 1072 block : bool [default self.block]
1077 1073 whether to wait for the result or not
1078 1074 track : bool
1079 1075 whether to create a MessageTracker to allow the user to
1080 1076 safely edit after arrays and buffers during non-copying
1081 1077 sends.
1082 1078 chunksize : int [default 1]
1083 1079 how many elements should be in each task.
1084 1080 ordered : bool [default True]
1085 1081 Whether the results should be gathered as they arrive, or enforce
1086 1082 the order of submission.
1087 1083
1088 1084 Only applies when iterating through AsyncMapResult as results arrive.
1089 1085 Has no effect when block=True.
1090 1086
1091 1087 Returns
1092 1088 -------
1093 1089
1094 if block=False:
1095 AsyncMapResult
1096 An object like AsyncResult, but which reassembles the sequence of results
1097 into a single list. AsyncMapResults can be iterated through before all
1098 results are complete.
1099 else:
1100 the result of map(f,*sequences)
1101
1090 if block=False
1091 An :class:`~IPython.parallel.client.asyncresult.AsyncMapResult` instance.
1092 An object like AsyncResult, but which reassembles the sequence of results
1093 into a single list. AsyncMapResults can be iterated through before all
1094 results are complete.
1095 else
1096 A list, the result of ``map(f,*sequences)``
1102 1097 """
1103 1098
1104 1099 # default
1105 1100 block = kwargs.get('block', self.block)
1106 1101 chunksize = kwargs.get('chunksize', 1)
1107 1102 ordered = kwargs.get('ordered', True)
1108 1103
1109 1104 keyset = set(kwargs.keys())
1110 1105 extra_keys = keyset.difference_update(set(['block', 'chunksize']))
1111 1106 if extra_keys:
1112 1107 raise TypeError("Invalid kwargs: %s"%list(extra_keys))
1113 1108
1114 1109 assert len(sequences) > 0, "must have some sequences to map onto!"
1115 1110
1116 1111 pf = ParallelFunction(self, f, block=block, chunksize=chunksize, ordered=ordered)
1117 1112 return pf.map(*sequences)
1118 1113
1119 1114 __all__ = ['LoadBalancedView', 'DirectView']
@@ -1,230 +1,229 b''
1 1 """Dependency utilities
2 2
3 3 Authors:
4 4
5 5 * Min RK
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2013 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 from types import ModuleType
15 15
16 16 from IPython.parallel.client.asyncresult import AsyncResult
17 17 from IPython.parallel.error import UnmetDependency
18 18 from IPython.parallel.util import interactive
19 19 from IPython.utils import py3compat
20 20 from IPython.utils.py3compat import string_types
21 21 from IPython.utils.pickleutil import can, uncan
22 22
23 23 class depend(object):
24 24 """Dependency decorator, for use with tasks.
25 25
26 26 `@depend` lets you define a function for engine dependencies
27 27 just like you use `apply` for tasks.
28 28
29 29
30 30 Examples
31 31 --------
32 32 ::
33 33
34 34 @depend(df, a,b, c=5)
35 35 def f(m,n,p)
36 36
37 37 view.apply(f, 1,2,3)
38 38
39 39 will call df(a,b,c=5) on the engine, and if it returns False or
40 40 raises an UnmetDependency error, then the task will not be run
41 41 and another engine will be tried.
42 42 """
43 43 def __init__(self, f, *args, **kwargs):
44 44 self.f = f
45 45 self.args = args
46 46 self.kwargs = kwargs
47 47
48 48 def __call__(self, f):
49 49 return dependent(f, self.f, *self.args, **self.kwargs)
50 50
51 51 class dependent(object):
52 52 """A function that depends on another function.
53 53 This is an object to prevent the closure used
54 54 in traditional decorators, which are not picklable.
55 55 """
56 56
57 57 def __init__(self, f, df, *dargs, **dkwargs):
58 58 self.f = f
59 59 name = getattr(f, '__name__', 'f')
60 60 if py3compat.PY3:
61 61 self.__name__ = name
62 62 else:
63 63 self.func_name = name
64 64 self.df = df
65 65 self.dargs = dargs
66 66 self.dkwargs = dkwargs
67 67
68 68 def check_dependency(self):
69 69 if self.df(*self.dargs, **self.dkwargs) is False:
70 70 raise UnmetDependency()
71 71
72 72 def __call__(self, *args, **kwargs):
73 73 return self.f(*args, **kwargs)
74 74
75 75 if not py3compat.PY3:
76 76 @property
77 77 def __name__(self):
78 78 return self.func_name
79 79
80 80 @interactive
81 81 def _require(*modules, **mapping):
82 82 """Helper for @require decorator."""
83 83 from IPython.parallel.error import UnmetDependency
84 84 from IPython.utils.pickleutil import uncan
85 85 user_ns = globals()
86 86 for name in modules:
87 87 try:
88 88 exec('import %s' % name, user_ns)
89 89 except ImportError:
90 90 raise UnmetDependency(name)
91 91
92 92 for name, cobj in mapping.items():
93 93 user_ns[name] = uncan(cobj, user_ns)
94 94 return True
95 95
96 96 def require(*objects, **mapping):
97 97 """Simple decorator for requiring local objects and modules to be available
98 98 when the decorated function is called on the engine.
99 99
100 100 Modules specified by name or passed directly will be imported
101 101 prior to calling the decorated function.
102 102
103 103 Objects other than modules will be pushed as a part of the task.
104 104 Functions can be passed positionally,
105 105 and will be pushed to the engine with their __name__.
106 106 Other objects can be passed by keyword arg.
107 107
108 Examples
109 --------
108 Examples::
110 109
111 In [1]: @require('numpy')
112 ...: def norm(a):
113 ...: return numpy.linalg.norm(a,2)
110 In [1]: @require('numpy')
111 ...: def norm(a):
112 ...: return numpy.linalg.norm(a,2)
114 113
115 In [2]: foo = lambda x: x*x
116 In [3]: @require(foo)
117 ...: def bar(a):
118 ...: return foo(1-a)
114 In [2]: foo = lambda x: x*x
115 In [3]: @require(foo)
116 ...: def bar(a):
117 ...: return foo(1-a)
119 118 """
120 119 names = []
121 120 for obj in objects:
122 121 if isinstance(obj, ModuleType):
123 122 obj = obj.__name__
124 123
125 124 if isinstance(obj, string_types):
126 125 names.append(obj)
127 126 elif hasattr(obj, '__name__'):
128 127 mapping[obj.__name__] = obj
129 128 else:
130 129 raise TypeError("Objects other than modules and functions "
131 130 "must be passed by kwarg, but got: %s" % type(obj)
132 131 )
133 132
134 133 for name, obj in mapping.items():
135 134 mapping[name] = can(obj)
136 135 return depend(_require, *names, **mapping)
137 136
138 137 class Dependency(set):
139 138 """An object for representing a set of msg_id dependencies.
140 139
141 140 Subclassed from set().
142 141
143 142 Parameters
144 143 ----------
145 144 dependencies: list/set of msg_ids or AsyncResult objects or output of Dependency.as_dict()
146 145 The msg_ids to depend on
147 146 all : bool [default True]
148 147 Whether the dependency should be considered met when *all* depending tasks have completed
149 148 or only when *any* have been completed.
150 149 success : bool [default True]
151 150 Whether to consider successes as fulfilling dependencies.
152 151 failure : bool [default False]
153 152 Whether to consider failures as fulfilling dependencies.
154 153
155 154 If `all=success=True` and `failure=False`, then the task will fail with an ImpossibleDependency
156 155 as soon as the first depended-upon task fails.
157 156 """
158 157
159 158 all=True
160 159 success=True
161 160 failure=True
162 161
163 162 def __init__(self, dependencies=[], all=True, success=True, failure=False):
164 163 if isinstance(dependencies, dict):
165 164 # load from dict
166 165 all = dependencies.get('all', True)
167 166 success = dependencies.get('success', success)
168 167 failure = dependencies.get('failure', failure)
169 168 dependencies = dependencies.get('dependencies', [])
170 169 ids = []
171 170
172 171 # extract ids from various sources:
173 172 if isinstance(dependencies, string_types + (AsyncResult,)):
174 173 dependencies = [dependencies]
175 174 for d in dependencies:
176 175 if isinstance(d, string_types):
177 176 ids.append(d)
178 177 elif isinstance(d, AsyncResult):
179 178 ids.extend(d.msg_ids)
180 179 else:
181 180 raise TypeError("invalid dependency type: %r"%type(d))
182 181
183 182 set.__init__(self, ids)
184 183 self.all = all
185 184 if not (success or failure):
186 185 raise ValueError("Must depend on at least one of successes or failures!")
187 186 self.success=success
188 187 self.failure = failure
189 188
190 189 def check(self, completed, failed=None):
191 190 """check whether our dependencies have been met."""
192 191 if len(self) == 0:
193 192 return True
194 193 against = set()
195 194 if self.success:
196 195 against = completed
197 196 if failed is not None and self.failure:
198 197 against = against.union(failed)
199 198 if self.all:
200 199 return self.issubset(against)
201 200 else:
202 201 return not self.isdisjoint(against)
203 202
204 203 def unreachable(self, completed, failed=None):
205 204 """return whether this dependency has become impossible."""
206 205 if len(self) == 0:
207 206 return False
208 207 against = set()
209 208 if not self.success:
210 209 against = completed
211 210 if failed is not None and not self.failure:
212 211 against = against.union(failed)
213 212 if self.all:
214 213 return not self.isdisjoint(against)
215 214 else:
216 215 return self.issubset(against)
217 216
218 217
219 218 def as_dict(self):
220 219 """Represent this dependency as a dict. For json compatibility."""
221 220 return dict(
222 221 dependencies=list(self),
223 222 all=self.all,
224 223 success=self.success,
225 224 failure=self.failure
226 225 )
227 226
228 227
229 228 __all__ = ['depend', 'require', 'dependent', 'Dependency']
230 229
@@ -1,312 +1,317 b''
1 1 """A Task logger that presents our DB interface,
2 2 but exists entirely in memory and implemented with dicts.
3 3
4 4 Authors:
5 5
6 6 * Min RK
7 7
8 8
9 TaskRecords are dicts of the form:
10 {
11 'msg_id' : str(uuid),
12 'client_uuid' : str(uuid),
13 'engine_uuid' : str(uuid) or None,
14 'header' : dict(header),
15 'content': dict(content),
16 'buffers': list(buffers),
17 'submitted': datetime,
18 'started': datetime or None,
19 'completed': datetime or None,
20 'resubmitted': datetime or None,
21 'result_header' : dict(header) or None,
22 'result_content' : dict(content) or None,
23 'result_buffers' : list(buffers) or None,
24 }
25 With this info, many of the special categories of tasks can be defined by query:
26
27 pending: completed is None
28 client's outstanding: client_uuid = uuid && completed is None
29 MIA: arrived is None (and completed is None)
30 etc.
9 TaskRecords are dicts of the form::
10
11 {
12 'msg_id' : str(uuid),
13 'client_uuid' : str(uuid),
14 'engine_uuid' : str(uuid) or None,
15 'header' : dict(header),
16 'content': dict(content),
17 'buffers': list(buffers),
18 'submitted': datetime,
19 'started': datetime or None,
20 'completed': datetime or None,
21 'resubmitted': datetime or None,
22 'result_header' : dict(header) or None,
23 'result_content' : dict(content) or None,
24 'result_buffers' : list(buffers) or None,
25 }
26
27 With this info, many of the special categories of tasks can be defined by query,
28 e.g.:
29
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 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 45 $lt,$gt,$lte,$gte,$ne,$in,$nin,$all,$mod,$exists
41 46 """
42 47 #-----------------------------------------------------------------------------
43 48 # Copyright (C) 2010-2011 The IPython Development Team
44 49 #
45 50 # Distributed under the terms of the BSD License. The full license is in
46 51 # the file COPYING, distributed as part of this software.
47 52 #-----------------------------------------------------------------------------
48 53
49 54 from copy import deepcopy as copy
50 55 from datetime import datetime
51 56
52 57 from IPython.config.configurable import LoggingConfigurable
53 58
54 59 from IPython.utils.py3compat import iteritems, itervalues
55 60 from IPython.utils.traitlets import Dict, Unicode, Integer, Float
56 61
57 62 filters = {
58 63 '$lt' : lambda a,b: a < b,
59 64 '$gt' : lambda a,b: b > a,
60 65 '$eq' : lambda a,b: a == b,
61 66 '$ne' : lambda a,b: a != b,
62 67 '$lte': lambda a,b: a <= b,
63 68 '$gte': lambda a,b: a >= b,
64 69 '$in' : lambda a,b: a in b,
65 70 '$nin': lambda a,b: a not in b,
66 71 '$all': lambda a,b: all([ a in bb for bb in b ]),
67 72 '$mod': lambda a,b: a%b[0] == b[1],
68 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 77 class CompositeFilter(object):
73 78 """Composite filter for matching multiple properties."""
74 79
75 80 def __init__(self, dikt):
76 81 self.tests = []
77 82 self.values = []
78 83 for key, value in iteritems(dikt):
79 84 self.tests.append(filters[key])
80 85 self.values.append(value)
81 86
82 87 def __call__(self, value):
83 88 for test,check in zip(self.tests, self.values):
84 89 if not test(value, check):
85 90 return False
86 91 return True
87 92
88 93 class BaseDB(LoggingConfigurable):
89 94 """Empty Parent class so traitlets work on DB."""
90 95 # base configurable traits:
91 96 session = Unicode("")
92 97
93 98 class DictDB(BaseDB):
94 99 """Basic in-memory dict-based object for saving Task Records.
95 100
96 101 This is the first object to present the DB interface
97 102 for logging tasks out of memory.
98 103
99 104 The interface is based on MongoDB, so adding a MongoDB
100 105 backend should be straightforward.
101 106 """
102 107
103 108 _records = Dict()
104 109 _culled_ids = set() # set of ids which have been culled
105 110 _buffer_bytes = Integer(0) # running total of the bytes in the DB
106 111
107 112 size_limit = Integer(1024**3, config=True,
108 113 help="""The maximum total size (in bytes) of the buffers stored in the db
109 114
110 115 When the db exceeds this size, the oldest records will be culled until
111 116 the total size is under size_limit * (1-cull_fraction).
112 117 default: 1 GB
113 118 """
114 119 )
115 120 record_limit = Integer(1024, config=True,
116 121 help="""The maximum number of records in the db
117 122
118 123 When the history exceeds this size, the first record_limit * cull_fraction
119 124 records will be culled.
120 125 """
121 126 )
122 127 cull_fraction = Float(0.1, config=True,
123 128 help="""The fraction by which the db should culled when one of the limits is exceeded
124 129
125 130 In general, the db size will spend most of its time with a size in the range:
126 131
127 132 [limit * (1-cull_fraction), limit]
128 133
129 134 for each of size_limit and record_limit.
130 135 """
131 136 )
132 137
133 138 def _match_one(self, rec, tests):
134 139 """Check if a specific record matches tests."""
135 140 for key,test in iteritems(tests):
136 141 if not test(rec.get(key, None)):
137 142 return False
138 143 return True
139 144
140 145 def _match(self, check):
141 146 """Find all the matches for a check dict."""
142 147 matches = []
143 148 tests = {}
144 149 for k,v in iteritems(check):
145 150 if isinstance(v, dict):
146 151 tests[k] = CompositeFilter(v)
147 152 else:
148 153 tests[k] = lambda o: o==v
149 154
150 155 for rec in itervalues(self._records):
151 156 if self._match_one(rec, tests):
152 157 matches.append(copy(rec))
153 158 return matches
154 159
155 160 def _extract_subdict(self, rec, keys):
156 161 """extract subdict of keys"""
157 162 d = {}
158 163 d['msg_id'] = rec['msg_id']
159 164 for key in keys:
160 165 d[key] = rec[key]
161 166 return copy(d)
162 167
163 168 # methods for monitoring size / culling history
164 169
165 170 def _add_bytes(self, rec):
166 171 for key in ('buffers', 'result_buffers'):
167 172 for buf in rec.get(key) or []:
168 173 self._buffer_bytes += len(buf)
169 174
170 175 self._maybe_cull()
171 176
172 177 def _drop_bytes(self, rec):
173 178 for key in ('buffers', 'result_buffers'):
174 179 for buf in rec.get(key) or []:
175 180 self._buffer_bytes -= len(buf)
176 181
177 182 def _cull_oldest(self, n=1):
178 183 """cull the oldest N records"""
179 184 for msg_id in self.get_history()[:n]:
180 185 self.log.debug("Culling record: %r", msg_id)
181 186 self._culled_ids.add(msg_id)
182 187 self.drop_record(msg_id)
183 188
184 189 def _maybe_cull(self):
185 190 # cull by count:
186 191 if len(self._records) > self.record_limit:
187 192 to_cull = int(self.cull_fraction * self.record_limit)
188 193 self.log.info("%i records exceeds limit of %i, culling oldest %i",
189 194 len(self._records), self.record_limit, to_cull
190 195 )
191 196 self._cull_oldest(to_cull)
192 197
193 198 # cull by size:
194 199 if self._buffer_bytes > self.size_limit:
195 200 limit = self.size_limit * (1 - self.cull_fraction)
196 201
197 202 before = self._buffer_bytes
198 203 before_count = len(self._records)
199 204 culled = 0
200 205 while self._buffer_bytes > limit:
201 206 self._cull_oldest(1)
202 207 culled += 1
203 208
204 209 self.log.info("%i records with total buffer size %i exceeds limit: %i. Culled oldest %i records.",
205 210 before_count, before, self.size_limit, culled
206 211 )
207 212
208 213 # public API methods:
209 214
210 215 def add_record(self, msg_id, rec):
211 216 """Add a new Task Record, by msg_id."""
212 217 if msg_id in self._records:
213 218 raise KeyError("Already have msg_id %r"%(msg_id))
214 219 self._records[msg_id] = rec
215 220 self._add_bytes(rec)
216 221 self._maybe_cull()
217 222
218 223 def get_record(self, msg_id):
219 224 """Get a specific Task Record, by msg_id."""
220 225 if msg_id in self._culled_ids:
221 226 raise KeyError("Record %r has been culled for size" % msg_id)
222 227 if not msg_id in self._records:
223 228 raise KeyError("No such msg_id %r"%(msg_id))
224 229 return copy(self._records[msg_id])
225 230
226 231 def update_record(self, msg_id, rec):
227 232 """Update the data in an existing record."""
228 233 if msg_id in self._culled_ids:
229 234 raise KeyError("Record %r has been culled for size" % msg_id)
230 235 _rec = self._records[msg_id]
231 236 self._drop_bytes(_rec)
232 237 _rec.update(rec)
233 238 self._add_bytes(_rec)
234 239
235 240 def drop_matching_records(self, check):
236 241 """Remove a record from the DB."""
237 242 matches = self._match(check)
238 243 for rec in matches:
239 244 self._drop_bytes(rec)
240 245 del self._records[rec['msg_id']]
241 246
242 247 def drop_record(self, msg_id):
243 248 """Remove a record from the DB."""
244 249 rec = self._records[msg_id]
245 250 self._drop_bytes(rec)
246 251 del self._records[msg_id]
247 252
248 253 def find_records(self, check, keys=None):
249 254 """Find records matching a query dict, optionally extracting subset of keys.
250 255
251 256 Returns dict keyed by msg_id of matching records.
252 257
253 258 Parameters
254 259 ----------
255 260
256 261 check: dict
257 262 mongodb-style query argument
258 263 keys: list of strs [optional]
259 264 if specified, the subset of keys to extract. msg_id will *always* be
260 265 included.
261 266 """
262 267 matches = self._match(check)
263 268 if keys:
264 269 return [ self._extract_subdict(rec, keys) for rec in matches ]
265 270 else:
266 271 return matches
267 272
268 273 def get_history(self):
269 274 """get all msg_ids, ordered by time submitted."""
270 275 msg_ids = self._records.keys()
271 276 # Remove any that do not have a submitted timestamp.
272 277 # This is extremely unlikely to happen,
273 278 # but it seems to come up in some tests on VMs.
274 279 msg_ids = [ m for m in msg_ids if self._records[m]['submitted'] is not None ]
275 280 return sorted(msg_ids, key=lambda m: self._records[m]['submitted'])
276 281
277 282
278 283 NODATA = KeyError("NoDB backend doesn't store any data. "
279 284 "Start the Controller with a DB backend to enable resubmission / result persistence."
280 285 )
281 286
282 287
283 288 class NoDB(BaseDB):
284 289 """A blackhole db backend that actually stores no information.
285 290
286 291 Provides the full DB interface, but raises KeyErrors on any
287 292 method that tries to access the records. This can be used to
288 293 minimize the memory footprint of the Hub when its record-keeping
289 294 functionality is not required.
290 295 """
291 296
292 297 def add_record(self, msg_id, record):
293 298 pass
294 299
295 300 def get_record(self, msg_id):
296 301 raise NODATA
297 302
298 303 def update_record(self, msg_id, record):
299 304 pass
300 305
301 306 def drop_matching_records(self, check):
302 307 pass
303 308
304 309 def drop_record(self, msg_id):
305 310 pass
306 311
307 312 def find_records(self, check, keys=None):
308 313 raise NODATA
309 314
310 315 def get_history(self):
311 316 raise NODATA
312 317
@@ -1,1422 +1,1426 b''
1 1 """The IPython Controller Hub with 0MQ
2 2 This is the master object that handles connections from engines and clients,
3 3 and monitors traffic through the various queues.
4 4
5 5 Authors:
6 6
7 7 * Min RK
8 8 """
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2010-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19 from __future__ import print_function
20 20
21 21 import json
22 22 import os
23 23 import sys
24 24 import time
25 25 from datetime import datetime
26 26
27 27 import zmq
28 28 from zmq.eventloop import ioloop
29 29 from zmq.eventloop.zmqstream import ZMQStream
30 30
31 31 # internal:
32 32 from IPython.utils.importstring import import_item
33 33 from IPython.utils.jsonutil import extract_dates
34 34 from IPython.utils.localinterfaces import localhost
35 35 from IPython.utils.py3compat import cast_bytes, unicode_type, iteritems
36 36 from IPython.utils.traitlets import (
37 37 HasTraits, Instance, Integer, Unicode, Dict, Set, Tuple, CBytes, DottedObjectName
38 38 )
39 39
40 40 from IPython.parallel import error, util
41 41 from IPython.parallel.factory import RegistrationFactory
42 42
43 43 from IPython.kernel.zmq.session import SessionFactory
44 44
45 45 from .heartmonitor import HeartMonitor
46 46
47 47 #-----------------------------------------------------------------------------
48 48 # Code
49 49 #-----------------------------------------------------------------------------
50 50
51 51 def _passer(*args, **kwargs):
52 52 return
53 53
54 54 def _printer(*args, **kwargs):
55 55 print (args)
56 56 print (kwargs)
57 57
58 58 def empty_record():
59 59 """Return an empty dict with all record keys."""
60 60 return {
61 61 'msg_id' : None,
62 62 'header' : None,
63 63 'metadata' : None,
64 64 'content': None,
65 65 'buffers': None,
66 66 'submitted': None,
67 67 'client_uuid' : None,
68 68 'engine_uuid' : None,
69 69 'started': None,
70 70 'completed': None,
71 71 'resubmitted': None,
72 72 'received': None,
73 73 'result_header' : None,
74 74 'result_metadata' : None,
75 75 'result_content' : None,
76 76 'result_buffers' : None,
77 77 'queue' : None,
78 78 'pyin' : None,
79 79 'pyout': None,
80 80 'pyerr': None,
81 81 'stdout': '',
82 82 'stderr': '',
83 83 }
84 84
85 85 def init_record(msg):
86 86 """Initialize a TaskRecord based on a request."""
87 87 header = msg['header']
88 88 return {
89 89 'msg_id' : header['msg_id'],
90 90 'header' : header,
91 91 'content': msg['content'],
92 92 'metadata': msg['metadata'],
93 93 'buffers': msg['buffers'],
94 94 'submitted': header['date'],
95 95 'client_uuid' : None,
96 96 'engine_uuid' : None,
97 97 'started': None,
98 98 'completed': None,
99 99 'resubmitted': None,
100 100 'received': None,
101 101 'result_header' : None,
102 102 'result_metadata': None,
103 103 'result_content' : None,
104 104 'result_buffers' : None,
105 105 'queue' : None,
106 106 'pyin' : None,
107 107 'pyout': None,
108 108 'pyerr': None,
109 109 'stdout': '',
110 110 'stderr': '',
111 111 }
112 112
113 113
114 114 class EngineConnector(HasTraits):
115 115 """A simple object for accessing the various zmq connections of an object.
116 116 Attributes are:
117 117 id (int): engine ID
118 118 uuid (unicode): engine UUID
119 119 pending: set of msg_ids
120 120 stallback: DelayedCallback for stalled registration
121 121 """
122 122
123 123 id = Integer(0)
124 124 uuid = Unicode()
125 125 pending = Set()
126 126 stallback = Instance(ioloop.DelayedCallback)
127 127
128 128
129 129 _db_shortcuts = {
130 130 'sqlitedb' : 'IPython.parallel.controller.sqlitedb.SQLiteDB',
131 131 'mongodb' : 'IPython.parallel.controller.mongodb.MongoDB',
132 132 'dictdb' : 'IPython.parallel.controller.dictdb.DictDB',
133 133 'nodb' : 'IPython.parallel.controller.dictdb.NoDB',
134 134 }
135 135
136 136 class HubFactory(RegistrationFactory):
137 137 """The Configurable for setting up a Hub."""
138 138
139 139 # port-pairs for monitoredqueues:
140 140 hb = Tuple(Integer,Integer,config=True,
141 141 help="""PUB/ROUTER Port pair for Engine heartbeats""")
142 142 def _hb_default(self):
143 143 return tuple(util.select_random_ports(2))
144 144
145 145 mux = Tuple(Integer,Integer,config=True,
146 146 help="""Client/Engine Port pair for MUX queue""")
147 147
148 148 def _mux_default(self):
149 149 return tuple(util.select_random_ports(2))
150 150
151 151 task = Tuple(Integer,Integer,config=True,
152 152 help="""Client/Engine Port pair for Task queue""")
153 153 def _task_default(self):
154 154 return tuple(util.select_random_ports(2))
155 155
156 156 control = Tuple(Integer,Integer,config=True,
157 157 help="""Client/Engine Port pair for Control queue""")
158 158
159 159 def _control_default(self):
160 160 return tuple(util.select_random_ports(2))
161 161
162 162 iopub = Tuple(Integer,Integer,config=True,
163 163 help="""Client/Engine Port pair for IOPub relay""")
164 164
165 165 def _iopub_default(self):
166 166 return tuple(util.select_random_ports(2))
167 167
168 168 # single ports:
169 169 mon_port = Integer(config=True,
170 170 help="""Monitor (SUB) port for queue traffic""")
171 171
172 172 def _mon_port_default(self):
173 173 return util.select_random_ports(1)[0]
174 174
175 175 notifier_port = Integer(config=True,
176 176 help="""PUB port for sending engine status notifications""")
177 177
178 178 def _notifier_port_default(self):
179 179 return util.select_random_ports(1)[0]
180 180
181 181 engine_ip = Unicode(config=True,
182 182 help="IP on which to listen for engine connections. [default: loopback]")
183 183 def _engine_ip_default(self):
184 184 return localhost()
185 185 engine_transport = Unicode('tcp', config=True,
186 186 help="0MQ transport for engine connections. [default: tcp]")
187 187
188 188 client_ip = Unicode(config=True,
189 189 help="IP on which to listen for client connections. [default: loopback]")
190 190 client_transport = Unicode('tcp', config=True,
191 191 help="0MQ transport for client connections. [default : tcp]")
192 192
193 193 monitor_ip = Unicode(config=True,
194 194 help="IP on which to listen for monitor messages. [default: loopback]")
195 195 monitor_transport = Unicode('tcp', config=True,
196 196 help="0MQ transport for monitor messages. [default : tcp]")
197 197
198 198 _client_ip_default = _monitor_ip_default = _engine_ip_default
199 199
200 200
201 201 monitor_url = Unicode('')
202 202
203 203 db_class = DottedObjectName('NoDB',
204 204 config=True, help="""The class to use for the DB backend
205 205
206 206 Options include:
207 207
208 208 SQLiteDB: SQLite
209 209 MongoDB : use MongoDB
210 210 DictDB : in-memory storage (fastest, but be mindful of memory growth of the Hub)
211 211 NoDB : disable database altogether (default)
212 212
213 213 """)
214 214
215 215 # not configurable
216 216 db = Instance('IPython.parallel.controller.dictdb.BaseDB')
217 217 heartmonitor = Instance('IPython.parallel.controller.heartmonitor.HeartMonitor')
218 218
219 219 def _ip_changed(self, name, old, new):
220 220 self.engine_ip = new
221 221 self.client_ip = new
222 222 self.monitor_ip = new
223 223 self._update_monitor_url()
224 224
225 225 def _update_monitor_url(self):
226 226 self.monitor_url = "%s://%s:%i" % (self.monitor_transport, self.monitor_ip, self.mon_port)
227 227
228 228 def _transport_changed(self, name, old, new):
229 229 self.engine_transport = new
230 230 self.client_transport = new
231 231 self.monitor_transport = new
232 232 self._update_monitor_url()
233 233
234 234 def __init__(self, **kwargs):
235 235 super(HubFactory, self).__init__(**kwargs)
236 236 self._update_monitor_url()
237 237
238 238
239 239 def construct(self):
240 240 self.init_hub()
241 241
242 242 def start(self):
243 243 self.heartmonitor.start()
244 244 self.log.info("Heartmonitor started")
245 245
246 246 def client_url(self, channel):
247 247 """return full zmq url for a named client channel"""
248 248 return "%s://%s:%i" % (self.client_transport, self.client_ip, self.client_info[channel])
249 249
250 250 def engine_url(self, channel):
251 251 """return full zmq url for a named engine channel"""
252 252 return "%s://%s:%i" % (self.engine_transport, self.engine_ip, self.engine_info[channel])
253 253
254 254 def init_hub(self):
255 255 """construct Hub object"""
256 256
257 257 ctx = self.context
258 258 loop = self.loop
259 259 if 'TaskScheduler.scheme_name' in self.config:
260 260 scheme = self.config.TaskScheduler.scheme_name
261 261 else:
262 262 from .scheduler import TaskScheduler
263 263 scheme = TaskScheduler.scheme_name.get_default_value()
264 264
265 265 # build connection dicts
266 266 engine = self.engine_info = {
267 267 'interface' : "%s://%s" % (self.engine_transport, self.engine_ip),
268 268 'registration' : self.regport,
269 269 'control' : self.control[1],
270 270 'mux' : self.mux[1],
271 271 'hb_ping' : self.hb[0],
272 272 'hb_pong' : self.hb[1],
273 273 'task' : self.task[1],
274 274 'iopub' : self.iopub[1],
275 275 }
276 276
277 277 client = self.client_info = {
278 278 'interface' : "%s://%s" % (self.client_transport, self.client_ip),
279 279 'registration' : self.regport,
280 280 'control' : self.control[0],
281 281 'mux' : self.mux[0],
282 282 'task' : self.task[0],
283 283 'task_scheme' : scheme,
284 284 'iopub' : self.iopub[0],
285 285 'notification' : self.notifier_port,
286 286 }
287 287
288 288 self.log.debug("Hub engine addrs: %s", self.engine_info)
289 289 self.log.debug("Hub client addrs: %s", self.client_info)
290 290
291 291 # Registrar socket
292 292 q = ZMQStream(ctx.socket(zmq.ROUTER), loop)
293 293 util.set_hwm(q, 0)
294 294 q.bind(self.client_url('registration'))
295 295 self.log.info("Hub listening on %s for registration.", self.client_url('registration'))
296 296 if self.client_ip != self.engine_ip:
297 297 q.bind(self.engine_url('registration'))
298 298 self.log.info("Hub listening on %s for registration.", self.engine_url('registration'))
299 299
300 300 ### Engine connections ###
301 301
302 302 # heartbeat
303 303 hpub = ctx.socket(zmq.PUB)
304 304 hpub.bind(self.engine_url('hb_ping'))
305 305 hrep = ctx.socket(zmq.ROUTER)
306 306 util.set_hwm(hrep, 0)
307 307 hrep.bind(self.engine_url('hb_pong'))
308 308 self.heartmonitor = HeartMonitor(loop=loop, parent=self, log=self.log,
309 309 pingstream=ZMQStream(hpub,loop),
310 310 pongstream=ZMQStream(hrep,loop)
311 311 )
312 312
313 313 ### Client connections ###
314 314
315 315 # Notifier socket
316 316 n = ZMQStream(ctx.socket(zmq.PUB), loop)
317 317 n.bind(self.client_url('notification'))
318 318
319 319 ### build and launch the queues ###
320 320
321 321 # monitor socket
322 322 sub = ctx.socket(zmq.SUB)
323 323 sub.setsockopt(zmq.SUBSCRIBE, b"")
324 324 sub.bind(self.monitor_url)
325 325 sub.bind('inproc://monitor')
326 326 sub = ZMQStream(sub, loop)
327 327
328 328 # connect the db
329 329 db_class = _db_shortcuts.get(self.db_class.lower(), self.db_class)
330 330 self.log.info('Hub using DB backend: %r', (db_class.split('.')[-1]))
331 331 self.db = import_item(str(db_class))(session=self.session.session,
332 332 parent=self, log=self.log)
333 333 time.sleep(.25)
334 334
335 335 # resubmit stream
336 336 r = ZMQStream(ctx.socket(zmq.DEALER), loop)
337 337 url = util.disambiguate_url(self.client_url('task'))
338 338 r.connect(url)
339 339
340 340 self.hub = Hub(loop=loop, session=self.session, monitor=sub, heartmonitor=self.heartmonitor,
341 341 query=q, notifier=n, resubmit=r, db=self.db,
342 342 engine_info=self.engine_info, client_info=self.client_info,
343 343 log=self.log)
344 344
345 345
346 346 class Hub(SessionFactory):
347 347 """The IPython Controller Hub with 0MQ connections
348 348
349 349 Parameters
350 350 ==========
351 351 loop: zmq IOLoop instance
352 352 session: Session object
353 353 <removed> context: zmq context for creating new connections (?)
354 354 queue: ZMQStream for monitoring the command queue (SUB)
355 355 query: ZMQStream for engine registration and client queries requests (ROUTER)
356 356 heartbeat: HeartMonitor object checking the pulse of the engines
357 357 notifier: ZMQStream for broadcasting engine registration changes (PUB)
358 358 db: connection to db for out of memory logging of commands
359 359 NotImplemented
360 360 engine_info: dict of zmq connection information for engines to connect
361 361 to the queues.
362 362 client_info: dict of zmq connection information for engines to connect
363 363 to the queues.
364 364 """
365 365
366 366 engine_state_file = Unicode()
367 367
368 368 # internal data structures:
369 369 ids=Set() # engine IDs
370 370 keytable=Dict()
371 371 by_ident=Dict()
372 372 engines=Dict()
373 373 clients=Dict()
374 374 hearts=Dict()
375 375 pending=Set()
376 376 queues=Dict() # pending msg_ids keyed by engine_id
377 377 tasks=Dict() # pending msg_ids submitted as tasks, keyed by client_id
378 378 completed=Dict() # completed msg_ids keyed by engine_id
379 379 all_completed=Set() # completed msg_ids keyed by engine_id
380 380 dead_engines=Set() # completed msg_ids keyed by engine_id
381 381 unassigned=Set() # set of task msg_ds not yet assigned a destination
382 382 incoming_registrations=Dict()
383 383 registration_timeout=Integer()
384 384 _idcounter=Integer(0)
385 385
386 386 # objects from constructor:
387 387 query=Instance(ZMQStream)
388 388 monitor=Instance(ZMQStream)
389 389 notifier=Instance(ZMQStream)
390 390 resubmit=Instance(ZMQStream)
391 391 heartmonitor=Instance(HeartMonitor)
392 392 db=Instance(object)
393 393 client_info=Dict()
394 394 engine_info=Dict()
395 395
396 396
397 397 def __init__(self, **kwargs):
398 398 """
399 399 # universal:
400 400 loop: IOLoop for creating future connections
401 401 session: streamsession for sending serialized data
402 402 # engine:
403 403 queue: ZMQStream for monitoring queue messages
404 404 query: ZMQStream for engine+client registration and client requests
405 405 heartbeat: HeartMonitor object for tracking engines
406 406 # extra:
407 407 db: ZMQStream for db connection (NotImplemented)
408 408 engine_info: zmq address/protocol dict for engine connections
409 409 client_info: zmq address/protocol dict for client connections
410 410 """
411 411
412 412 super(Hub, self).__init__(**kwargs)
413 413 self.registration_timeout = max(10000, 5*self.heartmonitor.period)
414 414
415 415 # register our callbacks
416 416 self.query.on_recv(self.dispatch_query)
417 417 self.monitor.on_recv(self.dispatch_monitor_traffic)
418 418
419 419 self.heartmonitor.add_heart_failure_handler(self.handle_heart_failure)
420 420 self.heartmonitor.add_new_heart_handler(self.handle_new_heart)
421 421
422 422 self.monitor_handlers = {b'in' : self.save_queue_request,
423 423 b'out': self.save_queue_result,
424 424 b'intask': self.save_task_request,
425 425 b'outtask': self.save_task_result,
426 426 b'tracktask': self.save_task_destination,
427 427 b'incontrol': _passer,
428 428 b'outcontrol': _passer,
429 429 b'iopub': self.save_iopub_message,
430 430 }
431 431
432 432 self.query_handlers = {'queue_request': self.queue_status,
433 433 'result_request': self.get_results,
434 434 'history_request': self.get_history,
435 435 'db_request': self.db_query,
436 436 'purge_request': self.purge_results,
437 437 'load_request': self.check_load,
438 438 'resubmit_request': self.resubmit_task,
439 439 'shutdown_request': self.shutdown_request,
440 440 'registration_request' : self.register_engine,
441 441 'unregistration_request' : self.unregister_engine,
442 442 'connection_request': self.connection_request,
443 443 }
444 444
445 445 # ignore resubmit replies
446 446 self.resubmit.on_recv(lambda msg: None, copy=False)
447 447
448 448 self.log.info("hub::created hub")
449 449
450 450 @property
451 451 def _next_id(self):
452 452 """gemerate a new ID.
453 453
454 454 No longer reuse old ids, just count from 0."""
455 455 newid = self._idcounter
456 456 self._idcounter += 1
457 457 return newid
458 458 # newid = 0
459 459 # incoming = [id[0] for id in itervalues(self.incoming_registrations)]
460 460 # # print newid, self.ids, self.incoming_registrations
461 461 # while newid in self.ids or newid in incoming:
462 462 # newid += 1
463 463 # return newid
464 464
465 465 #-----------------------------------------------------------------------------
466 466 # message validation
467 467 #-----------------------------------------------------------------------------
468 468
469 469 def _validate_targets(self, targets):
470 470 """turn any valid targets argument into a list of integer ids"""
471 471 if targets is None:
472 472 # default to all
473 473 return self.ids
474 474
475 475 if isinstance(targets, (int,str,unicode_type)):
476 476 # only one target specified
477 477 targets = [targets]
478 478 _targets = []
479 479 for t in targets:
480 480 # map raw identities to ids
481 481 if isinstance(t, (str,unicode_type)):
482 482 t = self.by_ident.get(cast_bytes(t), t)
483 483 _targets.append(t)
484 484 targets = _targets
485 485 bad_targets = [ t for t in targets if t not in self.ids ]
486 486 if bad_targets:
487 487 raise IndexError("No Such Engine: %r" % bad_targets)
488 488 if not targets:
489 489 raise IndexError("No Engines Registered")
490 490 return targets
491 491
492 492 #-----------------------------------------------------------------------------
493 493 # dispatch methods (1 per stream)
494 494 #-----------------------------------------------------------------------------
495 495
496 496
497 497 @util.log_errors
498 498 def dispatch_monitor_traffic(self, msg):
499 499 """all ME and Task queue messages come through here, as well as
500 500 IOPub traffic."""
501 501 self.log.debug("monitor traffic: %r", msg[0])
502 502 switch = msg[0]
503 503 try:
504 504 idents, msg = self.session.feed_identities(msg[1:])
505 505 except ValueError:
506 506 idents=[]
507 507 if not idents:
508 508 self.log.error("Monitor message without topic: %r", msg)
509 509 return
510 510 handler = self.monitor_handlers.get(switch, None)
511 511 if handler is not None:
512 512 handler(idents, msg)
513 513 else:
514 514 self.log.error("Unrecognized monitor topic: %r", switch)
515 515
516 516
517 517 @util.log_errors
518 518 def dispatch_query(self, msg):
519 519 """Route registration requests and queries from clients."""
520 520 try:
521 521 idents, msg = self.session.feed_identities(msg)
522 522 except ValueError:
523 523 idents = []
524 524 if not idents:
525 525 self.log.error("Bad Query Message: %r", msg)
526 526 return
527 527 client_id = idents[0]
528 528 try:
529 529 msg = self.session.unserialize(msg, content=True)
530 530 except Exception:
531 531 content = error.wrap_exception()
532 532 self.log.error("Bad Query Message: %r", msg, exc_info=True)
533 533 self.session.send(self.query, "hub_error", ident=client_id,
534 534 content=content)
535 535 return
536 536 # print client_id, header, parent, content
537 537 #switch on message type:
538 538 msg_type = msg['header']['msg_type']
539 539 self.log.info("client::client %r requested %r", client_id, msg_type)
540 540 handler = self.query_handlers.get(msg_type, None)
541 541 try:
542 542 assert handler is not None, "Bad Message Type: %r" % msg_type
543 543 except:
544 544 content = error.wrap_exception()
545 545 self.log.error("Bad Message Type: %r", msg_type, exc_info=True)
546 546 self.session.send(self.query, "hub_error", ident=client_id,
547 547 content=content)
548 548 return
549 549
550 550 else:
551 551 handler(idents, msg)
552 552
553 553 def dispatch_db(self, msg):
554 554 """"""
555 555 raise NotImplementedError
556 556
557 557 #---------------------------------------------------------------------------
558 558 # handler methods (1 per event)
559 559 #---------------------------------------------------------------------------
560 560
561 561 #----------------------- Heartbeat --------------------------------------
562 562
563 563 def handle_new_heart(self, heart):
564 564 """handler to attach to heartbeater.
565 565 Called when a new heart starts to beat.
566 566 Triggers completion of registration."""
567 567 self.log.debug("heartbeat::handle_new_heart(%r)", heart)
568 568 if heart not in self.incoming_registrations:
569 569 self.log.info("heartbeat::ignoring new heart: %r", heart)
570 570 else:
571 571 self.finish_registration(heart)
572 572
573 573
574 574 def handle_heart_failure(self, heart):
575 575 """handler to attach to heartbeater.
576 576 called when a previously registered heart fails to respond to beat request.
577 577 triggers unregistration"""
578 578 self.log.debug("heartbeat::handle_heart_failure(%r)", heart)
579 579 eid = self.hearts.get(heart, None)
580 580 uuid = self.engines[eid].uuid
581 581 if eid is None or self.keytable[eid] in self.dead_engines:
582 582 self.log.info("heartbeat::ignoring heart failure %r (not an engine or already dead)", heart)
583 583 else:
584 584 self.unregister_engine(heart, dict(content=dict(id=eid, queue=uuid)))
585 585
586 586 #----------------------- MUX Queue Traffic ------------------------------
587 587
588 588 def save_queue_request(self, idents, msg):
589 589 if len(idents) < 2:
590 590 self.log.error("invalid identity prefix: %r", idents)
591 591 return
592 592 queue_id, client_id = idents[:2]
593 593 try:
594 594 msg = self.session.unserialize(msg)
595 595 except Exception:
596 596 self.log.error("queue::client %r sent invalid message to %r: %r", client_id, queue_id, msg, exc_info=True)
597 597 return
598 598
599 599 eid = self.by_ident.get(queue_id, None)
600 600 if eid is None:
601 601 self.log.error("queue::target %r not registered", queue_id)
602 602 self.log.debug("queue:: valid are: %r", self.by_ident.keys())
603 603 return
604 604 record = init_record(msg)
605 605 msg_id = record['msg_id']
606 606 self.log.info("queue::client %r submitted request %r to %s", client_id, msg_id, eid)
607 607 # Unicode in records
608 608 record['engine_uuid'] = queue_id.decode('ascii')
609 609 record['client_uuid'] = msg['header']['session']
610 610 record['queue'] = 'mux'
611 611
612 612 try:
613 613 # it's posible iopub arrived first:
614 614 existing = self.db.get_record(msg_id)
615 615 for key,evalue in iteritems(existing):
616 616 rvalue = record.get(key, None)
617 617 if evalue and rvalue and evalue != rvalue:
618 618 self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue)
619 619 elif evalue and not rvalue:
620 620 record[key] = evalue
621 621 try:
622 622 self.db.update_record(msg_id, record)
623 623 except Exception:
624 624 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
625 625 except KeyError:
626 626 try:
627 627 self.db.add_record(msg_id, record)
628 628 except Exception:
629 629 self.log.error("DB Error adding record %r", msg_id, exc_info=True)
630 630
631 631
632 632 self.pending.add(msg_id)
633 633 self.queues[eid].append(msg_id)
634 634
635 635 def save_queue_result(self, idents, msg):
636 636 if len(idents) < 2:
637 637 self.log.error("invalid identity prefix: %r", idents)
638 638 return
639 639
640 640 client_id, queue_id = idents[:2]
641 641 try:
642 642 msg = self.session.unserialize(msg)
643 643 except Exception:
644 644 self.log.error("queue::engine %r sent invalid message to %r: %r",
645 645 queue_id, client_id, msg, exc_info=True)
646 646 return
647 647
648 648 eid = self.by_ident.get(queue_id, None)
649 649 if eid is None:
650 650 self.log.error("queue::unknown engine %r is sending a reply: ", queue_id)
651 651 return
652 652
653 653 parent = msg['parent_header']
654 654 if not parent:
655 655 return
656 656 msg_id = parent['msg_id']
657 657 if msg_id in self.pending:
658 658 self.pending.remove(msg_id)
659 659 self.all_completed.add(msg_id)
660 660 self.queues[eid].remove(msg_id)
661 661 self.completed[eid].append(msg_id)
662 662 self.log.info("queue::request %r completed on %s", msg_id, eid)
663 663 elif msg_id not in self.all_completed:
664 664 # it could be a result from a dead engine that died before delivering the
665 665 # result
666 666 self.log.warn("queue:: unknown msg finished %r", msg_id)
667 667 return
668 668 # update record anyway, because the unregistration could have been premature
669 669 rheader = msg['header']
670 670 md = msg['metadata']
671 671 completed = rheader['date']
672 672 started = md.get('started', None)
673 673 result = {
674 674 'result_header' : rheader,
675 675 'result_metadata': md,
676 676 'result_content': msg['content'],
677 677 'received': datetime.now(),
678 678 'started' : started,
679 679 'completed' : completed
680 680 }
681 681
682 682 result['result_buffers'] = msg['buffers']
683 683 try:
684 684 self.db.update_record(msg_id, result)
685 685 except Exception:
686 686 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
687 687
688 688
689 689 #--------------------- Task Queue Traffic ------------------------------
690 690
691 691 def save_task_request(self, idents, msg):
692 692 """Save the submission of a task."""
693 693 client_id = idents[0]
694 694
695 695 try:
696 696 msg = self.session.unserialize(msg)
697 697 except Exception:
698 698 self.log.error("task::client %r sent invalid task message: %r",
699 699 client_id, msg, exc_info=True)
700 700 return
701 701 record = init_record(msg)
702 702
703 703 record['client_uuid'] = msg['header']['session']
704 704 record['queue'] = 'task'
705 705 header = msg['header']
706 706 msg_id = header['msg_id']
707 707 self.pending.add(msg_id)
708 708 self.unassigned.add(msg_id)
709 709 try:
710 710 # it's posible iopub arrived first:
711 711 existing = self.db.get_record(msg_id)
712 712 if existing['resubmitted']:
713 713 for key in ('submitted', 'client_uuid', 'buffers'):
714 714 # don't clobber these keys on resubmit
715 715 # submitted and client_uuid should be different
716 716 # and buffers might be big, and shouldn't have changed
717 717 record.pop(key)
718 718 # still check content,header which should not change
719 719 # but are not expensive to compare as buffers
720 720
721 721 for key,evalue in iteritems(existing):
722 722 if key.endswith('buffers'):
723 723 # don't compare buffers
724 724 continue
725 725 rvalue = record.get(key, None)
726 726 if evalue and rvalue and evalue != rvalue:
727 727 self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue)
728 728 elif evalue and not rvalue:
729 729 record[key] = evalue
730 730 try:
731 731 self.db.update_record(msg_id, record)
732 732 except Exception:
733 733 self.log.error("DB Error updating record %r", msg_id, exc_info=True)
734 734 except KeyError:
735 735 try:
736 736 self.db.add_record(msg_id, record)
737 737 except Exception:
738 738 self.log.error("DB Error adding record %r", msg_id, exc_info=True)
739 739 except Exception:
740 740 self.log.error("DB Error saving task request %r", msg_id, exc_info=True)
741 741
742 742 def save_task_result(self, idents, msg):
743 743 """save the result of a completed task."""
744 744 client_id = idents[0]
745 745 try:
746 746 msg = self.session.unserialize(msg)
747 747 except Exception:
748 748 self.log.error("task::invalid task result message send to %r: %r",
749 749 client_id, msg, exc_info=True)
750 750 return
751 751
752 752 parent = msg['parent_header']
753 753 if not parent:
754 754 # print msg
755 755 self.log.warn("Task %r had no parent!", msg)
756 756 return
757 757 msg_id = parent['msg_id']
758 758 if msg_id in self.unassigned:
759 759 self.unassigned.remove(msg_id)
760 760
761 761 header = msg['header']
762 762 md = msg['metadata']
763 763 engine_uuid = md.get('engine', u'')
764 764 eid = self.by_ident.get(cast_bytes(engine_uuid), None)
765 765
766 766 status = md.get('status', None)
767 767
768 768 if msg_id in self.pending:
769 769 self.log.info("task::task %r finished on %s", msg_id, eid)
770 770 self.pending.remove(msg_id)
771 771 self.all_completed.add(msg_id)
772 772 if eid is not None:
773 773 if status != 'aborted':
774 774 self.completed[eid].append(msg_id)
775 775 if msg_id in self.tasks[eid]:
776 776 self.tasks[eid].remove(msg_id)
777 777 completed = header['date']
778 778 started = md.get('started', None)
779 779 result = {
780 780 'result_header' : header,
781 781 'result_metadata': msg['metadata'],
782 782 'result_content': msg['content'],
783 783 'started' : started,
784 784 'completed' : completed,
785 785 'received' : datetime.now(),
786 786 'engine_uuid': engine_uuid,
787 787 }
788 788
789 789 result['result_buffers'] = msg['buffers']
790 790 try:
791 791 self.db.update_record(msg_id, result)
792 792 except Exception:
793 793 self.log.error("DB Error saving task request %r", msg_id, exc_info=True)
794 794
795 795 else:
796 796 self.log.debug("task::unknown task %r finished", msg_id)
797 797
798 798 def save_task_destination(self, idents, msg):
799 799 try:
800 800 msg = self.session.unserialize(msg, content=True)
801 801 except Exception:
802 802 self.log.error("task::invalid task tracking message", exc_info=True)
803 803 return
804 804 content = msg['content']
805 805 # print (content)
806 806 msg_id = content['msg_id']
807 807 engine_uuid = content['engine_id']
808 808 eid = self.by_ident[cast_bytes(engine_uuid)]
809 809
810 810 self.log.info("task::task %r arrived on %r", msg_id, eid)
811 811 if msg_id in self.unassigned:
812 812 self.unassigned.remove(msg_id)
813 813 # else:
814 814 # self.log.debug("task::task %r not listed as MIA?!"%(msg_id))
815 815
816 816 self.tasks[eid].append(msg_id)
817 817 # self.pending[msg_id][1].update(received=datetime.now(),engine=(eid,engine_uuid))
818 818 try:
819 819 self.db.update_record(msg_id, dict(engine_uuid=engine_uuid))
820 820 except Exception:
821 821 self.log.error("DB Error saving task destination %r", msg_id, exc_info=True)
822 822
823 823
824 824 def mia_task_request(self, idents, msg):
825 825 raise NotImplementedError
826 826 client_id = idents[0]
827 827 # content = dict(mia=self.mia,status='ok')
828 828 # self.session.send('mia_reply', content=content, idents=client_id)
829 829
830 830
831 831 #--------------------- IOPub Traffic ------------------------------
832 832
833 833 def save_iopub_message(self, topics, msg):
834 834 """save an iopub message into the db"""
835 835 # print (topics)
836 836 try:
837 837 msg = self.session.unserialize(msg, content=True)
838 838 except Exception:
839 839 self.log.error("iopub::invalid IOPub message", exc_info=True)
840 840 return
841 841
842 842 parent = msg['parent_header']
843 843 if not parent:
844 844 self.log.warn("iopub::IOPub message lacks parent: %r", msg)
845 845 return
846 846 msg_id = parent['msg_id']
847 847 msg_type = msg['header']['msg_type']
848 848 content = msg['content']
849 849
850 850 # ensure msg_id is in db
851 851 try:
852 852 rec = self.db.get_record(msg_id)
853 853 except KeyError:
854 854 rec = empty_record()
855 855 rec['msg_id'] = msg_id
856 856 self.db.add_record(msg_id, rec)
857 857 # stream
858 858 d = {}
859 859 if msg_type == 'stream':
860 860 name = content['name']
861 861 s = rec[name] or ''
862 862 d[name] = s + content['data']
863 863
864 864 elif msg_type == 'pyerr':
865 865 d['pyerr'] = content
866 866 elif msg_type == 'pyin':
867 867 d['pyin'] = content['code']
868 868 elif msg_type in ('display_data', 'pyout'):
869 869 d[msg_type] = content
870 870 elif msg_type == 'status':
871 871 pass
872 872 elif msg_type == 'data_pub':
873 873 self.log.info("ignored data_pub message for %s" % msg_id)
874 874 else:
875 875 self.log.warn("unhandled iopub msg_type: %r", msg_type)
876 876
877 877 if not d:
878 878 return
879 879
880 880 try:
881 881 self.db.update_record(msg_id, d)
882 882 except Exception:
883 883 self.log.error("DB Error saving iopub message %r", msg_id, exc_info=True)
884 884
885 885
886 886
887 887 #-------------------------------------------------------------------------
888 888 # Registration requests
889 889 #-------------------------------------------------------------------------
890 890
891 891 def connection_request(self, client_id, msg):
892 892 """Reply with connection addresses for clients."""
893 893 self.log.info("client::client %r connected", client_id)
894 894 content = dict(status='ok')
895 895 jsonable = {}
896 896 for k,v in iteritems(self.keytable):
897 897 if v not in self.dead_engines:
898 898 jsonable[str(k)] = v
899 899 content['engines'] = jsonable
900 900 self.session.send(self.query, 'connection_reply', content, parent=msg, ident=client_id)
901 901
902 902 def register_engine(self, reg, msg):
903 903 """Register a new engine."""
904 904 content = msg['content']
905 905 try:
906 906 uuid = content['uuid']
907 907 except KeyError:
908 908 self.log.error("registration::queue not specified", exc_info=True)
909 909 return
910 910
911 911 eid = self._next_id
912 912
913 913 self.log.debug("registration::register_engine(%i, %r)", eid, uuid)
914 914
915 915 content = dict(id=eid,status='ok',hb_period=self.heartmonitor.period)
916 916 # check if requesting available IDs:
917 917 if cast_bytes(uuid) in self.by_ident:
918 918 try:
919 919 raise KeyError("uuid %r in use" % uuid)
920 920 except:
921 921 content = error.wrap_exception()
922 922 self.log.error("uuid %r in use", uuid, exc_info=True)
923 923 else:
924 924 for h, ec in iteritems(self.incoming_registrations):
925 925 if uuid == h:
926 926 try:
927 927 raise KeyError("heart_id %r in use" % uuid)
928 928 except:
929 929 self.log.error("heart_id %r in use", uuid, exc_info=True)
930 930 content = error.wrap_exception()
931 931 break
932 932 elif uuid == ec.uuid:
933 933 try:
934 934 raise KeyError("uuid %r in use" % uuid)
935 935 except:
936 936 self.log.error("uuid %r in use", uuid, exc_info=True)
937 937 content = error.wrap_exception()
938 938 break
939 939
940 940 msg = self.session.send(self.query, "registration_reply",
941 941 content=content,
942 942 ident=reg)
943 943
944 944 heart = cast_bytes(uuid)
945 945
946 946 if content['status'] == 'ok':
947 947 if heart in self.heartmonitor.hearts:
948 948 # already beating
949 949 self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid)
950 950 self.finish_registration(heart)
951 951 else:
952 952 purge = lambda : self._purge_stalled_registration(heart)
953 953 dc = ioloop.DelayedCallback(purge, self.registration_timeout, self.loop)
954 954 dc.start()
955 955 self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid,stallback=dc)
956 956 else:
957 957 self.log.error("registration::registration %i failed: %r", eid, content['evalue'])
958 958
959 959 return eid
960 960
961 961 def unregister_engine(self, ident, msg):
962 962 """Unregister an engine that explicitly requested to leave."""
963 963 try:
964 964 eid = msg['content']['id']
965 965 except:
966 966 self.log.error("registration::bad engine id for unregistration: %r", ident, exc_info=True)
967 967 return
968 968 self.log.info("registration::unregister_engine(%r)", eid)
969 969 # print (eid)
970 970 uuid = self.keytable[eid]
971 971 content=dict(id=eid, uuid=uuid)
972 972 self.dead_engines.add(uuid)
973 973 # self.ids.remove(eid)
974 974 # uuid = self.keytable.pop(eid)
975 975 #
976 976 # ec = self.engines.pop(eid)
977 977 # self.hearts.pop(ec.heartbeat)
978 978 # self.by_ident.pop(ec.queue)
979 979 # self.completed.pop(eid)
980 980 handleit = lambda : self._handle_stranded_msgs(eid, uuid)
981 981 dc = ioloop.DelayedCallback(handleit, self.registration_timeout, self.loop)
982 982 dc.start()
983 983 ############## TODO: HANDLE IT ################
984 984
985 985 self._save_engine_state()
986 986
987 987 if self.notifier:
988 988 self.session.send(self.notifier, "unregistration_notification", content=content)
989 989
990 990 def _handle_stranded_msgs(self, eid, uuid):
991 991 """Handle messages known to be on an engine when the engine unregisters.
992 992
993 993 It is possible that this will fire prematurely - that is, an engine will
994 994 go down after completing a result, and the client will be notified
995 995 that the result failed and later receive the actual result.
996 996 """
997 997
998 998 outstanding = self.queues[eid]
999 999
1000 1000 for msg_id in outstanding:
1001 1001 self.pending.remove(msg_id)
1002 1002 self.all_completed.add(msg_id)
1003 1003 try:
1004 1004 raise error.EngineError("Engine %r died while running task %r" % (eid, msg_id))
1005 1005 except:
1006 1006 content = error.wrap_exception()
1007 1007 # build a fake header:
1008 1008 header = {}
1009 1009 header['engine'] = uuid
1010 1010 header['date'] = datetime.now()
1011 1011 rec = dict(result_content=content, result_header=header, result_buffers=[])
1012 1012 rec['completed'] = header['date']
1013 1013 rec['engine_uuid'] = uuid
1014 1014 try:
1015 1015 self.db.update_record(msg_id, rec)
1016 1016 except Exception:
1017 1017 self.log.error("DB Error handling stranded msg %r", msg_id, exc_info=True)
1018 1018
1019 1019
1020 1020 def finish_registration(self, heart):
1021 1021 """Second half of engine registration, called after our HeartMonitor
1022 1022 has received a beat from the Engine's Heart."""
1023 1023 try:
1024 1024 ec = self.incoming_registrations.pop(heart)
1025 1025 except KeyError:
1026 1026 self.log.error("registration::tried to finish nonexistant registration", exc_info=True)
1027 1027 return
1028 1028 self.log.info("registration::finished registering engine %i:%s", ec.id, ec.uuid)
1029 1029 if ec.stallback is not None:
1030 1030 ec.stallback.stop()
1031 1031 eid = ec.id
1032 1032 self.ids.add(eid)
1033 1033 self.keytable[eid] = ec.uuid
1034 1034 self.engines[eid] = ec
1035 1035 self.by_ident[cast_bytes(ec.uuid)] = ec.id
1036 1036 self.queues[eid] = list()
1037 1037 self.tasks[eid] = list()
1038 1038 self.completed[eid] = list()
1039 1039 self.hearts[heart] = eid
1040 1040 content = dict(id=eid, uuid=self.engines[eid].uuid)
1041 1041 if self.notifier:
1042 1042 self.session.send(self.notifier, "registration_notification", content=content)
1043 1043 self.log.info("engine::Engine Connected: %i", eid)
1044 1044
1045 1045 self._save_engine_state()
1046 1046
1047 1047 def _purge_stalled_registration(self, heart):
1048 1048 if heart in self.incoming_registrations:
1049 1049 ec = self.incoming_registrations.pop(heart)
1050 1050 self.log.info("registration::purging stalled registration: %i", ec.id)
1051 1051 else:
1052 1052 pass
1053 1053
1054 1054 #-------------------------------------------------------------------------
1055 1055 # Engine State
1056 1056 #-------------------------------------------------------------------------
1057 1057
1058 1058
1059 1059 def _cleanup_engine_state_file(self):
1060 1060 """cleanup engine state mapping"""
1061 1061
1062 1062 if os.path.exists(self.engine_state_file):
1063 1063 self.log.debug("cleaning up engine state: %s", self.engine_state_file)
1064 1064 try:
1065 1065 os.remove(self.engine_state_file)
1066 1066 except IOError:
1067 1067 self.log.error("Couldn't cleanup file: %s", self.engine_state_file, exc_info=True)
1068 1068
1069 1069
1070 1070 def _save_engine_state(self):
1071 1071 """save engine mapping to JSON file"""
1072 1072 if not self.engine_state_file:
1073 1073 return
1074 1074 self.log.debug("save engine state to %s" % self.engine_state_file)
1075 1075 state = {}
1076 1076 engines = {}
1077 1077 for eid, ec in iteritems(self.engines):
1078 1078 if ec.uuid not in self.dead_engines:
1079 1079 engines[eid] = ec.uuid
1080 1080
1081 1081 state['engines'] = engines
1082 1082
1083 1083 state['next_id'] = self._idcounter
1084 1084
1085 1085 with open(self.engine_state_file, 'w') as f:
1086 1086 json.dump(state, f)
1087 1087
1088 1088
1089 1089 def _load_engine_state(self):
1090 1090 """load engine mapping from JSON file"""
1091 1091 if not os.path.exists(self.engine_state_file):
1092 1092 return
1093 1093
1094 1094 self.log.info("loading engine state from %s" % self.engine_state_file)
1095 1095
1096 1096 with open(self.engine_state_file) as f:
1097 1097 state = json.load(f)
1098 1098
1099 1099 save_notifier = self.notifier
1100 1100 self.notifier = None
1101 1101 for eid, uuid in iteritems(state['engines']):
1102 1102 heart = uuid.encode('ascii')
1103 1103 # start with this heart as current and beating:
1104 1104 self.heartmonitor.responses.add(heart)
1105 1105 self.heartmonitor.hearts.add(heart)
1106 1106
1107 1107 self.incoming_registrations[heart] = EngineConnector(id=int(eid), uuid=uuid)
1108 1108 self.finish_registration(heart)
1109 1109
1110 1110 self.notifier = save_notifier
1111 1111
1112 1112 self._idcounter = state['next_id']
1113 1113
1114 1114 #-------------------------------------------------------------------------
1115 1115 # Client Requests
1116 1116 #-------------------------------------------------------------------------
1117 1117
1118 1118 def shutdown_request(self, client_id, msg):
1119 1119 """handle shutdown request."""
1120 1120 self.session.send(self.query, 'shutdown_reply', content={'status': 'ok'}, ident=client_id)
1121 1121 # also notify other clients of shutdown
1122 1122 self.session.send(self.notifier, 'shutdown_notice', content={'status': 'ok'})
1123 1123 dc = ioloop.DelayedCallback(lambda : self._shutdown(), 1000, self.loop)
1124 1124 dc.start()
1125 1125
1126 1126 def _shutdown(self):
1127 1127 self.log.info("hub::hub shutting down.")
1128 1128 time.sleep(0.1)
1129 1129 sys.exit(0)
1130 1130
1131 1131
1132 1132 def check_load(self, client_id, msg):
1133 1133 content = msg['content']
1134 1134 try:
1135 1135 targets = content['targets']
1136 1136 targets = self._validate_targets(targets)
1137 1137 except:
1138 1138 content = error.wrap_exception()
1139 1139 self.session.send(self.query, "hub_error",
1140 1140 content=content, ident=client_id)
1141 1141 return
1142 1142
1143 1143 content = dict(status='ok')
1144 1144 # loads = {}
1145 1145 for t in targets:
1146 1146 content[bytes(t)] = len(self.queues[t])+len(self.tasks[t])
1147 1147 self.session.send(self.query, "load_reply", content=content, ident=client_id)
1148 1148
1149 1149
1150 1150 def queue_status(self, client_id, msg):
1151 1151 """Return the Queue status of one or more targets.
1152 if verbose: return the msg_ids
1153 else: return len of each type.
1154 keys: queue (pending MUX jobs)
1155 tasks (pending Task jobs)
1156 completed (finished jobs from both queues)"""
1152
1153 If verbose, return the msg_ids, else return len of each type.
1154
1155 Keys:
1156
1157 * queue (pending MUX jobs)
1158 * tasks (pending Task jobs)
1159 * completed (finished jobs from both queues)
1160 """
1157 1161 content = msg['content']
1158 1162 targets = content['targets']
1159 1163 try:
1160 1164 targets = self._validate_targets(targets)
1161 1165 except:
1162 1166 content = error.wrap_exception()
1163 1167 self.session.send(self.query, "hub_error",
1164 1168 content=content, ident=client_id)
1165 1169 return
1166 1170 verbose = content.get('verbose', False)
1167 1171 content = dict(status='ok')
1168 1172 for t in targets:
1169 1173 queue = self.queues[t]
1170 1174 completed = self.completed[t]
1171 1175 tasks = self.tasks[t]
1172 1176 if not verbose:
1173 1177 queue = len(queue)
1174 1178 completed = len(completed)
1175 1179 tasks = len(tasks)
1176 1180 content[str(t)] = {'queue': queue, 'completed': completed , 'tasks': tasks}
1177 1181 content['unassigned'] = list(self.unassigned) if verbose else len(self.unassigned)
1178 1182 # print (content)
1179 1183 self.session.send(self.query, "queue_reply", content=content, ident=client_id)
1180 1184
1181 1185 def purge_results(self, client_id, msg):
1182 1186 """Purge results from memory. This method is more valuable before we move
1183 1187 to a DB based message storage mechanism."""
1184 1188 content = msg['content']
1185 1189 self.log.info("Dropping records with %s", content)
1186 1190 msg_ids = content.get('msg_ids', [])
1187 1191 reply = dict(status='ok')
1188 1192 if msg_ids == 'all':
1189 1193 try:
1190 1194 self.db.drop_matching_records(dict(completed={'$ne':None}))
1191 1195 except Exception:
1192 1196 reply = error.wrap_exception()
1193 1197 else:
1194 1198 pending = [m for m in msg_ids if (m in self.pending)]
1195 1199 if pending:
1196 1200 try:
1197 1201 raise IndexError("msg pending: %r" % pending[0])
1198 1202 except:
1199 1203 reply = error.wrap_exception()
1200 1204 else:
1201 1205 try:
1202 1206 self.db.drop_matching_records(dict(msg_id={'$in':msg_ids}))
1203 1207 except Exception:
1204 1208 reply = error.wrap_exception()
1205 1209
1206 1210 if reply['status'] == 'ok':
1207 1211 eids = content.get('engine_ids', [])
1208 1212 for eid in eids:
1209 1213 if eid not in self.engines:
1210 1214 try:
1211 1215 raise IndexError("No such engine: %i" % eid)
1212 1216 except:
1213 1217 reply = error.wrap_exception()
1214 1218 break
1215 1219 uid = self.engines[eid].uuid
1216 1220 try:
1217 1221 self.db.drop_matching_records(dict(engine_uuid=uid, completed={'$ne':None}))
1218 1222 except Exception:
1219 1223 reply = error.wrap_exception()
1220 1224 break
1221 1225
1222 1226 self.session.send(self.query, 'purge_reply', content=reply, ident=client_id)
1223 1227
1224 1228 def resubmit_task(self, client_id, msg):
1225 1229 """Resubmit one or more tasks."""
1226 1230 def finish(reply):
1227 1231 self.session.send(self.query, 'resubmit_reply', content=reply, ident=client_id)
1228 1232
1229 1233 content = msg['content']
1230 1234 msg_ids = content['msg_ids']
1231 1235 reply = dict(status='ok')
1232 1236 try:
1233 1237 records = self.db.find_records({'msg_id' : {'$in' : msg_ids}}, keys=[
1234 1238 'header', 'content', 'buffers'])
1235 1239 except Exception:
1236 1240 self.log.error('db::db error finding tasks to resubmit', exc_info=True)
1237 1241 return finish(error.wrap_exception())
1238 1242
1239 1243 # validate msg_ids
1240 1244 found_ids = [ rec['msg_id'] for rec in records ]
1241 1245 pending_ids = [ msg_id for msg_id in found_ids if msg_id in self.pending ]
1242 1246 if len(records) > len(msg_ids):
1243 1247 try:
1244 1248 raise RuntimeError("DB appears to be in an inconsistent state."
1245 1249 "More matching records were found than should exist")
1246 1250 except Exception:
1247 1251 return finish(error.wrap_exception())
1248 1252 elif len(records) < len(msg_ids):
1249 1253 missing = [ m for m in msg_ids if m not in found_ids ]
1250 1254 try:
1251 1255 raise KeyError("No such msg(s): %r" % missing)
1252 1256 except KeyError:
1253 1257 return finish(error.wrap_exception())
1254 1258 elif pending_ids:
1255 1259 pass
1256 1260 # no need to raise on resubmit of pending task, now that we
1257 1261 # resubmit under new ID, but do we want to raise anyway?
1258 1262 # msg_id = invalid_ids[0]
1259 1263 # try:
1260 1264 # raise ValueError("Task(s) %r appears to be inflight" % )
1261 1265 # except Exception:
1262 1266 # return finish(error.wrap_exception())
1263 1267
1264 1268 # mapping of original IDs to resubmitted IDs
1265 1269 resubmitted = {}
1266 1270
1267 1271 # send the messages
1268 1272 for rec in records:
1269 1273 header = rec['header']
1270 1274 msg = self.session.msg(header['msg_type'], parent=header)
1271 1275 msg_id = msg['msg_id']
1272 1276 msg['content'] = rec['content']
1273 1277
1274 1278 # use the old header, but update msg_id and timestamp
1275 1279 fresh = msg['header']
1276 1280 header['msg_id'] = fresh['msg_id']
1277 1281 header['date'] = fresh['date']
1278 1282 msg['header'] = header
1279 1283
1280 1284 self.session.send(self.resubmit, msg, buffers=rec['buffers'])
1281 1285
1282 1286 resubmitted[rec['msg_id']] = msg_id
1283 1287 self.pending.add(msg_id)
1284 1288 msg['buffers'] = rec['buffers']
1285 1289 try:
1286 1290 self.db.add_record(msg_id, init_record(msg))
1287 1291 except Exception:
1288 1292 self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True)
1289 1293 return finish(error.wrap_exception())
1290 1294
1291 1295 finish(dict(status='ok', resubmitted=resubmitted))
1292 1296
1293 1297 # store the new IDs in the Task DB
1294 1298 for msg_id, resubmit_id in iteritems(resubmitted):
1295 1299 try:
1296 1300 self.db.update_record(msg_id, {'resubmitted' : resubmit_id})
1297 1301 except Exception:
1298 1302 self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True)
1299 1303
1300 1304
1301 1305 def _extract_record(self, rec):
1302 1306 """decompose a TaskRecord dict into subsection of reply for get_result"""
1303 1307 io_dict = {}
1304 1308 for key in ('pyin', 'pyout', 'pyerr', 'stdout', 'stderr'):
1305 1309 io_dict[key] = rec[key]
1306 1310 content = {
1307 1311 'header': rec['header'],
1308 1312 'metadata': rec['metadata'],
1309 1313 'result_metadata': rec['result_metadata'],
1310 1314 'result_header' : rec['result_header'],
1311 1315 'result_content': rec['result_content'],
1312 1316 'received' : rec['received'],
1313 1317 'io' : io_dict,
1314 1318 }
1315 1319 if rec['result_buffers']:
1316 1320 buffers = list(map(bytes, rec['result_buffers']))
1317 1321 else:
1318 1322 buffers = []
1319 1323
1320 1324 return content, buffers
1321 1325
1322 1326 def get_results(self, client_id, msg):
1323 1327 """Get the result of 1 or more messages."""
1324 1328 content = msg['content']
1325 1329 msg_ids = sorted(set(content['msg_ids']))
1326 1330 statusonly = content.get('status_only', False)
1327 1331 pending = []
1328 1332 completed = []
1329 1333 content = dict(status='ok')
1330 1334 content['pending'] = pending
1331 1335 content['completed'] = completed
1332 1336 buffers = []
1333 1337 if not statusonly:
1334 1338 try:
1335 1339 matches = self.db.find_records(dict(msg_id={'$in':msg_ids}))
1336 1340 # turn match list into dict, for faster lookup
1337 1341 records = {}
1338 1342 for rec in matches:
1339 1343 records[rec['msg_id']] = rec
1340 1344 except Exception:
1341 1345 content = error.wrap_exception()
1342 1346 self.session.send(self.query, "result_reply", content=content,
1343 1347 parent=msg, ident=client_id)
1344 1348 return
1345 1349 else:
1346 1350 records = {}
1347 1351 for msg_id in msg_ids:
1348 1352 if msg_id in self.pending:
1349 1353 pending.append(msg_id)
1350 1354 elif msg_id in self.all_completed:
1351 1355 completed.append(msg_id)
1352 1356 if not statusonly:
1353 1357 c,bufs = self._extract_record(records[msg_id])
1354 1358 content[msg_id] = c
1355 1359 buffers.extend(bufs)
1356 1360 elif msg_id in records:
1357 1361 if rec['completed']:
1358 1362 completed.append(msg_id)
1359 1363 c,bufs = self._extract_record(records[msg_id])
1360 1364 content[msg_id] = c
1361 1365 buffers.extend(bufs)
1362 1366 else:
1363 1367 pending.append(msg_id)
1364 1368 else:
1365 1369 try:
1366 1370 raise KeyError('No such message: '+msg_id)
1367 1371 except:
1368 1372 content = error.wrap_exception()
1369 1373 break
1370 1374 self.session.send(self.query, "result_reply", content=content,
1371 1375 parent=msg, ident=client_id,
1372 1376 buffers=buffers)
1373 1377
1374 1378 def get_history(self, client_id, msg):
1375 1379 """Get a list of all msg_ids in our DB records"""
1376 1380 try:
1377 1381 msg_ids = self.db.get_history()
1378 1382 except Exception as e:
1379 1383 content = error.wrap_exception()
1380 1384 else:
1381 1385 content = dict(status='ok', history=msg_ids)
1382 1386
1383 1387 self.session.send(self.query, "history_reply", content=content,
1384 1388 parent=msg, ident=client_id)
1385 1389
1386 1390 def db_query(self, client_id, msg):
1387 1391 """Perform a raw query on the task record database."""
1388 1392 content = msg['content']
1389 1393 query = extract_dates(content.get('query', {}))
1390 1394 keys = content.get('keys', None)
1391 1395 buffers = []
1392 1396 empty = list()
1393 1397 try:
1394 1398 records = self.db.find_records(query, keys)
1395 1399 except Exception as e:
1396 1400 content = error.wrap_exception()
1397 1401 else:
1398 1402 # extract buffers from reply content:
1399 1403 if keys is not None:
1400 1404 buffer_lens = [] if 'buffers' in keys else None
1401 1405 result_buffer_lens = [] if 'result_buffers' in keys else None
1402 1406 else:
1403 1407 buffer_lens = None
1404 1408 result_buffer_lens = None
1405 1409
1406 1410 for rec in records:
1407 1411 # buffers may be None, so double check
1408 1412 b = rec.pop('buffers', empty) or empty
1409 1413 if buffer_lens is not None:
1410 1414 buffer_lens.append(len(b))
1411 1415 buffers.extend(b)
1412 1416 rb = rec.pop('result_buffers', empty) or empty
1413 1417 if result_buffer_lens is not None:
1414 1418 result_buffer_lens.append(len(rb))
1415 1419 buffers.extend(rb)
1416 1420 content = dict(status='ok', records=records, buffer_lens=buffer_lens,
1417 1421 result_buffer_lens=result_buffer_lens)
1418 1422 # self.log.debug (content)
1419 1423 self.session.send(self.query, "db_reply", content=content,
1420 1424 parent=msg, ident=client_id,
1421 1425 buffers=buffers)
1422 1426
@@ -1,369 +1,370 b''
1 1 """some generic utilities for dealing with classes, urls, and serialization
2 2
3 3 Authors:
4 4
5 5 * Min RK
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2010-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # Standard library imports.
19 19 import logging
20 20 import os
21 21 import re
22 22 import stat
23 23 import socket
24 24 import sys
25 25 from signal import signal, SIGINT, SIGABRT, SIGTERM
26 26 try:
27 27 from signal import SIGKILL
28 28 except ImportError:
29 29 SIGKILL=None
30 30
31 31 try:
32 32 import cPickle
33 33 pickle = cPickle
34 34 except:
35 35 cPickle = None
36 36 import pickle
37 37
38 38 # System library imports
39 39 import zmq
40 40 from zmq.log import handlers
41 41
42 42 from IPython.external.decorator import decorator
43 43
44 44 # IPython imports
45 45 from IPython.config.application import Application
46 46 from IPython.utils.localinterfaces import localhost, is_public_ip, public_ips
47 47 from IPython.utils.py3compat import string_types, iteritems, itervalues
48 48 from IPython.kernel.zmq.log import EnginePUBHandler
49 49 from IPython.kernel.zmq.serialize import (
50 50 unserialize_object, serialize_object, pack_apply_message, unpack_apply_message
51 51 )
52 52
53 53 #-----------------------------------------------------------------------------
54 54 # Classes
55 55 #-----------------------------------------------------------------------------
56 56
57 57 class Namespace(dict):
58 58 """Subclass of dict for attribute access to keys."""
59 59
60 60 def __getattr__(self, key):
61 61 """getattr aliased to getitem"""
62 62 if key in self:
63 63 return self[key]
64 64 else:
65 65 raise NameError(key)
66 66
67 67 def __setattr__(self, key, value):
68 68 """setattr aliased to setitem, with strict"""
69 69 if hasattr(dict, key):
70 70 raise KeyError("Cannot override dict keys %r"%key)
71 71 self[key] = value
72 72
73 73
74 74 class ReverseDict(dict):
75 75 """simple double-keyed subset of dict methods."""
76 76
77 77 def __init__(self, *args, **kwargs):
78 78 dict.__init__(self, *args, **kwargs)
79 79 self._reverse = dict()
80 80 for key, value in iteritems(self):
81 81 self._reverse[value] = key
82 82
83 83 def __getitem__(self, key):
84 84 try:
85 85 return dict.__getitem__(self, key)
86 86 except KeyError:
87 87 return self._reverse[key]
88 88
89 89 def __setitem__(self, key, value):
90 90 if key in self._reverse:
91 91 raise KeyError("Can't have key %r on both sides!"%key)
92 92 dict.__setitem__(self, key, value)
93 93 self._reverse[value] = key
94 94
95 95 def pop(self, key):
96 96 value = dict.pop(self, key)
97 97 self._reverse.pop(value)
98 98 return value
99 99
100 100 def get(self, key, default=None):
101 101 try:
102 102 return self[key]
103 103 except KeyError:
104 104 return default
105 105
106 106 #-----------------------------------------------------------------------------
107 107 # Functions
108 108 #-----------------------------------------------------------------------------
109 109
110 110 @decorator
111 111 def log_errors(f, self, *args, **kwargs):
112 112 """decorator to log unhandled exceptions raised in a method.
113 113
114 114 For use wrapping on_recv callbacks, so that exceptions
115 115 do not cause the stream to be closed.
116 116 """
117 117 try:
118 118 return f(self, *args, **kwargs)
119 119 except Exception:
120 120 self.log.error("Uncaught exception in %r" % f, exc_info=True)
121 121
122 122
123 123 def is_url(url):
124 124 """boolean check for whether a string is a zmq url"""
125 125 if '://' not in url:
126 126 return False
127 127 proto, addr = url.split('://', 1)
128 128 if proto.lower() not in ['tcp','pgm','epgm','ipc','inproc']:
129 129 return False
130 130 return True
131 131
132 132 def validate_url(url):
133 133 """validate a url for zeromq"""
134 134 if not isinstance(url, string_types):
135 135 raise TypeError("url must be a string, not %r"%type(url))
136 136 url = url.lower()
137 137
138 138 proto_addr = url.split('://')
139 139 assert len(proto_addr) == 2, 'Invalid url: %r'%url
140 140 proto, addr = proto_addr
141 141 assert proto in ['tcp','pgm','epgm','ipc','inproc'], "Invalid protocol: %r"%proto
142 142
143 143 # domain pattern adapted from http://www.regexlib.com/REDetails.aspx?regexp_id=391
144 144 # author: Remi Sabourin
145 145 pat = re.compile(r'^([\w\d]([\w\d\-]{0,61}[\w\d])?\.)*[\w\d]([\w\d\-]{0,61}[\w\d])?$')
146 146
147 147 if proto == 'tcp':
148 148 lis = addr.split(':')
149 149 assert len(lis) == 2, 'Invalid url: %r'%url
150 150 addr,s_port = lis
151 151 try:
152 152 port = int(s_port)
153 153 except ValueError:
154 154 raise AssertionError("Invalid port %r in url: %r"%(port, url))
155 155
156 156 assert addr == '*' or pat.match(addr) is not None, 'Invalid url: %r'%url
157 157
158 158 else:
159 159 # only validate tcp urls currently
160 160 pass
161 161
162 162 return True
163 163
164 164
165 165 def validate_url_container(container):
166 166 """validate a potentially nested collection of urls."""
167 167 if isinstance(container, string_types):
168 168 url = container
169 169 return validate_url(url)
170 170 elif isinstance(container, dict):
171 171 container = itervalues(container)
172 172
173 173 for element in container:
174 174 validate_url_container(element)
175 175
176 176
177 177 def split_url(url):
178 178 """split a zmq url (tcp://ip:port) into ('tcp','ip','port')."""
179 179 proto_addr = url.split('://')
180 180 assert len(proto_addr) == 2, 'Invalid url: %r'%url
181 181 proto, addr = proto_addr
182 182 lis = addr.split(':')
183 183 assert len(lis) == 2, 'Invalid url: %r'%url
184 184 addr,s_port = lis
185 185 return proto,addr,s_port
186 186
187 187 def disambiguate_ip_address(ip, location=None):
188 188 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
189 189 ones, based on the location (default interpretation of location is localhost)."""
190 190 if ip in ('0.0.0.0', '*'):
191 191 if location is None or is_public_ip(location) or not public_ips():
192 192 # If location is unspecified or cannot be determined, assume local
193 193 ip = localhost()
194 194 elif location:
195 195 return location
196 196 return ip
197 197
198 198 def disambiguate_url(url, location=None):
199 199 """turn multi-ip interfaces '0.0.0.0' and '*' into connectable
200 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 204 try:
204 205 proto,ip,port = split_url(url)
205 206 except AssertionError:
206 207 # probably not tcp url; could be ipc, etc.
207 208 return url
208 209
209 210 ip = disambiguate_ip_address(ip,location)
210 211
211 212 return "%s://%s:%s"%(proto,ip,port)
212 213
213 214
214 215 #--------------------------------------------------------------------------
215 216 # helpers for implementing old MEC API via view.apply
216 217 #--------------------------------------------------------------------------
217 218
218 219 def interactive(f):
219 220 """decorator for making functions appear as interactively defined.
220 221 This results in the function being linked to the user_ns as globals()
221 222 instead of the module globals().
222 223 """
223 224 f.__module__ = '__main__'
224 225 return f
225 226
226 227 @interactive
227 228 def _push(**ns):
228 229 """helper method for implementing `client.push` via `client.apply`"""
229 230 user_ns = globals()
230 231 tmp = '_IP_PUSH_TMP_'
231 232 while tmp in user_ns:
232 233 tmp = tmp + '_'
233 234 try:
234 235 for name, value in ns.items():
235 236 user_ns[tmp] = value
236 237 exec("%s = %s" % (name, tmp), user_ns)
237 238 finally:
238 239 user_ns.pop(tmp, None)
239 240
240 241 @interactive
241 242 def _pull(keys):
242 243 """helper method for implementing `client.pull` via `client.apply`"""
243 244 if isinstance(keys, (list,tuple, set)):
244 245 return [eval(key, globals()) for key in keys]
245 246 else:
246 247 return eval(keys, globals())
247 248
248 249 @interactive
249 250 def _execute(code):
250 251 """helper method for implementing `client.execute` via `client.apply`"""
251 252 exec(code, globals())
252 253
253 254 #--------------------------------------------------------------------------
254 255 # extra process management utilities
255 256 #--------------------------------------------------------------------------
256 257
257 258 _random_ports = set()
258 259
259 260 def select_random_ports(n):
260 261 """Selects and return n random ports that are available."""
261 262 ports = []
262 263 for i in range(n):
263 264 sock = socket.socket()
264 265 sock.bind(('', 0))
265 266 while sock.getsockname()[1] in _random_ports:
266 267 sock.close()
267 268 sock = socket.socket()
268 269 sock.bind(('', 0))
269 270 ports.append(sock)
270 271 for i, sock in enumerate(ports):
271 272 port = sock.getsockname()[1]
272 273 sock.close()
273 274 ports[i] = port
274 275 _random_ports.add(port)
275 276 return ports
276 277
277 278 def signal_children(children):
278 279 """Relay interupt/term signals to children, for more solid process cleanup."""
279 280 def terminate_children(sig, frame):
280 281 log = Application.instance().log
281 282 log.critical("Got signal %i, terminating children..."%sig)
282 283 for child in children:
283 284 child.terminate()
284 285
285 286 sys.exit(sig != SIGINT)
286 287 # sys.exit(sig)
287 288 for sig in (SIGINT, SIGABRT, SIGTERM):
288 289 signal(sig, terminate_children)
289 290
290 291 def generate_exec_key(keyfile):
291 292 import uuid
292 293 newkey = str(uuid.uuid4())
293 294 with open(keyfile, 'w') as f:
294 295 # f.write('ipython-key ')
295 296 f.write(newkey+'\n')
296 297 # set user-only RW permissions (0600)
297 298 # this will have no effect on Windows
298 299 os.chmod(keyfile, stat.S_IRUSR|stat.S_IWUSR)
299 300
300 301
301 302 def integer_loglevel(loglevel):
302 303 try:
303 304 loglevel = int(loglevel)
304 305 except ValueError:
305 306 if isinstance(loglevel, str):
306 307 loglevel = getattr(logging, loglevel)
307 308 return loglevel
308 309
309 310 def connect_logger(logname, context, iface, root="ip", loglevel=logging.DEBUG):
310 311 logger = logging.getLogger(logname)
311 312 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
312 313 # don't add a second PUBHandler
313 314 return
314 315 loglevel = integer_loglevel(loglevel)
315 316 lsock = context.socket(zmq.PUB)
316 317 lsock.connect(iface)
317 318 handler = handlers.PUBHandler(lsock)
318 319 handler.setLevel(loglevel)
319 320 handler.root_topic = root
320 321 logger.addHandler(handler)
321 322 logger.setLevel(loglevel)
322 323
323 324 def connect_engine_logger(context, iface, engine, loglevel=logging.DEBUG):
324 325 logger = logging.getLogger()
325 326 if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]):
326 327 # don't add a second PUBHandler
327 328 return
328 329 loglevel = integer_loglevel(loglevel)
329 330 lsock = context.socket(zmq.PUB)
330 331 lsock.connect(iface)
331 332 handler = EnginePUBHandler(engine, lsock)
332 333 handler.setLevel(loglevel)
333 334 logger.addHandler(handler)
334 335 logger.setLevel(loglevel)
335 336 return logger
336 337
337 338 def local_logger(logname, loglevel=logging.DEBUG):
338 339 loglevel = integer_loglevel(loglevel)
339 340 logger = logging.getLogger(logname)
340 341 if any([isinstance(h, logging.StreamHandler) for h in logger.handlers]):
341 342 # don't add a second StreamHandler
342 343 return
343 344 handler = logging.StreamHandler()
344 345 handler.setLevel(loglevel)
345 346 formatter = logging.Formatter("%(asctime)s.%(msecs).03d [%(name)s] %(message)s",
346 347 datefmt="%Y-%m-%d %H:%M:%S")
347 348 handler.setFormatter(formatter)
348 349
349 350 logger.addHandler(handler)
350 351 logger.setLevel(loglevel)
351 352 return logger
352 353
353 354 def set_hwm(sock, hwm=0):
354 355 """set zmq High Water Mark on a socket
355 356
356 357 in a way that always works for various pyzmq / libzmq versions.
357 358 """
358 359 import zmq
359 360
360 361 for key in ('HWM', 'SNDHWM', 'RCVHWM'):
361 362 opt = getattr(zmq, key, None)
362 363 if opt is None:
363 364 continue
364 365 try:
365 366 sock.setsockopt(opt, hwm)
366 367 except zmq.ZMQError:
367 368 pass
368 369
369 370 No newline at end of file
@@ -1,692 +1,691 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Subclass of InteractiveShell for terminal based frontends."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 import bdb
19 19 import os
20 20 import sys
21 21
22 22 from IPython.core.error import TryNext, UsageError
23 23 from IPython.core.usage import interactive_usage, default_banner
24 24 from IPython.core.inputsplitter import IPythonInputSplitter
25 25 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
26 26 from IPython.core.magic import Magics, magics_class, line_magic
27 27 from IPython.lib.clipboard import ClipboardEmpty
28 28 from IPython.testing.skipdoctest import skip_doctest
29 29 from IPython.utils.encoding import get_stream_enc
30 30 from IPython.utils import py3compat
31 31 from IPython.utils.terminal import toggle_set_term_title, set_term_title
32 32 from IPython.utils.process import abbrev_cwd
33 33 from IPython.utils.warn import warn, error
34 34 from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes
35 35 from IPython.utils.traitlets import Integer, CBool, Unicode
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Utilities
39 39 #-----------------------------------------------------------------------------
40 40
41 41 def get_default_editor():
42 42 try:
43 43 ed = os.environ['EDITOR']
44 44 except KeyError:
45 45 if os.name == 'posix':
46 46 ed = 'vi' # the only one guaranteed to be there!
47 47 else:
48 48 ed = 'notepad' # same in Windows!
49 49 return ed
50 50
51 51
52 52 def get_pasted_lines(sentinel, l_input=py3compat.input):
53 53 """ Yield pasted lines until the user enters the given sentinel value.
54 54 """
55 55 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
56 56 % sentinel)
57 57 while True:
58 58 try:
59 59 l = l_input(':')
60 60 if l == sentinel:
61 61 return
62 62 else:
63 63 yield l
64 64 except EOFError:
65 65 print('<EOF>')
66 66 return
67 67
68 68
69 69 #------------------------------------------------------------------------
70 70 # Terminal-specific magics
71 71 #------------------------------------------------------------------------
72 72
73 73 @magics_class
74 74 class TerminalMagics(Magics):
75 75 def __init__(self, shell):
76 76 super(TerminalMagics, self).__init__(shell)
77 77 self.input_splitter = IPythonInputSplitter()
78 78
79 79 def store_or_execute(self, block, name):
80 80 """ Execute a block, or store it in a variable, per the user's request.
81 81 """
82 82 if name:
83 83 # If storing it for further editing
84 84 self.shell.user_ns[name] = SList(block.splitlines())
85 85 print("Block assigned to '%s'" % name)
86 86 else:
87 87 b = self.preclean_input(block)
88 88 self.shell.user_ns['pasted_block'] = b
89 89 self.shell.using_paste_magics = True
90 90 try:
91 91 self.shell.run_cell(b)
92 92 finally:
93 93 self.shell.using_paste_magics = False
94 94
95 95 def preclean_input(self, block):
96 96 lines = block.splitlines()
97 97 while lines and not lines[0].strip():
98 98 lines = lines[1:]
99 99 return strip_email_quotes('\n'.join(lines))
100 100
101 101 def rerun_pasted(self, name='pasted_block'):
102 102 """ Rerun a previously pasted command.
103 103 """
104 104 b = self.shell.user_ns.get(name)
105 105
106 106 # Sanity checks
107 107 if b is None:
108 108 raise UsageError('No previous pasted block available')
109 109 if not isinstance(b, py3compat.string_types):
110 110 raise UsageError(
111 111 "Variable 'pasted_block' is not a string, can't execute")
112 112
113 113 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
114 114 self.shell.run_cell(b)
115 115
116 116 @line_magic
117 117 def autoindent(self, parameter_s = ''):
118 118 """Toggle autoindent on/off (if available)."""
119 119
120 120 self.shell.set_autoindent()
121 121 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
122 122
123 123 @skip_doctest
124 124 @line_magic
125 125 def cpaste(self, parameter_s=''):
126 126 """Paste & execute a pre-formatted code block from clipboard.
127 127
128 128 You must terminate the block with '--' (two minus-signs) or Ctrl-D
129 129 alone on the line. You can also provide your own sentinel with '%paste
130 130 -s %%' ('%%' is the new sentinel for this operation)
131 131
132 132 The block is dedented prior to execution to enable execution of method
133 133 definitions. '>' and '+' characters at the beginning of a line are
134 134 ignored, to allow pasting directly from e-mails, diff files and
135 135 doctests (the '...' continuation prompt is also stripped). The
136 136 executed block is also assigned to variable named 'pasted_block' for
137 137 later editing with '%edit pasted_block'.
138 138
139 139 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
140 140 This assigns the pasted block to variable 'foo' as string, without
141 141 dedenting or executing it (preceding >>> and + is still stripped)
142 142
143 143 '%cpaste -r' re-executes the block previously entered by cpaste.
144 144
145 145 Do not be alarmed by garbled output on Windows (it's a readline bug).
146 146 Just press enter and type -- (and press enter again) and the block
147 147 will be what was just pasted.
148 148
149 149 IPython statements (magics, shell escapes) are not supported (yet).
150 150
151 151 See also
152 152 --------
153 153 paste: automatically pull code from clipboard.
154 154
155 155 Examples
156 156 --------
157 157 ::
158 158
159 159 In [8]: %cpaste
160 160 Pasting code; enter '--' alone on the line to stop.
161 161 :>>> a = ["world!", "Hello"]
162 162 :>>> print " ".join(sorted(a))
163 163 :--
164 164 Hello world!
165 165 """
166 166 opts, name = self.parse_options(parameter_s, 'rs:', mode='string')
167 167 if 'r' in opts:
168 168 self.rerun_pasted()
169 169 return
170 170
171 171 sentinel = opts.get('s', '--')
172 172 block = '\n'.join(get_pasted_lines(sentinel))
173 173 self.store_or_execute(block, name)
174 174
175 175 @line_magic
176 176 def paste(self, parameter_s=''):
177 177 """Paste & execute a pre-formatted code block from clipboard.
178 178
179 179 The text is pulled directly from the clipboard without user
180 180 intervention and printed back on the screen before execution (unless
181 181 the -q flag is given to force quiet mode).
182 182
183 183 The block is dedented prior to execution to enable execution of method
184 184 definitions. '>' and '+' characters at the beginning of a line are
185 185 ignored, to allow pasting directly from e-mails, diff files and
186 186 doctests (the '...' continuation prompt is also stripped). The
187 187 executed block is also assigned to variable named 'pasted_block' for
188 188 later editing with '%edit pasted_block'.
189 189
190 190 You can also pass a variable name as an argument, e.g. '%paste foo'.
191 191 This assigns the pasted block to variable 'foo' as string, without
192 192 executing it (preceding >>> and + is still stripped).
193 193
194 194 Options:
195 195
196 196 -r: re-executes the block previously entered by cpaste.
197 197
198 198 -q: quiet mode: do not echo the pasted text back to the terminal.
199 199
200 200 IPython statements (magics, shell escapes) are not supported (yet).
201 201
202 202 See also
203 203 --------
204 204 cpaste: manually paste code into terminal until you mark its end.
205 205 """
206 206 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
207 207 if 'r' in opts:
208 208 self.rerun_pasted()
209 209 return
210 210 try:
211 211 block = self.shell.hooks.clipboard_get()
212 212 except TryNext as clipboard_exc:
213 213 message = getattr(clipboard_exc, 'args')
214 214 if message:
215 215 error(message[0])
216 216 else:
217 217 error('Could not get text from the clipboard.')
218 218 return
219 219 except ClipboardEmpty:
220 220 raise UsageError("The clipboard appears to be empty")
221 221
222 222 # By default, echo back to terminal unless quiet mode is requested
223 223 if 'q' not in opts:
224 224 write = self.shell.write
225 225 write(self.shell.pycolorize(block))
226 226 if not block.endswith('\n'):
227 227 write('\n')
228 228 write("## -- End pasted text --\n")
229 229
230 230 self.store_or_execute(block, name)
231 231
232 232 # Class-level: add a '%cls' magic only on Windows
233 233 if sys.platform == 'win32':
234 234 @line_magic
235 235 def cls(self, s):
236 236 """Clear screen.
237 237 """
238 238 os.system("cls")
239 239
240 240 #-----------------------------------------------------------------------------
241 241 # Main class
242 242 #-----------------------------------------------------------------------------
243 243
244 244 class TerminalInteractiveShell(InteractiveShell):
245 245
246 246 autoedit_syntax = CBool(False, config=True,
247 247 help="auto editing of files with syntax errors.")
248 248 banner = Unicode('')
249 249 banner1 = Unicode(default_banner, config=True,
250 250 help="""The part of the banner to be printed before the profile"""
251 251 )
252 252 banner2 = Unicode('', config=True,
253 253 help="""The part of the banner to be printed after the profile"""
254 254 )
255 255 confirm_exit = CBool(True, config=True,
256 256 help="""
257 257 Set to confirm when you try to exit IPython with an EOF (Control-D
258 258 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
259 259 you can force a direct exit without any confirmation.""",
260 260 )
261 261 # This display_banner only controls whether or not self.show_banner()
262 262 # is called when mainloop/interact are called. The default is False
263 263 # because for the terminal based application, the banner behavior
264 264 # is controlled by Global.display_banner, which IPythonApp looks at
265 265 # to determine if *it* should call show_banner() by hand or not.
266 266 display_banner = CBool(False) # This isn't configurable!
267 267 embedded = CBool(False)
268 268 embedded_active = CBool(False)
269 269 editor = Unicode(get_default_editor(), config=True,
270 270 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
271 271 )
272 272 pager = Unicode('less', config=True,
273 273 help="The shell program to be used for paging.")
274 274
275 275 screen_length = Integer(0, config=True,
276 276 help=
277 277 """Number of lines of your screen, used to control printing of very
278 278 long strings. Strings longer than this number of lines will be sent
279 279 through a pager instead of directly printed. The default value for
280 280 this is 0, which means IPython will auto-detect your screen size every
281 281 time it needs to print certain potentially long strings (this doesn't
282 282 change the behavior of the 'print' keyword, it's only triggered
283 283 internally). If for some reason this isn't working well (it needs
284 284 curses support), specify it yourself. Otherwise don't change the
285 285 default.""",
286 286 )
287 287 term_title = CBool(False, config=True,
288 288 help="Enable auto setting the terminal title."
289 289 )
290 290
291 291 # This `using_paste_magics` is used to detect whether the code is being
292 292 # executed via paste magics functions
293 293 using_paste_magics = CBool(False)
294 294
295 295 # In the terminal, GUI control is done via PyOS_InputHook
296 296 @staticmethod
297 297 def enable_gui(gui=None, app=None):
298 298 """Switch amongst GUI input hooks by name.
299 299 """
300 300 # Deferred import
301 301 from IPython.lib.inputhook import enable_gui as real_enable_gui
302 302 try:
303 303 return real_enable_gui(gui, app)
304 304 except ValueError as e:
305 305 raise UsageError("%s" % e)
306 306
307 307 def __init__(self, config=None, ipython_dir=None, profile_dir=None,
308 308 user_ns=None, user_module=None, custom_exceptions=((),None),
309 309 usage=None, banner1=None, banner2=None, display_banner=None,
310 310 **kwargs):
311 311
312 312 super(TerminalInteractiveShell, self).__init__(
313 313 config=config, ipython_dir=ipython_dir, profile_dir=profile_dir, user_ns=user_ns,
314 314 user_module=user_module, custom_exceptions=custom_exceptions,
315 315 **kwargs
316 316 )
317 317 # use os.system instead of utils.process.system by default,
318 318 # because piped system doesn't make sense in the Terminal:
319 319 self.system = self.system_raw
320 320
321 321 self.init_term_title()
322 322 self.init_usage(usage)
323 323 self.init_banner(banner1, banner2, display_banner)
324 324
325 325 #-------------------------------------------------------------------------
326 326 # Overrides of init stages
327 327 #-------------------------------------------------------------------------
328 328
329 329 def init_display_formatter(self):
330 330 super(TerminalInteractiveShell, self).init_display_formatter()
331 331 # terminal only supports plaintext
332 332 self.display_formatter.active_types = ['text/plain']
333 333
334 334 #-------------------------------------------------------------------------
335 335 # Things related to the terminal
336 336 #-------------------------------------------------------------------------
337 337
338 338 @property
339 339 def usable_screen_length(self):
340 340 if self.screen_length == 0:
341 341 return 0
342 342 else:
343 343 num_lines_bot = self.separate_in.count('\n')+1
344 344 return self.screen_length - num_lines_bot
345 345
346 346 def init_term_title(self):
347 347 # Enable or disable the terminal title.
348 348 if self.term_title:
349 349 toggle_set_term_title(True)
350 350 set_term_title('IPython: ' + abbrev_cwd())
351 351 else:
352 352 toggle_set_term_title(False)
353 353
354 354 #-------------------------------------------------------------------------
355 355 # Things related to aliases
356 356 #-------------------------------------------------------------------------
357 357
358 358 def init_alias(self):
359 359 # The parent class defines aliases that can be safely used with any
360 360 # frontend.
361 361 super(TerminalInteractiveShell, self).init_alias()
362 362
363 363 # Now define aliases that only make sense on the terminal, because they
364 364 # need direct access to the console in a way that we can't emulate in
365 365 # GUI or web frontend
366 366 if os.name == 'posix':
367 367 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
368 368 ('man', 'man')]
369 369 elif os.name == 'nt':
370 370 aliases = [('cls', 'cls')]
371 371
372 372
373 373 for name, cmd in aliases:
374 374 self.alias_manager.soft_define_alias(name, cmd)
375 375
376 376 #-------------------------------------------------------------------------
377 377 # Things related to the banner and usage
378 378 #-------------------------------------------------------------------------
379 379
380 380 def _banner1_changed(self):
381 381 self.compute_banner()
382 382
383 383 def _banner2_changed(self):
384 384 self.compute_banner()
385 385
386 386 def _term_title_changed(self, name, new_value):
387 387 self.init_term_title()
388 388
389 389 def init_banner(self, banner1, banner2, display_banner):
390 390 if banner1 is not None:
391 391 self.banner1 = banner1
392 392 if banner2 is not None:
393 393 self.banner2 = banner2
394 394 if display_banner is not None:
395 395 self.display_banner = display_banner
396 396 self.compute_banner()
397 397
398 398 def show_banner(self, banner=None):
399 399 if banner is None:
400 400 banner = self.banner
401 401 self.write(banner)
402 402
403 403 def compute_banner(self):
404 404 self.banner = self.banner1
405 405 if self.profile and self.profile != 'default':
406 406 self.banner += '\nIPython profile: %s\n' % self.profile
407 407 if self.banner2:
408 408 self.banner += '\n' + self.banner2
409 409
410 410 def init_usage(self, usage=None):
411 411 if usage is None:
412 412 self.usage = interactive_usage
413 413 else:
414 414 self.usage = usage
415 415
416 416 #-------------------------------------------------------------------------
417 417 # Mainloop and code execution logic
418 418 #-------------------------------------------------------------------------
419 419
420 420 def mainloop(self, display_banner=None):
421 421 """Start the mainloop.
422 422
423 423 If an optional banner argument is given, it will override the
424 424 internally created default banner.
425 425 """
426 426
427 427 with self.builtin_trap, self.display_trap:
428 428
429 429 while 1:
430 430 try:
431 431 self.interact(display_banner=display_banner)
432 432 #self.interact_with_readline()
433 433 # XXX for testing of a readline-decoupled repl loop, call
434 434 # interact_with_readline above
435 435 break
436 436 except KeyboardInterrupt:
437 437 # this should not be necessary, but KeyboardInterrupt
438 438 # handling seems rather unpredictable...
439 439 self.write("\nKeyboardInterrupt in interact()\n")
440 440
441 441 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
442 442 """Store multiple lines as a single entry in history"""
443 443
444 444 # do nothing without readline or disabled multiline
445 445 if not self.has_readline or not self.multiline_history:
446 446 return hlen_before_cell
447 447
448 448 # windows rl has no remove_history_item
449 449 if not hasattr(self.readline, "remove_history_item"):
450 450 return hlen_before_cell
451 451
452 452 # skip empty cells
453 453 if not source_raw.rstrip():
454 454 return hlen_before_cell
455 455
456 456 # nothing changed do nothing, e.g. when rl removes consecutive dups
457 457 hlen = self.readline.get_current_history_length()
458 458 if hlen == hlen_before_cell:
459 459 return hlen_before_cell
460 460
461 461 for i in range(hlen - hlen_before_cell):
462 462 self.readline.remove_history_item(hlen - i - 1)
463 463 stdin_encoding = get_stream_enc(sys.stdin, 'utf-8')
464 464 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
465 465 stdin_encoding))
466 466 return self.readline.get_current_history_length()
467 467
468 468 def interact(self, display_banner=None):
469 469 """Closely emulate the interactive Python console."""
470 470
471 471 # batch run -> do not interact
472 472 if self.exit_now:
473 473 return
474 474
475 475 if display_banner is None:
476 476 display_banner = self.display_banner
477 477
478 478 if isinstance(display_banner, py3compat.string_types):
479 479 self.show_banner(display_banner)
480 480 elif display_banner:
481 481 self.show_banner()
482 482
483 483 more = False
484 484
485 485 if self.has_readline:
486 486 self.readline_startup_hook(self.pre_readline)
487 487 hlen_b4_cell = self.readline.get_current_history_length()
488 488 else:
489 489 hlen_b4_cell = 0
490 490 # exit_now is set by a call to %Exit or %Quit, through the
491 491 # ask_exit callback.
492 492
493 493 while not self.exit_now:
494 494 self.hooks.pre_prompt_hook()
495 495 if more:
496 496 try:
497 497 prompt = self.prompt_manager.render('in2')
498 498 except:
499 499 self.showtraceback()
500 500 if self.autoindent:
501 501 self.rl_do_indent = True
502 502
503 503 else:
504 504 try:
505 505 prompt = self.separate_in + self.prompt_manager.render('in')
506 506 except:
507 507 self.showtraceback()
508 508 try:
509 509 line = self.raw_input(prompt)
510 510 if self.exit_now:
511 511 # quick exit on sys.std[in|out] close
512 512 break
513 513 if self.autoindent:
514 514 self.rl_do_indent = False
515 515
516 516 except KeyboardInterrupt:
517 517 #double-guard against keyboardinterrupts during kbdint handling
518 518 try:
519 519 self.write('\nKeyboardInterrupt\n')
520 520 source_raw = self.input_splitter.source_raw_reset()[1]
521 521 hlen_b4_cell = \
522 522 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
523 523 more = False
524 524 except KeyboardInterrupt:
525 525 pass
526 526 except EOFError:
527 527 if self.autoindent:
528 528 self.rl_do_indent = False
529 529 if self.has_readline:
530 530 self.readline_startup_hook(None)
531 531 self.write('\n')
532 532 self.exit()
533 533 except bdb.BdbQuit:
534 534 warn('The Python debugger has exited with a BdbQuit exception.\n'
535 535 'Because of how pdb handles the stack, it is impossible\n'
536 536 'for IPython to properly format this particular exception.\n'
537 537 'IPython will resume normal operation.')
538 538 except:
539 539 # exceptions here are VERY RARE, but they can be triggered
540 540 # asynchronously by signal handlers, for example.
541 541 self.showtraceback()
542 542 else:
543 543 self.input_splitter.push(line)
544 544 more = self.input_splitter.push_accepts_more()
545 545 if (self.SyntaxTB.last_syntax_error and
546 546 self.autoedit_syntax):
547 547 self.edit_syntax_error()
548 548 if not more:
549 549 source_raw = self.input_splitter.source_raw_reset()[1]
550 550 self.run_cell(source_raw, store_history=True)
551 551 hlen_b4_cell = \
552 552 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
553 553
554 554 # Turn off the exit flag, so the mainloop can be restarted if desired
555 555 self.exit_now = False
556 556
557 557 def raw_input(self, prompt=''):
558 558 """Write a prompt and read a line.
559 559
560 560 The returned line does not include the trailing newline.
561 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
567 - continue_prompt(False): whether this line is the first one or a
568 continuation in a sequence of inputs.
566 prompt : str, optional
567 A string to be printed to prompt the user.
569 568 """
570 569 # Code run by the user may have modified the readline completer state.
571 570 # We must ensure that our completer is back in place.
572 571
573 572 if self.has_readline:
574 573 self.set_readline_completer()
575 574
576 575 # raw_input expects str, but we pass it unicode sometimes
577 576 prompt = py3compat.cast_bytes_py2(prompt)
578 577
579 578 try:
580 579 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
581 580 except ValueError:
582 581 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
583 582 " or sys.stdout.close()!\nExiting IPython!\n")
584 583 self.ask_exit()
585 584 return ""
586 585
587 586 # Try to be reasonably smart about not re-indenting pasted input more
588 587 # than necessary. We do this by trimming out the auto-indent initial
589 588 # spaces, if the user's actual input started itself with whitespace.
590 589 if self.autoindent:
591 590 if num_ini_spaces(line) > self.indent_current_nsp:
592 591 line = line[self.indent_current_nsp:]
593 592 self.indent_current_nsp = 0
594 593
595 594 return line
596 595
597 596 #-------------------------------------------------------------------------
598 597 # Methods to support auto-editing of SyntaxErrors.
599 598 #-------------------------------------------------------------------------
600 599
601 600 def edit_syntax_error(self):
602 601 """The bottom half of the syntax error handler called in the main loop.
603 602
604 603 Loop until syntax error is fixed or user cancels.
605 604 """
606 605
607 606 while self.SyntaxTB.last_syntax_error:
608 607 # copy and clear last_syntax_error
609 608 err = self.SyntaxTB.clear_err_state()
610 609 if not self._should_recompile(err):
611 610 return
612 611 try:
613 612 # may set last_syntax_error again if a SyntaxError is raised
614 613 self.safe_execfile(err.filename,self.user_ns)
615 614 except:
616 615 self.showtraceback()
617 616 else:
618 617 try:
619 618 f = open(err.filename)
620 619 try:
621 620 # This should be inside a display_trap block and I
622 621 # think it is.
623 622 sys.displayhook(f.read())
624 623 finally:
625 624 f.close()
626 625 except:
627 626 self.showtraceback()
628 627
629 628 def _should_recompile(self,e):
630 629 """Utility routine for edit_syntax_error"""
631 630
632 631 if e.filename in ('<ipython console>','<input>','<string>',
633 632 '<console>','<BackgroundJob compilation>',
634 633 None):
635 634
636 635 return False
637 636 try:
638 637 if (self.autoedit_syntax and
639 638 not self.ask_yes_no('Return to editor to correct syntax error? '
640 639 '[Y/n] ','y')):
641 640 return False
642 641 except EOFError:
643 642 return False
644 643
645 644 def int0(x):
646 645 try:
647 646 return int(x)
648 647 except TypeError:
649 648 return 0
650 649 # always pass integer line and offset values to editor hook
651 650 try:
652 651 self.hooks.fix_error_editor(e.filename,
653 652 int0(e.lineno),int0(e.offset),e.msg)
654 653 except TryNext:
655 654 warn('Could not open editor')
656 655 return False
657 656 return True
658 657
659 658 #-------------------------------------------------------------------------
660 659 # Things related to exiting
661 660 #-------------------------------------------------------------------------
662 661
663 662 def ask_exit(self):
664 663 """ Ask the shell to exit. Can be overiden and used as a callback. """
665 664 self.exit_now = True
666 665
667 666 def exit(self):
668 667 """Handle interactive exit.
669 668
670 669 This method calls the ask_exit callback."""
671 670 if self.confirm_exit:
672 671 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
673 672 self.ask_exit()
674 673 else:
675 674 self.ask_exit()
676 675
677 676 #-------------------------------------------------------------------------
678 677 # Things related to magics
679 678 #-------------------------------------------------------------------------
680 679
681 680 def init_magics(self):
682 681 super(TerminalInteractiveShell, self).init_magics()
683 682 self.register_magics(TerminalMagics)
684 683
685 684 def showindentationerror(self):
686 685 super(TerminalInteractiveShell, self).showindentationerror()
687 686 if not self.using_paste_magics:
688 687 print("If you want to paste code into IPython, try the "
689 688 "%paste and %cpaste magic functions.")
690 689
691 690
692 691 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -1,382 +1,383 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Decorators for labeling test objects.
3 3
4 4 Decorators that merely return a modified version of the original function
5 5 object are straightforward. Decorators that return a new function object need
6 6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 7 decorator, in order to preserve metadata such as function name, setup and
8 8 teardown functions and so on - see nose.tools for more information.
9 9
10 10 This module provides a set of useful decorators meant to be ready to use in
11 11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 12 find yourself writing a new one that may be of generic use, add it here.
13 13
14 14 Included decorators:
15 15
16 16
17 17 Lightweight testing that remains unittest-compatible.
18 18
19 19 - An @as_unittest decorator can be used to tag any normal parameter-less
20 20 function as a unittest TestCase. Then, both nose and normal unittest will
21 21 recognize it as such. This will make it easier to migrate away from Nose if
22 22 we ever need/want to while maintaining very lightweight tests.
23 23
24 24 NOTE: This file contains IPython-specific decorators. Using the machinery in
25 25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
26 26 available, OR use equivalent code in IPython.external._decorators, which
27 27 we've copied verbatim from numpy.
28 28
29 29 Authors
30 30 -------
31 31
32 32 - Fernando Perez <Fernando.Perez@berkeley.edu>
33 33 """
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Copyright (C) 2009-2011 The IPython Development Team
37 37 #
38 38 # Distributed under the terms of the BSD License. The full license is in
39 39 # the file COPYING, distributed as part of this software.
40 40 #-----------------------------------------------------------------------------
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Imports
44 44 #-----------------------------------------------------------------------------
45 45
46 46 # Stdlib imports
47 47 import sys
48 48 import os
49 49 import tempfile
50 50 import unittest
51 51
52 52 # Third-party imports
53 53
54 54 # This is Michele Simionato's decorator module, kept verbatim.
55 55 from IPython.external.decorator import decorator
56 56
57 57 # Expose the unittest-driven decorators
58 58 from .ipunittest import ipdoctest, ipdocstring
59 59
60 60 # Grab the numpy-specific decorators which we keep in a file that we
61 61 # occasionally update from upstream: decorators.py is a copy of
62 62 # numpy.testing.decorators, we expose all of it here.
63 63 from IPython.external.decorators import *
64 64
65 65 # For onlyif_cmd_exists decorator
66 66 from IPython.utils.process import is_cmd_found
67 67 from IPython.utils.py3compat import string_types
68 68
69 69 #-----------------------------------------------------------------------------
70 70 # Classes and functions
71 71 #-----------------------------------------------------------------------------
72 72
73 73 # Simple example of the basic idea
74 74 def as_unittest(func):
75 75 """Decorator to make a simple function into a normal test via unittest."""
76 76 class Tester(unittest.TestCase):
77 77 def test(self):
78 78 func()
79 79
80 80 Tester.__name__ = func.__name__
81 81
82 82 return Tester
83 83
84 84 # Utility functions
85 85
86 86 def apply_wrapper(wrapper,func):
87 87 """Apply a wrapper to a function for decoration.
88 88
89 89 This mixes Michele Simionato's decorator tool with nose's make_decorator,
90 90 to apply a wrapper in a decorator so that all nose attributes, as well as
91 91 function signature and other properties, survive the decoration cleanly.
92 92 This will ensure that wrapped functions can still be well introspected via
93 93 IPython, for example.
94 94 """
95 95 import nose.tools
96 96
97 97 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
98 98
99 99
100 100 def make_label_dec(label,ds=None):
101 101 """Factory function to create a decorator that applies one or more labels.
102 102
103 103 Parameters
104 104 ----------
105 105 label : string or sequence
106 106 One or more labels that will be applied by the decorator to the functions
107 107 it decorates. Labels are attributes of the decorated function with their
108 108 value set to True.
109 109
110 110 ds : string
111 111 An optional docstring for the resulting decorator. If not given, a
112 112 default docstring is auto-generated.
113 113
114 114 Returns
115 115 -------
116 116 A decorator.
117 117
118 118 Examples
119 119 --------
120 120
121 121 A simple labeling decorator:
122 122
123 123 >>> slow = make_label_dec('slow')
124 124 >>> slow.__doc__
125 125 "Labels a test as 'slow'."
126 126
127 127 And one that uses multiple labels and a custom docstring:
128 128
129 129 >>> rare = make_label_dec(['slow','hard'],
130 130 ... "Mix labels 'slow' and 'hard' for rare tests.")
131 131 >>> rare.__doc__
132 132 "Mix labels 'slow' and 'hard' for rare tests."
133 133
134 134 Now, let's test using this one:
135 135 >>> @rare
136 136 ... def f(): pass
137 137 ...
138 138 >>>
139 139 >>> f.slow
140 140 True
141 141 >>> f.hard
142 142 True
143 143 """
144 144
145 145 if isinstance(label, string_types):
146 146 labels = [label]
147 147 else:
148 148 labels = label
149 149
150 150 # Validate that the given label(s) are OK for use in setattr() by doing a
151 151 # dry run on a dummy function.
152 152 tmp = lambda : None
153 153 for label in labels:
154 154 setattr(tmp,label,True)
155 155
156 156 # This is the actual decorator we'll return
157 157 def decor(f):
158 158 for label in labels:
159 159 setattr(f,label,True)
160 160 return f
161 161
162 162 # Apply the user's docstring, or autogenerate a basic one
163 163 if ds is None:
164 164 ds = "Labels a test as %r." % label
165 165 decor.__doc__ = ds
166 166
167 167 return decor
168 168
169 169
170 170 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
171 171 # preserve function metadata better and allows the skip condition to be a
172 172 # callable.
173 173 def skipif(skip_condition, msg=None):
174 174 ''' Make function raise SkipTest exception if skip_condition is true
175 175
176 176 Parameters
177 177 ----------
178 skip_condition : bool or callable.
179 Flag to determine whether to skip test. If the condition is a
180 callable, it is used at runtime to dynamically make the decision. This
181 is useful for tests that may require costly imports, to delay the cost
182 until the test suite is actually executed.
178
179 skip_condition : bool or callable
180 Flag to determine whether to skip test. If the condition is a
181 callable, it is used at runtime to dynamically make the decision. This
182 is useful for tests that may require costly imports, to delay the cost
183 until the test suite is actually executed.
183 184 msg : string
184 Message to give on raising a SkipTest exception
185
186 Returns
187 -------
188 decorator : function
189 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 called normally otherwise.
185 Message to give on raising a SkipTest exception.
186
187 Returns
188 -------
189 decorator : function
190 Decorator, which, when applied to a function, causes SkipTest
191 to be raised when the skip_condition was True, and the function
192 to be called normally otherwise.
192 193
193 194 Notes
194 195 -----
195 196 You will see from the code that we had to further decorate the
196 197 decorator with the nose.tools.make_decorator function in order to
197 198 transmit function name, and various other metadata.
198 199 '''
199 200
200 201 def skip_decorator(f):
201 202 # Local import to avoid a hard nose dependency and only incur the
202 203 # import time overhead at actual test-time.
203 204 import nose
204 205
205 206 # Allow for both boolean or callable skip conditions.
206 207 if callable(skip_condition):
207 208 skip_val = skip_condition
208 209 else:
209 210 skip_val = lambda : skip_condition
210 211
211 212 def get_msg(func,msg=None):
212 213 """Skip message with information about function being skipped."""
213 214 if msg is None: out = 'Test skipped due to test condition.'
214 215 else: out = msg
215 216 return "Skipping test: %s. %s" % (func.__name__,out)
216 217
217 218 # We need to define *two* skippers because Python doesn't allow both
218 219 # return with value and yield inside the same function.
219 220 def skipper_func(*args, **kwargs):
220 221 """Skipper for normal test functions."""
221 222 if skip_val():
222 223 raise nose.SkipTest(get_msg(f,msg))
223 224 else:
224 225 return f(*args, **kwargs)
225 226
226 227 def skipper_gen(*args, **kwargs):
227 228 """Skipper for test generators."""
228 229 if skip_val():
229 230 raise nose.SkipTest(get_msg(f,msg))
230 231 else:
231 232 for x in f(*args, **kwargs):
232 233 yield x
233 234
234 235 # Choose the right skipper to use when building the actual generator.
235 236 if nose.util.isgenerator(f):
236 237 skipper = skipper_gen
237 238 else:
238 239 skipper = skipper_func
239 240
240 241 return nose.tools.make_decorator(f)(skipper)
241 242
242 243 return skip_decorator
243 244
244 245 # A version with the condition set to true, common case just to attach a message
245 246 # to a skip decorator
246 247 def skip(msg=None):
247 248 """Decorator factory - mark a test function for skipping from test suite.
248 249
249 250 Parameters
250 251 ----------
251 252 msg : string
252 253 Optional message to be added.
253 254
254 255 Returns
255 256 -------
256 257 decorator : function
257 258 Decorator, which, when applied to a function, causes SkipTest
258 259 to be raised, with the optional message added.
259 260 """
260 261
261 262 return skipif(True,msg)
262 263
263 264
264 265 def onlyif(condition, msg):
265 266 """The reverse from skipif, see skipif for details."""
266 267
267 268 if callable(condition):
268 269 skip_condition = lambda : not condition()
269 270 else:
270 271 skip_condition = lambda : not condition
271 272
272 273 return skipif(skip_condition, msg)
273 274
274 275 #-----------------------------------------------------------------------------
275 276 # Utility functions for decorators
276 277 def module_not_available(module):
277 278 """Can module be imported? Returns true if module does NOT import.
278 279
279 280 This is used to make a decorator to skip tests that require module to be
280 281 available, but delay the 'import numpy' to test execution time.
281 282 """
282 283 try:
283 284 mod = __import__(module)
284 285 mod_not_avail = False
285 286 except ImportError:
286 287 mod_not_avail = True
287 288
288 289 return mod_not_avail
289 290
290 291
291 292 def decorated_dummy(dec, name):
292 293 """Return a dummy function decorated with dec, with the given name.
293 294
294 295 Examples
295 296 --------
296 297 import IPython.testing.decorators as dec
297 298 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
298 299 """
299 300 dummy = lambda: None
300 301 dummy.__name__ = name
301 302 return dec(dummy)
302 303
303 304 #-----------------------------------------------------------------------------
304 305 # Decorators for public use
305 306
306 307 # Decorators to skip certain tests on specific platforms.
307 308 skip_win32 = skipif(sys.platform == 'win32',
308 309 "This test does not run under Windows")
309 310 skip_linux = skipif(sys.platform.startswith('linux'),
310 311 "This test does not run under Linux")
311 312 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
312 313
313 314
314 315 # Decorators to skip tests if not on specific platforms.
315 316 skip_if_not_win32 = skipif(sys.platform != 'win32',
316 317 "This test only runs under Windows")
317 318 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
318 319 "This test only runs under Linux")
319 320 skip_if_not_osx = skipif(sys.platform != 'darwin',
320 321 "This test only runs under OSX")
321 322
322 323
323 324 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
324 325 os.environ.get('DISPLAY', '') == '')
325 326 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
326 327
327 328 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
328 329
329 330 # not a decorator itself, returns a dummy function to be used as setup
330 331 def skip_file_no_x11(name):
331 332 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
332 333
333 334 # Other skip decorators
334 335
335 336 # generic skip without module
336 337 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
337 338
338 339 skipif_not_numpy = skip_without('numpy')
339 340
340 341 skipif_not_matplotlib = skip_without('matplotlib')
341 342
342 343 skipif_not_sympy = skip_without('sympy')
343 344
344 345 skip_known_failure = knownfailureif(True,'This test is known to fail')
345 346
346 347 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
347 348 'This test is known to fail on Python 3.')
348 349
349 350 # A null 'decorator', useful to make more readable code that needs to pick
350 351 # between different decorators based on OS or other conditions
351 352 null_deco = lambda f: f
352 353
353 354 # Some tests only run where we can use unicode paths. Note that we can't just
354 355 # check os.path.supports_unicode_filenames, which is always False on Linux.
355 356 try:
356 357 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
357 358 except UnicodeEncodeError:
358 359 unicode_paths = False
359 360 else:
360 361 unicode_paths = True
361 362 f.close()
362 363
363 364 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
364 365 "where we can use unicode in filenames."))
365 366
366 367
367 368 def onlyif_cmds_exist(*commands):
368 369 """
369 370 Decorator to skip test when at least one of `commands` is not found.
370 371 """
371 372 for cmd in commands:
372 373 try:
373 374 if not is_cmd_found(cmd):
374 375 return skip("This test runs only if command '{0}' "
375 376 "is installed".format(cmd))
376 377 except ImportError as e:
377 378 # is_cmd_found uses pywin32 on windows, which might not be available
378 379 if sys.platform == 'win32' and 'pywin32' in str(e):
379 380 return skip("This test runs only if pywin32 and command '{0}' "
380 381 "is installed".format(cmd))
381 382 raise e
382 383 return null_deco
@@ -1,621 +1,621 b''
1 1 .. _issues_list_012:
2 2
3 3 Issues closed in the 0.12 development cycle
4 4 ===========================================
5 5
6 6 Issues closed in 0.12.1
7 7 -----------------------
8 8
9 9 GitHub stats for bugfix release 0.12.1 (12/28/2011-04/16/2012), backporting
10 10 pull requests from 0.13.
11 11
12 12 We closed a total of 71 issues: 44 pull requests and 27 issues; this is the
13 13 full list (generated with the script `tools/github_stats.py`).
14 14
15 15 This list is automatically generated, and may be incomplete:
16 16
17 17 Pull Requests (44):
18 18
19 19 * :ghpull:`1175`: core.completer: Clean up excessive and unused code.
20 20 * :ghpull:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush
21 21 * :ghpull:`1190`: Fix link to Chris Fonnesbeck blog post about 0.11 highlights.
22 22 * :ghpull:`1196`: docs: looks like a file path might have been accidentally pasted in the middle of a word
23 23 * :ghpull:`1206`: don't preserve fixConsole output in json
24 24 * :ghpull:`1207`: fix loadpy duplicating newlines
25 25 * :ghpull:`1213`: BUG: Minor typo in history_console_widget.py
26 26 * :ghpull:`1218`: Added -q option to %prun for suppression of the output, along with editing the dochelp string.
27 27 * :ghpull:`1222`: allow Reference as callable in map/apply
28 28 * :ghpull:`1229`: Fix display of SyntaxError in Python 3
29 29 * :ghpull:`1246`: Skip tests that require X, when importing pylab results in RuntimeError.
30 30 * :ghpull:`1253`: set auto_create flag for notebook apps
31 31 * :ghpull:`1257`: use self.kernel_manager_class in qtconsoleapp
32 32 * :ghpull:`1262`: Heartbeat no longer shares the app's Context
33 33 * :ghpull:`1283`: HeartMonitor.period should be an Integer
34 34 * :ghpull:`1284`: a fix for GH 1269
35 35 * :ghpull:`1289`: Make autoreload extension work on Python 3.
36 36 * :ghpull:`1306`: Fix %prun input parsing for escaped characters (closes #1302)
37 37 * :ghpull:`1312`: minor heartbeat tweaks
38 38 * :ghpull:`1318`: make Ctrl-D in qtconsole act same as in terminal (ready to merge)
39 39 * :ghpull:`1341`: Don't attempt to tokenize binary files for tracebacks
40 40 * :ghpull:`1353`: Save notebook as script using unicode file handle.
41 41 * :ghpull:`1363`: Fix some minor color/style config issues in the qtconsole
42 42 * :ghpull:`1364`: avoid jsonlib returning Decimal
43 43 * :ghpull:`1369`: load header with engine id when engine dies in TaskScheduler
44 44 * :ghpull:`1370`: allow draft76 websockets (Safari)
45 45 * :ghpull:`1374`: remove calls to meaningless ZMQStream.on_err
46 46 * :ghpull:`1377`: Saving non-ascii history
47 47 * :ghpull:`1396`: Fix for %tb magic.
48 48 * :ghpull:`1402`: fix symlinked /home issue for FreeBSD
49 49 * :ghpull:`1413`: get_home_dir expands symlinks, adjust test accordingly
50 50 * :ghpull:`1414`: ignore errors in shell.var_expand
51 51 * :ghpull:`1430`: Fix for tornado check for tornado < 1.1.0
52 52 * :ghpull:`1445`: Don't build sphinx docs for sdists
53 53 * :ghpull:`1463`: Fix completion when importing modules in the cwd.
54 54 * :ghpull:`1477`: fix dangling `buffer` in IPython.parallel.util
55 55 * :ghpull:`1495`: BUG: Fix pretty-printing for overzealous objects
56 56 * :ghpull:`1496`: BUG: LBYL when clearing the output history on shutdown.
57 57 * :ghpull:`1514`: DOC: Fix references to IPython.lib.pretty instead of the old location
58 58 * :ghpull:`1517`: Fix indentation bug in IPython/lib/pretty.py
59 59 * :ghpull:`1538`: store git commit hash in utils._sysinfo instead of hidden data file
60 60 * :ghpull:`1599`: Fix for %run -d in Python 3
61 61 * :ghpull:`1602`: Fix %env for Python 3
62 62 * :ghpull:`1607`: cleanup sqlitedb temporary db file after tests
63 63
64 64 Issues (27):
65 65
66 66 * :ghissue:`676`: IPython.embed() from ipython crashes twice on exit
67 67 * :ghissue:`846`: Autoreload extension doesn't work with Python 3.2
68 68 * :ghissue:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush
69 69 * :ghissue:`1191`: profile/startup files not executed with "notebook"
70 70 * :ghissue:`1197`: Interactive shell trying to: from ... import history
71 71 * :ghissue:`1198`: Kernel Has Died error in Notebook
72 72 * :ghissue:`1201`: %env magic fails with Python 3.2
73 73 * :ghissue:`1204`: double newline from %loadpy in python notebook (at least on mac)
74 74 * :ghissue:`1208`: should dv.sync_import print failed imports ?
75 75 * :ghissue:`1225`: SyntaxError display broken in Python 3
76 76 * :ghissue:`1232`: Dead kernel loop
77 77 * :ghissue:`1241`: When our debugger class is used standalone `_oh` key errors are thrown
78 78 * :ghissue:`1254`: typo in notebooklist.js breaks links
79 79 * :ghissue:`1260`: heartbeat failure on long gil-holding operation
80 80 * :ghissue:`1268`: notebook %reset magic fails with StdinNotImplementedError
81 81 * :ghissue:`1269`: Another strange input handling error
82 82 * :ghissue:`1281`: in Hub: registration_timeout must be an integer, but heartmonitor.period is CFloat
83 83 * :ghissue:`1302`: Input parsing with %prun clobbers escapes
84 84 * :ghissue:`1304`: controller/server load can disrupt heartbeat
85 85 * :ghissue:`1317`: Very slow traceback construction from Cython extension
86 86 * :ghissue:`1345`: notebook can't save unicode as script
87 87 * :ghissue:`1375`: %history -g -f file encoding issue
88 88 * :ghissue:`1401`: numpy arrays cannot be used with View.apply() in Python 3
89 89 * :ghissue:`1408`: test_get_home_dir_3 failed on Mac OS X
90 90 * :ghissue:`1412`: Input parsing issue with %prun
91 91 * :ghissue:`1421`: ipython32 %run -d breaks with NameError name 'execfile' is not defined
92 92 * :ghissue:`1484`: unhide .git_commit_info.ini
93 93
94 94
95 95 Issues closed in 0.12
96 96 ---------------------
97 97
98 98 In this cycle, from August 1 to December 28 2011, we closed a total of 515
99 99 issues, 257 pull requests and 258 regular issues; this is the full list
100 100 (generated with the script `tools/github_stats.py`).
101 101
102 102 Pull requests (257):
103 103
104 104 * `1174 <https://github.com/ipython/ipython/issues/1174>`_: Remove %install_default_config and %install_profiles
105 105 * `1178 <https://github.com/ipython/ipython/issues/1178>`_: Correct string type casting in pinfo.
106 106 * `1096 <https://github.com/ipython/ipython/issues/1096>`_: Show class init and call tooltips in notebook
107 107 * `1176 <https://github.com/ipython/ipython/issues/1176>`_: Modifications to profile list
108 108 * `1173 <https://github.com/ipython/ipython/issues/1173>`_: don't load gui/pylab in console frontend
109 109 * `1168 <https://github.com/ipython/ipython/issues/1168>`_: Add --script flag as shorthand for notebook save_script option.
110 110 * `1165 <https://github.com/ipython/ipython/issues/1165>`_: encode image_tag as utf8 in [x]html export
111 111 * `1161 <https://github.com/ipython/ipython/issues/1161>`_: Allow %loadpy to load remote URLs that don't end in .py
112 112 * `1158 <https://github.com/ipython/ipython/issues/1158>`_: Add coding header when notebook exported to .py file.
113 113 * `1160 <https://github.com/ipython/ipython/issues/1160>`_: don't ignore ctrl-C during `%gui qt`
114 114 * `1159 <https://github.com/ipython/ipython/issues/1159>`_: Add encoding header to Python files downloaded from notebooks.
115 115 * `1155 <https://github.com/ipython/ipython/issues/1155>`_: minor post-execute fixes (#1154)
116 116 * `1153 <https://github.com/ipython/ipython/issues/1153>`_: Pager tearing bug
117 117 * `1152 <https://github.com/ipython/ipython/issues/1152>`_: Add support for displaying maptlotlib axes directly.
118 118 * `1079 <https://github.com/ipython/ipython/issues/1079>`_: Login/out button cleanups
119 119 * `1151 <https://github.com/ipython/ipython/issues/1151>`_: allow access to user_ns in prompt_manager
120 120 * `1120 <https://github.com/ipython/ipython/issues/1120>`_: updated vim-ipython (pending)
121 121 * `1150 <https://github.com/ipython/ipython/issues/1150>`_: BUG: Scrolling pager in vsplit on Mac OSX tears.
122 122 * `1149 <https://github.com/ipython/ipython/issues/1149>`_: #1148 (win32 arg_split)
123 123 * `1147 <https://github.com/ipython/ipython/issues/1147>`_: Put qtconsole forground when launching
124 124 * `1146 <https://github.com/ipython/ipython/issues/1146>`_: allow saving notebook.py next to notebook.ipynb
125 125 * `1128 <https://github.com/ipython/ipython/issues/1128>`_: fix pylab StartMenu item
126 126 * `1140 <https://github.com/ipython/ipython/issues/1140>`_: Namespaces for embedding
127 127 * `1132 <https://github.com/ipython/ipython/issues/1132>`_: [notebook] read-only: disable name field
128 128 * `1125 <https://github.com/ipython/ipython/issues/1125>`_: notebook : update logo
129 129 * `1135 <https://github.com/ipython/ipython/issues/1135>`_: allow customized template and static file paths for the notebook web app
130 130 * `1122 <https://github.com/ipython/ipython/issues/1122>`_: BUG: Issue #755 qt IPythonWidget.execute_file fails if filename contains...
131 131 * `1137 <https://github.com/ipython/ipython/issues/1137>`_: rename MPIExecLaunchers to MPILaunchers
132 132 * `1130 <https://github.com/ipython/ipython/issues/1130>`_: optionally ignore shlex's ValueError in arg_split
133 133 * `1116 <https://github.com/ipython/ipython/issues/1116>`_: Shlex unicode
134 134 * `1073 <https://github.com/ipython/ipython/issues/1073>`_: Storemagic plugin
135 135 * `1143 <https://github.com/ipython/ipython/issues/1143>`_: Add post_install script to create start menu entries in Python 3
136 136 * `1138 <https://github.com/ipython/ipython/issues/1138>`_: Fix tests to work when ~/.config/ipython contains a symlink.
137 137 * `1121 <https://github.com/ipython/ipython/issues/1121>`_: Don't transform function calls on IPyAutocall objects
138 138 * `1118 <https://github.com/ipython/ipython/issues/1118>`_: protect CRLF from carriage-return action
139 139 * `1105 <https://github.com/ipython/ipython/issues/1105>`_: Fix for prompts containing newlines.
140 140 * `1126 <https://github.com/ipython/ipython/issues/1126>`_: Totally remove pager when read only (notebook)
141 141 * `1091 <https://github.com/ipython/ipython/issues/1091>`_: qtconsole : allow copy with shortcut in pager
142 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 144 * `1089 <https://github.com/ipython/ipython/issues/1089>`_: Support carriage return ('\r') and beep ('\b') characters in the qtconsole
145 145 * `1108 <https://github.com/ipython/ipython/issues/1108>`_: Completer usability 2 (rebased of pr #1082)
146 146 * `864 <https://github.com/ipython/ipython/issues/864>`_: Two-process terminal frontend (ipython core branch)
147 147 * `1082 <https://github.com/ipython/ipython/issues/1082>`_: usability and cross browser compat for completer
148 148 * `1053 <https://github.com/ipython/ipython/issues/1053>`_: minor improvements to text placement in qtconsole
149 149 * `1106 <https://github.com/ipython/ipython/issues/1106>`_: Fix display of errors in compiled code on Python 3
150 150 * `1077 <https://github.com/ipython/ipython/issues/1077>`_: allow the notebook to run without MathJax
151 151 * `1072 <https://github.com/ipython/ipython/issues/1072>`_: If object has a getdoc() method, override its normal docstring.
152 152 * `1059 <https://github.com/ipython/ipython/issues/1059>`_: Switch to simple `__IPYTHON__` global
153 153 * `1070 <https://github.com/ipython/ipython/issues/1070>`_: Execution count after SyntaxError
154 154 * `1098 <https://github.com/ipython/ipython/issues/1098>`_: notebook: config section UI
155 155 * `1101 <https://github.com/ipython/ipython/issues/1101>`_: workaround spawnb missing from pexpect.__all__
156 156 * `1097 <https://github.com/ipython/ipython/issues/1097>`_: typo, should fix #1095
157 157 * `1099 <https://github.com/ipython/ipython/issues/1099>`_: qtconsole export xhtml/utf8
158 158 * `1083 <https://github.com/ipython/ipython/issues/1083>`_: Prompts
159 159 * `1081 <https://github.com/ipython/ipython/issues/1081>`_: Fix wildcard search for updated namespaces
160 160 * `1084 <https://github.com/ipython/ipython/issues/1084>`_: write busy in notebook window title...
161 161 * `1078 <https://github.com/ipython/ipython/issues/1078>`_: PromptManager fixes
162 162 * `1064 <https://github.com/ipython/ipython/issues/1064>`_: Win32 shlex
163 163 * `1069 <https://github.com/ipython/ipython/issues/1069>`_: As you type completer, fix on Firefox
164 164 * `1039 <https://github.com/ipython/ipython/issues/1039>`_: Base of an as you type completer.
165 165 * `1065 <https://github.com/ipython/ipython/issues/1065>`_: Qtconsole fix racecondition
166 166 * `507 <https://github.com/ipython/ipython/issues/507>`_: Prompt manager
167 167 * `1056 <https://github.com/ipython/ipython/issues/1056>`_: Warning in code. qtconsole ssh -X
168 168 * `1036 <https://github.com/ipython/ipython/issues/1036>`_: Clean up javascript based on js2-mode feedback.
169 169 * `1052 <https://github.com/ipython/ipython/issues/1052>`_: Pylab fix
170 170 * `648 <https://github.com/ipython/ipython/issues/648>`_: Usermod
171 171 * `969 <https://github.com/ipython/ipython/issues/969>`_: Pexpect-u
172 172 * `1007 <https://github.com/ipython/ipython/issues/1007>`_: Fix paste/cpaste bug and refactor/cleanup that code a lot.
173 173 * `506 <https://github.com/ipython/ipython/issues/506>`_: make ENTER on a previous input field replace current input buffer
174 174 * `1040 <https://github.com/ipython/ipython/issues/1040>`_: json/jsonapi cleanup
175 175 * `1042 <https://github.com/ipython/ipython/issues/1042>`_: fix firefox (windows) break line on empty prompt number
176 176 * `1015 <https://github.com/ipython/ipython/issues/1015>`_: emacs freezes when tab is hit in ipython with latest python-mode
177 177 * `1023 <https://github.com/ipython/ipython/issues/1023>`_: flush stdout/stderr at the end of kernel init
178 178 * `956 <https://github.com/ipython/ipython/issues/956>`_: Generate "All magics..." menu live
179 179 * `1038 <https://github.com/ipython/ipython/issues/1038>`_: Notebook: don't change cell when selecting code using shift+up/down.
180 180 * `987 <https://github.com/ipython/ipython/issues/987>`_: Add Tooltip to notebook.
181 181 * `1028 <https://github.com/ipython/ipython/issues/1028>`_: Cleaner minimum version comparison
182 182 * `998 <https://github.com/ipython/ipython/issues/998>`_: defer to stdlib for path.get_home_dir()
183 183 * `1033 <https://github.com/ipython/ipython/issues/1033>`_: update copyright to 2011/20xx-2011
184 184 * `1032 <https://github.com/ipython/ipython/issues/1032>`_: Intercept <esc> avoid closing websocket on Firefox
185 185 * `1030 <https://github.com/ipython/ipython/issues/1030>`_: use pyzmq tools where appropriate
186 186 * `1029 <https://github.com/ipython/ipython/issues/1029>`_: Restore pspersistence, including %store magic, as an extension.
187 187 * `1025 <https://github.com/ipython/ipython/issues/1025>`_: Dollar escape
188 188 * `999 <https://github.com/ipython/ipython/issues/999>`_: Fix issue #880 - more useful message to user when %paste fails
189 189 * `938 <https://github.com/ipython/ipython/issues/938>`_: changes to get ipython.el to work with the latest python-mode.el
190 190 * `1012 <https://github.com/ipython/ipython/issues/1012>`_: Add logout button.
191 191 * `1020 <https://github.com/ipython/ipython/issues/1020>`_: Dollar formatter for ! shell calls
192 192 * `1019 <https://github.com/ipython/ipython/issues/1019>`_: Use repr() to make quoted strings
193 193 * `1008 <https://github.com/ipython/ipython/issues/1008>`_: don't use crash_handler by default
194 194 * `1003 <https://github.com/ipython/ipython/issues/1003>`_: Drop consecutive duplicates when refilling readline history
195 195 * `997 <https://github.com/ipython/ipython/issues/997>`_: don't unregister interrupted post-exec functions
196 196 * `996 <https://github.com/ipython/ipython/issues/996>`_: add Integer traitlet
197 197 * `1016 <https://github.com/ipython/ipython/issues/1016>`_: Fix password hashing for Python 3
198 198 * `1014 <https://github.com/ipython/ipython/issues/1014>`_: escape minus signs in manpages
199 199 * `1013 <https://github.com/ipython/ipython/issues/1013>`_: [NumPyExampleDocstring] link was pointing to raw file
200 200 * `1011 <https://github.com/ipython/ipython/issues/1011>`_: Add hashed password support.
201 201 * `1005 <https://github.com/ipython/ipython/issues/1005>`_: Quick fix for os.system requiring str parameter
202 202 * `994 <https://github.com/ipython/ipython/issues/994>`_: Allow latex formulas in HTML output
203 203 * `955 <https://github.com/ipython/ipython/issues/955>`_: Websocket Adjustments
204 204 * `979 <https://github.com/ipython/ipython/issues/979>`_: use system_raw in terminal, even on Windows
205 205 * `989 <https://github.com/ipython/ipython/issues/989>`_: fix arguments for commands in _process_posix
206 206 * `991 <https://github.com/ipython/ipython/issues/991>`_: Show traceback, continuing to start kernel if pylab init fails
207 207 * `981 <https://github.com/ipython/ipython/issues/981>`_: Split likely multiline text when writing JSON notebooks
208 208 * `957 <https://github.com/ipython/ipython/issues/957>`_: allow change of png DPI in inline backend
209 209 * `968 <https://github.com/ipython/ipython/issues/968>`_: add wantDirectory to ipdoctest, so that directories will be checked for e
210 210 * `984 <https://github.com/ipython/ipython/issues/984>`_: Do not expose variables defined at startup to %who etc.
211 211 * `985 <https://github.com/ipython/ipython/issues/985>`_: Fixes for parallel code on Python 3
212 212 * `963 <https://github.com/ipython/ipython/issues/963>`_: disable calltips in PySide < 1.0.7 to prevent segfault
213 213 * `976 <https://github.com/ipython/ipython/issues/976>`_: Getting started on what's new
214 214 * `929 <https://github.com/ipython/ipython/issues/929>`_: Multiline history
215 215 * `964 <https://github.com/ipython/ipython/issues/964>`_: Default profile
216 216 * `961 <https://github.com/ipython/ipython/issues/961>`_: Disable the pager for the test suite
217 217 * `953 <https://github.com/ipython/ipython/issues/953>`_: Physics extension
218 218 * `950 <https://github.com/ipython/ipython/issues/950>`_: Add directory for startup files
219 219 * `940 <https://github.com/ipython/ipython/issues/940>`_: allow setting HistoryManager.hist_file with config
220 220 * `948 <https://github.com/ipython/ipython/issues/948>`_: Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16.
221 221 * `916 <https://github.com/ipython/ipython/issues/916>`_: Run p ( https://github.com/ipython/ipython/pull/901 )
222 222 * `923 <https://github.com/ipython/ipython/issues/923>`_: %config magic
223 223 * `920 <https://github.com/ipython/ipython/issues/920>`_: unordered iteration of AsyncMapResults (+ a couple fixes)
224 224 * `941 <https://github.com/ipython/ipython/issues/941>`_: Follow-up to 387dcd6a, `_rl.__doc__` is `None` with pyreadline
225 225 * `931 <https://github.com/ipython/ipython/issues/931>`_: read-only notebook mode
226 226 * `921 <https://github.com/ipython/ipython/issues/921>`_: Show invalid config message on TraitErrors during init
227 227 * `815 <https://github.com/ipython/ipython/issues/815>`_: Fix #481 using custom qt4 input hook
228 228 * `936 <https://github.com/ipython/ipython/issues/936>`_: Start webbrowser in a thread. Prevents lockup with Chrome.
229 229 * `937 <https://github.com/ipython/ipython/issues/937>`_: add dirty trick for readline import on OSX
230 230 * `913 <https://github.com/ipython/ipython/issues/913>`_: Py3 tests2
231 231 * `933 <https://github.com/ipython/ipython/issues/933>`_: Cancel in qt console closeevent should trigger event.ignore()
232 232 * `930 <https://github.com/ipython/ipython/issues/930>`_: read-only notebook mode
233 233 * `910 <https://github.com/ipython/ipython/issues/910>`_: Make import checks more explicit in %whos
234 234 * `926 <https://github.com/ipython/ipython/issues/926>`_: reincarnate -V cmdline option
235 235 * `928 <https://github.com/ipython/ipython/issues/928>`_: BUG: Set context for font size change shortcuts in ConsoleWidget
236 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 237 * `912 <https://github.com/ipython/ipython/issues/912>`_: Add magic for cls on windows. Fix for #181.
238 238 * `905 <https://github.com/ipython/ipython/issues/905>`_: enable %gui/%pylab magics in the Kernel
239 239 * `909 <https://github.com/ipython/ipython/issues/909>`_: Allow IPython to run without sqlite3
240 240 * `887 <https://github.com/ipython/ipython/issues/887>`_: Qtconsole menu
241 241 * `895 <https://github.com/ipython/ipython/issues/895>`_: notebook download implies save
242 242 * `896 <https://github.com/ipython/ipython/issues/896>`_: Execfile
243 243 * `899 <https://github.com/ipython/ipython/issues/899>`_: Brian's Notebook work
244 244 * `892 <https://github.com/ipython/ipython/issues/892>`_: don't close figures every cycle with inline matplotlib backend
245 245 * `893 <https://github.com/ipython/ipython/issues/893>`_: Adding clear_output to kernel and HTML notebook
246 246 * `789 <https://github.com/ipython/ipython/issues/789>`_: Adding clear_output to kernel and HTML notebook.
247 247 * `898 <https://github.com/ipython/ipython/issues/898>`_: Don't pass unicode sys.argv with %run or `ipython script.py`
248 248 * `897 <https://github.com/ipython/ipython/issues/897>`_: Add tooltips to the notebook via 'title' attr.
249 249 * `877 <https://github.com/ipython/ipython/issues/877>`_: partial fix for issue #678
250 250 * `838 <https://github.com/ipython/ipython/issues/838>`_: reenable multiline history for terminals
251 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 252 * `884 <https://github.com/ipython/ipython/issues/884>`_: Notebook usability fixes
253 253 * `883 <https://github.com/ipython/ipython/issues/883>`_: User notification if notebook saving fails
254 254 * `889 <https://github.com/ipython/ipython/issues/889>`_: Add drop_by_id method to shell, to remove variables added by extensions.
255 255 * `891 <https://github.com/ipython/ipython/issues/891>`_: Ability to open the notebook in a browser when it starts
256 256 * `813 <https://github.com/ipython/ipython/issues/813>`_: Create menu bar for qtconsole
257 257 * `876 <https://github.com/ipython/ipython/issues/876>`_: protect IPython from bad custom exception handlers
258 258 * `856 <https://github.com/ipython/ipython/issues/856>`_: Backgroundjobs
259 259 * `868 <https://github.com/ipython/ipython/issues/868>`_: Warn user if MathJax can't be fetched from notebook closes #744
260 260 * `878 <https://github.com/ipython/ipython/issues/878>`_: store_history=False default for run_cell
261 261 * `824 <https://github.com/ipython/ipython/issues/824>`_: History access
262 262 * `850 <https://github.com/ipython/ipython/issues/850>`_: Update codemirror to 2.15 and make the code internally more version-agnostic
263 263 * `861 <https://github.com/ipython/ipython/issues/861>`_: Fix for issue #56
264 264 * `819 <https://github.com/ipython/ipython/issues/819>`_: Adding -m option to %run, similar to -m for python interpreter.
265 265 * `855 <https://github.com/ipython/ipython/issues/855>`_: promote aliases and flags, to ensure they have priority over config files
266 266 * `862 <https://github.com/ipython/ipython/issues/862>`_: BUG: Completion widget position and pager focus.
267 267 * `847 <https://github.com/ipython/ipython/issues/847>`_: Allow connection to kernels by files
268 268 * `708 <https://github.com/ipython/ipython/issues/708>`_: Two-process terminal frontend
269 269 * `857 <https://github.com/ipython/ipython/issues/857>`_: make sdist flags work again (e.g. --manifest-only)
270 270 * `835 <https://github.com/ipython/ipython/issues/835>`_: Add Tab key to list of keys that scroll down the paging widget.
271 271 * `859 <https://github.com/ipython/ipython/issues/859>`_: Fix for issue #800
272 272 * `848 <https://github.com/ipython/ipython/issues/848>`_: Python3 setup.py install failiure
273 273 * `845 <https://github.com/ipython/ipython/issues/845>`_: Tests on Python 3
274 274 * `802 <https://github.com/ipython/ipython/issues/802>`_: DOC: extensions: add documentation for the bundled extensions
275 275 * `830 <https://github.com/ipython/ipython/issues/830>`_: contiguous stdout/stderr in notebook
276 276 * `761 <https://github.com/ipython/ipython/issues/761>`_: Windows: test runner fails if repo path (e.g. home dir) contains spaces
277 277 * `801 <https://github.com/ipython/ipython/issues/801>`_: Py3 notebook
278 278 * `809 <https://github.com/ipython/ipython/issues/809>`_: use CFRunLoop directly in `ipython kernel --pylab osx`
279 279 * `841 <https://github.com/ipython/ipython/issues/841>`_: updated old scipy.org links, other minor doc fixes
280 280 * `837 <https://github.com/ipython/ipython/issues/837>`_: remove all trailling spaces
281 281 * `834 <https://github.com/ipython/ipython/issues/834>`_: Issue https://github.com/ipython/ipython/issues/832 resolution
282 282 * `746 <https://github.com/ipython/ipython/issues/746>`_: ENH: extensions: port autoreload to current API
283 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 284 * `798 <https://github.com/ipython/ipython/issues/798>`_: pexpect & Python 3
285 285 * `804 <https://github.com/ipython/ipython/issues/804>`_: Magic 'range' crash if greater than len(input_hist)
286 286 * `821 <https://github.com/ipython/ipython/issues/821>`_: update tornado dependency to 2.1
287 287 * `807 <https://github.com/ipython/ipython/issues/807>`_: Faciliate ssh tunnel sharing by announcing ports
288 288 * `795 <https://github.com/ipython/ipython/issues/795>`_: Add cluster-id for multiple cluster instances per profile
289 289 * `742 <https://github.com/ipython/ipython/issues/742>`_: Glut
290 290 * `668 <https://github.com/ipython/ipython/issues/668>`_: Greedy completer
291 291 * `776 <https://github.com/ipython/ipython/issues/776>`_: Reworking qtconsole shortcut, add fullscreen
292 292 * `790 <https://github.com/ipython/ipython/issues/790>`_: TST: add future unicode_literals test (#786)
293 293 * `775 <https://github.com/ipython/ipython/issues/775>`_: redirect_in/redirect_out should be constrained to windows only
294 294 * `793 <https://github.com/ipython/ipython/issues/793>`_: Don't use readline in the ZMQShell
295 295 * `743 <https://github.com/ipython/ipython/issues/743>`_: Pyglet
296 296 * `774 <https://github.com/ipython/ipython/issues/774>`_: basic/initial .mailmap for nice shortlog summaries
297 297 * `770 <https://github.com/ipython/ipython/issues/770>`_: #769 (reopened)
298 298 * `784 <https://github.com/ipython/ipython/issues/784>`_: Parse user code to AST using compiler flags.
299 299 * `783 <https://github.com/ipython/ipython/issues/783>`_: always use StringIO, never cStringIO
300 300 * `782 <https://github.com/ipython/ipython/issues/782>`_: flush stdout/stderr on displayhook call
301 301 * `622 <https://github.com/ipython/ipython/issues/622>`_: Make pylab import all configurable
302 302 * `745 <https://github.com/ipython/ipython/issues/745>`_: Don't assume history requests succeed in qtconsole
303 303 * `725 <https://github.com/ipython/ipython/issues/725>`_: don't assume cursor.selectedText() is a string
304 304 * `778 <https://github.com/ipython/ipython/issues/778>`_: don't override execfile on Python 2
305 305 * `663 <https://github.com/ipython/ipython/issues/663>`_: Python 3 compatilibility work
306 306 * `762 <https://github.com/ipython/ipython/issues/762>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes
307 307 * `763 <https://github.com/ipython/ipython/issues/763>`_: Set context for shortcuts in ConsoleWidget
308 308 * `722 <https://github.com/ipython/ipython/issues/722>`_: PyPy compatibility
309 309 * `757 <https://github.com/ipython/ipython/issues/757>`_: ipython.el is broken in 0.11
310 310 * `764 <https://github.com/ipython/ipython/issues/764>`_: fix "--colors=<color>" option in py-python-command-args.
311 311 * `758 <https://github.com/ipython/ipython/issues/758>`_: use ROUTER/DEALER socket names instead of XREP/XREQ
312 312 * `736 <https://github.com/ipython/ipython/issues/736>`_: enh: added authentication ability for webapp
313 313 * `748 <https://github.com/ipython/ipython/issues/748>`_: Check for tornado before running frontend.html tests.
314 314 * `754 <https://github.com/ipython/ipython/issues/754>`_: restore msg_id/msg_type aliases in top level of msg dict
315 315 * `769 <https://github.com/ipython/ipython/issues/769>`_: Don't treat bytes objects as json-safe
316 316 * `753 <https://github.com/ipython/ipython/issues/753>`_: DOC: msg['msg_type'] removed
317 317 * `766 <https://github.com/ipython/ipython/issues/766>`_: fix "--colors=<color>" option in py-python-command-args.
318 318 * `765 <https://github.com/ipython/ipython/issues/765>`_: fix "--colors=<color>" option in py-python-command-args.
319 319 * `741 <https://github.com/ipython/ipython/issues/741>`_: Run PyOs_InputHook in pager to keep plot windows interactive.
320 320 * `664 <https://github.com/ipython/ipython/issues/664>`_: Remove ipythonrc references from documentation
321 321 * `750 <https://github.com/ipython/ipython/issues/750>`_: Tiny doc fixes
322 322 * `433 <https://github.com/ipython/ipython/issues/433>`_: ZMQ terminal frontend
323 323 * `734 <https://github.com/ipython/ipython/issues/734>`_: Allow %magic argument filenames with spaces to be specified with quotes under win32
324 324 * `731 <https://github.com/ipython/ipython/issues/731>`_: respect encoding of display data from urls
325 325 * `730 <https://github.com/ipython/ipython/issues/730>`_: doc improvements for running notebook via secure protocol
326 326 * `729 <https://github.com/ipython/ipython/issues/729>`_: use null char to start markdown cell placeholder
327 327 * `727 <https://github.com/ipython/ipython/issues/727>`_: Minor fixes to the htmlnotebook
328 328 * `726 <https://github.com/ipython/ipython/issues/726>`_: use bundled argparse if system argparse is < 1.1
329 329 * `705 <https://github.com/ipython/ipython/issues/705>`_: Htmlnotebook
330 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 331 * `714 <https://github.com/ipython/ipython/issues/714>`_: Install mathjax for offline use
332 332 * `718 <https://github.com/ipython/ipython/issues/718>`_: Underline keyboard shortcut characters on appropriate buttons
333 333 * `717 <https://github.com/ipython/ipython/issues/717>`_: Add source highlighting to markdown snippets
334 334 * `716 <https://github.com/ipython/ipython/issues/716>`_: update EvalFormatter to allow arbitrary expressions
335 335 * `712 <https://github.com/ipython/ipython/issues/712>`_: Reset execution counter after cache is cleared
336 336 * `713 <https://github.com/ipython/ipython/issues/713>`_: Align colons in html notebook help dialog
337 337 * `709 <https://github.com/ipython/ipython/issues/709>`_: Allow usage of '.' in notebook names
338 338 * `706 <https://github.com/ipython/ipython/issues/706>`_: Implement static publishing of HTML notebook
339 339 * `674 <https://github.com/ipython/ipython/issues/674>`_: use argparse to parse aliases & flags
340 340 * `679 <https://github.com/ipython/ipython/issues/679>`_: HistoryManager.get_session_info()
341 341 * `696 <https://github.com/ipython/ipython/issues/696>`_: Fix columnize bug, where tab completion with very long filenames would crash Qt console
342 342 * `686 <https://github.com/ipython/ipython/issues/686>`_: add ssh tunnel support to qtconsole
343 343 * `685 <https://github.com/ipython/ipython/issues/685>`_: Add SSH tunneling to engines
344 344 * `384 <https://github.com/ipython/ipython/issues/384>`_: Allow pickling objects defined interactively.
345 345 * `647 <https://github.com/ipython/ipython/issues/647>`_: My fix rpmlint
346 346 * `587 <https://github.com/ipython/ipython/issues/587>`_: don't special case for py3k+numpy
347 347 * `703 <https://github.com/ipython/ipython/issues/703>`_: make config-loading debug messages more explicit
348 348 * `699 <https://github.com/ipython/ipython/issues/699>`_: make calltips configurable in qtconsole
349 349 * `666 <https://github.com/ipython/ipython/issues/666>`_: parallel tests & extra readline escapes
350 350 * `683 <https://github.com/ipython/ipython/issues/683>`_: BF - allow nose with-doctest setting in environment
351 351 * `689 <https://github.com/ipython/ipython/issues/689>`_: Protect ipkernel from bad messages
352 352 * `702 <https://github.com/ipython/ipython/issues/702>`_: Prevent ipython.py launcher from being imported.
353 353 * `701 <https://github.com/ipython/ipython/issues/701>`_: Prevent ipython.py from being imported by accident
354 354 * `670 <https://github.com/ipython/ipython/issues/670>`_: check for writable dirs, not just existence, in utils.path
355 355 * `579 <https://github.com/ipython/ipython/issues/579>`_: Sessionwork
356 356 * `687 <https://github.com/ipython/ipython/issues/687>`_: add `ipython kernel` for starting just a kernel
357 357 * `627 <https://github.com/ipython/ipython/issues/627>`_: Qt Console history search
358 358 * `646 <https://github.com/ipython/ipython/issues/646>`_: Generate package list automatically in find_packages
359 359 * `660 <https://github.com/ipython/ipython/issues/660>`_: i658
360 360 * `659 <https://github.com/ipython/ipython/issues/659>`_: don't crash on bad config files
361 361
362 362 Regular issues (258):
363 363
364 364 * `1177 <https://github.com/ipython/ipython/issues/1177>`_: UnicodeDecodeError in py3compat from "xlrd??"
365 365 * `1094 <https://github.com/ipython/ipython/issues/1094>`_: Tooltip doesn't show constructor docstrings
366 366 * `1170 <https://github.com/ipython/ipython/issues/1170>`_: double pylab greeting with c.InteractiveShellApp.pylab = "tk" in zmqconsole
367 367 * `1166 <https://github.com/ipython/ipython/issues/1166>`_: E-mail cpaste broken
368 368 * `1164 <https://github.com/ipython/ipython/issues/1164>`_: IPython qtconsole (0.12) can't export to html with external png
369 369 * `1103 <https://github.com/ipython/ipython/issues/1103>`_: %loadpy should cut out encoding declaration
370 370 * `1156 <https://github.com/ipython/ipython/issues/1156>`_: Notebooks downloaded as Python files require a header stating the encoding
371 371 * `1157 <https://github.com/ipython/ipython/issues/1157>`_: Ctrl-C not working when GUI/pylab integration is active
372 372 * `1154 <https://github.com/ipython/ipython/issues/1154>`_: We should be less aggressive in de-registering post-execution functions
373 373 * `1134 <https://github.com/ipython/ipython/issues/1134>`_: "select-all, kill" leaves qtconsole in unusable state
374 374 * `1148 <https://github.com/ipython/ipython/issues/1148>`_: A lot of testerrors
375 375 * `803 <https://github.com/ipython/ipython/issues/803>`_: Make doctests work with Python 3
376 376 * `1119 <https://github.com/ipython/ipython/issues/1119>`_: Start menu shortcuts not created in Python 3
377 377 * `1136 <https://github.com/ipython/ipython/issues/1136>`_: The embedding machinery ignores user_ns
378 378 * `607 <https://github.com/ipython/ipython/issues/607>`_: Use the new IPython logo/font in the notebook header
379 379 * `755 <https://github.com/ipython/ipython/issues/755>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes
380 380 * `1115 <https://github.com/ipython/ipython/issues/1115>`_: shlex_split should return unicode
381 381 * `1109 <https://github.com/ipython/ipython/issues/1109>`_: timeit with string ending in space gives "ValueError: No closing quotation"
382 382 * `1142 <https://github.com/ipython/ipython/issues/1142>`_: Install problems
383 383 * `700 <https://github.com/ipython/ipython/issues/700>`_: Some SVG images render incorrectly in htmlnotebook
384 384 * `1117 <https://github.com/ipython/ipython/issues/1117>`_: quit() doesn't work in terminal
385 385 * `1111 <https://github.com/ipython/ipython/issues/1111>`_: ls broken after merge of #1089
386 386 * `1104 <https://github.com/ipython/ipython/issues/1104>`_: Prompt spacing weird
387 387 * `1124 <https://github.com/ipython/ipython/issues/1124>`_: Seg Fault 11 when calling PySide using "run" command
388 388 * `1088 <https://github.com/ipython/ipython/issues/1088>`_: QtConsole : can't copy from pager
389 389 * `568 <https://github.com/ipython/ipython/issues/568>`_: Test error and failure in IPython.core on windows
390 390 * `1112 <https://github.com/ipython/ipython/issues/1112>`_: testfailure in IPython.frontend on windows
391 391 * `1102 <https://github.com/ipython/ipython/issues/1102>`_: magic in IPythonDemo fails when not located at top of demo file
392 392 * `629 <https://github.com/ipython/ipython/issues/629>`_: \r and \b in qtconsole don't behave as expected
393 393 * `1080 <https://github.com/ipython/ipython/issues/1080>`_: Notebook: tab completion should close on "("
394 394 * `973 <https://github.com/ipython/ipython/issues/973>`_: Qt Console close dialog and on-top Qt Console
395 395 * `1087 <https://github.com/ipython/ipython/issues/1087>`_: QtConsole xhtml/Svg export broken ?
396 396 * `1067 <https://github.com/ipython/ipython/issues/1067>`_: Parallel test suite hangs on Python 3
397 397 * `1018 <https://github.com/ipython/ipython/issues/1018>`_: Local mathjax breaks install
398 398 * `993 <https://github.com/ipython/ipython/issues/993>`_: `raw_input` redirection to foreign kernels is extremely brittle
399 399 * `1100 <https://github.com/ipython/ipython/issues/1100>`_: ipython3 traceback unicode issue from extensions
400 400 * `1071 <https://github.com/ipython/ipython/issues/1071>`_: Large html-notebooks hang on load on a slow machine
401 401 * `89 <https://github.com/ipython/ipython/issues/89>`_: %pdoc np.ma.compress shows docstring twice
402 402 * `22 <https://github.com/ipython/ipython/issues/22>`_: Include improvements from anythingipython.el
403 403 * `633 <https://github.com/ipython/ipython/issues/633>`_: Execution count & SyntaxError
404 404 * `1095 <https://github.com/ipython/ipython/issues/1095>`_: Uncaught TypeError: Object has no method 'remove_and_cancell_tooltip'
405 405 * `1075 <https://github.com/ipython/ipython/issues/1075>`_: We're ignoring prompt customizations
406 406 * `1086 <https://github.com/ipython/ipython/issues/1086>`_: Can't open qtconsole from outside source tree
407 407 * `1076 <https://github.com/ipython/ipython/issues/1076>`_: namespace changes broke `foo.*bar*?` syntax
408 408 * `1074 <https://github.com/ipython/ipython/issues/1074>`_: pprinting old-style class objects fails (TypeError: 'tuple' object is not callable)
409 409 * `1063 <https://github.com/ipython/ipython/issues/1063>`_: IPython.utils test error due to missing unicodedata module
410 410 * `592 <https://github.com/ipython/ipython/issues/592>`_: Bug in argument parsing for %run
411 411 * `378 <https://github.com/ipython/ipython/issues/378>`_: Windows path escape issues
412 412 * `1068 <https://github.com/ipython/ipython/issues/1068>`_: Notebook tab completion broken in Firefox
413 413 * `75 <https://github.com/ipython/ipython/issues/75>`_: No tab completion after "/
414 414 * `103 <https://github.com/ipython/ipython/issues/103>`_: customizable cpaste
415 415 * `324 <https://github.com/ipython/ipython/issues/324>`_: Remove code in IPython.testing that is not being used
416 416 * `131 <https://github.com/ipython/ipython/issues/131>`_: Global variables not seen by cprofile.run()
417 417 * `851 <https://github.com/ipython/ipython/issues/851>`_: IPython shell swallows exceptions in certain circumstances
418 418 * `882 <https://github.com/ipython/ipython/issues/882>`_: ipython freezes at start if IPYTHONDIR is on an NFS mount
419 419 * `1057 <https://github.com/ipython/ipython/issues/1057>`_: Blocker: Qt console broken after "all magics" menu became dynamic
420 420 * `1027 <https://github.com/ipython/ipython/issues/1027>`_: ipython does not like white space at end of file
421 421 * `1058 <https://github.com/ipython/ipython/issues/1058>`_: New bug: Notebook asks for confirmation to leave even saved pages.
422 422 * `1061 <https://github.com/ipython/ipython/issues/1061>`_: rep (magic recall) under pypy
423 423 * `1047 <https://github.com/ipython/ipython/issues/1047>`_: Document the notebook format
424 424 * `102 <https://github.com/ipython/ipython/issues/102>`_: Properties accessed twice for classes defined interactively
425 425 * `16 <https://github.com/ipython/ipython/issues/16>`_: %store raises exception when storing compiled regex
426 426 * `67 <https://github.com/ipython/ipython/issues/67>`_: tab expansion should only take one directory level at the time
427 427 * `62 <https://github.com/ipython/ipython/issues/62>`_: Global variables undefined in interactive use of embedded ipython shell
428 428 * `57 <https://github.com/ipython/ipython/issues/57>`_: debugging with ipython does not work well outside ipython
429 429 * `38 <https://github.com/ipython/ipython/issues/38>`_: Line entry edge case error
430 430 * `980 <https://github.com/ipython/ipython/issues/980>`_: Update parallel docs for new parallel architecture
431 431 * `1017 <https://github.com/ipython/ipython/issues/1017>`_: Add small example about ipcluster/ssh startup
432 432 * `1041 <https://github.com/ipython/ipython/issues/1041>`_: Proxy Issues
433 433 * `967 <https://github.com/ipython/ipython/issues/967>`_: KernelManagers don't use zmq eventloop properly
434 434 * `1055 <https://github.com/ipython/ipython/issues/1055>`_: "All Magics" display on Ubuntu
435 435 * `1054 <https://github.com/ipython/ipython/issues/1054>`_: ipython explodes on syntax error
436 436 * `1051 <https://github.com/ipython/ipython/issues/1051>`_: ipython3 set_next_input() failure
437 437 * `693 <https://github.com/ipython/ipython/issues/693>`_: "run -i" no longer works after %reset in terminal
438 438 * `29 <https://github.com/ipython/ipython/issues/29>`_: cPickle works in standard interpreter, but not in IPython
439 439 * `1050 <https://github.com/ipython/ipython/issues/1050>`_: ipython3 broken by commit 8bb887c8c2c447bf7
440 440 * `1048 <https://github.com/ipython/ipython/issues/1048>`_: Update docs on notebook password
441 441 * `1046 <https://github.com/ipython/ipython/issues/1046>`_: Searies of questions/issues?
442 442 * `1045 <https://github.com/ipython/ipython/issues/1045>`_: crash when exiting - previously launched embedded sub-shell
443 443 * `1043 <https://github.com/ipython/ipython/issues/1043>`_: pylab doesn't work in qtconsole
444 444 * `1044 <https://github.com/ipython/ipython/issues/1044>`_: run -p doesn't work in python 3
445 445 * `1010 <https://github.com/ipython/ipython/issues/1010>`_: emacs freezes when ipython-complete is called
446 446 * `82 <https://github.com/ipython/ipython/issues/82>`_: Update devel docs with discussion about good changelogs
447 447 * `116 <https://github.com/ipython/ipython/issues/116>`_: Update release management scipts and release.revision for git
448 448 * `1022 <https://github.com/ipython/ipython/issues/1022>`_: Pylab banner shows up with first cell to execute
449 449 * `787 <https://github.com/ipython/ipython/issues/787>`_: Keyboard selection of multiple lines in the notebook behaves inconsistently
450 450 * `1037 <https://github.com/ipython/ipython/issues/1037>`_: notepad + jsonlib: TypeError: Only whitespace may be used for indentation.
451 451 * `970 <https://github.com/ipython/ipython/issues/970>`_: Default home not writable, %HOME% does not help (windows)
452 452 * `747 <https://github.com/ipython/ipython/issues/747>`_: HOMESHARE not a good choice for "writable homedir" on Windows
453 453 * `810 <https://github.com/ipython/ipython/issues/810>`_: cleanup utils.path.get_home_dir
454 454 * `2 <https://github.com/ipython/ipython/issues/2>`_: Fix the copyright statement in source code files to be accurate
455 455 * `1031 <https://github.com/ipython/ipython/issues/1031>`_: <esc> on Firefox crash websocket
456 456 * `684 <https://github.com/ipython/ipython/issues/684>`_: %Store eliminated in configuration and magic commands in 0.11
457 457 * `1026 <https://github.com/ipython/ipython/issues/1026>`_: BUG: wrong default parameter in ask_yes_no
458 458 * `880 <https://github.com/ipython/ipython/issues/880>`_: Better error message if %paste fails
459 459 * `1024 <https://github.com/ipython/ipython/issues/1024>`_: autopx magic broken
460 460 * `822 <https://github.com/ipython/ipython/issues/822>`_: Unicode bug in Itpl when expanding shell variables in syscalls with !
461 461 * `1009 <https://github.com/ipython/ipython/issues/1009>`_: Windows: regression in cd magic handling of paths
462 462 * `833 <https://github.com/ipython/ipython/issues/833>`_: Crash python with matplotlib and unequal length arrays
463 463 * `695 <https://github.com/ipython/ipython/issues/695>`_: Crash handler initialization is too aggressive
464 464 * `1000 <https://github.com/ipython/ipython/issues/1000>`_: Remove duplicates when refilling readline history
465 465 * `992 <https://github.com/ipython/ipython/issues/992>`_: Interrupting certain matplotlib operations leaves the inline backend 'wedged'
466 466 * `942 <https://github.com/ipython/ipython/issues/942>`_: number traits should cast if value doesn't change
467 467 * `1006 <https://github.com/ipython/ipython/issues/1006>`_: ls crashes when run on a UNC path or with non-ascii args
468 468 * `944 <https://github.com/ipython/ipython/issues/944>`_: Decide the default image format for inline figures: SVG or PNG?
469 469 * `842 <https://github.com/ipython/ipython/issues/842>`_: Python 3 on Windows (pyreadline) - expected an object with the buffer interface
470 470 * `1002 <https://github.com/ipython/ipython/issues/1002>`_: ImportError due to incorrect version checking
471 471 * `1001 <https://github.com/ipython/ipython/issues/1001>`_: Ipython "source" command?
472 472 * `954 <https://github.com/ipython/ipython/issues/954>`_: IPython embed doesn't respect namespaces
473 473 * `681 <https://github.com/ipython/ipython/issues/681>`_: pdb freezes inside qtconsole
474 474 * `698 <https://github.com/ipython/ipython/issues/698>`_: crash report "TypeError: can only concatenate list (not "unicode") to list"
475 475 * `978 <https://github.com/ipython/ipython/issues/978>`_: ipython 0.11 buffers external command output till the cmd is done
476 476 * `952 <https://github.com/ipython/ipython/issues/952>`_: Need user-facing warning in the browser if websocket connection fails
477 477 * `988 <https://github.com/ipython/ipython/issues/988>`_: Error using idlsave
478 478 * `990 <https://github.com/ipython/ipython/issues/990>`_: ipython notebook - kernel dies if matplotlib is not installed
479 479 * `752 <https://github.com/ipython/ipython/issues/752>`_: Matplotlib figures showed only once in notebook
480 480 * `54 <https://github.com/ipython/ipython/issues/54>`_: Exception hook should be optional for embedding IPython in GUIs
481 481 * `918 <https://github.com/ipython/ipython/issues/918>`_: IPython.frontend tests fail without tornado
482 482 * `986 <https://github.com/ipython/ipython/issues/986>`_: Views created with c.direct_view() fail
483 483 * `697 <https://github.com/ipython/ipython/issues/697>`_: Filter out from %who names loaded at initialization time
484 484 * `932 <https://github.com/ipython/ipython/issues/932>`_: IPython 0.11 quickref card has superfluous "%recall and"
485 485 * `982 <https://github.com/ipython/ipython/issues/982>`_: png files with executable permissions
486 486 * `914 <https://github.com/ipython/ipython/issues/914>`_: Simpler system for running code after InteractiveShell is initialised
487 487 * `911 <https://github.com/ipython/ipython/issues/911>`_: ipython crashes on startup if readline is missing
488 488 * `971 <https://github.com/ipython/ipython/issues/971>`_: bookmarks created in 0.11 are corrupt in 0.12
489 489 * `974 <https://github.com/ipython/ipython/issues/974>`_: object feature tab-completion crash
490 490 * `939 <https://github.com/ipython/ipython/issues/939>`_: ZMQShell always uses default profile
491 491 * `946 <https://github.com/ipython/ipython/issues/946>`_: Multi-tab Close action should offer option to leave all kernels alone
492 492 * `949 <https://github.com/ipython/ipython/issues/949>`_: Test suite must not require any manual interaction
493 493 * `643 <https://github.com/ipython/ipython/issues/643>`_: enable gui eventloop integration in ipkernel
494 494 * `965 <https://github.com/ipython/ipython/issues/965>`_: ipython is crashed without launch.(python3.2)
495 495 * `958 <https://github.com/ipython/ipython/issues/958>`_: Can't use os X clipboard on with qtconsole
496 496 * `962 <https://github.com/ipython/ipython/issues/962>`_: Don't require tornado in the tests
497 497 * `960 <https://github.com/ipython/ipython/issues/960>`_: crash on syntax error on Windows XP
498 498 * `934 <https://github.com/ipython/ipython/issues/934>`_: The latest ipython branch doesn't work in Chrome
499 499 * `870 <https://github.com/ipython/ipython/issues/870>`_: zmq version detection
500 500 * `943 <https://github.com/ipython/ipython/issues/943>`_: HISTIGNORE for IPython
501 501 * `947 <https://github.com/ipython/ipython/issues/947>`_: qtconsole segfaults at startup
502 502 * `903 <https://github.com/ipython/ipython/issues/903>`_: Expose a magic to control config of the inline pylab backend
503 503 * `908 <https://github.com/ipython/ipython/issues/908>`_: bad user config shouldn't crash IPython
504 504 * `935 <https://github.com/ipython/ipython/issues/935>`_: Typing `break` causes IPython to crash.
505 505 * `869 <https://github.com/ipython/ipython/issues/869>`_: Tab completion of `~/` shows no output post 0.10.x
506 506 * `904 <https://github.com/ipython/ipython/issues/904>`_: whos under pypy1.6
507 507 * `773 <https://github.com/ipython/ipython/issues/773>`_: check_security_dir() and check_pid_dir() fail on network filesystem
508 508 * `915 <https://github.com/ipython/ipython/issues/915>`_: OS X Lion Terminal.app line wrap problem
509 509 * `886 <https://github.com/ipython/ipython/issues/886>`_: Notebook kernel crash when specifying --notebook-dir on commandline
510 510 * `636 <https://github.com/ipython/ipython/issues/636>`_: debugger.py: pydb broken
511 511 * `808 <https://github.com/ipython/ipython/issues/808>`_: Ctrl+C during %reset confirm message crash Qtconsole
512 512 * `927 <https://github.com/ipython/ipython/issues/927>`_: Using return outside a function crashes ipython
513 513 * `919 <https://github.com/ipython/ipython/issues/919>`_: Pop-up segfault when moving cursor out of qtconsole window
514 514 * `181 <https://github.com/ipython/ipython/issues/181>`_: cls command does not work on windows
515 515 * `917 <https://github.com/ipython/ipython/issues/917>`_: documentation typos
516 516 * `818 <https://github.com/ipython/ipython/issues/818>`_: %run does not work with non-ascii characeters in path
517 517 * `907 <https://github.com/ipython/ipython/issues/907>`_: Errors in custom completer functions can crash IPython
518 518 * `867 <https://github.com/ipython/ipython/issues/867>`_: doc: notebook password authentication howto
519 519 * `211 <https://github.com/ipython/ipython/issues/211>`_: paste command not working
520 520 * `900 <https://github.com/ipython/ipython/issues/900>`_: Tab key should insert 4 spaces in qt console
521 521 * `513 <https://github.com/ipython/ipython/issues/513>`_: [Qt console] cannot insert new lines into console functions using tab
522 522 * `906 <https://github.com/ipython/ipython/issues/906>`_: qtconsoleapp 'parse_command_line' doen't like --existing anymore
523 523 * `638 <https://github.com/ipython/ipython/issues/638>`_: Qt console --pylab=inline and getfigs(), etc.
524 524 * `710 <https://github.com/ipython/ipython/issues/710>`_: unwanted unicode passed to args
525 525 * `436 <https://github.com/ipython/ipython/issues/436>`_: Users should see tooltips for all buttons in the notebook UI
526 526 * `207 <https://github.com/ipython/ipython/issues/207>`_: ipython crashes if atexit handler raises exception
527 527 * `692 <https://github.com/ipython/ipython/issues/692>`_: use of Tracer() when debugging works but gives error messages
528 528 * `690 <https://github.com/ipython/ipython/issues/690>`_: debugger does not print error message by default in 0.11
529 529 * `571 <https://github.com/ipython/ipython/issues/571>`_: history of multiline entries
530 530 * `749 <https://github.com/ipython/ipython/issues/749>`_: IPython.parallel test failure under Windows 7 and XP
531 531 * `890 <https://github.com/ipython/ipython/issues/890>`_: ipclusterapp.py - helep
532 532 * `885 <https://github.com/ipython/ipython/issues/885>`_: `ws-hostname` alias not recognized by notebook
533 533 * `881 <https://github.com/ipython/ipython/issues/881>`_: Missing manual.pdf?
534 534 * `744 <https://github.com/ipython/ipython/issues/744>`_: cannot create notebook in offline mode if mathjax not installed
535 535 * `865 <https://github.com/ipython/ipython/issues/865>`_: Make tracebacks from %paste show the code
536 536 * `535 <https://github.com/ipython/ipython/issues/535>`_: exception unicode handling in %run is faulty in qtconsole
537 537 * `817 <https://github.com/ipython/ipython/issues/817>`_: iPython crashed
538 538 * `799 <https://github.com/ipython/ipython/issues/799>`_: %edit magic not working on windows xp in qtconsole
539 539 * `732 <https://github.com/ipython/ipython/issues/732>`_: QTConsole wrongly promotes the index of the input line on which user presses Enter
540 540 * `662 <https://github.com/ipython/ipython/issues/662>`_: ipython test failures on Mac OS X Lion
541 541 * `650 <https://github.com/ipython/ipython/issues/650>`_: Handle bad config files better
542 542 * `829 <https://github.com/ipython/ipython/issues/829>`_: We should not insert new lines after all print statements in the notebook
543 543 * `874 <https://github.com/ipython/ipython/issues/874>`_: ipython-qtconsole: pyzmq Version Comparison
544 544 * `640 <https://github.com/ipython/ipython/issues/640>`_: matplotlib macosx windows don't respond in qtconsole
545 545 * `624 <https://github.com/ipython/ipython/issues/624>`_: ipython intermittently segfaults when figure is closed (Mac OS X)
546 546 * `871 <https://github.com/ipython/ipython/issues/871>`_: Notebook crashes if a profile is used
547 547 * `56 <https://github.com/ipython/ipython/issues/56>`_: Have %cpaste accept also Ctrl-D as a termination marker
548 548 * `849 <https://github.com/ipython/ipython/issues/849>`_: Command line options to not override profile options
549 549 * `806 <https://github.com/ipython/ipython/issues/806>`_: Provide single-port connection to kernels
550 550 * `691 <https://github.com/ipython/ipython/issues/691>`_: [wishlist] Automatically find existing kernel
551 551 * `688 <https://github.com/ipython/ipython/issues/688>`_: local security vulnerability: all ports visible to any local user.
552 552 * `866 <https://github.com/ipython/ipython/issues/866>`_: DistributionNotFound on running ipython 0.11 on Windows XP x86
553 553 * `673 <https://github.com/ipython/ipython/issues/673>`_: raw_input appears to be round-robin for qtconsole
554 554 * `863 <https://github.com/ipython/ipython/issues/863>`_: Graceful degradation when home directory not writable
555 555 * `800 <https://github.com/ipython/ipython/issues/800>`_: Timing scripts with run -t -N <N> fails on report output
556 556 * `858 <https://github.com/ipython/ipython/issues/858>`_: Typing 'continue' makes ipython0.11 crash
557 557 * `840 <https://github.com/ipython/ipython/issues/840>`_: all processes run on one CPU core
558 558 * `843 <https://github.com/ipython/ipython/issues/843>`_: "import braces" crashes ipython
559 559 * `836 <https://github.com/ipython/ipython/issues/836>`_: Strange Output after IPython Install
560 560 * `839 <https://github.com/ipython/ipython/issues/839>`_: Qtconsole segfaults when mouse exits window with active tooltip
561 561 * `827 <https://github.com/ipython/ipython/issues/827>`_: Add support for checking several limits before running task on engine
562 562 * `826 <https://github.com/ipython/ipython/issues/826>`_: Add support for creation of parallel task when no engine is running
563 563 * `832 <https://github.com/ipython/ipython/issues/832>`_: Improve error message for %logstop
564 564 * `831 <https://github.com/ipython/ipython/issues/831>`_: %logstart in read-only directory forbid any further command
565 565 * `814 <https://github.com/ipython/ipython/issues/814>`_: ipython does not start -- DistributionNotFound
566 566 * `794 <https://github.com/ipython/ipython/issues/794>`_: Allow >1 controller per profile
567 567 * `820 <https://github.com/ipython/ipython/issues/820>`_: Tab Completion feature
568 568 * `812 <https://github.com/ipython/ipython/issues/812>`_: Qt console crashes on Ubuntu 11.10
569 569 * `816 <https://github.com/ipython/ipython/issues/816>`_: Import error using Python 2.7 and dateutil2.0 No module named _thread
570 570 * `756 <https://github.com/ipython/ipython/issues/756>`_: qtconsole Windows fails to print error message for '%run nonexistent_file'
571 571 * `651 <https://github.com/ipython/ipython/issues/651>`_: Completion doesn't work on element of a list
572 572 * `617 <https://github.com/ipython/ipython/issues/617>`_: [qtconsole] %hist doesn't show anything in qtconsole
573 573 * `786 <https://github.com/ipython/ipython/issues/786>`_: from __future__ import unicode_literals does not work
574 574 * `779 <https://github.com/ipython/ipython/issues/779>`_: Using irunner from virtual evn uses systemwide ipython
575 575 * `768 <https://github.com/ipython/ipython/issues/768>`_: codepage handling of output from scripts and shellcommands are not handled properly by qtconsole
576 576 * `785 <https://github.com/ipython/ipython/issues/785>`_: Don't strip leading whitespace in repr() in notebook
577 577 * `737 <https://github.com/ipython/ipython/issues/737>`_: in pickleshare.py line52 should be "if not os.path.isdir(self.root):"?
578 578 * `738 <https://github.com/ipython/ipython/issues/738>`_: in ipthon_win_post_install.py line 38
579 579 * `777 <https://github.com/ipython/ipython/issues/777>`_: print(…, sep=…) raises SyntaxError
580 580 * `728 <https://github.com/ipython/ipython/issues/728>`_: ipcontroller crash with MPI
581 581 * `780 <https://github.com/ipython/ipython/issues/780>`_: qtconsole Out value prints before the print statements that precede it
582 582 * `632 <https://github.com/ipython/ipython/issues/632>`_: IPython Crash Report (0.10.2)
583 583 * `253 <https://github.com/ipython/ipython/issues/253>`_: Unable to install ipython on windows
584 584 * `80 <https://github.com/ipython/ipython/issues/80>`_: Split IPClusterApp into multiple Application subclasses for each subcommand
585 585 * `34 <https://github.com/ipython/ipython/issues/34>`_: non-blocking pendingResult partial results
586 586 * `739 <https://github.com/ipython/ipython/issues/739>`_: Tests fail if tornado not installed
587 587 * `719 <https://github.com/ipython/ipython/issues/719>`_: Better support Pypy
588 588 * `667 <https://github.com/ipython/ipython/issues/667>`_: qtconsole problem with default pylab profile
589 589 * `661 <https://github.com/ipython/ipython/issues/661>`_: ipythonrc referenced in magic command in 0.11
590 590 * `665 <https://github.com/ipython/ipython/issues/665>`_: Source introspection with ?? is broken
591 591 * `724 <https://github.com/ipython/ipython/issues/724>`_: crash - ipython qtconsole, %quickref
592 592 * `655 <https://github.com/ipython/ipython/issues/655>`_: ipython with qtconsole crashes
593 593 * `593 <https://github.com/ipython/ipython/issues/593>`_: HTML Notebook Prompt can be deleted . . .
594 594 * `563 <https://github.com/ipython/ipython/issues/563>`_: use argparse instead of kvloader for flags&aliases
595 595 * `751 <https://github.com/ipython/ipython/issues/751>`_: Tornado version greater than 2.0 needed for firefox 6
596 596 * `720 <https://github.com/ipython/ipython/issues/720>`_: Crash report when importing easter egg
597 597 * `740 <https://github.com/ipython/ipython/issues/740>`_: Ctrl-Enter clears line in notebook
598 598 * `772 <https://github.com/ipython/ipython/issues/772>`_: ipengine fails on Windows with "XXX lineno: 355, opcode: 0"
599 599 * `771 <https://github.com/ipython/ipython/issues/771>`_: Add python 3 tag to setup.py
600 600 * `767 <https://github.com/ipython/ipython/issues/767>`_: non-ascii in __doc__ string crashes qtconsole kernel when showing tooltip
601 601 * `733 <https://github.com/ipython/ipython/issues/733>`_: In Windows, %run fails to strip quotes from filename
602 602 * `721 <https://github.com/ipython/ipython/issues/721>`_: no completion in emacs by ipython(ipython.el)
603 603 * `669 <https://github.com/ipython/ipython/issues/669>`_: Do not accept an ipython_dir that's not writeable
604 604 * `711 <https://github.com/ipython/ipython/issues/711>`_: segfault on mac os x
605 605 * `500 <https://github.com/ipython/ipython/issues/500>`_: "RuntimeError: Cannot change input buffer during execution" in console_widget.py
606 606 * `707 <https://github.com/ipython/ipython/issues/707>`_: Copy and paste keyboard shortcuts do not work in Qt Console on OS X
607 607 * `478 <https://github.com/ipython/ipython/issues/478>`_: PyZMQ's use of memoryviews breaks reconstruction of numpy arrays
608 608 * `694 <https://github.com/ipython/ipython/issues/694>`_: Turning off callout tips in qtconsole
609 609 * `704 <https://github.com/ipython/ipython/issues/704>`_: return kills IPython
610 610 * `442 <https://github.com/ipython/ipython/issues/442>`_: Users should have intelligent autoindenting in the notebook
611 611 * `615 <https://github.com/ipython/ipython/issues/615>`_: Wireframe and implement a project dashboard page
612 612 * `614 <https://github.com/ipython/ipython/issues/614>`_: Wireframe and implement a notebook dashboard page
613 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 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 615 * `298 <https://github.com/ipython/ipython/issues/298>`_: Users should be able to save a notebook and then later reload it
616 616 * `649 <https://github.com/ipython/ipython/issues/649>`_: ipython qtconsole (v0.11): setting "c.IPythonWidget.in_prompt = '>>> ' crashes
617 617 * `672 <https://github.com/ipython/ipython/issues/672>`_: What happened to Exit?
618 618 * `658 <https://github.com/ipython/ipython/issues/658>`_: Put the InteractiveShellApp section first in the auto-generated config files
619 619 * `656 <https://github.com/ipython/ipython/issues/656>`_: [suggestion] dependency checking for pyqt for Windows installer
620 620 * `654 <https://github.com/ipython/ipython/issues/654>`_: broken documentation link on download page
621 621 * `653 <https://github.com/ipython/ipython/issues/653>`_: Test failures in IPython.parallel
@@ -1,1784 +1,1784 b''
1 1 .. _issues_list_100:
2 2
3 3 Issues closed in the 1.0 development cycle
4 4 ==========================================
5 5
6 6 Issues closed in 1.1
7 7 --------------------
8 8
9 9 GitHub stats for 2013/08/08 - 2013/09/09 (since 1.0)
10 10
11 11 These lists are automatically generated, and may be incomplete or contain duplicates.
12 12
13 13 The following 25 authors contributed 337 commits.
14 14
15 15 * Benjamin Ragan-Kelley
16 16 * Bing Xia
17 17 * Bradley M. Froehle
18 18 * Brian E. Granger
19 19 * DamiΓ‘n Avila
20 20 * dhirschfeld
21 21 * Dražen Lučanin
22 22 * gmbecker
23 23 * Jake Vanderplas
24 24 * Jason Grout
25 25 * Jonathan Frederic
26 26 * Kevin Burke
27 27 * Kyle Kelley
28 28 * Matt Henderson
29 29 * Matthew Brett
30 30 * Matthias Bussonnier
31 31 * Pankaj Pandey
32 32 * Paul Ivanov
33 33 * rossant
34 34 * Samuel Ainsworth
35 35 * Stephan Rave
36 36 * stonebig
37 37 * Thomas Kluyver
38 38 * Yaroslav Halchenko
39 39 * Zachary Sailer
40 40
41 41
42 42 We closed a total of 76 issues, 58 pull requests and 18 regular issues;
43 43 this is the full list (generated with the script :file:`tools/github_stats.py`):
44 44
45 45 Pull Requests (58):
46 46
47 47 * :ghpull:`4188`: Allow user_ns trait to be None
48 48 * :ghpull:`4189`: always fire LOCAL_IPS.extend(PUBLIC_IPS)
49 49 * :ghpull:`4174`: various issues in markdown and rst templates
50 50 * :ghpull:`4178`: add missing data_javascript
51 51 * :ghpull:`4181`: nbconvert: Fix, sphinx template not removing new lines from headers
52 52 * :ghpull:`4043`: don't 'restore_bytes' in from_JSON
53 53 * :ghpull:`4163`: Fix for incorrect default encoding on Windows.
54 54 * :ghpull:`4136`: catch javascript errors in any output
55 55 * :ghpull:`4171`: add nbconvert config file when creating profiles
56 56 * :ghpull:`4125`: Basic exercise of `ipython [subcommand] -h` and help-all
57 57 * :ghpull:`4085`: nbconvert: Fix sphinx preprocessor date format string for Windows
58 58 * :ghpull:`4159`: don't split `.cell` and `div.cell` CSS
59 59 * :ghpull:`4158`: generate choices for `--gui` configurable from real mapping
60 60 * :ghpull:`4065`: do not include specific css in embedable one
61 61 * :ghpull:`4092`: nbconvert: Fix for unicode html headers, Windows + Python 2.x
62 62 * :ghpull:`4074`: close Client sockets if connection fails
63 63 * :ghpull:`4064`: Store default codemirror mode in only 1 place
64 64 * :ghpull:`4104`: Add way to install MathJax to a particular profile
65 65 * :ghpull:`4144`: help_end transformer shouldn't pick up ? in multiline string
66 66 * :ghpull:`4143`: update example custom.js
67 67 * :ghpull:`4142`: DOC: unwrap openssl line in public_server doc
68 68 * :ghpull:`4141`: add files with a separate `add` call in backport_pr
69 69 * :ghpull:`4137`: Restore autorestore option for storemagic
70 70 * :ghpull:`4098`: pass profile-dir instead of profile name to Kernel
71 71 * :ghpull:`4120`: support `input` in Python 2 kernels
72 72 * :ghpull:`4088`: nbconvert: Fix coalescestreams line with incorrect nesting causing strange behavior
73 73 * :ghpull:`4060`: only strip continuation prompts if regular prompts seen first
74 74 * :ghpull:`4132`: Fixed name error bug in function safe_unicode in module py3compat.
75 75 * :ghpull:`4121`: move test_kernel from IPython.zmq to IPython.kernel
76 76 * :ghpull:`4118`: ZMQ heartbeat channel: catch EINTR exceptions and continue.
77 77 * :ghpull:`4054`: use unicode for HTML export
78 78 * :ghpull:`4106`: fix a couple of default block values
79 79 * :ghpull:`4115`: Update docs on declaring a magic function
80 80 * :ghpull:`4101`: restore accidentally removed EngineError
81 81 * :ghpull:`4096`: minor docs changes
82 82 * :ghpull:`4056`: respect `pylab_import_all` when `--pylab` specified at the command-line
83 83 * :ghpull:`4091`: Make Qt console banner configurable
84 84 * :ghpull:`4086`: fix missing errno import
85 85 * :ghpull:`4030`: exclude `.git` in MANIFEST.in
86 86 * :ghpull:`4047`: Use istype() when checking if canned object is a dict
87 87 * :ghpull:`4031`: don't close_fds on Windows
88 88 * :ghpull:`4029`: bson.Binary moved
89 89 * :ghpull:`4035`: Fixed custom jinja2 templates being ignored when setting template_path
90 90 * :ghpull:`4026`: small doc fix in nbconvert
91 91 * :ghpull:`4016`: Fix IPython.start_* functions
92 92 * :ghpull:`4021`: Fix parallel.client.View map() on numpy arrays
93 93 * :ghpull:`4022`: DOC: fix links to matplotlib, notebook docs
94 94 * :ghpull:`4018`: Fix warning when running IPython.kernel tests
95 95 * :ghpull:`4019`: Test skipping without unicode paths
96 96 * :ghpull:`4008`: Transform code before %prun/%%prun runs
97 97 * :ghpull:`4014`: Fix typo in ipapp
98 98 * :ghpull:`3987`: get files list in backport_pr
99 99 * :ghpull:`3974`: nbconvert: Fix app tests on Window7 w/ Python 3.3
100 100 * :ghpull:`3978`: fix `--existing` with non-localhost IP
101 101 * :ghpull:`3939`: minor checkpoint cleanup
102 102 * :ghpull:`3981`: BF: fix nbconvert rst input prompt spacing
103 103 * :ghpull:`3960`: Don't make sphinx a dependency for importing nbconvert
104 104 * :ghpull:`3973`: logging.Formatter is not new-style in 2.6
105 105
106 106 Issues (18):
107 107
108 108 * :ghissue:`4024`: nbconvert markdown issues
109 109 * :ghissue:`4095`: Catch js error in append html in stream/pyerr
110 110 * :ghissue:`4156`: Specifying --gui=tk at the command line
111 111 * :ghissue:`3818`: nbconvert can't handle Heading with Chinese characters on Japanese Windows OS.
112 112 * :ghissue:`4134`: multi-line parser fails on ''' in comment, qtconsole and notebook.
113 113 * :ghissue:`3998`: sample custom.js needs to be updated
114 114 * :ghissue:`4078`: StoreMagic.autorestore not working in 1.0.0
115 115 * :ghissue:`3990`: Buitlin `input` doesn't work over zmq
116 116 * :ghissue:`4015`: nbconvert fails to convert all the content of a notebook
117 117 * :ghissue:`4059`: Issues with Ellipsis literal in Python 3
118 118 * :ghissue:`4103`: Wrong default argument of DirectView.clear
119 119 * :ghissue:`4100`: parallel.client.client references undefined error.EngineError
120 120 * :ghissue:`4005`: IPython.start_kernel doesn't work.
121 121 * :ghissue:`4020`: IPython parallel map fails on numpy arrays
122 122 * :ghissue:`3945`: nbconvert: commandline tests fail Win7x64 Py3.3
123 123 * :ghissue:`3977`: unable to complete remote connections for two-process
124 124 * :ghissue:`3980`: nbconvert rst output lacks needed blank lines
125 125 * :ghissue:`3968`: TypeError: super() argument 1 must be type, not classobj (Python 2.6.6)
126 126
127 127 Issues closed in 1.0
128 128 --------------------
129 129
130 130 GitHub stats for 2012/06/30 - 2013/08/08 (since 0.13)
131 131
132 132 These lists are automatically generated, and may be incomplete or contain duplicates.
133 133
134 134 The following 155 authors contributed 4258 commits.
135 135
136 136 * Aaron Meurer
137 137 * Adam Davis
138 138 * Ahmet Bakan
139 139 * Alberto Valverde
140 140 * Allen Riddell
141 141 * Anders HovmΓΆller
142 142 * Andrea Bedini
143 143 * Andrew Spiers
144 144 * Andrew Vandever
145 145 * Anthony Scopatz
146 146 * Anton Akhmerov
147 147 * Anton I. Sipos
148 148 * Antony Lee
149 149 * Aron Ahmadia
150 150 * Benedikt Sauer
151 151 * Benjamin Jones
152 152 * Benjamin Ragan-Kelley
153 153 * Benjie Chen
154 154 * Boris de Laage
155 155 * Brad Reisfeld
156 156 * Bradley M. Froehle
157 157 * Brian E. Granger
158 158 * Cameron Bates
159 159 * Cavendish McKay
160 160 * chapmanb
161 161 * Chris Beaumont
162 162 * Chris Laumann
163 163 * Christoph Gohlke
164 164 * codebraker
165 165 * codespaced
166 166 * Corran Webster
167 167 * DamianHeard
168 168 * DamiΓ‘n Avila
169 169 * Dan Kilman
170 170 * Dan McDougall
171 171 * Danny Staple
172 172 * David Hirschfeld
173 173 * David P. Sanders
174 174 * David Warde-Farley
175 175 * David Wolever
176 176 * David Wyde
177 177 * debjan
178 178 * Diane Trout
179 179 * dkua
180 180 * Dominik Dabrowski
181 181 * Donald Curtis
182 182 * Dražen Lučanin
183 183 * drevicko
184 184 * Eric O. LEBIGOT
185 185 * Erik M. Bray
186 186 * Erik Tollerud
187 187 * Eugene Van den Bulke
188 188 * Evan Patterson
189 189 * Fernando Perez
190 190 * Francesco Montesano
191 191 * Frank Murphy
192 192 * Greg Caporaso
193 193 * Guy Haskin Fernald
194 194 * guziy
195 195 * Hans Meine
196 196 * Harry Moreno
197 197 * henryiii
198 198 * Ivan Djokic
199 199 * Jack Feser
200 200 * Jake Vanderplas
201 201 * jakobgager
202 202 * James Booth
203 203 * Jan Schulz
204 204 * Jason Grout
205 205 * Jeff Knisley
206 206 * Jens Hedegaard Nielsen
207 207 * jeremiahbuddha
208 208 * Jerry Fowler
209 209 * Jessica B. Hamrick
210 210 * Jez Ng
211 211 * John Zwinck
212 212 * Jonathan Frederic
213 213 * Jonathan Taylor
214 214 * Joon Ro
215 215 * Joseph Lansdowne
216 216 * Juergen Hasch
217 217 * Julian Taylor
218 218 * Jussi Sainio
219 219 * JΓΆrgen Stenarson
220 220 * kevin
221 221 * klonuo
222 222 * Konrad Hinsen
223 223 * Kyle Kelley
224 224 * Lars Solberg
225 225 * Lessandro Mariano
226 226 * Mark Sienkiewicz at STScI
227 227 * Martijn Vermaat
228 228 * Martin Spacek
229 229 * Matthias Bussonnier
230 230 * Maxim Grechkin
231 231 * Maximilian Albert
232 232 * MercuryRising
233 233 * Michael Droettboom
234 234 * Michael Shuffett
235 235 * MichaΕ‚ GΓ³rny
236 236 * Mikhail Korobov
237 237 * mr.Shu
238 238 * Nathan Goldbaum
239 239 * ocefpaf
240 240 * Ohad Ravid
241 241 * Olivier Grisel
242 242 * Olivier Verdier
243 243 * Owen Healy
244 244 * Pankaj Pandey
245 245 * Paul Ivanov
246 246 * Pawel Jasinski
247 247 * Pietro Berkes
248 248 * Piti Ongmongkolkul
249 249 * Puneeth Chaganti
250 250 * Rich Wareham
251 251 * Richard Everson
252 252 * Rick Lupton
253 253 * Rob Young
254 254 * Robert Kern
255 255 * Robert Marchman
256 256 * Robert McGibbon
257 257 * Rui Pereira
258 258 * Rustam Safin
259 259 * Ryan May
260 260 * s8weber
261 261 * Samuel Ainsworth
262 262 * Sean Vig
263 263 * Siyu Zhang
264 264 * Skylar Saveland
265 265 * slojo404
266 266 * smithj1
267 267 * Stefan Karpinski
268 268 * Stefan van der Walt
269 269 * Steven Silvester
270 270 * Takafumi Arakaki
271 271 * Takeshi Kanmae
272 272 * tcmulcahy
273 273 * teegaar
274 274 * Thomas Kluyver
275 275 * Thomas Robitaille
276 276 * Thomas Spura
277 277 * Thomas Weißschuh
278 278 * Timothy O'Donnell
279 279 * Tom Dimiduk
280 280 * ugurthemaster
281 281 * urielshaolin
282 282 * v923z
283 283 * Valentin Haenel
284 284 * Victor Zverovich
285 285 * W. Trevor King
286 286 * y-p
287 287 * Yoav Ram
288 288 * Zbigniew JΔ™drzejewski-Szmek
289 289 * ZoltΓ‘n VΓΆrΓΆs
290 290
291 291
292 292 We closed a total of 1484 issues, 793 pull requests and 691 regular issues;
293 293 this is the full list (generated with the script
294 294 :file:`tools/github_stats.py`):
295 295
296 296 Pull Requests (793):
297 297
298 298 * :ghpull:`3958`: doc update
299 299 * :ghpull:`3965`: Fix ansi color code for background yellow
300 300 * :ghpull:`3964`: Fix casing of message.
301 301 * :ghpull:`3942`: Pass on install docs
302 302 * :ghpull:`3962`: exclude IPython.lib.kernel in iptest
303 303 * :ghpull:`3961`: Longpath test fix
304 304 * :ghpull:`3905`: Remove references to 0.11 and 0.12 from config/overview.rst
305 305 * :ghpull:`3951`: nbconvert: fixed latex characters not escaped properly in nbconvert
306 306 * :ghpull:`3949`: log fatal error when PDF conversion fails
307 307 * :ghpull:`3947`: nbconvert: Make writer & post-processor aliases case insensitive.
308 308 * :ghpull:`3938`: Recompile css.
309 309 * :ghpull:`3948`: sphinx and PDF tweaks
310 310 * :ghpull:`3943`: nbconvert: Serve post-processor Windows fix
311 311 * :ghpull:`3934`: nbconvert: fix logic of verbose flag in PDF post processor
312 312 * :ghpull:`3929`: swallow enter event in rename dialog
313 313 * :ghpull:`3924`: nbconvert: Backport fixes
314 314 * :ghpull:`3925`: Replace --pylab flag with --matplotlib in usage
315 315 * :ghpull:`3910`: Added explicit error message for missing configuration arguments.
316 316 * :ghpull:`3913`: grffile to support spaces in notebook names
317 317 * :ghpull:`3918`: added check_for_tornado, closes #3916
318 318 * :ghpull:`3917`: change docs/examples refs to be just examples
319 319 * :ghpull:`3908`: what's new tweaks
320 320 * :ghpull:`3896`: two column quickhelp dialog, closes #3895
321 321 * :ghpull:`3911`: explicitly load python mode before IPython mode
322 322 * :ghpull:`3901`: don't force . relative path, fix #3897
323 323 * :ghpull:`3891`: fix #3889
324 324 * :ghpull:`3892`: Fix documentation of Kernel.stop_channels
325 325 * :ghpull:`3888`: posixify paths for Windows latex
326 326 * :ghpull:`3882`: quick fix for #3881
327 327 * :ghpull:`3877`: don't use `shell=True` in PDF export
328 328 * :ghpull:`3878`: minor template loading cleanup
329 329 * :ghpull:`3855`: nbconvert: Filter tests
330 330 * :ghpull:`3879`: finish 3870
331 331 * :ghpull:`3870`: Fix for converting notebooks that contain unicode characters.
332 332 * :ghpull:`3876`: Update parallel_winhpc.rst
333 333 * :ghpull:`3872`: removing vim-ipython, since it has it's own repo
334 334 * :ghpull:`3871`: updating docs
335 335 * :ghpull:`3873`: remove old examples
336 336 * :ghpull:`3868`: update CodeMirror component to 3.15
337 337 * :ghpull:`3865`: Escape filename for pdflatex in nbconvert
338 338 * :ghpull:`3861`: remove old external.js
339 339 * :ghpull:`3864`: add keyboard shortcut to docs
340 340 * :ghpull:`3834`: This PR fixes a few issues with nbconvert tests
341 341 * :ghpull:`3840`: prevent profile_dir from being undefined
342 342 * :ghpull:`3859`: Add "An Afternoon Hack" to docs
343 343 * :ghpull:`3854`: Catch errors filling readline history on startup
344 344 * :ghpull:`3857`: Delete extra auto
345 345 * :ghpull:`3845`: nbconvert: Serve from original build directory
346 346 * :ghpull:`3846`: Add basic logging to nbconvert
347 347 * :ghpull:`3850`: add missing store_history key to Notebook execute_requests
348 348 * :ghpull:`3844`: update payload source
349 349 * :ghpull:`3830`: mention metadata / display_data similarity in pyout spec
350 350 * :ghpull:`3848`: fix incorrect `empty-docstring`
351 351 * :ghpull:`3836`: Parse markdown correctly when mathjax is disabled
352 352 * :ghpull:`3849`: skip a failing test on windows
353 353 * :ghpull:`3828`: signature_scheme lives in Session
354 354 * :ghpull:`3831`: update nbconvert doc with new CLI
355 355 * :ghpull:`3822`: add output flag to nbconvert
356 356 * :ghpull:`3780`: Added serving the output directory if html-based format are selected.
357 357 * :ghpull:`3764`: Cleanup nbconvert templates
358 358 * :ghpull:`3829`: remove now-duplicate 'this is dev' note
359 359 * :ghpull:`3814`: add `ConsoleWidget.execute_on_complete_input` flag
360 360 * :ghpull:`3826`: try rtfd
361 361 * :ghpull:`3821`: add sphinx prolog
362 362 * :ghpull:`3817`: relax timeouts in terminal console and tests
363 363 * :ghpull:`3825`: fix more tests that fail when pandoc is missing
364 364 * :ghpull:`3824`: don't set target on internal markdown links
365 365 * :ghpull:`3816`: s/pylab/matplotlib in docs
366 366 * :ghpull:`3812`: Describe differences between start_ipython and embed
367 367 * :ghpull:`3805`: Print View has been removed
368 368 * :ghpull:`3820`: Make it clear that 1.0 is not released yet
369 369 * :ghpull:`3784`: nbconvert: Export flavors & PDF writer (ipy dev meeting)
370 370 * :ghpull:`3800`: semantic-versionify version number for non-releases
371 371 * :ghpull:`3802`: Documentation .txt to .rst
372 372 * :ghpull:`3765`: cleanup terminal console iopub handling
373 373 * :ghpull:`3720`: Fix for #3719
374 374 * :ghpull:`3787`: re-raise KeyboardInterrupt in raw_input
375 375 * :ghpull:`3770`: Organizing reveal's templates.
376 376 * :ghpull:`3751`: Use link(2) when possible in nbconvert
377 377 * :ghpull:`3792`: skip tests that require pandoc
378 378 * :ghpull:`3782`: add Importing Notebooks example
379 379 * :ghpull:`3752`: nbconvert: Add cwd to sys.path
380 380 * :ghpull:`3789`: fix raw_input in qtconsole
381 381 * :ghpull:`3756`: document the wire protocol
382 382 * :ghpull:`3749`: convert IPython syntax to Python syntax in nbconvert python template
383 383 * :ghpull:`3793`: Closes #3788
384 384 * :ghpull:`3794`: Change logo link to ipython.org
385 385 * :ghpull:`3746`: Raise a named exception when pandoc is missing
386 386 * :ghpull:`3781`: comply with the message spec in the notebook
387 387 * :ghpull:`3779`: remove bad `if logged_in` preventing new-notebook without login
388 388 * :ghpull:`3743`: remove notebook read-only view
389 389 * :ghpull:`3732`: add delay to autosave in beforeunload
390 390 * :ghpull:`3761`: Added rm_math_space to markdown cells in the basichtml.tpl to be rendered ok by mathjax after the nbconvertion.
391 391 * :ghpull:`3758`: nbconvert: Filter names cleanup
392 392 * :ghpull:`3769`: Add configurability to tabcompletion timeout
393 393 * :ghpull:`3771`: Update px pylab test to match new output of pylab
394 394 * :ghpull:`3741`: better message when notebook format is not supported
395 395 * :ghpull:`3753`: document Ctrl-C not working in ipython kernel
396 396 * :ghpull:`3766`: handle empty metadata in pyout messages more gracefully.
397 397 * :ghpull:`3736`: my attempt to fix #3735
398 398 * :ghpull:`3759`: nbconvert: Provide a more useful error for invalid use case.
399 399 * :ghpull:`3760`: nbconvert: Allow notebook filenames without their extensions
400 400 * :ghpull:`3750`: nbconvert: Add cwd to default templates search path.
401 401 * :ghpull:`3748`: Update nbconvert docs
402 402 * :ghpull:`3734`: Nbconvert: Export extracted files into `nbname_files` subdirectory
403 403 * :ghpull:`3733`: Nicer message when pandoc is missing, closes #3730
404 404 * :ghpull:`3722`: fix two failing test in IPython.lib
405 405 * :ghpull:`3704`: Start what's new for 1.0
406 406 * :ghpull:`3705`: Complete rewrite of IPython Notebook documentation: docs/source/interactive/htmlnotebook.txt
407 407 * :ghpull:`3709`: Docs cleanup
408 408 * :ghpull:`3716`: raw_input fixes for kernel restarts
409 409 * :ghpull:`3683`: use `%matplotlib` in example notebooks
410 410 * :ghpull:`3686`: remove quarantine
411 411 * :ghpull:`3699`: svg2pdf unicode fix
412 412 * :ghpull:`3695`: fix SVG2PDF
413 413 * :ghpull:`3685`: fix Pager.detach
414 414 * :ghpull:`3675`: document new dependencies
415 415 * :ghpull:`3690`: Fixing some css minors in full_html and reveal.
416 416 * :ghpull:`3671`: nbconvert tests
417 417 * :ghpull:`3692`: Fix rename notebook - show error with invalid name
418 418 * :ghpull:`3409`: Prevent qtconsole frontend freeze on lots of output.
419 419 * :ghpull:`3660`: refocus active cell on dialog close
420 420 * :ghpull:`3598`: Statelessify mathjaxutils
421 421 * :ghpull:`3673`: enable comment/uncomment selection
422 422 * :ghpull:`3677`: remove special-case in get_home_dir for frozen dists
423 423 * :ghpull:`3674`: add CONTRIBUTING.md
424 424 * :ghpull:`3670`: use Popen command list for ipexec
425 425 * :ghpull:`3568`: pylab import adjustments
426 426 * :ghpull:`3559`: add create.Cell and delete.Cell js events
427 427 * :ghpull:`3606`: push cell magic to the head of the transformer line
428 428 * :ghpull:`3607`: NbConvert: Writers, No YAML, and stuff...
429 429 * :ghpull:`3665`: Pywin32 skips
430 430 * :ghpull:`3669`: set default client_class for QtKernelManager
431 431 * :ghpull:`3662`: add strip_encoding_cookie transformer
432 432 * :ghpull:`3641`: increase patience for slow kernel startup in tests
433 433 * :ghpull:`3651`: remove a bunch of unused `default_config_file` assignments
434 434 * :ghpull:`3630`: CSS adjustments
435 435 * :ghpull:`3645`: Don't require HistoryManager to have a shell
436 436 * :ghpull:`3643`: don't assume tested ipython is on the PATH
437 437 * :ghpull:`3654`: fix single-result AsyncResults
438 438 * :ghpull:`3601`: Markdown in heading cells (take 2)
439 439 * :ghpull:`3652`: Remove old `docs/examples`
440 440 * :ghpull:`3621`: catch any exception appending output
441 441 * :ghpull:`3585`: don't blacklist builtin names
442 442 * :ghpull:`3647`: Fix `frontend` deprecation warnings in several examples
443 443 * :ghpull:`3649`: fix AsyncResult.get_dict for single result
444 444 * :ghpull:`3648`: Fix store magic test
445 445 * :ghpull:`3650`: Fix, config_file_name was ignored
446 446 * :ghpull:`3640`: Gcf.get_active() can return None
447 447 * :ghpull:`3571`: Added shorcuts to split cell, merge cell above and merge cell below.
448 448 * :ghpull:`3635`: Added missing slash to print-pdf call.
449 449 * :ghpull:`3487`: Drop patch for compatibility with pyreadline 1.5
450 450 * :ghpull:`3338`: Allow filename with extension in find_cmd in Windows.
451 451 * :ghpull:`3628`: Fix test for Python 3 on Windows.
452 452 * :ghpull:`3642`: Fix typo in docs
453 453 * :ghpull:`3627`: use DEFAULT_STATIC_FILES_PATH in a test instead of package dir
454 454 * :ghpull:`3624`: fix some unicode in zmqhandlers
455 455 * :ghpull:`3460`: Set calling program to UNKNOWN, when argv not in sys
456 456 * :ghpull:`3632`: Set calling program to UNKNOWN, when argv not in sys (take #2)
457 457 * :ghpull:`3629`: Use new entry point for python -m IPython
458 458 * :ghpull:`3626`: passing cell to showInPager, closes #3625
459 459 * :ghpull:`3618`: expand terminal color support
460 460 * :ghpull:`3623`: raise UsageError for unsupported GUI backends
461 461 * :ghpull:`3071`: Add magic function %drun to run code in debugger
462 462 * :ghpull:`3608`: a nicer error message when using %pylab magic
463 463 * :ghpull:`3592`: add extra_config_file
464 464 * :ghpull:`3612`: updated .mailmap
465 465 * :ghpull:`3616`: Add examples for interactive use of MPI.
466 466 * :ghpull:`3615`: fix regular expression for ANSI escapes
467 467 * :ghpull:`3586`: Corrected a typo in the format string for strftime the sphinx.py transformer of nbconvert
468 468 * :ghpull:`3611`: check for markdown no longer needed, closes #3610
469 469 * :ghpull:`3555`: Simplify caching of modules with %run
470 470 * :ghpull:`3583`: notebook small things
471 471 * :ghpull:`3594`: Fix duplicate completion in notebook
472 472 * :ghpull:`3600`: parallel: Improved logging for errors during BatchSystemLauncher.stop
473 473 * :ghpull:`3595`: Revert "allow markdown in heading cells"
474 474 * :ghpull:`3538`: add IPython.start_ipython
475 475 * :ghpull:`3562`: Allow custom nbconvert template loaders
476 476 * :ghpull:`3582`: pandoc adjustments
477 477 * :ghpull:`3560`: Remove max_msg_size
478 478 * :ghpull:`3591`: Refer to Setuptools instead of Distribute
479 479 * :ghpull:`3590`: IPython.sphinxext needs an __init__.py
480 480 * :ghpull:`3581`: Added the possibility to read a custom.css file for tweaking the final html in full_html and reveal templates.
481 481 * :ghpull:`3576`: Added support for markdown in heading cells when they are nbconverted.
482 482 * :ghpull:`3575`: tweak `run -d` message to 'continue execution'
483 483 * :ghpull:`3569`: add PYTHONSTARTUP to startup files
484 484 * :ghpull:`3567`: Trigger a single event on js app initilized
485 485 * :ghpull:`3565`: style.min.css shoudl always exist...
486 486 * :ghpull:`3531`: allow markdown in heading cells
487 487 * :ghpull:`3577`: Simplify codemirror ipython-mode
488 488 * :ghpull:`3495`: Simplified regexp, and suggestions for clearer regexps.
489 489 * :ghpull:`3578`: Use adjustbox to specify figure size in nbconvert -> latex
490 490 * :ghpull:`3572`: Skip import irunner test on Windows.
491 491 * :ghpull:`3574`: correct static path for CM modes autoload
492 492 * :ghpull:`3558`: Add IPython.sphinxext
493 493 * :ghpull:`3561`: mention double-control-C to stop notebook server
494 494 * :ghpull:`3566`: fix event names
495 495 * :ghpull:`3564`: Remove trivial nbconvert example
496 496 * :ghpull:`3540`: allow cython cache dir to be deleted
497 497 * :ghpull:`3527`: cleanup stale, unused exceptions in parallel.error
498 498 * :ghpull:`3529`: ensure raw_input returns str in zmq shell
499 499 * :ghpull:`3541`: respect image size metadata in qtconsole
500 500 * :ghpull:`3550`: Fixing issue preventing the correct read of images by full_html and reveal exporters.
501 501 * :ghpull:`3557`: open markdown links in new tabs
502 502 * :ghpull:`3556`: remove mention of nonexistent `_margv` in macro
503 503 * :ghpull:`3552`: set overflow-x: hidden on Firefox only
504 504 * :ghpull:`3554`: Fix missing import os in latex exporter.
505 505 * :ghpull:`3546`: Don't hardcode **latex** posix paths in nbconvert
506 506 * :ghpull:`3551`: fix path prefix in nbconvert
507 507 * :ghpull:`3533`: Use a CDN to get reveal.js library.
508 508 * :ghpull:`3498`: When a notebook is written to file, name the metadata name u''.
509 509 * :ghpull:`3548`: Change to standard save icon in Notebook toolbar
510 510 * :ghpull:`3539`: Don't hardcode posix paths in nbconvert
511 511 * :ghpull:`3508`: notebook supports raw_input and %debug now
512 512 * :ghpull:`3526`: ensure 'default' is first in cluster profile list
513 513 * :ghpull:`3525`: basic timezone info
514 514 * :ghpull:`3532`: include nbconvert templates in installation
515 515 * :ghpull:`3515`: update CodeMirror component to 3.14
516 516 * :ghpull:`3513`: add 'No Checkpoints' to Revert menu
517 517 * :ghpull:`3536`: format positions are required in Python 2.6.x
518 518 * :ghpull:`3521`: Nbconvert fix, silent fail if template doesn't exist
519 519 * :ghpull:`3530`: update %store magic docstring
520 520 * :ghpull:`3528`: fix local mathjax with custom base_project_url
521 521 * :ghpull:`3518`: Clear up unused imports
522 522 * :ghpull:`3506`: %store -r restores saved aliases and directory history, as well as variables
523 523 * :ghpull:`3516`: make css highlight style configurable
524 524 * :ghpull:`3523`: Exclude frontend shim from docs build
525 525 * :ghpull:`3514`: use bootstrap `disabled` instead of `ui-state-disabled`
526 526 * :ghpull:`3520`: Added relative import of RevealExporter to __init__.py inside exporters module
527 527 * :ghpull:`3507`: fix HTML capitalization in nbconvert exporter classes
528 528 * :ghpull:`3512`: fix nbconvert filter validation
529 529 * :ghpull:`3511`: Get Tracer working after ipapi.get replaced with get_ipython
530 530 * :ghpull:`3510`: use `window.onbeforeunload=` for nav-away warning
531 531 * :ghpull:`3504`: don't use parent=self in handlers
532 532 * :ghpull:`3500`: Merge nbconvert into IPython
533 533 * :ghpull:`3478`: restore "unsaved changes" warning on unload
534 534 * :ghpull:`3493`: add a dialog when the kernel is auto-restarted
535 535 * :ghpull:`3488`: Add test suite for autoreload extension
536 536 * :ghpull:`3484`: Catch some pathological cases inside oinspect
537 537 * :ghpull:`3481`: Display R errors without Python traceback
538 538 * :ghpull:`3468`: fix `%magic` output
539 539 * :ghpull:`3430`: add parent to Configurable
540 540 * :ghpull:`3491`: Remove unexpected keyword parameter to remove_kernel
541 541 * :ghpull:`3485`: SymPy has changed its recommended way to initialize printing
542 542 * :ghpull:`3486`: Add test for non-ascii characters in docstrings
543 543 * :ghpull:`3483`: Inputtransformer: Allow classic prompts without space
544 544 * :ghpull:`3482`: Use an absolute path to iptest, because the tests are not always run from $IPYTHONDIR.
545 545 * :ghpull:`3381`: enable 2x (retina) display
546 546 * :ghpull:`3450`: Flatten IPython.frontend
547 547 * :ghpull:`3477`: pass config to subapps
548 548 * :ghpull:`3466`: Kernel fails to start when username has non-ascii characters
549 549 * :ghpull:`3465`: Add HTCondor bindings to IPython.parallel
550 550 * :ghpull:`3463`: fix typo, closes #3462
551 551 * :ghpull:`3456`: Notice for users who disable javascript
552 552 * :ghpull:`3453`: fix cell execution in firefox, closes #3447
553 553 * :ghpull:`3393`: [WIP] bootstrapify
554 554 * :ghpull:`3440`: Fix installing mathjax from downloaded file via command line
555 555 * :ghpull:`3431`: Provide means for starting the Qt console maximized and with the menu bar hidden
556 556 * :ghpull:`3425`: base IPClusterApp inherits from BaseIPythonApp
557 557 * :ghpull:`3433`: Update IPython\external\path\__init__.py
558 558 * :ghpull:`3298`: Some fixes in IPython Sphinx directive
559 559 * :ghpull:`3428`: process escapes in mathjax
560 560 * :ghpull:`3420`: thansk -> thanks
561 561 * :ghpull:`3416`: Fix doc: "principle" not "principal"
562 562 * :ghpull:`3413`: more unique filename for test
563 563 * :ghpull:`3364`: Inject requirejs in notebook and start using it.
564 564 * :ghpull:`3390`: Fix %paste with blank lines
565 565 * :ghpull:`3403`: fix creating config objects from dicts
566 566 * :ghpull:`3401`: rollback #3358
567 567 * :ghpull:`3373`: make cookie_secret configurable
568 568 * :ghpull:`3307`: switch default ws_url logic to js side
569 569 * :ghpull:`3392`: Restore anchor link on h2-h6
570 570 * :ghpull:`3369`: Use different treshold for (auto)scroll in output
571 571 * :ghpull:`3370`: normalize unicode notebook filenames
572 572 * :ghpull:`3372`: base default cookie name on request host+port
573 573 * :ghpull:`3378`: disable CodeMirror drag/drop on Safari
574 574 * :ghpull:`3358`: workaround spurious CodeMirror scrollbars
575 575 * :ghpull:`3371`: make setting the notebook dirty flag an event
576 576 * :ghpull:`3366`: remove long-dead zmq frontend.py and completer.py
577 577 * :ghpull:`3382`: cull Session digest history
578 578 * :ghpull:`3330`: Fix get_ipython_dir when $HOME is /
579 579 * :ghpull:`3319`: IPEP 13: user-expressions and user-variables
580 580 * :ghpull:`3384`: comments in tools/gitwash_dumper.py changed (''' to """)
581 581 * :ghpull:`3387`: Make submodule checks work under Python 3.
582 582 * :ghpull:`3357`: move anchor-link off of heading text
583 583 * :ghpull:`3351`: start basic tests of ipcluster Launchers
584 584 * :ghpull:`3377`: allow class.__module__ to be None
585 585 * :ghpull:`3340`: skip submodule check in package managers
586 586 * :ghpull:`3328`: decode subprocess output in launchers
587 587 * :ghpull:`3368`: Reenable bracket matching
588 588 * :ghpull:`3356`: Mpr fixes
589 589 * :ghpull:`3336`: Use new input transformation API in %time magic
590 590 * :ghpull:`3325`: Organize the JS and less files by component.
591 591 * :ghpull:`3342`: fix test_find_cmd_python
592 592 * :ghpull:`3354`: catch socket.error in utils.localinterfaces
593 593 * :ghpull:`3341`: fix default cluster count
594 594 * :ghpull:`3286`: don't use `get_ipython` from builtins in library code
595 595 * :ghpull:`3333`: notebookapp: add missing whitespace to warnings
596 596 * :ghpull:`3323`: Strip prompts even if the prompt isn't present on the first line.
597 597 * :ghpull:`3321`: Reorganize the python/server side of the notebook
598 598 * :ghpull:`3320`: define `__file__` in config files
599 599 * :ghpull:`3317`: rename `%%file` to `%%writefile`
600 600 * :ghpull:`3304`: set unlimited HWM for all relay devices
601 601 * :ghpull:`3315`: Update Sympy_printing extension load
602 602 * :ghpull:`3310`: further clarify Image docstring
603 603 * :ghpull:`3285`: load extensions in builtin trap
604 604 * :ghpull:`3308`: Speed up AsyncResult._wait_for_outputs(0)
605 605 * :ghpull:`3294`: fix callbacks as optional in js kernel.execute
606 606 * :ghpull:`3276`: Fix: "python ABS/PATH/TO/ipython.py" fails
607 607 * :ghpull:`3301`: allow python3 tests without python installed
608 608 * :ghpull:`3282`: allow view.map to work with a few more things
609 609 * :ghpull:`3284`: remove `ipython.py` entry point
610 610 * :ghpull:`3281`: fix ignored IOPub messages with no parent
611 611 * :ghpull:`3275`: improve submodule messages / git hooks
612 612 * :ghpull:`3239`: Allow "x" icon and esc key to close pager in notebook
613 613 * :ghpull:`3290`: Improved heartbeat controller to engine monitoring for long running tasks
614 614 * :ghpull:`3142`: Better error message when CWD doesn't exist on startup
615 615 * :ghpull:`3066`: Add support for relative import to %run -m (fixes #2727)
616 616 * :ghpull:`3269`: protect highlight.js against unknown languages
617 617 * :ghpull:`3267`: add missing return
618 618 * :ghpull:`3101`: use marked / highlight.js instead of pagedown and prettify
619 619 * :ghpull:`3264`: use https url for submodule
620 620 * :ghpull:`3263`: fix set_last_checkpoint when no checkpoint
621 621 * :ghpull:`3258`: Fix submodule location in setup.py
622 622 * :ghpull:`3254`: fix a few URLs from previous PR
623 623 * :ghpull:`3240`: remove js components from the repo
624 624 * :ghpull:`3158`: IPEP 15: autosave the notebook
625 625 * :ghpull:`3252`: move images out of _static folder into _images
626 626 * :ghpull:`3251`: Fix for cell magics in Qt console
627 627 * :ghpull:`3250`: Added a simple __html__() method to the HTML class
628 628 * :ghpull:`3249`: remove copy of sphinx inheritance_diagram.py
629 629 * :ghpull:`3235`: Remove the unused print notebook view
630 630 * :ghpull:`3238`: Improve the design of the tab completion UI
631 631 * :ghpull:`3242`: Make changes of Application.log_format effective
632 632 * :ghpull:`3219`: Workaround so only one CTRL-C is required for a new prompt in --gui=qt
633 633 * :ghpull:`3190`: allow formatters to specify metadata
634 634 * :ghpull:`3231`: improve discovery of public IPs
635 635 * :ghpull:`3233`: check prefixes for swallowing kernel args
636 636 * :ghpull:`3234`: Removing old autogrow JS code.
637 637 * :ghpull:`3232`: Update to CodeMirror 3 and start to ship our components
638 638 * :ghpull:`3229`: The HTML output type accidentally got removed from the OutputArea.
639 639 * :ghpull:`3228`: Typo in IPython.Parallel documentation
640 640 * :ghpull:`3226`: Text in rename dialog was way too big - making it <p>.
641 641 * :ghpull:`3225`: Removing old restuctured text handler and web service.
642 642 * :ghpull:`3222`: make BlockingKernelClient the default Client
643 643 * :ghpull:`3223`: add missing mathjax_url to new settings dict
644 644 * :ghpull:`3089`: add stdin to the notebook
645 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 647 * :ghpull:`3088`: cleanup IPython handler settings
648 648 * :ghpull:`3201`: use much faster regexp for ansi coloring
649 649 * :ghpull:`3220`: avoid race condition in profile creation
650 650 * :ghpull:`3011`: IPEP 12: add KernelClient
651 651 * :ghpull:`3217`: informative error when trying to load directories
652 652 * :ghpull:`3174`: Simple class
653 653 * :ghpull:`2979`: CM configurable Take 2
654 654 * :ghpull:`3215`: Updates storemagic extension to allow for specifying variable name to load
655 655 * :ghpull:`3181`: backport If-Modified-Since fix from tornado
656 656 * :ghpull:`3200`: IFrame (VimeoVideo, ScribdDocument, ...)
657 657 * :ghpull:`3186`: Fix small inconsistency in nbconvert: etype -> ename
658 658 * :ghpull:`3212`: Fix issue #2563, "core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation"
659 659 * :ghpull:`3211`: Fix inheritance_diagram Sphinx extension for Sphinx 1.2
660 660 * :ghpull:`3208`: Update link to extensions index
661 661 * :ghpull:`3203`: Separate InputSplitter for transforming whole cells
662 662 * :ghpull:`3189`: Improve completer
663 663 * :ghpull:`3194`: finish up PR #3116
664 664 * :ghpull:`3188`: Add new keycodes
665 665 * :ghpull:`2695`: Key the root modules cache by sys.path entries.
666 666 * :ghpull:`3182`: clarify %%file docstring
667 667 * :ghpull:`3163`: BUG: Fix the set and frozenset pretty printer to handle the empty case correctly
668 668 * :ghpull:`3180`: better UsageError for cell magic with no body
669 669 * :ghpull:`3184`: Cython cache
670 670 * :ghpull:`3175`: Added missing s
671 671 * :ghpull:`3173`: Little bits of documentation cleanup
672 672 * :ghpull:`2635`: Improve Windows start menu shortcuts (#2)
673 673 * :ghpull:`3172`: Add missing import in IPython parallel magics example
674 674 * :ghpull:`3170`: default application logger shouldn't propagate
675 675 * :ghpull:`3159`: Autocompletion for zsh
676 676 * :ghpull:`3105`: move DEFAULT_STATIC_FILES_PATH to IPython.html
677 677 * :ghpull:`3144`: minor bower tweaks
678 678 * :ghpull:`3141`: Default color output for ls on OSX
679 679 * :ghpull:`3137`: fix dot syntax error in inheritance diagram
680 680 * :ghpull:`3072`: raise UnsupportedOperation on iostream.fileno()
681 681 * :ghpull:`3147`: Notebook support for a reverse proxy which handles SSL
682 682 * :ghpull:`3152`: make qtconsole size at startup configurable
683 683 * :ghpull:`3162`: adding stream kwarg to current.new_output
684 684 * :ghpull:`2981`: IPEP 10: kernel side filtering of display formats
685 685 * :ghpull:`3058`: add redirect handler for notebooks by name
686 686 * :ghpull:`3041`: support non-modules in @require
687 687 * :ghpull:`2447`: Stateful line transformers
688 688 * :ghpull:`3108`: fix some O(N) and O(N^2) operations in parallel.map
689 689 * :ghpull:`2791`: forward stdout from forked processes
690 690 * :ghpull:`3157`: use Python 3-style for pretty-printed sets
691 691 * :ghpull:`3148`: closes #3045, #3123 for tornado < version 3.0
692 692 * :ghpull:`3143`: minor heading-link tweaks
693 693 * :ghpull:`3136`: Strip useless ANSI escape codes in notebook
694 694 * :ghpull:`3126`: Prevent errors when pressing arrow keys in an empty notebook
695 695 * :ghpull:`3135`: quick dev installation instructions
696 696 * :ghpull:`2889`: Push pandas dataframes to R magic
697 697 * :ghpull:`3068`: Don't monkeypatch doctest during IPython startup.
698 698 * :ghpull:`3133`: fix argparse version check
699 699 * :ghpull:`3102`: set `spellcheck=false` in CodeCell inputarea
700 700 * :ghpull:`3064`: add anchors to heading cells
701 701 * :ghpull:`3097`: PyQt 4.10: use self._document = self.document()
702 702 * :ghpull:`3117`: propagate automagic change to shell
703 703 * :ghpull:`3118`: don't give up on weird os names
704 704 * :ghpull:`3115`: Fix example
705 705 * :ghpull:`2640`: fix quarantine/ipy_editors.py
706 706 * :ghpull:`3070`: Add info make target that was missing in old Sphinx
707 707 * :ghpull:`3082`: A few small patches to image handling
708 708 * :ghpull:`3078`: fix regular expression for detecting links in stdout
709 709 * :ghpull:`3054`: restore default behavior for automatic cluster size
710 710 * :ghpull:`3073`: fix ipython usage text
711 711 * :ghpull:`3083`: fix DisplayMagics.html docstring
712 712 * :ghpull:`3080`: noted sub_channel being renamed to iopub_channel
713 713 * :ghpull:`3079`: actually use IPKernelApp.kernel_class
714 714 * :ghpull:`3076`: Improve notebook.js documentation
715 715 * :ghpull:`3063`: add missing `%%html` magic
716 716 * :ghpull:`3075`: check for SIGUSR1 before using it, closes #3074
717 717 * :ghpull:`3051`: add width:100% to vbox for webkit / FF consistency
718 718 * :ghpull:`2999`: increase registration timeout
719 719 * :ghpull:`2997`: fix DictDB default size limit
720 720 * :ghpull:`3033`: on resume, print server info again
721 721 * :ghpull:`3062`: test double pyximport
722 722 * :ghpull:`3046`: cast kernel cwd to bytes on Python 2 on Windows
723 723 * :ghpull:`3038`: remove xml from notebook magic docstrings
724 724 * :ghpull:`3032`: fix time format to international time format
725 725 * :ghpull:`3022`: Fix test for Windows
726 726 * :ghpull:`3024`: changed instances of 'outout' to 'output' in alt texts
727 727 * :ghpull:`3013`: py3 workaround for reload in cythonmagic
728 728 * :ghpull:`2961`: time magic: shorten unnecessary output on windows
729 729 * :ghpull:`2987`: fix local files examples in markdown
730 730 * :ghpull:`2998`: fix css in .output_area pre
731 731 * :ghpull:`3003`: add $include /etc/inputrc to suggested ~/.inputrc
732 732 * :ghpull:`2957`: Refactor qt import logic. Fixes #2955
733 733 * :ghpull:`2994`: expanduser on %%file targets
734 734 * :ghpull:`2983`: fix run-all (that-> this)
735 735 * :ghpull:`2964`: fix count when testing composite error output
736 736 * :ghpull:`2967`: shows entire session history when only startsess is given
737 737 * :ghpull:`2942`: Move CM IPython theme out of codemirror folder
738 738 * :ghpull:`2929`: Cleanup cell insertion
739 739 * :ghpull:`2933`: Minordocupdate
740 740 * :ghpull:`2968`: fix notebook deletion.
741 741 * :ghpull:`2966`: Added assert msg to extract_hist_ranges()
742 742 * :ghpull:`2959`: Add command to trim the history database.
743 743 * :ghpull:`2681`: Don't enable pylab mode, when matplotlib is not importable
744 744 * :ghpull:`2901`: Fix inputhook_wx on osx
745 745 * :ghpull:`2871`: truncate potentially long CompositeErrors
746 746 * :ghpull:`2951`: use istype on lists/tuples
747 747 * :ghpull:`2946`: fix qtconsole history logic for end-of-line
748 748 * :ghpull:`2954`: fix logic for append_javascript
749 749 * :ghpull:`2941`: fix baseUrl
750 750 * :ghpull:`2903`: Specify toggle value on cell line number
751 751 * :ghpull:`2911`: display order in output area configurable
752 752 * :ghpull:`2897`: Dont rely on BaseProjectUrl data in body tag
753 753 * :ghpull:`2894`: Cm configurable
754 754 * :ghpull:`2927`: next release will be 1.0
755 755 * :ghpull:`2932`: Simplify using notebook static files from external code
756 756 * :ghpull:`2915`: added small config section to notebook docs page
757 757 * :ghpull:`2924`: safe_run_module: Silence SystemExit codes 0 and None.
758 758 * :ghpull:`2906`: Unpatch/Monkey patch CM
759 759 * :ghpull:`2921`: add menu item for undo delete cell
760 760 * :ghpull:`2917`: Don't add logging handler if one already exists.
761 761 * :ghpull:`2910`: Respect DB_IP and DB_PORT in mongodb tests
762 762 * :ghpull:`2926`: Don't die if stderr/stdout do not support set_parent() #2925
763 763 * :ghpull:`2885`: get monospace pager back
764 764 * :ghpull:`2876`: fix celltoolbar layout on FF
765 765 * :ghpull:`2904`: Skip remaining IPC test on Windows
766 766 * :ghpull:`2908`: fix last remaining KernelApp reference
767 767 * :ghpull:`2905`: fix a few remaining KernelApp/IPKernelApp changes
768 768 * :ghpull:`2900`: Don't assume test case for %time will finish in 0 time
769 769 * :ghpull:`2893`: exclude fabfile from tests
770 770 * :ghpull:`2884`: Correct import for kernelmanager on Windows
771 771 * :ghpull:`2882`: Utils cleanup
772 772 * :ghpull:`2883`: Don't call ast.fix_missing_locations unless the AST could have been modified
773 773 * :ghpull:`2855`: time(it) magic: Implement minutes/hour formatting and "%%time" cell magic
774 774 * :ghpull:`2874`: Empty cell warnings
775 775 * :ghpull:`2819`: tweak history prefix search (up/^p) in qtconsole
776 776 * :ghpull:`2868`: Import performance
777 777 * :ghpull:`2877`: minor css fixes
778 778 * :ghpull:`2880`: update examples docs with kernel move
779 779 * :ghpull:`2878`: Pass host environment on to kernel
780 780 * :ghpull:`2599`: func_kw_complete for builtin and cython with embededsignature=True using docstring
781 781 * :ghpull:`2792`: Add key "unique" to history_request protocol
782 782 * :ghpull:`2872`: fix payload keys
783 783 * :ghpull:`2869`: Fixing styling of toolbar selects on FF.
784 784 * :ghpull:`2708`: Less css
785 785 * :ghpull:`2854`: Move kernel code into IPython.kernel
786 786 * :ghpull:`2864`: Fix %run -t -N<N> TypeError
787 787 * :ghpull:`2852`: future pyzmq compatibility
788 788 * :ghpull:`2863`: whatsnew/version0.9.txt: Fix '~./ipython' -> '~/.ipython' typo
789 789 * :ghpull:`2861`: add missing KernelManager to ConsoleApp class list
790 790 * :ghpull:`2850`: Consolidate host IP detection in utils.localinterfaces
791 791 * :ghpull:`2859`: Correct docstring of ipython.py
792 792 * :ghpull:`2831`: avoid string version comparisons in external.qt
793 793 * :ghpull:`2844`: this should address the failure in #2732
794 794 * :ghpull:`2849`: utils/data: Use list comprehension for uniq_stable()
795 795 * :ghpull:`2839`: add jinja to install docs / setup.py
796 796 * :ghpull:`2841`: Miscellaneous docs fixes
797 797 * :ghpull:`2811`: Still more KernelManager cleanup
798 798 * :ghpull:`2820`: add '=' to greedy completer delims
799 799 * :ghpull:`2818`: log user tracebacks in the kernel (INFO-level)
800 800 * :ghpull:`2828`: Clean up notebook Javascript
801 801 * :ghpull:`2829`: avoid comparison error in dictdb hub history
802 802 * :ghpull:`2830`: BUG: Opening parenthesis after non-callable raises ValueError
803 803 * :ghpull:`2718`: try to fallback to pysqlite2.dbapi2 as sqlite3 in core.history
804 804 * :ghpull:`2816`: in %edit, don't save "last_call" unless last call succeeded
805 805 * :ghpull:`2817`: change ol format order
806 806 * :ghpull:`2537`: Organize example notebooks
807 807 * :ghpull:`2815`: update release/authors
808 808 * :ghpull:`2808`: improve patience for slow Hub in client tests
809 809 * :ghpull:`2812`: remove nonfunctional `-la` short arg in cython magic
810 810 * :ghpull:`2810`: remove dead utils.upgradedir
811 811 * :ghpull:`1671`: __future__ environments
812 812 * :ghpull:`2804`: skip ipc tests on Windows
813 813 * :ghpull:`2789`: Fixing styling issues with CellToolbar.
814 814 * :ghpull:`2805`: fix KeyError creating ZMQStreams in notebook
815 815 * :ghpull:`2775`: General cleanup of kernel manager code.
816 816 * :ghpull:`2340`: Initial Code to reduce parallel.Client caching
817 817 * :ghpull:`2799`: Exit code
818 818 * :ghpull:`2800`: use `type(obj) is cls` as switch when canning
819 819 * :ghpull:`2801`: Fix a breakpoint bug
820 820 * :ghpull:`2795`: Remove outdated code from extensions.autoreload
821 821 * :ghpull:`2796`: P3K: fix cookie parsing under Python 3.x (+ duplicate import is removed)
822 822 * :ghpull:`2724`: In-process kernel support (take 3)
823 823 * :ghpull:`2687`: [WIP] Metaui slideshow
824 824 * :ghpull:`2788`: Chrome frame awareness
825 825 * :ghpull:`2649`: Add version_request/reply messaging protocol
826 826 * :ghpull:`2753`: add `%%px --local` for local execution
827 827 * :ghpull:`2783`: Prefilter shouldn't touch execution_count
828 828 * :ghpull:`2333`: UI For Metadata
829 829 * :ghpull:`2396`: create a ipynbv3 json schema and a validator
830 830 * :ghpull:`2757`: check for complete pyside presence before trying to import
831 831 * :ghpull:`2782`: Allow the %run magic with '-b' to specify a file.
832 832 * :ghpull:`2778`: P3K: fix DeprecationWarning under Python 3.x
833 833 * :ghpull:`2776`: remove non-functional View.kill method
834 834 * :ghpull:`2755`: can interactively defined classes
835 835 * :ghpull:`2774`: Removing unused code in the notebook MappingKernelManager.
836 836 * :ghpull:`2773`: Fixed minor typo causing AttributeError to be thrown.
837 837 * :ghpull:`2609`: Add 'unique' option to history_request messaging protocol
838 838 * :ghpull:`2769`: Allow shutdown when no engines are registered
839 839 * :ghpull:`2766`: Define __file__ when we %edit a real file.
840 840 * :ghpull:`2476`: allow %edit <variable> to work when interactively defined
841 841 * :ghpull:`2763`: Reset readline delimiters after loading rmagic.
842 842 * :ghpull:`2460`: Better handling of `__file__` when running scripts.
843 843 * :ghpull:`2617`: Fix for `units` argument. Adds a `res` argument.
844 844 * :ghpull:`2738`: Unicode content crashes the pager (console)
845 845 * :ghpull:`2749`: Tell Travis CI to test on Python 3.3 as well
846 846 * :ghpull:`2744`: Don't show 'try %paste' message while using magics
847 847 * :ghpull:`2728`: shift tab for tooltip
848 848 * :ghpull:`2741`: Add note to `%cython` Black-Scholes example warning of missing erf.
849 849 * :ghpull:`2743`: BUG: Octavemagic inline plots not working on Windows: Fixed
850 850 * :ghpull:`2740`: Following #2737 this error is now a name error
851 851 * :ghpull:`2737`: Rmagic: error message when moving an non-existant variable from python to R
852 852 * :ghpull:`2723`: diverse fixes for project url
853 853 * :ghpull:`2731`: %Rpush: Look for variables in the local scope first.
854 854 * :ghpull:`2544`: Infinite loop when multiple debuggers have been attached.
855 855 * :ghpull:`2726`: Add qthelp docs creation
856 856 * :ghpull:`2730`: added blockquote CSS
857 857 * :ghpull:`2729`: Fix Read the doc build, Again
858 858 * :ghpull:`2446`: [alternate 2267] Offline mathjax
859 859 * :ghpull:`2716`: remove unexisting headings level
860 860 * :ghpull:`2717`: One liner to fix debugger printing stack traces when lines of context are larger than source.
861 861 * :ghpull:`2713`: Doc bugfix: user_ns is not an attribute of Magic objects.
862 862 * :ghpull:`2690`: Fix 'import '... completion for py3 & egg files.
863 863 * :ghpull:`2691`: Document OpenMP in %%cython magic
864 864 * :ghpull:`2699`: fix jinja2 rendering for password protected notebooks
865 865 * :ghpull:`2700`: Skip notebook testing if jinja2 is not available.
866 866 * :ghpull:`2692`: Add %%cython magics to generated documentation.
867 867 * :ghpull:`2685`: Fix pretty print of types when `__module__` is not available.
868 868 * :ghpull:`2686`: Fix tox.ini
869 869 * :ghpull:`2604`: Backslashes are misinterpreted as escape-sequences by the R-interpreter.
870 870 * :ghpull:`2689`: fix error in doc (arg->kwarg) and pep-8
871 871 * :ghpull:`2683`: for downloads, replaced window.open with window.location.assign
872 872 * :ghpull:`2659`: small bugs in js are fixed
873 873 * :ghpull:`2363`: Refactor notebook templates to use Jinja2
874 874 * :ghpull:`2662`: qtconsole: wrap argument list in tooltip to match width of text body
875 875 * :ghpull:`2328`: addition of classes to generate a link or list of links from files local to the IPython HTML notebook
876 876 * :ghpull:`2668`: pylab_not_importable: Catch all exceptions, not just RuntimeErrors.
877 877 * :ghpull:`2663`: Fix issue #2660: parsing of help and version arguments
878 878 * :ghpull:`2656`: Fix irunner tests when $PYTHONSTARTUP is set
879 879 * :ghpull:`2312`: Add bracket matching to code cells in notebook
880 880 * :ghpull:`2571`: Start to document Javascript
881 881 * :ghpull:`2641`: undefinied that -> this
882 882 * :ghpull:`2638`: Fix %paste in Python 3 on Mac
883 883 * :ghpull:`2301`: Ast transfomers
884 884 * :ghpull:`2616`: Revamp API docs
885 885 * :ghpull:`2572`: Make 'Paste Above' the default paste behavior.
886 886 * :ghpull:`2574`: Fix #2244
887 887 * :ghpull:`2582`: Fix displaying history when output cache is disabled.
888 888 * :ghpull:`2591`: Fix for Issue #2584
889 889 * :ghpull:`2526`: Don't kill paramiko tunnels when receiving ^C
890 890 * :ghpull:`2559`: Add psource, pfile, pinfo2 commands to ipdb.
891 891 * :ghpull:`2546`: use 4 Pythons to build 4 Windows installers
892 892 * :ghpull:`2561`: Fix display of plain text containing multiple carriage returns before line feed
893 893 * :ghpull:`2549`: Add a simple 'undo' for cell deletion.
894 894 * :ghpull:`2525`: Add event to kernel execution/shell reply.
895 895 * :ghpull:`2554`: Avoid stopping in ipdb until we reach the main script.
896 896 * :ghpull:`2404`: Option to limit search result in history magic command
897 897 * :ghpull:`2294`: inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication
898 898 * :ghpull:`2233`: Refactored Drag and Drop Support in Qt Console
899 899 * :ghpull:`1747`: switch between hsplit and vsplit paging (request for feedback)
900 900 * :ghpull:`2530`: Adding time offsets to the video
901 901 * :ghpull:`2542`: Allow starting IPython as `python -m IPython`.
902 902 * :ghpull:`2534`: Do not unescape backslashes in Windows (shellglob)
903 903 * :ghpull:`2517`: Improved MathJax, bug fixes
904 904 * :ghpull:`2511`: trigger default remote_profile_dir when profile_dir is set
905 905 * :ghpull:`2491`: color is supported in ironpython
906 906 * :ghpull:`2462`: Track which extensions are loaded
907 907 * :ghpull:`2464`: Locate URLs in text output and convert them to hyperlinks.
908 908 * :ghpull:`2490`: add ZMQInteractiveShell to IPEngineApp class list
909 909 * :ghpull:`2498`: Don't catch tab press when something selected
910 910 * :ghpull:`2527`: Run All Above and Run All Below
911 911 * :ghpull:`2513`: add GitHub uploads to release script
912 912 * :ghpull:`2529`: Windows aware tests for shellglob
913 913 * :ghpull:`2478`: Fix doctest_run_option_parser for Windows
914 914 * :ghpull:`2519`: clear In[ ] prompt numbers again
915 915 * :ghpull:`2467`: Clickable links
916 916 * :ghpull:`2500`: Add `encoding` attribute to `OutStream` class.
917 917 * :ghpull:`2349`: ENH: added StackExchange-style MathJax filtering
918 918 * :ghpull:`2503`: Fix traceback handling of SyntaxErrors without line numbers.
919 919 * :ghpull:`2492`: add missing 'qtconsole' extras_require
920 920 * :ghpull:`2480`: Add deprecation warnings for sympyprinting
921 921 * :ghpull:`2334`: Make the ipengine monitor the ipcontroller heartbeat and die if the ipcontroller goes down
922 922 * :ghpull:`2479`: use new _winapi instead of removed _subprocess
923 923 * :ghpull:`2474`: fix bootstrap name conflicts
924 924 * :ghpull:`2469`: Treat __init__.pyc same as __init__.py in module_list
925 925 * :ghpull:`2165`: Add -g option to %run to glob expand arguments
926 926 * :ghpull:`2468`: Tell git to ignore __pycache__ directories.
927 927 * :ghpull:`2421`: Some notebook tweaks.
928 928 * :ghpull:`2291`: Remove old plugin system
929 929 * :ghpull:`2127`: Ability to build toolbar in JS
930 930 * :ghpull:`2445`: changes for ironpython
931 931 * :ghpull:`2420`: Pass ipython_dir to __init__() method of TerminalInteractiveShell's superclass.
932 932 * :ghpull:`2432`: Revert #1831, the `__file__` injection in safe_execfile / safe_execfile_ipy.
933 933 * :ghpull:`2216`: Autochange highlight with cell magics
934 934 * :ghpull:`1946`: Add image message handler in ZMQTerminalInteractiveShell
935 935 * :ghpull:`2424`: skip find_cmd when setting up script magics
936 936 * :ghpull:`2389`: Catch sqlite DatabaseErrors in more places when reading the history database
937 937 * :ghpull:`2395`: Don't catch ImportError when trying to unpack module functions
938 938 * :ghpull:`1868`: enable IPC transport for kernels
939 939 * :ghpull:`2437`: don't let log cleanup prevent engine start
940 940 * :ghpull:`2441`: `sys.maxsize` is the maximum length of a container.
941 941 * :ghpull:`2442`: allow iptest to be interrupted
942 942 * :ghpull:`2240`: fix message built for engine dying during task
943 943 * :ghpull:`2369`: Block until kernel termination after sending a kill signal
944 944 * :ghpull:`2439`: Py3k: Octal (0777 -> 0o777)
945 945 * :ghpull:`2326`: Detachable pager in notebook.
946 946 * :ghpull:`2377`: Fix installation of man pages in Python 3
947 947 * :ghpull:`2407`: add IPython version to message headers
948 948 * :ghpull:`2408`: Fix Issue #2366
949 949 * :ghpull:`2405`: clarify TaskScheduler.hwm doc
950 950 * :ghpull:`2399`: IndentationError display
951 951 * :ghpull:`2400`: Add scroll_to_cell(cell_number) to the notebook
952 952 * :ghpull:`2401`: unmock read-the-docs modules
953 953 * :ghpull:`2311`: always perform requested trait assignments
954 954 * :ghpull:`2393`: New option `n` to limit history search hits
955 955 * :ghpull:`2386`: Adapt inline backend to changes in matplotlib
956 956 * :ghpull:`2392`: Remove suspicious double quote
957 957 * :ghpull:`2387`: Added -L library search path to cythonmagic cell magic
958 958 * :ghpull:`2370`: qtconsole: Create a prompt newline by inserting a new block (w/o formatting)
959 959 * :ghpull:`1715`: Fix for #1688, traceback-unicode issue
960 960 * :ghpull:`2378`: use Singleton.instance() for embed() instead of manual global
961 961 * :ghpull:`2373`: fix missing imports in core.interactiveshell
962 962 * :ghpull:`2368`: remove notification widget leftover
963 963 * :ghpull:`2327`: Parallel: Support get/set of nested objects in view (e.g. dv['a.b'])
964 964 * :ghpull:`2362`: Clean up ProgressBar class in example notebook
965 965 * :ghpull:`2346`: Extra xterm identification in set_term_title
966 966 * :ghpull:`2352`: Notebook: Store the username in a cookie whose name is unique.
967 967 * :ghpull:`2358`: add backport_pr to tools
968 968 * :ghpull:`2365`: fix names of notebooks for download/save
969 969 * :ghpull:`2364`: make clients use 'location' properly (fixes #2361)
970 970 * :ghpull:`2354`: Refactor notebook templates to use Jinja2
971 971 * :ghpull:`2339`: add bash completion example
972 972 * :ghpull:`2345`: Remove references to 'version' no longer in argparse. Github issue #2343.
973 973 * :ghpull:`2347`: adjust division error message checking to account for Python 3
974 974 * :ghpull:`2305`: RemoteError._render_traceback_ calls self.render_traceback
975 975 * :ghpull:`2338`: Normalize line endings for ipexec_validate, fix for #2315.
976 976 * :ghpull:`2192`: Introduce Notification Area
977 977 * :ghpull:`2329`: Better error messages for common magic commands.
978 978 * :ghpull:`2337`: ENH: added StackExchange-style MathJax filtering
979 979 * :ghpull:`2331`: update css for qtconsole in doc
980 980 * :ghpull:`2317`: adding cluster_id to parallel.Client.__init__
981 981 * :ghpull:`2130`: Add -l option to %R magic to allow passing in of local namespace
982 982 * :ghpull:`2196`: Fix for bad command line argument to latex
983 983 * :ghpull:`2300`: bug fix: was crashing when sqlite3 is not installed
984 984 * :ghpull:`2184`: Expose store_history to execute_request messages.
985 985 * :ghpull:`2308`: Add welcome_message option to enable_pylab
986 986 * :ghpull:`2302`: Fix variable expansion on 'self'
987 987 * :ghpull:`2299`: Remove code from prefilter that duplicates functionality in inputsplitter
988 988 * :ghpull:`2295`: allow pip install from github repository directly
989 989 * :ghpull:`2280`: fix SSH passwordless check for OpenSSH
990 990 * :ghpull:`2290`: nbmanager
991 991 * :ghpull:`2288`: s/assertEquals/assertEqual (again)
992 992 * :ghpull:`2287`: Removed outdated dev docs.
993 993 * :ghpull:`2218`: Use redirect for new notebooks
994 994 * :ghpull:`2277`: nb: up/down arrow keys move to begin/end of line at top/bottom of cell
995 995 * :ghpull:`2045`: Refactoring notebook managers and adding Azure backed storage.
996 996 * :ghpull:`2271`: use display instead of send_figure in inline backend hooks
997 997 * :ghpull:`2278`: allow disabling SQLite history
998 998 * :ghpull:`2225`: Add "--annotate" option to `%%cython` magic.
999 999 * :ghpull:`2246`: serialize individual args/kwargs rather than the containers
1000 1000 * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching.
1001 1001 * :ghpull:`2270`: SSHLauncher tweaks
1002 1002 * :ghpull:`2269`: add missing location when disambiguating controller IP
1003 1003 * :ghpull:`2263`: Allow docs to build on http://readthedocs.org/
1004 1004 * :ghpull:`2256`: Adding data publication example notebook.
1005 1005 * :ghpull:`2255`: better flush iopub with AsyncResults
1006 1006 * :ghpull:`2261`: Fix: longest_substr([]) -> ''
1007 1007 * :ghpull:`2260`: fix mpr again
1008 1008 * :ghpull:`2242`: Document globbing in `%history -g <pattern>`.
1009 1009 * :ghpull:`2250`: fix html in notebook example
1010 1010 * :ghpull:`2245`: Fix regression in embed() from pull-request #2096.
1011 1011 * :ghpull:`2248`: track sha of master in test_pr messages
1012 1012 * :ghpull:`2238`: Fast tests
1013 1013 * :ghpull:`2211`: add data publication message
1014 1014 * :ghpull:`2236`: minor test_pr tweaks
1015 1015 * :ghpull:`2231`: Improve Image format validation and add html width,height
1016 1016 * :ghpull:`2232`: Reapply monkeypatch to inspect.findsource()
1017 1017 * :ghpull:`2235`: remove spurious print statement from setupbase.py
1018 1018 * :ghpull:`2222`: adjust how canning deals with import strings
1019 1019 * :ghpull:`2224`: fix css typo
1020 1020 * :ghpull:`2223`: Custom tracebacks
1021 1021 * :ghpull:`2214`: use KernelApp.exec_lines/files in IPEngineApp
1022 1022 * :ghpull:`2199`: Wrap JS published by %%javascript in try/catch
1023 1023 * :ghpull:`2212`: catch errors in markdown javascript
1024 1024 * :ghpull:`2190`: Update code mirror 2.22 to 2.32
1025 1025 * :ghpull:`2200`: documentation build broken in bb429da5b
1026 1026 * :ghpull:`2194`: clean nan/inf in json_clean
1027 1027 * :ghpull:`2198`: fix mpr for earlier git version
1028 1028 * :ghpull:`2175`: add FileFindHandler for Notebook static files
1029 1029 * :ghpull:`1990`: can func_defaults
1030 1030 * :ghpull:`2069`: start improving serialization in parallel code
1031 1031 * :ghpull:`2202`: Create a unique & temporary IPYTHONDIR for each testing group.
1032 1032 * :ghpull:`2204`: Work around lack of os.kill in win32.
1033 1033 * :ghpull:`2148`: win32 iptest: Use subprocess.Popen() instead of os.system().
1034 1034 * :ghpull:`2179`: Pylab switch
1035 1035 * :ghpull:`2124`: Add an API for registering magic aliases.
1036 1036 * :ghpull:`2169`: ipdb: pdef, pdoc, pinfo magics all broken
1037 1037 * :ghpull:`2174`: Ensure consistent indentation in `%magic`.
1038 1038 * :ghpull:`1930`: add size-limiting to the DictDB backend
1039 1039 * :ghpull:`2189`: Fix IPython.lib.latextools for Python 3
1040 1040 * :ghpull:`2186`: removed references to h5py dependence in octave magic documentation
1041 1041 * :ghpull:`2183`: Include the kernel object in the event object passed to kernel events
1042 1042 * :ghpull:`2185`: added test for %store, fixed storemagic
1043 1043 * :ghpull:`2138`: Use breqn.sty in dvipng backend if possible
1044 1044 * :ghpull:`2182`: handle undefined param in notebooklist
1045 1045 * :ghpull:`1831`: fix #1814 set __file__ when running .ipy files
1046 1046 * :ghpull:`2051`: Add a metadata attribute to messages
1047 1047 * :ghpull:`1471`: simplify IPython.parallel connections and enable Controller Resume
1048 1048 * :ghpull:`2181`: add %%javascript, %%svg, and %%latex display magics
1049 1049 * :ghpull:`2116`: different images in 00_notebook-tour
1050 1050 * :ghpull:`2092`: %prun: Restore `stats.stream` after running `print_stream`.
1051 1051 * :ghpull:`2159`: show message on notebook list if server is unreachable
1052 1052 * :ghpull:`2176`: fix git mpr
1053 1053 * :ghpull:`2152`: [qtconsole] Namespace not empty at startup
1054 1054 * :ghpull:`2177`: remove numpy install from travis/tox scripts
1055 1055 * :ghpull:`2090`: New keybinding for code cell execution + cell insertion
1056 1056 * :ghpull:`2160`: Updating the parallel options pricing example
1057 1057 * :ghpull:`2168`: expand line in cell magics
1058 1058 * :ghpull:`2170`: Fix tab completion with IPython.embed_kernel().
1059 1059 * :ghpull:`2096`: embed(): Default to the future compiler flags of the calling frame.
1060 1060 * :ghpull:`2163`: fix 'remote_profie_dir' typo in SSH launchers
1061 1061 * :ghpull:`2158`: [2to3 compat ] Tuple params in func defs
1062 1062 * :ghpull:`2089`: Fix unittest DeprecationWarnings
1063 1063 * :ghpull:`2142`: Refactor test_pr.py
1064 1064 * :ghpull:`2140`: 2to3: Apply `has_key` fixer.
1065 1065 * :ghpull:`2131`: Add option append (-a) to %save
1066 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 1068 * :ghpull:`2134`: Apply 2to3 `next` fix.
1069 1069 * :ghpull:`2126`: ipcluster broken with any batch launcher (PBS/LSF/SGE)
1070 1070 * :ghpull:`2104`: Windows make file for Sphinx documentation
1071 1071 * :ghpull:`2074`: Make BG color of inline plot configurable
1072 1072 * :ghpull:`2123`: BUG: Look up the `_repr_pretty_` method on the class within the MRO rath...
1073 1073 * :ghpull:`2100`: [in progress] python 2 and 3 compatibility without 2to3, second try
1074 1074 * :ghpull:`2128`: open notebook copy in different tabs
1075 1075 * :ghpull:`2073`: allows password and prefix for notebook
1076 1076 * :ghpull:`1993`: Print View
1077 1077 * :ghpull:`2086`: re-aliad %ed to %edit in qtconsole
1078 1078 * :ghpull:`2110`: Fixes and improvements to the input splitter
1079 1079 * :ghpull:`2101`: fix completer deletting newline
1080 1080 * :ghpull:`2102`: Fix logging on interactive shell.
1081 1081 * :ghpull:`2088`: Fix (some) Python 3.2 ResourceWarnings
1082 1082 * :ghpull:`2064`: conform to pep 3110
1083 1083 * :ghpull:`2076`: Skip notebook 'static' dir in test suite.
1084 1084 * :ghpull:`2063`: Remove umlauts so py3 installations on LANG=C systems succeed.
1085 1085 * :ghpull:`2068`: record sysinfo in sdist
1086 1086 * :ghpull:`2067`: update tools/release_windows.py
1087 1087 * :ghpull:`2065`: Fix parentheses typo
1088 1088 * :ghpull:`2062`: Remove duplicates and auto-generated files from repo.
1089 1089 * :ghpull:`2061`: use explicit tuple in exception
1090 1090 * :ghpull:`2060`: change minus to \- or \(hy in manpages
1091 1091
1092 1092 Issues (691):
1093 1093
1094 1094 * :ghissue:`3940`: Install process documentation overhaul
1095 1095 * :ghissue:`3946`: The PDF option for `--post` should work with lowercase
1096 1096 * :ghissue:`3957`: Notebook help page broken in Firefox
1097 1097 * :ghissue:`3894`: nbconvert test failure
1098 1098 * :ghissue:`3887`: 1.0.0a1 shows blank screen in both firefox and chrome (windows 7)
1099 1099 * :ghissue:`3703`: `nbconvert`: Output options -- names and documentataion
1100 1100 * :ghissue:`3931`: Tab completion not working during debugging in the notebook
1101 1101 * :ghissue:`3936`: Ipcluster plugin is not working with Ipython 1.0dev
1102 1102 * :ghissue:`3941`: IPython Notebook kernel crash on Win7x64
1103 1103 * :ghissue:`3926`: Ending Notebook renaming dialog with return creates new-line
1104 1104 * :ghissue:`3932`: Incorrect empty docstring
1105 1105 * :ghissue:`3928`: Passing variables to script from the workspace
1106 1106 * :ghissue:`3774`: Notebooks with spaces in their names breaks nbconvert latex graphics
1107 1107 * :ghissue:`3916`: tornado needs its own check
1108 1108 * :ghissue:`3915`: Link to Parallel examples "found on GitHub" broken in docs
1109 1109 * :ghissue:`3895`: Keyboard shortcuts box in notebook doesn't fit the screen
1110 1110 * :ghissue:`3912`: IPython.utils fails automated test for RC1 1.0.0
1111 1111 * :ghissue:`3636`: Code cell missing highlight on load
1112 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 1113 * :ghissue:`3900`: python3 install syntax errors (OS X 10.8.4)
1114 1114 * :ghissue:`3899`: nbconvert to latex fails on notebooks with spaces in file name
1115 1115 * :ghissue:`3881`: Temporary Working Directory Test Fails
1116 1116 * :ghissue:`2750`: A way to freeze code cells in the notebook
1117 1117 * :ghissue:`3893`: Resize Local Image Files in Notebook doesn't work
1118 1118 * :ghissue:`3823`: nbconvert on windows: tex and paths
1119 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 1120 * :ghissue:`3889`: test_qt fails due to assertion error 'qt4' != 'qt'
1121 1121 * :ghissue:`3890`: double post, disregard this issue
1122 1122 * :ghissue:`3689`: nbconvert, remaining tests
1123 1123 * :ghissue:`3874`: Up/Down keys don't work to "Search previous command history" (besides Ctrl-p/Ctrl-n)
1124 1124 * :ghissue:`3853`: CodeMirror locks up in the notebook
1125 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 1126 * :ghissue:`3869`: custom css not working.
1127 1127 * :ghissue:`2960`: Keyboard shortcuts
1128 1128 * :ghissue:`3795`: ipcontroller process goes to 100% CPU, ignores connection requests
1129 1129 * :ghissue:`3553`: Ipython and pylab crashes in windows and canopy
1130 1130 * :ghissue:`3837`: Cannot set custom mathjax url, crash notebook server.
1131 1131 * :ghissue:`3808`: "Naming" releases ?
1132 1132 * :ghissue:`2431`: TypeError: must be string without null bytes, not str
1133 1133 * :ghissue:`3856`: `?` at end of comment causes line to execute
1134 1134 * :ghissue:`3731`: nbconvert: add logging for the different steps of nbconvert
1135 1135 * :ghissue:`3835`: Markdown cells do not render correctly when mathjax is disabled
1136 1136 * :ghissue:`3843`: nbconvert to rst: leftover "In[ ]"
1137 1137 * :ghissue:`3799`: nbconvert: Ability to specify name of output file
1138 1138 * :ghissue:`3726`: Document when IPython.start_ipython() should be used versus IPython.embed()
1139 1139 * :ghissue:`3778`: Add no more readonly view in what's new
1140 1140 * :ghissue:`3754`: No Print View in Notebook in 1.0dev
1141 1141 * :ghissue:`3798`: IPython 0.12.1 Crashes on autocompleting sqlalchemy.func.row_number properties
1142 1142 * :ghissue:`3811`: Opening notebook directly from the command line with multi-directory support installed
1143 1143 * :ghissue:`3775`: Annoying behavior when clicking on cell after execution (Ctrl+Enter)
1144 1144 * :ghissue:`3809`: Possible to add some bpython features?
1145 1145 * :ghissue:`3810`: Printing the contents of an image file messes up shell text
1146 1146 * :ghissue:`3702`: `nbconvert`: Default help message should be that of --help
1147 1147 * :ghissue:`3735`: Nbconvert 1.0.0a1 does not take into account the pdf extensions in graphs
1148 1148 * :ghissue:`3719`: Bad strftime format, for windows, in nbconvert exporter
1149 1149 * :ghissue:`3786`: Zmq errors appearing with `Ctrl-C` in console/qtconsole
1150 1150 * :ghissue:`3019`: disappearing scrollbar on tooltip in Chrome 24 on Ubuntu 12.04
1151 1151 * :ghissue:`3785`: ipdb completely broken in Qt console
1152 1152 * :ghissue:`3796`: Document the meaning of milestone/issues-tags for users.
1153 1153 * :ghissue:`3788`: Do not auto show tooltip if docstring empty.
1154 1154 * :ghissue:`1366`: [Web page] No link to front page from documentation
1155 1155 * :ghissue:`3739`: nbconvert (to slideshow) misses some of the math in markdown cells
1156 1156 * :ghissue:`3768`: increase and make timeout configurable in console completion.
1157 1157 * :ghissue:`3724`: ipcluster only running on one cpu
1158 1158 * :ghissue:`1592`: better message for unsupported nbformat
1159 1159 * :ghissue:`2049`: Can not stop "ipython kernel" on windows
1160 1160 * :ghissue:`3757`: Need direct entry point to given notebook
1161 1161 * :ghissue:`3745`: ImportError: cannot import name check_linecache_ipython
1162 1162 * :ghissue:`3701`: `nbconvert`: Final output file should be in same directory as input file
1163 1163 * :ghissue:`3738`: history -o works but history with -n produces identical results
1164 1164 * :ghissue:`3740`: error when attempting to run 'make' in docs directory
1165 1165 * :ghissue:`3737`: ipython nbconvert crashes with ValueError: Invalid format string.
1166 1166 * :ghissue:`3730`: nbconvert: unhelpful error when pandoc isn't installed
1167 1167 * :ghissue:`3718`: markdown cell cursor misaligned in notebook
1168 1168 * :ghissue:`3710`: mutiple input fields for %debug in the notebook after resetting the kernel
1169 1169 * :ghissue:`3713`: PyCharm has problems with IPython working inside PyPy created by virtualenv
1170 1170 * :ghissue:`3712`: Code completion: Complete on dictionary keys
1171 1171 * :ghissue:`3680`: --pylab and --matplotlib flag
1172 1172 * :ghissue:`3698`: nbconvert: Unicode error with minus sign
1173 1173 * :ghissue:`3693`: nbconvert does not process SVGs into PDFs
1174 1174 * :ghissue:`3688`: nbconvert, figures not extracting with Python 3.x
1175 1175 * :ghissue:`3542`: note new dependencies in docs / setup.py
1176 1176 * :ghissue:`2556`: [pagedown] do not target_blank anchor link
1177 1177 * :ghissue:`3684`: bad message when %pylab fails due import *other* than matplotlib
1178 1178 * :ghissue:`3682`: ipython notebook pylab inline import_all=False
1179 1179 * :ghissue:`3596`: MathjaxUtils race condition?
1180 1180 * :ghissue:`1540`: Comment/uncomment selection in notebook
1181 1181 * :ghissue:`2702`: frozen setup: permission denied for default ipython_dir
1182 1182 * :ghissue:`3672`: allow_none on Number-like traits.
1183 1183 * :ghissue:`2411`: add CONTRIBUTING.md
1184 1184 * :ghissue:`481`: IPython terminal issue with Qt4Agg on XP SP3
1185 1185 * :ghissue:`2664`: How to preserve user variables from import clashing?
1186 1186 * :ghissue:`3436`: enable_pylab(import_all=False) still imports np
1187 1187 * :ghissue:`2630`: lib.pylabtools.figsize : NameError when using Qt4Agg backend and %pylab magic.
1188 1188 * :ghissue:`3154`: Notebook: no event triggered when a Cell is created
1189 1189 * :ghissue:`3579`: Nbconvert: SVG are not transformed to PDF anymore
1190 1190 * :ghissue:`3604`: MathJax rendering problem in `%%latex` cell
1191 1191 * :ghissue:`3668`: AttributeError: 'BlockingKernelClient' object has no attribute 'started_channels'
1192 1192 * :ghissue:`3245`: SyntaxError: encoding declaration in Unicode string
1193 1193 * :ghissue:`3639`: %pylab inline in IPYTHON notebook throws "RuntimeError: Cannot activate multiple GUI eventloops"
1194 1194 * :ghissue:`3663`: frontend deprecation warnings
1195 1195 * :ghissue:`3661`: run -m not behaving like python -m
1196 1196 * :ghissue:`3597`: re-do PR #3531 - allow markdown in Header cell
1197 1197 * :ghissue:`3053`: Markdown in header cells is not rendered
1198 1198 * :ghissue:`3655`: IPython finding its way into pasted strings.
1199 1199 * :ghissue:`3620`: uncaught errors in HTML output
1200 1200 * :ghissue:`3646`: get_dict() error
1201 1201 * :ghissue:`3004`: `%load_ext rmagic` fails when legacy ipy_user_conf.py is installed (in ipython 0.13.1 / OSX 10.8)
1202 1202 * :ghissue:`3638`: setp() issue in ipython notebook with figure references
1203 1203 * :ghissue:`3634`: nbconvert reveal to pdf conversion ignores styling, prints only a single page.
1204 1204 * :ghissue:`1307`: Remove pyreadline workarounds, we now require pyreadline >= 1.7.1
1205 1205 * :ghissue:`3316`: find_cmd test failure on Windows
1206 1206 * :ghissue:`3494`: input() in notebook doesn't work in Python 3
1207 1207 * :ghissue:`3427`: Deprecate `$` as mathjax delimiter
1208 1208 * :ghissue:`3625`: Pager does not open from button
1209 1209 * :ghissue:`3149`: Miscellaneous small nbconvert feedback
1210 1210 * :ghissue:`3617`: 256 color escapes support
1211 1211 * :ghissue:`3609`: %pylab inline blows up for single process ipython
1212 1212 * :ghissue:`2934`: Publish the Interactive MPI Demo Notebook
1213 1213 * :ghissue:`3614`: ansi escapes broken in master (ls --color)
1214 1214 * :ghissue:`3610`: If you don't have markdown, python setup.py install says no pygments
1215 1215 * :ghissue:`3547`: %run modules clobber each other
1216 1216 * :ghissue:`3602`: import_item fails when one tries to use DottedObjectName instead of a string
1217 1217 * :ghissue:`3563`: Duplicate tab completions in the notebook
1218 1218 * :ghissue:`3599`: Problems trying to run IPython on python3 without installing...
1219 1219 * :ghissue:`2937`: too long completion in notebook
1220 1220 * :ghissue:`3479`: Write empty name for the notebooks
1221 1221 * :ghissue:`3505`: nbconvert: Failure in specifying user filter
1222 1222 * :ghissue:`1537`: think a bit about namespaces
1223 1223 * :ghissue:`3124`: Long multiline strings in Notebook
1224 1224 * :ghissue:`3464`: run -d message unclear
1225 1225 * :ghissue:`2706`: IPython 0.13.1 ignoring $PYTHONSTARTUP
1226 1226 * :ghissue:`3587`: LaTeX escaping bug in nbconvert when exporting to HTML
1227 1227 * :ghissue:`3213`: Long running notebook died with a coredump
1228 1228 * :ghissue:`3580`: Running ipython with pypy on windows
1229 1229 * :ghissue:`3573`: custom.js not working
1230 1230 * :ghissue:`3544`: IPython.lib test failure on Windows
1231 1231 * :ghissue:`3352`: Install Sphinx extensions
1232 1232 * :ghissue:`2971`: [notebook]user needs to press ctrl-c twice to stop notebook server should be put into terminal window
1233 1233 * :ghissue:`2413`: ipython3 qtconsole fails to install: ipython 0.13 has no such extra feature 'qtconsole'
1234 1234 * :ghissue:`2618`: documentation is incorrect for install process
1235 1235 * :ghissue:`2595`: mac 10.8 qtconsole export history
1236 1236 * :ghissue:`2586`: cannot store aliases
1237 1237 * :ghissue:`2714`: ipython qtconsole print unittest messages in console instead his own window.
1238 1238 * :ghissue:`2669`: cython magic failing to work with openmp.
1239 1239 * :ghissue:`3256`: Vagrant pandas instance of iPython Notebook does not respect additional plotting arguments
1240 1240 * :ghissue:`3010`: cython magic fail if cache dir is deleted while in session
1241 1241 * :ghissue:`2044`: prune unused names from parallel.error
1242 1242 * :ghissue:`1145`: Online help utility broken in QtConsole
1243 1243 * :ghissue:`3439`: Markdown links no longer open in new window (with change from pagedown to marked)
1244 1244 * :ghissue:`3476`: _margv for macros seems to be missing
1245 1245 * :ghissue:`3499`: Add reveal.js library (version 2.4.0) inside IPython
1246 1246 * :ghissue:`2771`: Wiki Migration to GitHub
1247 1247 * :ghissue:`2887`: ipcontroller purging some engines during connect
1248 1248 * :ghissue:`626`: Enable Resuming Controller
1249 1249 * :ghissue:`2824`: Kernel restarting after message "Kernel XXXX failed to respond to heartbeat"
1250 1250 * :ghissue:`2823`: %%cython magic gives ImportError: dlopen(long_file_name.so, 2): image not found
1251 1251 * :ghissue:`2891`: In IPython for Python 3, system site-packages comes before user site-packages
1252 1252 * :ghissue:`2928`: Add magic "watch" function (example)
1253 1253 * :ghissue:`2931`: Problem rendering pandas dataframe in Firefox for Windows
1254 1254 * :ghissue:`2939`: [notebook] Figure legend not shown in inline backend if ouside the box of the axes
1255 1255 * :ghissue:`2972`: [notebook] in Markdown mode, press Enter key at the end of <some http link>, the next line is indented unexpectly
1256 1256 * :ghissue:`3069`: Instructions for installing IPython notebook on Windows
1257 1257 * :ghissue:`3444`: Encoding problem: cannot use if user's name is not ascii?
1258 1258 * :ghissue:`3335`: Reenable bracket matching
1259 1259 * :ghissue:`3386`: Magic %paste not working in Python 3.3.2. TypeError: Type str doesn't support the buffer API
1260 1260 * :ghissue:`3543`: Exception shutting down kernel from notebook dashboard (0.13.1)
1261 1261 * :ghissue:`3549`: Codecell size changes with selection
1262 1262 * :ghissue:`3445`: Adding newlines in %%latex cell
1263 1263 * :ghissue:`3237`: [notebook] Can't close a notebook without errors
1264 1264 * :ghissue:`2916`: colon invokes auto(un)indent in markdown cells
1265 1265 * :ghissue:`2167`: Indent and dedent in htmlnotebook
1266 1266 * :ghissue:`3545`: Notebook save button icon not clear
1267 1267 * :ghissue:`3534`: nbconvert incompatible with Windows?
1268 1268 * :ghissue:`3489`: Update example notebook that raw_input is allowed
1269 1269 * :ghissue:`3396`: Notebook checkpoint time is displayed an hour out
1270 1270 * :ghissue:`3261`: Empty revert to checkpoint menu if no checkpoint...
1271 1271 * :ghissue:`2984`: "print" magic does not work in Python 3
1272 1272 * :ghissue:`3524`: Issues with pyzmq and ipython on EPD update
1273 1273 * :ghissue:`2434`: %store magic not auto-restoring
1274 1274 * :ghissue:`2720`: base_url and static path
1275 1275 * :ghissue:`2234`: Update various low resolution graphics for retina displays
1276 1276 * :ghissue:`2842`: Remember passwords for pw-protected notebooks
1277 1277 * :ghissue:`3244`: qtconsole: ValueError('close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr',)
1278 1278 * :ghissue:`2215`: AsyncResult.wait(0) can hang waiting for the client to get results?
1279 1279 * :ghissue:`2268`: provide mean to retrieve static data path
1280 1280 * :ghissue:`1905`: Expose UI for worksheets within each notebook
1281 1281 * :ghissue:`2380`: Qt inputhook prevents modal dialog boxes from displaying
1282 1282 * :ghissue:`3185`: prettify on double //
1283 1283 * :ghissue:`2821`: Test failure: IPython.parallel.tests.test_client.test_resubmit_header
1284 1284 * :ghissue:`2475`: [Notebook] Line is deindented when typing eg a colon in markdown mode
1285 1285 * :ghissue:`2470`: Do not destroy valid notebooks
1286 1286 * :ghissue:`860`: Allow the standalone export of a notebook to HTML
1287 1287 * :ghissue:`2652`: notebook with qt backend crashes at save image location popup
1288 1288 * :ghissue:`1587`: Improve kernel restarting in the notebook
1289 1289 * :ghissue:`2710`: Saving a plot in Mac OS X backend crashes IPython
1290 1290 * :ghissue:`2596`: notebook "Last saved:" is misleading on file opening.
1291 1291 * :ghissue:`2671`: TypeError :NoneType when executed "ipython qtconsole" in windows console
1292 1292 * :ghissue:`2703`: Notebook scrolling breaks after pager is shown
1293 1293 * :ghissue:`2803`: KernelManager and KernelClient should be two separate objects
1294 1294 * :ghissue:`2693`: TerminalIPythonApp configuration fails without ipython_config.py
1295 1295 * :ghissue:`2531`: IPython 0.13.1 python 2 32-bit installer includes 64-bit ipython*.exe launchers in the scripts folder
1296 1296 * :ghissue:`2520`: Control-C kills port forwarding
1297 1297 * :ghissue:`2279`: Setting `__file__` to None breaks Mayavi import
1298 1298 * :ghissue:`2161`: When logged into notebook, long titles are incorrectly positioned
1299 1299 * :ghissue:`1292`: Notebook, Print view should not be editable...
1300 1300 * :ghissue:`1731`: test parallel launchers
1301 1301 * :ghissue:`3227`: Improve documentation of ipcontroller and possible BUG
1302 1302 * :ghissue:`2896`: IPController very unstable
1303 1303 * :ghissue:`3517`: documentation build broken in head
1304 1304 * :ghissue:`3522`: UnicodeDecodeError: 'ascii' codec can't decode byte on Pycharm on Windows
1305 1305 * :ghissue:`3448`: Please include MathJax fonts with IPython Notebook
1306 1306 * :ghissue:`3519`: IPython Parallel map mysteriously turns pandas Series into numpy ndarray
1307 1307 * :ghissue:`3345`: IPython embedded shells ask if I want to exit, but I set confirm_exit = False
1308 1308 * :ghissue:`3509`: IPython won't close without asking "Are you sure?" in Firefox
1309 1309 * :ghissue:`3471`: Notebook jinja2/markupsafe depedencies in manual
1310 1310 * :ghissue:`3502`: Notebook broken in master
1311 1311 * :ghissue:`3302`: autoreload does not work in ipython 0.13.x, python 3.3
1312 1312 * :ghissue:`3475`: no warning when leaving/closing notebook on master without saved changes
1313 1313 * :ghissue:`3490`: No obvious feedback when kernel crashes
1314 1314 * :ghissue:`1912`: Move all autoreload tests to their own group
1315 1315 * :ghissue:`2577`: sh.py and ipython for python 3.3
1316 1316 * :ghissue:`3467`: %magic doesn't work
1317 1317 * :ghissue:`3501`: Editing markdown cells that wrap has off-by-one errors in cursor positioning
1318 1318 * :ghissue:`3492`: IPython for Python3
1319 1319 * :ghissue:`3474`: unexpected keyword argument to remove_kernel
1320 1320 * :ghissue:`2283`: TypeError when using '?' after a string in a %logstart session
1321 1321 * :ghissue:`2787`: rmagic and pandas DataFrame
1322 1322 * :ghissue:`2605`: Ellipsis literal triggers AttributeError
1323 1323 * :ghissue:`1179`: Test unicode source in pinfo
1324 1324 * :ghissue:`2055`: drop Python 3.1 support
1325 1325 * :ghissue:`2293`: IPEP 2: Input transformations
1326 1326 * :ghissue:`2790`: %paste and %cpaste not removing "..." lines
1327 1327 * :ghissue:`3480`: Testing fails because iptest.py cannot be found
1328 1328 * :ghissue:`2580`: will not run within PIL build directory
1329 1329 * :ghissue:`2797`: RMagic, Dataframe Conversion Problem
1330 1330 * :ghissue:`2838`: Empty lines disappear from triple-quoted literals.
1331 1331 * :ghissue:`3050`: Broken link on IPython.core.display page
1332 1332 * :ghissue:`3473`: Config not passed down to subcommands
1333 1333 * :ghissue:`3462`: Setting log_format in config file results in error (and no format changes)
1334 1334 * :ghissue:`3311`: Notebook (occasionally) not working on windows (Sophos AV)
1335 1335 * :ghissue:`3461`: Cursor positioning off by a character in auto-wrapped lines
1336 1336 * :ghissue:`3454`: _repr_html_ error
1337 1337 * :ghissue:`3457`: Space in long Paragraph Markdown cell with Chinese or Japanese
1338 1338 * :ghissue:`3447`: Run Cell Does not Work
1339 1339 * :ghissue:`1373`: Last lines in long cells are hidden
1340 1340 * :ghissue:`1504`: Revisit serialization in IPython.parallel
1341 1341 * :ghissue:`1459`: Can't connect to 2 HTTPS notebook servers on the same host
1342 1342 * :ghissue:`678`: Input prompt stripping broken with multiline data structures
1343 1343 * :ghissue:`3001`: IPython.notebook.dirty flag is not set when a cell has unsaved changes
1344 1344 * :ghissue:`3077`: Multiprocessing semantics in parallel.view.map
1345 1345 * :ghissue:`3056`: links across notebooks
1346 1346 * :ghissue:`3120`: Tornado 3.0
1347 1347 * :ghissue:`3156`: update pretty to use Python 3 style for sets
1348 1348 * :ghissue:`3197`: Can't escape multiple dollar signs in a markdown cell
1349 1349 * :ghissue:`3309`: `Image()` signature/doc improvements
1350 1350 * :ghissue:`3415`: Bug in IPython/external/path/__init__.py
1351 1351 * :ghissue:`3446`: Feature suggestion: Download matplotlib figure to client browser
1352 1352 * :ghissue:`3295`: autoexported notebooks: only export explicitly marked cells
1353 1353 * :ghissue:`3442`: Notebook: Summary table extracted from markdown headers
1354 1354 * :ghissue:`3438`: Zooming notebook in chrome is broken in master
1355 1355 * :ghissue:`1378`: Implement autosave in notebook
1356 1356 * :ghissue:`3437`: Highlighting matching parentheses
1357 1357 * :ghissue:`3435`: module search segfault
1358 1358 * :ghissue:`3424`: ipcluster --version
1359 1359 * :ghissue:`3434`: 0.13.2 Ipython/genutils.py doesn't exist
1360 1360 * :ghissue:`3426`: Feature request: Save by cell and not by line #: IPython %save magic
1361 1361 * :ghissue:`3412`: Non Responsive Kernel: Running a Django development server from an IPython Notebook
1362 1362 * :ghissue:`3408`: Save cell toolbar and slide type metadata in notebooks
1363 1363 * :ghissue:`3246`: %paste regression with blank lines
1364 1364 * :ghissue:`3404`: Weird error with $variable and grep in command line magic (!command)
1365 1365 * :ghissue:`3405`: Key auto-completion in dictionaries?
1366 1366 * :ghissue:`3259`: Codemirror linenumber css broken
1367 1367 * :ghissue:`3397`: Vertical text misalignment in Markdown cells
1368 1368 * :ghissue:`3391`: Revert #3358 once fix integrated into CM
1369 1369 * :ghissue:`3360`: Error 500 while saving IPython notebook
1370 1370 * :ghissue:`3375`: Frequent Safari/Webkit crashes
1371 1371 * :ghissue:`3365`: zmq frontend
1372 1372 * :ghissue:`2654`: User_expression issues
1373 1373 * :ghissue:`3389`: Store history as plain text
1374 1374 * :ghissue:`3388`: Ipython parallel: open TCP connection created for each result returned from engine
1375 1375 * :ghissue:`3385`: setup.py failure on Python 3
1376 1376 * :ghissue:`3376`: Setting `__module__` to None breaks pretty printing
1377 1377 * :ghissue:`3374`: ipython qtconsole does not display the prompt on OSX
1378 1378 * :ghissue:`3380`: simple call to kernel
1379 1379 * :ghissue:`3379`: TaskRecord key 'started' not set
1380 1380 * :ghissue:`3241`: notebook conection time out
1381 1381 * :ghissue:`3334`: magic interpreter interpretes non magic commands?
1382 1382 * :ghissue:`3326`: python3.3: Type error when launching SGE cluster in IPython notebook
1383 1383 * :ghissue:`3349`: pip3 doesn't run 2to3?
1384 1384 * :ghissue:`3347`: Longlist support in ipdb
1385 1385 * :ghissue:`3343`: Make pip install / easy_install faster
1386 1386 * :ghissue:`3337`: git submodules broke nightly PPA builds
1387 1387 * :ghissue:`3206`: Copy/Paste Regression in QtConsole
1388 1388 * :ghissue:`3329`: Buggy linewrap in Mac OSX Terminal (Mountain Lion)
1389 1389 * :ghissue:`3327`: Qt version check broken
1390 1390 * :ghissue:`3303`: parallel tasks never finish under heavy load
1391 1391 * :ghissue:`1381`: '\\' for equation continuations require an extra '\' in markdown cells
1392 1392 * :ghissue:`3314`: Error launching iPython
1393 1393 * :ghissue:`3306`: Test failure when running on a Vagrant VM
1394 1394 * :ghissue:`3280`: IPython.utils.process.getoutput returns stderr
1395 1395 * :ghissue:`3299`: variables named _ or __ exhibit incorrect behavior
1396 1396 * :ghissue:`3196`: add an "x" or similar to htmlnotebook pager
1397 1397 * :ghissue:`3293`: Several 404 errors for js files Firefox
1398 1398 * :ghissue:`3292`: syntax highlighting in chrome on OSX 10.8.3
1399 1399 * :ghissue:`3288`: Latest dev version hangs on page load
1400 1400 * :ghissue:`3283`: ipython dev retains directory information after directory change
1401 1401 * :ghissue:`3279`: custom.css is not overridden in the dev IPython (1.0)
1402 1402 * :ghissue:`2727`: %run -m doesn't support relative imports
1403 1403 * :ghissue:`3268`: GFM triple backquote and unknown language
1404 1404 * :ghissue:`3273`: Suppressing all plot related outputs
1405 1405 * :ghissue:`3272`: Backspace while completing load previous page
1406 1406 * :ghissue:`3260`: Js error in savewidget
1407 1407 * :ghissue:`3247`: scrollbar in notebook when not needed?
1408 1408 * :ghissue:`3243`: notebook: option to view json source from browser
1409 1409 * :ghissue:`3265`: 404 errors when running IPython 1.0dev
1410 1410 * :ghissue:`3257`: setup.py not finding submodules
1411 1411 * :ghissue:`3253`: Incorrect Qt and PySide version comparison
1412 1412 * :ghissue:`3248`: Cell magics broken in Qt console
1413 1413 * :ghissue:`3012`: Problems with the less based style.min.css
1414 1414 * :ghissue:`2390`: Image width/height don't work in embedded images
1415 1415 * :ghissue:`3236`: cannot set TerminalIPythonApp.log_format
1416 1416 * :ghissue:`3214`: notebook kernel dies if started with invalid parameter
1417 1417 * :ghissue:`2980`: Remove HTMLCell ?
1418 1418 * :ghissue:`3128`: qtconsole hangs on importing pylab (using X forwarding)
1419 1419 * :ghissue:`3198`: Hitting recursive depth causing all notebook pages to hang
1420 1420 * :ghissue:`3218`: race conditions in profile directory creation
1421 1421 * :ghissue:`3177`: OverflowError execption in handlers.py
1422 1422 * :ghissue:`2563`: core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation
1423 1423 * :ghissue:`3207`: [Feature] folders for ipython notebook dashboard
1424 1424 * :ghissue:`3178`: cell magics do not work with empty lines after #2447
1425 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 1427 * :ghissue:`3202`: File cell magic fails with blank lines
1428 1428 * :ghissue:`3199`: %%cython -a stopped working?
1429 1429 * :ghissue:`2688`: obsolete imports in import autocompletion
1430 1430 * :ghissue:`3192`: Python2, Unhandled exception, __builtin__.True = False
1431 1431 * :ghissue:`3179`: script magic error message loop
1432 1432 * :ghissue:`3009`: use XDG_CACHE_HOME for cython objects
1433 1433 * :ghissue:`3059`: Bugs in 00_notebook_tour example.
1434 1434 * :ghissue:`3104`: Integrate a javascript file manager into the notebook front end
1435 1435 * :ghissue:`3176`: Particular equation not rendering (notebook)
1436 1436 * :ghissue:`1133`: [notebook] readonly and upload files/UI
1437 1437 * :ghissue:`2975`: [notebook] python file and cell toolbar
1438 1438 * :ghissue:`3017`: SciPy.weave broken in IPython notebook/ qtconsole
1439 1439 * :ghissue:`3161`: paste macro not reading spaces correctly
1440 1440 * :ghissue:`2835`: %paste not working on WinXpSP3/ipython-0.13.1.py2-win32-PROPER.exe/python27
1441 1441 * :ghissue:`2628`: Make transformers work for lines following decorators
1442 1442 * :ghissue:`2612`: Multiline String containing ":\n?foo\n" confuses interpreter to replace ?foo with get_ipython().magic(u'pinfo foo')
1443 1443 * :ghissue:`2539`: Request: Enable cell magics inside of .ipy scripts
1444 1444 * :ghissue:`2507`: Multiline string does not work (includes `...`) with doctest type input in IPython notebook
1445 1445 * :ghissue:`2164`: Request: Line breaks in line magic command
1446 1446 * :ghissue:`3106`: poor parallel performance with many jobs
1447 1447 * :ghissue:`2438`: print inside multiprocessing crashes Ipython kernel
1448 1448 * :ghissue:`3155`: Bad md5 hash for package 0.13.2
1449 1449 * :ghissue:`3045`: [Notebook] Ipython Kernel does not start if disconnected from internet(/network?)
1450 1450 * :ghissue:`3146`: Using celery in python 3.3
1451 1451 * :ghissue:`3145`: The notebook viewer is down
1452 1452 * :ghissue:`2385`: grep --color not working well with notebook
1453 1453 * :ghissue:`3131`: Quickly install from source in a clean virtualenv?
1454 1454 * :ghissue:`3139`: Rolling log for ipython
1455 1455 * :ghissue:`3127`: notebook with pylab=inline appears to call figure.draw twice
1456 1456 * :ghissue:`3129`: Walking up and down the call stack
1457 1457 * :ghissue:`3123`: Notebook crashed if unplugged ethernet cable
1458 1458 * :ghissue:`3121`: NB should use normalize.css? was #3049
1459 1459 * :ghissue:`3087`: Disable spellchecking in notebook
1460 1460 * :ghissue:`3084`: ipython pyqt 4.10 incompatibilty, QTextBlockUserData
1461 1461 * :ghissue:`3113`: Fails to install under Jython 2.7 beta
1462 1462 * :ghissue:`3110`: Render of h4 headers is not correct in notebook (error in renderedhtml.css)
1463 1463 * :ghissue:`3109`: BUG: read_csv: dtype={'id' : np.str}: Datatype not understood
1464 1464 * :ghissue:`3107`: Autocompletion of object attributes in arrays
1465 1465 * :ghissue:`3103`: Reset locale setting in qtconsole
1466 1466 * :ghissue:`3090`: python3.3 Entry Point not found
1467 1467 * :ghissue:`3081`: UnicodeDecodeError when using Image(data="some.jpeg")
1468 1468 * :ghissue:`2834`: url regexp only finds one link
1469 1469 * :ghissue:`3091`: qtconsole breaks doctest.testmod() in Python 3.3
1470 1470 * :ghissue:`3074`: SIGUSR1 not available on Windows
1471 1471 * :ghissue:`2996`: registration::purging stalled registration high occurrence in small clusters
1472 1472 * :ghissue:`3065`: diff-ability of notebooks
1473 1473 * :ghissue:`3067`: Crash with pygit2
1474 1474 * :ghissue:`3061`: Bug handling Ellipsis
1475 1475 * :ghissue:`3049`: NB css inconsistent behavior between ff and webkit
1476 1476 * :ghissue:`3039`: unicode errors when opening a new notebook
1477 1477 * :ghissue:`3048`: Installning ipython qtConsole should be easyer att Windows
1478 1478 * :ghissue:`3042`: Profile creation fails on 0.13.2 branch
1479 1479 * :ghissue:`3035`: docstring typo/inconsistency: mention of an xml notebook format?
1480 1480 * :ghissue:`3031`: HDF5 library segfault (possibly due to mismatching headers?)
1481 1481 * :ghissue:`2991`: In notebook importing sympy closes ipython kernel
1482 1482 * :ghissue:`3027`: f.__globals__ causes an error in Python 3.3
1483 1483 * :ghissue:`3020`: Failing test test_interactiveshell.TestAstTransform on Windows
1484 1484 * :ghissue:`3023`: alt text for "click to expand output" has typo in alt text
1485 1485 * :ghissue:`2963`: %history to print all input history of a previous session when line range is omitted
1486 1486 * :ghissue:`3018`: IPython installed within virtualenv. WARNING "Please install IPython inside the virtualtenv"
1487 1487 * :ghissue:`2484`: Completion in Emacs *Python* buffer causes prompt to be increased.
1488 1488 * :ghissue:`3014`: Ctrl-C finishes notebook immediately
1489 1489 * :ghissue:`3007`: cython_pyximport reload broken in python3
1490 1490 * :ghissue:`2955`: Incompatible Qt imports when running inprocess_qtconsole
1491 1491 * :ghissue:`3006`: [IPython 0.13.1] The check of PyQt version is wrong
1492 1492 * :ghissue:`3005`: Renaming a notebook to an existing notebook name overwrites the other file
1493 1493 * :ghissue:`2940`: Abort trap in IPython Notebook after installing matplotlib
1494 1494 * :ghissue:`3000`: issue #3000
1495 1495 * :ghissue:`2995`: ipython_directive.py fails on multiline when prompt number < 100
1496 1496 * :ghissue:`2993`: File magic (%%file) does not work with paths beginning with tilde (e.g., ~/anaconda/stuff.txt)
1497 1497 * :ghissue:`2992`: Cell-based input for console and qt frontends?
1498 1498 * :ghissue:`2425`: Liaise with Spyder devs to integrate newer IPython
1499 1499 * :ghissue:`2986`: requesting help in a loop can damage a notebook
1500 1500 * :ghissue:`2978`: v1.0-dev build errors on Arch with Python 3.
1501 1501 * :ghissue:`2557`: [refactor] Insert_cell_at_index()
1502 1502 * :ghissue:`2969`: ipython command does not work in terminal
1503 1503 * :ghissue:`2762`: OSX wxPython (osx_cocoa, 64bit) command "%gui wx" blocks the interpreter
1504 1504 * :ghissue:`2956`: Silent importing of submodules differs from standard Python3.2 interpreter's behavior
1505 1505 * :ghissue:`2943`: Up arrow key history search gets stuck in QTConsole
1506 1506 * :ghissue:`2953`: using 'nonlocal' declaration in global scope causes ipython3 crash
1507 1507 * :ghissue:`2952`: qtconsole ignores exec_lines
1508 1508 * :ghissue:`2949`: ipython crashes due to atexit()
1509 1509 * :ghissue:`2947`: From rmagic to an R console
1510 1510 * :ghissue:`2938`: docstring pane not showing in notebook
1511 1511 * :ghissue:`2936`: Tornado assumes invalid signature for parse_qs on Python 3.1
1512 1512 * :ghissue:`2935`: unable to find python after easy_install / pip install
1513 1513 * :ghissue:`2920`: Add undo-cell deletion menu
1514 1514 * :ghissue:`2914`: BUG:saving a modified .py file after loading a module kills the kernel
1515 1515 * :ghissue:`2925`: BUG: kernel dies if user sets sys.stderr or sys.stdout to a file object
1516 1516 * :ghissue:`2909`: LaTeX sometimes fails to render in markdown cells with some curly bracket + underscore combinations
1517 1517 * :ghissue:`2898`: Skip ipc tests on Windows
1518 1518 * :ghissue:`2902`: ActiveState attempt to build ipython 0.12.1 for python 3.2.2 for Mac OS failed
1519 1519 * :ghissue:`2899`: Test failure in IPython.core.tests.test_magic.test_time
1520 1520 * :ghissue:`2890`: Test failure when fabric not installed
1521 1521 * :ghissue:`2892`: IPython tab completion bug for paths
1522 1522 * :ghissue:`1340`: Allow input cells to be collapsed
1523 1523 * :ghissue:`2881`: ? command in notebook does not show help in Safari
1524 1524 * :ghissue:`2751`: %%timeit should use minutes to format running time in long running cells
1525 1525 * :ghissue:`2879`: When importing a module with a wrong name, ipython crashes
1526 1526 * :ghissue:`2862`: %%timeit should warn of empty contents
1527 1527 * :ghissue:`2485`: History navigation breaks in qtconsole
1528 1528 * :ghissue:`2785`: gevent input hook
1529 1529 * :ghissue:`2843`: Sliently running code in clipboard (with paste, cpaste and variants)
1530 1530 * :ghissue:`2784`: %run -t -N<N> error
1531 1531 * :ghissue:`2732`: Test failure with FileLinks class on Windows
1532 1532 * :ghissue:`2860`: ipython help notebook -> KeyError: 'KernelManager'
1533 1533 * :ghissue:`2858`: Where is the installed `ipython` script?
1534 1534 * :ghissue:`2856`: Edit code entered from ipython in external editor
1535 1535 * :ghissue:`2722`: IPC transport option not taking effect ?
1536 1536 * :ghissue:`2473`: Better error messages in ipengine/ipcontroller
1537 1537 * :ghissue:`2836`: Cannot send builtin module definitions to IP engines
1538 1538 * :ghissue:`2833`: Any reason not to use super() ?
1539 1539 * :ghissue:`2781`: Cannot interrupt infinite loops in the notebook
1540 1540 * :ghissue:`2150`: clippath_demo.py in matplotlib example does not work with inline backend
1541 1541 * :ghissue:`2634`: Numbered list in notebook markdown cell renders with Roman numerals instead of numbers
1542 1542 * :ghissue:`2230`: IPython crashing during startup with "AttributeError: 'NoneType' object has no attribute 'rstrip'"
1543 1543 * :ghissue:`2483`: nbviewer bug? with multi-file gists
1544 1544 * :ghissue:`2466`: mistyping `ed -p` breaks `ed -p`
1545 1545 * :ghissue:`2477`: Glob expansion tests fail on Windows
1546 1546 * :ghissue:`2622`: doc issue: notebooks that ship with Ipython .13 are written for python 2.x
1547 1547 * :ghissue:`2626`: Add "Cell -> Run All Keep Going" for notebooks
1548 1548 * :ghissue:`1223`: Show last modification date of each notebook
1549 1549 * :ghissue:`2621`: user request: put link to example notebooks in Dashboard
1550 1550 * :ghissue:`2564`: grid blanks plots in ipython pylab inline mode (interactive)
1551 1551 * :ghissue:`2532`: Django shell (IPython) gives NameError on dict comprehensions
1552 1552 * :ghissue:`2188`: ipython crashes on ctrl-c
1553 1553 * :ghissue:`2391`: Request: nbformat API to load/save without changing version
1554 1554 * :ghissue:`2355`: Restart kernel message even though kernel is perfectly alive
1555 1555 * :ghissue:`2306`: Garbled input text after reverse search on Mac OS X
1556 1556 * :ghissue:`2297`: ipdb with separate kernel/client pushing stdout to kernel process only
1557 1557 * :ghissue:`2180`: Have [kernel busy] overridden only by [kernel idle]
1558 1558 * :ghissue:`1188`: Pylab with OSX backend keyboard focus issue and hang
1559 1559 * :ghissue:`2107`: test_octavemagic.py[everything] fails
1560 1560 * :ghissue:`1212`: Better understand/document browser compatibility
1561 1561 * :ghissue:`1585`: Refactor notebook templates to use Jinja2 and make each page a separate directory
1562 1562 * :ghissue:`1443`: xticks scaling factor partially obscured with qtconsole and inline plotting
1563 1563 * :ghissue:`1209`: can't make %result work as in doc.
1564 1564 * :ghissue:`1200`: IPython 0.12 Windows install fails on Vista
1565 1565 * :ghissue:`1127`: Interactive test scripts for Qt/nb issues
1566 1566 * :ghissue:`959`: Matplotlib figures hide
1567 1567 * :ghissue:`2071`: win32 installer issue on Windows XP
1568 1568 * :ghissue:`2610`: ZMQInteractiveShell.colors being ignored
1569 1569 * :ghissue:`2505`: Markdown Cell incorrectly highlighting after "<"
1570 1570 * :ghissue:`165`: Installer fails to create Start Menu entries on Windows
1571 1571 * :ghissue:`2356`: failing traceback in terminal ipython for first exception
1572 1572 * :ghissue:`2145`: Have dashboad show when server disconect
1573 1573 * :ghissue:`2098`: Do not crash on kernel shutdow if json file is missing
1574 1574 * :ghissue:`2813`: Offline MathJax is broken on 0.14dev
1575 1575 * :ghissue:`2807`: Test failure: IPython.parallel.tests.test_client.TestClient.test_purge_everything
1576 1576 * :ghissue:`2486`: Readline's history search in ipython console does not clear properly after cancellation with Ctrl+C
1577 1577 * :ghissue:`2709`: Cython -la doesn't work
1578 1578 * :ghissue:`2767`: What is IPython.utils.upgradedir ?
1579 1579 * :ghissue:`2210`: Placing matplotlib legend outside axis bounds causes inline display to clip it
1580 1580 * :ghissue:`2553`: IPython Notebooks not robust against client failures
1581 1581 * :ghissue:`2536`: ImageDraw in Ipython notebook not drawing lines
1582 1582 * :ghissue:`2264`: Feature request: Versioning messaging protocol
1583 1583 * :ghissue:`2589`: Creation of ~300+ MPI-spawned engines causes instability in ipcluster
1584 1584 * :ghissue:`2672`: notebook: inline option without pylab
1585 1585 * :ghissue:`2673`: Indefinite Articles & Traitlets
1586 1586 * :ghissue:`2705`: Notebook crashes Safari with select and drag
1587 1587 * :ghissue:`2721`: dreload kills ipython when it hits zmq
1588 1588 * :ghissue:`2806`: ipython.parallel doesn't discover globals under Python 3.3
1589 1589 * :ghissue:`2794`: _exit_code behaves differently in terminal vs ZMQ frontends
1590 1590 * :ghissue:`2793`: IPython.parallel issue with pushing pandas TimeSeries
1591 1591 * :ghissue:`1085`: In process kernel for Qt frontend
1592 1592 * :ghissue:`2760`: IndexError: list index out of range with Python 3.2
1593 1593 * :ghissue:`2780`: Save and load notebooks from github
1594 1594 * :ghissue:`2772`: AttributeError: 'Client' object has no attribute 'kill'
1595 1595 * :ghissue:`2754`: Fail to send class definitions from interactive session to engines namespaces
1596 1596 * :ghissue:`2764`: TypeError while using 'cd'
1597 1597 * :ghissue:`2765`: name '__file__' is not defined
1598 1598 * :ghissue:`2540`: Wrap tooltip if line exceeds threshold?
1599 1599 * :ghissue:`2394`: Startup error on ipython qtconsole (version 0.13 and 0.14-dev
1600 1600 * :ghissue:`2440`: IPEP 4: Python 3 Compatibility
1601 1601 * :ghissue:`1814`: __file__ is not defined when file end with .ipy
1602 1602 * :ghissue:`2759`: R magic extension interferes with tab completion
1603 1603 * :ghissue:`2615`: Small change needed to rmagic extension.
1604 1604 * :ghissue:`2748`: collapse parts of a html notebook
1605 1605 * :ghissue:`1661`: %paste still bugs about IndentationError and says to use %paste
1606 1606 * :ghissue:`2742`: Octavemagic fails to deliver inline images in IPython (on Windows)
1607 1607 * :ghissue:`2739`: wiki.ipython.org contaminated with prescription drug spam
1608 1608 * :ghissue:`2588`: Link error while executing code from cython example notebook
1609 1609 * :ghissue:`2550`: Rpush magic doesn't find local variables and doesn't support comma separated lists of variables
1610 1610 * :ghissue:`2675`: Markdown/html blockquote need css.
1611 1611 * :ghissue:`2419`: TerminalInteractiveShell.__init__() ignores value of ipython_dir argument
1612 1612 * :ghissue:`1523`: Better LaTeX printing in the qtconsole with the sympy profile
1613 1613 * :ghissue:`2719`: ipython fails with `pkg_resources.DistributionNotFound: ipython==0.13`
1614 1614 * :ghissue:`2715`: url crashes nbviewer.ipython.org
1615 1615 * :ghissue:`2555`: "import" module completion on MacOSX
1616 1616 * :ghissue:`2707`: Problem installing the new version of IPython in Windows
1617 1617 * :ghissue:`2696`: SymPy magic bug in IPython Notebook
1618 1618 * :ghissue:`2684`: pretty print broken for types created with PyType_FromSpec
1619 1619 * :ghissue:`2533`: rmagic breaks on Windows
1620 1620 * :ghissue:`2661`: Qtconsole tooltip is too wide when the function has many arguments
1621 1621 * :ghissue:`2679`: ipython3 qtconsole via Homebrew on Mac OS X 10.8 - pyqt/pyside import error
1622 1622 * :ghissue:`2646`: pylab_not_importable
1623 1623 * :ghissue:`2587`: cython magic pops 2 CLI windows upon execution on Windows
1624 1624 * :ghissue:`2660`: Certain arguments (-h, --help, --version) never passed to scripts run with ipython
1625 1625 * :ghissue:`2665`: Missing docs for rmagic and some other extensions
1626 1626 * :ghissue:`2611`: Travis wants to drop 3.1 support
1627 1627 * :ghissue:`2658`: Incorrect parsing of raw multiline strings
1628 1628 * :ghissue:`2655`: Test fails if `from __future__ import print_function` in .pythonrc.py
1629 1629 * :ghissue:`2651`: nonlocal with no existing variable produces too many errors
1630 1630 * :ghissue:`2645`: python3 is a pain (minor unicode bug)
1631 1631 * :ghissue:`2637`: %paste in Python 3 on Mac doesn't work
1632 1632 * :ghissue:`2624`: Error on launching IPython on Win 7 and Python 2.7.3
1633 1633 * :ghissue:`2608`: disk IO activity on cursor press
1634 1634 * :ghissue:`1275`: Markdown parses LaTeX math symbols as its formatting syntax in notebook
1635 1635 * :ghissue:`2613`: display(Math(...)) doesn't render \tau correctly
1636 1636 * :ghissue:`925`: Tab-completion in Qt console needn't use pager
1637 1637 * :ghissue:`2607`: %load_ext sympy.interactive.ipythonprinting dammaging output
1638 1638 * :ghissue:`2593`: Toolbar button to open qtconsole from notebook
1639 1639 * :ghissue:`2602`: IPython html documentation for downloading
1640 1640 * :ghissue:`2598`: ipython notebook --pylab=inline replaces built-in any()
1641 1641 * :ghissue:`2244`: small issue: wrong printout
1642 1642 * :ghissue:`2590`: add easier way to execute scripts in the current directory
1643 1643 * :ghissue:`2581`: %hist does not work when InteractiveShell.cache_size = 0
1644 1644 * :ghissue:`2584`: No file COPYING
1645 1645 * :ghissue:`2578`: AttributeError: 'module' object has no attribute 'TestCase'
1646 1646 * :ghissue:`2576`: One of my notebooks won't load any more -- is there a maximum notebook size?
1647 1647 * :ghissue:`2560`: Notebook output is invisible when printing strings with \r\r\n line endings
1648 1648 * :ghissue:`2566`: if pyside partially present ipython qtconsole fails to load even if pyqt4 present
1649 1649 * :ghissue:`1308`: ipython qtconsole --ssh=server --existing ... hangs
1650 1650 * :ghissue:`1679`: List command doesn't work in ipdb debugger the first time
1651 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 1653 * :ghissue:`2541`: Allow `python -m IPython`
1654 1654 * :ghissue:`2508`: subplots_adjust() does not work correctly in ipython notebook
1655 1655 * :ghissue:`2289`: Incorrect mathjax rendering of certain arrays of equations
1656 1656 * :ghissue:`2487`: Selecting and indenting
1657 1657 * :ghissue:`2521`: more fine-grained 'run' controls, such as 'run from here' and 'run until here'
1658 1658 * :ghissue:`2535`: Funny bounding box when plot with text
1659 1659 * :ghissue:`2523`: History not working
1660 1660 * :ghissue:`2514`: Issue with zooming in qtconsole
1661 1661 * :ghissue:`2220`: No sys.stdout.encoding in kernel based IPython
1662 1662 * :ghissue:`2512`: ERROR: Internal Python error in the inspect module.
1663 1663 * :ghissue:`2496`: Function passwd does not work in QtConsole
1664 1664 * :ghissue:`1453`: make engines reconnect/die when controller was restarted
1665 1665 * :ghissue:`2481`: ipython notebook -- clicking in a code cell's output moves the screen to the top of the code cell
1666 1666 * :ghissue:`2488`: Undesired plot outputs in Notebook inline mode
1667 1667 * :ghissue:`2482`: ipython notebook -- download may not get the latest notebook
1668 1668 * :ghissue:`2471`: _subprocess module removed in Python 3.3
1669 1669 * :ghissue:`2374`: Issues with man pages
1670 1670 * :ghissue:`2316`: parallel.Client.__init__ should take cluster_id kwarg
1671 1671 * :ghissue:`2457`: Can a R library wrapper be created with Rmagic?
1672 1672 * :ghissue:`1575`: Fallback frontend for console when connecting pylab=inlnie -enabled kernel?
1673 1673 * :ghissue:`2097`: Do not crash if history db is corrupted
1674 1674 * :ghissue:`2435`: ipengines fail if clean_logs enabled
1675 1675 * :ghissue:`2429`: Using warnings.warn() results in TypeError
1676 1676 * :ghissue:`2422`: Multiprocessing in ipython notebook kernel crash
1677 1677 * :ghissue:`2426`: ipython crashes with the following message. I do not what went wrong. Can you help me identify the problem?
1678 1678 * :ghissue:`2423`: Docs typo?
1679 1679 * :ghissue:`2257`: pip install -e fails
1680 1680 * :ghissue:`2418`: rmagic can't run R's read.csv on data files with NA data
1681 1681 * :ghissue:`2417`: HTML notebook: Backspace sometimes deletes multiple characters
1682 1682 * :ghissue:`2275`: notebook: "Down_Arrow" on last line of cell should move to end of line
1683 1683 * :ghissue:`2414`: 0.13.1 does not work with current EPD 7.3-2
1684 1684 * :ghissue:`2409`: there is a redundant None
1685 1685 * :ghissue:`2410`: Use /usr/bin/python3 instead of /usr/bin/python
1686 1686 * :ghissue:`2366`: Notebook Dashboard --notebook-dir and fullpath
1687 1687 * :ghissue:`2406`: Inability to get docstring in debugger
1688 1688 * :ghissue:`2398`: Show line number for IndentationErrors
1689 1689 * :ghissue:`2314`: HTML lists seem to interfere with the QtConsole display
1690 1690 * :ghissue:`1688`: unicode exception when using %run with failing script
1691 1691 * :ghissue:`1884`: IPython.embed changes color on error
1692 1692 * :ghissue:`2381`: %time doesn't work for multiline statements
1693 1693 * :ghissue:`1435`: Add size keywords in Image class
1694 1694 * :ghissue:`2372`: interactiveshell.py misses urllib and io_open imports
1695 1695 * :ghissue:`2371`: iPython not working
1696 1696 * :ghissue:`2367`: Tab expansion moves to next cell in notebook
1697 1697 * :ghissue:`2359`: nbviever alters the order of print and display() output
1698 1698 * :ghissue:`2227`: print name for IPython Notebooks has become uninformative
1699 1699 * :ghissue:`2361`: client doesn't use connection file's 'location' in disambiguating 'interface'
1700 1700 * :ghissue:`2357`: failing traceback in terminal ipython for first exception
1701 1701 * :ghissue:`2343`: Installing in a python 3.3b2 or python 3.3rc1 virtual environment.
1702 1702 * :ghissue:`2315`: Failure in test: "Test we're not loading modules on startup that we shouldn't."
1703 1703 * :ghissue:`2351`: Multiple Notebook Apps: cookies not port specific, clash with each other
1704 1704 * :ghissue:`2350`: running unittest from qtconsole prints output to terminal
1705 1705 * :ghissue:`2303`: remote tracebacks broken since 952d0d6 (PR #2223)
1706 1706 * :ghissue:`2330`: qtconsole does not hightlight tab-completion suggestion with custom stylesheet
1707 1707 * :ghissue:`2325`: Parsing Tex formula fails in Notebook
1708 1708 * :ghissue:`2324`: Parsing Tex formula fails
1709 1709 * :ghissue:`1474`: Add argument to `run -n` for custom namespace
1710 1710 * :ghissue:`2318`: C-m n/p don't work in Markdown cells in the notebook
1711 1711 * :ghissue:`2309`: time.time() in ipython notebook producing impossible results
1712 1712 * :ghissue:`2307`: schedule tasks on newly arrived engines
1713 1713 * :ghissue:`2313`: Allow Notebook HTML/JS to send messages to Python code
1714 1714 * :ghissue:`2304`: ipengine throws KeyError: url
1715 1715 * :ghissue:`1878`: shell access using ! will not fill class or function scope vars
1716 1716 * :ghissue:`2253`: %paste does not retrieve clipboard contents under screen/tmux on OS X
1717 1717 * :ghissue:`1510`: Add-on (or Monkey-patch) infrastructure for HTML notebook
1718 1718 * :ghissue:`2273`: triple quote and %s at beginning of line with %paste
1719 1719 * :ghissue:`2243`: Regression in .embed()
1720 1720 * :ghissue:`2266`: SSH passwordless check with OpenSSH checks for the wrong thing
1721 1721 * :ghissue:`2217`: Change NewNotebook handler to use 30x redirect
1722 1722 * :ghissue:`2276`: config option for disabling history store
1723 1723 * :ghissue:`2239`: can't use parallel.Reference in view.map
1724 1724 * :ghissue:`2272`: Sympy piecewise messed up rendering
1725 1725 * :ghissue:`2252`: %paste throws an exception with empty clipboard
1726 1726 * :ghissue:`2259`: git-mpr is currently broken
1727 1727 * :ghissue:`2247`: Variable expansion in shell commands should work in substrings
1728 1728 * :ghissue:`2026`: Run 'fast' tests only
1729 1729 * :ghissue:`2241`: read a list of notebooks on server and bring into browser only notebook
1730 1730 * :ghissue:`2237`: please put python and text editor in the web only ipython
1731 1731 * :ghissue:`2053`: Improvements to the IPython.display.Image object
1732 1732 * :ghissue:`1456`: ERROR: Internal Python error in the inspect module.
1733 1733 * :ghissue:`2221`: Avoid importing from IPython.parallel in core
1734 1734 * :ghissue:`2213`: Can't trigger startup code in Engines
1735 1735 * :ghissue:`1464`: Strange behavior for backspace with lines ending with more than 4 spaces in notebook
1736 1736 * :ghissue:`2187`: NaN in object_info_reply JSON causes parse error
1737 1737 * :ghissue:`214`: system command requiring administrative privileges
1738 1738 * :ghissue:`2195`: Unknown option `no-edit` in git-mpr
1739 1739 * :ghissue:`2201`: Add documentation build to tools/test_pr.py
1740 1740 * :ghissue:`2205`: Command-line option for default Notebook output collapsing behavior
1741 1741 * :ghissue:`1927`: toggle between inline and floating figures
1742 1742 * :ghissue:`2171`: Can't start StarCluster after upgrading to IPython 0.13
1743 1743 * :ghissue:`2173`: oct2py v >= 0.3.1 doesn't need h5py anymore
1744 1744 * :ghissue:`2099`: storemagic needs to use self.shell
1745 1745 * :ghissue:`2166`: DirectView map_sync() with Lambdas Using Generators
1746 1746 * :ghissue:`2091`: Unable to use print_stats after %prun -r in notebook
1747 1747 * :ghissue:`2132`: Add fail-over for pastebin
1748 1748 * :ghissue:`2156`: Make it possible to install ipython without nasty gui dependencies
1749 1749 * :ghissue:`2154`: Scrolled long output should be off in print view by default
1750 1750 * :ghissue:`2162`: Tab completion does not work with IPython.embed_kernel()
1751 1751 * :ghissue:`2157`: iPython 0.13 / github-master cannot create logfile from scratch
1752 1752 * :ghissue:`2151`: missing newline when a magic is called from the qtconsole menu
1753 1753 * :ghissue:`2139`: 00_notebook_tour Image example broken on master
1754 1754 * :ghissue:`2143`: Add a %%cython_annotate magic
1755 1755 * :ghissue:`2135`: Running IPython from terminal
1756 1756 * :ghissue:`2093`: Makefile for building Sphinx documentation on Windows
1757 1757 * :ghissue:`2122`: Bug in pretty printing
1758 1758 * :ghissue:`2120`: Notebook "Make a Copy..." keeps opening duplicates in the same tab
1759 1759 * :ghissue:`1997`: password cannot be used with url prefix
1760 1760 * :ghissue:`2129`: help/doc displayed multiple times if requested in loop
1761 1761 * :ghissue:`2121`: ipdb does not support input history in qtconsole
1762 1762 * :ghissue:`2114`: %logstart doesn't log
1763 1763 * :ghissue:`2085`: %ed magic fails in qtconsole
1764 1764 * :ghissue:`2119`: iPython fails to run on MacOS Lion
1765 1765 * :ghissue:`2052`: %pylab inline magic does not work on windows
1766 1766 * :ghissue:`2111`: Ipython won't start on W7
1767 1767 * :ghissue:`2112`: Strange internal traceback
1768 1768 * :ghissue:`2108`: Backslash (\) at the end of the line behavior different from default Python
1769 1769 * :ghissue:`1425`: Ampersands can't be typed sometimes in notebook cells
1770 1770 * :ghissue:`1513`: Add expand/collapse support for long output elements like stdout and tracebacks
1771 1771 * :ghissue:`2087`: error when starting ipython
1772 1772 * :ghissue:`2103`: Ability to run notebook file from commandline
1773 1773 * :ghissue:`2082`: Qt Console output spacing
1774 1774 * :ghissue:`2083`: Test failures with Python 3.2 and PYTHONWARNINGS="d"
1775 1775 * :ghissue:`2094`: about inline
1776 1776 * :ghissue:`2077`: Starting IPython3 on the terminal
1777 1777 * :ghissue:`1760`: easy_install ipython fails on py3.2-win32
1778 1778 * :ghissue:`2075`: Local Mathjax install causes iptest3 error under python3
1779 1779 * :ghissue:`2057`: setup fails for python3 with LANG=C
1780 1780 * :ghissue:`2070`: shebang on Windows
1781 1781 * :ghissue:`2054`: sys_info missing git hash in sdists
1782 1782 * :ghissue:`2059`: duplicate and modified files in documentation
1783 1783 * :ghissue:`2056`: except-shadows-builtin osm.py:687
1784 1784 * :ghissue:`2058`: hyphen-used-as-minus-sign in manpages
General Comments 0
You need to be logged in to leave comments. Login now