Show More
@@ -1,282 +1,285 b'' | |||||
1 | """Remote Functions and decorators for Views. |
|
1 | """Remote Functions and decorators for Views. | |
2 |
|
2 | |||
3 | Authors: |
|
3 | Authors: | |
4 |
|
4 | |||
5 | * Brian Granger |
|
5 | * Brian Granger | |
6 | * Min RK |
|
6 | * Min RK | |
7 | """ |
|
7 | """ | |
8 | #----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
9 | # Copyright (C) 2010-2011 The IPython Development Team |
|
9 | # Copyright (C) 2010-2011 The IPython Development Team | |
10 | # |
|
10 | # | |
11 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
12 | # the file COPYING, distributed as part of this software. |
|
12 | # the file COPYING, distributed as part of this software. | |
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 |
|
14 | |||
15 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
16 | # Imports |
|
16 | # Imports | |
17 | #----------------------------------------------------------------------------- |
|
17 | #----------------------------------------------------------------------------- | |
18 |
|
18 | |||
19 | from __future__ import division |
|
19 | from __future__ import division | |
20 |
|
20 | |||
21 | import sys |
|
21 | import sys | |
22 | import warnings |
|
22 | import warnings | |
23 |
|
23 | |||
24 | from IPython.external.decorator import decorator |
|
24 | from IPython.external.decorator import decorator | |
25 | from IPython.testing.skipdoctest import skip_doctest |
|
25 | from IPython.testing.skipdoctest import skip_doctest | |
26 |
|
26 | |||
27 | from . import map as Map |
|
27 | from . import map as Map | |
28 | from .asyncresult import AsyncMapResult |
|
28 | from .asyncresult import AsyncMapResult | |
29 |
|
29 | |||
30 | #----------------------------------------------------------------------------- |
|
30 | #----------------------------------------------------------------------------- | |
31 | # Functions and Decorators |
|
31 | # Functions and Decorators | |
32 | #----------------------------------------------------------------------------- |
|
32 | #----------------------------------------------------------------------------- | |
33 |
|
33 | |||
34 | @skip_doctest |
|
34 | @skip_doctest | |
35 | def remote(view, block=None, **flags): |
|
35 | def remote(view, block=None, **flags): | |
36 | """Turn a function into a remote function. |
|
36 | """Turn a function into a remote function. | |
37 |
|
37 | |||
38 | This method can be used for map: |
|
38 | This method can be used for map: | |
39 |
|
39 | |||
40 | In [1]: @remote(view,block=True) |
|
40 | In [1]: @remote(view,block=True) | |
41 | ...: def func(a): |
|
41 | ...: def func(a): | |
42 | ...: pass |
|
42 | ...: pass | |
43 | """ |
|
43 | """ | |
44 |
|
44 | |||
45 | def remote_function(f): |
|
45 | def remote_function(f): | |
46 | return RemoteFunction(view, f, block=block, **flags) |
|
46 | return RemoteFunction(view, f, block=block, **flags) | |
47 | return remote_function |
|
47 | return remote_function | |
48 |
|
48 | |||
49 | @skip_doctest |
|
49 | @skip_doctest | |
50 | def parallel(view, dist='b', block=None, ordered=True, **flags): |
|
50 | def parallel(view, dist='b', block=None, ordered=True, **flags): | |
51 | """Turn a function into a parallel remote function. |
|
51 | """Turn a function into a parallel remote function. | |
52 |
|
52 | |||
53 | This method can be used for map: |
|
53 | This method can be used for map: | |
54 |
|
54 | |||
55 | In [1]: @parallel(view, block=True) |
|
55 | In [1]: @parallel(view, block=True) | |
56 | ...: def func(a): |
|
56 | ...: def func(a): | |
57 | ...: pass |
|
57 | ...: pass | |
58 | """ |
|
58 | """ | |
59 |
|
59 | |||
60 | def parallel_function(f): |
|
60 | def parallel_function(f): | |
61 | return ParallelFunction(view, f, dist=dist, block=block, ordered=ordered, **flags) |
|
61 | return ParallelFunction(view, f, dist=dist, block=block, ordered=ordered, **flags) | |
62 | return parallel_function |
|
62 | return parallel_function | |
63 |
|
63 | |||
64 | def getname(f): |
|
64 | def getname(f): | |
65 | """Get the name of an object. |
|
65 | """Get the name of an object. | |
66 |
|
66 | |||
67 | For use in case of callables that are not functions, and |
|
67 | For use in case of callables that are not functions, and | |
68 | thus may not have __name__ defined. |
|
68 | thus may not have __name__ defined. | |
69 |
|
69 | |||
70 | Order: f.__name__ > f.name > str(f) |
|
70 | Order: f.__name__ > f.name > str(f) | |
71 | """ |
|
71 | """ | |
72 | try: |
|
72 | try: | |
73 | return f.__name__ |
|
73 | return f.__name__ | |
74 | except: |
|
74 | except: | |
75 | pass |
|
75 | pass | |
76 | try: |
|
76 | try: | |
77 | return f.name |
|
77 | return f.name | |
78 | except: |
|
78 | except: | |
79 | pass |
|
79 | pass | |
80 |
|
80 | |||
81 | return str(f) |
|
81 | return str(f) | |
82 |
|
82 | |||
83 | @decorator |
|
83 | @decorator | |
84 | def sync_view_results(f, self, *args, **kwargs): |
|
84 | def sync_view_results(f, self, *args, **kwargs): | |
85 | """sync relevant results from self.client to our results attribute. |
|
85 | """sync relevant results from self.client to our results attribute. | |
86 |
|
86 | |||
87 | This is a clone of view.sync_results, but for remote functions |
|
87 | This is a clone of view.sync_results, but for remote functions | |
88 | """ |
|
88 | """ | |
89 | view = self.view |
|
89 | view = self.view | |
90 | if view._in_sync_results: |
|
90 | if view._in_sync_results: | |
91 | return f(self, *args, **kwargs) |
|
91 | return f(self, *args, **kwargs) | |
92 | view._in_sync_results = True |
|
92 | view._in_sync_results = True | |
93 | try: |
|
93 | try: | |
94 | ret = f(self, *args, **kwargs) |
|
94 | ret = f(self, *args, **kwargs) | |
95 | finally: |
|
95 | finally: | |
96 | view._in_sync_results = False |
|
96 | view._in_sync_results = False | |
97 | view._sync_results() |
|
97 | view._sync_results() | |
98 | return ret |
|
98 | return ret | |
99 |
|
99 | |||
100 | #-------------------------------------------------------------------------- |
|
100 | #-------------------------------------------------------------------------- | |
101 | # Classes |
|
101 | # Classes | |
102 | #-------------------------------------------------------------------------- |
|
102 | #-------------------------------------------------------------------------- | |
103 |
|
103 | |||
104 | class RemoteFunction(object): |
|
104 | class RemoteFunction(object): | |
105 | """Turn an existing function into a remote function. |
|
105 | """Turn an existing function into a remote function. | |
106 |
|
106 | |||
107 | Parameters |
|
107 | Parameters | |
108 | ---------- |
|
108 | ---------- | |
109 |
|
109 | |||
110 | view : View instance |
|
110 | view : View instance | |
111 | The view to be used for execution |
|
111 | The view to be used for execution | |
112 | f : callable |
|
112 | f : callable | |
113 | The function to be wrapped into a remote function |
|
113 | The function to be wrapped into a remote function | |
114 | block : bool [default: None] |
|
114 | block : bool [default: None] | |
115 | Whether to wait for results or not. The default behavior is |
|
115 | Whether to wait for results or not. The default behavior is | |
116 | to use the current `block` attribute of `view` |
|
116 | to use the current `block` attribute of `view` | |
117 |
|
117 | |||
118 | **flags : remaining kwargs are passed to View.temp_flags |
|
118 | **flags : remaining kwargs are passed to View.temp_flags | |
119 | """ |
|
119 | """ | |
120 |
|
120 | |||
121 | view = None # the remote connection |
|
121 | view = None # the remote connection | |
122 | func = None # the wrapped function |
|
122 | func = None # the wrapped function | |
123 | block = None # whether to block |
|
123 | block = None # whether to block | |
124 | flags = None # dict of extra kwargs for temp_flags |
|
124 | flags = None # dict of extra kwargs for temp_flags | |
125 |
|
125 | |||
126 | def __init__(self, view, f, block=None, **flags): |
|
126 | def __init__(self, view, f, block=None, **flags): | |
127 | self.view = view |
|
127 | self.view = view | |
128 | self.func = f |
|
128 | self.func = f | |
129 | self.block=block |
|
129 | self.block=block | |
130 | self.flags=flags |
|
130 | self.flags=flags | |
131 |
|
131 | |||
132 | def __call__(self, *args, **kwargs): |
|
132 | def __call__(self, *args, **kwargs): | |
133 | block = self.view.block if self.block is None else self.block |
|
133 | block = self.view.block if self.block is None else self.block | |
134 | with self.view.temp_flags(block=block, **self.flags): |
|
134 | with self.view.temp_flags(block=block, **self.flags): | |
135 | return self.view.apply(self.func, *args, **kwargs) |
|
135 | return self.view.apply(self.func, *args, **kwargs) | |
136 |
|
136 | |||
137 |
|
137 | |||
138 | class ParallelFunction(RemoteFunction): |
|
138 | class ParallelFunction(RemoteFunction): | |
139 | """Class for mapping a function to sequences. |
|
139 | """Class for mapping a function to sequences. | |
140 |
|
140 | |||
141 | This will distribute the sequences according the a mapper, and call |
|
141 | This will distribute the sequences according the a mapper, and call | |
142 | the function on each sub-sequence. If called via map, then the function |
|
142 | the function on each sub-sequence. If called via map, then the function | |
143 | will be called once on each element, rather that each sub-sequence. |
|
143 | will be called once on each element, rather that each sub-sequence. | |
144 |
|
144 | |||
145 | Parameters |
|
145 | Parameters | |
146 | ---------- |
|
146 | ---------- | |
147 |
|
147 | |||
148 | view : View instance |
|
148 | view : View instance | |
149 | The view to be used for execution |
|
149 | The view to be used for execution | |
150 | f : callable |
|
150 | f : callable | |
151 | The function to be wrapped into a remote function |
|
151 | The function to be wrapped into a remote function | |
152 | dist : str [default: 'b'] |
|
152 | dist : str [default: 'b'] | |
153 | The key for which mapObject to use to distribute sequences |
|
153 | The key for which mapObject to use to distribute sequences | |
154 | options are: |
|
154 | options are: | |
|
155 | ||||
155 |
|
|
156 | * 'b' : use contiguous chunks in order | |
156 |
|
|
157 | * 'r' : use round-robin striping | |
|
158 | ||||
157 | block : bool [default: None] |
|
159 | block : bool [default: None] | |
158 | Whether to wait for results or not. The default behavior is |
|
160 | Whether to wait for results or not. The default behavior is | |
159 | to use the current `block` attribute of `view` |
|
161 | to use the current `block` attribute of `view` | |
160 | chunksize : int or None |
|
162 | chunksize : int or None | |
161 | The size of chunk to use when breaking up sequences in a load-balanced manner |
|
163 | The size of chunk to use when breaking up sequences in a load-balanced manner | |
162 | ordered : bool [default: True] |
|
164 | ordered : bool [default: True] | |
163 | Whether the result should be kept in order. If False, |
|
165 | Whether the result should be kept in order. If False, | |
164 | results become available as they arrive, regardless of submission order. |
|
166 | results become available as they arrive, regardless of submission order. | |
165 | **flags : remaining kwargs are passed to View.temp_flags |
|
167 | **flags | |
|
168 | remaining kwargs are passed to View.temp_flags | |||
166 | """ |
|
169 | """ | |
167 |
|
170 | |||
168 | chunksize = None |
|
171 | chunksize = None | |
169 | ordered = None |
|
172 | ordered = None | |
170 | mapObject = None |
|
173 | mapObject = None | |
171 | _mapping = False |
|
174 | _mapping = False | |
172 |
|
175 | |||
173 | def __init__(self, view, f, dist='b', block=None, chunksize=None, ordered=True, **flags): |
|
176 | def __init__(self, view, f, dist='b', block=None, chunksize=None, ordered=True, **flags): | |
174 | super(ParallelFunction, self).__init__(view, f, block=block, **flags) |
|
177 | super(ParallelFunction, self).__init__(view, f, block=block, **flags) | |
175 | self.chunksize = chunksize |
|
178 | self.chunksize = chunksize | |
176 | self.ordered = ordered |
|
179 | self.ordered = ordered | |
177 |
|
180 | |||
178 | mapClass = Map.dists[dist] |
|
181 | mapClass = Map.dists[dist] | |
179 | self.mapObject = mapClass() |
|
182 | self.mapObject = mapClass() | |
180 |
|
183 | |||
181 | @sync_view_results |
|
184 | @sync_view_results | |
182 | def __call__(self, *sequences): |
|
185 | def __call__(self, *sequences): | |
183 | client = self.view.client |
|
186 | client = self.view.client | |
184 |
|
187 | |||
185 | lens = [] |
|
188 | lens = [] | |
186 | maxlen = minlen = -1 |
|
189 | maxlen = minlen = -1 | |
187 | for i, seq in enumerate(sequences): |
|
190 | for i, seq in enumerate(sequences): | |
188 | try: |
|
191 | try: | |
189 | n = len(seq) |
|
192 | n = len(seq) | |
190 | except Exception: |
|
193 | except Exception: | |
191 | seq = list(seq) |
|
194 | seq = list(seq) | |
192 | if isinstance(sequences, tuple): |
|
195 | if isinstance(sequences, tuple): | |
193 | # can't alter a tuple |
|
196 | # can't alter a tuple | |
194 | sequences = list(sequences) |
|
197 | sequences = list(sequences) | |
195 | sequences[i] = seq |
|
198 | sequences[i] = seq | |
196 | n = len(seq) |
|
199 | n = len(seq) | |
197 | if n > maxlen: |
|
200 | if n > maxlen: | |
198 | maxlen = n |
|
201 | maxlen = n | |
199 | if minlen == -1 or n < minlen: |
|
202 | if minlen == -1 or n < minlen: | |
200 | minlen = n |
|
203 | minlen = n | |
201 | lens.append(n) |
|
204 | lens.append(n) | |
202 |
|
205 | |||
203 | # check that the length of sequences match |
|
206 | # check that the length of sequences match | |
204 | if not self._mapping and minlen != maxlen: |
|
207 | if not self._mapping and minlen != maxlen: | |
205 | msg = 'all sequences must have equal length, but have %s' % lens |
|
208 | msg = 'all sequences must have equal length, but have %s' % lens | |
206 | raise ValueError(msg) |
|
209 | raise ValueError(msg) | |
207 |
|
210 | |||
208 | balanced = 'Balanced' in self.view.__class__.__name__ |
|
211 | balanced = 'Balanced' in self.view.__class__.__name__ | |
209 | if balanced: |
|
212 | if balanced: | |
210 | if self.chunksize: |
|
213 | if self.chunksize: | |
211 | nparts = maxlen // self.chunksize + int(maxlen % self.chunksize > 0) |
|
214 | nparts = maxlen // self.chunksize + int(maxlen % self.chunksize > 0) | |
212 | else: |
|
215 | else: | |
213 | nparts = maxlen |
|
216 | nparts = maxlen | |
214 | targets = [None]*nparts |
|
217 | targets = [None]*nparts | |
215 | else: |
|
218 | else: | |
216 | if self.chunksize: |
|
219 | if self.chunksize: | |
217 | warnings.warn("`chunksize` is ignored unless load balancing", UserWarning) |
|
220 | warnings.warn("`chunksize` is ignored unless load balancing", UserWarning) | |
218 | # multiplexed: |
|
221 | # multiplexed: | |
219 | targets = self.view.targets |
|
222 | targets = self.view.targets | |
220 | # 'all' is lazily evaluated at execution time, which is now: |
|
223 | # 'all' is lazily evaluated at execution time, which is now: | |
221 | if targets == 'all': |
|
224 | if targets == 'all': | |
222 | targets = client._build_targets(targets)[1] |
|
225 | targets = client._build_targets(targets)[1] | |
223 | elif isinstance(targets, int): |
|
226 | elif isinstance(targets, int): | |
224 | # single-engine view, targets must be iterable |
|
227 | # single-engine view, targets must be iterable | |
225 | targets = [targets] |
|
228 | targets = [targets] | |
226 | nparts = len(targets) |
|
229 | nparts = len(targets) | |
227 |
|
230 | |||
228 | msg_ids = [] |
|
231 | msg_ids = [] | |
229 | for index, t in enumerate(targets): |
|
232 | for index, t in enumerate(targets): | |
230 | args = [] |
|
233 | args = [] | |
231 | for seq in sequences: |
|
234 | for seq in sequences: | |
232 | part = self.mapObject.getPartition(seq, index, nparts, maxlen) |
|
235 | part = self.mapObject.getPartition(seq, index, nparts, maxlen) | |
233 | args.append(part) |
|
236 | args.append(part) | |
234 |
|
237 | |||
235 | if sum([len(arg) for arg in args]) == 0: |
|
238 | if sum([len(arg) for arg in args]) == 0: | |
236 | continue |
|
239 | continue | |
237 |
|
240 | |||
238 | if self._mapping: |
|
241 | if self._mapping: | |
239 | if sys.version_info[0] >= 3: |
|
242 | if sys.version_info[0] >= 3: | |
240 | f = lambda f, *sequences: list(map(f, *sequences)) |
|
243 | f = lambda f, *sequences: list(map(f, *sequences)) | |
241 | else: |
|
244 | else: | |
242 | f = map |
|
245 | f = map | |
243 | args = [self.func] + args |
|
246 | args = [self.func] + args | |
244 | else: |
|
247 | else: | |
245 | f=self.func |
|
248 | f=self.func | |
246 |
|
249 | |||
247 | view = self.view if balanced else client[t] |
|
250 | view = self.view if balanced else client[t] | |
248 | with view.temp_flags(block=False, **self.flags): |
|
251 | with view.temp_flags(block=False, **self.flags): | |
249 | ar = view.apply(f, *args) |
|
252 | ar = view.apply(f, *args) | |
250 |
|
253 | |||
251 | msg_ids.extend(ar.msg_ids) |
|
254 | msg_ids.extend(ar.msg_ids) | |
252 |
|
255 | |||
253 | r = AsyncMapResult(self.view.client, msg_ids, self.mapObject, |
|
256 | r = AsyncMapResult(self.view.client, msg_ids, self.mapObject, | |
254 | fname=getname(self.func), |
|
257 | fname=getname(self.func), | |
255 | ordered=self.ordered |
|
258 | ordered=self.ordered | |
256 | ) |
|
259 | ) | |
257 |
|
260 | |||
258 | if self.block: |
|
261 | if self.block: | |
259 | try: |
|
262 | try: | |
260 | return r.get() |
|
263 | return r.get() | |
261 | except KeyboardInterrupt: |
|
264 | except KeyboardInterrupt: | |
262 | return r |
|
265 | return r | |
263 | else: |
|
266 | else: | |
264 | return r |
|
267 | return r | |
265 |
|
268 | |||
266 | def map(self, *sequences): |
|
269 | def map(self, *sequences): | |
267 | """call a function on each element of one or more sequence(s) remotely. |
|
270 | """call a function on each element of one or more sequence(s) remotely. | |
268 | This should behave very much like the builtin map, but return an AsyncMapResult |
|
271 | This should behave very much like the builtin map, but return an AsyncMapResult | |
269 | if self.block is False. |
|
272 | if self.block is False. | |
270 |
|
273 | |||
271 | That means it can take generators (will be cast to lists locally), |
|
274 | That means it can take generators (will be cast to lists locally), | |
272 | and mismatched sequence lengths will be padded with None. |
|
275 | and mismatched sequence lengths will be padded with None. | |
273 | """ |
|
276 | """ | |
274 | # set _mapping as a flag for use inside self.__call__ |
|
277 | # set _mapping as a flag for use inside self.__call__ | |
275 | self._mapping = True |
|
278 | self._mapping = True | |
276 | try: |
|
279 | try: | |
277 | ret = self(*sequences) |
|
280 | ret = self(*sequences) | |
278 | finally: |
|
281 | finally: | |
279 | self._mapping = False |
|
282 | self._mapping = False | |
280 | return ret |
|
283 | return ret | |
281 |
|
284 | |||
282 | __all__ = ['remote', 'parallel', 'RemoteFunction', 'ParallelFunction'] |
|
285 | __all__ = ['remote', 'parallel', 'RemoteFunction', 'ParallelFunction'] |
@@ -1,1119 +1,1114 b'' | |||||
1 | """Views of remote engines. |
|
1 | """Views of remote engines. | |
2 |
|
2 | |||
3 | Authors: |
|
3 | Authors: | |
4 |
|
4 | |||
5 | * Min RK |
|
5 | * Min RK | |
6 | """ |
|
6 | """ | |
7 | from __future__ import print_function |
|
7 | from __future__ import print_function | |
8 | #----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
9 | # Copyright (C) 2010-2011 The IPython Development Team |
|
9 | # Copyright (C) 2010-2011 The IPython Development Team | |
10 | # |
|
10 | # | |
11 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
12 | # the file COPYING, distributed as part of this software. |
|
12 | # the file COPYING, distributed as part of this software. | |
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 |
|
14 | |||
15 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
16 | # Imports |
|
16 | # Imports | |
17 | #----------------------------------------------------------------------------- |
|
17 | #----------------------------------------------------------------------------- | |
18 |
|
18 | |||
19 | import imp |
|
19 | import imp | |
20 | import sys |
|
20 | import sys | |
21 | import warnings |
|
21 | import warnings | |
22 | from contextlib import contextmanager |
|
22 | from contextlib import contextmanager | |
23 | from types import ModuleType |
|
23 | from types import ModuleType | |
24 |
|
24 | |||
25 | import zmq |
|
25 | import zmq | |
26 |
|
26 | |||
27 | from IPython.testing.skipdoctest import skip_doctest |
|
27 | from IPython.testing.skipdoctest import skip_doctest | |
28 | from IPython.utils.traitlets import ( |
|
28 | from IPython.utils.traitlets import ( | |
29 | HasTraits, Any, Bool, List, Dict, Set, Instance, CFloat, Integer |
|
29 | HasTraits, Any, Bool, List, Dict, Set, Instance, CFloat, Integer | |
30 | ) |
|
30 | ) | |
31 | from IPython.external.decorator import decorator |
|
31 | from IPython.external.decorator import decorator | |
32 |
|
32 | |||
33 | from IPython.parallel import util |
|
33 | from IPython.parallel import util | |
34 | from IPython.parallel.controller.dependency import Dependency, dependent |
|
34 | from IPython.parallel.controller.dependency import Dependency, dependent | |
35 | from IPython.utils.py3compat import string_types, iteritems, PY3 |
|
35 | from IPython.utils.py3compat import string_types, iteritems, PY3 | |
36 |
|
36 | |||
37 | from . import map as Map |
|
37 | from . import map as Map | |
38 | from .asyncresult import AsyncResult, AsyncMapResult |
|
38 | from .asyncresult import AsyncResult, AsyncMapResult | |
39 | from .remotefunction import ParallelFunction, parallel, remote, getname |
|
39 | from .remotefunction import ParallelFunction, parallel, remote, getname | |
40 |
|
40 | |||
41 | #----------------------------------------------------------------------------- |
|
41 | #----------------------------------------------------------------------------- | |
42 | # Decorators |
|
42 | # Decorators | |
43 | #----------------------------------------------------------------------------- |
|
43 | #----------------------------------------------------------------------------- | |
44 |
|
44 | |||
45 | @decorator |
|
45 | @decorator | |
46 | def save_ids(f, self, *args, **kwargs): |
|
46 | def save_ids(f, self, *args, **kwargs): | |
47 | """Keep our history and outstanding attributes up to date after a method call.""" |
|
47 | """Keep our history and outstanding attributes up to date after a method call.""" | |
48 | n_previous = len(self.client.history) |
|
48 | n_previous = len(self.client.history) | |
49 | try: |
|
49 | try: | |
50 | ret = f(self, *args, **kwargs) |
|
50 | ret = f(self, *args, **kwargs) | |
51 | finally: |
|
51 | finally: | |
52 | nmsgs = len(self.client.history) - n_previous |
|
52 | nmsgs = len(self.client.history) - n_previous | |
53 | msg_ids = self.client.history[-nmsgs:] |
|
53 | msg_ids = self.client.history[-nmsgs:] | |
54 | self.history.extend(msg_ids) |
|
54 | self.history.extend(msg_ids) | |
55 | self.outstanding.update(msg_ids) |
|
55 | self.outstanding.update(msg_ids) | |
56 | return ret |
|
56 | return ret | |
57 |
|
57 | |||
58 | @decorator |
|
58 | @decorator | |
59 | def sync_results(f, self, *args, **kwargs): |
|
59 | def sync_results(f, self, *args, **kwargs): | |
60 | """sync relevant results from self.client to our results attribute.""" |
|
60 | """sync relevant results from self.client to our results attribute.""" | |
61 | if self._in_sync_results: |
|
61 | if self._in_sync_results: | |
62 | return f(self, *args, **kwargs) |
|
62 | return f(self, *args, **kwargs) | |
63 | self._in_sync_results = True |
|
63 | self._in_sync_results = True | |
64 | try: |
|
64 | try: | |
65 | ret = f(self, *args, **kwargs) |
|
65 | ret = f(self, *args, **kwargs) | |
66 | finally: |
|
66 | finally: | |
67 | self._in_sync_results = False |
|
67 | self._in_sync_results = False | |
68 | self._sync_results() |
|
68 | self._sync_results() | |
69 | return ret |
|
69 | return ret | |
70 |
|
70 | |||
71 | @decorator |
|
71 | @decorator | |
72 | def spin_after(f, self, *args, **kwargs): |
|
72 | def spin_after(f, self, *args, **kwargs): | |
73 | """call spin after the method.""" |
|
73 | """call spin after the method.""" | |
74 | ret = f(self, *args, **kwargs) |
|
74 | ret = f(self, *args, **kwargs) | |
75 | self.spin() |
|
75 | self.spin() | |
76 | return ret |
|
76 | return ret | |
77 |
|
77 | |||
78 | #----------------------------------------------------------------------------- |
|
78 | #----------------------------------------------------------------------------- | |
79 | # Classes |
|
79 | # Classes | |
80 | #----------------------------------------------------------------------------- |
|
80 | #----------------------------------------------------------------------------- | |
81 |
|
81 | |||
82 | @skip_doctest |
|
82 | @skip_doctest | |
83 | class View(HasTraits): |
|
83 | class View(HasTraits): | |
84 | """Base View class for more convenint apply(f,*args,**kwargs) syntax via attributes. |
|
84 | """Base View class for more convenint apply(f,*args,**kwargs) syntax via attributes. | |
85 |
|
85 | |||
86 | Don't use this class, use subclasses. |
|
86 | Don't use this class, use subclasses. | |
87 |
|
87 | |||
88 | Methods |
|
88 | Methods | |
89 | ------- |
|
89 | ------- | |
90 |
|
90 | |||
91 | spin |
|
91 | spin | |
92 | flushes incoming results and registration state changes |
|
92 | flushes incoming results and registration state changes | |
93 | control methods spin, and requesting `ids` also ensures up to date |
|
93 | control methods spin, and requesting `ids` also ensures up to date | |
94 |
|
94 | |||
95 | wait |
|
95 | wait | |
96 | wait on one or more msg_ids |
|
96 | wait on one or more msg_ids | |
97 |
|
97 | |||
98 | execution methods |
|
98 | execution methods | |
99 | apply |
|
99 | apply | |
100 | legacy: execute, run |
|
100 | legacy: execute, run | |
101 |
|
101 | |||
102 | data movement |
|
102 | data movement | |
103 | push, pull, scatter, gather |
|
103 | push, pull, scatter, gather | |
104 |
|
104 | |||
105 | query methods |
|
105 | query methods | |
106 | get_result, queue_status, purge_results, result_status |
|
106 | get_result, queue_status, purge_results, result_status | |
107 |
|
107 | |||
108 | control methods |
|
108 | control methods | |
109 | abort, shutdown |
|
109 | abort, shutdown | |
110 |
|
110 | |||
111 | """ |
|
111 | """ | |
112 | # flags |
|
112 | # flags | |
113 | block=Bool(False) |
|
113 | block=Bool(False) | |
114 | track=Bool(True) |
|
114 | track=Bool(True) | |
115 | targets = Any() |
|
115 | targets = Any() | |
116 |
|
116 | |||
117 | history=List() |
|
117 | history=List() | |
118 | outstanding = Set() |
|
118 | outstanding = Set() | |
119 | results = Dict() |
|
119 | results = Dict() | |
120 | client = Instance('IPython.parallel.Client') |
|
120 | client = Instance('IPython.parallel.Client') | |
121 |
|
121 | |||
122 | _socket = Instance('zmq.Socket') |
|
122 | _socket = Instance('zmq.Socket') | |
123 | _flag_names = List(['targets', 'block', 'track']) |
|
123 | _flag_names = List(['targets', 'block', 'track']) | |
124 | _in_sync_results = Bool(False) |
|
124 | _in_sync_results = Bool(False) | |
125 | _targets = Any() |
|
125 | _targets = Any() | |
126 | _idents = Any() |
|
126 | _idents = Any() | |
127 |
|
127 | |||
128 | def __init__(self, client=None, socket=None, **flags): |
|
128 | def __init__(self, client=None, socket=None, **flags): | |
129 | super(View, self).__init__(client=client, _socket=socket) |
|
129 | super(View, self).__init__(client=client, _socket=socket) | |
130 | self.results = client.results |
|
130 | self.results = client.results | |
131 | self.block = client.block |
|
131 | self.block = client.block | |
132 |
|
132 | |||
133 | self.set_flags(**flags) |
|
133 | self.set_flags(**flags) | |
134 |
|
134 | |||
135 | assert not self.__class__ is View, "Don't use base View objects, use subclasses" |
|
135 | assert not self.__class__ is View, "Don't use base View objects, use subclasses" | |
136 |
|
136 | |||
137 | def __repr__(self): |
|
137 | def __repr__(self): | |
138 | strtargets = str(self.targets) |
|
138 | strtargets = str(self.targets) | |
139 | if len(strtargets) > 16: |
|
139 | if len(strtargets) > 16: | |
140 | strtargets = strtargets[:12]+'...]' |
|
140 | strtargets = strtargets[:12]+'...]' | |
141 | return "<%s %s>"%(self.__class__.__name__, strtargets) |
|
141 | return "<%s %s>"%(self.__class__.__name__, strtargets) | |
142 |
|
142 | |||
143 | def __len__(self): |
|
143 | def __len__(self): | |
144 | if isinstance(self.targets, list): |
|
144 | if isinstance(self.targets, list): | |
145 | return len(self.targets) |
|
145 | return len(self.targets) | |
146 | elif isinstance(self.targets, int): |
|
146 | elif isinstance(self.targets, int): | |
147 | return 1 |
|
147 | return 1 | |
148 | else: |
|
148 | else: | |
149 | return len(self.client) |
|
149 | return len(self.client) | |
150 |
|
150 | |||
151 | def set_flags(self, **kwargs): |
|
151 | def set_flags(self, **kwargs): | |
152 | """set my attribute flags by keyword. |
|
152 | """set my attribute flags by keyword. | |
153 |
|
153 | |||
154 | Views determine behavior with a few attributes (`block`, `track`, etc.). |
|
154 | Views determine behavior with a few attributes (`block`, `track`, etc.). | |
155 | These attributes can be set all at once by name with this method. |
|
155 | These attributes can be set all at once by name with this method. | |
156 |
|
156 | |||
157 | Parameters |
|
157 | Parameters | |
158 | ---------- |
|
158 | ---------- | |
159 |
|
159 | |||
160 | block : bool |
|
160 | block : bool | |
161 | whether to wait for results |
|
161 | whether to wait for results | |
162 | track : bool |
|
162 | track : bool | |
163 | whether to create a MessageTracker to allow the user to |
|
163 | whether to create a MessageTracker to allow the user to | |
164 | safely edit after arrays and buffers during non-copying |
|
164 | safely edit after arrays and buffers during non-copying | |
165 | sends. |
|
165 | sends. | |
166 | """ |
|
166 | """ | |
167 | for name, value in iteritems(kwargs): |
|
167 | for name, value in iteritems(kwargs): | |
168 | if name not in self._flag_names: |
|
168 | if name not in self._flag_names: | |
169 | raise KeyError("Invalid name: %r"%name) |
|
169 | raise KeyError("Invalid name: %r"%name) | |
170 | else: |
|
170 | else: | |
171 | setattr(self, name, value) |
|
171 | setattr(self, name, value) | |
172 |
|
172 | |||
173 | @contextmanager |
|
173 | @contextmanager | |
174 | def temp_flags(self, **kwargs): |
|
174 | def temp_flags(self, **kwargs): | |
175 | """temporarily set flags, for use in `with` statements. |
|
175 | """temporarily set flags, for use in `with` statements. | |
176 |
|
176 | |||
177 | See set_flags for permanent setting of flags |
|
177 | See set_flags for permanent setting of flags | |
178 |
|
178 | |||
179 | Examples |
|
179 | Examples | |
180 | -------- |
|
180 | -------- | |
181 |
|
181 | |||
182 | >>> view.track=False |
|
182 | >>> view.track=False | |
183 | ... |
|
183 | ... | |
184 | >>> with view.temp_flags(track=True): |
|
184 | >>> with view.temp_flags(track=True): | |
185 | ... ar = view.apply(dostuff, my_big_array) |
|
185 | ... ar = view.apply(dostuff, my_big_array) | |
186 | ... ar.tracker.wait() # wait for send to finish |
|
186 | ... ar.tracker.wait() # wait for send to finish | |
187 | >>> view.track |
|
187 | >>> view.track | |
188 | False |
|
188 | False | |
189 |
|
189 | |||
190 | """ |
|
190 | """ | |
191 | # preflight: save flags, and set temporaries |
|
191 | # preflight: save flags, and set temporaries | |
192 | saved_flags = {} |
|
192 | saved_flags = {} | |
193 | for f in self._flag_names: |
|
193 | for f in self._flag_names: | |
194 | saved_flags[f] = getattr(self, f) |
|
194 | saved_flags[f] = getattr(self, f) | |
195 | self.set_flags(**kwargs) |
|
195 | self.set_flags(**kwargs) | |
196 | # yield to the with-statement block |
|
196 | # yield to the with-statement block | |
197 | try: |
|
197 | try: | |
198 | yield |
|
198 | yield | |
199 | finally: |
|
199 | finally: | |
200 | # postflight: restore saved flags |
|
200 | # postflight: restore saved flags | |
201 | self.set_flags(**saved_flags) |
|
201 | self.set_flags(**saved_flags) | |
202 |
|
202 | |||
203 |
|
203 | |||
204 | #---------------------------------------------------------------- |
|
204 | #---------------------------------------------------------------- | |
205 | # apply |
|
205 | # apply | |
206 | #---------------------------------------------------------------- |
|
206 | #---------------------------------------------------------------- | |
207 |
|
207 | |||
208 | def _sync_results(self): |
|
208 | def _sync_results(self): | |
209 | """to be called by @sync_results decorator |
|
209 | """to be called by @sync_results decorator | |
210 |
|
210 | |||
211 | after submitting any tasks. |
|
211 | after submitting any tasks. | |
212 | """ |
|
212 | """ | |
213 | delta = self.outstanding.difference(self.client.outstanding) |
|
213 | delta = self.outstanding.difference(self.client.outstanding) | |
214 | completed = self.outstanding.intersection(delta) |
|
214 | completed = self.outstanding.intersection(delta) | |
215 | self.outstanding = self.outstanding.difference(completed) |
|
215 | self.outstanding = self.outstanding.difference(completed) | |
216 |
|
216 | |||
217 | @sync_results |
|
217 | @sync_results | |
218 | @save_ids |
|
218 | @save_ids | |
219 | def _really_apply(self, f, args, kwargs, block=None, **options): |
|
219 | def _really_apply(self, f, args, kwargs, block=None, **options): | |
220 | """wrapper for client.send_apply_request""" |
|
220 | """wrapper for client.send_apply_request""" | |
221 | raise NotImplementedError("Implement in subclasses") |
|
221 | raise NotImplementedError("Implement in subclasses") | |
222 |
|
222 | |||
223 | def apply(self, f, *args, **kwargs): |
|
223 | def apply(self, f, *args, **kwargs): | |
224 | """calls f(*args, **kwargs) on remote engines, returning the result. |
|
224 | """calls ``f(*args, **kwargs)`` on remote engines, returning the result. | |
225 |
|
225 | |||
226 | This method sets all apply flags via this View's attributes. |
|
226 | This method sets all apply flags via this View's attributes. | |
227 |
|
227 | |||
228 | if self.block is False: |
|
228 | Returns :class:`~IPython.parallel.client.asyncresult.AsyncResult` | |
229 | returns AsyncResult |
|
229 | instance if ``self.block`` is False, otherwise the return value of | |
230 | else: |
|
230 | ``f(*args, **kwargs)``. | |
231 | returns actual result of f(*args, **kwargs) |
|
|||
232 | """ |
|
231 | """ | |
233 | return self._really_apply(f, args, kwargs) |
|
232 | return self._really_apply(f, args, kwargs) | |
234 |
|
233 | |||
235 | def apply_async(self, f, *args, **kwargs): |
|
234 | def apply_async(self, f, *args, **kwargs): | |
236 | """calls f(*args, **kwargs) on remote engines in a nonblocking manner. |
|
235 | """calls ``f(*args, **kwargs)`` on remote engines in a nonblocking manner. | |
237 |
|
236 | |||
238 | returns AsyncResult |
|
237 | Returns :class:`~IPython.parallel.client.asyncresult.AsyncResult` instance. | |
239 | """ |
|
238 | """ | |
240 | return self._really_apply(f, args, kwargs, block=False) |
|
239 | return self._really_apply(f, args, kwargs, block=False) | |
241 |
|
240 | |||
242 | @spin_after |
|
241 | @spin_after | |
243 | def apply_sync(self, f, *args, **kwargs): |
|
242 | def apply_sync(self, f, *args, **kwargs): | |
244 | """calls f(*args, **kwargs) on remote engines in a blocking manner, |
|
243 | """calls ``f(*args, **kwargs)`` on remote engines in a blocking manner, | |
245 | returning the result. |
|
244 | returning the result. | |
246 |
|
||||
247 | returns: actual result of f(*args, **kwargs) |
|
|||
248 | """ |
|
245 | """ | |
249 | return self._really_apply(f, args, kwargs, block=True) |
|
246 | return self._really_apply(f, args, kwargs, block=True) | |
250 |
|
247 | |||
251 | #---------------------------------------------------------------- |
|
248 | #---------------------------------------------------------------- | |
252 | # wrappers for client and control methods |
|
249 | # wrappers for client and control methods | |
253 | #---------------------------------------------------------------- |
|
250 | #---------------------------------------------------------------- | |
254 | @sync_results |
|
251 | @sync_results | |
255 | def spin(self): |
|
252 | def spin(self): | |
256 | """spin the client, and sync""" |
|
253 | """spin the client, and sync""" | |
257 | self.client.spin() |
|
254 | self.client.spin() | |
258 |
|
255 | |||
259 | @sync_results |
|
256 | @sync_results | |
260 | def wait(self, jobs=None, timeout=-1): |
|
257 | def wait(self, jobs=None, timeout=-1): | |
261 | """waits on one or more `jobs`, for up to `timeout` seconds. |
|
258 | """waits on one or more `jobs`, for up to `timeout` seconds. | |
262 |
|
259 | |||
263 | Parameters |
|
260 | Parameters | |
264 | ---------- |
|
261 | ---------- | |
265 |
|
262 | |||
266 | jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects |
|
263 | jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects | |
267 | ints are indices to self.history |
|
264 | ints are indices to self.history | |
268 | strs are msg_ids |
|
265 | strs are msg_ids | |
269 | default: wait on all outstanding messages |
|
266 | default: wait on all outstanding messages | |
270 | timeout : float |
|
267 | timeout : float | |
271 | a time in seconds, after which to give up. |
|
268 | a time in seconds, after which to give up. | |
272 | default is -1, which means no timeout |
|
269 | default is -1, which means no timeout | |
273 |
|
270 | |||
274 | Returns |
|
271 | Returns | |
275 | ------- |
|
272 | ------- | |
276 |
|
273 | |||
277 | True : when all msg_ids are done |
|
274 | True : when all msg_ids are done | |
278 | False : timeout reached, some msg_ids still outstanding |
|
275 | False : timeout reached, some msg_ids still outstanding | |
279 | """ |
|
276 | """ | |
280 | if jobs is None: |
|
277 | if jobs is None: | |
281 | jobs = self.history |
|
278 | jobs = self.history | |
282 | return self.client.wait(jobs, timeout) |
|
279 | return self.client.wait(jobs, timeout) | |
283 |
|
280 | |||
284 | def abort(self, jobs=None, targets=None, block=None): |
|
281 | def abort(self, jobs=None, targets=None, block=None): | |
285 | """Abort jobs on my engines. |
|
282 | """Abort jobs on my engines. | |
286 |
|
283 | |||
287 | Parameters |
|
284 | Parameters | |
288 | ---------- |
|
285 | ---------- | |
289 |
|
286 | |||
290 | jobs : None, str, list of strs, optional |
|
287 | jobs : None, str, list of strs, optional | |
291 | if None: abort all jobs. |
|
288 | if None: abort all jobs. | |
292 | else: abort specific msg_id(s). |
|
289 | else: abort specific msg_id(s). | |
293 | """ |
|
290 | """ | |
294 | block = block if block is not None else self.block |
|
291 | block = block if block is not None else self.block | |
295 | targets = targets if targets is not None else self.targets |
|
292 | targets = targets if targets is not None else self.targets | |
296 | jobs = jobs if jobs is not None else list(self.outstanding) |
|
293 | jobs = jobs if jobs is not None else list(self.outstanding) | |
297 |
|
294 | |||
298 | return self.client.abort(jobs=jobs, targets=targets, block=block) |
|
295 | return self.client.abort(jobs=jobs, targets=targets, block=block) | |
299 |
|
296 | |||
300 | def queue_status(self, targets=None, verbose=False): |
|
297 | def queue_status(self, targets=None, verbose=False): | |
301 | """Fetch the Queue status of my engines""" |
|
298 | """Fetch the Queue status of my engines""" | |
302 | targets = targets if targets is not None else self.targets |
|
299 | targets = targets if targets is not None else self.targets | |
303 | return self.client.queue_status(targets=targets, verbose=verbose) |
|
300 | return self.client.queue_status(targets=targets, verbose=verbose) | |
304 |
|
301 | |||
305 | def purge_results(self, jobs=[], targets=[]): |
|
302 | def purge_results(self, jobs=[], targets=[]): | |
306 | """Instruct the controller to forget specific results.""" |
|
303 | """Instruct the controller to forget specific results.""" | |
307 | if targets is None or targets == 'all': |
|
304 | if targets is None or targets == 'all': | |
308 | targets = self.targets |
|
305 | targets = self.targets | |
309 | return self.client.purge_results(jobs=jobs, targets=targets) |
|
306 | return self.client.purge_results(jobs=jobs, targets=targets) | |
310 |
|
307 | |||
311 | def shutdown(self, targets=None, restart=False, hub=False, block=None): |
|
308 | def shutdown(self, targets=None, restart=False, hub=False, block=None): | |
312 | """Terminates one or more engine processes, optionally including the hub. |
|
309 | """Terminates one or more engine processes, optionally including the hub. | |
313 | """ |
|
310 | """ | |
314 | block = self.block if block is None else block |
|
311 | block = self.block if block is None else block | |
315 | if targets is None or targets == 'all': |
|
312 | if targets is None or targets == 'all': | |
316 | targets = self.targets |
|
313 | targets = self.targets | |
317 | return self.client.shutdown(targets=targets, restart=restart, hub=hub, block=block) |
|
314 | return self.client.shutdown(targets=targets, restart=restart, hub=hub, block=block) | |
318 |
|
315 | |||
319 | @spin_after |
|
316 | @spin_after | |
320 | def get_result(self, indices_or_msg_ids=None): |
|
317 | def get_result(self, indices_or_msg_ids=None): | |
321 | """return one or more results, specified by history index or msg_id. |
|
318 | """return one or more results, specified by history index or msg_id. | |
322 |
|
319 | |||
323 | See client.get_result for details. |
|
320 | See :meth:`IPython.parallel.client.client.Client.get_result` for details. | |
324 |
|
||||
325 | """ |
|
321 | """ | |
326 |
|
322 | |||
327 | if indices_or_msg_ids is None: |
|
323 | if indices_or_msg_ids is None: | |
328 | indices_or_msg_ids = -1 |
|
324 | indices_or_msg_ids = -1 | |
329 | if isinstance(indices_or_msg_ids, int): |
|
325 | if isinstance(indices_or_msg_ids, int): | |
330 | indices_or_msg_ids = self.history[indices_or_msg_ids] |
|
326 | indices_or_msg_ids = self.history[indices_or_msg_ids] | |
331 | elif isinstance(indices_or_msg_ids, (list,tuple,set)): |
|
327 | elif isinstance(indices_or_msg_ids, (list,tuple,set)): | |
332 | indices_or_msg_ids = list(indices_or_msg_ids) |
|
328 | indices_or_msg_ids = list(indices_or_msg_ids) | |
333 | for i,index in enumerate(indices_or_msg_ids): |
|
329 | for i,index in enumerate(indices_or_msg_ids): | |
334 | if isinstance(index, int): |
|
330 | if isinstance(index, int): | |
335 | indices_or_msg_ids[i] = self.history[index] |
|
331 | indices_or_msg_ids[i] = self.history[index] | |
336 | return self.client.get_result(indices_or_msg_ids) |
|
332 | return self.client.get_result(indices_or_msg_ids) | |
337 |
|
333 | |||
338 | #------------------------------------------------------------------- |
|
334 | #------------------------------------------------------------------- | |
339 | # Map |
|
335 | # Map | |
340 | #------------------------------------------------------------------- |
|
336 | #------------------------------------------------------------------- | |
341 |
|
337 | |||
342 | @sync_results |
|
338 | @sync_results | |
343 | def map(self, f, *sequences, **kwargs): |
|
339 | def map(self, f, *sequences, **kwargs): | |
344 | """override in subclasses""" |
|
340 | """override in subclasses""" | |
345 | raise NotImplementedError |
|
341 | raise NotImplementedError | |
346 |
|
342 | |||
347 | def map_async(self, f, *sequences, **kwargs): |
|
343 | def map_async(self, f, *sequences, **kwargs): | |
348 | """Parallel version of builtin `map`, using this view's engines. |
|
344 | """Parallel version of builtin :func:`python:map`, using this view's engines. | |
349 |
|
345 | |||
350 | This is equivalent to map(...block=False) |
|
346 | This is equivalent to ``map(...block=False)``. | |
351 |
|
347 | |||
352 | See `self.map` for details. |
|
348 | See `self.map` for details. | |
353 | """ |
|
349 | """ | |
354 | if 'block' in kwargs: |
|
350 | if 'block' in kwargs: | |
355 | raise TypeError("map_async doesn't take a `block` keyword argument.") |
|
351 | raise TypeError("map_async doesn't take a `block` keyword argument.") | |
356 | kwargs['block'] = False |
|
352 | kwargs['block'] = False | |
357 | return self.map(f,*sequences,**kwargs) |
|
353 | return self.map(f,*sequences,**kwargs) | |
358 |
|
354 | |||
359 | def map_sync(self, f, *sequences, **kwargs): |
|
355 | def map_sync(self, f, *sequences, **kwargs): | |
360 | """Parallel version of builtin `map`, using this view's engines. |
|
356 | """Parallel version of builtin :func:`python:map`, using this view's engines. | |
361 |
|
357 | |||
362 | This is equivalent to map(...block=True) |
|
358 | This is equivalent to ``map(...block=True)``. | |
363 |
|
359 | |||
364 | See `self.map` for details. |
|
360 | See `self.map` for details. | |
365 | """ |
|
361 | """ | |
366 | if 'block' in kwargs: |
|
362 | if 'block' in kwargs: | |
367 | raise TypeError("map_sync doesn't take a `block` keyword argument.") |
|
363 | raise TypeError("map_sync doesn't take a `block` keyword argument.") | |
368 | kwargs['block'] = True |
|
364 | kwargs['block'] = True | |
369 | return self.map(f,*sequences,**kwargs) |
|
365 | return self.map(f,*sequences,**kwargs) | |
370 |
|
366 | |||
371 | def imap(self, f, *sequences, **kwargs): |
|
367 | def imap(self, f, *sequences, **kwargs): | |
372 | """Parallel version of `itertools.imap`. |
|
368 | """Parallel version of :func:`itertools.imap`. | |
373 |
|
369 | |||
374 | See `self.map` for details. |
|
370 | See `self.map` for details. | |
375 |
|
371 | |||
376 | """ |
|
372 | """ | |
377 |
|
373 | |||
378 | return iter(self.map_async(f,*sequences, **kwargs)) |
|
374 | return iter(self.map_async(f,*sequences, **kwargs)) | |
379 |
|
375 | |||
380 | #------------------------------------------------------------------- |
|
376 | #------------------------------------------------------------------- | |
381 | # Decorators |
|
377 | # Decorators | |
382 | #------------------------------------------------------------------- |
|
378 | #------------------------------------------------------------------- | |
383 |
|
379 | |||
384 | def remote(self, block=None, **flags): |
|
380 | def remote(self, block=None, **flags): | |
385 | """Decorator for making a RemoteFunction""" |
|
381 | """Decorator for making a RemoteFunction""" | |
386 | block = self.block if block is None else block |
|
382 | block = self.block if block is None else block | |
387 | return remote(self, block=block, **flags) |
|
383 | return remote(self, block=block, **flags) | |
388 |
|
384 | |||
389 | def parallel(self, dist='b', block=None, **flags): |
|
385 | def parallel(self, dist='b', block=None, **flags): | |
390 | """Decorator for making a ParallelFunction""" |
|
386 | """Decorator for making a ParallelFunction""" | |
391 | block = self.block if block is None else block |
|
387 | block = self.block if block is None else block | |
392 | return parallel(self, dist=dist, block=block, **flags) |
|
388 | return parallel(self, dist=dist, block=block, **flags) | |
393 |
|
389 | |||
394 | @skip_doctest |
|
390 | @skip_doctest | |
395 | class DirectView(View): |
|
391 | class DirectView(View): | |
396 | """Direct Multiplexer View of one or more engines. |
|
392 | """Direct Multiplexer View of one or more engines. | |
397 |
|
393 | |||
398 | These are created via indexed access to a client: |
|
394 | These are created via indexed access to a client: | |
399 |
|
395 | |||
400 | >>> dv_1 = client[1] |
|
396 | >>> dv_1 = client[1] | |
401 | >>> dv_all = client[:] |
|
397 | >>> dv_all = client[:] | |
402 | >>> dv_even = client[::2] |
|
398 | >>> dv_even = client[::2] | |
403 | >>> dv_some = client[1:3] |
|
399 | >>> dv_some = client[1:3] | |
404 |
|
400 | |||
405 | This object provides dictionary access to engine namespaces: |
|
401 | This object provides dictionary access to engine namespaces: | |
406 |
|
402 | |||
407 | # push a=5: |
|
403 | # push a=5: | |
408 | >>> dv['a'] = 5 |
|
404 | >>> dv['a'] = 5 | |
409 | # pull 'foo': |
|
405 | # pull 'foo': | |
410 | >>> db['foo'] |
|
406 | >>> db['foo'] | |
411 |
|
407 | |||
412 | """ |
|
408 | """ | |
413 |
|
409 | |||
414 | def __init__(self, client=None, socket=None, targets=None): |
|
410 | def __init__(self, client=None, socket=None, targets=None): | |
415 | super(DirectView, self).__init__(client=client, socket=socket, targets=targets) |
|
411 | super(DirectView, self).__init__(client=client, socket=socket, targets=targets) | |
416 |
|
412 | |||
417 | @property |
|
413 | @property | |
418 | def importer(self): |
|
414 | def importer(self): | |
419 | """sync_imports(local=True) as a property. |
|
415 | """sync_imports(local=True) as a property. | |
420 |
|
416 | |||
421 | See sync_imports for details. |
|
417 | See sync_imports for details. | |
422 |
|
418 | |||
423 | """ |
|
419 | """ | |
424 | return self.sync_imports(True) |
|
420 | return self.sync_imports(True) | |
425 |
|
421 | |||
426 | @contextmanager |
|
422 | @contextmanager | |
427 | def sync_imports(self, local=True, quiet=False): |
|
423 | def sync_imports(self, local=True, quiet=False): | |
428 | """Context Manager for performing simultaneous local and remote imports. |
|
424 | """Context Manager for performing simultaneous local and remote imports. | |
429 |
|
425 | |||
430 | 'import x as y' will *not* work. The 'as y' part will simply be ignored. |
|
426 | 'import x as y' will *not* work. The 'as y' part will simply be ignored. | |
431 |
|
427 | |||
432 | If `local=True`, then the package will also be imported locally. |
|
428 | If `local=True`, then the package will also be imported locally. | |
433 |
|
429 | |||
434 | If `quiet=True`, no output will be produced when attempting remote |
|
430 | If `quiet=True`, no output will be produced when attempting remote | |
435 | imports. |
|
431 | imports. | |
436 |
|
432 | |||
437 | Note that remote-only (`local=False`) imports have not been implemented. |
|
433 | Note that remote-only (`local=False`) imports have not been implemented. | |
438 |
|
434 | |||
439 | >>> with view.sync_imports(): |
|
435 | >>> with view.sync_imports(): | |
440 | ... from numpy import recarray |
|
436 | ... from numpy import recarray | |
441 | importing recarray from numpy on engine(s) |
|
437 | importing recarray from numpy on engine(s) | |
442 |
|
438 | |||
443 | """ |
|
439 | """ | |
444 | from IPython.utils.py3compat import builtin_mod |
|
440 | from IPython.utils.py3compat import builtin_mod | |
445 | local_import = builtin_mod.__import__ |
|
441 | local_import = builtin_mod.__import__ | |
446 | modules = set() |
|
442 | modules = set() | |
447 | results = [] |
|
443 | results = [] | |
448 | @util.interactive |
|
444 | @util.interactive | |
449 | def remote_import(name, fromlist, level): |
|
445 | def remote_import(name, fromlist, level): | |
450 | """the function to be passed to apply, that actually performs the import |
|
446 | """the function to be passed to apply, that actually performs the import | |
451 | on the engine, and loads up the user namespace. |
|
447 | on the engine, and loads up the user namespace. | |
452 | """ |
|
448 | """ | |
453 | import sys |
|
449 | import sys | |
454 | user_ns = globals() |
|
450 | user_ns = globals() | |
455 | mod = __import__(name, fromlist=fromlist, level=level) |
|
451 | mod = __import__(name, fromlist=fromlist, level=level) | |
456 | if fromlist: |
|
452 | if fromlist: | |
457 | for key in fromlist: |
|
453 | for key in fromlist: | |
458 | user_ns[key] = getattr(mod, key) |
|
454 | user_ns[key] = getattr(mod, key) | |
459 | else: |
|
455 | else: | |
460 | user_ns[name] = sys.modules[name] |
|
456 | user_ns[name] = sys.modules[name] | |
461 |
|
457 | |||
462 | def view_import(name, globals={}, locals={}, fromlist=[], level=0): |
|
458 | def view_import(name, globals={}, locals={}, fromlist=[], level=0): | |
463 | """the drop-in replacement for __import__, that optionally imports |
|
459 | """the drop-in replacement for __import__, that optionally imports | |
464 | locally as well. |
|
460 | locally as well. | |
465 | """ |
|
461 | """ | |
466 | # don't override nested imports |
|
462 | # don't override nested imports | |
467 | save_import = builtin_mod.__import__ |
|
463 | save_import = builtin_mod.__import__ | |
468 | builtin_mod.__import__ = local_import |
|
464 | builtin_mod.__import__ = local_import | |
469 |
|
465 | |||
470 | if imp.lock_held(): |
|
466 | if imp.lock_held(): | |
471 | # this is a side-effect import, don't do it remotely, or even |
|
467 | # this is a side-effect import, don't do it remotely, or even | |
472 | # ignore the local effects |
|
468 | # ignore the local effects | |
473 | return local_import(name, globals, locals, fromlist, level) |
|
469 | return local_import(name, globals, locals, fromlist, level) | |
474 |
|
470 | |||
475 | imp.acquire_lock() |
|
471 | imp.acquire_lock() | |
476 | if local: |
|
472 | if local: | |
477 | mod = local_import(name, globals, locals, fromlist, level) |
|
473 | mod = local_import(name, globals, locals, fromlist, level) | |
478 | else: |
|
474 | else: | |
479 | raise NotImplementedError("remote-only imports not yet implemented") |
|
475 | raise NotImplementedError("remote-only imports not yet implemented") | |
480 | imp.release_lock() |
|
476 | imp.release_lock() | |
481 |
|
477 | |||
482 | key = name+':'+','.join(fromlist or []) |
|
478 | key = name+':'+','.join(fromlist or []) | |
483 | if level <= 0 and key not in modules: |
|
479 | if level <= 0 and key not in modules: | |
484 | modules.add(key) |
|
480 | modules.add(key) | |
485 | if not quiet: |
|
481 | if not quiet: | |
486 | if fromlist: |
|
482 | if fromlist: | |
487 | print("importing %s from %s on engine(s)"%(','.join(fromlist), name)) |
|
483 | print("importing %s from %s on engine(s)"%(','.join(fromlist), name)) | |
488 | else: |
|
484 | else: | |
489 | print("importing %s on engine(s)"%name) |
|
485 | print("importing %s on engine(s)"%name) | |
490 | results.append(self.apply_async(remote_import, name, fromlist, level)) |
|
486 | results.append(self.apply_async(remote_import, name, fromlist, level)) | |
491 | # restore override |
|
487 | # restore override | |
492 | builtin_mod.__import__ = save_import |
|
488 | builtin_mod.__import__ = save_import | |
493 |
|
489 | |||
494 | return mod |
|
490 | return mod | |
495 |
|
491 | |||
496 | # override __import__ |
|
492 | # override __import__ | |
497 | builtin_mod.__import__ = view_import |
|
493 | builtin_mod.__import__ = view_import | |
498 | try: |
|
494 | try: | |
499 | # enter the block |
|
495 | # enter the block | |
500 | yield |
|
496 | yield | |
501 | except ImportError: |
|
497 | except ImportError: | |
502 | if local: |
|
498 | if local: | |
503 | raise |
|
499 | raise | |
504 | else: |
|
500 | else: | |
505 | # ignore import errors if not doing local imports |
|
501 | # ignore import errors if not doing local imports | |
506 | pass |
|
502 | pass | |
507 | finally: |
|
503 | finally: | |
508 | # always restore __import__ |
|
504 | # always restore __import__ | |
509 | builtin_mod.__import__ = local_import |
|
505 | builtin_mod.__import__ = local_import | |
510 |
|
506 | |||
511 | for r in results: |
|
507 | for r in results: | |
512 | # raise possible remote ImportErrors here |
|
508 | # raise possible remote ImportErrors here | |
513 | r.get() |
|
509 | r.get() | |
514 |
|
510 | |||
515 |
|
511 | |||
516 | @sync_results |
|
512 | @sync_results | |
517 | @save_ids |
|
513 | @save_ids | |
518 | def _really_apply(self, f, args=None, kwargs=None, targets=None, block=None, track=None): |
|
514 | def _really_apply(self, f, args=None, kwargs=None, targets=None, block=None, track=None): | |
519 | """calls f(*args, **kwargs) on remote engines, returning the result. |
|
515 | """calls f(*args, **kwargs) on remote engines, returning the result. | |
520 |
|
516 | |||
521 | This method sets all of `apply`'s flags via this View's attributes. |
|
517 | This method sets all of `apply`'s flags via this View's attributes. | |
522 |
|
518 | |||
523 | Parameters |
|
519 | Parameters | |
524 | ---------- |
|
520 | ---------- | |
525 |
|
521 | |||
526 | f : callable |
|
522 | f : callable | |
527 |
|
523 | |||
528 | args : list [default: empty] |
|
524 | args : list [default: empty] | |
529 |
|
525 | |||
530 | kwargs : dict [default: empty] |
|
526 | kwargs : dict [default: empty] | |
531 |
|
527 | |||
532 | targets : target list [default: self.targets] |
|
528 | targets : target list [default: self.targets] | |
533 | where to run |
|
529 | where to run | |
534 | block : bool [default: self.block] |
|
530 | block : bool [default: self.block] | |
535 | whether to block |
|
531 | whether to block | |
536 | track : bool [default: self.track] |
|
532 | track : bool [default: self.track] | |
537 | whether to ask zmq to track the message, for safe non-copying sends |
|
533 | whether to ask zmq to track the message, for safe non-copying sends | |
538 |
|
534 | |||
539 | Returns |
|
535 | Returns | |
540 | ------- |
|
536 | ------- | |
541 |
|
537 | |||
542 | if self.block is False: |
|
538 | if self.block is False: | |
543 | returns AsyncResult |
|
539 | returns AsyncResult | |
544 | else: |
|
540 | else: | |
545 | returns actual result of f(*args, **kwargs) on the engine(s) |
|
541 | returns actual result of f(*args, **kwargs) on the engine(s) | |
546 | This will be a list of self.targets is also a list (even length 1), or |
|
542 | This will be a list of self.targets is also a list (even length 1), or | |
547 | the single result if self.targets is an integer engine id |
|
543 | the single result if self.targets is an integer engine id | |
548 | """ |
|
544 | """ | |
549 | args = [] if args is None else args |
|
545 | args = [] if args is None else args | |
550 | kwargs = {} if kwargs is None else kwargs |
|
546 | kwargs = {} if kwargs is None else kwargs | |
551 | block = self.block if block is None else block |
|
547 | block = self.block if block is None else block | |
552 | track = self.track if track is None else track |
|
548 | track = self.track if track is None else track | |
553 | targets = self.targets if targets is None else targets |
|
549 | targets = self.targets if targets is None else targets | |
554 |
|
550 | |||
555 | _idents, _targets = self.client._build_targets(targets) |
|
551 | _idents, _targets = self.client._build_targets(targets) | |
556 | msg_ids = [] |
|
552 | msg_ids = [] | |
557 | trackers = [] |
|
553 | trackers = [] | |
558 | for ident in _idents: |
|
554 | for ident in _idents: | |
559 | msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track, |
|
555 | msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track, | |
560 | ident=ident) |
|
556 | ident=ident) | |
561 | if track: |
|
557 | if track: | |
562 | trackers.append(msg['tracker']) |
|
558 | trackers.append(msg['tracker']) | |
563 | msg_ids.append(msg['header']['msg_id']) |
|
559 | msg_ids.append(msg['header']['msg_id']) | |
564 | if isinstance(targets, int): |
|
560 | if isinstance(targets, int): | |
565 | msg_ids = msg_ids[0] |
|
561 | msg_ids = msg_ids[0] | |
566 | tracker = None if track is False else zmq.MessageTracker(*trackers) |
|
562 | tracker = None if track is False else zmq.MessageTracker(*trackers) | |
567 | ar = AsyncResult(self.client, msg_ids, fname=getname(f), targets=_targets, tracker=tracker) |
|
563 | ar = AsyncResult(self.client, msg_ids, fname=getname(f), targets=_targets, tracker=tracker) | |
568 | if block: |
|
564 | if block: | |
569 | try: |
|
565 | try: | |
570 | return ar.get() |
|
566 | return ar.get() | |
571 | except KeyboardInterrupt: |
|
567 | except KeyboardInterrupt: | |
572 | pass |
|
568 | pass | |
573 | return ar |
|
569 | return ar | |
574 |
|
570 | |||
575 |
|
571 | |||
576 | @sync_results |
|
572 | @sync_results | |
577 | def map(self, f, *sequences, **kwargs): |
|
573 | def map(self, f, *sequences, **kwargs): | |
578 | """view.map(f, *sequences, block=self.block) => list|AsyncMapResult |
|
574 | """``view.map(f, *sequences, block=self.block)`` => list|AsyncMapResult | |
579 |
|
575 | |||
580 | Parallel version of builtin `map`, using this View's `targets`. |
|
576 | Parallel version of builtin `map`, using this View's `targets`. | |
581 |
|
577 | |||
582 | There will be one task per target, so work will be chunked |
|
578 | There will be one task per target, so work will be chunked | |
583 | if the sequences are longer than `targets`. |
|
579 | if the sequences are longer than `targets`. | |
584 |
|
580 | |||
585 | Results can be iterated as they are ready, but will become available in chunks. |
|
581 | Results can be iterated as they are ready, but will become available in chunks. | |
586 |
|
582 | |||
587 | Parameters |
|
583 | Parameters | |
588 | ---------- |
|
584 | ---------- | |
589 |
|
585 | |||
590 | f : callable |
|
586 | f : callable | |
591 | function to be mapped |
|
587 | function to be mapped | |
592 | *sequences: one or more sequences of matching length |
|
588 | *sequences: one or more sequences of matching length | |
593 | the sequences to be distributed and passed to `f` |
|
589 | the sequences to be distributed and passed to `f` | |
594 | block : bool |
|
590 | block : bool | |
595 | whether to wait for the result or not [default self.block] |
|
591 | whether to wait for the result or not [default self.block] | |
596 |
|
592 | |||
597 | Returns |
|
593 | Returns | |
598 | ------- |
|
594 | ------- | |
599 |
|
595 | |||
600 | if block=False: |
|
596 | ||
601 | AsyncMapResult |
|
597 | If block=False | |
|
598 | An :class:`~IPython.parallel.client.asyncresult.AsyncMapResult` instance. | |||
602 |
|
|
599 | An object like AsyncResult, but which reassembles the sequence of results | |
603 |
|
|
600 | into a single list. AsyncMapResults can be iterated through before all | |
604 |
|
|
601 | results are complete. | |
605 |
else |
|
602 | else | |
606 | list |
|
603 | A list, the result of ``map(f,*sequences)`` | |
607 | the result of map(f,*sequences) |
|
|||
608 | """ |
|
604 | """ | |
609 |
|
605 | |||
610 | block = kwargs.pop('block', self.block) |
|
606 | block = kwargs.pop('block', self.block) | |
611 | for k in kwargs.keys(): |
|
607 | for k in kwargs.keys(): | |
612 | if k not in ['block', 'track']: |
|
608 | if k not in ['block', 'track']: | |
613 | raise TypeError("invalid keyword arg, %r"%k) |
|
609 | raise TypeError("invalid keyword arg, %r"%k) | |
614 |
|
610 | |||
615 | assert len(sequences) > 0, "must have some sequences to map onto!" |
|
611 | assert len(sequences) > 0, "must have some sequences to map onto!" | |
616 | pf = ParallelFunction(self, f, block=block, **kwargs) |
|
612 | pf = ParallelFunction(self, f, block=block, **kwargs) | |
617 | return pf.map(*sequences) |
|
613 | return pf.map(*sequences) | |
618 |
|
614 | |||
619 | @sync_results |
|
615 | @sync_results | |
620 | @save_ids |
|
616 | @save_ids | |
621 | def execute(self, code, silent=True, targets=None, block=None): |
|
617 | def execute(self, code, silent=True, targets=None, block=None): | |
622 | """Executes `code` on `targets` in blocking or nonblocking manner. |
|
618 | """Executes `code` on `targets` in blocking or nonblocking manner. | |
623 |
|
619 | |||
624 | ``execute`` is always `bound` (affects engine namespace) |
|
620 | ``execute`` is always `bound` (affects engine namespace) | |
625 |
|
621 | |||
626 | Parameters |
|
622 | Parameters | |
627 | ---------- |
|
623 | ---------- | |
628 |
|
624 | |||
629 | code : str |
|
625 | code : str | |
630 | the code string to be executed |
|
626 | the code string to be executed | |
631 | block : bool |
|
627 | block : bool | |
632 | whether or not to wait until done to return |
|
628 | whether or not to wait until done to return | |
633 | default: self.block |
|
629 | default: self.block | |
634 | """ |
|
630 | """ | |
635 | block = self.block if block is None else block |
|
631 | block = self.block if block is None else block | |
636 | targets = self.targets if targets is None else targets |
|
632 | targets = self.targets if targets is None else targets | |
637 |
|
633 | |||
638 | _idents, _targets = self.client._build_targets(targets) |
|
634 | _idents, _targets = self.client._build_targets(targets) | |
639 | msg_ids = [] |
|
635 | msg_ids = [] | |
640 | trackers = [] |
|
636 | trackers = [] | |
641 | for ident in _idents: |
|
637 | for ident in _idents: | |
642 | msg = self.client.send_execute_request(self._socket, code, silent=silent, ident=ident) |
|
638 | msg = self.client.send_execute_request(self._socket, code, silent=silent, ident=ident) | |
643 | msg_ids.append(msg['header']['msg_id']) |
|
639 | msg_ids.append(msg['header']['msg_id']) | |
644 | if isinstance(targets, int): |
|
640 | if isinstance(targets, int): | |
645 | msg_ids = msg_ids[0] |
|
641 | msg_ids = msg_ids[0] | |
646 | ar = AsyncResult(self.client, msg_ids, fname='execute', targets=_targets) |
|
642 | ar = AsyncResult(self.client, msg_ids, fname='execute', targets=_targets) | |
647 | if block: |
|
643 | if block: | |
648 | try: |
|
644 | try: | |
649 | ar.get() |
|
645 | ar.get() | |
650 | except KeyboardInterrupt: |
|
646 | except KeyboardInterrupt: | |
651 | pass |
|
647 | pass | |
652 | return ar |
|
648 | return ar | |
653 |
|
649 | |||
654 | def run(self, filename, targets=None, block=None): |
|
650 | def run(self, filename, targets=None, block=None): | |
655 | """Execute contents of `filename` on my engine(s). |
|
651 | """Execute contents of `filename` on my engine(s). | |
656 |
|
652 | |||
657 | This simply reads the contents of the file and calls `execute`. |
|
653 | This simply reads the contents of the file and calls `execute`. | |
658 |
|
654 | |||
659 | Parameters |
|
655 | Parameters | |
660 | ---------- |
|
656 | ---------- | |
661 |
|
657 | |||
662 | filename : str |
|
658 | filename : str | |
663 | The path to the file |
|
659 | The path to the file | |
664 | targets : int/str/list of ints/strs |
|
660 | targets : int/str/list of ints/strs | |
665 | the engines on which to execute |
|
661 | the engines on which to execute | |
666 | default : all |
|
662 | default : all | |
667 | block : bool |
|
663 | block : bool | |
668 | whether or not to wait until done |
|
664 | whether or not to wait until done | |
669 | default: self.block |
|
665 | default: self.block | |
670 |
|
666 | |||
671 | """ |
|
667 | """ | |
672 | with open(filename, 'r') as f: |
|
668 | with open(filename, 'r') as f: | |
673 | # add newline in case of trailing indented whitespace |
|
669 | # add newline in case of trailing indented whitespace | |
674 | # which will cause SyntaxError |
|
670 | # which will cause SyntaxError | |
675 | code = f.read()+'\n' |
|
671 | code = f.read()+'\n' | |
676 | return self.execute(code, block=block, targets=targets) |
|
672 | return self.execute(code, block=block, targets=targets) | |
677 |
|
673 | |||
678 | def update(self, ns): |
|
674 | def update(self, ns): | |
679 | """update remote namespace with dict `ns` |
|
675 | """update remote namespace with dict `ns` | |
680 |
|
676 | |||
681 | See `push` for details. |
|
677 | See `push` for details. | |
682 | """ |
|
678 | """ | |
683 | return self.push(ns, block=self.block, track=self.track) |
|
679 | return self.push(ns, block=self.block, track=self.track) | |
684 |
|
680 | |||
685 | def push(self, ns, targets=None, block=None, track=None): |
|
681 | def push(self, ns, targets=None, block=None, track=None): | |
686 | """update remote namespace with dict `ns` |
|
682 | """update remote namespace with dict `ns` | |
687 |
|
683 | |||
688 | Parameters |
|
684 | Parameters | |
689 | ---------- |
|
685 | ---------- | |
690 |
|
686 | |||
691 | ns : dict |
|
687 | ns : dict | |
692 | dict of keys with which to update engine namespace(s) |
|
688 | dict of keys with which to update engine namespace(s) | |
693 | block : bool [default : self.block] |
|
689 | block : bool [default : self.block] | |
694 | whether to wait to be notified of engine receipt |
|
690 | whether to wait to be notified of engine receipt | |
695 |
|
691 | |||
696 | """ |
|
692 | """ | |
697 |
|
693 | |||
698 | block = block if block is not None else self.block |
|
694 | block = block if block is not None else self.block | |
699 | track = track if track is not None else self.track |
|
695 | track = track if track is not None else self.track | |
700 | targets = targets if targets is not None else self.targets |
|
696 | targets = targets if targets is not None else self.targets | |
701 | # applier = self.apply_sync if block else self.apply_async |
|
697 | # applier = self.apply_sync if block else self.apply_async | |
702 | if not isinstance(ns, dict): |
|
698 | if not isinstance(ns, dict): | |
703 | raise TypeError("Must be a dict, not %s"%type(ns)) |
|
699 | raise TypeError("Must be a dict, not %s"%type(ns)) | |
704 | return self._really_apply(util._push, kwargs=ns, block=block, track=track, targets=targets) |
|
700 | return self._really_apply(util._push, kwargs=ns, block=block, track=track, targets=targets) | |
705 |
|
701 | |||
706 | def get(self, key_s): |
|
702 | def get(self, key_s): | |
707 | """get object(s) by `key_s` from remote namespace |
|
703 | """get object(s) by `key_s` from remote namespace | |
708 |
|
704 | |||
709 | see `pull` for details. |
|
705 | see `pull` for details. | |
710 | """ |
|
706 | """ | |
711 | # block = block if block is not None else self.block |
|
707 | # block = block if block is not None else self.block | |
712 | return self.pull(key_s, block=True) |
|
708 | return self.pull(key_s, block=True) | |
713 |
|
709 | |||
714 | def pull(self, names, targets=None, block=None): |
|
710 | def pull(self, names, targets=None, block=None): | |
715 | """get object(s) by `name` from remote namespace |
|
711 | """get object(s) by `name` from remote namespace | |
716 |
|
712 | |||
717 | will return one object if it is a key. |
|
713 | will return one object if it is a key. | |
718 | can also take a list of keys, in which case it will return a list of objects. |
|
714 | can also take a list of keys, in which case it will return a list of objects. | |
719 | """ |
|
715 | """ | |
720 | block = block if block is not None else self.block |
|
716 | block = block if block is not None else self.block | |
721 | targets = targets if targets is not None else self.targets |
|
717 | targets = targets if targets is not None else self.targets | |
722 | applier = self.apply_sync if block else self.apply_async |
|
718 | applier = self.apply_sync if block else self.apply_async | |
723 | if isinstance(names, string_types): |
|
719 | if isinstance(names, string_types): | |
724 | pass |
|
720 | pass | |
725 | elif isinstance(names, (list,tuple,set)): |
|
721 | elif isinstance(names, (list,tuple,set)): | |
726 | for key in names: |
|
722 | for key in names: | |
727 | if not isinstance(key, string_types): |
|
723 | if not isinstance(key, string_types): | |
728 | raise TypeError("keys must be str, not type %r"%type(key)) |
|
724 | raise TypeError("keys must be str, not type %r"%type(key)) | |
729 | else: |
|
725 | else: | |
730 | raise TypeError("names must be strs, not %r"%names) |
|
726 | raise TypeError("names must be strs, not %r"%names) | |
731 | return self._really_apply(util._pull, (names,), block=block, targets=targets) |
|
727 | return self._really_apply(util._pull, (names,), block=block, targets=targets) | |
732 |
|
728 | |||
733 | def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None, track=None): |
|
729 | def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None, track=None): | |
734 | """ |
|
730 | """ | |
735 | Partition a Python sequence and send the partitions to a set of engines. |
|
731 | Partition a Python sequence and send the partitions to a set of engines. | |
736 | """ |
|
732 | """ | |
737 | block = block if block is not None else self.block |
|
733 | block = block if block is not None else self.block | |
738 | track = track if track is not None else self.track |
|
734 | track = track if track is not None else self.track | |
739 | targets = targets if targets is not None else self.targets |
|
735 | targets = targets if targets is not None else self.targets | |
740 |
|
736 | |||
741 | # construct integer ID list: |
|
737 | # construct integer ID list: | |
742 | targets = self.client._build_targets(targets)[1] |
|
738 | targets = self.client._build_targets(targets)[1] | |
743 |
|
739 | |||
744 | mapObject = Map.dists[dist]() |
|
740 | mapObject = Map.dists[dist]() | |
745 | nparts = len(targets) |
|
741 | nparts = len(targets) | |
746 | msg_ids = [] |
|
742 | msg_ids = [] | |
747 | trackers = [] |
|
743 | trackers = [] | |
748 | for index, engineid in enumerate(targets): |
|
744 | for index, engineid in enumerate(targets): | |
749 | partition = mapObject.getPartition(seq, index, nparts) |
|
745 | partition = mapObject.getPartition(seq, index, nparts) | |
750 | if flatten and len(partition) == 1: |
|
746 | if flatten and len(partition) == 1: | |
751 | ns = {key: partition[0]} |
|
747 | ns = {key: partition[0]} | |
752 | else: |
|
748 | else: | |
753 | ns = {key: partition} |
|
749 | ns = {key: partition} | |
754 | r = self.push(ns, block=False, track=track, targets=engineid) |
|
750 | r = self.push(ns, block=False, track=track, targets=engineid) | |
755 | msg_ids.extend(r.msg_ids) |
|
751 | msg_ids.extend(r.msg_ids) | |
756 | if track: |
|
752 | if track: | |
757 | trackers.append(r._tracker) |
|
753 | trackers.append(r._tracker) | |
758 |
|
754 | |||
759 | if track: |
|
755 | if track: | |
760 | tracker = zmq.MessageTracker(*trackers) |
|
756 | tracker = zmq.MessageTracker(*trackers) | |
761 | else: |
|
757 | else: | |
762 | tracker = None |
|
758 | tracker = None | |
763 |
|
759 | |||
764 | r = AsyncResult(self.client, msg_ids, fname='scatter', targets=targets, tracker=tracker) |
|
760 | r = AsyncResult(self.client, msg_ids, fname='scatter', targets=targets, tracker=tracker) | |
765 | if block: |
|
761 | if block: | |
766 | r.wait() |
|
762 | r.wait() | |
767 | else: |
|
763 | else: | |
768 | return r |
|
764 | return r | |
769 |
|
765 | |||
770 | @sync_results |
|
766 | @sync_results | |
771 | @save_ids |
|
767 | @save_ids | |
772 | def gather(self, key, dist='b', targets=None, block=None): |
|
768 | def gather(self, key, dist='b', targets=None, block=None): | |
773 | """ |
|
769 | """ | |
774 | Gather a partitioned sequence on a set of engines as a single local seq. |
|
770 | Gather a partitioned sequence on a set of engines as a single local seq. | |
775 | """ |
|
771 | """ | |
776 | block = block if block is not None else self.block |
|
772 | block = block if block is not None else self.block | |
777 | targets = targets if targets is not None else self.targets |
|
773 | targets = targets if targets is not None else self.targets | |
778 | mapObject = Map.dists[dist]() |
|
774 | mapObject = Map.dists[dist]() | |
779 | msg_ids = [] |
|
775 | msg_ids = [] | |
780 |
|
776 | |||
781 | # construct integer ID list: |
|
777 | # construct integer ID list: | |
782 | targets = self.client._build_targets(targets)[1] |
|
778 | targets = self.client._build_targets(targets)[1] | |
783 |
|
779 | |||
784 | for index, engineid in enumerate(targets): |
|
780 | for index, engineid in enumerate(targets): | |
785 | msg_ids.extend(self.pull(key, block=False, targets=engineid).msg_ids) |
|
781 | msg_ids.extend(self.pull(key, block=False, targets=engineid).msg_ids) | |
786 |
|
782 | |||
787 | r = AsyncMapResult(self.client, msg_ids, mapObject, fname='gather') |
|
783 | r = AsyncMapResult(self.client, msg_ids, mapObject, fname='gather') | |
788 |
|
784 | |||
789 | if block: |
|
785 | if block: | |
790 | try: |
|
786 | try: | |
791 | return r.get() |
|
787 | return r.get() | |
792 | except KeyboardInterrupt: |
|
788 | except KeyboardInterrupt: | |
793 | pass |
|
789 | pass | |
794 | return r |
|
790 | return r | |
795 |
|
791 | |||
796 | def __getitem__(self, key): |
|
792 | def __getitem__(self, key): | |
797 | return self.get(key) |
|
793 | return self.get(key) | |
798 |
|
794 | |||
799 | def __setitem__(self,key, value): |
|
795 | def __setitem__(self,key, value): | |
800 | self.update({key:value}) |
|
796 | self.update({key:value}) | |
801 |
|
797 | |||
802 | def clear(self, targets=None, block=None): |
|
798 | def clear(self, targets=None, block=None): | |
803 | """Clear the remote namespaces on my engines.""" |
|
799 | """Clear the remote namespaces on my engines.""" | |
804 | block = block if block is not None else self.block |
|
800 | block = block if block is not None else self.block | |
805 | targets = targets if targets is not None else self.targets |
|
801 | targets = targets if targets is not None else self.targets | |
806 | return self.client.clear(targets=targets, block=block) |
|
802 | return self.client.clear(targets=targets, block=block) | |
807 |
|
803 | |||
808 | #---------------------------------------- |
|
804 | #---------------------------------------- | |
809 | # activate for %px, %autopx, etc. magics |
|
805 | # activate for %px, %autopx, etc. magics | |
810 | #---------------------------------------- |
|
806 | #---------------------------------------- | |
811 |
|
807 | |||
812 | def activate(self, suffix=''): |
|
808 | def activate(self, suffix=''): | |
813 | """Activate IPython magics associated with this View |
|
809 | """Activate IPython magics associated with this View | |
814 |
|
810 | |||
815 | Defines the magics `%px, %autopx, %pxresult, %%px, %pxconfig` |
|
811 | Defines the magics `%px, %autopx, %pxresult, %%px, %pxconfig` | |
816 |
|
812 | |||
817 | Parameters |
|
813 | Parameters | |
818 | ---------- |
|
814 | ---------- | |
819 |
|
815 | |||
820 | suffix: str [default: ''] |
|
816 | suffix: str [default: ''] | |
821 | The suffix, if any, for the magics. This allows you to have |
|
817 | The suffix, if any, for the magics. This allows you to have | |
822 | multiple views associated with parallel magics at the same time. |
|
818 | multiple views associated with parallel magics at the same time. | |
823 |
|
819 | |||
824 | e.g. ``rc[::2].activate(suffix='_even')`` will give you |
|
820 | e.g. ``rc[::2].activate(suffix='_even')`` will give you | |
825 | the magics ``%px_even``, ``%pxresult_even``, etc. for running magics |
|
821 | the magics ``%px_even``, ``%pxresult_even``, etc. for running magics | |
826 | on the even engines. |
|
822 | on the even engines. | |
827 | """ |
|
823 | """ | |
828 |
|
824 | |||
829 | from IPython.parallel.client.magics import ParallelMagics |
|
825 | from IPython.parallel.client.magics import ParallelMagics | |
830 |
|
826 | |||
831 | try: |
|
827 | try: | |
832 | # This is injected into __builtins__. |
|
828 | # This is injected into __builtins__. | |
833 | ip = get_ipython() |
|
829 | ip = get_ipython() | |
834 | except NameError: |
|
830 | except NameError: | |
835 | print("The IPython parallel magics (%px, etc.) only work within IPython.") |
|
831 | print("The IPython parallel magics (%px, etc.) only work within IPython.") | |
836 | return |
|
832 | return | |
837 |
|
833 | |||
838 | M = ParallelMagics(ip, self, suffix) |
|
834 | M = ParallelMagics(ip, self, suffix) | |
839 | ip.magics_manager.register(M) |
|
835 | ip.magics_manager.register(M) | |
840 |
|
836 | |||
841 |
|
837 | |||
842 | @skip_doctest |
|
838 | @skip_doctest | |
843 | class LoadBalancedView(View): |
|
839 | class LoadBalancedView(View): | |
844 | """An load-balancing View that only executes via the Task scheduler. |
|
840 | """An load-balancing View that only executes via the Task scheduler. | |
845 |
|
841 | |||
846 | Load-balanced views can be created with the client's `view` method: |
|
842 | Load-balanced views can be created with the client's `view` method: | |
847 |
|
843 | |||
848 | >>> v = client.load_balanced_view() |
|
844 | >>> v = client.load_balanced_view() | |
849 |
|
845 | |||
850 | or targets can be specified, to restrict the potential destinations: |
|
846 | or targets can be specified, to restrict the potential destinations: | |
851 |
|
847 | |||
852 | >>> v = client.client.load_balanced_view([1,3]) |
|
848 | >>> v = client.client.load_balanced_view([1,3]) | |
853 |
|
849 | |||
854 | which would restrict loadbalancing to between engines 1 and 3. |
|
850 | which would restrict loadbalancing to between engines 1 and 3. | |
855 |
|
851 | |||
856 | """ |
|
852 | """ | |
857 |
|
853 | |||
858 | follow=Any() |
|
854 | follow=Any() | |
859 | after=Any() |
|
855 | after=Any() | |
860 | timeout=CFloat() |
|
856 | timeout=CFloat() | |
861 | retries = Integer(0) |
|
857 | retries = Integer(0) | |
862 |
|
858 | |||
863 | _task_scheme = Any() |
|
859 | _task_scheme = Any() | |
864 | _flag_names = List(['targets', 'block', 'track', 'follow', 'after', 'timeout', 'retries']) |
|
860 | _flag_names = List(['targets', 'block', 'track', 'follow', 'after', 'timeout', 'retries']) | |
865 |
|
861 | |||
866 | def __init__(self, client=None, socket=None, **flags): |
|
862 | def __init__(self, client=None, socket=None, **flags): | |
867 | super(LoadBalancedView, self).__init__(client=client, socket=socket, **flags) |
|
863 | super(LoadBalancedView, self).__init__(client=client, socket=socket, **flags) | |
868 | self._task_scheme=client._task_scheme |
|
864 | self._task_scheme=client._task_scheme | |
869 |
|
865 | |||
870 | def _validate_dependency(self, dep): |
|
866 | def _validate_dependency(self, dep): | |
871 | """validate a dependency. |
|
867 | """validate a dependency. | |
872 |
|
868 | |||
873 | For use in `set_flags`. |
|
869 | For use in `set_flags`. | |
874 | """ |
|
870 | """ | |
875 | if dep is None or isinstance(dep, string_types + (AsyncResult, Dependency)): |
|
871 | if dep is None or isinstance(dep, string_types + (AsyncResult, Dependency)): | |
876 | return True |
|
872 | return True | |
877 | elif isinstance(dep, (list,set, tuple)): |
|
873 | elif isinstance(dep, (list,set, tuple)): | |
878 | for d in dep: |
|
874 | for d in dep: | |
879 | if not isinstance(d, string_types + (AsyncResult,)): |
|
875 | if not isinstance(d, string_types + (AsyncResult,)): | |
880 | return False |
|
876 | return False | |
881 | elif isinstance(dep, dict): |
|
877 | elif isinstance(dep, dict): | |
882 | if set(dep.keys()) != set(Dependency().as_dict().keys()): |
|
878 | if set(dep.keys()) != set(Dependency().as_dict().keys()): | |
883 | return False |
|
879 | return False | |
884 | if not isinstance(dep['msg_ids'], list): |
|
880 | if not isinstance(dep['msg_ids'], list): | |
885 | return False |
|
881 | return False | |
886 | for d in dep['msg_ids']: |
|
882 | for d in dep['msg_ids']: | |
887 | if not isinstance(d, string_types): |
|
883 | if not isinstance(d, string_types): | |
888 | return False |
|
884 | return False | |
889 | else: |
|
885 | else: | |
890 | return False |
|
886 | return False | |
891 |
|
887 | |||
892 | return True |
|
888 | return True | |
893 |
|
889 | |||
894 | def _render_dependency(self, dep): |
|
890 | def _render_dependency(self, dep): | |
895 | """helper for building jsonable dependencies from various input forms.""" |
|
891 | """helper for building jsonable dependencies from various input forms.""" | |
896 | if isinstance(dep, Dependency): |
|
892 | if isinstance(dep, Dependency): | |
897 | return dep.as_dict() |
|
893 | return dep.as_dict() | |
898 | elif isinstance(dep, AsyncResult): |
|
894 | elif isinstance(dep, AsyncResult): | |
899 | return dep.msg_ids |
|
895 | return dep.msg_ids | |
900 | elif dep is None: |
|
896 | elif dep is None: | |
901 | return [] |
|
897 | return [] | |
902 | else: |
|
898 | else: | |
903 | # pass to Dependency constructor |
|
899 | # pass to Dependency constructor | |
904 | return list(Dependency(dep)) |
|
900 | return list(Dependency(dep)) | |
905 |
|
901 | |||
906 | def set_flags(self, **kwargs): |
|
902 | def set_flags(self, **kwargs): | |
907 | """set my attribute flags by keyword. |
|
903 | """set my attribute flags by keyword. | |
908 |
|
904 | |||
909 | A View is a wrapper for the Client's apply method, but with attributes |
|
905 | A View is a wrapper for the Client's apply method, but with attributes | |
910 | that specify keyword arguments, those attributes can be set by keyword |
|
906 | that specify keyword arguments, those attributes can be set by keyword | |
911 | argument with this method. |
|
907 | argument with this method. | |
912 |
|
908 | |||
913 | Parameters |
|
909 | Parameters | |
914 | ---------- |
|
910 | ---------- | |
915 |
|
911 | |||
916 | block : bool |
|
912 | block : bool | |
917 | whether to wait for results |
|
913 | whether to wait for results | |
918 | track : bool |
|
914 | track : bool | |
919 | whether to create a MessageTracker to allow the user to |
|
915 | whether to create a MessageTracker to allow the user to | |
920 | safely edit after arrays and buffers during non-copying |
|
916 | safely edit after arrays and buffers during non-copying | |
921 | sends. |
|
917 | sends. | |
922 |
|
918 | |||
923 | after : Dependency or collection of msg_ids |
|
919 | after : Dependency or collection of msg_ids | |
924 | Only for load-balanced execution (targets=None) |
|
920 | Only for load-balanced execution (targets=None) | |
925 | Specify a list of msg_ids as a time-based dependency. |
|
921 | Specify a list of msg_ids as a time-based dependency. | |
926 | This job will only be run *after* the dependencies |
|
922 | This job will only be run *after* the dependencies | |
927 | have been met. |
|
923 | have been met. | |
928 |
|
924 | |||
929 | follow : Dependency or collection of msg_ids |
|
925 | follow : Dependency or collection of msg_ids | |
930 | Only for load-balanced execution (targets=None) |
|
926 | Only for load-balanced execution (targets=None) | |
931 | Specify a list of msg_ids as a location-based dependency. |
|
927 | Specify a list of msg_ids as a location-based dependency. | |
932 | This job will only be run on an engine where this dependency |
|
928 | This job will only be run on an engine where this dependency | |
933 | is met. |
|
929 | is met. | |
934 |
|
930 | |||
935 | timeout : float/int or None |
|
931 | timeout : float/int or None | |
936 | Only for load-balanced execution (targets=None) |
|
932 | Only for load-balanced execution (targets=None) | |
937 | Specify an amount of time (in seconds) for the scheduler to |
|
933 | Specify an amount of time (in seconds) for the scheduler to | |
938 | wait for dependencies to be met before failing with a |
|
934 | wait for dependencies to be met before failing with a | |
939 | DependencyTimeout. |
|
935 | DependencyTimeout. | |
940 |
|
936 | |||
941 | retries : int |
|
937 | retries : int | |
942 | Number of times a task will be retried on failure. |
|
938 | Number of times a task will be retried on failure. | |
943 | """ |
|
939 | """ | |
944 |
|
940 | |||
945 | super(LoadBalancedView, self).set_flags(**kwargs) |
|
941 | super(LoadBalancedView, self).set_flags(**kwargs) | |
946 | for name in ('follow', 'after'): |
|
942 | for name in ('follow', 'after'): | |
947 | if name in kwargs: |
|
943 | if name in kwargs: | |
948 | value = kwargs[name] |
|
944 | value = kwargs[name] | |
949 | if self._validate_dependency(value): |
|
945 | if self._validate_dependency(value): | |
950 | setattr(self, name, value) |
|
946 | setattr(self, name, value) | |
951 | else: |
|
947 | else: | |
952 | raise ValueError("Invalid dependency: %r"%value) |
|
948 | raise ValueError("Invalid dependency: %r"%value) | |
953 | if 'timeout' in kwargs: |
|
949 | if 'timeout' in kwargs: | |
954 | t = kwargs['timeout'] |
|
950 | t = kwargs['timeout'] | |
955 | if not isinstance(t, (int, float, type(None))): |
|
951 | if not isinstance(t, (int, float, type(None))): | |
956 | if (not PY3) and (not isinstance(t, long)): |
|
952 | if (not PY3) and (not isinstance(t, long)): | |
957 | raise TypeError("Invalid type for timeout: %r"%type(t)) |
|
953 | raise TypeError("Invalid type for timeout: %r"%type(t)) | |
958 | if t is not None: |
|
954 | if t is not None: | |
959 | if t < 0: |
|
955 | if t < 0: | |
960 | raise ValueError("Invalid timeout: %s"%t) |
|
956 | raise ValueError("Invalid timeout: %s"%t) | |
961 | self.timeout = t |
|
957 | self.timeout = t | |
962 |
|
958 | |||
963 | @sync_results |
|
959 | @sync_results | |
964 | @save_ids |
|
960 | @save_ids | |
965 | def _really_apply(self, f, args=None, kwargs=None, block=None, track=None, |
|
961 | def _really_apply(self, f, args=None, kwargs=None, block=None, track=None, | |
966 | after=None, follow=None, timeout=None, |
|
962 | after=None, follow=None, timeout=None, | |
967 | targets=None, retries=None): |
|
963 | targets=None, retries=None): | |
968 | """calls f(*args, **kwargs) on a remote engine, returning the result. |
|
964 | """calls f(*args, **kwargs) on a remote engine, returning the result. | |
969 |
|
965 | |||
970 | This method temporarily sets all of `apply`'s flags for a single call. |
|
966 | This method temporarily sets all of `apply`'s flags for a single call. | |
971 |
|
967 | |||
972 | Parameters |
|
968 | Parameters | |
973 | ---------- |
|
969 | ---------- | |
974 |
|
970 | |||
975 | f : callable |
|
971 | f : callable | |
976 |
|
972 | |||
977 | args : list [default: empty] |
|
973 | args : list [default: empty] | |
978 |
|
974 | |||
979 | kwargs : dict [default: empty] |
|
975 | kwargs : dict [default: empty] | |
980 |
|
976 | |||
981 | block : bool [default: self.block] |
|
977 | block : bool [default: self.block] | |
982 | whether to block |
|
978 | whether to block | |
983 | track : bool [default: self.track] |
|
979 | track : bool [default: self.track] | |
984 | whether to ask zmq to track the message, for safe non-copying sends |
|
980 | whether to ask zmq to track the message, for safe non-copying sends | |
985 |
|
981 | |||
986 | !!!!!! TODO: THE REST HERE !!!! |
|
982 | !!!!!! TODO: THE REST HERE !!!! | |
987 |
|
983 | |||
988 | Returns |
|
984 | Returns | |
989 | ------- |
|
985 | ------- | |
990 |
|
986 | |||
991 | if self.block is False: |
|
987 | if self.block is False: | |
992 | returns AsyncResult |
|
988 | returns AsyncResult | |
993 | else: |
|
989 | else: | |
994 | returns actual result of f(*args, **kwargs) on the engine(s) |
|
990 | returns actual result of f(*args, **kwargs) on the engine(s) | |
995 | This will be a list of self.targets is also a list (even length 1), or |
|
991 | This will be a list of self.targets is also a list (even length 1), or | |
996 | the single result if self.targets is an integer engine id |
|
992 | the single result if self.targets is an integer engine id | |
997 | """ |
|
993 | """ | |
998 |
|
994 | |||
999 | # validate whether we can run |
|
995 | # validate whether we can run | |
1000 | if self._socket.closed: |
|
996 | if self._socket.closed: | |
1001 | msg = "Task farming is disabled" |
|
997 | msg = "Task farming is disabled" | |
1002 | if self._task_scheme == 'pure': |
|
998 | if self._task_scheme == 'pure': | |
1003 | msg += " because the pure ZMQ scheduler cannot handle" |
|
999 | msg += " because the pure ZMQ scheduler cannot handle" | |
1004 | msg += " disappearing engines." |
|
1000 | msg += " disappearing engines." | |
1005 | raise RuntimeError(msg) |
|
1001 | raise RuntimeError(msg) | |
1006 |
|
1002 | |||
1007 | if self._task_scheme == 'pure': |
|
1003 | if self._task_scheme == 'pure': | |
1008 | # pure zmq scheme doesn't support extra features |
|
1004 | # pure zmq scheme doesn't support extra features | |
1009 | msg = "Pure ZMQ scheduler doesn't support the following flags:" |
|
1005 | msg = "Pure ZMQ scheduler doesn't support the following flags:" | |
1010 | "follow, after, retries, targets, timeout" |
|
1006 | "follow, after, retries, targets, timeout" | |
1011 | if (follow or after or retries or targets or timeout): |
|
1007 | if (follow or after or retries or targets or timeout): | |
1012 | # hard fail on Scheduler flags |
|
1008 | # hard fail on Scheduler flags | |
1013 | raise RuntimeError(msg) |
|
1009 | raise RuntimeError(msg) | |
1014 | if isinstance(f, dependent): |
|
1010 | if isinstance(f, dependent): | |
1015 | # soft warn on functional dependencies |
|
1011 | # soft warn on functional dependencies | |
1016 | warnings.warn(msg, RuntimeWarning) |
|
1012 | warnings.warn(msg, RuntimeWarning) | |
1017 |
|
1013 | |||
1018 | # build args |
|
1014 | # build args | |
1019 | args = [] if args is None else args |
|
1015 | args = [] if args is None else args | |
1020 | kwargs = {} if kwargs is None else kwargs |
|
1016 | kwargs = {} if kwargs is None else kwargs | |
1021 | block = self.block if block is None else block |
|
1017 | block = self.block if block is None else block | |
1022 | track = self.track if track is None else track |
|
1018 | track = self.track if track is None else track | |
1023 | after = self.after if after is None else after |
|
1019 | after = self.after if after is None else after | |
1024 | retries = self.retries if retries is None else retries |
|
1020 | retries = self.retries if retries is None else retries | |
1025 | follow = self.follow if follow is None else follow |
|
1021 | follow = self.follow if follow is None else follow | |
1026 | timeout = self.timeout if timeout is None else timeout |
|
1022 | timeout = self.timeout if timeout is None else timeout | |
1027 | targets = self.targets if targets is None else targets |
|
1023 | targets = self.targets if targets is None else targets | |
1028 |
|
1024 | |||
1029 | if not isinstance(retries, int): |
|
1025 | if not isinstance(retries, int): | |
1030 | raise TypeError('retries must be int, not %r'%type(retries)) |
|
1026 | raise TypeError('retries must be int, not %r'%type(retries)) | |
1031 |
|
1027 | |||
1032 | if targets is None: |
|
1028 | if targets is None: | |
1033 | idents = [] |
|
1029 | idents = [] | |
1034 | else: |
|
1030 | else: | |
1035 | idents = self.client._build_targets(targets)[0] |
|
1031 | idents = self.client._build_targets(targets)[0] | |
1036 | # ensure *not* bytes |
|
1032 | # ensure *not* bytes | |
1037 | idents = [ ident.decode() for ident in idents ] |
|
1033 | idents = [ ident.decode() for ident in idents ] | |
1038 |
|
1034 | |||
1039 | after = self._render_dependency(after) |
|
1035 | after = self._render_dependency(after) | |
1040 | follow = self._render_dependency(follow) |
|
1036 | follow = self._render_dependency(follow) | |
1041 | metadata = dict(after=after, follow=follow, timeout=timeout, targets=idents, retries=retries) |
|
1037 | metadata = dict(after=after, follow=follow, timeout=timeout, targets=idents, retries=retries) | |
1042 |
|
1038 | |||
1043 | msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track, |
|
1039 | msg = self.client.send_apply_request(self._socket, f, args, kwargs, track=track, | |
1044 | metadata=metadata) |
|
1040 | metadata=metadata) | |
1045 | tracker = None if track is False else msg['tracker'] |
|
1041 | tracker = None if track is False else msg['tracker'] | |
1046 |
|
1042 | |||
1047 | ar = AsyncResult(self.client, msg['header']['msg_id'], fname=getname(f), targets=None, tracker=tracker) |
|
1043 | ar = AsyncResult(self.client, msg['header']['msg_id'], fname=getname(f), targets=None, tracker=tracker) | |
1048 |
|
1044 | |||
1049 | if block: |
|
1045 | if block: | |
1050 | try: |
|
1046 | try: | |
1051 | return ar.get() |
|
1047 | return ar.get() | |
1052 | except KeyboardInterrupt: |
|
1048 | except KeyboardInterrupt: | |
1053 | pass |
|
1049 | pass | |
1054 | return ar |
|
1050 | return ar | |
1055 |
|
1051 | |||
1056 | @sync_results |
|
1052 | @sync_results | |
1057 | @save_ids |
|
1053 | @save_ids | |
1058 | def map(self, f, *sequences, **kwargs): |
|
1054 | def map(self, f, *sequences, **kwargs): | |
1059 | """view.map(f, *sequences, block=self.block, chunksize=1, ordered=True) => list|AsyncMapResult |
|
1055 | """``view.map(f, *sequences, block=self.block, chunksize=1, ordered=True)`` => list|AsyncMapResult | |
1060 |
|
1056 | |||
1061 | Parallel version of builtin `map`, load-balanced by this View. |
|
1057 | Parallel version of builtin `map`, load-balanced by this View. | |
1062 |
|
1058 | |||
1063 | `block`, and `chunksize` can be specified by keyword only. |
|
1059 | `block`, and `chunksize` can be specified by keyword only. | |
1064 |
|
1060 | |||
1065 | Each `chunksize` elements will be a separate task, and will be |
|
1061 | Each `chunksize` elements will be a separate task, and will be | |
1066 | load-balanced. This lets individual elements be available for iteration |
|
1062 | load-balanced. This lets individual elements be available for iteration | |
1067 | as soon as they arrive. |
|
1063 | as soon as they arrive. | |
1068 |
|
1064 | |||
1069 | Parameters |
|
1065 | Parameters | |
1070 | ---------- |
|
1066 | ---------- | |
1071 |
|
1067 | |||
1072 | f : callable |
|
1068 | f : callable | |
1073 | function to be mapped |
|
1069 | function to be mapped | |
1074 | *sequences: one or more sequences of matching length |
|
1070 | *sequences: one or more sequences of matching length | |
1075 | the sequences to be distributed and passed to `f` |
|
1071 | the sequences to be distributed and passed to `f` | |
1076 | block : bool [default self.block] |
|
1072 | block : bool [default self.block] | |
1077 | whether to wait for the result or not |
|
1073 | whether to wait for the result or not | |
1078 | track : bool |
|
1074 | track : bool | |
1079 | whether to create a MessageTracker to allow the user to |
|
1075 | whether to create a MessageTracker to allow the user to | |
1080 | safely edit after arrays and buffers during non-copying |
|
1076 | safely edit after arrays and buffers during non-copying | |
1081 | sends. |
|
1077 | sends. | |
1082 | chunksize : int [default 1] |
|
1078 | chunksize : int [default 1] | |
1083 | how many elements should be in each task. |
|
1079 | how many elements should be in each task. | |
1084 | ordered : bool [default True] |
|
1080 | ordered : bool [default True] | |
1085 | Whether the results should be gathered as they arrive, or enforce |
|
1081 | Whether the results should be gathered as they arrive, or enforce | |
1086 | the order of submission. |
|
1082 | the order of submission. | |
1087 |
|
1083 | |||
1088 | Only applies when iterating through AsyncMapResult as results arrive. |
|
1084 | Only applies when iterating through AsyncMapResult as results arrive. | |
1089 | Has no effect when block=True. |
|
1085 | Has no effect when block=True. | |
1090 |
|
1086 | |||
1091 | Returns |
|
1087 | Returns | |
1092 | ------- |
|
1088 | ------- | |
1093 |
|
1089 | |||
1094 |
if block=False |
|
1090 | if block=False | |
1095 | AsyncMapResult |
|
1091 | An :class:`~IPython.parallel.client.asyncresult.AsyncMapResult` instance. | |
1096 |
|
|
1092 | An object like AsyncResult, but which reassembles the sequence of results | |
1097 |
|
|
1093 | into a single list. AsyncMapResults can be iterated through before all | |
1098 |
|
|
1094 | results are complete. | |
1099 |
|
|
1095 | else | |
1100 |
|
|
1096 | A list, the result of ``map(f,*sequences)`` | |
1101 |
|
||||
1102 | """ |
|
1097 | """ | |
1103 |
|
1098 | |||
1104 | # default |
|
1099 | # default | |
1105 | block = kwargs.get('block', self.block) |
|
1100 | block = kwargs.get('block', self.block) | |
1106 | chunksize = kwargs.get('chunksize', 1) |
|
1101 | chunksize = kwargs.get('chunksize', 1) | |
1107 | ordered = kwargs.get('ordered', True) |
|
1102 | ordered = kwargs.get('ordered', True) | |
1108 |
|
1103 | |||
1109 | keyset = set(kwargs.keys()) |
|
1104 | keyset = set(kwargs.keys()) | |
1110 | extra_keys = keyset.difference_update(set(['block', 'chunksize'])) |
|
1105 | extra_keys = keyset.difference_update(set(['block', 'chunksize'])) | |
1111 | if extra_keys: |
|
1106 | if extra_keys: | |
1112 | raise TypeError("Invalid kwargs: %s"%list(extra_keys)) |
|
1107 | raise TypeError("Invalid kwargs: %s"%list(extra_keys)) | |
1113 |
|
1108 | |||
1114 | assert len(sequences) > 0, "must have some sequences to map onto!" |
|
1109 | assert len(sequences) > 0, "must have some sequences to map onto!" | |
1115 |
|
1110 | |||
1116 | pf = ParallelFunction(self, f, block=block, chunksize=chunksize, ordered=ordered) |
|
1111 | pf = ParallelFunction(self, f, block=block, chunksize=chunksize, ordered=ordered) | |
1117 | return pf.map(*sequences) |
|
1112 | return pf.map(*sequences) | |
1118 |
|
1113 | |||
1119 | __all__ = ['LoadBalancedView', 'DirectView'] |
|
1114 | __all__ = ['LoadBalancedView', 'DirectView'] |
@@ -1,230 +1,229 b'' | |||||
1 | """Dependency utilities |
|
1 | """Dependency utilities | |
2 |
|
2 | |||
3 | Authors: |
|
3 | Authors: | |
4 |
|
4 | |||
5 | * Min RK |
|
5 | * Min RK | |
6 | """ |
|
6 | """ | |
7 | #----------------------------------------------------------------------------- |
|
7 | #----------------------------------------------------------------------------- | |
8 | # Copyright (C) 2013 The IPython Development Team |
|
8 | # Copyright (C) 2013 The IPython Development Team | |
9 | # |
|
9 | # | |
10 | # Distributed under the terms of the BSD License. The full license is in |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
11 | # the file COPYING, distributed as part of this software. |
|
11 | # the file COPYING, distributed as part of this software. | |
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 | from types import ModuleType |
|
14 | from types import ModuleType | |
15 |
|
15 | |||
16 | from IPython.parallel.client.asyncresult import AsyncResult |
|
16 | from IPython.parallel.client.asyncresult import AsyncResult | |
17 | from IPython.parallel.error import UnmetDependency |
|
17 | from IPython.parallel.error import UnmetDependency | |
18 | from IPython.parallel.util import interactive |
|
18 | from IPython.parallel.util import interactive | |
19 | from IPython.utils import py3compat |
|
19 | from IPython.utils import py3compat | |
20 | from IPython.utils.py3compat import string_types |
|
20 | from IPython.utils.py3compat import string_types | |
21 | from IPython.utils.pickleutil import can, uncan |
|
21 | from IPython.utils.pickleutil import can, uncan | |
22 |
|
22 | |||
23 | class depend(object): |
|
23 | class depend(object): | |
24 | """Dependency decorator, for use with tasks. |
|
24 | """Dependency decorator, for use with tasks. | |
25 |
|
25 | |||
26 | `@depend` lets you define a function for engine dependencies |
|
26 | `@depend` lets you define a function for engine dependencies | |
27 | just like you use `apply` for tasks. |
|
27 | just like you use `apply` for tasks. | |
28 |
|
28 | |||
29 |
|
29 | |||
30 | Examples |
|
30 | Examples | |
31 | -------- |
|
31 | -------- | |
32 | :: |
|
32 | :: | |
33 |
|
33 | |||
34 | @depend(df, a,b, c=5) |
|
34 | @depend(df, a,b, c=5) | |
35 | def f(m,n,p) |
|
35 | def f(m,n,p) | |
36 |
|
36 | |||
37 | view.apply(f, 1,2,3) |
|
37 | view.apply(f, 1,2,3) | |
38 |
|
38 | |||
39 | will call df(a,b,c=5) on the engine, and if it returns False or |
|
39 | will call df(a,b,c=5) on the engine, and if it returns False or | |
40 | raises an UnmetDependency error, then the task will not be run |
|
40 | raises an UnmetDependency error, then the task will not be run | |
41 | and another engine will be tried. |
|
41 | and another engine will be tried. | |
42 | """ |
|
42 | """ | |
43 | def __init__(self, f, *args, **kwargs): |
|
43 | def __init__(self, f, *args, **kwargs): | |
44 | self.f = f |
|
44 | self.f = f | |
45 | self.args = args |
|
45 | self.args = args | |
46 | self.kwargs = kwargs |
|
46 | self.kwargs = kwargs | |
47 |
|
47 | |||
48 | def __call__(self, f): |
|
48 | def __call__(self, f): | |
49 | return dependent(f, self.f, *self.args, **self.kwargs) |
|
49 | return dependent(f, self.f, *self.args, **self.kwargs) | |
50 |
|
50 | |||
51 | class dependent(object): |
|
51 | class dependent(object): | |
52 | """A function that depends on another function. |
|
52 | """A function that depends on another function. | |
53 | This is an object to prevent the closure used |
|
53 | This is an object to prevent the closure used | |
54 | in traditional decorators, which are not picklable. |
|
54 | in traditional decorators, which are not picklable. | |
55 | """ |
|
55 | """ | |
56 |
|
56 | |||
57 | def __init__(self, f, df, *dargs, **dkwargs): |
|
57 | def __init__(self, f, df, *dargs, **dkwargs): | |
58 | self.f = f |
|
58 | self.f = f | |
59 | name = getattr(f, '__name__', 'f') |
|
59 | name = getattr(f, '__name__', 'f') | |
60 | if py3compat.PY3: |
|
60 | if py3compat.PY3: | |
61 | self.__name__ = name |
|
61 | self.__name__ = name | |
62 | else: |
|
62 | else: | |
63 | self.func_name = name |
|
63 | self.func_name = name | |
64 | self.df = df |
|
64 | self.df = df | |
65 | self.dargs = dargs |
|
65 | self.dargs = dargs | |
66 | self.dkwargs = dkwargs |
|
66 | self.dkwargs = dkwargs | |
67 |
|
67 | |||
68 | def check_dependency(self): |
|
68 | def check_dependency(self): | |
69 | if self.df(*self.dargs, **self.dkwargs) is False: |
|
69 | if self.df(*self.dargs, **self.dkwargs) is False: | |
70 | raise UnmetDependency() |
|
70 | raise UnmetDependency() | |
71 |
|
71 | |||
72 | def __call__(self, *args, **kwargs): |
|
72 | def __call__(self, *args, **kwargs): | |
73 | return self.f(*args, **kwargs) |
|
73 | return self.f(*args, **kwargs) | |
74 |
|
74 | |||
75 | if not py3compat.PY3: |
|
75 | if not py3compat.PY3: | |
76 | @property |
|
76 | @property | |
77 | def __name__(self): |
|
77 | def __name__(self): | |
78 | return self.func_name |
|
78 | return self.func_name | |
79 |
|
79 | |||
80 | @interactive |
|
80 | @interactive | |
81 | def _require(*modules, **mapping): |
|
81 | def _require(*modules, **mapping): | |
82 | """Helper for @require decorator.""" |
|
82 | """Helper for @require decorator.""" | |
83 | from IPython.parallel.error import UnmetDependency |
|
83 | from IPython.parallel.error import UnmetDependency | |
84 | from IPython.utils.pickleutil import uncan |
|
84 | from IPython.utils.pickleutil import uncan | |
85 | user_ns = globals() |
|
85 | user_ns = globals() | |
86 | for name in modules: |
|
86 | for name in modules: | |
87 | try: |
|
87 | try: | |
88 | exec('import %s' % name, user_ns) |
|
88 | exec('import %s' % name, user_ns) | |
89 | except ImportError: |
|
89 | except ImportError: | |
90 | raise UnmetDependency(name) |
|
90 | raise UnmetDependency(name) | |
91 |
|
91 | |||
92 | for name, cobj in mapping.items(): |
|
92 | for name, cobj in mapping.items(): | |
93 | user_ns[name] = uncan(cobj, user_ns) |
|
93 | user_ns[name] = uncan(cobj, user_ns) | |
94 | return True |
|
94 | return True | |
95 |
|
95 | |||
96 | def require(*objects, **mapping): |
|
96 | def require(*objects, **mapping): | |
97 | """Simple decorator for requiring local objects and modules to be available |
|
97 | """Simple decorator for requiring local objects and modules to be available | |
98 | when the decorated function is called on the engine. |
|
98 | when the decorated function is called on the engine. | |
99 |
|
99 | |||
100 | Modules specified by name or passed directly will be imported |
|
100 | Modules specified by name or passed directly will be imported | |
101 | prior to calling the decorated function. |
|
101 | prior to calling the decorated function. | |
102 |
|
102 | |||
103 | Objects other than modules will be pushed as a part of the task. |
|
103 | Objects other than modules will be pushed as a part of the task. | |
104 | Functions can be passed positionally, |
|
104 | Functions can be passed positionally, | |
105 | and will be pushed to the engine with their __name__. |
|
105 | and will be pushed to the engine with their __name__. | |
106 | Other objects can be passed by keyword arg. |
|
106 | Other objects can be passed by keyword arg. | |
107 |
|
107 | |||
108 | Examples |
|
108 | Examples:: | |
109 | -------- |
|
|||
110 |
|
109 | |||
111 | In [1]: @require('numpy') |
|
110 | In [1]: @require('numpy') | |
112 | ...: def norm(a): |
|
111 | ...: def norm(a): | |
113 | ...: return numpy.linalg.norm(a,2) |
|
112 | ...: return numpy.linalg.norm(a,2) | |
114 |
|
113 | |||
115 | In [2]: foo = lambda x: x*x |
|
114 | In [2]: foo = lambda x: x*x | |
116 | In [3]: @require(foo) |
|
115 | In [3]: @require(foo) | |
117 | ...: def bar(a): |
|
116 | ...: def bar(a): | |
118 | ...: return foo(1-a) |
|
117 | ...: return foo(1-a) | |
119 | """ |
|
118 | """ | |
120 | names = [] |
|
119 | names = [] | |
121 | for obj in objects: |
|
120 | for obj in objects: | |
122 | if isinstance(obj, ModuleType): |
|
121 | if isinstance(obj, ModuleType): | |
123 | obj = obj.__name__ |
|
122 | obj = obj.__name__ | |
124 |
|
123 | |||
125 | if isinstance(obj, string_types): |
|
124 | if isinstance(obj, string_types): | |
126 | names.append(obj) |
|
125 | names.append(obj) | |
127 | elif hasattr(obj, '__name__'): |
|
126 | elif hasattr(obj, '__name__'): | |
128 | mapping[obj.__name__] = obj |
|
127 | mapping[obj.__name__] = obj | |
129 | else: |
|
128 | else: | |
130 | raise TypeError("Objects other than modules and functions " |
|
129 | raise TypeError("Objects other than modules and functions " | |
131 | "must be passed by kwarg, but got: %s" % type(obj) |
|
130 | "must be passed by kwarg, but got: %s" % type(obj) | |
132 | ) |
|
131 | ) | |
133 |
|
132 | |||
134 | for name, obj in mapping.items(): |
|
133 | for name, obj in mapping.items(): | |
135 | mapping[name] = can(obj) |
|
134 | mapping[name] = can(obj) | |
136 | return depend(_require, *names, **mapping) |
|
135 | return depend(_require, *names, **mapping) | |
137 |
|
136 | |||
138 | class Dependency(set): |
|
137 | class Dependency(set): | |
139 | """An object for representing a set of msg_id dependencies. |
|
138 | """An object for representing a set of msg_id dependencies. | |
140 |
|
139 | |||
141 | Subclassed from set(). |
|
140 | Subclassed from set(). | |
142 |
|
141 | |||
143 | Parameters |
|
142 | Parameters | |
144 | ---------- |
|
143 | ---------- | |
145 | dependencies: list/set of msg_ids or AsyncResult objects or output of Dependency.as_dict() |
|
144 | dependencies: list/set of msg_ids or AsyncResult objects or output of Dependency.as_dict() | |
146 | The msg_ids to depend on |
|
145 | The msg_ids to depend on | |
147 | all : bool [default True] |
|
146 | all : bool [default True] | |
148 | Whether the dependency should be considered met when *all* depending tasks have completed |
|
147 | Whether the dependency should be considered met when *all* depending tasks have completed | |
149 | or only when *any* have been completed. |
|
148 | or only when *any* have been completed. | |
150 | success : bool [default True] |
|
149 | success : bool [default True] | |
151 | Whether to consider successes as fulfilling dependencies. |
|
150 | Whether to consider successes as fulfilling dependencies. | |
152 | failure : bool [default False] |
|
151 | failure : bool [default False] | |
153 | Whether to consider failures as fulfilling dependencies. |
|
152 | Whether to consider failures as fulfilling dependencies. | |
154 |
|
153 | |||
155 | If `all=success=True` and `failure=False`, then the task will fail with an ImpossibleDependency |
|
154 | If `all=success=True` and `failure=False`, then the task will fail with an ImpossibleDependency | |
156 | as soon as the first depended-upon task fails. |
|
155 | as soon as the first depended-upon task fails. | |
157 | """ |
|
156 | """ | |
158 |
|
157 | |||
159 | all=True |
|
158 | all=True | |
160 | success=True |
|
159 | success=True | |
161 | failure=True |
|
160 | failure=True | |
162 |
|
161 | |||
163 | def __init__(self, dependencies=[], all=True, success=True, failure=False): |
|
162 | def __init__(self, dependencies=[], all=True, success=True, failure=False): | |
164 | if isinstance(dependencies, dict): |
|
163 | if isinstance(dependencies, dict): | |
165 | # load from dict |
|
164 | # load from dict | |
166 | all = dependencies.get('all', True) |
|
165 | all = dependencies.get('all', True) | |
167 | success = dependencies.get('success', success) |
|
166 | success = dependencies.get('success', success) | |
168 | failure = dependencies.get('failure', failure) |
|
167 | failure = dependencies.get('failure', failure) | |
169 | dependencies = dependencies.get('dependencies', []) |
|
168 | dependencies = dependencies.get('dependencies', []) | |
170 | ids = [] |
|
169 | ids = [] | |
171 |
|
170 | |||
172 | # extract ids from various sources: |
|
171 | # extract ids from various sources: | |
173 | if isinstance(dependencies, string_types + (AsyncResult,)): |
|
172 | if isinstance(dependencies, string_types + (AsyncResult,)): | |
174 | dependencies = [dependencies] |
|
173 | dependencies = [dependencies] | |
175 | for d in dependencies: |
|
174 | for d in dependencies: | |
176 | if isinstance(d, string_types): |
|
175 | if isinstance(d, string_types): | |
177 | ids.append(d) |
|
176 | ids.append(d) | |
178 | elif isinstance(d, AsyncResult): |
|
177 | elif isinstance(d, AsyncResult): | |
179 | ids.extend(d.msg_ids) |
|
178 | ids.extend(d.msg_ids) | |
180 | else: |
|
179 | else: | |
181 | raise TypeError("invalid dependency type: %r"%type(d)) |
|
180 | raise TypeError("invalid dependency type: %r"%type(d)) | |
182 |
|
181 | |||
183 | set.__init__(self, ids) |
|
182 | set.__init__(self, ids) | |
184 | self.all = all |
|
183 | self.all = all | |
185 | if not (success or failure): |
|
184 | if not (success or failure): | |
186 | raise ValueError("Must depend on at least one of successes or failures!") |
|
185 | raise ValueError("Must depend on at least one of successes or failures!") | |
187 | self.success=success |
|
186 | self.success=success | |
188 | self.failure = failure |
|
187 | self.failure = failure | |
189 |
|
188 | |||
190 | def check(self, completed, failed=None): |
|
189 | def check(self, completed, failed=None): | |
191 | """check whether our dependencies have been met.""" |
|
190 | """check whether our dependencies have been met.""" | |
192 | if len(self) == 0: |
|
191 | if len(self) == 0: | |
193 | return True |
|
192 | return True | |
194 | against = set() |
|
193 | against = set() | |
195 | if self.success: |
|
194 | if self.success: | |
196 | against = completed |
|
195 | against = completed | |
197 | if failed is not None and self.failure: |
|
196 | if failed is not None and self.failure: | |
198 | against = against.union(failed) |
|
197 | against = against.union(failed) | |
199 | if self.all: |
|
198 | if self.all: | |
200 | return self.issubset(against) |
|
199 | return self.issubset(against) | |
201 | else: |
|
200 | else: | |
202 | return not self.isdisjoint(against) |
|
201 | return not self.isdisjoint(against) | |
203 |
|
202 | |||
204 | def unreachable(self, completed, failed=None): |
|
203 | def unreachable(self, completed, failed=None): | |
205 | """return whether this dependency has become impossible.""" |
|
204 | """return whether this dependency has become impossible.""" | |
206 | if len(self) == 0: |
|
205 | if len(self) == 0: | |
207 | return False |
|
206 | return False | |
208 | against = set() |
|
207 | against = set() | |
209 | if not self.success: |
|
208 | if not self.success: | |
210 | against = completed |
|
209 | against = completed | |
211 | if failed is not None and not self.failure: |
|
210 | if failed is not None and not self.failure: | |
212 | against = against.union(failed) |
|
211 | against = against.union(failed) | |
213 | if self.all: |
|
212 | if self.all: | |
214 | return not self.isdisjoint(against) |
|
213 | return not self.isdisjoint(against) | |
215 | else: |
|
214 | else: | |
216 | return self.issubset(against) |
|
215 | return self.issubset(against) | |
217 |
|
216 | |||
218 |
|
217 | |||
219 | def as_dict(self): |
|
218 | def as_dict(self): | |
220 | """Represent this dependency as a dict. For json compatibility.""" |
|
219 | """Represent this dependency as a dict. For json compatibility.""" | |
221 | return dict( |
|
220 | return dict( | |
222 | dependencies=list(self), |
|
221 | dependencies=list(self), | |
223 | all=self.all, |
|
222 | all=self.all, | |
224 | success=self.success, |
|
223 | success=self.success, | |
225 | failure=self.failure |
|
224 | failure=self.failure | |
226 | ) |
|
225 | ) | |
227 |
|
226 | |||
228 |
|
227 | |||
229 | __all__ = ['depend', 'require', 'dependent', 'Dependency'] |
|
228 | __all__ = ['depend', 'require', 'dependent', 'Dependency'] | |
230 |
|
229 |
@@ -1,312 +1,317 b'' | |||||
1 | """A Task logger that presents our DB interface, |
|
1 | """A Task logger that presents our DB interface, | |
2 | but exists entirely in memory and implemented with dicts. |
|
2 | but exists entirely in memory and implemented with dicts. | |
3 |
|
3 | |||
4 | Authors: |
|
4 | Authors: | |
5 |
|
5 | |||
6 | * Min RK |
|
6 | * Min RK | |
7 |
|
7 | |||
8 |
|
8 | |||
9 | TaskRecords are dicts of the form: |
|
9 | TaskRecords are dicts of the form:: | |
|
10 | ||||
10 | { |
|
11 | { | |
11 | 'msg_id' : str(uuid), |
|
12 | 'msg_id' : str(uuid), | |
12 | 'client_uuid' : str(uuid), |
|
13 | 'client_uuid' : str(uuid), | |
13 | 'engine_uuid' : str(uuid) or None, |
|
14 | 'engine_uuid' : str(uuid) or None, | |
14 | 'header' : dict(header), |
|
15 | 'header' : dict(header), | |
15 | 'content': dict(content), |
|
16 | 'content': dict(content), | |
16 | 'buffers': list(buffers), |
|
17 | 'buffers': list(buffers), | |
17 | 'submitted': datetime, |
|
18 | 'submitted': datetime, | |
18 | 'started': datetime or None, |
|
19 | 'started': datetime or None, | |
19 | 'completed': datetime or None, |
|
20 | 'completed': datetime or None, | |
20 | 'resubmitted': datetime or None, |
|
21 | 'resubmitted': datetime or None, | |
21 | 'result_header' : dict(header) or None, |
|
22 | 'result_header' : dict(header) or None, | |
22 | 'result_content' : dict(content) or None, |
|
23 | 'result_content' : dict(content) or None, | |
23 | 'result_buffers' : list(buffers) or None, |
|
24 | 'result_buffers' : list(buffers) or None, | |
24 | } |
|
25 | } | |
25 | With this info, many of the special categories of tasks can be defined by query: |
|
|||
26 |
|
26 | |||
27 | pending: completed is None |
|
27 | With this info, many of the special categories of tasks can be defined by query, | |
28 | client's outstanding: client_uuid = uuid && completed is None |
|
28 | e.g.: | |
29 | MIA: arrived is None (and completed is None) |
|
29 | ||
30 | etc. |
|
30 | * pending: completed is None | |
|
31 | * client's outstanding: client_uuid = uuid && completed is None | |||
|
32 | * MIA: arrived is None (and completed is None) | |||
|
33 | ||||
|
34 | EngineRecords are dicts of the form:: | |||
31 |
|
35 | |||
32 | EngineRecords are dicts of the form: |
|
|||
33 | { |
|
36 | { | |
34 | 'eid' : int(id), |
|
37 | 'eid' : int(id), | |
35 | 'uuid': str(uuid) |
|
38 | 'uuid': str(uuid) | |
36 | } |
|
39 | } | |
|
40 | ||||
37 | This may be extended, but is currently. |
|
41 | This may be extended, but is currently. | |
38 |
|
42 | |||
39 | We support a subset of mongodb operators: |
|
43 | We support a subset of mongodb operators:: | |
|
44 | ||||
40 | $lt,$gt,$lte,$gte,$ne,$in,$nin,$all,$mod,$exists |
|
45 | $lt,$gt,$lte,$gte,$ne,$in,$nin,$all,$mod,$exists | |
41 | """ |
|
46 | """ | |
42 | #----------------------------------------------------------------------------- |
|
47 | #----------------------------------------------------------------------------- | |
43 | # Copyright (C) 2010-2011 The IPython Development Team |
|
48 | # Copyright (C) 2010-2011 The IPython Development Team | |
44 | # |
|
49 | # | |
45 | # Distributed under the terms of the BSD License. The full license is in |
|
50 | # Distributed under the terms of the BSD License. The full license is in | |
46 | # the file COPYING, distributed as part of this software. |
|
51 | # the file COPYING, distributed as part of this software. | |
47 | #----------------------------------------------------------------------------- |
|
52 | #----------------------------------------------------------------------------- | |
48 |
|
53 | |||
49 | from copy import deepcopy as copy |
|
54 | from copy import deepcopy as copy | |
50 | from datetime import datetime |
|
55 | from datetime import datetime | |
51 |
|
56 | |||
52 | from IPython.config.configurable import LoggingConfigurable |
|
57 | from IPython.config.configurable import LoggingConfigurable | |
53 |
|
58 | |||
54 | from IPython.utils.py3compat import iteritems, itervalues |
|
59 | from IPython.utils.py3compat import iteritems, itervalues | |
55 | from IPython.utils.traitlets import Dict, Unicode, Integer, Float |
|
60 | from IPython.utils.traitlets import Dict, Unicode, Integer, Float | |
56 |
|
61 | |||
57 | filters = { |
|
62 | filters = { | |
58 | '$lt' : lambda a,b: a < b, |
|
63 | '$lt' : lambda a,b: a < b, | |
59 | '$gt' : lambda a,b: b > a, |
|
64 | '$gt' : lambda a,b: b > a, | |
60 | '$eq' : lambda a,b: a == b, |
|
65 | '$eq' : lambda a,b: a == b, | |
61 | '$ne' : lambda a,b: a != b, |
|
66 | '$ne' : lambda a,b: a != b, | |
62 | '$lte': lambda a,b: a <= b, |
|
67 | '$lte': lambda a,b: a <= b, | |
63 | '$gte': lambda a,b: a >= b, |
|
68 | '$gte': lambda a,b: a >= b, | |
64 | '$in' : lambda a,b: a in b, |
|
69 | '$in' : lambda a,b: a in b, | |
65 | '$nin': lambda a,b: a not in b, |
|
70 | '$nin': lambda a,b: a not in b, | |
66 | '$all': lambda a,b: all([ a in bb for bb in b ]), |
|
71 | '$all': lambda a,b: all([ a in bb for bb in b ]), | |
67 | '$mod': lambda a,b: a%b[0] == b[1], |
|
72 | '$mod': lambda a,b: a%b[0] == b[1], | |
68 | '$exists' : lambda a,b: (b and a is not None) or (a is None and not b) |
|
73 | '$exists' : lambda a,b: (b and a is not None) or (a is None and not b) | |
69 | } |
|
74 | } | |
70 |
|
75 | |||
71 |
|
76 | |||
72 | class CompositeFilter(object): |
|
77 | class CompositeFilter(object): | |
73 | """Composite filter for matching multiple properties.""" |
|
78 | """Composite filter for matching multiple properties.""" | |
74 |
|
79 | |||
75 | def __init__(self, dikt): |
|
80 | def __init__(self, dikt): | |
76 | self.tests = [] |
|
81 | self.tests = [] | |
77 | self.values = [] |
|
82 | self.values = [] | |
78 | for key, value in iteritems(dikt): |
|
83 | for key, value in iteritems(dikt): | |
79 | self.tests.append(filters[key]) |
|
84 | self.tests.append(filters[key]) | |
80 | self.values.append(value) |
|
85 | self.values.append(value) | |
81 |
|
86 | |||
82 | def __call__(self, value): |
|
87 | def __call__(self, value): | |
83 | for test,check in zip(self.tests, self.values): |
|
88 | for test,check in zip(self.tests, self.values): | |
84 | if not test(value, check): |
|
89 | if not test(value, check): | |
85 | return False |
|
90 | return False | |
86 | return True |
|
91 | return True | |
87 |
|
92 | |||
88 | class BaseDB(LoggingConfigurable): |
|
93 | class BaseDB(LoggingConfigurable): | |
89 | """Empty Parent class so traitlets work on DB.""" |
|
94 | """Empty Parent class so traitlets work on DB.""" | |
90 | # base configurable traits: |
|
95 | # base configurable traits: | |
91 | session = Unicode("") |
|
96 | session = Unicode("") | |
92 |
|
97 | |||
93 | class DictDB(BaseDB): |
|
98 | class DictDB(BaseDB): | |
94 | """Basic in-memory dict-based object for saving Task Records. |
|
99 | """Basic in-memory dict-based object for saving Task Records. | |
95 |
|
100 | |||
96 | This is the first object to present the DB interface |
|
101 | This is the first object to present the DB interface | |
97 | for logging tasks out of memory. |
|
102 | for logging tasks out of memory. | |
98 |
|
103 | |||
99 | The interface is based on MongoDB, so adding a MongoDB |
|
104 | The interface is based on MongoDB, so adding a MongoDB | |
100 | backend should be straightforward. |
|
105 | backend should be straightforward. | |
101 | """ |
|
106 | """ | |
102 |
|
107 | |||
103 | _records = Dict() |
|
108 | _records = Dict() | |
104 | _culled_ids = set() # set of ids which have been culled |
|
109 | _culled_ids = set() # set of ids which have been culled | |
105 | _buffer_bytes = Integer(0) # running total of the bytes in the DB |
|
110 | _buffer_bytes = Integer(0) # running total of the bytes in the DB | |
106 |
|
111 | |||
107 | size_limit = Integer(1024**3, config=True, |
|
112 | size_limit = Integer(1024**3, config=True, | |
108 | help="""The maximum total size (in bytes) of the buffers stored in the db |
|
113 | help="""The maximum total size (in bytes) of the buffers stored in the db | |
109 |
|
114 | |||
110 | When the db exceeds this size, the oldest records will be culled until |
|
115 | When the db exceeds this size, the oldest records will be culled until | |
111 | the total size is under size_limit * (1-cull_fraction). |
|
116 | the total size is under size_limit * (1-cull_fraction). | |
112 | default: 1 GB |
|
117 | default: 1 GB | |
113 | """ |
|
118 | """ | |
114 | ) |
|
119 | ) | |
115 | record_limit = Integer(1024, config=True, |
|
120 | record_limit = Integer(1024, config=True, | |
116 | help="""The maximum number of records in the db |
|
121 | help="""The maximum number of records in the db | |
117 |
|
122 | |||
118 | When the history exceeds this size, the first record_limit * cull_fraction |
|
123 | When the history exceeds this size, the first record_limit * cull_fraction | |
119 | records will be culled. |
|
124 | records will be culled. | |
120 | """ |
|
125 | """ | |
121 | ) |
|
126 | ) | |
122 | cull_fraction = Float(0.1, config=True, |
|
127 | cull_fraction = Float(0.1, config=True, | |
123 | help="""The fraction by which the db should culled when one of the limits is exceeded |
|
128 | help="""The fraction by which the db should culled when one of the limits is exceeded | |
124 |
|
129 | |||
125 | In general, the db size will spend most of its time with a size in the range: |
|
130 | In general, the db size will spend most of its time with a size in the range: | |
126 |
|
131 | |||
127 | [limit * (1-cull_fraction), limit] |
|
132 | [limit * (1-cull_fraction), limit] | |
128 |
|
133 | |||
129 | for each of size_limit and record_limit. |
|
134 | for each of size_limit and record_limit. | |
130 | """ |
|
135 | """ | |
131 | ) |
|
136 | ) | |
132 |
|
137 | |||
133 | def _match_one(self, rec, tests): |
|
138 | def _match_one(self, rec, tests): | |
134 | """Check if a specific record matches tests.""" |
|
139 | """Check if a specific record matches tests.""" | |
135 | for key,test in iteritems(tests): |
|
140 | for key,test in iteritems(tests): | |
136 | if not test(rec.get(key, None)): |
|
141 | if not test(rec.get(key, None)): | |
137 | return False |
|
142 | return False | |
138 | return True |
|
143 | return True | |
139 |
|
144 | |||
140 | def _match(self, check): |
|
145 | def _match(self, check): | |
141 | """Find all the matches for a check dict.""" |
|
146 | """Find all the matches for a check dict.""" | |
142 | matches = [] |
|
147 | matches = [] | |
143 | tests = {} |
|
148 | tests = {} | |
144 | for k,v in iteritems(check): |
|
149 | for k,v in iteritems(check): | |
145 | if isinstance(v, dict): |
|
150 | if isinstance(v, dict): | |
146 | tests[k] = CompositeFilter(v) |
|
151 | tests[k] = CompositeFilter(v) | |
147 | else: |
|
152 | else: | |
148 | tests[k] = lambda o: o==v |
|
153 | tests[k] = lambda o: o==v | |
149 |
|
154 | |||
150 | for rec in itervalues(self._records): |
|
155 | for rec in itervalues(self._records): | |
151 | if self._match_one(rec, tests): |
|
156 | if self._match_one(rec, tests): | |
152 | matches.append(copy(rec)) |
|
157 | matches.append(copy(rec)) | |
153 | return matches |
|
158 | return matches | |
154 |
|
159 | |||
155 | def _extract_subdict(self, rec, keys): |
|
160 | def _extract_subdict(self, rec, keys): | |
156 | """extract subdict of keys""" |
|
161 | """extract subdict of keys""" | |
157 | d = {} |
|
162 | d = {} | |
158 | d['msg_id'] = rec['msg_id'] |
|
163 | d['msg_id'] = rec['msg_id'] | |
159 | for key in keys: |
|
164 | for key in keys: | |
160 | d[key] = rec[key] |
|
165 | d[key] = rec[key] | |
161 | return copy(d) |
|
166 | return copy(d) | |
162 |
|
167 | |||
163 | # methods for monitoring size / culling history |
|
168 | # methods for monitoring size / culling history | |
164 |
|
169 | |||
165 | def _add_bytes(self, rec): |
|
170 | def _add_bytes(self, rec): | |
166 | for key in ('buffers', 'result_buffers'): |
|
171 | for key in ('buffers', 'result_buffers'): | |
167 | for buf in rec.get(key) or []: |
|
172 | for buf in rec.get(key) or []: | |
168 | self._buffer_bytes += len(buf) |
|
173 | self._buffer_bytes += len(buf) | |
169 |
|
174 | |||
170 | self._maybe_cull() |
|
175 | self._maybe_cull() | |
171 |
|
176 | |||
172 | def _drop_bytes(self, rec): |
|
177 | def _drop_bytes(self, rec): | |
173 | for key in ('buffers', 'result_buffers'): |
|
178 | for key in ('buffers', 'result_buffers'): | |
174 | for buf in rec.get(key) or []: |
|
179 | for buf in rec.get(key) or []: | |
175 | self._buffer_bytes -= len(buf) |
|
180 | self._buffer_bytes -= len(buf) | |
176 |
|
181 | |||
177 | def _cull_oldest(self, n=1): |
|
182 | def _cull_oldest(self, n=1): | |
178 | """cull the oldest N records""" |
|
183 | """cull the oldest N records""" | |
179 | for msg_id in self.get_history()[:n]: |
|
184 | for msg_id in self.get_history()[:n]: | |
180 | self.log.debug("Culling record: %r", msg_id) |
|
185 | self.log.debug("Culling record: %r", msg_id) | |
181 | self._culled_ids.add(msg_id) |
|
186 | self._culled_ids.add(msg_id) | |
182 | self.drop_record(msg_id) |
|
187 | self.drop_record(msg_id) | |
183 |
|
188 | |||
184 | def _maybe_cull(self): |
|
189 | def _maybe_cull(self): | |
185 | # cull by count: |
|
190 | # cull by count: | |
186 | if len(self._records) > self.record_limit: |
|
191 | if len(self._records) > self.record_limit: | |
187 | to_cull = int(self.cull_fraction * self.record_limit) |
|
192 | to_cull = int(self.cull_fraction * self.record_limit) | |
188 | self.log.info("%i records exceeds limit of %i, culling oldest %i", |
|
193 | self.log.info("%i records exceeds limit of %i, culling oldest %i", | |
189 | len(self._records), self.record_limit, to_cull |
|
194 | len(self._records), self.record_limit, to_cull | |
190 | ) |
|
195 | ) | |
191 | self._cull_oldest(to_cull) |
|
196 | self._cull_oldest(to_cull) | |
192 |
|
197 | |||
193 | # cull by size: |
|
198 | # cull by size: | |
194 | if self._buffer_bytes > self.size_limit: |
|
199 | if self._buffer_bytes > self.size_limit: | |
195 | limit = self.size_limit * (1 - self.cull_fraction) |
|
200 | limit = self.size_limit * (1 - self.cull_fraction) | |
196 |
|
201 | |||
197 | before = self._buffer_bytes |
|
202 | before = self._buffer_bytes | |
198 | before_count = len(self._records) |
|
203 | before_count = len(self._records) | |
199 | culled = 0 |
|
204 | culled = 0 | |
200 | while self._buffer_bytes > limit: |
|
205 | while self._buffer_bytes > limit: | |
201 | self._cull_oldest(1) |
|
206 | self._cull_oldest(1) | |
202 | culled += 1 |
|
207 | culled += 1 | |
203 |
|
208 | |||
204 | self.log.info("%i records with total buffer size %i exceeds limit: %i. Culled oldest %i records.", |
|
209 | self.log.info("%i records with total buffer size %i exceeds limit: %i. Culled oldest %i records.", | |
205 | before_count, before, self.size_limit, culled |
|
210 | before_count, before, self.size_limit, culled | |
206 | ) |
|
211 | ) | |
207 |
|
212 | |||
208 | # public API methods: |
|
213 | # public API methods: | |
209 |
|
214 | |||
210 | def add_record(self, msg_id, rec): |
|
215 | def add_record(self, msg_id, rec): | |
211 | """Add a new Task Record, by msg_id.""" |
|
216 | """Add a new Task Record, by msg_id.""" | |
212 | if msg_id in self._records: |
|
217 | if msg_id in self._records: | |
213 | raise KeyError("Already have msg_id %r"%(msg_id)) |
|
218 | raise KeyError("Already have msg_id %r"%(msg_id)) | |
214 | self._records[msg_id] = rec |
|
219 | self._records[msg_id] = rec | |
215 | self._add_bytes(rec) |
|
220 | self._add_bytes(rec) | |
216 | self._maybe_cull() |
|
221 | self._maybe_cull() | |
217 |
|
222 | |||
218 | def get_record(self, msg_id): |
|
223 | def get_record(self, msg_id): | |
219 | """Get a specific Task Record, by msg_id.""" |
|
224 | """Get a specific Task Record, by msg_id.""" | |
220 | if msg_id in self._culled_ids: |
|
225 | if msg_id in self._culled_ids: | |
221 | raise KeyError("Record %r has been culled for size" % msg_id) |
|
226 | raise KeyError("Record %r has been culled for size" % msg_id) | |
222 | if not msg_id in self._records: |
|
227 | if not msg_id in self._records: | |
223 | raise KeyError("No such msg_id %r"%(msg_id)) |
|
228 | raise KeyError("No such msg_id %r"%(msg_id)) | |
224 | return copy(self._records[msg_id]) |
|
229 | return copy(self._records[msg_id]) | |
225 |
|
230 | |||
226 | def update_record(self, msg_id, rec): |
|
231 | def update_record(self, msg_id, rec): | |
227 | """Update the data in an existing record.""" |
|
232 | """Update the data in an existing record.""" | |
228 | if msg_id in self._culled_ids: |
|
233 | if msg_id in self._culled_ids: | |
229 | raise KeyError("Record %r has been culled for size" % msg_id) |
|
234 | raise KeyError("Record %r has been culled for size" % msg_id) | |
230 | _rec = self._records[msg_id] |
|
235 | _rec = self._records[msg_id] | |
231 | self._drop_bytes(_rec) |
|
236 | self._drop_bytes(_rec) | |
232 | _rec.update(rec) |
|
237 | _rec.update(rec) | |
233 | self._add_bytes(_rec) |
|
238 | self._add_bytes(_rec) | |
234 |
|
239 | |||
235 | def drop_matching_records(self, check): |
|
240 | def drop_matching_records(self, check): | |
236 | """Remove a record from the DB.""" |
|
241 | """Remove a record from the DB.""" | |
237 | matches = self._match(check) |
|
242 | matches = self._match(check) | |
238 | for rec in matches: |
|
243 | for rec in matches: | |
239 | self._drop_bytes(rec) |
|
244 | self._drop_bytes(rec) | |
240 | del self._records[rec['msg_id']] |
|
245 | del self._records[rec['msg_id']] | |
241 |
|
246 | |||
242 | def drop_record(self, msg_id): |
|
247 | def drop_record(self, msg_id): | |
243 | """Remove a record from the DB.""" |
|
248 | """Remove a record from the DB.""" | |
244 | rec = self._records[msg_id] |
|
249 | rec = self._records[msg_id] | |
245 | self._drop_bytes(rec) |
|
250 | self._drop_bytes(rec) | |
246 | del self._records[msg_id] |
|
251 | del self._records[msg_id] | |
247 |
|
252 | |||
248 | def find_records(self, check, keys=None): |
|
253 | def find_records(self, check, keys=None): | |
249 | """Find records matching a query dict, optionally extracting subset of keys. |
|
254 | """Find records matching a query dict, optionally extracting subset of keys. | |
250 |
|
255 | |||
251 | Returns dict keyed by msg_id of matching records. |
|
256 | Returns dict keyed by msg_id of matching records. | |
252 |
|
257 | |||
253 | Parameters |
|
258 | Parameters | |
254 | ---------- |
|
259 | ---------- | |
255 |
|
260 | |||
256 | check: dict |
|
261 | check: dict | |
257 | mongodb-style query argument |
|
262 | mongodb-style query argument | |
258 | keys: list of strs [optional] |
|
263 | keys: list of strs [optional] | |
259 | if specified, the subset of keys to extract. msg_id will *always* be |
|
264 | if specified, the subset of keys to extract. msg_id will *always* be | |
260 | included. |
|
265 | included. | |
261 | """ |
|
266 | """ | |
262 | matches = self._match(check) |
|
267 | matches = self._match(check) | |
263 | if keys: |
|
268 | if keys: | |
264 | return [ self._extract_subdict(rec, keys) for rec in matches ] |
|
269 | return [ self._extract_subdict(rec, keys) for rec in matches ] | |
265 | else: |
|
270 | else: | |
266 | return matches |
|
271 | return matches | |
267 |
|
272 | |||
268 | def get_history(self): |
|
273 | def get_history(self): | |
269 | """get all msg_ids, ordered by time submitted.""" |
|
274 | """get all msg_ids, ordered by time submitted.""" | |
270 | msg_ids = self._records.keys() |
|
275 | msg_ids = self._records.keys() | |
271 | # Remove any that do not have a submitted timestamp. |
|
276 | # Remove any that do not have a submitted timestamp. | |
272 | # This is extremely unlikely to happen, |
|
277 | # This is extremely unlikely to happen, | |
273 | # but it seems to come up in some tests on VMs. |
|
278 | # but it seems to come up in some tests on VMs. | |
274 | msg_ids = [ m for m in msg_ids if self._records[m]['submitted'] is not None ] |
|
279 | msg_ids = [ m for m in msg_ids if self._records[m]['submitted'] is not None ] | |
275 | return sorted(msg_ids, key=lambda m: self._records[m]['submitted']) |
|
280 | return sorted(msg_ids, key=lambda m: self._records[m]['submitted']) | |
276 |
|
281 | |||
277 |
|
282 | |||
278 | NODATA = KeyError("NoDB backend doesn't store any data. " |
|
283 | NODATA = KeyError("NoDB backend doesn't store any data. " | |
279 | "Start the Controller with a DB backend to enable resubmission / result persistence." |
|
284 | "Start the Controller with a DB backend to enable resubmission / result persistence." | |
280 | ) |
|
285 | ) | |
281 |
|
286 | |||
282 |
|
287 | |||
283 | class NoDB(BaseDB): |
|
288 | class NoDB(BaseDB): | |
284 | """A blackhole db backend that actually stores no information. |
|
289 | """A blackhole db backend that actually stores no information. | |
285 |
|
290 | |||
286 | Provides the full DB interface, but raises KeyErrors on any |
|
291 | Provides the full DB interface, but raises KeyErrors on any | |
287 | method that tries to access the records. This can be used to |
|
292 | method that tries to access the records. This can be used to | |
288 | minimize the memory footprint of the Hub when its record-keeping |
|
293 | minimize the memory footprint of the Hub when its record-keeping | |
289 | functionality is not required. |
|
294 | functionality is not required. | |
290 | """ |
|
295 | """ | |
291 |
|
296 | |||
292 | def add_record(self, msg_id, record): |
|
297 | def add_record(self, msg_id, record): | |
293 | pass |
|
298 | pass | |
294 |
|
299 | |||
295 | def get_record(self, msg_id): |
|
300 | def get_record(self, msg_id): | |
296 | raise NODATA |
|
301 | raise NODATA | |
297 |
|
302 | |||
298 | def update_record(self, msg_id, record): |
|
303 | def update_record(self, msg_id, record): | |
299 | pass |
|
304 | pass | |
300 |
|
305 | |||
301 | def drop_matching_records(self, check): |
|
306 | def drop_matching_records(self, check): | |
302 | pass |
|
307 | pass | |
303 |
|
308 | |||
304 | def drop_record(self, msg_id): |
|
309 | def drop_record(self, msg_id): | |
305 | pass |
|
310 | pass | |
306 |
|
311 | |||
307 | def find_records(self, check, keys=None): |
|
312 | def find_records(self, check, keys=None): | |
308 | raise NODATA |
|
313 | raise NODATA | |
309 |
|
314 | |||
310 | def get_history(self): |
|
315 | def get_history(self): | |
311 | raise NODATA |
|
316 | raise NODATA | |
312 |
|
317 |
@@ -1,1422 +1,1426 b'' | |||||
1 | """The IPython Controller Hub with 0MQ |
|
1 | """The IPython Controller Hub with 0MQ | |
2 | This is the master object that handles connections from engines and clients, |
|
2 | This is the master object that handles connections from engines and clients, | |
3 | and monitors traffic through the various queues. |
|
3 | and monitors traffic through the various queues. | |
4 |
|
4 | |||
5 | Authors: |
|
5 | Authors: | |
6 |
|
6 | |||
7 | * Min RK |
|
7 | * Min RK | |
8 | """ |
|
8 | """ | |
9 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
10 | # Copyright (C) 2010-2011 The IPython Development Team |
|
10 | # Copyright (C) 2010-2011 The IPython Development Team | |
11 | # |
|
11 | # | |
12 | # Distributed under the terms of the BSD License. The full license is in |
|
12 | # Distributed under the terms of the BSD License. The full license is in | |
13 | # the file COPYING, distributed as part of this software. |
|
13 | # the file COPYING, distributed as part of this software. | |
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 |
|
15 | |||
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 | # Imports |
|
17 | # Imports | |
18 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
19 | from __future__ import print_function |
|
19 | from __future__ import print_function | |
20 |
|
20 | |||
21 | import json |
|
21 | import json | |
22 | import os |
|
22 | import os | |
23 | import sys |
|
23 | import sys | |
24 | import time |
|
24 | import time | |
25 | from datetime import datetime |
|
25 | from datetime import datetime | |
26 |
|
26 | |||
27 | import zmq |
|
27 | import zmq | |
28 | from zmq.eventloop import ioloop |
|
28 | from zmq.eventloop import ioloop | |
29 | from zmq.eventloop.zmqstream import ZMQStream |
|
29 | from zmq.eventloop.zmqstream import ZMQStream | |
30 |
|
30 | |||
31 | # internal: |
|
31 | # internal: | |
32 | from IPython.utils.importstring import import_item |
|
32 | from IPython.utils.importstring import import_item | |
33 | from IPython.utils.jsonutil import extract_dates |
|
33 | from IPython.utils.jsonutil import extract_dates | |
34 | from IPython.utils.localinterfaces import localhost |
|
34 | from IPython.utils.localinterfaces import localhost | |
35 | from IPython.utils.py3compat import cast_bytes, unicode_type, iteritems |
|
35 | from IPython.utils.py3compat import cast_bytes, unicode_type, iteritems | |
36 | from IPython.utils.traitlets import ( |
|
36 | from IPython.utils.traitlets import ( | |
37 | HasTraits, Instance, Integer, Unicode, Dict, Set, Tuple, CBytes, DottedObjectName |
|
37 | HasTraits, Instance, Integer, Unicode, Dict, Set, Tuple, CBytes, DottedObjectName | |
38 | ) |
|
38 | ) | |
39 |
|
39 | |||
40 | from IPython.parallel import error, util |
|
40 | from IPython.parallel import error, util | |
41 | from IPython.parallel.factory import RegistrationFactory |
|
41 | from IPython.parallel.factory import RegistrationFactory | |
42 |
|
42 | |||
43 | from IPython.kernel.zmq.session import SessionFactory |
|
43 | from IPython.kernel.zmq.session import SessionFactory | |
44 |
|
44 | |||
45 | from .heartmonitor import HeartMonitor |
|
45 | from .heartmonitor import HeartMonitor | |
46 |
|
46 | |||
47 | #----------------------------------------------------------------------------- |
|
47 | #----------------------------------------------------------------------------- | |
48 | # Code |
|
48 | # Code | |
49 | #----------------------------------------------------------------------------- |
|
49 | #----------------------------------------------------------------------------- | |
50 |
|
50 | |||
51 | def _passer(*args, **kwargs): |
|
51 | def _passer(*args, **kwargs): | |
52 | return |
|
52 | return | |
53 |
|
53 | |||
54 | def _printer(*args, **kwargs): |
|
54 | def _printer(*args, **kwargs): | |
55 | print (args) |
|
55 | print (args) | |
56 | print (kwargs) |
|
56 | print (kwargs) | |
57 |
|
57 | |||
58 | def empty_record(): |
|
58 | def empty_record(): | |
59 | """Return an empty dict with all record keys.""" |
|
59 | """Return an empty dict with all record keys.""" | |
60 | return { |
|
60 | return { | |
61 | 'msg_id' : None, |
|
61 | 'msg_id' : None, | |
62 | 'header' : None, |
|
62 | 'header' : None, | |
63 | 'metadata' : None, |
|
63 | 'metadata' : None, | |
64 | 'content': None, |
|
64 | 'content': None, | |
65 | 'buffers': None, |
|
65 | 'buffers': None, | |
66 | 'submitted': None, |
|
66 | 'submitted': None, | |
67 | 'client_uuid' : None, |
|
67 | 'client_uuid' : None, | |
68 | 'engine_uuid' : None, |
|
68 | 'engine_uuid' : None, | |
69 | 'started': None, |
|
69 | 'started': None, | |
70 | 'completed': None, |
|
70 | 'completed': None, | |
71 | 'resubmitted': None, |
|
71 | 'resubmitted': None, | |
72 | 'received': None, |
|
72 | 'received': None, | |
73 | 'result_header' : None, |
|
73 | 'result_header' : None, | |
74 | 'result_metadata' : None, |
|
74 | 'result_metadata' : None, | |
75 | 'result_content' : None, |
|
75 | 'result_content' : None, | |
76 | 'result_buffers' : None, |
|
76 | 'result_buffers' : None, | |
77 | 'queue' : None, |
|
77 | 'queue' : None, | |
78 | 'pyin' : None, |
|
78 | 'pyin' : None, | |
79 | 'pyout': None, |
|
79 | 'pyout': None, | |
80 | 'pyerr': None, |
|
80 | 'pyerr': None, | |
81 | 'stdout': '', |
|
81 | 'stdout': '', | |
82 | 'stderr': '', |
|
82 | 'stderr': '', | |
83 | } |
|
83 | } | |
84 |
|
84 | |||
85 | def init_record(msg): |
|
85 | def init_record(msg): | |
86 | """Initialize a TaskRecord based on a request.""" |
|
86 | """Initialize a TaskRecord based on a request.""" | |
87 | header = msg['header'] |
|
87 | header = msg['header'] | |
88 | return { |
|
88 | return { | |
89 | 'msg_id' : header['msg_id'], |
|
89 | 'msg_id' : header['msg_id'], | |
90 | 'header' : header, |
|
90 | 'header' : header, | |
91 | 'content': msg['content'], |
|
91 | 'content': msg['content'], | |
92 | 'metadata': msg['metadata'], |
|
92 | 'metadata': msg['metadata'], | |
93 | 'buffers': msg['buffers'], |
|
93 | 'buffers': msg['buffers'], | |
94 | 'submitted': header['date'], |
|
94 | 'submitted': header['date'], | |
95 | 'client_uuid' : None, |
|
95 | 'client_uuid' : None, | |
96 | 'engine_uuid' : None, |
|
96 | 'engine_uuid' : None, | |
97 | 'started': None, |
|
97 | 'started': None, | |
98 | 'completed': None, |
|
98 | 'completed': None, | |
99 | 'resubmitted': None, |
|
99 | 'resubmitted': None, | |
100 | 'received': None, |
|
100 | 'received': None, | |
101 | 'result_header' : None, |
|
101 | 'result_header' : None, | |
102 | 'result_metadata': None, |
|
102 | 'result_metadata': None, | |
103 | 'result_content' : None, |
|
103 | 'result_content' : None, | |
104 | 'result_buffers' : None, |
|
104 | 'result_buffers' : None, | |
105 | 'queue' : None, |
|
105 | 'queue' : None, | |
106 | 'pyin' : None, |
|
106 | 'pyin' : None, | |
107 | 'pyout': None, |
|
107 | 'pyout': None, | |
108 | 'pyerr': None, |
|
108 | 'pyerr': None, | |
109 | 'stdout': '', |
|
109 | 'stdout': '', | |
110 | 'stderr': '', |
|
110 | 'stderr': '', | |
111 | } |
|
111 | } | |
112 |
|
112 | |||
113 |
|
113 | |||
114 | class EngineConnector(HasTraits): |
|
114 | class EngineConnector(HasTraits): | |
115 | """A simple object for accessing the various zmq connections of an object. |
|
115 | """A simple object for accessing the various zmq connections of an object. | |
116 | Attributes are: |
|
116 | Attributes are: | |
117 | id (int): engine ID |
|
117 | id (int): engine ID | |
118 | uuid (unicode): engine UUID |
|
118 | uuid (unicode): engine UUID | |
119 | pending: set of msg_ids |
|
119 | pending: set of msg_ids | |
120 | stallback: DelayedCallback for stalled registration |
|
120 | stallback: DelayedCallback for stalled registration | |
121 | """ |
|
121 | """ | |
122 |
|
122 | |||
123 | id = Integer(0) |
|
123 | id = Integer(0) | |
124 | uuid = Unicode() |
|
124 | uuid = Unicode() | |
125 | pending = Set() |
|
125 | pending = Set() | |
126 | stallback = Instance(ioloop.DelayedCallback) |
|
126 | stallback = Instance(ioloop.DelayedCallback) | |
127 |
|
127 | |||
128 |
|
128 | |||
129 | _db_shortcuts = { |
|
129 | _db_shortcuts = { | |
130 | 'sqlitedb' : 'IPython.parallel.controller.sqlitedb.SQLiteDB', |
|
130 | 'sqlitedb' : 'IPython.parallel.controller.sqlitedb.SQLiteDB', | |
131 | 'mongodb' : 'IPython.parallel.controller.mongodb.MongoDB', |
|
131 | 'mongodb' : 'IPython.parallel.controller.mongodb.MongoDB', | |
132 | 'dictdb' : 'IPython.parallel.controller.dictdb.DictDB', |
|
132 | 'dictdb' : 'IPython.parallel.controller.dictdb.DictDB', | |
133 | 'nodb' : 'IPython.parallel.controller.dictdb.NoDB', |
|
133 | 'nodb' : 'IPython.parallel.controller.dictdb.NoDB', | |
134 | } |
|
134 | } | |
135 |
|
135 | |||
136 | class HubFactory(RegistrationFactory): |
|
136 | class HubFactory(RegistrationFactory): | |
137 | """The Configurable for setting up a Hub.""" |
|
137 | """The Configurable for setting up a Hub.""" | |
138 |
|
138 | |||
139 | # port-pairs for monitoredqueues: |
|
139 | # port-pairs for monitoredqueues: | |
140 | hb = Tuple(Integer,Integer,config=True, |
|
140 | hb = Tuple(Integer,Integer,config=True, | |
141 | help="""PUB/ROUTER Port pair for Engine heartbeats""") |
|
141 | help="""PUB/ROUTER Port pair for Engine heartbeats""") | |
142 | def _hb_default(self): |
|
142 | def _hb_default(self): | |
143 | return tuple(util.select_random_ports(2)) |
|
143 | return tuple(util.select_random_ports(2)) | |
144 |
|
144 | |||
145 | mux = Tuple(Integer,Integer,config=True, |
|
145 | mux = Tuple(Integer,Integer,config=True, | |
146 | help="""Client/Engine Port pair for MUX queue""") |
|
146 | help="""Client/Engine Port pair for MUX queue""") | |
147 |
|
147 | |||
148 | def _mux_default(self): |
|
148 | def _mux_default(self): | |
149 | return tuple(util.select_random_ports(2)) |
|
149 | return tuple(util.select_random_ports(2)) | |
150 |
|
150 | |||
151 | task = Tuple(Integer,Integer,config=True, |
|
151 | task = Tuple(Integer,Integer,config=True, | |
152 | help="""Client/Engine Port pair for Task queue""") |
|
152 | help="""Client/Engine Port pair for Task queue""") | |
153 | def _task_default(self): |
|
153 | def _task_default(self): | |
154 | return tuple(util.select_random_ports(2)) |
|
154 | return tuple(util.select_random_ports(2)) | |
155 |
|
155 | |||
156 | control = Tuple(Integer,Integer,config=True, |
|
156 | control = Tuple(Integer,Integer,config=True, | |
157 | help="""Client/Engine Port pair for Control queue""") |
|
157 | help="""Client/Engine Port pair for Control queue""") | |
158 |
|
158 | |||
159 | def _control_default(self): |
|
159 | def _control_default(self): | |
160 | return tuple(util.select_random_ports(2)) |
|
160 | return tuple(util.select_random_ports(2)) | |
161 |
|
161 | |||
162 | iopub = Tuple(Integer,Integer,config=True, |
|
162 | iopub = Tuple(Integer,Integer,config=True, | |
163 | help="""Client/Engine Port pair for IOPub relay""") |
|
163 | help="""Client/Engine Port pair for IOPub relay""") | |
164 |
|
164 | |||
165 | def _iopub_default(self): |
|
165 | def _iopub_default(self): | |
166 | return tuple(util.select_random_ports(2)) |
|
166 | return tuple(util.select_random_ports(2)) | |
167 |
|
167 | |||
168 | # single ports: |
|
168 | # single ports: | |
169 | mon_port = Integer(config=True, |
|
169 | mon_port = Integer(config=True, | |
170 | help="""Monitor (SUB) port for queue traffic""") |
|
170 | help="""Monitor (SUB) port for queue traffic""") | |
171 |
|
171 | |||
172 | def _mon_port_default(self): |
|
172 | def _mon_port_default(self): | |
173 | return util.select_random_ports(1)[0] |
|
173 | return util.select_random_ports(1)[0] | |
174 |
|
174 | |||
175 | notifier_port = Integer(config=True, |
|
175 | notifier_port = Integer(config=True, | |
176 | help="""PUB port for sending engine status notifications""") |
|
176 | help="""PUB port for sending engine status notifications""") | |
177 |
|
177 | |||
178 | def _notifier_port_default(self): |
|
178 | def _notifier_port_default(self): | |
179 | return util.select_random_ports(1)[0] |
|
179 | return util.select_random_ports(1)[0] | |
180 |
|
180 | |||
181 | engine_ip = Unicode(config=True, |
|
181 | engine_ip = Unicode(config=True, | |
182 | help="IP on which to listen for engine connections. [default: loopback]") |
|
182 | help="IP on which to listen for engine connections. [default: loopback]") | |
183 | def _engine_ip_default(self): |
|
183 | def _engine_ip_default(self): | |
184 | return localhost() |
|
184 | return localhost() | |
185 | engine_transport = Unicode('tcp', config=True, |
|
185 | engine_transport = Unicode('tcp', config=True, | |
186 | help="0MQ transport for engine connections. [default: tcp]") |
|
186 | help="0MQ transport for engine connections. [default: tcp]") | |
187 |
|
187 | |||
188 | client_ip = Unicode(config=True, |
|
188 | client_ip = Unicode(config=True, | |
189 | help="IP on which to listen for client connections. [default: loopback]") |
|
189 | help="IP on which to listen for client connections. [default: loopback]") | |
190 | client_transport = Unicode('tcp', config=True, |
|
190 | client_transport = Unicode('tcp', config=True, | |
191 | help="0MQ transport for client connections. [default : tcp]") |
|
191 | help="0MQ transport for client connections. [default : tcp]") | |
192 |
|
192 | |||
193 | monitor_ip = Unicode(config=True, |
|
193 | monitor_ip = Unicode(config=True, | |
194 | help="IP on which to listen for monitor messages. [default: loopback]") |
|
194 | help="IP on which to listen for monitor messages. [default: loopback]") | |
195 | monitor_transport = Unicode('tcp', config=True, |
|
195 | monitor_transport = Unicode('tcp', config=True, | |
196 | help="0MQ transport for monitor messages. [default : tcp]") |
|
196 | help="0MQ transport for monitor messages. [default : tcp]") | |
197 |
|
197 | |||
198 | _client_ip_default = _monitor_ip_default = _engine_ip_default |
|
198 | _client_ip_default = _monitor_ip_default = _engine_ip_default | |
199 |
|
199 | |||
200 |
|
200 | |||
201 | monitor_url = Unicode('') |
|
201 | monitor_url = Unicode('') | |
202 |
|
202 | |||
203 | db_class = DottedObjectName('NoDB', |
|
203 | db_class = DottedObjectName('NoDB', | |
204 | config=True, help="""The class to use for the DB backend |
|
204 | config=True, help="""The class to use for the DB backend | |
205 |
|
205 | |||
206 | Options include: |
|
206 | Options include: | |
207 |
|
207 | |||
208 | SQLiteDB: SQLite |
|
208 | SQLiteDB: SQLite | |
209 | MongoDB : use MongoDB |
|
209 | MongoDB : use MongoDB | |
210 | DictDB : in-memory storage (fastest, but be mindful of memory growth of the Hub) |
|
210 | DictDB : in-memory storage (fastest, but be mindful of memory growth of the Hub) | |
211 | NoDB : disable database altogether (default) |
|
211 | NoDB : disable database altogether (default) | |
212 |
|
212 | |||
213 | """) |
|
213 | """) | |
214 |
|
214 | |||
215 | # not configurable |
|
215 | # not configurable | |
216 | db = Instance('IPython.parallel.controller.dictdb.BaseDB') |
|
216 | db = Instance('IPython.parallel.controller.dictdb.BaseDB') | |
217 | heartmonitor = Instance('IPython.parallel.controller.heartmonitor.HeartMonitor') |
|
217 | heartmonitor = Instance('IPython.parallel.controller.heartmonitor.HeartMonitor') | |
218 |
|
218 | |||
219 | def _ip_changed(self, name, old, new): |
|
219 | def _ip_changed(self, name, old, new): | |
220 | self.engine_ip = new |
|
220 | self.engine_ip = new | |
221 | self.client_ip = new |
|
221 | self.client_ip = new | |
222 | self.monitor_ip = new |
|
222 | self.monitor_ip = new | |
223 | self._update_monitor_url() |
|
223 | self._update_monitor_url() | |
224 |
|
224 | |||
225 | def _update_monitor_url(self): |
|
225 | def _update_monitor_url(self): | |
226 | self.monitor_url = "%s://%s:%i" % (self.monitor_transport, self.monitor_ip, self.mon_port) |
|
226 | self.monitor_url = "%s://%s:%i" % (self.monitor_transport, self.monitor_ip, self.mon_port) | |
227 |
|
227 | |||
228 | def _transport_changed(self, name, old, new): |
|
228 | def _transport_changed(self, name, old, new): | |
229 | self.engine_transport = new |
|
229 | self.engine_transport = new | |
230 | self.client_transport = new |
|
230 | self.client_transport = new | |
231 | self.monitor_transport = new |
|
231 | self.monitor_transport = new | |
232 | self._update_monitor_url() |
|
232 | self._update_monitor_url() | |
233 |
|
233 | |||
234 | def __init__(self, **kwargs): |
|
234 | def __init__(self, **kwargs): | |
235 | super(HubFactory, self).__init__(**kwargs) |
|
235 | super(HubFactory, self).__init__(**kwargs) | |
236 | self._update_monitor_url() |
|
236 | self._update_monitor_url() | |
237 |
|
237 | |||
238 |
|
238 | |||
239 | def construct(self): |
|
239 | def construct(self): | |
240 | self.init_hub() |
|
240 | self.init_hub() | |
241 |
|
241 | |||
242 | def start(self): |
|
242 | def start(self): | |
243 | self.heartmonitor.start() |
|
243 | self.heartmonitor.start() | |
244 | self.log.info("Heartmonitor started") |
|
244 | self.log.info("Heartmonitor started") | |
245 |
|
245 | |||
246 | def client_url(self, channel): |
|
246 | def client_url(self, channel): | |
247 | """return full zmq url for a named client channel""" |
|
247 | """return full zmq url for a named client channel""" | |
248 | return "%s://%s:%i" % (self.client_transport, self.client_ip, self.client_info[channel]) |
|
248 | return "%s://%s:%i" % (self.client_transport, self.client_ip, self.client_info[channel]) | |
249 |
|
249 | |||
250 | def engine_url(self, channel): |
|
250 | def engine_url(self, channel): | |
251 | """return full zmq url for a named engine channel""" |
|
251 | """return full zmq url for a named engine channel""" | |
252 | return "%s://%s:%i" % (self.engine_transport, self.engine_ip, self.engine_info[channel]) |
|
252 | return "%s://%s:%i" % (self.engine_transport, self.engine_ip, self.engine_info[channel]) | |
253 |
|
253 | |||
254 | def init_hub(self): |
|
254 | def init_hub(self): | |
255 | """construct Hub object""" |
|
255 | """construct Hub object""" | |
256 |
|
256 | |||
257 | ctx = self.context |
|
257 | ctx = self.context | |
258 | loop = self.loop |
|
258 | loop = self.loop | |
259 | if 'TaskScheduler.scheme_name' in self.config: |
|
259 | if 'TaskScheduler.scheme_name' in self.config: | |
260 | scheme = self.config.TaskScheduler.scheme_name |
|
260 | scheme = self.config.TaskScheduler.scheme_name | |
261 | else: |
|
261 | else: | |
262 | from .scheduler import TaskScheduler |
|
262 | from .scheduler import TaskScheduler | |
263 | scheme = TaskScheduler.scheme_name.get_default_value() |
|
263 | scheme = TaskScheduler.scheme_name.get_default_value() | |
264 |
|
264 | |||
265 | # build connection dicts |
|
265 | # build connection dicts | |
266 | engine = self.engine_info = { |
|
266 | engine = self.engine_info = { | |
267 | 'interface' : "%s://%s" % (self.engine_transport, self.engine_ip), |
|
267 | 'interface' : "%s://%s" % (self.engine_transport, self.engine_ip), | |
268 | 'registration' : self.regport, |
|
268 | 'registration' : self.regport, | |
269 | 'control' : self.control[1], |
|
269 | 'control' : self.control[1], | |
270 | 'mux' : self.mux[1], |
|
270 | 'mux' : self.mux[1], | |
271 | 'hb_ping' : self.hb[0], |
|
271 | 'hb_ping' : self.hb[0], | |
272 | 'hb_pong' : self.hb[1], |
|
272 | 'hb_pong' : self.hb[1], | |
273 | 'task' : self.task[1], |
|
273 | 'task' : self.task[1], | |
274 | 'iopub' : self.iopub[1], |
|
274 | 'iopub' : self.iopub[1], | |
275 | } |
|
275 | } | |
276 |
|
276 | |||
277 | client = self.client_info = { |
|
277 | client = self.client_info = { | |
278 | 'interface' : "%s://%s" % (self.client_transport, self.client_ip), |
|
278 | 'interface' : "%s://%s" % (self.client_transport, self.client_ip), | |
279 | 'registration' : self.regport, |
|
279 | 'registration' : self.regport, | |
280 | 'control' : self.control[0], |
|
280 | 'control' : self.control[0], | |
281 | 'mux' : self.mux[0], |
|
281 | 'mux' : self.mux[0], | |
282 | 'task' : self.task[0], |
|
282 | 'task' : self.task[0], | |
283 | 'task_scheme' : scheme, |
|
283 | 'task_scheme' : scheme, | |
284 | 'iopub' : self.iopub[0], |
|
284 | 'iopub' : self.iopub[0], | |
285 | 'notification' : self.notifier_port, |
|
285 | 'notification' : self.notifier_port, | |
286 | } |
|
286 | } | |
287 |
|
287 | |||
288 | self.log.debug("Hub engine addrs: %s", self.engine_info) |
|
288 | self.log.debug("Hub engine addrs: %s", self.engine_info) | |
289 | self.log.debug("Hub client addrs: %s", self.client_info) |
|
289 | self.log.debug("Hub client addrs: %s", self.client_info) | |
290 |
|
290 | |||
291 | # Registrar socket |
|
291 | # Registrar socket | |
292 | q = ZMQStream(ctx.socket(zmq.ROUTER), loop) |
|
292 | q = ZMQStream(ctx.socket(zmq.ROUTER), loop) | |
293 | util.set_hwm(q, 0) |
|
293 | util.set_hwm(q, 0) | |
294 | q.bind(self.client_url('registration')) |
|
294 | q.bind(self.client_url('registration')) | |
295 | self.log.info("Hub listening on %s for registration.", self.client_url('registration')) |
|
295 | self.log.info("Hub listening on %s for registration.", self.client_url('registration')) | |
296 | if self.client_ip != self.engine_ip: |
|
296 | if self.client_ip != self.engine_ip: | |
297 | q.bind(self.engine_url('registration')) |
|
297 | q.bind(self.engine_url('registration')) | |
298 | self.log.info("Hub listening on %s for registration.", self.engine_url('registration')) |
|
298 | self.log.info("Hub listening on %s for registration.", self.engine_url('registration')) | |
299 |
|
299 | |||
300 | ### Engine connections ### |
|
300 | ### Engine connections ### | |
301 |
|
301 | |||
302 | # heartbeat |
|
302 | # heartbeat | |
303 | hpub = ctx.socket(zmq.PUB) |
|
303 | hpub = ctx.socket(zmq.PUB) | |
304 | hpub.bind(self.engine_url('hb_ping')) |
|
304 | hpub.bind(self.engine_url('hb_ping')) | |
305 | hrep = ctx.socket(zmq.ROUTER) |
|
305 | hrep = ctx.socket(zmq.ROUTER) | |
306 | util.set_hwm(hrep, 0) |
|
306 | util.set_hwm(hrep, 0) | |
307 | hrep.bind(self.engine_url('hb_pong')) |
|
307 | hrep.bind(self.engine_url('hb_pong')) | |
308 | self.heartmonitor = HeartMonitor(loop=loop, parent=self, log=self.log, |
|
308 | self.heartmonitor = HeartMonitor(loop=loop, parent=self, log=self.log, | |
309 | pingstream=ZMQStream(hpub,loop), |
|
309 | pingstream=ZMQStream(hpub,loop), | |
310 | pongstream=ZMQStream(hrep,loop) |
|
310 | pongstream=ZMQStream(hrep,loop) | |
311 | ) |
|
311 | ) | |
312 |
|
312 | |||
313 | ### Client connections ### |
|
313 | ### Client connections ### | |
314 |
|
314 | |||
315 | # Notifier socket |
|
315 | # Notifier socket | |
316 | n = ZMQStream(ctx.socket(zmq.PUB), loop) |
|
316 | n = ZMQStream(ctx.socket(zmq.PUB), loop) | |
317 | n.bind(self.client_url('notification')) |
|
317 | n.bind(self.client_url('notification')) | |
318 |
|
318 | |||
319 | ### build and launch the queues ### |
|
319 | ### build and launch the queues ### | |
320 |
|
320 | |||
321 | # monitor socket |
|
321 | # monitor socket | |
322 | sub = ctx.socket(zmq.SUB) |
|
322 | sub = ctx.socket(zmq.SUB) | |
323 | sub.setsockopt(zmq.SUBSCRIBE, b"") |
|
323 | sub.setsockopt(zmq.SUBSCRIBE, b"") | |
324 | sub.bind(self.monitor_url) |
|
324 | sub.bind(self.monitor_url) | |
325 | sub.bind('inproc://monitor') |
|
325 | sub.bind('inproc://monitor') | |
326 | sub = ZMQStream(sub, loop) |
|
326 | sub = ZMQStream(sub, loop) | |
327 |
|
327 | |||
328 | # connect the db |
|
328 | # connect the db | |
329 | db_class = _db_shortcuts.get(self.db_class.lower(), self.db_class) |
|
329 | db_class = _db_shortcuts.get(self.db_class.lower(), self.db_class) | |
330 | self.log.info('Hub using DB backend: %r', (db_class.split('.')[-1])) |
|
330 | self.log.info('Hub using DB backend: %r', (db_class.split('.')[-1])) | |
331 | self.db = import_item(str(db_class))(session=self.session.session, |
|
331 | self.db = import_item(str(db_class))(session=self.session.session, | |
332 | parent=self, log=self.log) |
|
332 | parent=self, log=self.log) | |
333 | time.sleep(.25) |
|
333 | time.sleep(.25) | |
334 |
|
334 | |||
335 | # resubmit stream |
|
335 | # resubmit stream | |
336 | r = ZMQStream(ctx.socket(zmq.DEALER), loop) |
|
336 | r = ZMQStream(ctx.socket(zmq.DEALER), loop) | |
337 | url = util.disambiguate_url(self.client_url('task')) |
|
337 | url = util.disambiguate_url(self.client_url('task')) | |
338 | r.connect(url) |
|
338 | r.connect(url) | |
339 |
|
339 | |||
340 | self.hub = Hub(loop=loop, session=self.session, monitor=sub, heartmonitor=self.heartmonitor, |
|
340 | self.hub = Hub(loop=loop, session=self.session, monitor=sub, heartmonitor=self.heartmonitor, | |
341 | query=q, notifier=n, resubmit=r, db=self.db, |
|
341 | query=q, notifier=n, resubmit=r, db=self.db, | |
342 | engine_info=self.engine_info, client_info=self.client_info, |
|
342 | engine_info=self.engine_info, client_info=self.client_info, | |
343 | log=self.log) |
|
343 | log=self.log) | |
344 |
|
344 | |||
345 |
|
345 | |||
346 | class Hub(SessionFactory): |
|
346 | class Hub(SessionFactory): | |
347 | """The IPython Controller Hub with 0MQ connections |
|
347 | """The IPython Controller Hub with 0MQ connections | |
348 |
|
348 | |||
349 | Parameters |
|
349 | Parameters | |
350 | ========== |
|
350 | ========== | |
351 | loop: zmq IOLoop instance |
|
351 | loop: zmq IOLoop instance | |
352 | session: Session object |
|
352 | session: Session object | |
353 | <removed> context: zmq context for creating new connections (?) |
|
353 | <removed> context: zmq context for creating new connections (?) | |
354 | queue: ZMQStream for monitoring the command queue (SUB) |
|
354 | queue: ZMQStream for monitoring the command queue (SUB) | |
355 | query: ZMQStream for engine registration and client queries requests (ROUTER) |
|
355 | query: ZMQStream for engine registration and client queries requests (ROUTER) | |
356 | heartbeat: HeartMonitor object checking the pulse of the engines |
|
356 | heartbeat: HeartMonitor object checking the pulse of the engines | |
357 | notifier: ZMQStream for broadcasting engine registration changes (PUB) |
|
357 | notifier: ZMQStream for broadcasting engine registration changes (PUB) | |
358 | db: connection to db for out of memory logging of commands |
|
358 | db: connection to db for out of memory logging of commands | |
359 | NotImplemented |
|
359 | NotImplemented | |
360 | engine_info: dict of zmq connection information for engines to connect |
|
360 | engine_info: dict of zmq connection information for engines to connect | |
361 | to the queues. |
|
361 | to the queues. | |
362 | client_info: dict of zmq connection information for engines to connect |
|
362 | client_info: dict of zmq connection information for engines to connect | |
363 | to the queues. |
|
363 | to the queues. | |
364 | """ |
|
364 | """ | |
365 |
|
365 | |||
366 | engine_state_file = Unicode() |
|
366 | engine_state_file = Unicode() | |
367 |
|
367 | |||
368 | # internal data structures: |
|
368 | # internal data structures: | |
369 | ids=Set() # engine IDs |
|
369 | ids=Set() # engine IDs | |
370 | keytable=Dict() |
|
370 | keytable=Dict() | |
371 | by_ident=Dict() |
|
371 | by_ident=Dict() | |
372 | engines=Dict() |
|
372 | engines=Dict() | |
373 | clients=Dict() |
|
373 | clients=Dict() | |
374 | hearts=Dict() |
|
374 | hearts=Dict() | |
375 | pending=Set() |
|
375 | pending=Set() | |
376 | queues=Dict() # pending msg_ids keyed by engine_id |
|
376 | queues=Dict() # pending msg_ids keyed by engine_id | |
377 | tasks=Dict() # pending msg_ids submitted as tasks, keyed by client_id |
|
377 | tasks=Dict() # pending msg_ids submitted as tasks, keyed by client_id | |
378 | completed=Dict() # completed msg_ids keyed by engine_id |
|
378 | completed=Dict() # completed msg_ids keyed by engine_id | |
379 | all_completed=Set() # completed msg_ids keyed by engine_id |
|
379 | all_completed=Set() # completed msg_ids keyed by engine_id | |
380 | dead_engines=Set() # completed msg_ids keyed by engine_id |
|
380 | dead_engines=Set() # completed msg_ids keyed by engine_id | |
381 | unassigned=Set() # set of task msg_ds not yet assigned a destination |
|
381 | unassigned=Set() # set of task msg_ds not yet assigned a destination | |
382 | incoming_registrations=Dict() |
|
382 | incoming_registrations=Dict() | |
383 | registration_timeout=Integer() |
|
383 | registration_timeout=Integer() | |
384 | _idcounter=Integer(0) |
|
384 | _idcounter=Integer(0) | |
385 |
|
385 | |||
386 | # objects from constructor: |
|
386 | # objects from constructor: | |
387 | query=Instance(ZMQStream) |
|
387 | query=Instance(ZMQStream) | |
388 | monitor=Instance(ZMQStream) |
|
388 | monitor=Instance(ZMQStream) | |
389 | notifier=Instance(ZMQStream) |
|
389 | notifier=Instance(ZMQStream) | |
390 | resubmit=Instance(ZMQStream) |
|
390 | resubmit=Instance(ZMQStream) | |
391 | heartmonitor=Instance(HeartMonitor) |
|
391 | heartmonitor=Instance(HeartMonitor) | |
392 | db=Instance(object) |
|
392 | db=Instance(object) | |
393 | client_info=Dict() |
|
393 | client_info=Dict() | |
394 | engine_info=Dict() |
|
394 | engine_info=Dict() | |
395 |
|
395 | |||
396 |
|
396 | |||
397 | def __init__(self, **kwargs): |
|
397 | def __init__(self, **kwargs): | |
398 | """ |
|
398 | """ | |
399 | # universal: |
|
399 | # universal: | |
400 | loop: IOLoop for creating future connections |
|
400 | loop: IOLoop for creating future connections | |
401 | session: streamsession for sending serialized data |
|
401 | session: streamsession for sending serialized data | |
402 | # engine: |
|
402 | # engine: | |
403 | queue: ZMQStream for monitoring queue messages |
|
403 | queue: ZMQStream for monitoring queue messages | |
404 | query: ZMQStream for engine+client registration and client requests |
|
404 | query: ZMQStream for engine+client registration and client requests | |
405 | heartbeat: HeartMonitor object for tracking engines |
|
405 | heartbeat: HeartMonitor object for tracking engines | |
406 | # extra: |
|
406 | # extra: | |
407 | db: ZMQStream for db connection (NotImplemented) |
|
407 | db: ZMQStream for db connection (NotImplemented) | |
408 | engine_info: zmq address/protocol dict for engine connections |
|
408 | engine_info: zmq address/protocol dict for engine connections | |
409 | client_info: zmq address/protocol dict for client connections |
|
409 | client_info: zmq address/protocol dict for client connections | |
410 | """ |
|
410 | """ | |
411 |
|
411 | |||
412 | super(Hub, self).__init__(**kwargs) |
|
412 | super(Hub, self).__init__(**kwargs) | |
413 | self.registration_timeout = max(10000, 5*self.heartmonitor.period) |
|
413 | self.registration_timeout = max(10000, 5*self.heartmonitor.period) | |
414 |
|
414 | |||
415 | # register our callbacks |
|
415 | # register our callbacks | |
416 | self.query.on_recv(self.dispatch_query) |
|
416 | self.query.on_recv(self.dispatch_query) | |
417 | self.monitor.on_recv(self.dispatch_monitor_traffic) |
|
417 | self.monitor.on_recv(self.dispatch_monitor_traffic) | |
418 |
|
418 | |||
419 | self.heartmonitor.add_heart_failure_handler(self.handle_heart_failure) |
|
419 | self.heartmonitor.add_heart_failure_handler(self.handle_heart_failure) | |
420 | self.heartmonitor.add_new_heart_handler(self.handle_new_heart) |
|
420 | self.heartmonitor.add_new_heart_handler(self.handle_new_heart) | |
421 |
|
421 | |||
422 | self.monitor_handlers = {b'in' : self.save_queue_request, |
|
422 | self.monitor_handlers = {b'in' : self.save_queue_request, | |
423 | b'out': self.save_queue_result, |
|
423 | b'out': self.save_queue_result, | |
424 | b'intask': self.save_task_request, |
|
424 | b'intask': self.save_task_request, | |
425 | b'outtask': self.save_task_result, |
|
425 | b'outtask': self.save_task_result, | |
426 | b'tracktask': self.save_task_destination, |
|
426 | b'tracktask': self.save_task_destination, | |
427 | b'incontrol': _passer, |
|
427 | b'incontrol': _passer, | |
428 | b'outcontrol': _passer, |
|
428 | b'outcontrol': _passer, | |
429 | b'iopub': self.save_iopub_message, |
|
429 | b'iopub': self.save_iopub_message, | |
430 | } |
|
430 | } | |
431 |
|
431 | |||
432 | self.query_handlers = {'queue_request': self.queue_status, |
|
432 | self.query_handlers = {'queue_request': self.queue_status, | |
433 | 'result_request': self.get_results, |
|
433 | 'result_request': self.get_results, | |
434 | 'history_request': self.get_history, |
|
434 | 'history_request': self.get_history, | |
435 | 'db_request': self.db_query, |
|
435 | 'db_request': self.db_query, | |
436 | 'purge_request': self.purge_results, |
|
436 | 'purge_request': self.purge_results, | |
437 | 'load_request': self.check_load, |
|
437 | 'load_request': self.check_load, | |
438 | 'resubmit_request': self.resubmit_task, |
|
438 | 'resubmit_request': self.resubmit_task, | |
439 | 'shutdown_request': self.shutdown_request, |
|
439 | 'shutdown_request': self.shutdown_request, | |
440 | 'registration_request' : self.register_engine, |
|
440 | 'registration_request' : self.register_engine, | |
441 | 'unregistration_request' : self.unregister_engine, |
|
441 | 'unregistration_request' : self.unregister_engine, | |
442 | 'connection_request': self.connection_request, |
|
442 | 'connection_request': self.connection_request, | |
443 | } |
|
443 | } | |
444 |
|
444 | |||
445 | # ignore resubmit replies |
|
445 | # ignore resubmit replies | |
446 | self.resubmit.on_recv(lambda msg: None, copy=False) |
|
446 | self.resubmit.on_recv(lambda msg: None, copy=False) | |
447 |
|
447 | |||
448 | self.log.info("hub::created hub") |
|
448 | self.log.info("hub::created hub") | |
449 |
|
449 | |||
450 | @property |
|
450 | @property | |
451 | def _next_id(self): |
|
451 | def _next_id(self): | |
452 | """gemerate a new ID. |
|
452 | """gemerate a new ID. | |
453 |
|
453 | |||
454 | No longer reuse old ids, just count from 0.""" |
|
454 | No longer reuse old ids, just count from 0.""" | |
455 | newid = self._idcounter |
|
455 | newid = self._idcounter | |
456 | self._idcounter += 1 |
|
456 | self._idcounter += 1 | |
457 | return newid |
|
457 | return newid | |
458 | # newid = 0 |
|
458 | # newid = 0 | |
459 | # incoming = [id[0] for id in itervalues(self.incoming_registrations)] |
|
459 | # incoming = [id[0] for id in itervalues(self.incoming_registrations)] | |
460 | # # print newid, self.ids, self.incoming_registrations |
|
460 | # # print newid, self.ids, self.incoming_registrations | |
461 | # while newid in self.ids or newid in incoming: |
|
461 | # while newid in self.ids or newid in incoming: | |
462 | # newid += 1 |
|
462 | # newid += 1 | |
463 | # return newid |
|
463 | # return newid | |
464 |
|
464 | |||
465 | #----------------------------------------------------------------------------- |
|
465 | #----------------------------------------------------------------------------- | |
466 | # message validation |
|
466 | # message validation | |
467 | #----------------------------------------------------------------------------- |
|
467 | #----------------------------------------------------------------------------- | |
468 |
|
468 | |||
469 | def _validate_targets(self, targets): |
|
469 | def _validate_targets(self, targets): | |
470 | """turn any valid targets argument into a list of integer ids""" |
|
470 | """turn any valid targets argument into a list of integer ids""" | |
471 | if targets is None: |
|
471 | if targets is None: | |
472 | # default to all |
|
472 | # default to all | |
473 | return self.ids |
|
473 | return self.ids | |
474 |
|
474 | |||
475 | if isinstance(targets, (int,str,unicode_type)): |
|
475 | if isinstance(targets, (int,str,unicode_type)): | |
476 | # only one target specified |
|
476 | # only one target specified | |
477 | targets = [targets] |
|
477 | targets = [targets] | |
478 | _targets = [] |
|
478 | _targets = [] | |
479 | for t in targets: |
|
479 | for t in targets: | |
480 | # map raw identities to ids |
|
480 | # map raw identities to ids | |
481 | if isinstance(t, (str,unicode_type)): |
|
481 | if isinstance(t, (str,unicode_type)): | |
482 | t = self.by_ident.get(cast_bytes(t), t) |
|
482 | t = self.by_ident.get(cast_bytes(t), t) | |
483 | _targets.append(t) |
|
483 | _targets.append(t) | |
484 | targets = _targets |
|
484 | targets = _targets | |
485 | bad_targets = [ t for t in targets if t not in self.ids ] |
|
485 | bad_targets = [ t for t in targets if t not in self.ids ] | |
486 | if bad_targets: |
|
486 | if bad_targets: | |
487 | raise IndexError("No Such Engine: %r" % bad_targets) |
|
487 | raise IndexError("No Such Engine: %r" % bad_targets) | |
488 | if not targets: |
|
488 | if not targets: | |
489 | raise IndexError("No Engines Registered") |
|
489 | raise IndexError("No Engines Registered") | |
490 | return targets |
|
490 | return targets | |
491 |
|
491 | |||
492 | #----------------------------------------------------------------------------- |
|
492 | #----------------------------------------------------------------------------- | |
493 | # dispatch methods (1 per stream) |
|
493 | # dispatch methods (1 per stream) | |
494 | #----------------------------------------------------------------------------- |
|
494 | #----------------------------------------------------------------------------- | |
495 |
|
495 | |||
496 |
|
496 | |||
497 | @util.log_errors |
|
497 | @util.log_errors | |
498 | def dispatch_monitor_traffic(self, msg): |
|
498 | def dispatch_monitor_traffic(self, msg): | |
499 | """all ME and Task queue messages come through here, as well as |
|
499 | """all ME and Task queue messages come through here, as well as | |
500 | IOPub traffic.""" |
|
500 | IOPub traffic.""" | |
501 | self.log.debug("monitor traffic: %r", msg[0]) |
|
501 | self.log.debug("monitor traffic: %r", msg[0]) | |
502 | switch = msg[0] |
|
502 | switch = msg[0] | |
503 | try: |
|
503 | try: | |
504 | idents, msg = self.session.feed_identities(msg[1:]) |
|
504 | idents, msg = self.session.feed_identities(msg[1:]) | |
505 | except ValueError: |
|
505 | except ValueError: | |
506 | idents=[] |
|
506 | idents=[] | |
507 | if not idents: |
|
507 | if not idents: | |
508 | self.log.error("Monitor message without topic: %r", msg) |
|
508 | self.log.error("Monitor message without topic: %r", msg) | |
509 | return |
|
509 | return | |
510 | handler = self.monitor_handlers.get(switch, None) |
|
510 | handler = self.monitor_handlers.get(switch, None) | |
511 | if handler is not None: |
|
511 | if handler is not None: | |
512 | handler(idents, msg) |
|
512 | handler(idents, msg) | |
513 | else: |
|
513 | else: | |
514 | self.log.error("Unrecognized monitor topic: %r", switch) |
|
514 | self.log.error("Unrecognized monitor topic: %r", switch) | |
515 |
|
515 | |||
516 |
|
516 | |||
517 | @util.log_errors |
|
517 | @util.log_errors | |
518 | def dispatch_query(self, msg): |
|
518 | def dispatch_query(self, msg): | |
519 | """Route registration requests and queries from clients.""" |
|
519 | """Route registration requests and queries from clients.""" | |
520 | try: |
|
520 | try: | |
521 | idents, msg = self.session.feed_identities(msg) |
|
521 | idents, msg = self.session.feed_identities(msg) | |
522 | except ValueError: |
|
522 | except ValueError: | |
523 | idents = [] |
|
523 | idents = [] | |
524 | if not idents: |
|
524 | if not idents: | |
525 | self.log.error("Bad Query Message: %r", msg) |
|
525 | self.log.error("Bad Query Message: %r", msg) | |
526 | return |
|
526 | return | |
527 | client_id = idents[0] |
|
527 | client_id = idents[0] | |
528 | try: |
|
528 | try: | |
529 | msg = self.session.unserialize(msg, content=True) |
|
529 | msg = self.session.unserialize(msg, content=True) | |
530 | except Exception: |
|
530 | except Exception: | |
531 | content = error.wrap_exception() |
|
531 | content = error.wrap_exception() | |
532 | self.log.error("Bad Query Message: %r", msg, exc_info=True) |
|
532 | self.log.error("Bad Query Message: %r", msg, exc_info=True) | |
533 | self.session.send(self.query, "hub_error", ident=client_id, |
|
533 | self.session.send(self.query, "hub_error", ident=client_id, | |
534 | content=content) |
|
534 | content=content) | |
535 | return |
|
535 | return | |
536 | # print client_id, header, parent, content |
|
536 | # print client_id, header, parent, content | |
537 | #switch on message type: |
|
537 | #switch on message type: | |
538 | msg_type = msg['header']['msg_type'] |
|
538 | msg_type = msg['header']['msg_type'] | |
539 | self.log.info("client::client %r requested %r", client_id, msg_type) |
|
539 | self.log.info("client::client %r requested %r", client_id, msg_type) | |
540 | handler = self.query_handlers.get(msg_type, None) |
|
540 | handler = self.query_handlers.get(msg_type, None) | |
541 | try: |
|
541 | try: | |
542 | assert handler is not None, "Bad Message Type: %r" % msg_type |
|
542 | assert handler is not None, "Bad Message Type: %r" % msg_type | |
543 | except: |
|
543 | except: | |
544 | content = error.wrap_exception() |
|
544 | content = error.wrap_exception() | |
545 | self.log.error("Bad Message Type: %r", msg_type, exc_info=True) |
|
545 | self.log.error("Bad Message Type: %r", msg_type, exc_info=True) | |
546 | self.session.send(self.query, "hub_error", ident=client_id, |
|
546 | self.session.send(self.query, "hub_error", ident=client_id, | |
547 | content=content) |
|
547 | content=content) | |
548 | return |
|
548 | return | |
549 |
|
549 | |||
550 | else: |
|
550 | else: | |
551 | handler(idents, msg) |
|
551 | handler(idents, msg) | |
552 |
|
552 | |||
553 | def dispatch_db(self, msg): |
|
553 | def dispatch_db(self, msg): | |
554 | """""" |
|
554 | """""" | |
555 | raise NotImplementedError |
|
555 | raise NotImplementedError | |
556 |
|
556 | |||
557 | #--------------------------------------------------------------------------- |
|
557 | #--------------------------------------------------------------------------- | |
558 | # handler methods (1 per event) |
|
558 | # handler methods (1 per event) | |
559 | #--------------------------------------------------------------------------- |
|
559 | #--------------------------------------------------------------------------- | |
560 |
|
560 | |||
561 | #----------------------- Heartbeat -------------------------------------- |
|
561 | #----------------------- Heartbeat -------------------------------------- | |
562 |
|
562 | |||
563 | def handle_new_heart(self, heart): |
|
563 | def handle_new_heart(self, heart): | |
564 | """handler to attach to heartbeater. |
|
564 | """handler to attach to heartbeater. | |
565 | Called when a new heart starts to beat. |
|
565 | Called when a new heart starts to beat. | |
566 | Triggers completion of registration.""" |
|
566 | Triggers completion of registration.""" | |
567 | self.log.debug("heartbeat::handle_new_heart(%r)", heart) |
|
567 | self.log.debug("heartbeat::handle_new_heart(%r)", heart) | |
568 | if heart not in self.incoming_registrations: |
|
568 | if heart not in self.incoming_registrations: | |
569 | self.log.info("heartbeat::ignoring new heart: %r", heart) |
|
569 | self.log.info("heartbeat::ignoring new heart: %r", heart) | |
570 | else: |
|
570 | else: | |
571 | self.finish_registration(heart) |
|
571 | self.finish_registration(heart) | |
572 |
|
572 | |||
573 |
|
573 | |||
574 | def handle_heart_failure(self, heart): |
|
574 | def handle_heart_failure(self, heart): | |
575 | """handler to attach to heartbeater. |
|
575 | """handler to attach to heartbeater. | |
576 | called when a previously registered heart fails to respond to beat request. |
|
576 | called when a previously registered heart fails to respond to beat request. | |
577 | triggers unregistration""" |
|
577 | triggers unregistration""" | |
578 | self.log.debug("heartbeat::handle_heart_failure(%r)", heart) |
|
578 | self.log.debug("heartbeat::handle_heart_failure(%r)", heart) | |
579 | eid = self.hearts.get(heart, None) |
|
579 | eid = self.hearts.get(heart, None) | |
580 | uuid = self.engines[eid].uuid |
|
580 | uuid = self.engines[eid].uuid | |
581 | if eid is None or self.keytable[eid] in self.dead_engines: |
|
581 | if eid is None or self.keytable[eid] in self.dead_engines: | |
582 | self.log.info("heartbeat::ignoring heart failure %r (not an engine or already dead)", heart) |
|
582 | self.log.info("heartbeat::ignoring heart failure %r (not an engine or already dead)", heart) | |
583 | else: |
|
583 | else: | |
584 | self.unregister_engine(heart, dict(content=dict(id=eid, queue=uuid))) |
|
584 | self.unregister_engine(heart, dict(content=dict(id=eid, queue=uuid))) | |
585 |
|
585 | |||
586 | #----------------------- MUX Queue Traffic ------------------------------ |
|
586 | #----------------------- MUX Queue Traffic ------------------------------ | |
587 |
|
587 | |||
588 | def save_queue_request(self, idents, msg): |
|
588 | def save_queue_request(self, idents, msg): | |
589 | if len(idents) < 2: |
|
589 | if len(idents) < 2: | |
590 | self.log.error("invalid identity prefix: %r", idents) |
|
590 | self.log.error("invalid identity prefix: %r", idents) | |
591 | return |
|
591 | return | |
592 | queue_id, client_id = idents[:2] |
|
592 | queue_id, client_id = idents[:2] | |
593 | try: |
|
593 | try: | |
594 | msg = self.session.unserialize(msg) |
|
594 | msg = self.session.unserialize(msg) | |
595 | except Exception: |
|
595 | except Exception: | |
596 | self.log.error("queue::client %r sent invalid message to %r: %r", client_id, queue_id, msg, exc_info=True) |
|
596 | self.log.error("queue::client %r sent invalid message to %r: %r", client_id, queue_id, msg, exc_info=True) | |
597 | return |
|
597 | return | |
598 |
|
598 | |||
599 | eid = self.by_ident.get(queue_id, None) |
|
599 | eid = self.by_ident.get(queue_id, None) | |
600 | if eid is None: |
|
600 | if eid is None: | |
601 | self.log.error("queue::target %r not registered", queue_id) |
|
601 | self.log.error("queue::target %r not registered", queue_id) | |
602 | self.log.debug("queue:: valid are: %r", self.by_ident.keys()) |
|
602 | self.log.debug("queue:: valid are: %r", self.by_ident.keys()) | |
603 | return |
|
603 | return | |
604 | record = init_record(msg) |
|
604 | record = init_record(msg) | |
605 | msg_id = record['msg_id'] |
|
605 | msg_id = record['msg_id'] | |
606 | self.log.info("queue::client %r submitted request %r to %s", client_id, msg_id, eid) |
|
606 | self.log.info("queue::client %r submitted request %r to %s", client_id, msg_id, eid) | |
607 | # Unicode in records |
|
607 | # Unicode in records | |
608 | record['engine_uuid'] = queue_id.decode('ascii') |
|
608 | record['engine_uuid'] = queue_id.decode('ascii') | |
609 | record['client_uuid'] = msg['header']['session'] |
|
609 | record['client_uuid'] = msg['header']['session'] | |
610 | record['queue'] = 'mux' |
|
610 | record['queue'] = 'mux' | |
611 |
|
611 | |||
612 | try: |
|
612 | try: | |
613 | # it's posible iopub arrived first: |
|
613 | # it's posible iopub arrived first: | |
614 | existing = self.db.get_record(msg_id) |
|
614 | existing = self.db.get_record(msg_id) | |
615 | for key,evalue in iteritems(existing): |
|
615 | for key,evalue in iteritems(existing): | |
616 | rvalue = record.get(key, None) |
|
616 | rvalue = record.get(key, None) | |
617 | if evalue and rvalue and evalue != rvalue: |
|
617 | if evalue and rvalue and evalue != rvalue: | |
618 | self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue) |
|
618 | self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue) | |
619 | elif evalue and not rvalue: |
|
619 | elif evalue and not rvalue: | |
620 | record[key] = evalue |
|
620 | record[key] = evalue | |
621 | try: |
|
621 | try: | |
622 | self.db.update_record(msg_id, record) |
|
622 | self.db.update_record(msg_id, record) | |
623 | except Exception: |
|
623 | except Exception: | |
624 | self.log.error("DB Error updating record %r", msg_id, exc_info=True) |
|
624 | self.log.error("DB Error updating record %r", msg_id, exc_info=True) | |
625 | except KeyError: |
|
625 | except KeyError: | |
626 | try: |
|
626 | try: | |
627 | self.db.add_record(msg_id, record) |
|
627 | self.db.add_record(msg_id, record) | |
628 | except Exception: |
|
628 | except Exception: | |
629 | self.log.error("DB Error adding record %r", msg_id, exc_info=True) |
|
629 | self.log.error("DB Error adding record %r", msg_id, exc_info=True) | |
630 |
|
630 | |||
631 |
|
631 | |||
632 | self.pending.add(msg_id) |
|
632 | self.pending.add(msg_id) | |
633 | self.queues[eid].append(msg_id) |
|
633 | self.queues[eid].append(msg_id) | |
634 |
|
634 | |||
635 | def save_queue_result(self, idents, msg): |
|
635 | def save_queue_result(self, idents, msg): | |
636 | if len(idents) < 2: |
|
636 | if len(idents) < 2: | |
637 | self.log.error("invalid identity prefix: %r", idents) |
|
637 | self.log.error("invalid identity prefix: %r", idents) | |
638 | return |
|
638 | return | |
639 |
|
639 | |||
640 | client_id, queue_id = idents[:2] |
|
640 | client_id, queue_id = idents[:2] | |
641 | try: |
|
641 | try: | |
642 | msg = self.session.unserialize(msg) |
|
642 | msg = self.session.unserialize(msg) | |
643 | except Exception: |
|
643 | except Exception: | |
644 | self.log.error("queue::engine %r sent invalid message to %r: %r", |
|
644 | self.log.error("queue::engine %r sent invalid message to %r: %r", | |
645 | queue_id, client_id, msg, exc_info=True) |
|
645 | queue_id, client_id, msg, exc_info=True) | |
646 | return |
|
646 | return | |
647 |
|
647 | |||
648 | eid = self.by_ident.get(queue_id, None) |
|
648 | eid = self.by_ident.get(queue_id, None) | |
649 | if eid is None: |
|
649 | if eid is None: | |
650 | self.log.error("queue::unknown engine %r is sending a reply: ", queue_id) |
|
650 | self.log.error("queue::unknown engine %r is sending a reply: ", queue_id) | |
651 | return |
|
651 | return | |
652 |
|
652 | |||
653 | parent = msg['parent_header'] |
|
653 | parent = msg['parent_header'] | |
654 | if not parent: |
|
654 | if not parent: | |
655 | return |
|
655 | return | |
656 | msg_id = parent['msg_id'] |
|
656 | msg_id = parent['msg_id'] | |
657 | if msg_id in self.pending: |
|
657 | if msg_id in self.pending: | |
658 | self.pending.remove(msg_id) |
|
658 | self.pending.remove(msg_id) | |
659 | self.all_completed.add(msg_id) |
|
659 | self.all_completed.add(msg_id) | |
660 | self.queues[eid].remove(msg_id) |
|
660 | self.queues[eid].remove(msg_id) | |
661 | self.completed[eid].append(msg_id) |
|
661 | self.completed[eid].append(msg_id) | |
662 | self.log.info("queue::request %r completed on %s", msg_id, eid) |
|
662 | self.log.info("queue::request %r completed on %s", msg_id, eid) | |
663 | elif msg_id not in self.all_completed: |
|
663 | elif msg_id not in self.all_completed: | |
664 | # it could be a result from a dead engine that died before delivering the |
|
664 | # it could be a result from a dead engine that died before delivering the | |
665 | # result |
|
665 | # result | |
666 | self.log.warn("queue:: unknown msg finished %r", msg_id) |
|
666 | self.log.warn("queue:: unknown msg finished %r", msg_id) | |
667 | return |
|
667 | return | |
668 | # update record anyway, because the unregistration could have been premature |
|
668 | # update record anyway, because the unregistration could have been premature | |
669 | rheader = msg['header'] |
|
669 | rheader = msg['header'] | |
670 | md = msg['metadata'] |
|
670 | md = msg['metadata'] | |
671 | completed = rheader['date'] |
|
671 | completed = rheader['date'] | |
672 | started = md.get('started', None) |
|
672 | started = md.get('started', None) | |
673 | result = { |
|
673 | result = { | |
674 | 'result_header' : rheader, |
|
674 | 'result_header' : rheader, | |
675 | 'result_metadata': md, |
|
675 | 'result_metadata': md, | |
676 | 'result_content': msg['content'], |
|
676 | 'result_content': msg['content'], | |
677 | 'received': datetime.now(), |
|
677 | 'received': datetime.now(), | |
678 | 'started' : started, |
|
678 | 'started' : started, | |
679 | 'completed' : completed |
|
679 | 'completed' : completed | |
680 | } |
|
680 | } | |
681 |
|
681 | |||
682 | result['result_buffers'] = msg['buffers'] |
|
682 | result['result_buffers'] = msg['buffers'] | |
683 | try: |
|
683 | try: | |
684 | self.db.update_record(msg_id, result) |
|
684 | self.db.update_record(msg_id, result) | |
685 | except Exception: |
|
685 | except Exception: | |
686 | self.log.error("DB Error updating record %r", msg_id, exc_info=True) |
|
686 | self.log.error("DB Error updating record %r", msg_id, exc_info=True) | |
687 |
|
687 | |||
688 |
|
688 | |||
689 | #--------------------- Task Queue Traffic ------------------------------ |
|
689 | #--------------------- Task Queue Traffic ------------------------------ | |
690 |
|
690 | |||
691 | def save_task_request(self, idents, msg): |
|
691 | def save_task_request(self, idents, msg): | |
692 | """Save the submission of a task.""" |
|
692 | """Save the submission of a task.""" | |
693 | client_id = idents[0] |
|
693 | client_id = idents[0] | |
694 |
|
694 | |||
695 | try: |
|
695 | try: | |
696 | msg = self.session.unserialize(msg) |
|
696 | msg = self.session.unserialize(msg) | |
697 | except Exception: |
|
697 | except Exception: | |
698 | self.log.error("task::client %r sent invalid task message: %r", |
|
698 | self.log.error("task::client %r sent invalid task message: %r", | |
699 | client_id, msg, exc_info=True) |
|
699 | client_id, msg, exc_info=True) | |
700 | return |
|
700 | return | |
701 | record = init_record(msg) |
|
701 | record = init_record(msg) | |
702 |
|
702 | |||
703 | record['client_uuid'] = msg['header']['session'] |
|
703 | record['client_uuid'] = msg['header']['session'] | |
704 | record['queue'] = 'task' |
|
704 | record['queue'] = 'task' | |
705 | header = msg['header'] |
|
705 | header = msg['header'] | |
706 | msg_id = header['msg_id'] |
|
706 | msg_id = header['msg_id'] | |
707 | self.pending.add(msg_id) |
|
707 | self.pending.add(msg_id) | |
708 | self.unassigned.add(msg_id) |
|
708 | self.unassigned.add(msg_id) | |
709 | try: |
|
709 | try: | |
710 | # it's posible iopub arrived first: |
|
710 | # it's posible iopub arrived first: | |
711 | existing = self.db.get_record(msg_id) |
|
711 | existing = self.db.get_record(msg_id) | |
712 | if existing['resubmitted']: |
|
712 | if existing['resubmitted']: | |
713 | for key in ('submitted', 'client_uuid', 'buffers'): |
|
713 | for key in ('submitted', 'client_uuid', 'buffers'): | |
714 | # don't clobber these keys on resubmit |
|
714 | # don't clobber these keys on resubmit | |
715 | # submitted and client_uuid should be different |
|
715 | # submitted and client_uuid should be different | |
716 | # and buffers might be big, and shouldn't have changed |
|
716 | # and buffers might be big, and shouldn't have changed | |
717 | record.pop(key) |
|
717 | record.pop(key) | |
718 | # still check content,header which should not change |
|
718 | # still check content,header which should not change | |
719 | # but are not expensive to compare as buffers |
|
719 | # but are not expensive to compare as buffers | |
720 |
|
720 | |||
721 | for key,evalue in iteritems(existing): |
|
721 | for key,evalue in iteritems(existing): | |
722 | if key.endswith('buffers'): |
|
722 | if key.endswith('buffers'): | |
723 | # don't compare buffers |
|
723 | # don't compare buffers | |
724 | continue |
|
724 | continue | |
725 | rvalue = record.get(key, None) |
|
725 | rvalue = record.get(key, None) | |
726 | if evalue and rvalue and evalue != rvalue: |
|
726 | if evalue and rvalue and evalue != rvalue: | |
727 | self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue) |
|
727 | self.log.warn("conflicting initial state for record: %r:%r <%r> %r", msg_id, rvalue, key, evalue) | |
728 | elif evalue and not rvalue: |
|
728 | elif evalue and not rvalue: | |
729 | record[key] = evalue |
|
729 | record[key] = evalue | |
730 | try: |
|
730 | try: | |
731 | self.db.update_record(msg_id, record) |
|
731 | self.db.update_record(msg_id, record) | |
732 | except Exception: |
|
732 | except Exception: | |
733 | self.log.error("DB Error updating record %r", msg_id, exc_info=True) |
|
733 | self.log.error("DB Error updating record %r", msg_id, exc_info=True) | |
734 | except KeyError: |
|
734 | except KeyError: | |
735 | try: |
|
735 | try: | |
736 | self.db.add_record(msg_id, record) |
|
736 | self.db.add_record(msg_id, record) | |
737 | except Exception: |
|
737 | except Exception: | |
738 | self.log.error("DB Error adding record %r", msg_id, exc_info=True) |
|
738 | self.log.error("DB Error adding record %r", msg_id, exc_info=True) | |
739 | except Exception: |
|
739 | except Exception: | |
740 | self.log.error("DB Error saving task request %r", msg_id, exc_info=True) |
|
740 | self.log.error("DB Error saving task request %r", msg_id, exc_info=True) | |
741 |
|
741 | |||
742 | def save_task_result(self, idents, msg): |
|
742 | def save_task_result(self, idents, msg): | |
743 | """save the result of a completed task.""" |
|
743 | """save the result of a completed task.""" | |
744 | client_id = idents[0] |
|
744 | client_id = idents[0] | |
745 | try: |
|
745 | try: | |
746 | msg = self.session.unserialize(msg) |
|
746 | msg = self.session.unserialize(msg) | |
747 | except Exception: |
|
747 | except Exception: | |
748 | self.log.error("task::invalid task result message send to %r: %r", |
|
748 | self.log.error("task::invalid task result message send to %r: %r", | |
749 | client_id, msg, exc_info=True) |
|
749 | client_id, msg, exc_info=True) | |
750 | return |
|
750 | return | |
751 |
|
751 | |||
752 | parent = msg['parent_header'] |
|
752 | parent = msg['parent_header'] | |
753 | if not parent: |
|
753 | if not parent: | |
754 | # print msg |
|
754 | # print msg | |
755 | self.log.warn("Task %r had no parent!", msg) |
|
755 | self.log.warn("Task %r had no parent!", msg) | |
756 | return |
|
756 | return | |
757 | msg_id = parent['msg_id'] |
|
757 | msg_id = parent['msg_id'] | |
758 | if msg_id in self.unassigned: |
|
758 | if msg_id in self.unassigned: | |
759 | self.unassigned.remove(msg_id) |
|
759 | self.unassigned.remove(msg_id) | |
760 |
|
760 | |||
761 | header = msg['header'] |
|
761 | header = msg['header'] | |
762 | md = msg['metadata'] |
|
762 | md = msg['metadata'] | |
763 | engine_uuid = md.get('engine', u'') |
|
763 | engine_uuid = md.get('engine', u'') | |
764 | eid = self.by_ident.get(cast_bytes(engine_uuid), None) |
|
764 | eid = self.by_ident.get(cast_bytes(engine_uuid), None) | |
765 |
|
765 | |||
766 | status = md.get('status', None) |
|
766 | status = md.get('status', None) | |
767 |
|
767 | |||
768 | if msg_id in self.pending: |
|
768 | if msg_id in self.pending: | |
769 | self.log.info("task::task %r finished on %s", msg_id, eid) |
|
769 | self.log.info("task::task %r finished on %s", msg_id, eid) | |
770 | self.pending.remove(msg_id) |
|
770 | self.pending.remove(msg_id) | |
771 | self.all_completed.add(msg_id) |
|
771 | self.all_completed.add(msg_id) | |
772 | if eid is not None: |
|
772 | if eid is not None: | |
773 | if status != 'aborted': |
|
773 | if status != 'aborted': | |
774 | self.completed[eid].append(msg_id) |
|
774 | self.completed[eid].append(msg_id) | |
775 | if msg_id in self.tasks[eid]: |
|
775 | if msg_id in self.tasks[eid]: | |
776 | self.tasks[eid].remove(msg_id) |
|
776 | self.tasks[eid].remove(msg_id) | |
777 | completed = header['date'] |
|
777 | completed = header['date'] | |
778 | started = md.get('started', None) |
|
778 | started = md.get('started', None) | |
779 | result = { |
|
779 | result = { | |
780 | 'result_header' : header, |
|
780 | 'result_header' : header, | |
781 | 'result_metadata': msg['metadata'], |
|
781 | 'result_metadata': msg['metadata'], | |
782 | 'result_content': msg['content'], |
|
782 | 'result_content': msg['content'], | |
783 | 'started' : started, |
|
783 | 'started' : started, | |
784 | 'completed' : completed, |
|
784 | 'completed' : completed, | |
785 | 'received' : datetime.now(), |
|
785 | 'received' : datetime.now(), | |
786 | 'engine_uuid': engine_uuid, |
|
786 | 'engine_uuid': engine_uuid, | |
787 | } |
|
787 | } | |
788 |
|
788 | |||
789 | result['result_buffers'] = msg['buffers'] |
|
789 | result['result_buffers'] = msg['buffers'] | |
790 | try: |
|
790 | try: | |
791 | self.db.update_record(msg_id, result) |
|
791 | self.db.update_record(msg_id, result) | |
792 | except Exception: |
|
792 | except Exception: | |
793 | self.log.error("DB Error saving task request %r", msg_id, exc_info=True) |
|
793 | self.log.error("DB Error saving task request %r", msg_id, exc_info=True) | |
794 |
|
794 | |||
795 | else: |
|
795 | else: | |
796 | self.log.debug("task::unknown task %r finished", msg_id) |
|
796 | self.log.debug("task::unknown task %r finished", msg_id) | |
797 |
|
797 | |||
798 | def save_task_destination(self, idents, msg): |
|
798 | def save_task_destination(self, idents, msg): | |
799 | try: |
|
799 | try: | |
800 | msg = self.session.unserialize(msg, content=True) |
|
800 | msg = self.session.unserialize(msg, content=True) | |
801 | except Exception: |
|
801 | except Exception: | |
802 | self.log.error("task::invalid task tracking message", exc_info=True) |
|
802 | self.log.error("task::invalid task tracking message", exc_info=True) | |
803 | return |
|
803 | return | |
804 | content = msg['content'] |
|
804 | content = msg['content'] | |
805 | # print (content) |
|
805 | # print (content) | |
806 | msg_id = content['msg_id'] |
|
806 | msg_id = content['msg_id'] | |
807 | engine_uuid = content['engine_id'] |
|
807 | engine_uuid = content['engine_id'] | |
808 | eid = self.by_ident[cast_bytes(engine_uuid)] |
|
808 | eid = self.by_ident[cast_bytes(engine_uuid)] | |
809 |
|
809 | |||
810 | self.log.info("task::task %r arrived on %r", msg_id, eid) |
|
810 | self.log.info("task::task %r arrived on %r", msg_id, eid) | |
811 | if msg_id in self.unassigned: |
|
811 | if msg_id in self.unassigned: | |
812 | self.unassigned.remove(msg_id) |
|
812 | self.unassigned.remove(msg_id) | |
813 | # else: |
|
813 | # else: | |
814 | # self.log.debug("task::task %r not listed as MIA?!"%(msg_id)) |
|
814 | # self.log.debug("task::task %r not listed as MIA?!"%(msg_id)) | |
815 |
|
815 | |||
816 | self.tasks[eid].append(msg_id) |
|
816 | self.tasks[eid].append(msg_id) | |
817 | # self.pending[msg_id][1].update(received=datetime.now(),engine=(eid,engine_uuid)) |
|
817 | # self.pending[msg_id][1].update(received=datetime.now(),engine=(eid,engine_uuid)) | |
818 | try: |
|
818 | try: | |
819 | self.db.update_record(msg_id, dict(engine_uuid=engine_uuid)) |
|
819 | self.db.update_record(msg_id, dict(engine_uuid=engine_uuid)) | |
820 | except Exception: |
|
820 | except Exception: | |
821 | self.log.error("DB Error saving task destination %r", msg_id, exc_info=True) |
|
821 | self.log.error("DB Error saving task destination %r", msg_id, exc_info=True) | |
822 |
|
822 | |||
823 |
|
823 | |||
824 | def mia_task_request(self, idents, msg): |
|
824 | def mia_task_request(self, idents, msg): | |
825 | raise NotImplementedError |
|
825 | raise NotImplementedError | |
826 | client_id = idents[0] |
|
826 | client_id = idents[0] | |
827 | # content = dict(mia=self.mia,status='ok') |
|
827 | # content = dict(mia=self.mia,status='ok') | |
828 | # self.session.send('mia_reply', content=content, idents=client_id) |
|
828 | # self.session.send('mia_reply', content=content, idents=client_id) | |
829 |
|
829 | |||
830 |
|
830 | |||
831 | #--------------------- IOPub Traffic ------------------------------ |
|
831 | #--------------------- IOPub Traffic ------------------------------ | |
832 |
|
832 | |||
833 | def save_iopub_message(self, topics, msg): |
|
833 | def save_iopub_message(self, topics, msg): | |
834 | """save an iopub message into the db""" |
|
834 | """save an iopub message into the db""" | |
835 | # print (topics) |
|
835 | # print (topics) | |
836 | try: |
|
836 | try: | |
837 | msg = self.session.unserialize(msg, content=True) |
|
837 | msg = self.session.unserialize(msg, content=True) | |
838 | except Exception: |
|
838 | except Exception: | |
839 | self.log.error("iopub::invalid IOPub message", exc_info=True) |
|
839 | self.log.error("iopub::invalid IOPub message", exc_info=True) | |
840 | return |
|
840 | return | |
841 |
|
841 | |||
842 | parent = msg['parent_header'] |
|
842 | parent = msg['parent_header'] | |
843 | if not parent: |
|
843 | if not parent: | |
844 | self.log.warn("iopub::IOPub message lacks parent: %r", msg) |
|
844 | self.log.warn("iopub::IOPub message lacks parent: %r", msg) | |
845 | return |
|
845 | return | |
846 | msg_id = parent['msg_id'] |
|
846 | msg_id = parent['msg_id'] | |
847 | msg_type = msg['header']['msg_type'] |
|
847 | msg_type = msg['header']['msg_type'] | |
848 | content = msg['content'] |
|
848 | content = msg['content'] | |
849 |
|
849 | |||
850 | # ensure msg_id is in db |
|
850 | # ensure msg_id is in db | |
851 | try: |
|
851 | try: | |
852 | rec = self.db.get_record(msg_id) |
|
852 | rec = self.db.get_record(msg_id) | |
853 | except KeyError: |
|
853 | except KeyError: | |
854 | rec = empty_record() |
|
854 | rec = empty_record() | |
855 | rec['msg_id'] = msg_id |
|
855 | rec['msg_id'] = msg_id | |
856 | self.db.add_record(msg_id, rec) |
|
856 | self.db.add_record(msg_id, rec) | |
857 | # stream |
|
857 | # stream | |
858 | d = {} |
|
858 | d = {} | |
859 | if msg_type == 'stream': |
|
859 | if msg_type == 'stream': | |
860 | name = content['name'] |
|
860 | name = content['name'] | |
861 | s = rec[name] or '' |
|
861 | s = rec[name] or '' | |
862 | d[name] = s + content['data'] |
|
862 | d[name] = s + content['data'] | |
863 |
|
863 | |||
864 | elif msg_type == 'pyerr': |
|
864 | elif msg_type == 'pyerr': | |
865 | d['pyerr'] = content |
|
865 | d['pyerr'] = content | |
866 | elif msg_type == 'pyin': |
|
866 | elif msg_type == 'pyin': | |
867 | d['pyin'] = content['code'] |
|
867 | d['pyin'] = content['code'] | |
868 | elif msg_type in ('display_data', 'pyout'): |
|
868 | elif msg_type in ('display_data', 'pyout'): | |
869 | d[msg_type] = content |
|
869 | d[msg_type] = content | |
870 | elif msg_type == 'status': |
|
870 | elif msg_type == 'status': | |
871 | pass |
|
871 | pass | |
872 | elif msg_type == 'data_pub': |
|
872 | elif msg_type == 'data_pub': | |
873 | self.log.info("ignored data_pub message for %s" % msg_id) |
|
873 | self.log.info("ignored data_pub message for %s" % msg_id) | |
874 | else: |
|
874 | else: | |
875 | self.log.warn("unhandled iopub msg_type: %r", msg_type) |
|
875 | self.log.warn("unhandled iopub msg_type: %r", msg_type) | |
876 |
|
876 | |||
877 | if not d: |
|
877 | if not d: | |
878 | return |
|
878 | return | |
879 |
|
879 | |||
880 | try: |
|
880 | try: | |
881 | self.db.update_record(msg_id, d) |
|
881 | self.db.update_record(msg_id, d) | |
882 | except Exception: |
|
882 | except Exception: | |
883 | self.log.error("DB Error saving iopub message %r", msg_id, exc_info=True) |
|
883 | self.log.error("DB Error saving iopub message %r", msg_id, exc_info=True) | |
884 |
|
884 | |||
885 |
|
885 | |||
886 |
|
886 | |||
887 | #------------------------------------------------------------------------- |
|
887 | #------------------------------------------------------------------------- | |
888 | # Registration requests |
|
888 | # Registration requests | |
889 | #------------------------------------------------------------------------- |
|
889 | #------------------------------------------------------------------------- | |
890 |
|
890 | |||
891 | def connection_request(self, client_id, msg): |
|
891 | def connection_request(self, client_id, msg): | |
892 | """Reply with connection addresses for clients.""" |
|
892 | """Reply with connection addresses for clients.""" | |
893 | self.log.info("client::client %r connected", client_id) |
|
893 | self.log.info("client::client %r connected", client_id) | |
894 | content = dict(status='ok') |
|
894 | content = dict(status='ok') | |
895 | jsonable = {} |
|
895 | jsonable = {} | |
896 | for k,v in iteritems(self.keytable): |
|
896 | for k,v in iteritems(self.keytable): | |
897 | if v not in self.dead_engines: |
|
897 | if v not in self.dead_engines: | |
898 | jsonable[str(k)] = v |
|
898 | jsonable[str(k)] = v | |
899 | content['engines'] = jsonable |
|
899 | content['engines'] = jsonable | |
900 | self.session.send(self.query, 'connection_reply', content, parent=msg, ident=client_id) |
|
900 | self.session.send(self.query, 'connection_reply', content, parent=msg, ident=client_id) | |
901 |
|
901 | |||
902 | def register_engine(self, reg, msg): |
|
902 | def register_engine(self, reg, msg): | |
903 | """Register a new engine.""" |
|
903 | """Register a new engine.""" | |
904 | content = msg['content'] |
|
904 | content = msg['content'] | |
905 | try: |
|
905 | try: | |
906 | uuid = content['uuid'] |
|
906 | uuid = content['uuid'] | |
907 | except KeyError: |
|
907 | except KeyError: | |
908 | self.log.error("registration::queue not specified", exc_info=True) |
|
908 | self.log.error("registration::queue not specified", exc_info=True) | |
909 | return |
|
909 | return | |
910 |
|
910 | |||
911 | eid = self._next_id |
|
911 | eid = self._next_id | |
912 |
|
912 | |||
913 | self.log.debug("registration::register_engine(%i, %r)", eid, uuid) |
|
913 | self.log.debug("registration::register_engine(%i, %r)", eid, uuid) | |
914 |
|
914 | |||
915 | content = dict(id=eid,status='ok',hb_period=self.heartmonitor.period) |
|
915 | content = dict(id=eid,status='ok',hb_period=self.heartmonitor.period) | |
916 | # check if requesting available IDs: |
|
916 | # check if requesting available IDs: | |
917 | if cast_bytes(uuid) in self.by_ident: |
|
917 | if cast_bytes(uuid) in self.by_ident: | |
918 | try: |
|
918 | try: | |
919 | raise KeyError("uuid %r in use" % uuid) |
|
919 | raise KeyError("uuid %r in use" % uuid) | |
920 | except: |
|
920 | except: | |
921 | content = error.wrap_exception() |
|
921 | content = error.wrap_exception() | |
922 | self.log.error("uuid %r in use", uuid, exc_info=True) |
|
922 | self.log.error("uuid %r in use", uuid, exc_info=True) | |
923 | else: |
|
923 | else: | |
924 | for h, ec in iteritems(self.incoming_registrations): |
|
924 | for h, ec in iteritems(self.incoming_registrations): | |
925 | if uuid == h: |
|
925 | if uuid == h: | |
926 | try: |
|
926 | try: | |
927 | raise KeyError("heart_id %r in use" % uuid) |
|
927 | raise KeyError("heart_id %r in use" % uuid) | |
928 | except: |
|
928 | except: | |
929 | self.log.error("heart_id %r in use", uuid, exc_info=True) |
|
929 | self.log.error("heart_id %r in use", uuid, exc_info=True) | |
930 | content = error.wrap_exception() |
|
930 | content = error.wrap_exception() | |
931 | break |
|
931 | break | |
932 | elif uuid == ec.uuid: |
|
932 | elif uuid == ec.uuid: | |
933 | try: |
|
933 | try: | |
934 | raise KeyError("uuid %r in use" % uuid) |
|
934 | raise KeyError("uuid %r in use" % uuid) | |
935 | except: |
|
935 | except: | |
936 | self.log.error("uuid %r in use", uuid, exc_info=True) |
|
936 | self.log.error("uuid %r in use", uuid, exc_info=True) | |
937 | content = error.wrap_exception() |
|
937 | content = error.wrap_exception() | |
938 | break |
|
938 | break | |
939 |
|
939 | |||
940 | msg = self.session.send(self.query, "registration_reply", |
|
940 | msg = self.session.send(self.query, "registration_reply", | |
941 | content=content, |
|
941 | content=content, | |
942 | ident=reg) |
|
942 | ident=reg) | |
943 |
|
943 | |||
944 | heart = cast_bytes(uuid) |
|
944 | heart = cast_bytes(uuid) | |
945 |
|
945 | |||
946 | if content['status'] == 'ok': |
|
946 | if content['status'] == 'ok': | |
947 | if heart in self.heartmonitor.hearts: |
|
947 | if heart in self.heartmonitor.hearts: | |
948 | # already beating |
|
948 | # already beating | |
949 | self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid) |
|
949 | self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid) | |
950 | self.finish_registration(heart) |
|
950 | self.finish_registration(heart) | |
951 | else: |
|
951 | else: | |
952 | purge = lambda : self._purge_stalled_registration(heart) |
|
952 | purge = lambda : self._purge_stalled_registration(heart) | |
953 | dc = ioloop.DelayedCallback(purge, self.registration_timeout, self.loop) |
|
953 | dc = ioloop.DelayedCallback(purge, self.registration_timeout, self.loop) | |
954 | dc.start() |
|
954 | dc.start() | |
955 | self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid,stallback=dc) |
|
955 | self.incoming_registrations[heart] = EngineConnector(id=eid,uuid=uuid,stallback=dc) | |
956 | else: |
|
956 | else: | |
957 | self.log.error("registration::registration %i failed: %r", eid, content['evalue']) |
|
957 | self.log.error("registration::registration %i failed: %r", eid, content['evalue']) | |
958 |
|
958 | |||
959 | return eid |
|
959 | return eid | |
960 |
|
960 | |||
961 | def unregister_engine(self, ident, msg): |
|
961 | def unregister_engine(self, ident, msg): | |
962 | """Unregister an engine that explicitly requested to leave.""" |
|
962 | """Unregister an engine that explicitly requested to leave.""" | |
963 | try: |
|
963 | try: | |
964 | eid = msg['content']['id'] |
|
964 | eid = msg['content']['id'] | |
965 | except: |
|
965 | except: | |
966 | self.log.error("registration::bad engine id for unregistration: %r", ident, exc_info=True) |
|
966 | self.log.error("registration::bad engine id for unregistration: %r", ident, exc_info=True) | |
967 | return |
|
967 | return | |
968 | self.log.info("registration::unregister_engine(%r)", eid) |
|
968 | self.log.info("registration::unregister_engine(%r)", eid) | |
969 | # print (eid) |
|
969 | # print (eid) | |
970 | uuid = self.keytable[eid] |
|
970 | uuid = self.keytable[eid] | |
971 | content=dict(id=eid, uuid=uuid) |
|
971 | content=dict(id=eid, uuid=uuid) | |
972 | self.dead_engines.add(uuid) |
|
972 | self.dead_engines.add(uuid) | |
973 | # self.ids.remove(eid) |
|
973 | # self.ids.remove(eid) | |
974 | # uuid = self.keytable.pop(eid) |
|
974 | # uuid = self.keytable.pop(eid) | |
975 | # |
|
975 | # | |
976 | # ec = self.engines.pop(eid) |
|
976 | # ec = self.engines.pop(eid) | |
977 | # self.hearts.pop(ec.heartbeat) |
|
977 | # self.hearts.pop(ec.heartbeat) | |
978 | # self.by_ident.pop(ec.queue) |
|
978 | # self.by_ident.pop(ec.queue) | |
979 | # self.completed.pop(eid) |
|
979 | # self.completed.pop(eid) | |
980 | handleit = lambda : self._handle_stranded_msgs(eid, uuid) |
|
980 | handleit = lambda : self._handle_stranded_msgs(eid, uuid) | |
981 | dc = ioloop.DelayedCallback(handleit, self.registration_timeout, self.loop) |
|
981 | dc = ioloop.DelayedCallback(handleit, self.registration_timeout, self.loop) | |
982 | dc.start() |
|
982 | dc.start() | |
983 | ############## TODO: HANDLE IT ################ |
|
983 | ############## TODO: HANDLE IT ################ | |
984 |
|
984 | |||
985 | self._save_engine_state() |
|
985 | self._save_engine_state() | |
986 |
|
986 | |||
987 | if self.notifier: |
|
987 | if self.notifier: | |
988 | self.session.send(self.notifier, "unregistration_notification", content=content) |
|
988 | self.session.send(self.notifier, "unregistration_notification", content=content) | |
989 |
|
989 | |||
990 | def _handle_stranded_msgs(self, eid, uuid): |
|
990 | def _handle_stranded_msgs(self, eid, uuid): | |
991 | """Handle messages known to be on an engine when the engine unregisters. |
|
991 | """Handle messages known to be on an engine when the engine unregisters. | |
992 |
|
992 | |||
993 | It is possible that this will fire prematurely - that is, an engine will |
|
993 | It is possible that this will fire prematurely - that is, an engine will | |
994 | go down after completing a result, and the client will be notified |
|
994 | go down after completing a result, and the client will be notified | |
995 | that the result failed and later receive the actual result. |
|
995 | that the result failed and later receive the actual result. | |
996 | """ |
|
996 | """ | |
997 |
|
997 | |||
998 | outstanding = self.queues[eid] |
|
998 | outstanding = self.queues[eid] | |
999 |
|
999 | |||
1000 | for msg_id in outstanding: |
|
1000 | for msg_id in outstanding: | |
1001 | self.pending.remove(msg_id) |
|
1001 | self.pending.remove(msg_id) | |
1002 | self.all_completed.add(msg_id) |
|
1002 | self.all_completed.add(msg_id) | |
1003 | try: |
|
1003 | try: | |
1004 | raise error.EngineError("Engine %r died while running task %r" % (eid, msg_id)) |
|
1004 | raise error.EngineError("Engine %r died while running task %r" % (eid, msg_id)) | |
1005 | except: |
|
1005 | except: | |
1006 | content = error.wrap_exception() |
|
1006 | content = error.wrap_exception() | |
1007 | # build a fake header: |
|
1007 | # build a fake header: | |
1008 | header = {} |
|
1008 | header = {} | |
1009 | header['engine'] = uuid |
|
1009 | header['engine'] = uuid | |
1010 | header['date'] = datetime.now() |
|
1010 | header['date'] = datetime.now() | |
1011 | rec = dict(result_content=content, result_header=header, result_buffers=[]) |
|
1011 | rec = dict(result_content=content, result_header=header, result_buffers=[]) | |
1012 | rec['completed'] = header['date'] |
|
1012 | rec['completed'] = header['date'] | |
1013 | rec['engine_uuid'] = uuid |
|
1013 | rec['engine_uuid'] = uuid | |
1014 | try: |
|
1014 | try: | |
1015 | self.db.update_record(msg_id, rec) |
|
1015 | self.db.update_record(msg_id, rec) | |
1016 | except Exception: |
|
1016 | except Exception: | |
1017 | self.log.error("DB Error handling stranded msg %r", msg_id, exc_info=True) |
|
1017 | self.log.error("DB Error handling stranded msg %r", msg_id, exc_info=True) | |
1018 |
|
1018 | |||
1019 |
|
1019 | |||
1020 | def finish_registration(self, heart): |
|
1020 | def finish_registration(self, heart): | |
1021 | """Second half of engine registration, called after our HeartMonitor |
|
1021 | """Second half of engine registration, called after our HeartMonitor | |
1022 | has received a beat from the Engine's Heart.""" |
|
1022 | has received a beat from the Engine's Heart.""" | |
1023 | try: |
|
1023 | try: | |
1024 | ec = self.incoming_registrations.pop(heart) |
|
1024 | ec = self.incoming_registrations.pop(heart) | |
1025 | except KeyError: |
|
1025 | except KeyError: | |
1026 | self.log.error("registration::tried to finish nonexistant registration", exc_info=True) |
|
1026 | self.log.error("registration::tried to finish nonexistant registration", exc_info=True) | |
1027 | return |
|
1027 | return | |
1028 | self.log.info("registration::finished registering engine %i:%s", ec.id, ec.uuid) |
|
1028 | self.log.info("registration::finished registering engine %i:%s", ec.id, ec.uuid) | |
1029 | if ec.stallback is not None: |
|
1029 | if ec.stallback is not None: | |
1030 | ec.stallback.stop() |
|
1030 | ec.stallback.stop() | |
1031 | eid = ec.id |
|
1031 | eid = ec.id | |
1032 | self.ids.add(eid) |
|
1032 | self.ids.add(eid) | |
1033 | self.keytable[eid] = ec.uuid |
|
1033 | self.keytable[eid] = ec.uuid | |
1034 | self.engines[eid] = ec |
|
1034 | self.engines[eid] = ec | |
1035 | self.by_ident[cast_bytes(ec.uuid)] = ec.id |
|
1035 | self.by_ident[cast_bytes(ec.uuid)] = ec.id | |
1036 | self.queues[eid] = list() |
|
1036 | self.queues[eid] = list() | |
1037 | self.tasks[eid] = list() |
|
1037 | self.tasks[eid] = list() | |
1038 | self.completed[eid] = list() |
|
1038 | self.completed[eid] = list() | |
1039 | self.hearts[heart] = eid |
|
1039 | self.hearts[heart] = eid | |
1040 | content = dict(id=eid, uuid=self.engines[eid].uuid) |
|
1040 | content = dict(id=eid, uuid=self.engines[eid].uuid) | |
1041 | if self.notifier: |
|
1041 | if self.notifier: | |
1042 | self.session.send(self.notifier, "registration_notification", content=content) |
|
1042 | self.session.send(self.notifier, "registration_notification", content=content) | |
1043 | self.log.info("engine::Engine Connected: %i", eid) |
|
1043 | self.log.info("engine::Engine Connected: %i", eid) | |
1044 |
|
1044 | |||
1045 | self._save_engine_state() |
|
1045 | self._save_engine_state() | |
1046 |
|
1046 | |||
1047 | def _purge_stalled_registration(self, heart): |
|
1047 | def _purge_stalled_registration(self, heart): | |
1048 | if heart in self.incoming_registrations: |
|
1048 | if heart in self.incoming_registrations: | |
1049 | ec = self.incoming_registrations.pop(heart) |
|
1049 | ec = self.incoming_registrations.pop(heart) | |
1050 | self.log.info("registration::purging stalled registration: %i", ec.id) |
|
1050 | self.log.info("registration::purging stalled registration: %i", ec.id) | |
1051 | else: |
|
1051 | else: | |
1052 | pass |
|
1052 | pass | |
1053 |
|
1053 | |||
1054 | #------------------------------------------------------------------------- |
|
1054 | #------------------------------------------------------------------------- | |
1055 | # Engine State |
|
1055 | # Engine State | |
1056 | #------------------------------------------------------------------------- |
|
1056 | #------------------------------------------------------------------------- | |
1057 |
|
1057 | |||
1058 |
|
1058 | |||
1059 | def _cleanup_engine_state_file(self): |
|
1059 | def _cleanup_engine_state_file(self): | |
1060 | """cleanup engine state mapping""" |
|
1060 | """cleanup engine state mapping""" | |
1061 |
|
1061 | |||
1062 | if os.path.exists(self.engine_state_file): |
|
1062 | if os.path.exists(self.engine_state_file): | |
1063 | self.log.debug("cleaning up engine state: %s", self.engine_state_file) |
|
1063 | self.log.debug("cleaning up engine state: %s", self.engine_state_file) | |
1064 | try: |
|
1064 | try: | |
1065 | os.remove(self.engine_state_file) |
|
1065 | os.remove(self.engine_state_file) | |
1066 | except IOError: |
|
1066 | except IOError: | |
1067 | self.log.error("Couldn't cleanup file: %s", self.engine_state_file, exc_info=True) |
|
1067 | self.log.error("Couldn't cleanup file: %s", self.engine_state_file, exc_info=True) | |
1068 |
|
1068 | |||
1069 |
|
1069 | |||
1070 | def _save_engine_state(self): |
|
1070 | def _save_engine_state(self): | |
1071 | """save engine mapping to JSON file""" |
|
1071 | """save engine mapping to JSON file""" | |
1072 | if not self.engine_state_file: |
|
1072 | if not self.engine_state_file: | |
1073 | return |
|
1073 | return | |
1074 | self.log.debug("save engine state to %s" % self.engine_state_file) |
|
1074 | self.log.debug("save engine state to %s" % self.engine_state_file) | |
1075 | state = {} |
|
1075 | state = {} | |
1076 | engines = {} |
|
1076 | engines = {} | |
1077 | for eid, ec in iteritems(self.engines): |
|
1077 | for eid, ec in iteritems(self.engines): | |
1078 | if ec.uuid not in self.dead_engines: |
|
1078 | if ec.uuid not in self.dead_engines: | |
1079 | engines[eid] = ec.uuid |
|
1079 | engines[eid] = ec.uuid | |
1080 |
|
1080 | |||
1081 | state['engines'] = engines |
|
1081 | state['engines'] = engines | |
1082 |
|
1082 | |||
1083 | state['next_id'] = self._idcounter |
|
1083 | state['next_id'] = self._idcounter | |
1084 |
|
1084 | |||
1085 | with open(self.engine_state_file, 'w') as f: |
|
1085 | with open(self.engine_state_file, 'w') as f: | |
1086 | json.dump(state, f) |
|
1086 | json.dump(state, f) | |
1087 |
|
1087 | |||
1088 |
|
1088 | |||
1089 | def _load_engine_state(self): |
|
1089 | def _load_engine_state(self): | |
1090 | """load engine mapping from JSON file""" |
|
1090 | """load engine mapping from JSON file""" | |
1091 | if not os.path.exists(self.engine_state_file): |
|
1091 | if not os.path.exists(self.engine_state_file): | |
1092 | return |
|
1092 | return | |
1093 |
|
1093 | |||
1094 | self.log.info("loading engine state from %s" % self.engine_state_file) |
|
1094 | self.log.info("loading engine state from %s" % self.engine_state_file) | |
1095 |
|
1095 | |||
1096 | with open(self.engine_state_file) as f: |
|
1096 | with open(self.engine_state_file) as f: | |
1097 | state = json.load(f) |
|
1097 | state = json.load(f) | |
1098 |
|
1098 | |||
1099 | save_notifier = self.notifier |
|
1099 | save_notifier = self.notifier | |
1100 | self.notifier = None |
|
1100 | self.notifier = None | |
1101 | for eid, uuid in iteritems(state['engines']): |
|
1101 | for eid, uuid in iteritems(state['engines']): | |
1102 | heart = uuid.encode('ascii') |
|
1102 | heart = uuid.encode('ascii') | |
1103 | # start with this heart as current and beating: |
|
1103 | # start with this heart as current and beating: | |
1104 | self.heartmonitor.responses.add(heart) |
|
1104 | self.heartmonitor.responses.add(heart) | |
1105 | self.heartmonitor.hearts.add(heart) |
|
1105 | self.heartmonitor.hearts.add(heart) | |
1106 |
|
1106 | |||
1107 | self.incoming_registrations[heart] = EngineConnector(id=int(eid), uuid=uuid) |
|
1107 | self.incoming_registrations[heart] = EngineConnector(id=int(eid), uuid=uuid) | |
1108 | self.finish_registration(heart) |
|
1108 | self.finish_registration(heart) | |
1109 |
|
1109 | |||
1110 | self.notifier = save_notifier |
|
1110 | self.notifier = save_notifier | |
1111 |
|
1111 | |||
1112 | self._idcounter = state['next_id'] |
|
1112 | self._idcounter = state['next_id'] | |
1113 |
|
1113 | |||
1114 | #------------------------------------------------------------------------- |
|
1114 | #------------------------------------------------------------------------- | |
1115 | # Client Requests |
|
1115 | # Client Requests | |
1116 | #------------------------------------------------------------------------- |
|
1116 | #------------------------------------------------------------------------- | |
1117 |
|
1117 | |||
1118 | def shutdown_request(self, client_id, msg): |
|
1118 | def shutdown_request(self, client_id, msg): | |
1119 | """handle shutdown request.""" |
|
1119 | """handle shutdown request.""" | |
1120 | self.session.send(self.query, 'shutdown_reply', content={'status': 'ok'}, ident=client_id) |
|
1120 | self.session.send(self.query, 'shutdown_reply', content={'status': 'ok'}, ident=client_id) | |
1121 | # also notify other clients of shutdown |
|
1121 | # also notify other clients of shutdown | |
1122 | self.session.send(self.notifier, 'shutdown_notice', content={'status': 'ok'}) |
|
1122 | self.session.send(self.notifier, 'shutdown_notice', content={'status': 'ok'}) | |
1123 | dc = ioloop.DelayedCallback(lambda : self._shutdown(), 1000, self.loop) |
|
1123 | dc = ioloop.DelayedCallback(lambda : self._shutdown(), 1000, self.loop) | |
1124 | dc.start() |
|
1124 | dc.start() | |
1125 |
|
1125 | |||
1126 | def _shutdown(self): |
|
1126 | def _shutdown(self): | |
1127 | self.log.info("hub::hub shutting down.") |
|
1127 | self.log.info("hub::hub shutting down.") | |
1128 | time.sleep(0.1) |
|
1128 | time.sleep(0.1) | |
1129 | sys.exit(0) |
|
1129 | sys.exit(0) | |
1130 |
|
1130 | |||
1131 |
|
1131 | |||
1132 | def check_load(self, client_id, msg): |
|
1132 | def check_load(self, client_id, msg): | |
1133 | content = msg['content'] |
|
1133 | content = msg['content'] | |
1134 | try: |
|
1134 | try: | |
1135 | targets = content['targets'] |
|
1135 | targets = content['targets'] | |
1136 | targets = self._validate_targets(targets) |
|
1136 | targets = self._validate_targets(targets) | |
1137 | except: |
|
1137 | except: | |
1138 | content = error.wrap_exception() |
|
1138 | content = error.wrap_exception() | |
1139 | self.session.send(self.query, "hub_error", |
|
1139 | self.session.send(self.query, "hub_error", | |
1140 | content=content, ident=client_id) |
|
1140 | content=content, ident=client_id) | |
1141 | return |
|
1141 | return | |
1142 |
|
1142 | |||
1143 | content = dict(status='ok') |
|
1143 | content = dict(status='ok') | |
1144 | # loads = {} |
|
1144 | # loads = {} | |
1145 | for t in targets: |
|
1145 | for t in targets: | |
1146 | content[bytes(t)] = len(self.queues[t])+len(self.tasks[t]) |
|
1146 | content[bytes(t)] = len(self.queues[t])+len(self.tasks[t]) | |
1147 | self.session.send(self.query, "load_reply", content=content, ident=client_id) |
|
1147 | self.session.send(self.query, "load_reply", content=content, ident=client_id) | |
1148 |
|
1148 | |||
1149 |
|
1149 | |||
1150 | def queue_status(self, client_id, msg): |
|
1150 | def queue_status(self, client_id, msg): | |
1151 | """Return the Queue status of one or more targets. |
|
1151 | """Return the Queue status of one or more targets. | |
1152 | if verbose: return the msg_ids |
|
1152 | ||
1153 |
else |
|
1153 | If verbose, return the msg_ids, else return len of each type. | |
1154 | keys: queue (pending MUX jobs) |
|
1154 | ||
1155 | tasks (pending Task jobs) |
|
1155 | Keys: | |
1156 | completed (finished jobs from both queues)""" |
|
1156 | ||
|
1157 | * queue (pending MUX jobs) | |||
|
1158 | * tasks (pending Task jobs) | |||
|
1159 | * completed (finished jobs from both queues) | |||
|
1160 | """ | |||
1157 | content = msg['content'] |
|
1161 | content = msg['content'] | |
1158 | targets = content['targets'] |
|
1162 | targets = content['targets'] | |
1159 | try: |
|
1163 | try: | |
1160 | targets = self._validate_targets(targets) |
|
1164 | targets = self._validate_targets(targets) | |
1161 | except: |
|
1165 | except: | |
1162 | content = error.wrap_exception() |
|
1166 | content = error.wrap_exception() | |
1163 | self.session.send(self.query, "hub_error", |
|
1167 | self.session.send(self.query, "hub_error", | |
1164 | content=content, ident=client_id) |
|
1168 | content=content, ident=client_id) | |
1165 | return |
|
1169 | return | |
1166 | verbose = content.get('verbose', False) |
|
1170 | verbose = content.get('verbose', False) | |
1167 | content = dict(status='ok') |
|
1171 | content = dict(status='ok') | |
1168 | for t in targets: |
|
1172 | for t in targets: | |
1169 | queue = self.queues[t] |
|
1173 | queue = self.queues[t] | |
1170 | completed = self.completed[t] |
|
1174 | completed = self.completed[t] | |
1171 | tasks = self.tasks[t] |
|
1175 | tasks = self.tasks[t] | |
1172 | if not verbose: |
|
1176 | if not verbose: | |
1173 | queue = len(queue) |
|
1177 | queue = len(queue) | |
1174 | completed = len(completed) |
|
1178 | completed = len(completed) | |
1175 | tasks = len(tasks) |
|
1179 | tasks = len(tasks) | |
1176 | content[str(t)] = {'queue': queue, 'completed': completed , 'tasks': tasks} |
|
1180 | content[str(t)] = {'queue': queue, 'completed': completed , 'tasks': tasks} | |
1177 | content['unassigned'] = list(self.unassigned) if verbose else len(self.unassigned) |
|
1181 | content['unassigned'] = list(self.unassigned) if verbose else len(self.unassigned) | |
1178 | # print (content) |
|
1182 | # print (content) | |
1179 | self.session.send(self.query, "queue_reply", content=content, ident=client_id) |
|
1183 | self.session.send(self.query, "queue_reply", content=content, ident=client_id) | |
1180 |
|
1184 | |||
1181 | def purge_results(self, client_id, msg): |
|
1185 | def purge_results(self, client_id, msg): | |
1182 | """Purge results from memory. This method is more valuable before we move |
|
1186 | """Purge results from memory. This method is more valuable before we move | |
1183 | to a DB based message storage mechanism.""" |
|
1187 | to a DB based message storage mechanism.""" | |
1184 | content = msg['content'] |
|
1188 | content = msg['content'] | |
1185 | self.log.info("Dropping records with %s", content) |
|
1189 | self.log.info("Dropping records with %s", content) | |
1186 | msg_ids = content.get('msg_ids', []) |
|
1190 | msg_ids = content.get('msg_ids', []) | |
1187 | reply = dict(status='ok') |
|
1191 | reply = dict(status='ok') | |
1188 | if msg_ids == 'all': |
|
1192 | if msg_ids == 'all': | |
1189 | try: |
|
1193 | try: | |
1190 | self.db.drop_matching_records(dict(completed={'$ne':None})) |
|
1194 | self.db.drop_matching_records(dict(completed={'$ne':None})) | |
1191 | except Exception: |
|
1195 | except Exception: | |
1192 | reply = error.wrap_exception() |
|
1196 | reply = error.wrap_exception() | |
1193 | else: |
|
1197 | else: | |
1194 | pending = [m for m in msg_ids if (m in self.pending)] |
|
1198 | pending = [m for m in msg_ids if (m in self.pending)] | |
1195 | if pending: |
|
1199 | if pending: | |
1196 | try: |
|
1200 | try: | |
1197 | raise IndexError("msg pending: %r" % pending[0]) |
|
1201 | raise IndexError("msg pending: %r" % pending[0]) | |
1198 | except: |
|
1202 | except: | |
1199 | reply = error.wrap_exception() |
|
1203 | reply = error.wrap_exception() | |
1200 | else: |
|
1204 | else: | |
1201 | try: |
|
1205 | try: | |
1202 | self.db.drop_matching_records(dict(msg_id={'$in':msg_ids})) |
|
1206 | self.db.drop_matching_records(dict(msg_id={'$in':msg_ids})) | |
1203 | except Exception: |
|
1207 | except Exception: | |
1204 | reply = error.wrap_exception() |
|
1208 | reply = error.wrap_exception() | |
1205 |
|
1209 | |||
1206 | if reply['status'] == 'ok': |
|
1210 | if reply['status'] == 'ok': | |
1207 | eids = content.get('engine_ids', []) |
|
1211 | eids = content.get('engine_ids', []) | |
1208 | for eid in eids: |
|
1212 | for eid in eids: | |
1209 | if eid not in self.engines: |
|
1213 | if eid not in self.engines: | |
1210 | try: |
|
1214 | try: | |
1211 | raise IndexError("No such engine: %i" % eid) |
|
1215 | raise IndexError("No such engine: %i" % eid) | |
1212 | except: |
|
1216 | except: | |
1213 | reply = error.wrap_exception() |
|
1217 | reply = error.wrap_exception() | |
1214 | break |
|
1218 | break | |
1215 | uid = self.engines[eid].uuid |
|
1219 | uid = self.engines[eid].uuid | |
1216 | try: |
|
1220 | try: | |
1217 | self.db.drop_matching_records(dict(engine_uuid=uid, completed={'$ne':None})) |
|
1221 | self.db.drop_matching_records(dict(engine_uuid=uid, completed={'$ne':None})) | |
1218 | except Exception: |
|
1222 | except Exception: | |
1219 | reply = error.wrap_exception() |
|
1223 | reply = error.wrap_exception() | |
1220 | break |
|
1224 | break | |
1221 |
|
1225 | |||
1222 | self.session.send(self.query, 'purge_reply', content=reply, ident=client_id) |
|
1226 | self.session.send(self.query, 'purge_reply', content=reply, ident=client_id) | |
1223 |
|
1227 | |||
1224 | def resubmit_task(self, client_id, msg): |
|
1228 | def resubmit_task(self, client_id, msg): | |
1225 | """Resubmit one or more tasks.""" |
|
1229 | """Resubmit one or more tasks.""" | |
1226 | def finish(reply): |
|
1230 | def finish(reply): | |
1227 | self.session.send(self.query, 'resubmit_reply', content=reply, ident=client_id) |
|
1231 | self.session.send(self.query, 'resubmit_reply', content=reply, ident=client_id) | |
1228 |
|
1232 | |||
1229 | content = msg['content'] |
|
1233 | content = msg['content'] | |
1230 | msg_ids = content['msg_ids'] |
|
1234 | msg_ids = content['msg_ids'] | |
1231 | reply = dict(status='ok') |
|
1235 | reply = dict(status='ok') | |
1232 | try: |
|
1236 | try: | |
1233 | records = self.db.find_records({'msg_id' : {'$in' : msg_ids}}, keys=[ |
|
1237 | records = self.db.find_records({'msg_id' : {'$in' : msg_ids}}, keys=[ | |
1234 | 'header', 'content', 'buffers']) |
|
1238 | 'header', 'content', 'buffers']) | |
1235 | except Exception: |
|
1239 | except Exception: | |
1236 | self.log.error('db::db error finding tasks to resubmit', exc_info=True) |
|
1240 | self.log.error('db::db error finding tasks to resubmit', exc_info=True) | |
1237 | return finish(error.wrap_exception()) |
|
1241 | return finish(error.wrap_exception()) | |
1238 |
|
1242 | |||
1239 | # validate msg_ids |
|
1243 | # validate msg_ids | |
1240 | found_ids = [ rec['msg_id'] for rec in records ] |
|
1244 | found_ids = [ rec['msg_id'] for rec in records ] | |
1241 | pending_ids = [ msg_id for msg_id in found_ids if msg_id in self.pending ] |
|
1245 | pending_ids = [ msg_id for msg_id in found_ids if msg_id in self.pending ] | |
1242 | if len(records) > len(msg_ids): |
|
1246 | if len(records) > len(msg_ids): | |
1243 | try: |
|
1247 | try: | |
1244 | raise RuntimeError("DB appears to be in an inconsistent state." |
|
1248 | raise RuntimeError("DB appears to be in an inconsistent state." | |
1245 | "More matching records were found than should exist") |
|
1249 | "More matching records were found than should exist") | |
1246 | except Exception: |
|
1250 | except Exception: | |
1247 | return finish(error.wrap_exception()) |
|
1251 | return finish(error.wrap_exception()) | |
1248 | elif len(records) < len(msg_ids): |
|
1252 | elif len(records) < len(msg_ids): | |
1249 | missing = [ m for m in msg_ids if m not in found_ids ] |
|
1253 | missing = [ m for m in msg_ids if m not in found_ids ] | |
1250 | try: |
|
1254 | try: | |
1251 | raise KeyError("No such msg(s): %r" % missing) |
|
1255 | raise KeyError("No such msg(s): %r" % missing) | |
1252 | except KeyError: |
|
1256 | except KeyError: | |
1253 | return finish(error.wrap_exception()) |
|
1257 | return finish(error.wrap_exception()) | |
1254 | elif pending_ids: |
|
1258 | elif pending_ids: | |
1255 | pass |
|
1259 | pass | |
1256 | # no need to raise on resubmit of pending task, now that we |
|
1260 | # no need to raise on resubmit of pending task, now that we | |
1257 | # resubmit under new ID, but do we want to raise anyway? |
|
1261 | # resubmit under new ID, but do we want to raise anyway? | |
1258 | # msg_id = invalid_ids[0] |
|
1262 | # msg_id = invalid_ids[0] | |
1259 | # try: |
|
1263 | # try: | |
1260 | # raise ValueError("Task(s) %r appears to be inflight" % ) |
|
1264 | # raise ValueError("Task(s) %r appears to be inflight" % ) | |
1261 | # except Exception: |
|
1265 | # except Exception: | |
1262 | # return finish(error.wrap_exception()) |
|
1266 | # return finish(error.wrap_exception()) | |
1263 |
|
1267 | |||
1264 | # mapping of original IDs to resubmitted IDs |
|
1268 | # mapping of original IDs to resubmitted IDs | |
1265 | resubmitted = {} |
|
1269 | resubmitted = {} | |
1266 |
|
1270 | |||
1267 | # send the messages |
|
1271 | # send the messages | |
1268 | for rec in records: |
|
1272 | for rec in records: | |
1269 | header = rec['header'] |
|
1273 | header = rec['header'] | |
1270 | msg = self.session.msg(header['msg_type'], parent=header) |
|
1274 | msg = self.session.msg(header['msg_type'], parent=header) | |
1271 | msg_id = msg['msg_id'] |
|
1275 | msg_id = msg['msg_id'] | |
1272 | msg['content'] = rec['content'] |
|
1276 | msg['content'] = rec['content'] | |
1273 |
|
1277 | |||
1274 | # use the old header, but update msg_id and timestamp |
|
1278 | # use the old header, but update msg_id and timestamp | |
1275 | fresh = msg['header'] |
|
1279 | fresh = msg['header'] | |
1276 | header['msg_id'] = fresh['msg_id'] |
|
1280 | header['msg_id'] = fresh['msg_id'] | |
1277 | header['date'] = fresh['date'] |
|
1281 | header['date'] = fresh['date'] | |
1278 | msg['header'] = header |
|
1282 | msg['header'] = header | |
1279 |
|
1283 | |||
1280 | self.session.send(self.resubmit, msg, buffers=rec['buffers']) |
|
1284 | self.session.send(self.resubmit, msg, buffers=rec['buffers']) | |
1281 |
|
1285 | |||
1282 | resubmitted[rec['msg_id']] = msg_id |
|
1286 | resubmitted[rec['msg_id']] = msg_id | |
1283 | self.pending.add(msg_id) |
|
1287 | self.pending.add(msg_id) | |
1284 | msg['buffers'] = rec['buffers'] |
|
1288 | msg['buffers'] = rec['buffers'] | |
1285 | try: |
|
1289 | try: | |
1286 | self.db.add_record(msg_id, init_record(msg)) |
|
1290 | self.db.add_record(msg_id, init_record(msg)) | |
1287 | except Exception: |
|
1291 | except Exception: | |
1288 | self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True) |
|
1292 | self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True) | |
1289 | return finish(error.wrap_exception()) |
|
1293 | return finish(error.wrap_exception()) | |
1290 |
|
1294 | |||
1291 | finish(dict(status='ok', resubmitted=resubmitted)) |
|
1295 | finish(dict(status='ok', resubmitted=resubmitted)) | |
1292 |
|
1296 | |||
1293 | # store the new IDs in the Task DB |
|
1297 | # store the new IDs in the Task DB | |
1294 | for msg_id, resubmit_id in iteritems(resubmitted): |
|
1298 | for msg_id, resubmit_id in iteritems(resubmitted): | |
1295 | try: |
|
1299 | try: | |
1296 | self.db.update_record(msg_id, {'resubmitted' : resubmit_id}) |
|
1300 | self.db.update_record(msg_id, {'resubmitted' : resubmit_id}) | |
1297 | except Exception: |
|
1301 | except Exception: | |
1298 | self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True) |
|
1302 | self.log.error("db::DB Error updating record: %s", msg_id, exc_info=True) | |
1299 |
|
1303 | |||
1300 |
|
1304 | |||
1301 | def _extract_record(self, rec): |
|
1305 | def _extract_record(self, rec): | |
1302 | """decompose a TaskRecord dict into subsection of reply for get_result""" |
|
1306 | """decompose a TaskRecord dict into subsection of reply for get_result""" | |
1303 | io_dict = {} |
|
1307 | io_dict = {} | |
1304 | for key in ('pyin', 'pyout', 'pyerr', 'stdout', 'stderr'): |
|
1308 | for key in ('pyin', 'pyout', 'pyerr', 'stdout', 'stderr'): | |
1305 | io_dict[key] = rec[key] |
|
1309 | io_dict[key] = rec[key] | |
1306 | content = { |
|
1310 | content = { | |
1307 | 'header': rec['header'], |
|
1311 | 'header': rec['header'], | |
1308 | 'metadata': rec['metadata'], |
|
1312 | 'metadata': rec['metadata'], | |
1309 | 'result_metadata': rec['result_metadata'], |
|
1313 | 'result_metadata': rec['result_metadata'], | |
1310 | 'result_header' : rec['result_header'], |
|
1314 | 'result_header' : rec['result_header'], | |
1311 | 'result_content': rec['result_content'], |
|
1315 | 'result_content': rec['result_content'], | |
1312 | 'received' : rec['received'], |
|
1316 | 'received' : rec['received'], | |
1313 | 'io' : io_dict, |
|
1317 | 'io' : io_dict, | |
1314 | } |
|
1318 | } | |
1315 | if rec['result_buffers']: |
|
1319 | if rec['result_buffers']: | |
1316 | buffers = list(map(bytes, rec['result_buffers'])) |
|
1320 | buffers = list(map(bytes, rec['result_buffers'])) | |
1317 | else: |
|
1321 | else: | |
1318 | buffers = [] |
|
1322 | buffers = [] | |
1319 |
|
1323 | |||
1320 | return content, buffers |
|
1324 | return content, buffers | |
1321 |
|
1325 | |||
1322 | def get_results(self, client_id, msg): |
|
1326 | def get_results(self, client_id, msg): | |
1323 | """Get the result of 1 or more messages.""" |
|
1327 | """Get the result of 1 or more messages.""" | |
1324 | content = msg['content'] |
|
1328 | content = msg['content'] | |
1325 | msg_ids = sorted(set(content['msg_ids'])) |
|
1329 | msg_ids = sorted(set(content['msg_ids'])) | |
1326 | statusonly = content.get('status_only', False) |
|
1330 | statusonly = content.get('status_only', False) | |
1327 | pending = [] |
|
1331 | pending = [] | |
1328 | completed = [] |
|
1332 | completed = [] | |
1329 | content = dict(status='ok') |
|
1333 | content = dict(status='ok') | |
1330 | content['pending'] = pending |
|
1334 | content['pending'] = pending | |
1331 | content['completed'] = completed |
|
1335 | content['completed'] = completed | |
1332 | buffers = [] |
|
1336 | buffers = [] | |
1333 | if not statusonly: |
|
1337 | if not statusonly: | |
1334 | try: |
|
1338 | try: | |
1335 | matches = self.db.find_records(dict(msg_id={'$in':msg_ids})) |
|
1339 | matches = self.db.find_records(dict(msg_id={'$in':msg_ids})) | |
1336 | # turn match list into dict, for faster lookup |
|
1340 | # turn match list into dict, for faster lookup | |
1337 | records = {} |
|
1341 | records = {} | |
1338 | for rec in matches: |
|
1342 | for rec in matches: | |
1339 | records[rec['msg_id']] = rec |
|
1343 | records[rec['msg_id']] = rec | |
1340 | except Exception: |
|
1344 | except Exception: | |
1341 | content = error.wrap_exception() |
|
1345 | content = error.wrap_exception() | |
1342 | self.session.send(self.query, "result_reply", content=content, |
|
1346 | self.session.send(self.query, "result_reply", content=content, | |
1343 | parent=msg, ident=client_id) |
|
1347 | parent=msg, ident=client_id) | |
1344 | return |
|
1348 | return | |
1345 | else: |
|
1349 | else: | |
1346 | records = {} |
|
1350 | records = {} | |
1347 | for msg_id in msg_ids: |
|
1351 | for msg_id in msg_ids: | |
1348 | if msg_id in self.pending: |
|
1352 | if msg_id in self.pending: | |
1349 | pending.append(msg_id) |
|
1353 | pending.append(msg_id) | |
1350 | elif msg_id in self.all_completed: |
|
1354 | elif msg_id in self.all_completed: | |
1351 | completed.append(msg_id) |
|
1355 | completed.append(msg_id) | |
1352 | if not statusonly: |
|
1356 | if not statusonly: | |
1353 | c,bufs = self._extract_record(records[msg_id]) |
|
1357 | c,bufs = self._extract_record(records[msg_id]) | |
1354 | content[msg_id] = c |
|
1358 | content[msg_id] = c | |
1355 | buffers.extend(bufs) |
|
1359 | buffers.extend(bufs) | |
1356 | elif msg_id in records: |
|
1360 | elif msg_id in records: | |
1357 | if rec['completed']: |
|
1361 | if rec['completed']: | |
1358 | completed.append(msg_id) |
|
1362 | completed.append(msg_id) | |
1359 | c,bufs = self._extract_record(records[msg_id]) |
|
1363 | c,bufs = self._extract_record(records[msg_id]) | |
1360 | content[msg_id] = c |
|
1364 | content[msg_id] = c | |
1361 | buffers.extend(bufs) |
|
1365 | buffers.extend(bufs) | |
1362 | else: |
|
1366 | else: | |
1363 | pending.append(msg_id) |
|
1367 | pending.append(msg_id) | |
1364 | else: |
|
1368 | else: | |
1365 | try: |
|
1369 | try: | |
1366 | raise KeyError('No such message: '+msg_id) |
|
1370 | raise KeyError('No such message: '+msg_id) | |
1367 | except: |
|
1371 | except: | |
1368 | content = error.wrap_exception() |
|
1372 | content = error.wrap_exception() | |
1369 | break |
|
1373 | break | |
1370 | self.session.send(self.query, "result_reply", content=content, |
|
1374 | self.session.send(self.query, "result_reply", content=content, | |
1371 | parent=msg, ident=client_id, |
|
1375 | parent=msg, ident=client_id, | |
1372 | buffers=buffers) |
|
1376 | buffers=buffers) | |
1373 |
|
1377 | |||
1374 | def get_history(self, client_id, msg): |
|
1378 | def get_history(self, client_id, msg): | |
1375 | """Get a list of all msg_ids in our DB records""" |
|
1379 | """Get a list of all msg_ids in our DB records""" | |
1376 | try: |
|
1380 | try: | |
1377 | msg_ids = self.db.get_history() |
|
1381 | msg_ids = self.db.get_history() | |
1378 | except Exception as e: |
|
1382 | except Exception as e: | |
1379 | content = error.wrap_exception() |
|
1383 | content = error.wrap_exception() | |
1380 | else: |
|
1384 | else: | |
1381 | content = dict(status='ok', history=msg_ids) |
|
1385 | content = dict(status='ok', history=msg_ids) | |
1382 |
|
1386 | |||
1383 | self.session.send(self.query, "history_reply", content=content, |
|
1387 | self.session.send(self.query, "history_reply", content=content, | |
1384 | parent=msg, ident=client_id) |
|
1388 | parent=msg, ident=client_id) | |
1385 |
|
1389 | |||
1386 | def db_query(self, client_id, msg): |
|
1390 | def db_query(self, client_id, msg): | |
1387 | """Perform a raw query on the task record database.""" |
|
1391 | """Perform a raw query on the task record database.""" | |
1388 | content = msg['content'] |
|
1392 | content = msg['content'] | |
1389 | query = extract_dates(content.get('query', {})) |
|
1393 | query = extract_dates(content.get('query', {})) | |
1390 | keys = content.get('keys', None) |
|
1394 | keys = content.get('keys', None) | |
1391 | buffers = [] |
|
1395 | buffers = [] | |
1392 | empty = list() |
|
1396 | empty = list() | |
1393 | try: |
|
1397 | try: | |
1394 | records = self.db.find_records(query, keys) |
|
1398 | records = self.db.find_records(query, keys) | |
1395 | except Exception as e: |
|
1399 | except Exception as e: | |
1396 | content = error.wrap_exception() |
|
1400 | content = error.wrap_exception() | |
1397 | else: |
|
1401 | else: | |
1398 | # extract buffers from reply content: |
|
1402 | # extract buffers from reply content: | |
1399 | if keys is not None: |
|
1403 | if keys is not None: | |
1400 | buffer_lens = [] if 'buffers' in keys else None |
|
1404 | buffer_lens = [] if 'buffers' in keys else None | |
1401 | result_buffer_lens = [] if 'result_buffers' in keys else None |
|
1405 | result_buffer_lens = [] if 'result_buffers' in keys else None | |
1402 | else: |
|
1406 | else: | |
1403 | buffer_lens = None |
|
1407 | buffer_lens = None | |
1404 | result_buffer_lens = None |
|
1408 | result_buffer_lens = None | |
1405 |
|
1409 | |||
1406 | for rec in records: |
|
1410 | for rec in records: | |
1407 | # buffers may be None, so double check |
|
1411 | # buffers may be None, so double check | |
1408 | b = rec.pop('buffers', empty) or empty |
|
1412 | b = rec.pop('buffers', empty) or empty | |
1409 | if buffer_lens is not None: |
|
1413 | if buffer_lens is not None: | |
1410 | buffer_lens.append(len(b)) |
|
1414 | buffer_lens.append(len(b)) | |
1411 | buffers.extend(b) |
|
1415 | buffers.extend(b) | |
1412 | rb = rec.pop('result_buffers', empty) or empty |
|
1416 | rb = rec.pop('result_buffers', empty) or empty | |
1413 | if result_buffer_lens is not None: |
|
1417 | if result_buffer_lens is not None: | |
1414 | result_buffer_lens.append(len(rb)) |
|
1418 | result_buffer_lens.append(len(rb)) | |
1415 | buffers.extend(rb) |
|
1419 | buffers.extend(rb) | |
1416 | content = dict(status='ok', records=records, buffer_lens=buffer_lens, |
|
1420 | content = dict(status='ok', records=records, buffer_lens=buffer_lens, | |
1417 | result_buffer_lens=result_buffer_lens) |
|
1421 | result_buffer_lens=result_buffer_lens) | |
1418 | # self.log.debug (content) |
|
1422 | # self.log.debug (content) | |
1419 | self.session.send(self.query, "db_reply", content=content, |
|
1423 | self.session.send(self.query, "db_reply", content=content, | |
1420 | parent=msg, ident=client_id, |
|
1424 | parent=msg, ident=client_id, | |
1421 | buffers=buffers) |
|
1425 | buffers=buffers) | |
1422 |
|
1426 |
@@ -1,369 +1,370 b'' | |||||
1 | """some generic utilities for dealing with classes, urls, and serialization |
|
1 | """some generic utilities for dealing with classes, urls, and serialization | |
2 |
|
2 | |||
3 | Authors: |
|
3 | Authors: | |
4 |
|
4 | |||
5 | * Min RK |
|
5 | * Min RK | |
6 | """ |
|
6 | """ | |
7 | #----------------------------------------------------------------------------- |
|
7 | #----------------------------------------------------------------------------- | |
8 | # Copyright (C) 2010-2011 The IPython Development Team |
|
8 | # Copyright (C) 2010-2011 The IPython Development Team | |
9 | # |
|
9 | # | |
10 | # Distributed under the terms of the BSD License. The full license is in |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
11 | # the file COPYING, distributed as part of this software. |
|
11 | # the file COPYING, distributed as part of this software. | |
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 | # Imports |
|
15 | # Imports | |
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | # Standard library imports. |
|
18 | # Standard library imports. | |
19 | import logging |
|
19 | import logging | |
20 | import os |
|
20 | import os | |
21 | import re |
|
21 | import re | |
22 | import stat |
|
22 | import stat | |
23 | import socket |
|
23 | import socket | |
24 | import sys |
|
24 | import sys | |
25 | from signal import signal, SIGINT, SIGABRT, SIGTERM |
|
25 | from signal import signal, SIGINT, SIGABRT, SIGTERM | |
26 | try: |
|
26 | try: | |
27 | from signal import SIGKILL |
|
27 | from signal import SIGKILL | |
28 | except ImportError: |
|
28 | except ImportError: | |
29 | SIGKILL=None |
|
29 | SIGKILL=None | |
30 |
|
30 | |||
31 | try: |
|
31 | try: | |
32 | import cPickle |
|
32 | import cPickle | |
33 | pickle = cPickle |
|
33 | pickle = cPickle | |
34 | except: |
|
34 | except: | |
35 | cPickle = None |
|
35 | cPickle = None | |
36 | import pickle |
|
36 | import pickle | |
37 |
|
37 | |||
38 | # System library imports |
|
38 | # System library imports | |
39 | import zmq |
|
39 | import zmq | |
40 | from zmq.log import handlers |
|
40 | from zmq.log import handlers | |
41 |
|
41 | |||
42 | from IPython.external.decorator import decorator |
|
42 | from IPython.external.decorator import decorator | |
43 |
|
43 | |||
44 | # IPython imports |
|
44 | # IPython imports | |
45 | from IPython.config.application import Application |
|
45 | from IPython.config.application import Application | |
46 | from IPython.utils.localinterfaces import localhost, is_public_ip, public_ips |
|
46 | from IPython.utils.localinterfaces import localhost, is_public_ip, public_ips | |
47 | from IPython.utils.py3compat import string_types, iteritems, itervalues |
|
47 | from IPython.utils.py3compat import string_types, iteritems, itervalues | |
48 | from IPython.kernel.zmq.log import EnginePUBHandler |
|
48 | from IPython.kernel.zmq.log import EnginePUBHandler | |
49 | from IPython.kernel.zmq.serialize import ( |
|
49 | from IPython.kernel.zmq.serialize import ( | |
50 | unserialize_object, serialize_object, pack_apply_message, unpack_apply_message |
|
50 | unserialize_object, serialize_object, pack_apply_message, unpack_apply_message | |
51 | ) |
|
51 | ) | |
52 |
|
52 | |||
53 | #----------------------------------------------------------------------------- |
|
53 | #----------------------------------------------------------------------------- | |
54 | # Classes |
|
54 | # Classes | |
55 | #----------------------------------------------------------------------------- |
|
55 | #----------------------------------------------------------------------------- | |
56 |
|
56 | |||
57 | class Namespace(dict): |
|
57 | class Namespace(dict): | |
58 | """Subclass of dict for attribute access to keys.""" |
|
58 | """Subclass of dict for attribute access to keys.""" | |
59 |
|
59 | |||
60 | def __getattr__(self, key): |
|
60 | def __getattr__(self, key): | |
61 | """getattr aliased to getitem""" |
|
61 | """getattr aliased to getitem""" | |
62 | if key in self: |
|
62 | if key in self: | |
63 | return self[key] |
|
63 | return self[key] | |
64 | else: |
|
64 | else: | |
65 | raise NameError(key) |
|
65 | raise NameError(key) | |
66 |
|
66 | |||
67 | def __setattr__(self, key, value): |
|
67 | def __setattr__(self, key, value): | |
68 | """setattr aliased to setitem, with strict""" |
|
68 | """setattr aliased to setitem, with strict""" | |
69 | if hasattr(dict, key): |
|
69 | if hasattr(dict, key): | |
70 | raise KeyError("Cannot override dict keys %r"%key) |
|
70 | raise KeyError("Cannot override dict keys %r"%key) | |
71 | self[key] = value |
|
71 | self[key] = value | |
72 |
|
72 | |||
73 |
|
73 | |||
74 | class ReverseDict(dict): |
|
74 | class ReverseDict(dict): | |
75 | """simple double-keyed subset of dict methods.""" |
|
75 | """simple double-keyed subset of dict methods.""" | |
76 |
|
76 | |||
77 | def __init__(self, *args, **kwargs): |
|
77 | def __init__(self, *args, **kwargs): | |
78 | dict.__init__(self, *args, **kwargs) |
|
78 | dict.__init__(self, *args, **kwargs) | |
79 | self._reverse = dict() |
|
79 | self._reverse = dict() | |
80 | for key, value in iteritems(self): |
|
80 | for key, value in iteritems(self): | |
81 | self._reverse[value] = key |
|
81 | self._reverse[value] = key | |
82 |
|
82 | |||
83 | def __getitem__(self, key): |
|
83 | def __getitem__(self, key): | |
84 | try: |
|
84 | try: | |
85 | return dict.__getitem__(self, key) |
|
85 | return dict.__getitem__(self, key) | |
86 | except KeyError: |
|
86 | except KeyError: | |
87 | return self._reverse[key] |
|
87 | return self._reverse[key] | |
88 |
|
88 | |||
89 | def __setitem__(self, key, value): |
|
89 | def __setitem__(self, key, value): | |
90 | if key in self._reverse: |
|
90 | if key in self._reverse: | |
91 | raise KeyError("Can't have key %r on both sides!"%key) |
|
91 | raise KeyError("Can't have key %r on both sides!"%key) | |
92 | dict.__setitem__(self, key, value) |
|
92 | dict.__setitem__(self, key, value) | |
93 | self._reverse[value] = key |
|
93 | self._reverse[value] = key | |
94 |
|
94 | |||
95 | def pop(self, key): |
|
95 | def pop(self, key): | |
96 | value = dict.pop(self, key) |
|
96 | value = dict.pop(self, key) | |
97 | self._reverse.pop(value) |
|
97 | self._reverse.pop(value) | |
98 | return value |
|
98 | return value | |
99 |
|
99 | |||
100 | def get(self, key, default=None): |
|
100 | def get(self, key, default=None): | |
101 | try: |
|
101 | try: | |
102 | return self[key] |
|
102 | return self[key] | |
103 | except KeyError: |
|
103 | except KeyError: | |
104 | return default |
|
104 | return default | |
105 |
|
105 | |||
106 | #----------------------------------------------------------------------------- |
|
106 | #----------------------------------------------------------------------------- | |
107 | # Functions |
|
107 | # Functions | |
108 | #----------------------------------------------------------------------------- |
|
108 | #----------------------------------------------------------------------------- | |
109 |
|
109 | |||
110 | @decorator |
|
110 | @decorator | |
111 | def log_errors(f, self, *args, **kwargs): |
|
111 | def log_errors(f, self, *args, **kwargs): | |
112 | """decorator to log unhandled exceptions raised in a method. |
|
112 | """decorator to log unhandled exceptions raised in a method. | |
113 |
|
113 | |||
114 | For use wrapping on_recv callbacks, so that exceptions |
|
114 | For use wrapping on_recv callbacks, so that exceptions | |
115 | do not cause the stream to be closed. |
|
115 | do not cause the stream to be closed. | |
116 | """ |
|
116 | """ | |
117 | try: |
|
117 | try: | |
118 | return f(self, *args, **kwargs) |
|
118 | return f(self, *args, **kwargs) | |
119 | except Exception: |
|
119 | except Exception: | |
120 | self.log.error("Uncaught exception in %r" % f, exc_info=True) |
|
120 | self.log.error("Uncaught exception in %r" % f, exc_info=True) | |
121 |
|
121 | |||
122 |
|
122 | |||
123 | def is_url(url): |
|
123 | def is_url(url): | |
124 | """boolean check for whether a string is a zmq url""" |
|
124 | """boolean check for whether a string is a zmq url""" | |
125 | if '://' not in url: |
|
125 | if '://' not in url: | |
126 | return False |
|
126 | return False | |
127 | proto, addr = url.split('://', 1) |
|
127 | proto, addr = url.split('://', 1) | |
128 | if proto.lower() not in ['tcp','pgm','epgm','ipc','inproc']: |
|
128 | if proto.lower() not in ['tcp','pgm','epgm','ipc','inproc']: | |
129 | return False |
|
129 | return False | |
130 | return True |
|
130 | return True | |
131 |
|
131 | |||
132 | def validate_url(url): |
|
132 | def validate_url(url): | |
133 | """validate a url for zeromq""" |
|
133 | """validate a url for zeromq""" | |
134 | if not isinstance(url, string_types): |
|
134 | if not isinstance(url, string_types): | |
135 | raise TypeError("url must be a string, not %r"%type(url)) |
|
135 | raise TypeError("url must be a string, not %r"%type(url)) | |
136 | url = url.lower() |
|
136 | url = url.lower() | |
137 |
|
137 | |||
138 | proto_addr = url.split('://') |
|
138 | proto_addr = url.split('://') | |
139 | assert len(proto_addr) == 2, 'Invalid url: %r'%url |
|
139 | assert len(proto_addr) == 2, 'Invalid url: %r'%url | |
140 | proto, addr = proto_addr |
|
140 | proto, addr = proto_addr | |
141 | assert proto in ['tcp','pgm','epgm','ipc','inproc'], "Invalid protocol: %r"%proto |
|
141 | assert proto in ['tcp','pgm','epgm','ipc','inproc'], "Invalid protocol: %r"%proto | |
142 |
|
142 | |||
143 | # domain pattern adapted from http://www.regexlib.com/REDetails.aspx?regexp_id=391 |
|
143 | # domain pattern adapted from http://www.regexlib.com/REDetails.aspx?regexp_id=391 | |
144 | # author: Remi Sabourin |
|
144 | # author: Remi Sabourin | |
145 | pat = re.compile(r'^([\w\d]([\w\d\-]{0,61}[\w\d])?\.)*[\w\d]([\w\d\-]{0,61}[\w\d])?$') |
|
145 | pat = re.compile(r'^([\w\d]([\w\d\-]{0,61}[\w\d])?\.)*[\w\d]([\w\d\-]{0,61}[\w\d])?$') | |
146 |
|
146 | |||
147 | if proto == 'tcp': |
|
147 | if proto == 'tcp': | |
148 | lis = addr.split(':') |
|
148 | lis = addr.split(':') | |
149 | assert len(lis) == 2, 'Invalid url: %r'%url |
|
149 | assert len(lis) == 2, 'Invalid url: %r'%url | |
150 | addr,s_port = lis |
|
150 | addr,s_port = lis | |
151 | try: |
|
151 | try: | |
152 | port = int(s_port) |
|
152 | port = int(s_port) | |
153 | except ValueError: |
|
153 | except ValueError: | |
154 | raise AssertionError("Invalid port %r in url: %r"%(port, url)) |
|
154 | raise AssertionError("Invalid port %r in url: %r"%(port, url)) | |
155 |
|
155 | |||
156 | assert addr == '*' or pat.match(addr) is not None, 'Invalid url: %r'%url |
|
156 | assert addr == '*' or pat.match(addr) is not None, 'Invalid url: %r'%url | |
157 |
|
157 | |||
158 | else: |
|
158 | else: | |
159 | # only validate tcp urls currently |
|
159 | # only validate tcp urls currently | |
160 | pass |
|
160 | pass | |
161 |
|
161 | |||
162 | return True |
|
162 | return True | |
163 |
|
163 | |||
164 |
|
164 | |||
165 | def validate_url_container(container): |
|
165 | def validate_url_container(container): | |
166 | """validate a potentially nested collection of urls.""" |
|
166 | """validate a potentially nested collection of urls.""" | |
167 | if isinstance(container, string_types): |
|
167 | if isinstance(container, string_types): | |
168 | url = container |
|
168 | url = container | |
169 | return validate_url(url) |
|
169 | return validate_url(url) | |
170 | elif isinstance(container, dict): |
|
170 | elif isinstance(container, dict): | |
171 | container = itervalues(container) |
|
171 | container = itervalues(container) | |
172 |
|
172 | |||
173 | for element in container: |
|
173 | for element in container: | |
174 | validate_url_container(element) |
|
174 | validate_url_container(element) | |
175 |
|
175 | |||
176 |
|
176 | |||
177 | def split_url(url): |
|
177 | def split_url(url): | |
178 | """split a zmq url (tcp://ip:port) into ('tcp','ip','port').""" |
|
178 | """split a zmq url (tcp://ip:port) into ('tcp','ip','port').""" | |
179 | proto_addr = url.split('://') |
|
179 | proto_addr = url.split('://') | |
180 | assert len(proto_addr) == 2, 'Invalid url: %r'%url |
|
180 | assert len(proto_addr) == 2, 'Invalid url: %r'%url | |
181 | proto, addr = proto_addr |
|
181 | proto, addr = proto_addr | |
182 | lis = addr.split(':') |
|
182 | lis = addr.split(':') | |
183 | assert len(lis) == 2, 'Invalid url: %r'%url |
|
183 | assert len(lis) == 2, 'Invalid url: %r'%url | |
184 | addr,s_port = lis |
|
184 | addr,s_port = lis | |
185 | return proto,addr,s_port |
|
185 | return proto,addr,s_port | |
186 |
|
186 | |||
187 | def disambiguate_ip_address(ip, location=None): |
|
187 | def disambiguate_ip_address(ip, location=None): | |
188 | """turn multi-ip interfaces '0.0.0.0' and '*' into connectable |
|
188 | """turn multi-ip interfaces '0.0.0.0' and '*' into connectable | |
189 | ones, based on the location (default interpretation of location is localhost).""" |
|
189 | ones, based on the location (default interpretation of location is localhost).""" | |
190 | if ip in ('0.0.0.0', '*'): |
|
190 | if ip in ('0.0.0.0', '*'): | |
191 | if location is None or is_public_ip(location) or not public_ips(): |
|
191 | if location is None or is_public_ip(location) or not public_ips(): | |
192 | # If location is unspecified or cannot be determined, assume local |
|
192 | # If location is unspecified or cannot be determined, assume local | |
193 | ip = localhost() |
|
193 | ip = localhost() | |
194 | elif location: |
|
194 | elif location: | |
195 | return location |
|
195 | return location | |
196 | return ip |
|
196 | return ip | |
197 |
|
197 | |||
198 | def disambiguate_url(url, location=None): |
|
198 | def disambiguate_url(url, location=None): | |
199 | """turn multi-ip interfaces '0.0.0.0' and '*' into connectable |
|
199 | """turn multi-ip interfaces '0.0.0.0' and '*' into connectable | |
200 | ones, based on the location (default interpretation is localhost). |
|
200 | ones, based on the location (default interpretation is localhost). | |
201 |
|
201 | |||
202 |
This is for zeromq urls, such as tcp://*:10101. |
|
202 | This is for zeromq urls, such as ``tcp://*:10101``. | |
|
203 | """ | |||
203 | try: |
|
204 | try: | |
204 | proto,ip,port = split_url(url) |
|
205 | proto,ip,port = split_url(url) | |
205 | except AssertionError: |
|
206 | except AssertionError: | |
206 | # probably not tcp url; could be ipc, etc. |
|
207 | # probably not tcp url; could be ipc, etc. | |
207 | return url |
|
208 | return url | |
208 |
|
209 | |||
209 | ip = disambiguate_ip_address(ip,location) |
|
210 | ip = disambiguate_ip_address(ip,location) | |
210 |
|
211 | |||
211 | return "%s://%s:%s"%(proto,ip,port) |
|
212 | return "%s://%s:%s"%(proto,ip,port) | |
212 |
|
213 | |||
213 |
|
214 | |||
214 | #-------------------------------------------------------------------------- |
|
215 | #-------------------------------------------------------------------------- | |
215 | # helpers for implementing old MEC API via view.apply |
|
216 | # helpers for implementing old MEC API via view.apply | |
216 | #-------------------------------------------------------------------------- |
|
217 | #-------------------------------------------------------------------------- | |
217 |
|
218 | |||
218 | def interactive(f): |
|
219 | def interactive(f): | |
219 | """decorator for making functions appear as interactively defined. |
|
220 | """decorator for making functions appear as interactively defined. | |
220 | This results in the function being linked to the user_ns as globals() |
|
221 | This results in the function being linked to the user_ns as globals() | |
221 | instead of the module globals(). |
|
222 | instead of the module globals(). | |
222 | """ |
|
223 | """ | |
223 | f.__module__ = '__main__' |
|
224 | f.__module__ = '__main__' | |
224 | return f |
|
225 | return f | |
225 |
|
226 | |||
226 | @interactive |
|
227 | @interactive | |
227 | def _push(**ns): |
|
228 | def _push(**ns): | |
228 | """helper method for implementing `client.push` via `client.apply`""" |
|
229 | """helper method for implementing `client.push` via `client.apply`""" | |
229 | user_ns = globals() |
|
230 | user_ns = globals() | |
230 | tmp = '_IP_PUSH_TMP_' |
|
231 | tmp = '_IP_PUSH_TMP_' | |
231 | while tmp in user_ns: |
|
232 | while tmp in user_ns: | |
232 | tmp = tmp + '_' |
|
233 | tmp = tmp + '_' | |
233 | try: |
|
234 | try: | |
234 | for name, value in ns.items(): |
|
235 | for name, value in ns.items(): | |
235 | user_ns[tmp] = value |
|
236 | user_ns[tmp] = value | |
236 | exec("%s = %s" % (name, tmp), user_ns) |
|
237 | exec("%s = %s" % (name, tmp), user_ns) | |
237 | finally: |
|
238 | finally: | |
238 | user_ns.pop(tmp, None) |
|
239 | user_ns.pop(tmp, None) | |
239 |
|
240 | |||
240 | @interactive |
|
241 | @interactive | |
241 | def _pull(keys): |
|
242 | def _pull(keys): | |
242 | """helper method for implementing `client.pull` via `client.apply`""" |
|
243 | """helper method for implementing `client.pull` via `client.apply`""" | |
243 | if isinstance(keys, (list,tuple, set)): |
|
244 | if isinstance(keys, (list,tuple, set)): | |
244 | return [eval(key, globals()) for key in keys] |
|
245 | return [eval(key, globals()) for key in keys] | |
245 | else: |
|
246 | else: | |
246 | return eval(keys, globals()) |
|
247 | return eval(keys, globals()) | |
247 |
|
248 | |||
248 | @interactive |
|
249 | @interactive | |
249 | def _execute(code): |
|
250 | def _execute(code): | |
250 | """helper method for implementing `client.execute` via `client.apply`""" |
|
251 | """helper method for implementing `client.execute` via `client.apply`""" | |
251 | exec(code, globals()) |
|
252 | exec(code, globals()) | |
252 |
|
253 | |||
253 | #-------------------------------------------------------------------------- |
|
254 | #-------------------------------------------------------------------------- | |
254 | # extra process management utilities |
|
255 | # extra process management utilities | |
255 | #-------------------------------------------------------------------------- |
|
256 | #-------------------------------------------------------------------------- | |
256 |
|
257 | |||
257 | _random_ports = set() |
|
258 | _random_ports = set() | |
258 |
|
259 | |||
259 | def select_random_ports(n): |
|
260 | def select_random_ports(n): | |
260 | """Selects and return n random ports that are available.""" |
|
261 | """Selects and return n random ports that are available.""" | |
261 | ports = [] |
|
262 | ports = [] | |
262 | for i in range(n): |
|
263 | for i in range(n): | |
263 | sock = socket.socket() |
|
264 | sock = socket.socket() | |
264 | sock.bind(('', 0)) |
|
265 | sock.bind(('', 0)) | |
265 | while sock.getsockname()[1] in _random_ports: |
|
266 | while sock.getsockname()[1] in _random_ports: | |
266 | sock.close() |
|
267 | sock.close() | |
267 | sock = socket.socket() |
|
268 | sock = socket.socket() | |
268 | sock.bind(('', 0)) |
|
269 | sock.bind(('', 0)) | |
269 | ports.append(sock) |
|
270 | ports.append(sock) | |
270 | for i, sock in enumerate(ports): |
|
271 | for i, sock in enumerate(ports): | |
271 | port = sock.getsockname()[1] |
|
272 | port = sock.getsockname()[1] | |
272 | sock.close() |
|
273 | sock.close() | |
273 | ports[i] = port |
|
274 | ports[i] = port | |
274 | _random_ports.add(port) |
|
275 | _random_ports.add(port) | |
275 | return ports |
|
276 | return ports | |
276 |
|
277 | |||
277 | def signal_children(children): |
|
278 | def signal_children(children): | |
278 | """Relay interupt/term signals to children, for more solid process cleanup.""" |
|
279 | """Relay interupt/term signals to children, for more solid process cleanup.""" | |
279 | def terminate_children(sig, frame): |
|
280 | def terminate_children(sig, frame): | |
280 | log = Application.instance().log |
|
281 | log = Application.instance().log | |
281 | log.critical("Got signal %i, terminating children..."%sig) |
|
282 | log.critical("Got signal %i, terminating children..."%sig) | |
282 | for child in children: |
|
283 | for child in children: | |
283 | child.terminate() |
|
284 | child.terminate() | |
284 |
|
285 | |||
285 | sys.exit(sig != SIGINT) |
|
286 | sys.exit(sig != SIGINT) | |
286 | # sys.exit(sig) |
|
287 | # sys.exit(sig) | |
287 | for sig in (SIGINT, SIGABRT, SIGTERM): |
|
288 | for sig in (SIGINT, SIGABRT, SIGTERM): | |
288 | signal(sig, terminate_children) |
|
289 | signal(sig, terminate_children) | |
289 |
|
290 | |||
290 | def generate_exec_key(keyfile): |
|
291 | def generate_exec_key(keyfile): | |
291 | import uuid |
|
292 | import uuid | |
292 | newkey = str(uuid.uuid4()) |
|
293 | newkey = str(uuid.uuid4()) | |
293 | with open(keyfile, 'w') as f: |
|
294 | with open(keyfile, 'w') as f: | |
294 | # f.write('ipython-key ') |
|
295 | # f.write('ipython-key ') | |
295 | f.write(newkey+'\n') |
|
296 | f.write(newkey+'\n') | |
296 | # set user-only RW permissions (0600) |
|
297 | # set user-only RW permissions (0600) | |
297 | # this will have no effect on Windows |
|
298 | # this will have no effect on Windows | |
298 | os.chmod(keyfile, stat.S_IRUSR|stat.S_IWUSR) |
|
299 | os.chmod(keyfile, stat.S_IRUSR|stat.S_IWUSR) | |
299 |
|
300 | |||
300 |
|
301 | |||
301 | def integer_loglevel(loglevel): |
|
302 | def integer_loglevel(loglevel): | |
302 | try: |
|
303 | try: | |
303 | loglevel = int(loglevel) |
|
304 | loglevel = int(loglevel) | |
304 | except ValueError: |
|
305 | except ValueError: | |
305 | if isinstance(loglevel, str): |
|
306 | if isinstance(loglevel, str): | |
306 | loglevel = getattr(logging, loglevel) |
|
307 | loglevel = getattr(logging, loglevel) | |
307 | return loglevel |
|
308 | return loglevel | |
308 |
|
309 | |||
309 | def connect_logger(logname, context, iface, root="ip", loglevel=logging.DEBUG): |
|
310 | def connect_logger(logname, context, iface, root="ip", loglevel=logging.DEBUG): | |
310 | logger = logging.getLogger(logname) |
|
311 | logger = logging.getLogger(logname) | |
311 | if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]): |
|
312 | if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]): | |
312 | # don't add a second PUBHandler |
|
313 | # don't add a second PUBHandler | |
313 | return |
|
314 | return | |
314 | loglevel = integer_loglevel(loglevel) |
|
315 | loglevel = integer_loglevel(loglevel) | |
315 | lsock = context.socket(zmq.PUB) |
|
316 | lsock = context.socket(zmq.PUB) | |
316 | lsock.connect(iface) |
|
317 | lsock.connect(iface) | |
317 | handler = handlers.PUBHandler(lsock) |
|
318 | handler = handlers.PUBHandler(lsock) | |
318 | handler.setLevel(loglevel) |
|
319 | handler.setLevel(loglevel) | |
319 | handler.root_topic = root |
|
320 | handler.root_topic = root | |
320 | logger.addHandler(handler) |
|
321 | logger.addHandler(handler) | |
321 | logger.setLevel(loglevel) |
|
322 | logger.setLevel(loglevel) | |
322 |
|
323 | |||
323 | def connect_engine_logger(context, iface, engine, loglevel=logging.DEBUG): |
|
324 | def connect_engine_logger(context, iface, engine, loglevel=logging.DEBUG): | |
324 | logger = logging.getLogger() |
|
325 | logger = logging.getLogger() | |
325 | if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]): |
|
326 | if any([isinstance(h, handlers.PUBHandler) for h in logger.handlers]): | |
326 | # don't add a second PUBHandler |
|
327 | # don't add a second PUBHandler | |
327 | return |
|
328 | return | |
328 | loglevel = integer_loglevel(loglevel) |
|
329 | loglevel = integer_loglevel(loglevel) | |
329 | lsock = context.socket(zmq.PUB) |
|
330 | lsock = context.socket(zmq.PUB) | |
330 | lsock.connect(iface) |
|
331 | lsock.connect(iface) | |
331 | handler = EnginePUBHandler(engine, lsock) |
|
332 | handler = EnginePUBHandler(engine, lsock) | |
332 | handler.setLevel(loglevel) |
|
333 | handler.setLevel(loglevel) | |
333 | logger.addHandler(handler) |
|
334 | logger.addHandler(handler) | |
334 | logger.setLevel(loglevel) |
|
335 | logger.setLevel(loglevel) | |
335 | return logger |
|
336 | return logger | |
336 |
|
337 | |||
337 | def local_logger(logname, loglevel=logging.DEBUG): |
|
338 | def local_logger(logname, loglevel=logging.DEBUG): | |
338 | loglevel = integer_loglevel(loglevel) |
|
339 | loglevel = integer_loglevel(loglevel) | |
339 | logger = logging.getLogger(logname) |
|
340 | logger = logging.getLogger(logname) | |
340 | if any([isinstance(h, logging.StreamHandler) for h in logger.handlers]): |
|
341 | if any([isinstance(h, logging.StreamHandler) for h in logger.handlers]): | |
341 | # don't add a second StreamHandler |
|
342 | # don't add a second StreamHandler | |
342 | return |
|
343 | return | |
343 | handler = logging.StreamHandler() |
|
344 | handler = logging.StreamHandler() | |
344 | handler.setLevel(loglevel) |
|
345 | handler.setLevel(loglevel) | |
345 | formatter = logging.Formatter("%(asctime)s.%(msecs).03d [%(name)s] %(message)s", |
|
346 | formatter = logging.Formatter("%(asctime)s.%(msecs).03d [%(name)s] %(message)s", | |
346 | datefmt="%Y-%m-%d %H:%M:%S") |
|
347 | datefmt="%Y-%m-%d %H:%M:%S") | |
347 | handler.setFormatter(formatter) |
|
348 | handler.setFormatter(formatter) | |
348 |
|
349 | |||
349 | logger.addHandler(handler) |
|
350 | logger.addHandler(handler) | |
350 | logger.setLevel(loglevel) |
|
351 | logger.setLevel(loglevel) | |
351 | return logger |
|
352 | return logger | |
352 |
|
353 | |||
353 | def set_hwm(sock, hwm=0): |
|
354 | def set_hwm(sock, hwm=0): | |
354 | """set zmq High Water Mark on a socket |
|
355 | """set zmq High Water Mark on a socket | |
355 |
|
356 | |||
356 | in a way that always works for various pyzmq / libzmq versions. |
|
357 | in a way that always works for various pyzmq / libzmq versions. | |
357 | """ |
|
358 | """ | |
358 | import zmq |
|
359 | import zmq | |
359 |
|
360 | |||
360 | for key in ('HWM', 'SNDHWM', 'RCVHWM'): |
|
361 | for key in ('HWM', 'SNDHWM', 'RCVHWM'): | |
361 | opt = getattr(zmq, key, None) |
|
362 | opt = getattr(zmq, key, None) | |
362 | if opt is None: |
|
363 | if opt is None: | |
363 | continue |
|
364 | continue | |
364 | try: |
|
365 | try: | |
365 | sock.setsockopt(opt, hwm) |
|
366 | sock.setsockopt(opt, hwm) | |
366 | except zmq.ZMQError: |
|
367 | except zmq.ZMQError: | |
367 | pass |
|
368 | pass | |
368 |
|
369 | |||
369 | No newline at end of file |
|
370 |
@@ -1,692 +1,691 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """Subclass of InteractiveShell for terminal based frontends.""" |
|
2 | """Subclass of InteractiveShell for terminal based frontends.""" | |
3 |
|
3 | |||
4 | #----------------------------------------------------------------------------- |
|
4 | #----------------------------------------------------------------------------- | |
5 | # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> |
|
5 | # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> | |
6 | # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu> |
|
6 | # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu> | |
7 | # Copyright (C) 2008-2011 The IPython Development Team |
|
7 | # Copyright (C) 2008-2011 The IPython Development Team | |
8 | # |
|
8 | # | |
9 | # Distributed under the terms of the BSD License. The full license is in |
|
9 | # Distributed under the terms of the BSD License. The full license is in | |
10 | # the file COPYING, distributed as part of this software. |
|
10 | # the file COPYING, distributed as part of this software. | |
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 |
|
12 | |||
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 | # Imports |
|
14 | # Imports | |
15 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
16 | from __future__ import print_function |
|
16 | from __future__ import print_function | |
17 |
|
17 | |||
18 | import bdb |
|
18 | import bdb | |
19 | import os |
|
19 | import os | |
20 | import sys |
|
20 | import sys | |
21 |
|
21 | |||
22 | from IPython.core.error import TryNext, UsageError |
|
22 | from IPython.core.error import TryNext, UsageError | |
23 | from IPython.core.usage import interactive_usage, default_banner |
|
23 | from IPython.core.usage import interactive_usage, default_banner | |
24 | from IPython.core.inputsplitter import IPythonInputSplitter |
|
24 | from IPython.core.inputsplitter import IPythonInputSplitter | |
25 | from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC |
|
25 | from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC | |
26 | from IPython.core.magic import Magics, magics_class, line_magic |
|
26 | from IPython.core.magic import Magics, magics_class, line_magic | |
27 | from IPython.lib.clipboard import ClipboardEmpty |
|
27 | from IPython.lib.clipboard import ClipboardEmpty | |
28 | from IPython.testing.skipdoctest import skip_doctest |
|
28 | from IPython.testing.skipdoctest import skip_doctest | |
29 | from IPython.utils.encoding import get_stream_enc |
|
29 | from IPython.utils.encoding import get_stream_enc | |
30 | from IPython.utils import py3compat |
|
30 | from IPython.utils import py3compat | |
31 | from IPython.utils.terminal import toggle_set_term_title, set_term_title |
|
31 | from IPython.utils.terminal import toggle_set_term_title, set_term_title | |
32 | from IPython.utils.process import abbrev_cwd |
|
32 | from IPython.utils.process import abbrev_cwd | |
33 | from IPython.utils.warn import warn, error |
|
33 | from IPython.utils.warn import warn, error | |
34 | from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes |
|
34 | from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes | |
35 | from IPython.utils.traitlets import Integer, CBool, Unicode |
|
35 | from IPython.utils.traitlets import Integer, CBool, Unicode | |
36 |
|
36 | |||
37 | #----------------------------------------------------------------------------- |
|
37 | #----------------------------------------------------------------------------- | |
38 | # Utilities |
|
38 | # Utilities | |
39 | #----------------------------------------------------------------------------- |
|
39 | #----------------------------------------------------------------------------- | |
40 |
|
40 | |||
41 | def get_default_editor(): |
|
41 | def get_default_editor(): | |
42 | try: |
|
42 | try: | |
43 | ed = os.environ['EDITOR'] |
|
43 | ed = os.environ['EDITOR'] | |
44 | except KeyError: |
|
44 | except KeyError: | |
45 | if os.name == 'posix': |
|
45 | if os.name == 'posix': | |
46 | ed = 'vi' # the only one guaranteed to be there! |
|
46 | ed = 'vi' # the only one guaranteed to be there! | |
47 | else: |
|
47 | else: | |
48 | ed = 'notepad' # same in Windows! |
|
48 | ed = 'notepad' # same in Windows! | |
49 | return ed |
|
49 | return ed | |
50 |
|
50 | |||
51 |
|
51 | |||
52 | def get_pasted_lines(sentinel, l_input=py3compat.input): |
|
52 | def get_pasted_lines(sentinel, l_input=py3compat.input): | |
53 | """ Yield pasted lines until the user enters the given sentinel value. |
|
53 | """ Yield pasted lines until the user enters the given sentinel value. | |
54 | """ |
|
54 | """ | |
55 | print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \ |
|
55 | print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \ | |
56 | % sentinel) |
|
56 | % sentinel) | |
57 | while True: |
|
57 | while True: | |
58 | try: |
|
58 | try: | |
59 | l = l_input(':') |
|
59 | l = l_input(':') | |
60 | if l == sentinel: |
|
60 | if l == sentinel: | |
61 | return |
|
61 | return | |
62 | else: |
|
62 | else: | |
63 | yield l |
|
63 | yield l | |
64 | except EOFError: |
|
64 | except EOFError: | |
65 | print('<EOF>') |
|
65 | print('<EOF>') | |
66 | return |
|
66 | return | |
67 |
|
67 | |||
68 |
|
68 | |||
69 | #------------------------------------------------------------------------ |
|
69 | #------------------------------------------------------------------------ | |
70 | # Terminal-specific magics |
|
70 | # Terminal-specific magics | |
71 | #------------------------------------------------------------------------ |
|
71 | #------------------------------------------------------------------------ | |
72 |
|
72 | |||
73 | @magics_class |
|
73 | @magics_class | |
74 | class TerminalMagics(Magics): |
|
74 | class TerminalMagics(Magics): | |
75 | def __init__(self, shell): |
|
75 | def __init__(self, shell): | |
76 | super(TerminalMagics, self).__init__(shell) |
|
76 | super(TerminalMagics, self).__init__(shell) | |
77 | self.input_splitter = IPythonInputSplitter() |
|
77 | self.input_splitter = IPythonInputSplitter() | |
78 |
|
78 | |||
79 | def store_or_execute(self, block, name): |
|
79 | def store_or_execute(self, block, name): | |
80 | """ Execute a block, or store it in a variable, per the user's request. |
|
80 | """ Execute a block, or store it in a variable, per the user's request. | |
81 | """ |
|
81 | """ | |
82 | if name: |
|
82 | if name: | |
83 | # If storing it for further editing |
|
83 | # If storing it for further editing | |
84 | self.shell.user_ns[name] = SList(block.splitlines()) |
|
84 | self.shell.user_ns[name] = SList(block.splitlines()) | |
85 | print("Block assigned to '%s'" % name) |
|
85 | print("Block assigned to '%s'" % name) | |
86 | else: |
|
86 | else: | |
87 | b = self.preclean_input(block) |
|
87 | b = self.preclean_input(block) | |
88 | self.shell.user_ns['pasted_block'] = b |
|
88 | self.shell.user_ns['pasted_block'] = b | |
89 | self.shell.using_paste_magics = True |
|
89 | self.shell.using_paste_magics = True | |
90 | try: |
|
90 | try: | |
91 | self.shell.run_cell(b) |
|
91 | self.shell.run_cell(b) | |
92 | finally: |
|
92 | finally: | |
93 | self.shell.using_paste_magics = False |
|
93 | self.shell.using_paste_magics = False | |
94 |
|
94 | |||
95 | def preclean_input(self, block): |
|
95 | def preclean_input(self, block): | |
96 | lines = block.splitlines() |
|
96 | lines = block.splitlines() | |
97 | while lines and not lines[0].strip(): |
|
97 | while lines and not lines[0].strip(): | |
98 | lines = lines[1:] |
|
98 | lines = lines[1:] | |
99 | return strip_email_quotes('\n'.join(lines)) |
|
99 | return strip_email_quotes('\n'.join(lines)) | |
100 |
|
100 | |||
101 | def rerun_pasted(self, name='pasted_block'): |
|
101 | def rerun_pasted(self, name='pasted_block'): | |
102 | """ Rerun a previously pasted command. |
|
102 | """ Rerun a previously pasted command. | |
103 | """ |
|
103 | """ | |
104 | b = self.shell.user_ns.get(name) |
|
104 | b = self.shell.user_ns.get(name) | |
105 |
|
105 | |||
106 | # Sanity checks |
|
106 | # Sanity checks | |
107 | if b is None: |
|
107 | if b is None: | |
108 | raise UsageError('No previous pasted block available') |
|
108 | raise UsageError('No previous pasted block available') | |
109 | if not isinstance(b, py3compat.string_types): |
|
109 | if not isinstance(b, py3compat.string_types): | |
110 | raise UsageError( |
|
110 | raise UsageError( | |
111 | "Variable 'pasted_block' is not a string, can't execute") |
|
111 | "Variable 'pasted_block' is not a string, can't execute") | |
112 |
|
112 | |||
113 | print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))) |
|
113 | print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))) | |
114 | self.shell.run_cell(b) |
|
114 | self.shell.run_cell(b) | |
115 |
|
115 | |||
116 | @line_magic |
|
116 | @line_magic | |
117 | def autoindent(self, parameter_s = ''): |
|
117 | def autoindent(self, parameter_s = ''): | |
118 | """Toggle autoindent on/off (if available).""" |
|
118 | """Toggle autoindent on/off (if available).""" | |
119 |
|
119 | |||
120 | self.shell.set_autoindent() |
|
120 | self.shell.set_autoindent() | |
121 | print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent]) |
|
121 | print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent]) | |
122 |
|
122 | |||
123 | @skip_doctest |
|
123 | @skip_doctest | |
124 | @line_magic |
|
124 | @line_magic | |
125 | def cpaste(self, parameter_s=''): |
|
125 | def cpaste(self, parameter_s=''): | |
126 | """Paste & execute a pre-formatted code block from clipboard. |
|
126 | """Paste & execute a pre-formatted code block from clipboard. | |
127 |
|
127 | |||
128 | You must terminate the block with '--' (two minus-signs) or Ctrl-D |
|
128 | You must terminate the block with '--' (two minus-signs) or Ctrl-D | |
129 | alone on the line. You can also provide your own sentinel with '%paste |
|
129 | alone on the line. You can also provide your own sentinel with '%paste | |
130 | -s %%' ('%%' is the new sentinel for this operation) |
|
130 | -s %%' ('%%' is the new sentinel for this operation) | |
131 |
|
131 | |||
132 | The block is dedented prior to execution to enable execution of method |
|
132 | The block is dedented prior to execution to enable execution of method | |
133 | definitions. '>' and '+' characters at the beginning of a line are |
|
133 | definitions. '>' and '+' characters at the beginning of a line are | |
134 | ignored, to allow pasting directly from e-mails, diff files and |
|
134 | ignored, to allow pasting directly from e-mails, diff files and | |
135 | doctests (the '...' continuation prompt is also stripped). The |
|
135 | doctests (the '...' continuation prompt is also stripped). The | |
136 | executed block is also assigned to variable named 'pasted_block' for |
|
136 | executed block is also assigned to variable named 'pasted_block' for | |
137 | later editing with '%edit pasted_block'. |
|
137 | later editing with '%edit pasted_block'. | |
138 |
|
138 | |||
139 | You can also pass a variable name as an argument, e.g. '%cpaste foo'. |
|
139 | You can also pass a variable name as an argument, e.g. '%cpaste foo'. | |
140 | This assigns the pasted block to variable 'foo' as string, without |
|
140 | This assigns the pasted block to variable 'foo' as string, without | |
141 | dedenting or executing it (preceding >>> and + is still stripped) |
|
141 | dedenting or executing it (preceding >>> and + is still stripped) | |
142 |
|
142 | |||
143 | '%cpaste -r' re-executes the block previously entered by cpaste. |
|
143 | '%cpaste -r' re-executes the block previously entered by cpaste. | |
144 |
|
144 | |||
145 | Do not be alarmed by garbled output on Windows (it's a readline bug). |
|
145 | Do not be alarmed by garbled output on Windows (it's a readline bug). | |
146 | Just press enter and type -- (and press enter again) and the block |
|
146 | Just press enter and type -- (and press enter again) and the block | |
147 | will be what was just pasted. |
|
147 | will be what was just pasted. | |
148 |
|
148 | |||
149 | IPython statements (magics, shell escapes) are not supported (yet). |
|
149 | IPython statements (magics, shell escapes) are not supported (yet). | |
150 |
|
150 | |||
151 | See also |
|
151 | See also | |
152 | -------- |
|
152 | -------- | |
153 | paste: automatically pull code from clipboard. |
|
153 | paste: automatically pull code from clipboard. | |
154 |
|
154 | |||
155 | Examples |
|
155 | Examples | |
156 | -------- |
|
156 | -------- | |
157 | :: |
|
157 | :: | |
158 |
|
158 | |||
159 | In [8]: %cpaste |
|
159 | In [8]: %cpaste | |
160 | Pasting code; enter '--' alone on the line to stop. |
|
160 | Pasting code; enter '--' alone on the line to stop. | |
161 | :>>> a = ["world!", "Hello"] |
|
161 | :>>> a = ["world!", "Hello"] | |
162 | :>>> print " ".join(sorted(a)) |
|
162 | :>>> print " ".join(sorted(a)) | |
163 | :-- |
|
163 | :-- | |
164 | Hello world! |
|
164 | Hello world! | |
165 | """ |
|
165 | """ | |
166 | opts, name = self.parse_options(parameter_s, 'rs:', mode='string') |
|
166 | opts, name = self.parse_options(parameter_s, 'rs:', mode='string') | |
167 | if 'r' in opts: |
|
167 | if 'r' in opts: | |
168 | self.rerun_pasted() |
|
168 | self.rerun_pasted() | |
169 | return |
|
169 | return | |
170 |
|
170 | |||
171 | sentinel = opts.get('s', '--') |
|
171 | sentinel = opts.get('s', '--') | |
172 | block = '\n'.join(get_pasted_lines(sentinel)) |
|
172 | block = '\n'.join(get_pasted_lines(sentinel)) | |
173 | self.store_or_execute(block, name) |
|
173 | self.store_or_execute(block, name) | |
174 |
|
174 | |||
175 | @line_magic |
|
175 | @line_magic | |
176 | def paste(self, parameter_s=''): |
|
176 | def paste(self, parameter_s=''): | |
177 | """Paste & execute a pre-formatted code block from clipboard. |
|
177 | """Paste & execute a pre-formatted code block from clipboard. | |
178 |
|
178 | |||
179 | The text is pulled directly from the clipboard without user |
|
179 | The text is pulled directly from the clipboard without user | |
180 | intervention and printed back on the screen before execution (unless |
|
180 | intervention and printed back on the screen before execution (unless | |
181 | the -q flag is given to force quiet mode). |
|
181 | the -q flag is given to force quiet mode). | |
182 |
|
182 | |||
183 | The block is dedented prior to execution to enable execution of method |
|
183 | The block is dedented prior to execution to enable execution of method | |
184 | definitions. '>' and '+' characters at the beginning of a line are |
|
184 | definitions. '>' and '+' characters at the beginning of a line are | |
185 | ignored, to allow pasting directly from e-mails, diff files and |
|
185 | ignored, to allow pasting directly from e-mails, diff files and | |
186 | doctests (the '...' continuation prompt is also stripped). The |
|
186 | doctests (the '...' continuation prompt is also stripped). The | |
187 | executed block is also assigned to variable named 'pasted_block' for |
|
187 | executed block is also assigned to variable named 'pasted_block' for | |
188 | later editing with '%edit pasted_block'. |
|
188 | later editing with '%edit pasted_block'. | |
189 |
|
189 | |||
190 | You can also pass a variable name as an argument, e.g. '%paste foo'. |
|
190 | You can also pass a variable name as an argument, e.g. '%paste foo'. | |
191 | This assigns the pasted block to variable 'foo' as string, without |
|
191 | This assigns the pasted block to variable 'foo' as string, without | |
192 | executing it (preceding >>> and + is still stripped). |
|
192 | executing it (preceding >>> and + is still stripped). | |
193 |
|
193 | |||
194 | Options: |
|
194 | Options: | |
195 |
|
195 | |||
196 | -r: re-executes the block previously entered by cpaste. |
|
196 | -r: re-executes the block previously entered by cpaste. | |
197 |
|
197 | |||
198 | -q: quiet mode: do not echo the pasted text back to the terminal. |
|
198 | -q: quiet mode: do not echo the pasted text back to the terminal. | |
199 |
|
199 | |||
200 | IPython statements (magics, shell escapes) are not supported (yet). |
|
200 | IPython statements (magics, shell escapes) are not supported (yet). | |
201 |
|
201 | |||
202 | See also |
|
202 | See also | |
203 | -------- |
|
203 | -------- | |
204 | cpaste: manually paste code into terminal until you mark its end. |
|
204 | cpaste: manually paste code into terminal until you mark its end. | |
205 | """ |
|
205 | """ | |
206 | opts, name = self.parse_options(parameter_s, 'rq', mode='string') |
|
206 | opts, name = self.parse_options(parameter_s, 'rq', mode='string') | |
207 | if 'r' in opts: |
|
207 | if 'r' in opts: | |
208 | self.rerun_pasted() |
|
208 | self.rerun_pasted() | |
209 | return |
|
209 | return | |
210 | try: |
|
210 | try: | |
211 | block = self.shell.hooks.clipboard_get() |
|
211 | block = self.shell.hooks.clipboard_get() | |
212 | except TryNext as clipboard_exc: |
|
212 | except TryNext as clipboard_exc: | |
213 | message = getattr(clipboard_exc, 'args') |
|
213 | message = getattr(clipboard_exc, 'args') | |
214 | if message: |
|
214 | if message: | |
215 | error(message[0]) |
|
215 | error(message[0]) | |
216 | else: |
|
216 | else: | |
217 | error('Could not get text from the clipboard.') |
|
217 | error('Could not get text from the clipboard.') | |
218 | return |
|
218 | return | |
219 | except ClipboardEmpty: |
|
219 | except ClipboardEmpty: | |
220 | raise UsageError("The clipboard appears to be empty") |
|
220 | raise UsageError("The clipboard appears to be empty") | |
221 |
|
221 | |||
222 | # By default, echo back to terminal unless quiet mode is requested |
|
222 | # By default, echo back to terminal unless quiet mode is requested | |
223 | if 'q' not in opts: |
|
223 | if 'q' not in opts: | |
224 | write = self.shell.write |
|
224 | write = self.shell.write | |
225 | write(self.shell.pycolorize(block)) |
|
225 | write(self.shell.pycolorize(block)) | |
226 | if not block.endswith('\n'): |
|
226 | if not block.endswith('\n'): | |
227 | write('\n') |
|
227 | write('\n') | |
228 | write("## -- End pasted text --\n") |
|
228 | write("## -- End pasted text --\n") | |
229 |
|
229 | |||
230 | self.store_or_execute(block, name) |
|
230 | self.store_or_execute(block, name) | |
231 |
|
231 | |||
232 | # Class-level: add a '%cls' magic only on Windows |
|
232 | # Class-level: add a '%cls' magic only on Windows | |
233 | if sys.platform == 'win32': |
|
233 | if sys.platform == 'win32': | |
234 | @line_magic |
|
234 | @line_magic | |
235 | def cls(self, s): |
|
235 | def cls(self, s): | |
236 | """Clear screen. |
|
236 | """Clear screen. | |
237 | """ |
|
237 | """ | |
238 | os.system("cls") |
|
238 | os.system("cls") | |
239 |
|
239 | |||
240 | #----------------------------------------------------------------------------- |
|
240 | #----------------------------------------------------------------------------- | |
241 | # Main class |
|
241 | # Main class | |
242 | #----------------------------------------------------------------------------- |
|
242 | #----------------------------------------------------------------------------- | |
243 |
|
243 | |||
244 | class TerminalInteractiveShell(InteractiveShell): |
|
244 | class TerminalInteractiveShell(InteractiveShell): | |
245 |
|
245 | |||
246 | autoedit_syntax = CBool(False, config=True, |
|
246 | autoedit_syntax = CBool(False, config=True, | |
247 | help="auto editing of files with syntax errors.") |
|
247 | help="auto editing of files with syntax errors.") | |
248 | banner = Unicode('') |
|
248 | banner = Unicode('') | |
249 | banner1 = Unicode(default_banner, config=True, |
|
249 | banner1 = Unicode(default_banner, config=True, | |
250 | help="""The part of the banner to be printed before the profile""" |
|
250 | help="""The part of the banner to be printed before the profile""" | |
251 | ) |
|
251 | ) | |
252 | banner2 = Unicode('', config=True, |
|
252 | banner2 = Unicode('', config=True, | |
253 | help="""The part of the banner to be printed after the profile""" |
|
253 | help="""The part of the banner to be printed after the profile""" | |
254 | ) |
|
254 | ) | |
255 | confirm_exit = CBool(True, config=True, |
|
255 | confirm_exit = CBool(True, config=True, | |
256 | help=""" |
|
256 | help=""" | |
257 | Set to confirm when you try to exit IPython with an EOF (Control-D |
|
257 | Set to confirm when you try to exit IPython with an EOF (Control-D | |
258 | in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', |
|
258 | in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', | |
259 | you can force a direct exit without any confirmation.""", |
|
259 | you can force a direct exit without any confirmation.""", | |
260 | ) |
|
260 | ) | |
261 | # This display_banner only controls whether or not self.show_banner() |
|
261 | # This display_banner only controls whether or not self.show_banner() | |
262 | # is called when mainloop/interact are called. The default is False |
|
262 | # is called when mainloop/interact are called. The default is False | |
263 | # because for the terminal based application, the banner behavior |
|
263 | # because for the terminal based application, the banner behavior | |
264 | # is controlled by Global.display_banner, which IPythonApp looks at |
|
264 | # is controlled by Global.display_banner, which IPythonApp looks at | |
265 | # to determine if *it* should call show_banner() by hand or not. |
|
265 | # to determine if *it* should call show_banner() by hand or not. | |
266 | display_banner = CBool(False) # This isn't configurable! |
|
266 | display_banner = CBool(False) # This isn't configurable! | |
267 | embedded = CBool(False) |
|
267 | embedded = CBool(False) | |
268 | embedded_active = CBool(False) |
|
268 | embedded_active = CBool(False) | |
269 | editor = Unicode(get_default_editor(), config=True, |
|
269 | editor = Unicode(get_default_editor(), config=True, | |
270 | help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." |
|
270 | help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." | |
271 | ) |
|
271 | ) | |
272 | pager = Unicode('less', config=True, |
|
272 | pager = Unicode('less', config=True, | |
273 | help="The shell program to be used for paging.") |
|
273 | help="The shell program to be used for paging.") | |
274 |
|
274 | |||
275 | screen_length = Integer(0, config=True, |
|
275 | screen_length = Integer(0, config=True, | |
276 | help= |
|
276 | help= | |
277 | """Number of lines of your screen, used to control printing of very |
|
277 | """Number of lines of your screen, used to control printing of very | |
278 | long strings. Strings longer than this number of lines will be sent |
|
278 | long strings. Strings longer than this number of lines will be sent | |
279 | through a pager instead of directly printed. The default value for |
|
279 | through a pager instead of directly printed. The default value for | |
280 | this is 0, which means IPython will auto-detect your screen size every |
|
280 | this is 0, which means IPython will auto-detect your screen size every | |
281 | time it needs to print certain potentially long strings (this doesn't |
|
281 | time it needs to print certain potentially long strings (this doesn't | |
282 | change the behavior of the 'print' keyword, it's only triggered |
|
282 | change the behavior of the 'print' keyword, it's only triggered | |
283 | internally). If for some reason this isn't working well (it needs |
|
283 | internally). If for some reason this isn't working well (it needs | |
284 | curses support), specify it yourself. Otherwise don't change the |
|
284 | curses support), specify it yourself. Otherwise don't change the | |
285 | default.""", |
|
285 | default.""", | |
286 | ) |
|
286 | ) | |
287 | term_title = CBool(False, config=True, |
|
287 | term_title = CBool(False, config=True, | |
288 | help="Enable auto setting the terminal title." |
|
288 | help="Enable auto setting the terminal title." | |
289 | ) |
|
289 | ) | |
290 |
|
290 | |||
291 | # This `using_paste_magics` is used to detect whether the code is being |
|
291 | # This `using_paste_magics` is used to detect whether the code is being | |
292 | # executed via paste magics functions |
|
292 | # executed via paste magics functions | |
293 | using_paste_magics = CBool(False) |
|
293 | using_paste_magics = CBool(False) | |
294 |
|
294 | |||
295 | # In the terminal, GUI control is done via PyOS_InputHook |
|
295 | # In the terminal, GUI control is done via PyOS_InputHook | |
296 | @staticmethod |
|
296 | @staticmethod | |
297 | def enable_gui(gui=None, app=None): |
|
297 | def enable_gui(gui=None, app=None): | |
298 | """Switch amongst GUI input hooks by name. |
|
298 | """Switch amongst GUI input hooks by name. | |
299 | """ |
|
299 | """ | |
300 | # Deferred import |
|
300 | # Deferred import | |
301 | from IPython.lib.inputhook import enable_gui as real_enable_gui |
|
301 | from IPython.lib.inputhook import enable_gui as real_enable_gui | |
302 | try: |
|
302 | try: | |
303 | return real_enable_gui(gui, app) |
|
303 | return real_enable_gui(gui, app) | |
304 | except ValueError as e: |
|
304 | except ValueError as e: | |
305 | raise UsageError("%s" % e) |
|
305 | raise UsageError("%s" % e) | |
306 |
|
306 | |||
307 | def __init__(self, config=None, ipython_dir=None, profile_dir=None, |
|
307 | def __init__(self, config=None, ipython_dir=None, profile_dir=None, | |
308 | user_ns=None, user_module=None, custom_exceptions=((),None), |
|
308 | user_ns=None, user_module=None, custom_exceptions=((),None), | |
309 | usage=None, banner1=None, banner2=None, display_banner=None, |
|
309 | usage=None, banner1=None, banner2=None, display_banner=None, | |
310 | **kwargs): |
|
310 | **kwargs): | |
311 |
|
311 | |||
312 | super(TerminalInteractiveShell, self).__init__( |
|
312 | super(TerminalInteractiveShell, self).__init__( | |
313 | config=config, ipython_dir=ipython_dir, profile_dir=profile_dir, user_ns=user_ns, |
|
313 | config=config, ipython_dir=ipython_dir, profile_dir=profile_dir, user_ns=user_ns, | |
314 | user_module=user_module, custom_exceptions=custom_exceptions, |
|
314 | user_module=user_module, custom_exceptions=custom_exceptions, | |
315 | **kwargs |
|
315 | **kwargs | |
316 | ) |
|
316 | ) | |
317 | # use os.system instead of utils.process.system by default, |
|
317 | # use os.system instead of utils.process.system by default, | |
318 | # because piped system doesn't make sense in the Terminal: |
|
318 | # because piped system doesn't make sense in the Terminal: | |
319 | self.system = self.system_raw |
|
319 | self.system = self.system_raw | |
320 |
|
320 | |||
321 | self.init_term_title() |
|
321 | self.init_term_title() | |
322 | self.init_usage(usage) |
|
322 | self.init_usage(usage) | |
323 | self.init_banner(banner1, banner2, display_banner) |
|
323 | self.init_banner(banner1, banner2, display_banner) | |
324 |
|
324 | |||
325 | #------------------------------------------------------------------------- |
|
325 | #------------------------------------------------------------------------- | |
326 | # Overrides of init stages |
|
326 | # Overrides of init stages | |
327 | #------------------------------------------------------------------------- |
|
327 | #------------------------------------------------------------------------- | |
328 |
|
328 | |||
329 | def init_display_formatter(self): |
|
329 | def init_display_formatter(self): | |
330 | super(TerminalInteractiveShell, self).init_display_formatter() |
|
330 | super(TerminalInteractiveShell, self).init_display_formatter() | |
331 | # terminal only supports plaintext |
|
331 | # terminal only supports plaintext | |
332 | self.display_formatter.active_types = ['text/plain'] |
|
332 | self.display_formatter.active_types = ['text/plain'] | |
333 |
|
333 | |||
334 | #------------------------------------------------------------------------- |
|
334 | #------------------------------------------------------------------------- | |
335 | # Things related to the terminal |
|
335 | # Things related to the terminal | |
336 | #------------------------------------------------------------------------- |
|
336 | #------------------------------------------------------------------------- | |
337 |
|
337 | |||
338 | @property |
|
338 | @property | |
339 | def usable_screen_length(self): |
|
339 | def usable_screen_length(self): | |
340 | if self.screen_length == 0: |
|
340 | if self.screen_length == 0: | |
341 | return 0 |
|
341 | return 0 | |
342 | else: |
|
342 | else: | |
343 | num_lines_bot = self.separate_in.count('\n')+1 |
|
343 | num_lines_bot = self.separate_in.count('\n')+1 | |
344 | return self.screen_length - num_lines_bot |
|
344 | return self.screen_length - num_lines_bot | |
345 |
|
345 | |||
346 | def init_term_title(self): |
|
346 | def init_term_title(self): | |
347 | # Enable or disable the terminal title. |
|
347 | # Enable or disable the terminal title. | |
348 | if self.term_title: |
|
348 | if self.term_title: | |
349 | toggle_set_term_title(True) |
|
349 | toggle_set_term_title(True) | |
350 | set_term_title('IPython: ' + abbrev_cwd()) |
|
350 | set_term_title('IPython: ' + abbrev_cwd()) | |
351 | else: |
|
351 | else: | |
352 | toggle_set_term_title(False) |
|
352 | toggle_set_term_title(False) | |
353 |
|
353 | |||
354 | #------------------------------------------------------------------------- |
|
354 | #------------------------------------------------------------------------- | |
355 | # Things related to aliases |
|
355 | # Things related to aliases | |
356 | #------------------------------------------------------------------------- |
|
356 | #------------------------------------------------------------------------- | |
357 |
|
357 | |||
358 | def init_alias(self): |
|
358 | def init_alias(self): | |
359 | # The parent class defines aliases that can be safely used with any |
|
359 | # The parent class defines aliases that can be safely used with any | |
360 | # frontend. |
|
360 | # frontend. | |
361 | super(TerminalInteractiveShell, self).init_alias() |
|
361 | super(TerminalInteractiveShell, self).init_alias() | |
362 |
|
362 | |||
363 | # Now define aliases that only make sense on the terminal, because they |
|
363 | # Now define aliases that only make sense on the terminal, because they | |
364 | # need direct access to the console in a way that we can't emulate in |
|
364 | # need direct access to the console in a way that we can't emulate in | |
365 | # GUI or web frontend |
|
365 | # GUI or web frontend | |
366 | if os.name == 'posix': |
|
366 | if os.name == 'posix': | |
367 | aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'), |
|
367 | aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'), | |
368 | ('man', 'man')] |
|
368 | ('man', 'man')] | |
369 | elif os.name == 'nt': |
|
369 | elif os.name == 'nt': | |
370 | aliases = [('cls', 'cls')] |
|
370 | aliases = [('cls', 'cls')] | |
371 |
|
371 | |||
372 |
|
372 | |||
373 | for name, cmd in aliases: |
|
373 | for name, cmd in aliases: | |
374 | self.alias_manager.soft_define_alias(name, cmd) |
|
374 | self.alias_manager.soft_define_alias(name, cmd) | |
375 |
|
375 | |||
376 | #------------------------------------------------------------------------- |
|
376 | #------------------------------------------------------------------------- | |
377 | # Things related to the banner and usage |
|
377 | # Things related to the banner and usage | |
378 | #------------------------------------------------------------------------- |
|
378 | #------------------------------------------------------------------------- | |
379 |
|
379 | |||
380 | def _banner1_changed(self): |
|
380 | def _banner1_changed(self): | |
381 | self.compute_banner() |
|
381 | self.compute_banner() | |
382 |
|
382 | |||
383 | def _banner2_changed(self): |
|
383 | def _banner2_changed(self): | |
384 | self.compute_banner() |
|
384 | self.compute_banner() | |
385 |
|
385 | |||
386 | def _term_title_changed(self, name, new_value): |
|
386 | def _term_title_changed(self, name, new_value): | |
387 | self.init_term_title() |
|
387 | self.init_term_title() | |
388 |
|
388 | |||
389 | def init_banner(self, banner1, banner2, display_banner): |
|
389 | def init_banner(self, banner1, banner2, display_banner): | |
390 | if banner1 is not None: |
|
390 | if banner1 is not None: | |
391 | self.banner1 = banner1 |
|
391 | self.banner1 = banner1 | |
392 | if banner2 is not None: |
|
392 | if banner2 is not None: | |
393 | self.banner2 = banner2 |
|
393 | self.banner2 = banner2 | |
394 | if display_banner is not None: |
|
394 | if display_banner is not None: | |
395 | self.display_banner = display_banner |
|
395 | self.display_banner = display_banner | |
396 | self.compute_banner() |
|
396 | self.compute_banner() | |
397 |
|
397 | |||
398 | def show_banner(self, banner=None): |
|
398 | def show_banner(self, banner=None): | |
399 | if banner is None: |
|
399 | if banner is None: | |
400 | banner = self.banner |
|
400 | banner = self.banner | |
401 | self.write(banner) |
|
401 | self.write(banner) | |
402 |
|
402 | |||
403 | def compute_banner(self): |
|
403 | def compute_banner(self): | |
404 | self.banner = self.banner1 |
|
404 | self.banner = self.banner1 | |
405 | if self.profile and self.profile != 'default': |
|
405 | if self.profile and self.profile != 'default': | |
406 | self.banner += '\nIPython profile: %s\n' % self.profile |
|
406 | self.banner += '\nIPython profile: %s\n' % self.profile | |
407 | if self.banner2: |
|
407 | if self.banner2: | |
408 | self.banner += '\n' + self.banner2 |
|
408 | self.banner += '\n' + self.banner2 | |
409 |
|
409 | |||
410 | def init_usage(self, usage=None): |
|
410 | def init_usage(self, usage=None): | |
411 | if usage is None: |
|
411 | if usage is None: | |
412 | self.usage = interactive_usage |
|
412 | self.usage = interactive_usage | |
413 | else: |
|
413 | else: | |
414 | self.usage = usage |
|
414 | self.usage = usage | |
415 |
|
415 | |||
416 | #------------------------------------------------------------------------- |
|
416 | #------------------------------------------------------------------------- | |
417 | # Mainloop and code execution logic |
|
417 | # Mainloop and code execution logic | |
418 | #------------------------------------------------------------------------- |
|
418 | #------------------------------------------------------------------------- | |
419 |
|
419 | |||
420 | def mainloop(self, display_banner=None): |
|
420 | def mainloop(self, display_banner=None): | |
421 | """Start the mainloop. |
|
421 | """Start the mainloop. | |
422 |
|
422 | |||
423 | If an optional banner argument is given, it will override the |
|
423 | If an optional banner argument is given, it will override the | |
424 | internally created default banner. |
|
424 | internally created default banner. | |
425 | """ |
|
425 | """ | |
426 |
|
426 | |||
427 | with self.builtin_trap, self.display_trap: |
|
427 | with self.builtin_trap, self.display_trap: | |
428 |
|
428 | |||
429 | while 1: |
|
429 | while 1: | |
430 | try: |
|
430 | try: | |
431 | self.interact(display_banner=display_banner) |
|
431 | self.interact(display_banner=display_banner) | |
432 | #self.interact_with_readline() |
|
432 | #self.interact_with_readline() | |
433 | # XXX for testing of a readline-decoupled repl loop, call |
|
433 | # XXX for testing of a readline-decoupled repl loop, call | |
434 | # interact_with_readline above |
|
434 | # interact_with_readline above | |
435 | break |
|
435 | break | |
436 | except KeyboardInterrupt: |
|
436 | except KeyboardInterrupt: | |
437 | # this should not be necessary, but KeyboardInterrupt |
|
437 | # this should not be necessary, but KeyboardInterrupt | |
438 | # handling seems rather unpredictable... |
|
438 | # handling seems rather unpredictable... | |
439 | self.write("\nKeyboardInterrupt in interact()\n") |
|
439 | self.write("\nKeyboardInterrupt in interact()\n") | |
440 |
|
440 | |||
441 | def _replace_rlhist_multiline(self, source_raw, hlen_before_cell): |
|
441 | def _replace_rlhist_multiline(self, source_raw, hlen_before_cell): | |
442 | """Store multiple lines as a single entry in history""" |
|
442 | """Store multiple lines as a single entry in history""" | |
443 |
|
443 | |||
444 | # do nothing without readline or disabled multiline |
|
444 | # do nothing without readline or disabled multiline | |
445 | if not self.has_readline or not self.multiline_history: |
|
445 | if not self.has_readline or not self.multiline_history: | |
446 | return hlen_before_cell |
|
446 | return hlen_before_cell | |
447 |
|
447 | |||
448 | # windows rl has no remove_history_item |
|
448 | # windows rl has no remove_history_item | |
449 | if not hasattr(self.readline, "remove_history_item"): |
|
449 | if not hasattr(self.readline, "remove_history_item"): | |
450 | return hlen_before_cell |
|
450 | return hlen_before_cell | |
451 |
|
451 | |||
452 | # skip empty cells |
|
452 | # skip empty cells | |
453 | if not source_raw.rstrip(): |
|
453 | if not source_raw.rstrip(): | |
454 | return hlen_before_cell |
|
454 | return hlen_before_cell | |
455 |
|
455 | |||
456 | # nothing changed do nothing, e.g. when rl removes consecutive dups |
|
456 | # nothing changed do nothing, e.g. when rl removes consecutive dups | |
457 | hlen = self.readline.get_current_history_length() |
|
457 | hlen = self.readline.get_current_history_length() | |
458 | if hlen == hlen_before_cell: |
|
458 | if hlen == hlen_before_cell: | |
459 | return hlen_before_cell |
|
459 | return hlen_before_cell | |
460 |
|
460 | |||
461 | for i in range(hlen - hlen_before_cell): |
|
461 | for i in range(hlen - hlen_before_cell): | |
462 | self.readline.remove_history_item(hlen - i - 1) |
|
462 | self.readline.remove_history_item(hlen - i - 1) | |
463 | stdin_encoding = get_stream_enc(sys.stdin, 'utf-8') |
|
463 | stdin_encoding = get_stream_enc(sys.stdin, 'utf-8') | |
464 | self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(), |
|
464 | self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(), | |
465 | stdin_encoding)) |
|
465 | stdin_encoding)) | |
466 | return self.readline.get_current_history_length() |
|
466 | return self.readline.get_current_history_length() | |
467 |
|
467 | |||
468 | def interact(self, display_banner=None): |
|
468 | def interact(self, display_banner=None): | |
469 | """Closely emulate the interactive Python console.""" |
|
469 | """Closely emulate the interactive Python console.""" | |
470 |
|
470 | |||
471 | # batch run -> do not interact |
|
471 | # batch run -> do not interact | |
472 | if self.exit_now: |
|
472 | if self.exit_now: | |
473 | return |
|
473 | return | |
474 |
|
474 | |||
475 | if display_banner is None: |
|
475 | if display_banner is None: | |
476 | display_banner = self.display_banner |
|
476 | display_banner = self.display_banner | |
477 |
|
477 | |||
478 | if isinstance(display_banner, py3compat.string_types): |
|
478 | if isinstance(display_banner, py3compat.string_types): | |
479 | self.show_banner(display_banner) |
|
479 | self.show_banner(display_banner) | |
480 | elif display_banner: |
|
480 | elif display_banner: | |
481 | self.show_banner() |
|
481 | self.show_banner() | |
482 |
|
482 | |||
483 | more = False |
|
483 | more = False | |
484 |
|
484 | |||
485 | if self.has_readline: |
|
485 | if self.has_readline: | |
486 | self.readline_startup_hook(self.pre_readline) |
|
486 | self.readline_startup_hook(self.pre_readline) | |
487 | hlen_b4_cell = self.readline.get_current_history_length() |
|
487 | hlen_b4_cell = self.readline.get_current_history_length() | |
488 | else: |
|
488 | else: | |
489 | hlen_b4_cell = 0 |
|
489 | hlen_b4_cell = 0 | |
490 | # exit_now is set by a call to %Exit or %Quit, through the |
|
490 | # exit_now is set by a call to %Exit or %Quit, through the | |
491 | # ask_exit callback. |
|
491 | # ask_exit callback. | |
492 |
|
492 | |||
493 | while not self.exit_now: |
|
493 | while not self.exit_now: | |
494 | self.hooks.pre_prompt_hook() |
|
494 | self.hooks.pre_prompt_hook() | |
495 | if more: |
|
495 | if more: | |
496 | try: |
|
496 | try: | |
497 | prompt = self.prompt_manager.render('in2') |
|
497 | prompt = self.prompt_manager.render('in2') | |
498 | except: |
|
498 | except: | |
499 | self.showtraceback() |
|
499 | self.showtraceback() | |
500 | if self.autoindent: |
|
500 | if self.autoindent: | |
501 | self.rl_do_indent = True |
|
501 | self.rl_do_indent = True | |
502 |
|
502 | |||
503 | else: |
|
503 | else: | |
504 | try: |
|
504 | try: | |
505 | prompt = self.separate_in + self.prompt_manager.render('in') |
|
505 | prompt = self.separate_in + self.prompt_manager.render('in') | |
506 | except: |
|
506 | except: | |
507 | self.showtraceback() |
|
507 | self.showtraceback() | |
508 | try: |
|
508 | try: | |
509 | line = self.raw_input(prompt) |
|
509 | line = self.raw_input(prompt) | |
510 | if self.exit_now: |
|
510 | if self.exit_now: | |
511 | # quick exit on sys.std[in|out] close |
|
511 | # quick exit on sys.std[in|out] close | |
512 | break |
|
512 | break | |
513 | if self.autoindent: |
|
513 | if self.autoindent: | |
514 | self.rl_do_indent = False |
|
514 | self.rl_do_indent = False | |
515 |
|
515 | |||
516 | except KeyboardInterrupt: |
|
516 | except KeyboardInterrupt: | |
517 | #double-guard against keyboardinterrupts during kbdint handling |
|
517 | #double-guard against keyboardinterrupts during kbdint handling | |
518 | try: |
|
518 | try: | |
519 | self.write('\nKeyboardInterrupt\n') |
|
519 | self.write('\nKeyboardInterrupt\n') | |
520 | source_raw = self.input_splitter.source_raw_reset()[1] |
|
520 | source_raw = self.input_splitter.source_raw_reset()[1] | |
521 | hlen_b4_cell = \ |
|
521 | hlen_b4_cell = \ | |
522 | self._replace_rlhist_multiline(source_raw, hlen_b4_cell) |
|
522 | self._replace_rlhist_multiline(source_raw, hlen_b4_cell) | |
523 | more = False |
|
523 | more = False | |
524 | except KeyboardInterrupt: |
|
524 | except KeyboardInterrupt: | |
525 | pass |
|
525 | pass | |
526 | except EOFError: |
|
526 | except EOFError: | |
527 | if self.autoindent: |
|
527 | if self.autoindent: | |
528 | self.rl_do_indent = False |
|
528 | self.rl_do_indent = False | |
529 | if self.has_readline: |
|
529 | if self.has_readline: | |
530 | self.readline_startup_hook(None) |
|
530 | self.readline_startup_hook(None) | |
531 | self.write('\n') |
|
531 | self.write('\n') | |
532 | self.exit() |
|
532 | self.exit() | |
533 | except bdb.BdbQuit: |
|
533 | except bdb.BdbQuit: | |
534 | warn('The Python debugger has exited with a BdbQuit exception.\n' |
|
534 | warn('The Python debugger has exited with a BdbQuit exception.\n' | |
535 | 'Because of how pdb handles the stack, it is impossible\n' |
|
535 | 'Because of how pdb handles the stack, it is impossible\n' | |
536 | 'for IPython to properly format this particular exception.\n' |
|
536 | 'for IPython to properly format this particular exception.\n' | |
537 | 'IPython will resume normal operation.') |
|
537 | 'IPython will resume normal operation.') | |
538 | except: |
|
538 | except: | |
539 | # exceptions here are VERY RARE, but they can be triggered |
|
539 | # exceptions here are VERY RARE, but they can be triggered | |
540 | # asynchronously by signal handlers, for example. |
|
540 | # asynchronously by signal handlers, for example. | |
541 | self.showtraceback() |
|
541 | self.showtraceback() | |
542 | else: |
|
542 | else: | |
543 | self.input_splitter.push(line) |
|
543 | self.input_splitter.push(line) | |
544 | more = self.input_splitter.push_accepts_more() |
|
544 | more = self.input_splitter.push_accepts_more() | |
545 | if (self.SyntaxTB.last_syntax_error and |
|
545 | if (self.SyntaxTB.last_syntax_error and | |
546 | self.autoedit_syntax): |
|
546 | self.autoedit_syntax): | |
547 | self.edit_syntax_error() |
|
547 | self.edit_syntax_error() | |
548 | if not more: |
|
548 | if not more: | |
549 | source_raw = self.input_splitter.source_raw_reset()[1] |
|
549 | source_raw = self.input_splitter.source_raw_reset()[1] | |
550 | self.run_cell(source_raw, store_history=True) |
|
550 | self.run_cell(source_raw, store_history=True) | |
551 | hlen_b4_cell = \ |
|
551 | hlen_b4_cell = \ | |
552 | self._replace_rlhist_multiline(source_raw, hlen_b4_cell) |
|
552 | self._replace_rlhist_multiline(source_raw, hlen_b4_cell) | |
553 |
|
553 | |||
554 | # Turn off the exit flag, so the mainloop can be restarted if desired |
|
554 | # Turn off the exit flag, so the mainloop can be restarted if desired | |
555 | self.exit_now = False |
|
555 | self.exit_now = False | |
556 |
|
556 | |||
557 | def raw_input(self, prompt=''): |
|
557 | def raw_input(self, prompt=''): | |
558 | """Write a prompt and read a line. |
|
558 | """Write a prompt and read a line. | |
559 |
|
559 | |||
560 | The returned line does not include the trailing newline. |
|
560 | The returned line does not include the trailing newline. | |
561 | When the user enters the EOF key sequence, EOFError is raised. |
|
561 | When the user enters the EOF key sequence, EOFError is raised. | |
562 |
|
562 | |||
563 | Optional inputs: |
|
563 | Parameters | |
|
564 | ---------- | |||
564 |
|
565 | |||
565 | - prompt(''): a string to be printed to prompt the user. |
|
566 | prompt : str, optional | |
566 |
|
567 | A string to be printed to prompt the user. | ||
567 | - continue_prompt(False): whether this line is the first one or a |
|
|||
568 | continuation in a sequence of inputs. |
|
|||
569 | """ |
|
568 | """ | |
570 | # Code run by the user may have modified the readline completer state. |
|
569 | # Code run by the user may have modified the readline completer state. | |
571 | # We must ensure that our completer is back in place. |
|
570 | # We must ensure that our completer is back in place. | |
572 |
|
571 | |||
573 | if self.has_readline: |
|
572 | if self.has_readline: | |
574 | self.set_readline_completer() |
|
573 | self.set_readline_completer() | |
575 |
|
574 | |||
576 | # raw_input expects str, but we pass it unicode sometimes |
|
575 | # raw_input expects str, but we pass it unicode sometimes | |
577 | prompt = py3compat.cast_bytes_py2(prompt) |
|
576 | prompt = py3compat.cast_bytes_py2(prompt) | |
578 |
|
577 | |||
579 | try: |
|
578 | try: | |
580 | line = py3compat.str_to_unicode(self.raw_input_original(prompt)) |
|
579 | line = py3compat.str_to_unicode(self.raw_input_original(prompt)) | |
581 | except ValueError: |
|
580 | except ValueError: | |
582 | warn("\n********\nYou or a %run:ed script called sys.stdin.close()" |
|
581 | warn("\n********\nYou or a %run:ed script called sys.stdin.close()" | |
583 | " or sys.stdout.close()!\nExiting IPython!\n") |
|
582 | " or sys.stdout.close()!\nExiting IPython!\n") | |
584 | self.ask_exit() |
|
583 | self.ask_exit() | |
585 | return "" |
|
584 | return "" | |
586 |
|
585 | |||
587 | # Try to be reasonably smart about not re-indenting pasted input more |
|
586 | # Try to be reasonably smart about not re-indenting pasted input more | |
588 | # than necessary. We do this by trimming out the auto-indent initial |
|
587 | # than necessary. We do this by trimming out the auto-indent initial | |
589 | # spaces, if the user's actual input started itself with whitespace. |
|
588 | # spaces, if the user's actual input started itself with whitespace. | |
590 | if self.autoindent: |
|
589 | if self.autoindent: | |
591 | if num_ini_spaces(line) > self.indent_current_nsp: |
|
590 | if num_ini_spaces(line) > self.indent_current_nsp: | |
592 | line = line[self.indent_current_nsp:] |
|
591 | line = line[self.indent_current_nsp:] | |
593 | self.indent_current_nsp = 0 |
|
592 | self.indent_current_nsp = 0 | |
594 |
|
593 | |||
595 | return line |
|
594 | return line | |
596 |
|
595 | |||
597 | #------------------------------------------------------------------------- |
|
596 | #------------------------------------------------------------------------- | |
598 | # Methods to support auto-editing of SyntaxErrors. |
|
597 | # Methods to support auto-editing of SyntaxErrors. | |
599 | #------------------------------------------------------------------------- |
|
598 | #------------------------------------------------------------------------- | |
600 |
|
599 | |||
601 | def edit_syntax_error(self): |
|
600 | def edit_syntax_error(self): | |
602 | """The bottom half of the syntax error handler called in the main loop. |
|
601 | """The bottom half of the syntax error handler called in the main loop. | |
603 |
|
602 | |||
604 | Loop until syntax error is fixed or user cancels. |
|
603 | Loop until syntax error is fixed or user cancels. | |
605 | """ |
|
604 | """ | |
606 |
|
605 | |||
607 | while self.SyntaxTB.last_syntax_error: |
|
606 | while self.SyntaxTB.last_syntax_error: | |
608 | # copy and clear last_syntax_error |
|
607 | # copy and clear last_syntax_error | |
609 | err = self.SyntaxTB.clear_err_state() |
|
608 | err = self.SyntaxTB.clear_err_state() | |
610 | if not self._should_recompile(err): |
|
609 | if not self._should_recompile(err): | |
611 | return |
|
610 | return | |
612 | try: |
|
611 | try: | |
613 | # may set last_syntax_error again if a SyntaxError is raised |
|
612 | # may set last_syntax_error again if a SyntaxError is raised | |
614 | self.safe_execfile(err.filename,self.user_ns) |
|
613 | self.safe_execfile(err.filename,self.user_ns) | |
615 | except: |
|
614 | except: | |
616 | self.showtraceback() |
|
615 | self.showtraceback() | |
617 | else: |
|
616 | else: | |
618 | try: |
|
617 | try: | |
619 | f = open(err.filename) |
|
618 | f = open(err.filename) | |
620 | try: |
|
619 | try: | |
621 | # This should be inside a display_trap block and I |
|
620 | # This should be inside a display_trap block and I | |
622 | # think it is. |
|
621 | # think it is. | |
623 | sys.displayhook(f.read()) |
|
622 | sys.displayhook(f.read()) | |
624 | finally: |
|
623 | finally: | |
625 | f.close() |
|
624 | f.close() | |
626 | except: |
|
625 | except: | |
627 | self.showtraceback() |
|
626 | self.showtraceback() | |
628 |
|
627 | |||
629 | def _should_recompile(self,e): |
|
628 | def _should_recompile(self,e): | |
630 | """Utility routine for edit_syntax_error""" |
|
629 | """Utility routine for edit_syntax_error""" | |
631 |
|
630 | |||
632 | if e.filename in ('<ipython console>','<input>','<string>', |
|
631 | if e.filename in ('<ipython console>','<input>','<string>', | |
633 | '<console>','<BackgroundJob compilation>', |
|
632 | '<console>','<BackgroundJob compilation>', | |
634 | None): |
|
633 | None): | |
635 |
|
634 | |||
636 | return False |
|
635 | return False | |
637 | try: |
|
636 | try: | |
638 | if (self.autoedit_syntax and |
|
637 | if (self.autoedit_syntax and | |
639 | not self.ask_yes_no('Return to editor to correct syntax error? ' |
|
638 | not self.ask_yes_no('Return to editor to correct syntax error? ' | |
640 | '[Y/n] ','y')): |
|
639 | '[Y/n] ','y')): | |
641 | return False |
|
640 | return False | |
642 | except EOFError: |
|
641 | except EOFError: | |
643 | return False |
|
642 | return False | |
644 |
|
643 | |||
645 | def int0(x): |
|
644 | def int0(x): | |
646 | try: |
|
645 | try: | |
647 | return int(x) |
|
646 | return int(x) | |
648 | except TypeError: |
|
647 | except TypeError: | |
649 | return 0 |
|
648 | return 0 | |
650 | # always pass integer line and offset values to editor hook |
|
649 | # always pass integer line and offset values to editor hook | |
651 | try: |
|
650 | try: | |
652 | self.hooks.fix_error_editor(e.filename, |
|
651 | self.hooks.fix_error_editor(e.filename, | |
653 | int0(e.lineno),int0(e.offset),e.msg) |
|
652 | int0(e.lineno),int0(e.offset),e.msg) | |
654 | except TryNext: |
|
653 | except TryNext: | |
655 | warn('Could not open editor') |
|
654 | warn('Could not open editor') | |
656 | return False |
|
655 | return False | |
657 | return True |
|
656 | return True | |
658 |
|
657 | |||
659 | #------------------------------------------------------------------------- |
|
658 | #------------------------------------------------------------------------- | |
660 | # Things related to exiting |
|
659 | # Things related to exiting | |
661 | #------------------------------------------------------------------------- |
|
660 | #------------------------------------------------------------------------- | |
662 |
|
661 | |||
663 | def ask_exit(self): |
|
662 | def ask_exit(self): | |
664 | """ Ask the shell to exit. Can be overiden and used as a callback. """ |
|
663 | """ Ask the shell to exit. Can be overiden and used as a callback. """ | |
665 | self.exit_now = True |
|
664 | self.exit_now = True | |
666 |
|
665 | |||
667 | def exit(self): |
|
666 | def exit(self): | |
668 | """Handle interactive exit. |
|
667 | """Handle interactive exit. | |
669 |
|
668 | |||
670 | This method calls the ask_exit callback.""" |
|
669 | This method calls the ask_exit callback.""" | |
671 | if self.confirm_exit: |
|
670 | if self.confirm_exit: | |
672 | if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'): |
|
671 | if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'): | |
673 | self.ask_exit() |
|
672 | self.ask_exit() | |
674 | else: |
|
673 | else: | |
675 | self.ask_exit() |
|
674 | self.ask_exit() | |
676 |
|
675 | |||
677 | #------------------------------------------------------------------------- |
|
676 | #------------------------------------------------------------------------- | |
678 | # Things related to magics |
|
677 | # Things related to magics | |
679 | #------------------------------------------------------------------------- |
|
678 | #------------------------------------------------------------------------- | |
680 |
|
679 | |||
681 | def init_magics(self): |
|
680 | def init_magics(self): | |
682 | super(TerminalInteractiveShell, self).init_magics() |
|
681 | super(TerminalInteractiveShell, self).init_magics() | |
683 | self.register_magics(TerminalMagics) |
|
682 | self.register_magics(TerminalMagics) | |
684 |
|
683 | |||
685 | def showindentationerror(self): |
|
684 | def showindentationerror(self): | |
686 | super(TerminalInteractiveShell, self).showindentationerror() |
|
685 | super(TerminalInteractiveShell, self).showindentationerror() | |
687 | if not self.using_paste_magics: |
|
686 | if not self.using_paste_magics: | |
688 | print("If you want to paste code into IPython, try the " |
|
687 | print("If you want to paste code into IPython, try the " | |
689 | "%paste and %cpaste magic functions.") |
|
688 | "%paste and %cpaste magic functions.") | |
690 |
|
689 | |||
691 |
|
690 | |||
692 | InteractiveShellABC.register(TerminalInteractiveShell) |
|
691 | InteractiveShellABC.register(TerminalInteractiveShell) |
@@ -1,382 +1,383 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """Decorators for labeling test objects. |
|
2 | """Decorators for labeling test objects. | |
3 |
|
3 | |||
4 | Decorators that merely return a modified version of the original function |
|
4 | Decorators that merely return a modified version of the original function | |
5 | object are straightforward. Decorators that return a new function object need |
|
5 | object are straightforward. Decorators that return a new function object need | |
6 | to use nose.tools.make_decorator(original_function)(decorator) in returning the |
|
6 | to use nose.tools.make_decorator(original_function)(decorator) in returning the | |
7 | decorator, in order to preserve metadata such as function name, setup and |
|
7 | decorator, in order to preserve metadata such as function name, setup and | |
8 | teardown functions and so on - see nose.tools for more information. |
|
8 | teardown functions and so on - see nose.tools for more information. | |
9 |
|
9 | |||
10 | This module provides a set of useful decorators meant to be ready to use in |
|
10 | This module provides a set of useful decorators meant to be ready to use in | |
11 | your own tests. See the bottom of the file for the ready-made ones, and if you |
|
11 | your own tests. See the bottom of the file for the ready-made ones, and if you | |
12 | find yourself writing a new one that may be of generic use, add it here. |
|
12 | find yourself writing a new one that may be of generic use, add it here. | |
13 |
|
13 | |||
14 | Included decorators: |
|
14 | Included decorators: | |
15 |
|
15 | |||
16 |
|
16 | |||
17 | Lightweight testing that remains unittest-compatible. |
|
17 | Lightweight testing that remains unittest-compatible. | |
18 |
|
18 | |||
19 | - An @as_unittest decorator can be used to tag any normal parameter-less |
|
19 | - An @as_unittest decorator can be used to tag any normal parameter-less | |
20 | function as a unittest TestCase. Then, both nose and normal unittest will |
|
20 | function as a unittest TestCase. Then, both nose and normal unittest will | |
21 | recognize it as such. This will make it easier to migrate away from Nose if |
|
21 | recognize it as such. This will make it easier to migrate away from Nose if | |
22 | we ever need/want to while maintaining very lightweight tests. |
|
22 | we ever need/want to while maintaining very lightweight tests. | |
23 |
|
23 | |||
24 | NOTE: This file contains IPython-specific decorators. Using the machinery in |
|
24 | NOTE: This file contains IPython-specific decorators. Using the machinery in | |
25 | IPython.external.decorators, we import either numpy.testing.decorators if numpy is |
|
25 | IPython.external.decorators, we import either numpy.testing.decorators if numpy is | |
26 | available, OR use equivalent code in IPython.external._decorators, which |
|
26 | available, OR use equivalent code in IPython.external._decorators, which | |
27 | we've copied verbatim from numpy. |
|
27 | we've copied verbatim from numpy. | |
28 |
|
28 | |||
29 | Authors |
|
29 | Authors | |
30 | ------- |
|
30 | ------- | |
31 |
|
31 | |||
32 | - Fernando Perez <Fernando.Perez@berkeley.edu> |
|
32 | - Fernando Perez <Fernando.Perez@berkeley.edu> | |
33 | """ |
|
33 | """ | |
34 |
|
34 | |||
35 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
36 | # Copyright (C) 2009-2011 The IPython Development Team |
|
36 | # Copyright (C) 2009-2011 The IPython Development Team | |
37 | # |
|
37 | # | |
38 | # Distributed under the terms of the BSD License. The full license is in |
|
38 | # Distributed under the terms of the BSD License. The full license is in | |
39 | # the file COPYING, distributed as part of this software. |
|
39 | # the file COPYING, distributed as part of this software. | |
40 | #----------------------------------------------------------------------------- |
|
40 | #----------------------------------------------------------------------------- | |
41 |
|
41 | |||
42 | #----------------------------------------------------------------------------- |
|
42 | #----------------------------------------------------------------------------- | |
43 | # Imports |
|
43 | # Imports | |
44 | #----------------------------------------------------------------------------- |
|
44 | #----------------------------------------------------------------------------- | |
45 |
|
45 | |||
46 | # Stdlib imports |
|
46 | # Stdlib imports | |
47 | import sys |
|
47 | import sys | |
48 | import os |
|
48 | import os | |
49 | import tempfile |
|
49 | import tempfile | |
50 | import unittest |
|
50 | import unittest | |
51 |
|
51 | |||
52 | # Third-party imports |
|
52 | # Third-party imports | |
53 |
|
53 | |||
54 | # This is Michele Simionato's decorator module, kept verbatim. |
|
54 | # This is Michele Simionato's decorator module, kept verbatim. | |
55 | from IPython.external.decorator import decorator |
|
55 | from IPython.external.decorator import decorator | |
56 |
|
56 | |||
57 | # Expose the unittest-driven decorators |
|
57 | # Expose the unittest-driven decorators | |
58 | from .ipunittest import ipdoctest, ipdocstring |
|
58 | from .ipunittest import ipdoctest, ipdocstring | |
59 |
|
59 | |||
60 | # Grab the numpy-specific decorators which we keep in a file that we |
|
60 | # Grab the numpy-specific decorators which we keep in a file that we | |
61 | # occasionally update from upstream: decorators.py is a copy of |
|
61 | # occasionally update from upstream: decorators.py is a copy of | |
62 | # numpy.testing.decorators, we expose all of it here. |
|
62 | # numpy.testing.decorators, we expose all of it here. | |
63 | from IPython.external.decorators import * |
|
63 | from IPython.external.decorators import * | |
64 |
|
64 | |||
65 | # For onlyif_cmd_exists decorator |
|
65 | # For onlyif_cmd_exists decorator | |
66 | from IPython.utils.process import is_cmd_found |
|
66 | from IPython.utils.process import is_cmd_found | |
67 | from IPython.utils.py3compat import string_types |
|
67 | from IPython.utils.py3compat import string_types | |
68 |
|
68 | |||
69 | #----------------------------------------------------------------------------- |
|
69 | #----------------------------------------------------------------------------- | |
70 | # Classes and functions |
|
70 | # Classes and functions | |
71 | #----------------------------------------------------------------------------- |
|
71 | #----------------------------------------------------------------------------- | |
72 |
|
72 | |||
73 | # Simple example of the basic idea |
|
73 | # Simple example of the basic idea | |
74 | def as_unittest(func): |
|
74 | def as_unittest(func): | |
75 | """Decorator to make a simple function into a normal test via unittest.""" |
|
75 | """Decorator to make a simple function into a normal test via unittest.""" | |
76 | class Tester(unittest.TestCase): |
|
76 | class Tester(unittest.TestCase): | |
77 | def test(self): |
|
77 | def test(self): | |
78 | func() |
|
78 | func() | |
79 |
|
79 | |||
80 | Tester.__name__ = func.__name__ |
|
80 | Tester.__name__ = func.__name__ | |
81 |
|
81 | |||
82 | return Tester |
|
82 | return Tester | |
83 |
|
83 | |||
84 | # Utility functions |
|
84 | # Utility functions | |
85 |
|
85 | |||
86 | def apply_wrapper(wrapper,func): |
|
86 | def apply_wrapper(wrapper,func): | |
87 | """Apply a wrapper to a function for decoration. |
|
87 | """Apply a wrapper to a function for decoration. | |
88 |
|
88 | |||
89 | This mixes Michele Simionato's decorator tool with nose's make_decorator, |
|
89 | This mixes Michele Simionato's decorator tool with nose's make_decorator, | |
90 | to apply a wrapper in a decorator so that all nose attributes, as well as |
|
90 | to apply a wrapper in a decorator so that all nose attributes, as well as | |
91 | function signature and other properties, survive the decoration cleanly. |
|
91 | function signature and other properties, survive the decoration cleanly. | |
92 | This will ensure that wrapped functions can still be well introspected via |
|
92 | This will ensure that wrapped functions can still be well introspected via | |
93 | IPython, for example. |
|
93 | IPython, for example. | |
94 | """ |
|
94 | """ | |
95 | import nose.tools |
|
95 | import nose.tools | |
96 |
|
96 | |||
97 | return decorator(wrapper,nose.tools.make_decorator(func)(wrapper)) |
|
97 | return decorator(wrapper,nose.tools.make_decorator(func)(wrapper)) | |
98 |
|
98 | |||
99 |
|
99 | |||
100 | def make_label_dec(label,ds=None): |
|
100 | def make_label_dec(label,ds=None): | |
101 | """Factory function to create a decorator that applies one or more labels. |
|
101 | """Factory function to create a decorator that applies one or more labels. | |
102 |
|
102 | |||
103 | Parameters |
|
103 | Parameters | |
104 | ---------- |
|
104 | ---------- | |
105 | label : string or sequence |
|
105 | label : string or sequence | |
106 | One or more labels that will be applied by the decorator to the functions |
|
106 | One or more labels that will be applied by the decorator to the functions | |
107 | it decorates. Labels are attributes of the decorated function with their |
|
107 | it decorates. Labels are attributes of the decorated function with their | |
108 | value set to True. |
|
108 | value set to True. | |
109 |
|
109 | |||
110 | ds : string |
|
110 | ds : string | |
111 | An optional docstring for the resulting decorator. If not given, a |
|
111 | An optional docstring for the resulting decorator. If not given, a | |
112 | default docstring is auto-generated. |
|
112 | default docstring is auto-generated. | |
113 |
|
113 | |||
114 | Returns |
|
114 | Returns | |
115 | ------- |
|
115 | ------- | |
116 | A decorator. |
|
116 | A decorator. | |
117 |
|
117 | |||
118 | Examples |
|
118 | Examples | |
119 | -------- |
|
119 | -------- | |
120 |
|
120 | |||
121 | A simple labeling decorator: |
|
121 | A simple labeling decorator: | |
122 |
|
122 | |||
123 | >>> slow = make_label_dec('slow') |
|
123 | >>> slow = make_label_dec('slow') | |
124 | >>> slow.__doc__ |
|
124 | >>> slow.__doc__ | |
125 | "Labels a test as 'slow'." |
|
125 | "Labels a test as 'slow'." | |
126 |
|
126 | |||
127 | And one that uses multiple labels and a custom docstring: |
|
127 | And one that uses multiple labels and a custom docstring: | |
128 |
|
128 | |||
129 | >>> rare = make_label_dec(['slow','hard'], |
|
129 | >>> rare = make_label_dec(['slow','hard'], | |
130 | ... "Mix labels 'slow' and 'hard' for rare tests.") |
|
130 | ... "Mix labels 'slow' and 'hard' for rare tests.") | |
131 | >>> rare.__doc__ |
|
131 | >>> rare.__doc__ | |
132 | "Mix labels 'slow' and 'hard' for rare tests." |
|
132 | "Mix labels 'slow' and 'hard' for rare tests." | |
133 |
|
133 | |||
134 | Now, let's test using this one: |
|
134 | Now, let's test using this one: | |
135 | >>> @rare |
|
135 | >>> @rare | |
136 | ... def f(): pass |
|
136 | ... def f(): pass | |
137 | ... |
|
137 | ... | |
138 | >>> |
|
138 | >>> | |
139 | >>> f.slow |
|
139 | >>> f.slow | |
140 | True |
|
140 | True | |
141 | >>> f.hard |
|
141 | >>> f.hard | |
142 | True |
|
142 | True | |
143 | """ |
|
143 | """ | |
144 |
|
144 | |||
145 | if isinstance(label, string_types): |
|
145 | if isinstance(label, string_types): | |
146 | labels = [label] |
|
146 | labels = [label] | |
147 | else: |
|
147 | else: | |
148 | labels = label |
|
148 | labels = label | |
149 |
|
149 | |||
150 | # Validate that the given label(s) are OK for use in setattr() by doing a |
|
150 | # Validate that the given label(s) are OK for use in setattr() by doing a | |
151 | # dry run on a dummy function. |
|
151 | # dry run on a dummy function. | |
152 | tmp = lambda : None |
|
152 | tmp = lambda : None | |
153 | for label in labels: |
|
153 | for label in labels: | |
154 | setattr(tmp,label,True) |
|
154 | setattr(tmp,label,True) | |
155 |
|
155 | |||
156 | # This is the actual decorator we'll return |
|
156 | # This is the actual decorator we'll return | |
157 | def decor(f): |
|
157 | def decor(f): | |
158 | for label in labels: |
|
158 | for label in labels: | |
159 | setattr(f,label,True) |
|
159 | setattr(f,label,True) | |
160 | return f |
|
160 | return f | |
161 |
|
161 | |||
162 | # Apply the user's docstring, or autogenerate a basic one |
|
162 | # Apply the user's docstring, or autogenerate a basic one | |
163 | if ds is None: |
|
163 | if ds is None: | |
164 | ds = "Labels a test as %r." % label |
|
164 | ds = "Labels a test as %r." % label | |
165 | decor.__doc__ = ds |
|
165 | decor.__doc__ = ds | |
166 |
|
166 | |||
167 | return decor |
|
167 | return decor | |
168 |
|
168 | |||
169 |
|
169 | |||
170 | # Inspired by numpy's skipif, but uses the full apply_wrapper utility to |
|
170 | # Inspired by numpy's skipif, but uses the full apply_wrapper utility to | |
171 | # preserve function metadata better and allows the skip condition to be a |
|
171 | # preserve function metadata better and allows the skip condition to be a | |
172 | # callable. |
|
172 | # callable. | |
173 | def skipif(skip_condition, msg=None): |
|
173 | def skipif(skip_condition, msg=None): | |
174 | ''' Make function raise SkipTest exception if skip_condition is true |
|
174 | ''' Make function raise SkipTest exception if skip_condition is true | |
175 |
|
175 | |||
176 | Parameters |
|
176 | Parameters | |
177 | ---------- |
|
177 | ---------- | |
178 | skip_condition : bool or callable. |
|
178 | ||
|
179 | skip_condition : bool or callable | |||
179 |
|
|
180 | Flag to determine whether to skip test. If the condition is a | |
180 |
|
|
181 | callable, it is used at runtime to dynamically make the decision. This | |
181 |
|
|
182 | is useful for tests that may require costly imports, to delay the cost | |
182 |
|
|
183 | until the test suite is actually executed. | |
183 | msg : string |
|
184 | msg : string | |
184 |
|
|
185 | Message to give on raising a SkipTest exception. | |
185 |
|
186 | |||
186 | Returns |
|
187 | Returns | |
187 | ------- |
|
188 | ------- | |
188 | decorator : function |
|
189 | decorator : function | |
189 |
|
|
190 | Decorator, which, when applied to a function, causes SkipTest | |
190 |
|
|
191 | to be raised when the skip_condition was True, and the function | |
191 |
|
|
192 | to be called normally otherwise. | |
192 |
|
193 | |||
193 | Notes |
|
194 | Notes | |
194 | ----- |
|
195 | ----- | |
195 | You will see from the code that we had to further decorate the |
|
196 | You will see from the code that we had to further decorate the | |
196 | decorator with the nose.tools.make_decorator function in order to |
|
197 | decorator with the nose.tools.make_decorator function in order to | |
197 | transmit function name, and various other metadata. |
|
198 | transmit function name, and various other metadata. | |
198 | ''' |
|
199 | ''' | |
199 |
|
200 | |||
200 | def skip_decorator(f): |
|
201 | def skip_decorator(f): | |
201 | # Local import to avoid a hard nose dependency and only incur the |
|
202 | # Local import to avoid a hard nose dependency and only incur the | |
202 | # import time overhead at actual test-time. |
|
203 | # import time overhead at actual test-time. | |
203 | import nose |
|
204 | import nose | |
204 |
|
205 | |||
205 | # Allow for both boolean or callable skip conditions. |
|
206 | # Allow for both boolean or callable skip conditions. | |
206 | if callable(skip_condition): |
|
207 | if callable(skip_condition): | |
207 | skip_val = skip_condition |
|
208 | skip_val = skip_condition | |
208 | else: |
|
209 | else: | |
209 | skip_val = lambda : skip_condition |
|
210 | skip_val = lambda : skip_condition | |
210 |
|
211 | |||
211 | def get_msg(func,msg=None): |
|
212 | def get_msg(func,msg=None): | |
212 | """Skip message with information about function being skipped.""" |
|
213 | """Skip message with information about function being skipped.""" | |
213 | if msg is None: out = 'Test skipped due to test condition.' |
|
214 | if msg is None: out = 'Test skipped due to test condition.' | |
214 | else: out = msg |
|
215 | else: out = msg | |
215 | return "Skipping test: %s. %s" % (func.__name__,out) |
|
216 | return "Skipping test: %s. %s" % (func.__name__,out) | |
216 |
|
217 | |||
217 | # We need to define *two* skippers because Python doesn't allow both |
|
218 | # We need to define *two* skippers because Python doesn't allow both | |
218 | # return with value and yield inside the same function. |
|
219 | # return with value and yield inside the same function. | |
219 | def skipper_func(*args, **kwargs): |
|
220 | def skipper_func(*args, **kwargs): | |
220 | """Skipper for normal test functions.""" |
|
221 | """Skipper for normal test functions.""" | |
221 | if skip_val(): |
|
222 | if skip_val(): | |
222 | raise nose.SkipTest(get_msg(f,msg)) |
|
223 | raise nose.SkipTest(get_msg(f,msg)) | |
223 | else: |
|
224 | else: | |
224 | return f(*args, **kwargs) |
|
225 | return f(*args, **kwargs) | |
225 |
|
226 | |||
226 | def skipper_gen(*args, **kwargs): |
|
227 | def skipper_gen(*args, **kwargs): | |
227 | """Skipper for test generators.""" |
|
228 | """Skipper for test generators.""" | |
228 | if skip_val(): |
|
229 | if skip_val(): | |
229 | raise nose.SkipTest(get_msg(f,msg)) |
|
230 | raise nose.SkipTest(get_msg(f,msg)) | |
230 | else: |
|
231 | else: | |
231 | for x in f(*args, **kwargs): |
|
232 | for x in f(*args, **kwargs): | |
232 | yield x |
|
233 | yield x | |
233 |
|
234 | |||
234 | # Choose the right skipper to use when building the actual generator. |
|
235 | # Choose the right skipper to use when building the actual generator. | |
235 | if nose.util.isgenerator(f): |
|
236 | if nose.util.isgenerator(f): | |
236 | skipper = skipper_gen |
|
237 | skipper = skipper_gen | |
237 | else: |
|
238 | else: | |
238 | skipper = skipper_func |
|
239 | skipper = skipper_func | |
239 |
|
240 | |||
240 | return nose.tools.make_decorator(f)(skipper) |
|
241 | return nose.tools.make_decorator(f)(skipper) | |
241 |
|
242 | |||
242 | return skip_decorator |
|
243 | return skip_decorator | |
243 |
|
244 | |||
244 | # A version with the condition set to true, common case just to attach a message |
|
245 | # A version with the condition set to true, common case just to attach a message | |
245 | # to a skip decorator |
|
246 | # to a skip decorator | |
246 | def skip(msg=None): |
|
247 | def skip(msg=None): | |
247 | """Decorator factory - mark a test function for skipping from test suite. |
|
248 | """Decorator factory - mark a test function for skipping from test suite. | |
248 |
|
249 | |||
249 | Parameters |
|
250 | Parameters | |
250 | ---------- |
|
251 | ---------- | |
251 | msg : string |
|
252 | msg : string | |
252 | Optional message to be added. |
|
253 | Optional message to be added. | |
253 |
|
254 | |||
254 | Returns |
|
255 | Returns | |
255 | ------- |
|
256 | ------- | |
256 | decorator : function |
|
257 | decorator : function | |
257 | Decorator, which, when applied to a function, causes SkipTest |
|
258 | Decorator, which, when applied to a function, causes SkipTest | |
258 | to be raised, with the optional message added. |
|
259 | to be raised, with the optional message added. | |
259 | """ |
|
260 | """ | |
260 |
|
261 | |||
261 | return skipif(True,msg) |
|
262 | return skipif(True,msg) | |
262 |
|
263 | |||
263 |
|
264 | |||
264 | def onlyif(condition, msg): |
|
265 | def onlyif(condition, msg): | |
265 | """The reverse from skipif, see skipif for details.""" |
|
266 | """The reverse from skipif, see skipif for details.""" | |
266 |
|
267 | |||
267 | if callable(condition): |
|
268 | if callable(condition): | |
268 | skip_condition = lambda : not condition() |
|
269 | skip_condition = lambda : not condition() | |
269 | else: |
|
270 | else: | |
270 | skip_condition = lambda : not condition |
|
271 | skip_condition = lambda : not condition | |
271 |
|
272 | |||
272 | return skipif(skip_condition, msg) |
|
273 | return skipif(skip_condition, msg) | |
273 |
|
274 | |||
274 | #----------------------------------------------------------------------------- |
|
275 | #----------------------------------------------------------------------------- | |
275 | # Utility functions for decorators |
|
276 | # Utility functions for decorators | |
276 | def module_not_available(module): |
|
277 | def module_not_available(module): | |
277 | """Can module be imported? Returns true if module does NOT import. |
|
278 | """Can module be imported? Returns true if module does NOT import. | |
278 |
|
279 | |||
279 | This is used to make a decorator to skip tests that require module to be |
|
280 | This is used to make a decorator to skip tests that require module to be | |
280 | available, but delay the 'import numpy' to test execution time. |
|
281 | available, but delay the 'import numpy' to test execution time. | |
281 | """ |
|
282 | """ | |
282 | try: |
|
283 | try: | |
283 | mod = __import__(module) |
|
284 | mod = __import__(module) | |
284 | mod_not_avail = False |
|
285 | mod_not_avail = False | |
285 | except ImportError: |
|
286 | except ImportError: | |
286 | mod_not_avail = True |
|
287 | mod_not_avail = True | |
287 |
|
288 | |||
288 | return mod_not_avail |
|
289 | return mod_not_avail | |
289 |
|
290 | |||
290 |
|
291 | |||
291 | def decorated_dummy(dec, name): |
|
292 | def decorated_dummy(dec, name): | |
292 | """Return a dummy function decorated with dec, with the given name. |
|
293 | """Return a dummy function decorated with dec, with the given name. | |
293 |
|
294 | |||
294 | Examples |
|
295 | Examples | |
295 | -------- |
|
296 | -------- | |
296 | import IPython.testing.decorators as dec |
|
297 | import IPython.testing.decorators as dec | |
297 | setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__) |
|
298 | setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__) | |
298 | """ |
|
299 | """ | |
299 | dummy = lambda: None |
|
300 | dummy = lambda: None | |
300 | dummy.__name__ = name |
|
301 | dummy.__name__ = name | |
301 | return dec(dummy) |
|
302 | return dec(dummy) | |
302 |
|
303 | |||
303 | #----------------------------------------------------------------------------- |
|
304 | #----------------------------------------------------------------------------- | |
304 | # Decorators for public use |
|
305 | # Decorators for public use | |
305 |
|
306 | |||
306 | # Decorators to skip certain tests on specific platforms. |
|
307 | # Decorators to skip certain tests on specific platforms. | |
307 | skip_win32 = skipif(sys.platform == 'win32', |
|
308 | skip_win32 = skipif(sys.platform == 'win32', | |
308 | "This test does not run under Windows") |
|
309 | "This test does not run under Windows") | |
309 | skip_linux = skipif(sys.platform.startswith('linux'), |
|
310 | skip_linux = skipif(sys.platform.startswith('linux'), | |
310 | "This test does not run under Linux") |
|
311 | "This test does not run under Linux") | |
311 | skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X") |
|
312 | skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X") | |
312 |
|
313 | |||
313 |
|
314 | |||
314 | # Decorators to skip tests if not on specific platforms. |
|
315 | # Decorators to skip tests if not on specific platforms. | |
315 | skip_if_not_win32 = skipif(sys.platform != 'win32', |
|
316 | skip_if_not_win32 = skipif(sys.platform != 'win32', | |
316 | "This test only runs under Windows") |
|
317 | "This test only runs under Windows") | |
317 | skip_if_not_linux = skipif(not sys.platform.startswith('linux'), |
|
318 | skip_if_not_linux = skipif(not sys.platform.startswith('linux'), | |
318 | "This test only runs under Linux") |
|
319 | "This test only runs under Linux") | |
319 | skip_if_not_osx = skipif(sys.platform != 'darwin', |
|
320 | skip_if_not_osx = skipif(sys.platform != 'darwin', | |
320 | "This test only runs under OSX") |
|
321 | "This test only runs under OSX") | |
321 |
|
322 | |||
322 |
|
323 | |||
323 | _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and |
|
324 | _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and | |
324 | os.environ.get('DISPLAY', '') == '') |
|
325 | os.environ.get('DISPLAY', '') == '') | |
325 | _x11_skip_msg = "Skipped under *nix when X11/XOrg not available" |
|
326 | _x11_skip_msg = "Skipped under *nix when X11/XOrg not available" | |
326 |
|
327 | |||
327 | skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg) |
|
328 | skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg) | |
328 |
|
329 | |||
329 | # not a decorator itself, returns a dummy function to be used as setup |
|
330 | # not a decorator itself, returns a dummy function to be used as setup | |
330 | def skip_file_no_x11(name): |
|
331 | def skip_file_no_x11(name): | |
331 | return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None |
|
332 | return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None | |
332 |
|
333 | |||
333 | # Other skip decorators |
|
334 | # Other skip decorators | |
334 |
|
335 | |||
335 | # generic skip without module |
|
336 | # generic skip without module | |
336 | skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod) |
|
337 | skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod) | |
337 |
|
338 | |||
338 | skipif_not_numpy = skip_without('numpy') |
|
339 | skipif_not_numpy = skip_without('numpy') | |
339 |
|
340 | |||
340 | skipif_not_matplotlib = skip_without('matplotlib') |
|
341 | skipif_not_matplotlib = skip_without('matplotlib') | |
341 |
|
342 | |||
342 | skipif_not_sympy = skip_without('sympy') |
|
343 | skipif_not_sympy = skip_without('sympy') | |
343 |
|
344 | |||
344 | skip_known_failure = knownfailureif(True,'This test is known to fail') |
|
345 | skip_known_failure = knownfailureif(True,'This test is known to fail') | |
345 |
|
346 | |||
346 | known_failure_py3 = knownfailureif(sys.version_info[0] >= 3, |
|
347 | known_failure_py3 = knownfailureif(sys.version_info[0] >= 3, | |
347 | 'This test is known to fail on Python 3.') |
|
348 | 'This test is known to fail on Python 3.') | |
348 |
|
349 | |||
349 | # A null 'decorator', useful to make more readable code that needs to pick |
|
350 | # A null 'decorator', useful to make more readable code that needs to pick | |
350 | # between different decorators based on OS or other conditions |
|
351 | # between different decorators based on OS or other conditions | |
351 | null_deco = lambda f: f |
|
352 | null_deco = lambda f: f | |
352 |
|
353 | |||
353 | # Some tests only run where we can use unicode paths. Note that we can't just |
|
354 | # Some tests only run where we can use unicode paths. Note that we can't just | |
354 | # check os.path.supports_unicode_filenames, which is always False on Linux. |
|
355 | # check os.path.supports_unicode_filenames, which is always False on Linux. | |
355 | try: |
|
356 | try: | |
356 | f = tempfile.NamedTemporaryFile(prefix=u"tmpβ¬") |
|
357 | f = tempfile.NamedTemporaryFile(prefix=u"tmpβ¬") | |
357 | except UnicodeEncodeError: |
|
358 | except UnicodeEncodeError: | |
358 | unicode_paths = False |
|
359 | unicode_paths = False | |
359 | else: |
|
360 | else: | |
360 | unicode_paths = True |
|
361 | unicode_paths = True | |
361 | f.close() |
|
362 | f.close() | |
362 |
|
363 | |||
363 | onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable " |
|
364 | onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable " | |
364 | "where we can use unicode in filenames.")) |
|
365 | "where we can use unicode in filenames.")) | |
365 |
|
366 | |||
366 |
|
367 | |||
367 | def onlyif_cmds_exist(*commands): |
|
368 | def onlyif_cmds_exist(*commands): | |
368 | """ |
|
369 | """ | |
369 | Decorator to skip test when at least one of `commands` is not found. |
|
370 | Decorator to skip test when at least one of `commands` is not found. | |
370 | """ |
|
371 | """ | |
371 | for cmd in commands: |
|
372 | for cmd in commands: | |
372 | try: |
|
373 | try: | |
373 | if not is_cmd_found(cmd): |
|
374 | if not is_cmd_found(cmd): | |
374 | return skip("This test runs only if command '{0}' " |
|
375 | return skip("This test runs only if command '{0}' " | |
375 | "is installed".format(cmd)) |
|
376 | "is installed".format(cmd)) | |
376 | except ImportError as e: |
|
377 | except ImportError as e: | |
377 | # is_cmd_found uses pywin32 on windows, which might not be available |
|
378 | # is_cmd_found uses pywin32 on windows, which might not be available | |
378 | if sys.platform == 'win32' and 'pywin32' in str(e): |
|
379 | if sys.platform == 'win32' and 'pywin32' in str(e): | |
379 | return skip("This test runs only if pywin32 and command '{0}' " |
|
380 | return skip("This test runs only if pywin32 and command '{0}' " | |
380 | "is installed".format(cmd)) |
|
381 | "is installed".format(cmd)) | |
381 | raise e |
|
382 | raise e | |
382 | return null_deco |
|
383 | return null_deco |
@@ -1,621 +1,621 b'' | |||||
1 | .. _issues_list_012: |
|
1 | .. _issues_list_012: | |
2 |
|
2 | |||
3 | Issues closed in the 0.12 development cycle |
|
3 | Issues closed in the 0.12 development cycle | |
4 | =========================================== |
|
4 | =========================================== | |
5 |
|
5 | |||
6 | Issues closed in 0.12.1 |
|
6 | Issues closed in 0.12.1 | |
7 | ----------------------- |
|
7 | ----------------------- | |
8 |
|
8 | |||
9 | GitHub stats for bugfix release 0.12.1 (12/28/2011-04/16/2012), backporting |
|
9 | GitHub stats for bugfix release 0.12.1 (12/28/2011-04/16/2012), backporting | |
10 | pull requests from 0.13. |
|
10 | pull requests from 0.13. | |
11 |
|
11 | |||
12 | We closed a total of 71 issues: 44 pull requests and 27 issues; this is the |
|
12 | We closed a total of 71 issues: 44 pull requests and 27 issues; this is the | |
13 | full list (generated with the script `tools/github_stats.py`). |
|
13 | full list (generated with the script `tools/github_stats.py`). | |
14 |
|
14 | |||
15 | This list is automatically generated, and may be incomplete: |
|
15 | This list is automatically generated, and may be incomplete: | |
16 |
|
16 | |||
17 | Pull Requests (44): |
|
17 | Pull Requests (44): | |
18 |
|
18 | |||
19 | * :ghpull:`1175`: core.completer: Clean up excessive and unused code. |
|
19 | * :ghpull:`1175`: core.completer: Clean up excessive and unused code. | |
20 | * :ghpull:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush |
|
20 | * :ghpull:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush | |
21 | * :ghpull:`1190`: Fix link to Chris Fonnesbeck blog post about 0.11 highlights. |
|
21 | * :ghpull:`1190`: Fix link to Chris Fonnesbeck blog post about 0.11 highlights. | |
22 | * :ghpull:`1196`: docs: looks like a file path might have been accidentally pasted in the middle of a word |
|
22 | * :ghpull:`1196`: docs: looks like a file path might have been accidentally pasted in the middle of a word | |
23 | * :ghpull:`1206`: don't preserve fixConsole output in json |
|
23 | * :ghpull:`1206`: don't preserve fixConsole output in json | |
24 | * :ghpull:`1207`: fix loadpy duplicating newlines |
|
24 | * :ghpull:`1207`: fix loadpy duplicating newlines | |
25 | * :ghpull:`1213`: BUG: Minor typo in history_console_widget.py |
|
25 | * :ghpull:`1213`: BUG: Minor typo in history_console_widget.py | |
26 | * :ghpull:`1218`: Added -q option to %prun for suppression of the output, along with editing the dochelp string. |
|
26 | * :ghpull:`1218`: Added -q option to %prun for suppression of the output, along with editing the dochelp string. | |
27 | * :ghpull:`1222`: allow Reference as callable in map/apply |
|
27 | * :ghpull:`1222`: allow Reference as callable in map/apply | |
28 | * :ghpull:`1229`: Fix display of SyntaxError in Python 3 |
|
28 | * :ghpull:`1229`: Fix display of SyntaxError in Python 3 | |
29 | * :ghpull:`1246`: Skip tests that require X, when importing pylab results in RuntimeError. |
|
29 | * :ghpull:`1246`: Skip tests that require X, when importing pylab results in RuntimeError. | |
30 | * :ghpull:`1253`: set auto_create flag for notebook apps |
|
30 | * :ghpull:`1253`: set auto_create flag for notebook apps | |
31 | * :ghpull:`1257`: use self.kernel_manager_class in qtconsoleapp |
|
31 | * :ghpull:`1257`: use self.kernel_manager_class in qtconsoleapp | |
32 | * :ghpull:`1262`: Heartbeat no longer shares the app's Context |
|
32 | * :ghpull:`1262`: Heartbeat no longer shares the app's Context | |
33 | * :ghpull:`1283`: HeartMonitor.period should be an Integer |
|
33 | * :ghpull:`1283`: HeartMonitor.period should be an Integer | |
34 | * :ghpull:`1284`: a fix for GH 1269 |
|
34 | * :ghpull:`1284`: a fix for GH 1269 | |
35 | * :ghpull:`1289`: Make autoreload extension work on Python 3. |
|
35 | * :ghpull:`1289`: Make autoreload extension work on Python 3. | |
36 | * :ghpull:`1306`: Fix %prun input parsing for escaped characters (closes #1302) |
|
36 | * :ghpull:`1306`: Fix %prun input parsing for escaped characters (closes #1302) | |
37 | * :ghpull:`1312`: minor heartbeat tweaks |
|
37 | * :ghpull:`1312`: minor heartbeat tweaks | |
38 | * :ghpull:`1318`: make Ctrl-D in qtconsole act same as in terminal (ready to merge) |
|
38 | * :ghpull:`1318`: make Ctrl-D in qtconsole act same as in terminal (ready to merge) | |
39 | * :ghpull:`1341`: Don't attempt to tokenize binary files for tracebacks |
|
39 | * :ghpull:`1341`: Don't attempt to tokenize binary files for tracebacks | |
40 | * :ghpull:`1353`: Save notebook as script using unicode file handle. |
|
40 | * :ghpull:`1353`: Save notebook as script using unicode file handle. | |
41 | * :ghpull:`1363`: Fix some minor color/style config issues in the qtconsole |
|
41 | * :ghpull:`1363`: Fix some minor color/style config issues in the qtconsole | |
42 | * :ghpull:`1364`: avoid jsonlib returning Decimal |
|
42 | * :ghpull:`1364`: avoid jsonlib returning Decimal | |
43 | * :ghpull:`1369`: load header with engine id when engine dies in TaskScheduler |
|
43 | * :ghpull:`1369`: load header with engine id when engine dies in TaskScheduler | |
44 | * :ghpull:`1370`: allow draft76 websockets (Safari) |
|
44 | * :ghpull:`1370`: allow draft76 websockets (Safari) | |
45 | * :ghpull:`1374`: remove calls to meaningless ZMQStream.on_err |
|
45 | * :ghpull:`1374`: remove calls to meaningless ZMQStream.on_err | |
46 | * :ghpull:`1377`: Saving non-ascii history |
|
46 | * :ghpull:`1377`: Saving non-ascii history | |
47 | * :ghpull:`1396`: Fix for %tb magic. |
|
47 | * :ghpull:`1396`: Fix for %tb magic. | |
48 | * :ghpull:`1402`: fix symlinked /home issue for FreeBSD |
|
48 | * :ghpull:`1402`: fix symlinked /home issue for FreeBSD | |
49 | * :ghpull:`1413`: get_home_dir expands symlinks, adjust test accordingly |
|
49 | * :ghpull:`1413`: get_home_dir expands symlinks, adjust test accordingly | |
50 | * :ghpull:`1414`: ignore errors in shell.var_expand |
|
50 | * :ghpull:`1414`: ignore errors in shell.var_expand | |
51 | * :ghpull:`1430`: Fix for tornado check for tornado < 1.1.0 |
|
51 | * :ghpull:`1430`: Fix for tornado check for tornado < 1.1.0 | |
52 | * :ghpull:`1445`: Don't build sphinx docs for sdists |
|
52 | * :ghpull:`1445`: Don't build sphinx docs for sdists | |
53 | * :ghpull:`1463`: Fix completion when importing modules in the cwd. |
|
53 | * :ghpull:`1463`: Fix completion when importing modules in the cwd. | |
54 | * :ghpull:`1477`: fix dangling `buffer` in IPython.parallel.util |
|
54 | * :ghpull:`1477`: fix dangling `buffer` in IPython.parallel.util | |
55 | * :ghpull:`1495`: BUG: Fix pretty-printing for overzealous objects |
|
55 | * :ghpull:`1495`: BUG: Fix pretty-printing for overzealous objects | |
56 | * :ghpull:`1496`: BUG: LBYL when clearing the output history on shutdown. |
|
56 | * :ghpull:`1496`: BUG: LBYL when clearing the output history on shutdown. | |
57 | * :ghpull:`1514`: DOC: Fix references to IPython.lib.pretty instead of the old location |
|
57 | * :ghpull:`1514`: DOC: Fix references to IPython.lib.pretty instead of the old location | |
58 | * :ghpull:`1517`: Fix indentation bug in IPython/lib/pretty.py |
|
58 | * :ghpull:`1517`: Fix indentation bug in IPython/lib/pretty.py | |
59 | * :ghpull:`1538`: store git commit hash in utils._sysinfo instead of hidden data file |
|
59 | * :ghpull:`1538`: store git commit hash in utils._sysinfo instead of hidden data file | |
60 | * :ghpull:`1599`: Fix for %run -d in Python 3 |
|
60 | * :ghpull:`1599`: Fix for %run -d in Python 3 | |
61 | * :ghpull:`1602`: Fix %env for Python 3 |
|
61 | * :ghpull:`1602`: Fix %env for Python 3 | |
62 | * :ghpull:`1607`: cleanup sqlitedb temporary db file after tests |
|
62 | * :ghpull:`1607`: cleanup sqlitedb temporary db file after tests | |
63 |
|
63 | |||
64 | Issues (27): |
|
64 | Issues (27): | |
65 |
|
65 | |||
66 | * :ghissue:`676`: IPython.embed() from ipython crashes twice on exit |
|
66 | * :ghissue:`676`: IPython.embed() from ipython crashes twice on exit | |
67 | * :ghissue:`846`: Autoreload extension doesn't work with Python 3.2 |
|
67 | * :ghissue:`846`: Autoreload extension doesn't work with Python 3.2 | |
68 | * :ghissue:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush |
|
68 | * :ghissue:`1187`: misc notebook: connection file cleanup, first heartbeat, startup flush | |
69 | * :ghissue:`1191`: profile/startup files not executed with "notebook" |
|
69 | * :ghissue:`1191`: profile/startup files not executed with "notebook" | |
70 | * :ghissue:`1197`: Interactive shell trying to: from ... import history |
|
70 | * :ghissue:`1197`: Interactive shell trying to: from ... import history | |
71 | * :ghissue:`1198`: Kernel Has Died error in Notebook |
|
71 | * :ghissue:`1198`: Kernel Has Died error in Notebook | |
72 | * :ghissue:`1201`: %env magic fails with Python 3.2 |
|
72 | * :ghissue:`1201`: %env magic fails with Python 3.2 | |
73 | * :ghissue:`1204`: double newline from %loadpy in python notebook (at least on mac) |
|
73 | * :ghissue:`1204`: double newline from %loadpy in python notebook (at least on mac) | |
74 | * :ghissue:`1208`: should dv.sync_import print failed imports ? |
|
74 | * :ghissue:`1208`: should dv.sync_import print failed imports ? | |
75 | * :ghissue:`1225`: SyntaxError display broken in Python 3 |
|
75 | * :ghissue:`1225`: SyntaxError display broken in Python 3 | |
76 | * :ghissue:`1232`: Dead kernel loop |
|
76 | * :ghissue:`1232`: Dead kernel loop | |
77 | * :ghissue:`1241`: When our debugger class is used standalone `_oh` key errors are thrown |
|
77 | * :ghissue:`1241`: When our debugger class is used standalone `_oh` key errors are thrown | |
78 | * :ghissue:`1254`: typo in notebooklist.js breaks links |
|
78 | * :ghissue:`1254`: typo in notebooklist.js breaks links | |
79 | * :ghissue:`1260`: heartbeat failure on long gil-holding operation |
|
79 | * :ghissue:`1260`: heartbeat failure on long gil-holding operation | |
80 | * :ghissue:`1268`: notebook %reset magic fails with StdinNotImplementedError |
|
80 | * :ghissue:`1268`: notebook %reset magic fails with StdinNotImplementedError | |
81 | * :ghissue:`1269`: Another strange input handling error |
|
81 | * :ghissue:`1269`: Another strange input handling error | |
82 | * :ghissue:`1281`: in Hub: registration_timeout must be an integer, but heartmonitor.period is CFloat |
|
82 | * :ghissue:`1281`: in Hub: registration_timeout must be an integer, but heartmonitor.period is CFloat | |
83 | * :ghissue:`1302`: Input parsing with %prun clobbers escapes |
|
83 | * :ghissue:`1302`: Input parsing with %prun clobbers escapes | |
84 | * :ghissue:`1304`: controller/server load can disrupt heartbeat |
|
84 | * :ghissue:`1304`: controller/server load can disrupt heartbeat | |
85 | * :ghissue:`1317`: Very slow traceback construction from Cython extension |
|
85 | * :ghissue:`1317`: Very slow traceback construction from Cython extension | |
86 | * :ghissue:`1345`: notebook can't save unicode as script |
|
86 | * :ghissue:`1345`: notebook can't save unicode as script | |
87 | * :ghissue:`1375`: %history -g -f file encoding issue |
|
87 | * :ghissue:`1375`: %history -g -f file encoding issue | |
88 | * :ghissue:`1401`: numpy arrays cannot be used with View.apply() in Python 3 |
|
88 | * :ghissue:`1401`: numpy arrays cannot be used with View.apply() in Python 3 | |
89 | * :ghissue:`1408`: test_get_home_dir_3 failed on Mac OS X |
|
89 | * :ghissue:`1408`: test_get_home_dir_3 failed on Mac OS X | |
90 | * :ghissue:`1412`: Input parsing issue with %prun |
|
90 | * :ghissue:`1412`: Input parsing issue with %prun | |
91 | * :ghissue:`1421`: ipython32 %run -d breaks with NameError name 'execfile' is not defined |
|
91 | * :ghissue:`1421`: ipython32 %run -d breaks with NameError name 'execfile' is not defined | |
92 | * :ghissue:`1484`: unhide .git_commit_info.ini |
|
92 | * :ghissue:`1484`: unhide .git_commit_info.ini | |
93 |
|
93 | |||
94 |
|
94 | |||
95 | Issues closed in 0.12 |
|
95 | Issues closed in 0.12 | |
96 | --------------------- |
|
96 | --------------------- | |
97 |
|
97 | |||
98 | In this cycle, from August 1 to December 28 2011, we closed a total of 515 |
|
98 | In this cycle, from August 1 to December 28 2011, we closed a total of 515 | |
99 | issues, 257 pull requests and 258 regular issues; this is the full list |
|
99 | issues, 257 pull requests and 258 regular issues; this is the full list | |
100 | (generated with the script `tools/github_stats.py`). |
|
100 | (generated with the script `tools/github_stats.py`). | |
101 |
|
101 | |||
102 | Pull requests (257): |
|
102 | Pull requests (257): | |
103 |
|
103 | |||
104 | * `1174 <https://github.com/ipython/ipython/issues/1174>`_: Remove %install_default_config and %install_profiles |
|
104 | * `1174 <https://github.com/ipython/ipython/issues/1174>`_: Remove %install_default_config and %install_profiles | |
105 | * `1178 <https://github.com/ipython/ipython/issues/1178>`_: Correct string type casting in pinfo. |
|
105 | * `1178 <https://github.com/ipython/ipython/issues/1178>`_: Correct string type casting in pinfo. | |
106 | * `1096 <https://github.com/ipython/ipython/issues/1096>`_: Show class init and call tooltips in notebook |
|
106 | * `1096 <https://github.com/ipython/ipython/issues/1096>`_: Show class init and call tooltips in notebook | |
107 | * `1176 <https://github.com/ipython/ipython/issues/1176>`_: Modifications to profile list |
|
107 | * `1176 <https://github.com/ipython/ipython/issues/1176>`_: Modifications to profile list | |
108 | * `1173 <https://github.com/ipython/ipython/issues/1173>`_: don't load gui/pylab in console frontend |
|
108 | * `1173 <https://github.com/ipython/ipython/issues/1173>`_: don't load gui/pylab in console frontend | |
109 | * `1168 <https://github.com/ipython/ipython/issues/1168>`_: Add --script flag as shorthand for notebook save_script option. |
|
109 | * `1168 <https://github.com/ipython/ipython/issues/1168>`_: Add --script flag as shorthand for notebook save_script option. | |
110 | * `1165 <https://github.com/ipython/ipython/issues/1165>`_: encode image_tag as utf8 in [x]html export |
|
110 | * `1165 <https://github.com/ipython/ipython/issues/1165>`_: encode image_tag as utf8 in [x]html export | |
111 | * `1161 <https://github.com/ipython/ipython/issues/1161>`_: Allow %loadpy to load remote URLs that don't end in .py |
|
111 | * `1161 <https://github.com/ipython/ipython/issues/1161>`_: Allow %loadpy to load remote URLs that don't end in .py | |
112 | * `1158 <https://github.com/ipython/ipython/issues/1158>`_: Add coding header when notebook exported to .py file. |
|
112 | * `1158 <https://github.com/ipython/ipython/issues/1158>`_: Add coding header when notebook exported to .py file. | |
113 | * `1160 <https://github.com/ipython/ipython/issues/1160>`_: don't ignore ctrl-C during `%gui qt` |
|
113 | * `1160 <https://github.com/ipython/ipython/issues/1160>`_: don't ignore ctrl-C during `%gui qt` | |
114 | * `1159 <https://github.com/ipython/ipython/issues/1159>`_: Add encoding header to Python files downloaded from notebooks. |
|
114 | * `1159 <https://github.com/ipython/ipython/issues/1159>`_: Add encoding header to Python files downloaded from notebooks. | |
115 | * `1155 <https://github.com/ipython/ipython/issues/1155>`_: minor post-execute fixes (#1154) |
|
115 | * `1155 <https://github.com/ipython/ipython/issues/1155>`_: minor post-execute fixes (#1154) | |
116 | * `1153 <https://github.com/ipython/ipython/issues/1153>`_: Pager tearing bug |
|
116 | * `1153 <https://github.com/ipython/ipython/issues/1153>`_: Pager tearing bug | |
117 | * `1152 <https://github.com/ipython/ipython/issues/1152>`_: Add support for displaying maptlotlib axes directly. |
|
117 | * `1152 <https://github.com/ipython/ipython/issues/1152>`_: Add support for displaying maptlotlib axes directly. | |
118 | * `1079 <https://github.com/ipython/ipython/issues/1079>`_: Login/out button cleanups |
|
118 | * `1079 <https://github.com/ipython/ipython/issues/1079>`_: Login/out button cleanups | |
119 | * `1151 <https://github.com/ipython/ipython/issues/1151>`_: allow access to user_ns in prompt_manager |
|
119 | * `1151 <https://github.com/ipython/ipython/issues/1151>`_: allow access to user_ns in prompt_manager | |
120 | * `1120 <https://github.com/ipython/ipython/issues/1120>`_: updated vim-ipython (pending) |
|
120 | * `1120 <https://github.com/ipython/ipython/issues/1120>`_: updated vim-ipython (pending) | |
121 | * `1150 <https://github.com/ipython/ipython/issues/1150>`_: BUG: Scrolling pager in vsplit on Mac OSX tears. |
|
121 | * `1150 <https://github.com/ipython/ipython/issues/1150>`_: BUG: Scrolling pager in vsplit on Mac OSX tears. | |
122 | * `1149 <https://github.com/ipython/ipython/issues/1149>`_: #1148 (win32 arg_split) |
|
122 | * `1149 <https://github.com/ipython/ipython/issues/1149>`_: #1148 (win32 arg_split) | |
123 | * `1147 <https://github.com/ipython/ipython/issues/1147>`_: Put qtconsole forground when launching |
|
123 | * `1147 <https://github.com/ipython/ipython/issues/1147>`_: Put qtconsole forground when launching | |
124 | * `1146 <https://github.com/ipython/ipython/issues/1146>`_: allow saving notebook.py next to notebook.ipynb |
|
124 | * `1146 <https://github.com/ipython/ipython/issues/1146>`_: allow saving notebook.py next to notebook.ipynb | |
125 | * `1128 <https://github.com/ipython/ipython/issues/1128>`_: fix pylab StartMenu item |
|
125 | * `1128 <https://github.com/ipython/ipython/issues/1128>`_: fix pylab StartMenu item | |
126 | * `1140 <https://github.com/ipython/ipython/issues/1140>`_: Namespaces for embedding |
|
126 | * `1140 <https://github.com/ipython/ipython/issues/1140>`_: Namespaces for embedding | |
127 | * `1132 <https://github.com/ipython/ipython/issues/1132>`_: [notebook] read-only: disable name field |
|
127 | * `1132 <https://github.com/ipython/ipython/issues/1132>`_: [notebook] read-only: disable name field | |
128 | * `1125 <https://github.com/ipython/ipython/issues/1125>`_: notebook : update logo |
|
128 | * `1125 <https://github.com/ipython/ipython/issues/1125>`_: notebook : update logo | |
129 | * `1135 <https://github.com/ipython/ipython/issues/1135>`_: allow customized template and static file paths for the notebook web app |
|
129 | * `1135 <https://github.com/ipython/ipython/issues/1135>`_: allow customized template and static file paths for the notebook web app | |
130 | * `1122 <https://github.com/ipython/ipython/issues/1122>`_: BUG: Issue #755 qt IPythonWidget.execute_file fails if filename contains... |
|
130 | * `1122 <https://github.com/ipython/ipython/issues/1122>`_: BUG: Issue #755 qt IPythonWidget.execute_file fails if filename contains... | |
131 | * `1137 <https://github.com/ipython/ipython/issues/1137>`_: rename MPIExecLaunchers to MPILaunchers |
|
131 | * `1137 <https://github.com/ipython/ipython/issues/1137>`_: rename MPIExecLaunchers to MPILaunchers | |
132 | * `1130 <https://github.com/ipython/ipython/issues/1130>`_: optionally ignore shlex's ValueError in arg_split |
|
132 | * `1130 <https://github.com/ipython/ipython/issues/1130>`_: optionally ignore shlex's ValueError in arg_split | |
133 | * `1116 <https://github.com/ipython/ipython/issues/1116>`_: Shlex unicode |
|
133 | * `1116 <https://github.com/ipython/ipython/issues/1116>`_: Shlex unicode | |
134 | * `1073 <https://github.com/ipython/ipython/issues/1073>`_: Storemagic plugin |
|
134 | * `1073 <https://github.com/ipython/ipython/issues/1073>`_: Storemagic plugin | |
135 | * `1143 <https://github.com/ipython/ipython/issues/1143>`_: Add post_install script to create start menu entries in Python 3 |
|
135 | * `1143 <https://github.com/ipython/ipython/issues/1143>`_: Add post_install script to create start menu entries in Python 3 | |
136 | * `1138 <https://github.com/ipython/ipython/issues/1138>`_: Fix tests to work when ~/.config/ipython contains a symlink. |
|
136 | * `1138 <https://github.com/ipython/ipython/issues/1138>`_: Fix tests to work when ~/.config/ipython contains a symlink. | |
137 | * `1121 <https://github.com/ipython/ipython/issues/1121>`_: Don't transform function calls on IPyAutocall objects |
|
137 | * `1121 <https://github.com/ipython/ipython/issues/1121>`_: Don't transform function calls on IPyAutocall objects | |
138 | * `1118 <https://github.com/ipython/ipython/issues/1118>`_: protect CRLF from carriage-return action |
|
138 | * `1118 <https://github.com/ipython/ipython/issues/1118>`_: protect CRLF from carriage-return action | |
139 | * `1105 <https://github.com/ipython/ipython/issues/1105>`_: Fix for prompts containing newlines. |
|
139 | * `1105 <https://github.com/ipython/ipython/issues/1105>`_: Fix for prompts containing newlines. | |
140 | * `1126 <https://github.com/ipython/ipython/issues/1126>`_: Totally remove pager when read only (notebook) |
|
140 | * `1126 <https://github.com/ipython/ipython/issues/1126>`_: Totally remove pager when read only (notebook) | |
141 | * `1091 <https://github.com/ipython/ipython/issues/1091>`_: qtconsole : allow copy with shortcut in pager |
|
141 | * `1091 <https://github.com/ipython/ipython/issues/1091>`_: qtconsole : allow copy with shortcut in pager | |
142 | * `1114 <https://github.com/ipython/ipython/issues/1114>`_: fix magics history in two-process ipython console |
|
142 | * `1114 <https://github.com/ipython/ipython/issues/1114>`_: fix magics history in two-process ipython console | |
143 |
* `1113 <https://github.com/ipython/ipython/issues/1113>`_: Fixing #1112 removing failing asserts for test_carriage_return and test_ |
|
143 | * `1113 <https://github.com/ipython/ipython/issues/1113>`_: Fixing #1112 removing failing asserts for test_carriage_return and test_beep | |
144 | * `1089 <https://github.com/ipython/ipython/issues/1089>`_: Support carriage return ('\r') and beep ('\b') characters in the qtconsole |
|
144 | * `1089 <https://github.com/ipython/ipython/issues/1089>`_: Support carriage return ('\r') and beep ('\b') characters in the qtconsole | |
145 | * `1108 <https://github.com/ipython/ipython/issues/1108>`_: Completer usability 2 (rebased of pr #1082) |
|
145 | * `1108 <https://github.com/ipython/ipython/issues/1108>`_: Completer usability 2 (rebased of pr #1082) | |
146 | * `864 <https://github.com/ipython/ipython/issues/864>`_: Two-process terminal frontend (ipython core branch) |
|
146 | * `864 <https://github.com/ipython/ipython/issues/864>`_: Two-process terminal frontend (ipython core branch) | |
147 | * `1082 <https://github.com/ipython/ipython/issues/1082>`_: usability and cross browser compat for completer |
|
147 | * `1082 <https://github.com/ipython/ipython/issues/1082>`_: usability and cross browser compat for completer | |
148 | * `1053 <https://github.com/ipython/ipython/issues/1053>`_: minor improvements to text placement in qtconsole |
|
148 | * `1053 <https://github.com/ipython/ipython/issues/1053>`_: minor improvements to text placement in qtconsole | |
149 | * `1106 <https://github.com/ipython/ipython/issues/1106>`_: Fix display of errors in compiled code on Python 3 |
|
149 | * `1106 <https://github.com/ipython/ipython/issues/1106>`_: Fix display of errors in compiled code on Python 3 | |
150 | * `1077 <https://github.com/ipython/ipython/issues/1077>`_: allow the notebook to run without MathJax |
|
150 | * `1077 <https://github.com/ipython/ipython/issues/1077>`_: allow the notebook to run without MathJax | |
151 | * `1072 <https://github.com/ipython/ipython/issues/1072>`_: If object has a getdoc() method, override its normal docstring. |
|
151 | * `1072 <https://github.com/ipython/ipython/issues/1072>`_: If object has a getdoc() method, override its normal docstring. | |
152 | * `1059 <https://github.com/ipython/ipython/issues/1059>`_: Switch to simple `__IPYTHON__` global |
|
152 | * `1059 <https://github.com/ipython/ipython/issues/1059>`_: Switch to simple `__IPYTHON__` global | |
153 | * `1070 <https://github.com/ipython/ipython/issues/1070>`_: Execution count after SyntaxError |
|
153 | * `1070 <https://github.com/ipython/ipython/issues/1070>`_: Execution count after SyntaxError | |
154 | * `1098 <https://github.com/ipython/ipython/issues/1098>`_: notebook: config section UI |
|
154 | * `1098 <https://github.com/ipython/ipython/issues/1098>`_: notebook: config section UI | |
155 | * `1101 <https://github.com/ipython/ipython/issues/1101>`_: workaround spawnb missing from pexpect.__all__ |
|
155 | * `1101 <https://github.com/ipython/ipython/issues/1101>`_: workaround spawnb missing from pexpect.__all__ | |
156 | * `1097 <https://github.com/ipython/ipython/issues/1097>`_: typo, should fix #1095 |
|
156 | * `1097 <https://github.com/ipython/ipython/issues/1097>`_: typo, should fix #1095 | |
157 | * `1099 <https://github.com/ipython/ipython/issues/1099>`_: qtconsole export xhtml/utf8 |
|
157 | * `1099 <https://github.com/ipython/ipython/issues/1099>`_: qtconsole export xhtml/utf8 | |
158 | * `1083 <https://github.com/ipython/ipython/issues/1083>`_: Prompts |
|
158 | * `1083 <https://github.com/ipython/ipython/issues/1083>`_: Prompts | |
159 | * `1081 <https://github.com/ipython/ipython/issues/1081>`_: Fix wildcard search for updated namespaces |
|
159 | * `1081 <https://github.com/ipython/ipython/issues/1081>`_: Fix wildcard search for updated namespaces | |
160 | * `1084 <https://github.com/ipython/ipython/issues/1084>`_: write busy in notebook window title... |
|
160 | * `1084 <https://github.com/ipython/ipython/issues/1084>`_: write busy in notebook window title... | |
161 | * `1078 <https://github.com/ipython/ipython/issues/1078>`_: PromptManager fixes |
|
161 | * `1078 <https://github.com/ipython/ipython/issues/1078>`_: PromptManager fixes | |
162 | * `1064 <https://github.com/ipython/ipython/issues/1064>`_: Win32 shlex |
|
162 | * `1064 <https://github.com/ipython/ipython/issues/1064>`_: Win32 shlex | |
163 | * `1069 <https://github.com/ipython/ipython/issues/1069>`_: As you type completer, fix on Firefox |
|
163 | * `1069 <https://github.com/ipython/ipython/issues/1069>`_: As you type completer, fix on Firefox | |
164 | * `1039 <https://github.com/ipython/ipython/issues/1039>`_: Base of an as you type completer. |
|
164 | * `1039 <https://github.com/ipython/ipython/issues/1039>`_: Base of an as you type completer. | |
165 | * `1065 <https://github.com/ipython/ipython/issues/1065>`_: Qtconsole fix racecondition |
|
165 | * `1065 <https://github.com/ipython/ipython/issues/1065>`_: Qtconsole fix racecondition | |
166 | * `507 <https://github.com/ipython/ipython/issues/507>`_: Prompt manager |
|
166 | * `507 <https://github.com/ipython/ipython/issues/507>`_: Prompt manager | |
167 | * `1056 <https://github.com/ipython/ipython/issues/1056>`_: Warning in code. qtconsole ssh -X |
|
167 | * `1056 <https://github.com/ipython/ipython/issues/1056>`_: Warning in code. qtconsole ssh -X | |
168 | * `1036 <https://github.com/ipython/ipython/issues/1036>`_: Clean up javascript based on js2-mode feedback. |
|
168 | * `1036 <https://github.com/ipython/ipython/issues/1036>`_: Clean up javascript based on js2-mode feedback. | |
169 | * `1052 <https://github.com/ipython/ipython/issues/1052>`_: Pylab fix |
|
169 | * `1052 <https://github.com/ipython/ipython/issues/1052>`_: Pylab fix | |
170 | * `648 <https://github.com/ipython/ipython/issues/648>`_: Usermod |
|
170 | * `648 <https://github.com/ipython/ipython/issues/648>`_: Usermod | |
171 | * `969 <https://github.com/ipython/ipython/issues/969>`_: Pexpect-u |
|
171 | * `969 <https://github.com/ipython/ipython/issues/969>`_: Pexpect-u | |
172 | * `1007 <https://github.com/ipython/ipython/issues/1007>`_: Fix paste/cpaste bug and refactor/cleanup that code a lot. |
|
172 | * `1007 <https://github.com/ipython/ipython/issues/1007>`_: Fix paste/cpaste bug and refactor/cleanup that code a lot. | |
173 | * `506 <https://github.com/ipython/ipython/issues/506>`_: make ENTER on a previous input field replace current input buffer |
|
173 | * `506 <https://github.com/ipython/ipython/issues/506>`_: make ENTER on a previous input field replace current input buffer | |
174 | * `1040 <https://github.com/ipython/ipython/issues/1040>`_: json/jsonapi cleanup |
|
174 | * `1040 <https://github.com/ipython/ipython/issues/1040>`_: json/jsonapi cleanup | |
175 | * `1042 <https://github.com/ipython/ipython/issues/1042>`_: fix firefox (windows) break line on empty prompt number |
|
175 | * `1042 <https://github.com/ipython/ipython/issues/1042>`_: fix firefox (windows) break line on empty prompt number | |
176 | * `1015 <https://github.com/ipython/ipython/issues/1015>`_: emacs freezes when tab is hit in ipython with latest python-mode |
|
176 | * `1015 <https://github.com/ipython/ipython/issues/1015>`_: emacs freezes when tab is hit in ipython with latest python-mode | |
177 | * `1023 <https://github.com/ipython/ipython/issues/1023>`_: flush stdout/stderr at the end of kernel init |
|
177 | * `1023 <https://github.com/ipython/ipython/issues/1023>`_: flush stdout/stderr at the end of kernel init | |
178 | * `956 <https://github.com/ipython/ipython/issues/956>`_: Generate "All magics..." menu live |
|
178 | * `956 <https://github.com/ipython/ipython/issues/956>`_: Generate "All magics..." menu live | |
179 | * `1038 <https://github.com/ipython/ipython/issues/1038>`_: Notebook: don't change cell when selecting code using shift+up/down. |
|
179 | * `1038 <https://github.com/ipython/ipython/issues/1038>`_: Notebook: don't change cell when selecting code using shift+up/down. | |
180 | * `987 <https://github.com/ipython/ipython/issues/987>`_: Add Tooltip to notebook. |
|
180 | * `987 <https://github.com/ipython/ipython/issues/987>`_: Add Tooltip to notebook. | |
181 | * `1028 <https://github.com/ipython/ipython/issues/1028>`_: Cleaner minimum version comparison |
|
181 | * `1028 <https://github.com/ipython/ipython/issues/1028>`_: Cleaner minimum version comparison | |
182 | * `998 <https://github.com/ipython/ipython/issues/998>`_: defer to stdlib for path.get_home_dir() |
|
182 | * `998 <https://github.com/ipython/ipython/issues/998>`_: defer to stdlib for path.get_home_dir() | |
183 | * `1033 <https://github.com/ipython/ipython/issues/1033>`_: update copyright to 2011/20xx-2011 |
|
183 | * `1033 <https://github.com/ipython/ipython/issues/1033>`_: update copyright to 2011/20xx-2011 | |
184 | * `1032 <https://github.com/ipython/ipython/issues/1032>`_: Intercept <esc> avoid closing websocket on Firefox |
|
184 | * `1032 <https://github.com/ipython/ipython/issues/1032>`_: Intercept <esc> avoid closing websocket on Firefox | |
185 | * `1030 <https://github.com/ipython/ipython/issues/1030>`_: use pyzmq tools where appropriate |
|
185 | * `1030 <https://github.com/ipython/ipython/issues/1030>`_: use pyzmq tools where appropriate | |
186 | * `1029 <https://github.com/ipython/ipython/issues/1029>`_: Restore pspersistence, including %store magic, as an extension. |
|
186 | * `1029 <https://github.com/ipython/ipython/issues/1029>`_: Restore pspersistence, including %store magic, as an extension. | |
187 | * `1025 <https://github.com/ipython/ipython/issues/1025>`_: Dollar escape |
|
187 | * `1025 <https://github.com/ipython/ipython/issues/1025>`_: Dollar escape | |
188 | * `999 <https://github.com/ipython/ipython/issues/999>`_: Fix issue #880 - more useful message to user when %paste fails |
|
188 | * `999 <https://github.com/ipython/ipython/issues/999>`_: Fix issue #880 - more useful message to user when %paste fails | |
189 | * `938 <https://github.com/ipython/ipython/issues/938>`_: changes to get ipython.el to work with the latest python-mode.el |
|
189 | * `938 <https://github.com/ipython/ipython/issues/938>`_: changes to get ipython.el to work with the latest python-mode.el | |
190 | * `1012 <https://github.com/ipython/ipython/issues/1012>`_: Add logout button. |
|
190 | * `1012 <https://github.com/ipython/ipython/issues/1012>`_: Add logout button. | |
191 | * `1020 <https://github.com/ipython/ipython/issues/1020>`_: Dollar formatter for ! shell calls |
|
191 | * `1020 <https://github.com/ipython/ipython/issues/1020>`_: Dollar formatter for ! shell calls | |
192 | * `1019 <https://github.com/ipython/ipython/issues/1019>`_: Use repr() to make quoted strings |
|
192 | * `1019 <https://github.com/ipython/ipython/issues/1019>`_: Use repr() to make quoted strings | |
193 | * `1008 <https://github.com/ipython/ipython/issues/1008>`_: don't use crash_handler by default |
|
193 | * `1008 <https://github.com/ipython/ipython/issues/1008>`_: don't use crash_handler by default | |
194 | * `1003 <https://github.com/ipython/ipython/issues/1003>`_: Drop consecutive duplicates when refilling readline history |
|
194 | * `1003 <https://github.com/ipython/ipython/issues/1003>`_: Drop consecutive duplicates when refilling readline history | |
195 | * `997 <https://github.com/ipython/ipython/issues/997>`_: don't unregister interrupted post-exec functions |
|
195 | * `997 <https://github.com/ipython/ipython/issues/997>`_: don't unregister interrupted post-exec functions | |
196 | * `996 <https://github.com/ipython/ipython/issues/996>`_: add Integer traitlet |
|
196 | * `996 <https://github.com/ipython/ipython/issues/996>`_: add Integer traitlet | |
197 | * `1016 <https://github.com/ipython/ipython/issues/1016>`_: Fix password hashing for Python 3 |
|
197 | * `1016 <https://github.com/ipython/ipython/issues/1016>`_: Fix password hashing for Python 3 | |
198 | * `1014 <https://github.com/ipython/ipython/issues/1014>`_: escape minus signs in manpages |
|
198 | * `1014 <https://github.com/ipython/ipython/issues/1014>`_: escape minus signs in manpages | |
199 | * `1013 <https://github.com/ipython/ipython/issues/1013>`_: [NumPyExampleDocstring] link was pointing to raw file |
|
199 | * `1013 <https://github.com/ipython/ipython/issues/1013>`_: [NumPyExampleDocstring] link was pointing to raw file | |
200 | * `1011 <https://github.com/ipython/ipython/issues/1011>`_: Add hashed password support. |
|
200 | * `1011 <https://github.com/ipython/ipython/issues/1011>`_: Add hashed password support. | |
201 | * `1005 <https://github.com/ipython/ipython/issues/1005>`_: Quick fix for os.system requiring str parameter |
|
201 | * `1005 <https://github.com/ipython/ipython/issues/1005>`_: Quick fix for os.system requiring str parameter | |
202 | * `994 <https://github.com/ipython/ipython/issues/994>`_: Allow latex formulas in HTML output |
|
202 | * `994 <https://github.com/ipython/ipython/issues/994>`_: Allow latex formulas in HTML output | |
203 | * `955 <https://github.com/ipython/ipython/issues/955>`_: Websocket Adjustments |
|
203 | * `955 <https://github.com/ipython/ipython/issues/955>`_: Websocket Adjustments | |
204 | * `979 <https://github.com/ipython/ipython/issues/979>`_: use system_raw in terminal, even on Windows |
|
204 | * `979 <https://github.com/ipython/ipython/issues/979>`_: use system_raw in terminal, even on Windows | |
205 | * `989 <https://github.com/ipython/ipython/issues/989>`_: fix arguments for commands in _process_posix |
|
205 | * `989 <https://github.com/ipython/ipython/issues/989>`_: fix arguments for commands in _process_posix | |
206 | * `991 <https://github.com/ipython/ipython/issues/991>`_: Show traceback, continuing to start kernel if pylab init fails |
|
206 | * `991 <https://github.com/ipython/ipython/issues/991>`_: Show traceback, continuing to start kernel if pylab init fails | |
207 | * `981 <https://github.com/ipython/ipython/issues/981>`_: Split likely multiline text when writing JSON notebooks |
|
207 | * `981 <https://github.com/ipython/ipython/issues/981>`_: Split likely multiline text when writing JSON notebooks | |
208 | * `957 <https://github.com/ipython/ipython/issues/957>`_: allow change of png DPI in inline backend |
|
208 | * `957 <https://github.com/ipython/ipython/issues/957>`_: allow change of png DPI in inline backend | |
209 | * `968 <https://github.com/ipython/ipython/issues/968>`_: add wantDirectory to ipdoctest, so that directories will be checked for e |
|
209 | * `968 <https://github.com/ipython/ipython/issues/968>`_: add wantDirectory to ipdoctest, so that directories will be checked for e | |
210 | * `984 <https://github.com/ipython/ipython/issues/984>`_: Do not expose variables defined at startup to %who etc. |
|
210 | * `984 <https://github.com/ipython/ipython/issues/984>`_: Do not expose variables defined at startup to %who etc. | |
211 | * `985 <https://github.com/ipython/ipython/issues/985>`_: Fixes for parallel code on Python 3 |
|
211 | * `985 <https://github.com/ipython/ipython/issues/985>`_: Fixes for parallel code on Python 3 | |
212 | * `963 <https://github.com/ipython/ipython/issues/963>`_: disable calltips in PySide < 1.0.7 to prevent segfault |
|
212 | * `963 <https://github.com/ipython/ipython/issues/963>`_: disable calltips in PySide < 1.0.7 to prevent segfault | |
213 | * `976 <https://github.com/ipython/ipython/issues/976>`_: Getting started on what's new |
|
213 | * `976 <https://github.com/ipython/ipython/issues/976>`_: Getting started on what's new | |
214 | * `929 <https://github.com/ipython/ipython/issues/929>`_: Multiline history |
|
214 | * `929 <https://github.com/ipython/ipython/issues/929>`_: Multiline history | |
215 | * `964 <https://github.com/ipython/ipython/issues/964>`_: Default profile |
|
215 | * `964 <https://github.com/ipython/ipython/issues/964>`_: Default profile | |
216 | * `961 <https://github.com/ipython/ipython/issues/961>`_: Disable the pager for the test suite |
|
216 | * `961 <https://github.com/ipython/ipython/issues/961>`_: Disable the pager for the test suite | |
217 | * `953 <https://github.com/ipython/ipython/issues/953>`_: Physics extension |
|
217 | * `953 <https://github.com/ipython/ipython/issues/953>`_: Physics extension | |
218 | * `950 <https://github.com/ipython/ipython/issues/950>`_: Add directory for startup files |
|
218 | * `950 <https://github.com/ipython/ipython/issues/950>`_: Add directory for startup files | |
219 | * `940 <https://github.com/ipython/ipython/issues/940>`_: allow setting HistoryManager.hist_file with config |
|
219 | * `940 <https://github.com/ipython/ipython/issues/940>`_: allow setting HistoryManager.hist_file with config | |
220 | * `948 <https://github.com/ipython/ipython/issues/948>`_: Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16. |
|
220 | * `948 <https://github.com/ipython/ipython/issues/948>`_: Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16. | |
221 | * `916 <https://github.com/ipython/ipython/issues/916>`_: Run p ( https://github.com/ipython/ipython/pull/901 ) |
|
221 | * `916 <https://github.com/ipython/ipython/issues/916>`_: Run p ( https://github.com/ipython/ipython/pull/901 ) | |
222 | * `923 <https://github.com/ipython/ipython/issues/923>`_: %config magic |
|
222 | * `923 <https://github.com/ipython/ipython/issues/923>`_: %config magic | |
223 | * `920 <https://github.com/ipython/ipython/issues/920>`_: unordered iteration of AsyncMapResults (+ a couple fixes) |
|
223 | * `920 <https://github.com/ipython/ipython/issues/920>`_: unordered iteration of AsyncMapResults (+ a couple fixes) | |
224 | * `941 <https://github.com/ipython/ipython/issues/941>`_: Follow-up to 387dcd6a, `_rl.__doc__` is `None` with pyreadline |
|
224 | * `941 <https://github.com/ipython/ipython/issues/941>`_: Follow-up to 387dcd6a, `_rl.__doc__` is `None` with pyreadline | |
225 | * `931 <https://github.com/ipython/ipython/issues/931>`_: read-only notebook mode |
|
225 | * `931 <https://github.com/ipython/ipython/issues/931>`_: read-only notebook mode | |
226 | * `921 <https://github.com/ipython/ipython/issues/921>`_: Show invalid config message on TraitErrors during init |
|
226 | * `921 <https://github.com/ipython/ipython/issues/921>`_: Show invalid config message on TraitErrors during init | |
227 | * `815 <https://github.com/ipython/ipython/issues/815>`_: Fix #481 using custom qt4 input hook |
|
227 | * `815 <https://github.com/ipython/ipython/issues/815>`_: Fix #481 using custom qt4 input hook | |
228 | * `936 <https://github.com/ipython/ipython/issues/936>`_: Start webbrowser in a thread. Prevents lockup with Chrome. |
|
228 | * `936 <https://github.com/ipython/ipython/issues/936>`_: Start webbrowser in a thread. Prevents lockup with Chrome. | |
229 | * `937 <https://github.com/ipython/ipython/issues/937>`_: add dirty trick for readline import on OSX |
|
229 | * `937 <https://github.com/ipython/ipython/issues/937>`_: add dirty trick for readline import on OSX | |
230 | * `913 <https://github.com/ipython/ipython/issues/913>`_: Py3 tests2 |
|
230 | * `913 <https://github.com/ipython/ipython/issues/913>`_: Py3 tests2 | |
231 | * `933 <https://github.com/ipython/ipython/issues/933>`_: Cancel in qt console closeevent should trigger event.ignore() |
|
231 | * `933 <https://github.com/ipython/ipython/issues/933>`_: Cancel in qt console closeevent should trigger event.ignore() | |
232 | * `930 <https://github.com/ipython/ipython/issues/930>`_: read-only notebook mode |
|
232 | * `930 <https://github.com/ipython/ipython/issues/930>`_: read-only notebook mode | |
233 | * `910 <https://github.com/ipython/ipython/issues/910>`_: Make import checks more explicit in %whos |
|
233 | * `910 <https://github.com/ipython/ipython/issues/910>`_: Make import checks more explicit in %whos | |
234 | * `926 <https://github.com/ipython/ipython/issues/926>`_: reincarnate -V cmdline option |
|
234 | * `926 <https://github.com/ipython/ipython/issues/926>`_: reincarnate -V cmdline option | |
235 | * `928 <https://github.com/ipython/ipython/issues/928>`_: BUG: Set context for font size change shortcuts in ConsoleWidget |
|
235 | * `928 <https://github.com/ipython/ipython/issues/928>`_: BUG: Set context for font size change shortcuts in ConsoleWidget | |
236 | * `901 <https://github.com/ipython/ipython/issues/901>`_: - There is a bug when running the profiler in the magic command (prun) with python3 |
|
236 | * `901 <https://github.com/ipython/ipython/issues/901>`_: - There is a bug when running the profiler in the magic command (prun) with python3 | |
237 | * `912 <https://github.com/ipython/ipython/issues/912>`_: Add magic for cls on windows. Fix for #181. |
|
237 | * `912 <https://github.com/ipython/ipython/issues/912>`_: Add magic for cls on windows. Fix for #181. | |
238 | * `905 <https://github.com/ipython/ipython/issues/905>`_: enable %gui/%pylab magics in the Kernel |
|
238 | * `905 <https://github.com/ipython/ipython/issues/905>`_: enable %gui/%pylab magics in the Kernel | |
239 | * `909 <https://github.com/ipython/ipython/issues/909>`_: Allow IPython to run without sqlite3 |
|
239 | * `909 <https://github.com/ipython/ipython/issues/909>`_: Allow IPython to run without sqlite3 | |
240 | * `887 <https://github.com/ipython/ipython/issues/887>`_: Qtconsole menu |
|
240 | * `887 <https://github.com/ipython/ipython/issues/887>`_: Qtconsole menu | |
241 | * `895 <https://github.com/ipython/ipython/issues/895>`_: notebook download implies save |
|
241 | * `895 <https://github.com/ipython/ipython/issues/895>`_: notebook download implies save | |
242 | * `896 <https://github.com/ipython/ipython/issues/896>`_: Execfile |
|
242 | * `896 <https://github.com/ipython/ipython/issues/896>`_: Execfile | |
243 | * `899 <https://github.com/ipython/ipython/issues/899>`_: Brian's Notebook work |
|
243 | * `899 <https://github.com/ipython/ipython/issues/899>`_: Brian's Notebook work | |
244 | * `892 <https://github.com/ipython/ipython/issues/892>`_: don't close figures every cycle with inline matplotlib backend |
|
244 | * `892 <https://github.com/ipython/ipython/issues/892>`_: don't close figures every cycle with inline matplotlib backend | |
245 | * `893 <https://github.com/ipython/ipython/issues/893>`_: Adding clear_output to kernel and HTML notebook |
|
245 | * `893 <https://github.com/ipython/ipython/issues/893>`_: Adding clear_output to kernel and HTML notebook | |
246 | * `789 <https://github.com/ipython/ipython/issues/789>`_: Adding clear_output to kernel and HTML notebook. |
|
246 | * `789 <https://github.com/ipython/ipython/issues/789>`_: Adding clear_output to kernel and HTML notebook. | |
247 | * `898 <https://github.com/ipython/ipython/issues/898>`_: Don't pass unicode sys.argv with %run or `ipython script.py` |
|
247 | * `898 <https://github.com/ipython/ipython/issues/898>`_: Don't pass unicode sys.argv with %run or `ipython script.py` | |
248 | * `897 <https://github.com/ipython/ipython/issues/897>`_: Add tooltips to the notebook via 'title' attr. |
|
248 | * `897 <https://github.com/ipython/ipython/issues/897>`_: Add tooltips to the notebook via 'title' attr. | |
249 | * `877 <https://github.com/ipython/ipython/issues/877>`_: partial fix for issue #678 |
|
249 | * `877 <https://github.com/ipython/ipython/issues/877>`_: partial fix for issue #678 | |
250 | * `838 <https://github.com/ipython/ipython/issues/838>`_: reenable multiline history for terminals |
|
250 | * `838 <https://github.com/ipython/ipython/issues/838>`_: reenable multiline history for terminals | |
251 | * `872 <https://github.com/ipython/ipython/issues/872>`_: The constructor of Client() checks for AssertionError in validate_url to open a file instead of connection to a URL if it fails. |
|
251 | * `872 <https://github.com/ipython/ipython/issues/872>`_: The constructor of Client() checks for AssertionError in validate_url to open a file instead of connection to a URL if it fails. | |
252 | * `884 <https://github.com/ipython/ipython/issues/884>`_: Notebook usability fixes |
|
252 | * `884 <https://github.com/ipython/ipython/issues/884>`_: Notebook usability fixes | |
253 | * `883 <https://github.com/ipython/ipython/issues/883>`_: User notification if notebook saving fails |
|
253 | * `883 <https://github.com/ipython/ipython/issues/883>`_: User notification if notebook saving fails | |
254 | * `889 <https://github.com/ipython/ipython/issues/889>`_: Add drop_by_id method to shell, to remove variables added by extensions. |
|
254 | * `889 <https://github.com/ipython/ipython/issues/889>`_: Add drop_by_id method to shell, to remove variables added by extensions. | |
255 | * `891 <https://github.com/ipython/ipython/issues/891>`_: Ability to open the notebook in a browser when it starts |
|
255 | * `891 <https://github.com/ipython/ipython/issues/891>`_: Ability to open the notebook in a browser when it starts | |
256 | * `813 <https://github.com/ipython/ipython/issues/813>`_: Create menu bar for qtconsole |
|
256 | * `813 <https://github.com/ipython/ipython/issues/813>`_: Create menu bar for qtconsole | |
257 | * `876 <https://github.com/ipython/ipython/issues/876>`_: protect IPython from bad custom exception handlers |
|
257 | * `876 <https://github.com/ipython/ipython/issues/876>`_: protect IPython from bad custom exception handlers | |
258 | * `856 <https://github.com/ipython/ipython/issues/856>`_: Backgroundjobs |
|
258 | * `856 <https://github.com/ipython/ipython/issues/856>`_: Backgroundjobs | |
259 | * `868 <https://github.com/ipython/ipython/issues/868>`_: Warn user if MathJax can't be fetched from notebook closes #744 |
|
259 | * `868 <https://github.com/ipython/ipython/issues/868>`_: Warn user if MathJax can't be fetched from notebook closes #744 | |
260 | * `878 <https://github.com/ipython/ipython/issues/878>`_: store_history=False default for run_cell |
|
260 | * `878 <https://github.com/ipython/ipython/issues/878>`_: store_history=False default for run_cell | |
261 | * `824 <https://github.com/ipython/ipython/issues/824>`_: History access |
|
261 | * `824 <https://github.com/ipython/ipython/issues/824>`_: History access | |
262 | * `850 <https://github.com/ipython/ipython/issues/850>`_: Update codemirror to 2.15 and make the code internally more version-agnostic |
|
262 | * `850 <https://github.com/ipython/ipython/issues/850>`_: Update codemirror to 2.15 and make the code internally more version-agnostic | |
263 | * `861 <https://github.com/ipython/ipython/issues/861>`_: Fix for issue #56 |
|
263 | * `861 <https://github.com/ipython/ipython/issues/861>`_: Fix for issue #56 | |
264 | * `819 <https://github.com/ipython/ipython/issues/819>`_: Adding -m option to %run, similar to -m for python interpreter. |
|
264 | * `819 <https://github.com/ipython/ipython/issues/819>`_: Adding -m option to %run, similar to -m for python interpreter. | |
265 | * `855 <https://github.com/ipython/ipython/issues/855>`_: promote aliases and flags, to ensure they have priority over config files |
|
265 | * `855 <https://github.com/ipython/ipython/issues/855>`_: promote aliases and flags, to ensure they have priority over config files | |
266 | * `862 <https://github.com/ipython/ipython/issues/862>`_: BUG: Completion widget position and pager focus. |
|
266 | * `862 <https://github.com/ipython/ipython/issues/862>`_: BUG: Completion widget position and pager focus. | |
267 | * `847 <https://github.com/ipython/ipython/issues/847>`_: Allow connection to kernels by files |
|
267 | * `847 <https://github.com/ipython/ipython/issues/847>`_: Allow connection to kernels by files | |
268 | * `708 <https://github.com/ipython/ipython/issues/708>`_: Two-process terminal frontend |
|
268 | * `708 <https://github.com/ipython/ipython/issues/708>`_: Two-process terminal frontend | |
269 | * `857 <https://github.com/ipython/ipython/issues/857>`_: make sdist flags work again (e.g. --manifest-only) |
|
269 | * `857 <https://github.com/ipython/ipython/issues/857>`_: make sdist flags work again (e.g. --manifest-only) | |
270 | * `835 <https://github.com/ipython/ipython/issues/835>`_: Add Tab key to list of keys that scroll down the paging widget. |
|
270 | * `835 <https://github.com/ipython/ipython/issues/835>`_: Add Tab key to list of keys that scroll down the paging widget. | |
271 | * `859 <https://github.com/ipython/ipython/issues/859>`_: Fix for issue #800 |
|
271 | * `859 <https://github.com/ipython/ipython/issues/859>`_: Fix for issue #800 | |
272 | * `848 <https://github.com/ipython/ipython/issues/848>`_: Python3 setup.py install failiure |
|
272 | * `848 <https://github.com/ipython/ipython/issues/848>`_: Python3 setup.py install failiure | |
273 | * `845 <https://github.com/ipython/ipython/issues/845>`_: Tests on Python 3 |
|
273 | * `845 <https://github.com/ipython/ipython/issues/845>`_: Tests on Python 3 | |
274 | * `802 <https://github.com/ipython/ipython/issues/802>`_: DOC: extensions: add documentation for the bundled extensions |
|
274 | * `802 <https://github.com/ipython/ipython/issues/802>`_: DOC: extensions: add documentation for the bundled extensions | |
275 | * `830 <https://github.com/ipython/ipython/issues/830>`_: contiguous stdout/stderr in notebook |
|
275 | * `830 <https://github.com/ipython/ipython/issues/830>`_: contiguous stdout/stderr in notebook | |
276 | * `761 <https://github.com/ipython/ipython/issues/761>`_: Windows: test runner fails if repo path (e.g. home dir) contains spaces |
|
276 | * `761 <https://github.com/ipython/ipython/issues/761>`_: Windows: test runner fails if repo path (e.g. home dir) contains spaces | |
277 | * `801 <https://github.com/ipython/ipython/issues/801>`_: Py3 notebook |
|
277 | * `801 <https://github.com/ipython/ipython/issues/801>`_: Py3 notebook | |
278 | * `809 <https://github.com/ipython/ipython/issues/809>`_: use CFRunLoop directly in `ipython kernel --pylab osx` |
|
278 | * `809 <https://github.com/ipython/ipython/issues/809>`_: use CFRunLoop directly in `ipython kernel --pylab osx` | |
279 | * `841 <https://github.com/ipython/ipython/issues/841>`_: updated old scipy.org links, other minor doc fixes |
|
279 | * `841 <https://github.com/ipython/ipython/issues/841>`_: updated old scipy.org links, other minor doc fixes | |
280 | * `837 <https://github.com/ipython/ipython/issues/837>`_: remove all trailling spaces |
|
280 | * `837 <https://github.com/ipython/ipython/issues/837>`_: remove all trailling spaces | |
281 | * `834 <https://github.com/ipython/ipython/issues/834>`_: Issue https://github.com/ipython/ipython/issues/832 resolution |
|
281 | * `834 <https://github.com/ipython/ipython/issues/834>`_: Issue https://github.com/ipython/ipython/issues/832 resolution | |
282 | * `746 <https://github.com/ipython/ipython/issues/746>`_: ENH: extensions: port autoreload to current API |
|
282 | * `746 <https://github.com/ipython/ipython/issues/746>`_: ENH: extensions: port autoreload to current API | |
283 | * `828 <https://github.com/ipython/ipython/issues/828>`_: fixed permissions (sub-modules should not be executable) + added shebang for run_ipy_in_profiler.py |
|
283 | * `828 <https://github.com/ipython/ipython/issues/828>`_: fixed permissions (sub-modules should not be executable) + added shebang for run_ipy_in_profiler.py | |
284 | * `798 <https://github.com/ipython/ipython/issues/798>`_: pexpect & Python 3 |
|
284 | * `798 <https://github.com/ipython/ipython/issues/798>`_: pexpect & Python 3 | |
285 | * `804 <https://github.com/ipython/ipython/issues/804>`_: Magic 'range' crash if greater than len(input_hist) |
|
285 | * `804 <https://github.com/ipython/ipython/issues/804>`_: Magic 'range' crash if greater than len(input_hist) | |
286 | * `821 <https://github.com/ipython/ipython/issues/821>`_: update tornado dependency to 2.1 |
|
286 | * `821 <https://github.com/ipython/ipython/issues/821>`_: update tornado dependency to 2.1 | |
287 | * `807 <https://github.com/ipython/ipython/issues/807>`_: Faciliate ssh tunnel sharing by announcing ports |
|
287 | * `807 <https://github.com/ipython/ipython/issues/807>`_: Faciliate ssh tunnel sharing by announcing ports | |
288 | * `795 <https://github.com/ipython/ipython/issues/795>`_: Add cluster-id for multiple cluster instances per profile |
|
288 | * `795 <https://github.com/ipython/ipython/issues/795>`_: Add cluster-id for multiple cluster instances per profile | |
289 | * `742 <https://github.com/ipython/ipython/issues/742>`_: Glut |
|
289 | * `742 <https://github.com/ipython/ipython/issues/742>`_: Glut | |
290 | * `668 <https://github.com/ipython/ipython/issues/668>`_: Greedy completer |
|
290 | * `668 <https://github.com/ipython/ipython/issues/668>`_: Greedy completer | |
291 | * `776 <https://github.com/ipython/ipython/issues/776>`_: Reworking qtconsole shortcut, add fullscreen |
|
291 | * `776 <https://github.com/ipython/ipython/issues/776>`_: Reworking qtconsole shortcut, add fullscreen | |
292 | * `790 <https://github.com/ipython/ipython/issues/790>`_: TST: add future unicode_literals test (#786) |
|
292 | * `790 <https://github.com/ipython/ipython/issues/790>`_: TST: add future unicode_literals test (#786) | |
293 | * `775 <https://github.com/ipython/ipython/issues/775>`_: redirect_in/redirect_out should be constrained to windows only |
|
293 | * `775 <https://github.com/ipython/ipython/issues/775>`_: redirect_in/redirect_out should be constrained to windows only | |
294 | * `793 <https://github.com/ipython/ipython/issues/793>`_: Don't use readline in the ZMQShell |
|
294 | * `793 <https://github.com/ipython/ipython/issues/793>`_: Don't use readline in the ZMQShell | |
295 | * `743 <https://github.com/ipython/ipython/issues/743>`_: Pyglet |
|
295 | * `743 <https://github.com/ipython/ipython/issues/743>`_: Pyglet | |
296 | * `774 <https://github.com/ipython/ipython/issues/774>`_: basic/initial .mailmap for nice shortlog summaries |
|
296 | * `774 <https://github.com/ipython/ipython/issues/774>`_: basic/initial .mailmap for nice shortlog summaries | |
297 | * `770 <https://github.com/ipython/ipython/issues/770>`_: #769 (reopened) |
|
297 | * `770 <https://github.com/ipython/ipython/issues/770>`_: #769 (reopened) | |
298 | * `784 <https://github.com/ipython/ipython/issues/784>`_: Parse user code to AST using compiler flags. |
|
298 | * `784 <https://github.com/ipython/ipython/issues/784>`_: Parse user code to AST using compiler flags. | |
299 | * `783 <https://github.com/ipython/ipython/issues/783>`_: always use StringIO, never cStringIO |
|
299 | * `783 <https://github.com/ipython/ipython/issues/783>`_: always use StringIO, never cStringIO | |
300 | * `782 <https://github.com/ipython/ipython/issues/782>`_: flush stdout/stderr on displayhook call |
|
300 | * `782 <https://github.com/ipython/ipython/issues/782>`_: flush stdout/stderr on displayhook call | |
301 | * `622 <https://github.com/ipython/ipython/issues/622>`_: Make pylab import all configurable |
|
301 | * `622 <https://github.com/ipython/ipython/issues/622>`_: Make pylab import all configurable | |
302 | * `745 <https://github.com/ipython/ipython/issues/745>`_: Don't assume history requests succeed in qtconsole |
|
302 | * `745 <https://github.com/ipython/ipython/issues/745>`_: Don't assume history requests succeed in qtconsole | |
303 | * `725 <https://github.com/ipython/ipython/issues/725>`_: don't assume cursor.selectedText() is a string |
|
303 | * `725 <https://github.com/ipython/ipython/issues/725>`_: don't assume cursor.selectedText() is a string | |
304 | * `778 <https://github.com/ipython/ipython/issues/778>`_: don't override execfile on Python 2 |
|
304 | * `778 <https://github.com/ipython/ipython/issues/778>`_: don't override execfile on Python 2 | |
305 | * `663 <https://github.com/ipython/ipython/issues/663>`_: Python 3 compatilibility work |
|
305 | * `663 <https://github.com/ipython/ipython/issues/663>`_: Python 3 compatilibility work | |
306 | * `762 <https://github.com/ipython/ipython/issues/762>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes |
|
306 | * `762 <https://github.com/ipython/ipython/issues/762>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes | |
307 | * `763 <https://github.com/ipython/ipython/issues/763>`_: Set context for shortcuts in ConsoleWidget |
|
307 | * `763 <https://github.com/ipython/ipython/issues/763>`_: Set context for shortcuts in ConsoleWidget | |
308 | * `722 <https://github.com/ipython/ipython/issues/722>`_: PyPy compatibility |
|
308 | * `722 <https://github.com/ipython/ipython/issues/722>`_: PyPy compatibility | |
309 | * `757 <https://github.com/ipython/ipython/issues/757>`_: ipython.el is broken in 0.11 |
|
309 | * `757 <https://github.com/ipython/ipython/issues/757>`_: ipython.el is broken in 0.11 | |
310 | * `764 <https://github.com/ipython/ipython/issues/764>`_: fix "--colors=<color>" option in py-python-command-args. |
|
310 | * `764 <https://github.com/ipython/ipython/issues/764>`_: fix "--colors=<color>" option in py-python-command-args. | |
311 | * `758 <https://github.com/ipython/ipython/issues/758>`_: use ROUTER/DEALER socket names instead of XREP/XREQ |
|
311 | * `758 <https://github.com/ipython/ipython/issues/758>`_: use ROUTER/DEALER socket names instead of XREP/XREQ | |
312 | * `736 <https://github.com/ipython/ipython/issues/736>`_: enh: added authentication ability for webapp |
|
312 | * `736 <https://github.com/ipython/ipython/issues/736>`_: enh: added authentication ability for webapp | |
313 | * `748 <https://github.com/ipython/ipython/issues/748>`_: Check for tornado before running frontend.html tests. |
|
313 | * `748 <https://github.com/ipython/ipython/issues/748>`_: Check for tornado before running frontend.html tests. | |
314 | * `754 <https://github.com/ipython/ipython/issues/754>`_: restore msg_id/msg_type aliases in top level of msg dict |
|
314 | * `754 <https://github.com/ipython/ipython/issues/754>`_: restore msg_id/msg_type aliases in top level of msg dict | |
315 | * `769 <https://github.com/ipython/ipython/issues/769>`_: Don't treat bytes objects as json-safe |
|
315 | * `769 <https://github.com/ipython/ipython/issues/769>`_: Don't treat bytes objects as json-safe | |
316 | * `753 <https://github.com/ipython/ipython/issues/753>`_: DOC: msg['msg_type'] removed |
|
316 | * `753 <https://github.com/ipython/ipython/issues/753>`_: DOC: msg['msg_type'] removed | |
317 | * `766 <https://github.com/ipython/ipython/issues/766>`_: fix "--colors=<color>" option in py-python-command-args. |
|
317 | * `766 <https://github.com/ipython/ipython/issues/766>`_: fix "--colors=<color>" option in py-python-command-args. | |
318 | * `765 <https://github.com/ipython/ipython/issues/765>`_: fix "--colors=<color>" option in py-python-command-args. |
|
318 | * `765 <https://github.com/ipython/ipython/issues/765>`_: fix "--colors=<color>" option in py-python-command-args. | |
319 | * `741 <https://github.com/ipython/ipython/issues/741>`_: Run PyOs_InputHook in pager to keep plot windows interactive. |
|
319 | * `741 <https://github.com/ipython/ipython/issues/741>`_: Run PyOs_InputHook in pager to keep plot windows interactive. | |
320 | * `664 <https://github.com/ipython/ipython/issues/664>`_: Remove ipythonrc references from documentation |
|
320 | * `664 <https://github.com/ipython/ipython/issues/664>`_: Remove ipythonrc references from documentation | |
321 | * `750 <https://github.com/ipython/ipython/issues/750>`_: Tiny doc fixes |
|
321 | * `750 <https://github.com/ipython/ipython/issues/750>`_: Tiny doc fixes | |
322 | * `433 <https://github.com/ipython/ipython/issues/433>`_: ZMQ terminal frontend |
|
322 | * `433 <https://github.com/ipython/ipython/issues/433>`_: ZMQ terminal frontend | |
323 | * `734 <https://github.com/ipython/ipython/issues/734>`_: Allow %magic argument filenames with spaces to be specified with quotes under win32 |
|
323 | * `734 <https://github.com/ipython/ipython/issues/734>`_: Allow %magic argument filenames with spaces to be specified with quotes under win32 | |
324 | * `731 <https://github.com/ipython/ipython/issues/731>`_: respect encoding of display data from urls |
|
324 | * `731 <https://github.com/ipython/ipython/issues/731>`_: respect encoding of display data from urls | |
325 | * `730 <https://github.com/ipython/ipython/issues/730>`_: doc improvements for running notebook via secure protocol |
|
325 | * `730 <https://github.com/ipython/ipython/issues/730>`_: doc improvements for running notebook via secure protocol | |
326 | * `729 <https://github.com/ipython/ipython/issues/729>`_: use null char to start markdown cell placeholder |
|
326 | * `729 <https://github.com/ipython/ipython/issues/729>`_: use null char to start markdown cell placeholder | |
327 | * `727 <https://github.com/ipython/ipython/issues/727>`_: Minor fixes to the htmlnotebook |
|
327 | * `727 <https://github.com/ipython/ipython/issues/727>`_: Minor fixes to the htmlnotebook | |
328 | * `726 <https://github.com/ipython/ipython/issues/726>`_: use bundled argparse if system argparse is < 1.1 |
|
328 | * `726 <https://github.com/ipython/ipython/issues/726>`_: use bundled argparse if system argparse is < 1.1 | |
329 | * `705 <https://github.com/ipython/ipython/issues/705>`_: Htmlnotebook |
|
329 | * `705 <https://github.com/ipython/ipython/issues/705>`_: Htmlnotebook | |
330 | * `723 <https://github.com/ipython/ipython/issues/723>`_: Add 'import time' to IPython/parallel/apps/launcher.py as time.sleep is called without time being imported |
|
330 | * `723 <https://github.com/ipython/ipython/issues/723>`_: Add 'import time' to IPython/parallel/apps/launcher.py as time.sleep is called without time being imported | |
331 | * `714 <https://github.com/ipython/ipython/issues/714>`_: Install mathjax for offline use |
|
331 | * `714 <https://github.com/ipython/ipython/issues/714>`_: Install mathjax for offline use | |
332 | * `718 <https://github.com/ipython/ipython/issues/718>`_: Underline keyboard shortcut characters on appropriate buttons |
|
332 | * `718 <https://github.com/ipython/ipython/issues/718>`_: Underline keyboard shortcut characters on appropriate buttons | |
333 | * `717 <https://github.com/ipython/ipython/issues/717>`_: Add source highlighting to markdown snippets |
|
333 | * `717 <https://github.com/ipython/ipython/issues/717>`_: Add source highlighting to markdown snippets | |
334 | * `716 <https://github.com/ipython/ipython/issues/716>`_: update EvalFormatter to allow arbitrary expressions |
|
334 | * `716 <https://github.com/ipython/ipython/issues/716>`_: update EvalFormatter to allow arbitrary expressions | |
335 | * `712 <https://github.com/ipython/ipython/issues/712>`_: Reset execution counter after cache is cleared |
|
335 | * `712 <https://github.com/ipython/ipython/issues/712>`_: Reset execution counter after cache is cleared | |
336 | * `713 <https://github.com/ipython/ipython/issues/713>`_: Align colons in html notebook help dialog |
|
336 | * `713 <https://github.com/ipython/ipython/issues/713>`_: Align colons in html notebook help dialog | |
337 | * `709 <https://github.com/ipython/ipython/issues/709>`_: Allow usage of '.' in notebook names |
|
337 | * `709 <https://github.com/ipython/ipython/issues/709>`_: Allow usage of '.' in notebook names | |
338 | * `706 <https://github.com/ipython/ipython/issues/706>`_: Implement static publishing of HTML notebook |
|
338 | * `706 <https://github.com/ipython/ipython/issues/706>`_: Implement static publishing of HTML notebook | |
339 | * `674 <https://github.com/ipython/ipython/issues/674>`_: use argparse to parse aliases & flags |
|
339 | * `674 <https://github.com/ipython/ipython/issues/674>`_: use argparse to parse aliases & flags | |
340 | * `679 <https://github.com/ipython/ipython/issues/679>`_: HistoryManager.get_session_info() |
|
340 | * `679 <https://github.com/ipython/ipython/issues/679>`_: HistoryManager.get_session_info() | |
341 | * `696 <https://github.com/ipython/ipython/issues/696>`_: Fix columnize bug, where tab completion with very long filenames would crash Qt console |
|
341 | * `696 <https://github.com/ipython/ipython/issues/696>`_: Fix columnize bug, where tab completion with very long filenames would crash Qt console | |
342 | * `686 <https://github.com/ipython/ipython/issues/686>`_: add ssh tunnel support to qtconsole |
|
342 | * `686 <https://github.com/ipython/ipython/issues/686>`_: add ssh tunnel support to qtconsole | |
343 | * `685 <https://github.com/ipython/ipython/issues/685>`_: Add SSH tunneling to engines |
|
343 | * `685 <https://github.com/ipython/ipython/issues/685>`_: Add SSH tunneling to engines | |
344 | * `384 <https://github.com/ipython/ipython/issues/384>`_: Allow pickling objects defined interactively. |
|
344 | * `384 <https://github.com/ipython/ipython/issues/384>`_: Allow pickling objects defined interactively. | |
345 | * `647 <https://github.com/ipython/ipython/issues/647>`_: My fix rpmlint |
|
345 | * `647 <https://github.com/ipython/ipython/issues/647>`_: My fix rpmlint | |
346 | * `587 <https://github.com/ipython/ipython/issues/587>`_: don't special case for py3k+numpy |
|
346 | * `587 <https://github.com/ipython/ipython/issues/587>`_: don't special case for py3k+numpy | |
347 | * `703 <https://github.com/ipython/ipython/issues/703>`_: make config-loading debug messages more explicit |
|
347 | * `703 <https://github.com/ipython/ipython/issues/703>`_: make config-loading debug messages more explicit | |
348 | * `699 <https://github.com/ipython/ipython/issues/699>`_: make calltips configurable in qtconsole |
|
348 | * `699 <https://github.com/ipython/ipython/issues/699>`_: make calltips configurable in qtconsole | |
349 | * `666 <https://github.com/ipython/ipython/issues/666>`_: parallel tests & extra readline escapes |
|
349 | * `666 <https://github.com/ipython/ipython/issues/666>`_: parallel tests & extra readline escapes | |
350 | * `683 <https://github.com/ipython/ipython/issues/683>`_: BF - allow nose with-doctest setting in environment |
|
350 | * `683 <https://github.com/ipython/ipython/issues/683>`_: BF - allow nose with-doctest setting in environment | |
351 | * `689 <https://github.com/ipython/ipython/issues/689>`_: Protect ipkernel from bad messages |
|
351 | * `689 <https://github.com/ipython/ipython/issues/689>`_: Protect ipkernel from bad messages | |
352 | * `702 <https://github.com/ipython/ipython/issues/702>`_: Prevent ipython.py launcher from being imported. |
|
352 | * `702 <https://github.com/ipython/ipython/issues/702>`_: Prevent ipython.py launcher from being imported. | |
353 | * `701 <https://github.com/ipython/ipython/issues/701>`_: Prevent ipython.py from being imported by accident |
|
353 | * `701 <https://github.com/ipython/ipython/issues/701>`_: Prevent ipython.py from being imported by accident | |
354 | * `670 <https://github.com/ipython/ipython/issues/670>`_: check for writable dirs, not just existence, in utils.path |
|
354 | * `670 <https://github.com/ipython/ipython/issues/670>`_: check for writable dirs, not just existence, in utils.path | |
355 | * `579 <https://github.com/ipython/ipython/issues/579>`_: Sessionwork |
|
355 | * `579 <https://github.com/ipython/ipython/issues/579>`_: Sessionwork | |
356 | * `687 <https://github.com/ipython/ipython/issues/687>`_: add `ipython kernel` for starting just a kernel |
|
356 | * `687 <https://github.com/ipython/ipython/issues/687>`_: add `ipython kernel` for starting just a kernel | |
357 | * `627 <https://github.com/ipython/ipython/issues/627>`_: Qt Console history search |
|
357 | * `627 <https://github.com/ipython/ipython/issues/627>`_: Qt Console history search | |
358 | * `646 <https://github.com/ipython/ipython/issues/646>`_: Generate package list automatically in find_packages |
|
358 | * `646 <https://github.com/ipython/ipython/issues/646>`_: Generate package list automatically in find_packages | |
359 | * `660 <https://github.com/ipython/ipython/issues/660>`_: i658 |
|
359 | * `660 <https://github.com/ipython/ipython/issues/660>`_: i658 | |
360 | * `659 <https://github.com/ipython/ipython/issues/659>`_: don't crash on bad config files |
|
360 | * `659 <https://github.com/ipython/ipython/issues/659>`_: don't crash on bad config files | |
361 |
|
361 | |||
362 | Regular issues (258): |
|
362 | Regular issues (258): | |
363 |
|
363 | |||
364 | * `1177 <https://github.com/ipython/ipython/issues/1177>`_: UnicodeDecodeError in py3compat from "xlrd??" |
|
364 | * `1177 <https://github.com/ipython/ipython/issues/1177>`_: UnicodeDecodeError in py3compat from "xlrd??" | |
365 | * `1094 <https://github.com/ipython/ipython/issues/1094>`_: Tooltip doesn't show constructor docstrings |
|
365 | * `1094 <https://github.com/ipython/ipython/issues/1094>`_: Tooltip doesn't show constructor docstrings | |
366 | * `1170 <https://github.com/ipython/ipython/issues/1170>`_: double pylab greeting with c.InteractiveShellApp.pylab = "tk" in zmqconsole |
|
366 | * `1170 <https://github.com/ipython/ipython/issues/1170>`_: double pylab greeting with c.InteractiveShellApp.pylab = "tk" in zmqconsole | |
367 | * `1166 <https://github.com/ipython/ipython/issues/1166>`_: E-mail cpaste broken |
|
367 | * `1166 <https://github.com/ipython/ipython/issues/1166>`_: E-mail cpaste broken | |
368 | * `1164 <https://github.com/ipython/ipython/issues/1164>`_: IPython qtconsole (0.12) can't export to html with external png |
|
368 | * `1164 <https://github.com/ipython/ipython/issues/1164>`_: IPython qtconsole (0.12) can't export to html with external png | |
369 | * `1103 <https://github.com/ipython/ipython/issues/1103>`_: %loadpy should cut out encoding declaration |
|
369 | * `1103 <https://github.com/ipython/ipython/issues/1103>`_: %loadpy should cut out encoding declaration | |
370 | * `1156 <https://github.com/ipython/ipython/issues/1156>`_: Notebooks downloaded as Python files require a header stating the encoding |
|
370 | * `1156 <https://github.com/ipython/ipython/issues/1156>`_: Notebooks downloaded as Python files require a header stating the encoding | |
371 | * `1157 <https://github.com/ipython/ipython/issues/1157>`_: Ctrl-C not working when GUI/pylab integration is active |
|
371 | * `1157 <https://github.com/ipython/ipython/issues/1157>`_: Ctrl-C not working when GUI/pylab integration is active | |
372 | * `1154 <https://github.com/ipython/ipython/issues/1154>`_: We should be less aggressive in de-registering post-execution functions |
|
372 | * `1154 <https://github.com/ipython/ipython/issues/1154>`_: We should be less aggressive in de-registering post-execution functions | |
373 | * `1134 <https://github.com/ipython/ipython/issues/1134>`_: "select-all, kill" leaves qtconsole in unusable state |
|
373 | * `1134 <https://github.com/ipython/ipython/issues/1134>`_: "select-all, kill" leaves qtconsole in unusable state | |
374 | * `1148 <https://github.com/ipython/ipython/issues/1148>`_: A lot of testerrors |
|
374 | * `1148 <https://github.com/ipython/ipython/issues/1148>`_: A lot of testerrors | |
375 | * `803 <https://github.com/ipython/ipython/issues/803>`_: Make doctests work with Python 3 |
|
375 | * `803 <https://github.com/ipython/ipython/issues/803>`_: Make doctests work with Python 3 | |
376 | * `1119 <https://github.com/ipython/ipython/issues/1119>`_: Start menu shortcuts not created in Python 3 |
|
376 | * `1119 <https://github.com/ipython/ipython/issues/1119>`_: Start menu shortcuts not created in Python 3 | |
377 | * `1136 <https://github.com/ipython/ipython/issues/1136>`_: The embedding machinery ignores user_ns |
|
377 | * `1136 <https://github.com/ipython/ipython/issues/1136>`_: The embedding machinery ignores user_ns | |
378 | * `607 <https://github.com/ipython/ipython/issues/607>`_: Use the new IPython logo/font in the notebook header |
|
378 | * `607 <https://github.com/ipython/ipython/issues/607>`_: Use the new IPython logo/font in the notebook header | |
379 | * `755 <https://github.com/ipython/ipython/issues/755>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes |
|
379 | * `755 <https://github.com/ipython/ipython/issues/755>`_: qtconsole ipython widget's execute_file fails if filename contains spaces or quotes | |
380 | * `1115 <https://github.com/ipython/ipython/issues/1115>`_: shlex_split should return unicode |
|
380 | * `1115 <https://github.com/ipython/ipython/issues/1115>`_: shlex_split should return unicode | |
381 | * `1109 <https://github.com/ipython/ipython/issues/1109>`_: timeit with string ending in space gives "ValueError: No closing quotation" |
|
381 | * `1109 <https://github.com/ipython/ipython/issues/1109>`_: timeit with string ending in space gives "ValueError: No closing quotation" | |
382 | * `1142 <https://github.com/ipython/ipython/issues/1142>`_: Install problems |
|
382 | * `1142 <https://github.com/ipython/ipython/issues/1142>`_: Install problems | |
383 | * `700 <https://github.com/ipython/ipython/issues/700>`_: Some SVG images render incorrectly in htmlnotebook |
|
383 | * `700 <https://github.com/ipython/ipython/issues/700>`_: Some SVG images render incorrectly in htmlnotebook | |
384 | * `1117 <https://github.com/ipython/ipython/issues/1117>`_: quit() doesn't work in terminal |
|
384 | * `1117 <https://github.com/ipython/ipython/issues/1117>`_: quit() doesn't work in terminal | |
385 | * `1111 <https://github.com/ipython/ipython/issues/1111>`_: ls broken after merge of #1089 |
|
385 | * `1111 <https://github.com/ipython/ipython/issues/1111>`_: ls broken after merge of #1089 | |
386 | * `1104 <https://github.com/ipython/ipython/issues/1104>`_: Prompt spacing weird |
|
386 | * `1104 <https://github.com/ipython/ipython/issues/1104>`_: Prompt spacing weird | |
387 | * `1124 <https://github.com/ipython/ipython/issues/1124>`_: Seg Fault 11 when calling PySide using "run" command |
|
387 | * `1124 <https://github.com/ipython/ipython/issues/1124>`_: Seg Fault 11 when calling PySide using "run" command | |
388 | * `1088 <https://github.com/ipython/ipython/issues/1088>`_: QtConsole : can't copy from pager |
|
388 | * `1088 <https://github.com/ipython/ipython/issues/1088>`_: QtConsole : can't copy from pager | |
389 | * `568 <https://github.com/ipython/ipython/issues/568>`_: Test error and failure in IPython.core on windows |
|
389 | * `568 <https://github.com/ipython/ipython/issues/568>`_: Test error and failure in IPython.core on windows | |
390 | * `1112 <https://github.com/ipython/ipython/issues/1112>`_: testfailure in IPython.frontend on windows |
|
390 | * `1112 <https://github.com/ipython/ipython/issues/1112>`_: testfailure in IPython.frontend on windows | |
391 | * `1102 <https://github.com/ipython/ipython/issues/1102>`_: magic in IPythonDemo fails when not located at top of demo file |
|
391 | * `1102 <https://github.com/ipython/ipython/issues/1102>`_: magic in IPythonDemo fails when not located at top of demo file | |
392 | * `629 <https://github.com/ipython/ipython/issues/629>`_: \r and \b in qtconsole don't behave as expected |
|
392 | * `629 <https://github.com/ipython/ipython/issues/629>`_: \r and \b in qtconsole don't behave as expected | |
393 | * `1080 <https://github.com/ipython/ipython/issues/1080>`_: Notebook: tab completion should close on "(" |
|
393 | * `1080 <https://github.com/ipython/ipython/issues/1080>`_: Notebook: tab completion should close on "(" | |
394 | * `973 <https://github.com/ipython/ipython/issues/973>`_: Qt Console close dialog and on-top Qt Console |
|
394 | * `973 <https://github.com/ipython/ipython/issues/973>`_: Qt Console close dialog and on-top Qt Console | |
395 | * `1087 <https://github.com/ipython/ipython/issues/1087>`_: QtConsole xhtml/Svg export broken ? |
|
395 | * `1087 <https://github.com/ipython/ipython/issues/1087>`_: QtConsole xhtml/Svg export broken ? | |
396 | * `1067 <https://github.com/ipython/ipython/issues/1067>`_: Parallel test suite hangs on Python 3 |
|
396 | * `1067 <https://github.com/ipython/ipython/issues/1067>`_: Parallel test suite hangs on Python 3 | |
397 | * `1018 <https://github.com/ipython/ipython/issues/1018>`_: Local mathjax breaks install |
|
397 | * `1018 <https://github.com/ipython/ipython/issues/1018>`_: Local mathjax breaks install | |
398 | * `993 <https://github.com/ipython/ipython/issues/993>`_: `raw_input` redirection to foreign kernels is extremely brittle |
|
398 | * `993 <https://github.com/ipython/ipython/issues/993>`_: `raw_input` redirection to foreign kernels is extremely brittle | |
399 | * `1100 <https://github.com/ipython/ipython/issues/1100>`_: ipython3 traceback unicode issue from extensions |
|
399 | * `1100 <https://github.com/ipython/ipython/issues/1100>`_: ipython3 traceback unicode issue from extensions | |
400 | * `1071 <https://github.com/ipython/ipython/issues/1071>`_: Large html-notebooks hang on load on a slow machine |
|
400 | * `1071 <https://github.com/ipython/ipython/issues/1071>`_: Large html-notebooks hang on load on a slow machine | |
401 | * `89 <https://github.com/ipython/ipython/issues/89>`_: %pdoc np.ma.compress shows docstring twice |
|
401 | * `89 <https://github.com/ipython/ipython/issues/89>`_: %pdoc np.ma.compress shows docstring twice | |
402 | * `22 <https://github.com/ipython/ipython/issues/22>`_: Include improvements from anythingipython.el |
|
402 | * `22 <https://github.com/ipython/ipython/issues/22>`_: Include improvements from anythingipython.el | |
403 | * `633 <https://github.com/ipython/ipython/issues/633>`_: Execution count & SyntaxError |
|
403 | * `633 <https://github.com/ipython/ipython/issues/633>`_: Execution count & SyntaxError | |
404 | * `1095 <https://github.com/ipython/ipython/issues/1095>`_: Uncaught TypeError: Object has no method 'remove_and_cancell_tooltip' |
|
404 | * `1095 <https://github.com/ipython/ipython/issues/1095>`_: Uncaught TypeError: Object has no method 'remove_and_cancell_tooltip' | |
405 | * `1075 <https://github.com/ipython/ipython/issues/1075>`_: We're ignoring prompt customizations |
|
405 | * `1075 <https://github.com/ipython/ipython/issues/1075>`_: We're ignoring prompt customizations | |
406 | * `1086 <https://github.com/ipython/ipython/issues/1086>`_: Can't open qtconsole from outside source tree |
|
406 | * `1086 <https://github.com/ipython/ipython/issues/1086>`_: Can't open qtconsole from outside source tree | |
407 | * `1076 <https://github.com/ipython/ipython/issues/1076>`_: namespace changes broke `foo.*bar*?` syntax |
|
407 | * `1076 <https://github.com/ipython/ipython/issues/1076>`_: namespace changes broke `foo.*bar*?` syntax | |
408 | * `1074 <https://github.com/ipython/ipython/issues/1074>`_: pprinting old-style class objects fails (TypeError: 'tuple' object is not callable) |
|
408 | * `1074 <https://github.com/ipython/ipython/issues/1074>`_: pprinting old-style class objects fails (TypeError: 'tuple' object is not callable) | |
409 | * `1063 <https://github.com/ipython/ipython/issues/1063>`_: IPython.utils test error due to missing unicodedata module |
|
409 | * `1063 <https://github.com/ipython/ipython/issues/1063>`_: IPython.utils test error due to missing unicodedata module | |
410 | * `592 <https://github.com/ipython/ipython/issues/592>`_: Bug in argument parsing for %run |
|
410 | * `592 <https://github.com/ipython/ipython/issues/592>`_: Bug in argument parsing for %run | |
411 | * `378 <https://github.com/ipython/ipython/issues/378>`_: Windows path escape issues |
|
411 | * `378 <https://github.com/ipython/ipython/issues/378>`_: Windows path escape issues | |
412 | * `1068 <https://github.com/ipython/ipython/issues/1068>`_: Notebook tab completion broken in Firefox |
|
412 | * `1068 <https://github.com/ipython/ipython/issues/1068>`_: Notebook tab completion broken in Firefox | |
413 | * `75 <https://github.com/ipython/ipython/issues/75>`_: No tab completion after "/ |
|
413 | * `75 <https://github.com/ipython/ipython/issues/75>`_: No tab completion after "/ | |
414 | * `103 <https://github.com/ipython/ipython/issues/103>`_: customizable cpaste |
|
414 | * `103 <https://github.com/ipython/ipython/issues/103>`_: customizable cpaste | |
415 | * `324 <https://github.com/ipython/ipython/issues/324>`_: Remove code in IPython.testing that is not being used |
|
415 | * `324 <https://github.com/ipython/ipython/issues/324>`_: Remove code in IPython.testing that is not being used | |
416 | * `131 <https://github.com/ipython/ipython/issues/131>`_: Global variables not seen by cprofile.run() |
|
416 | * `131 <https://github.com/ipython/ipython/issues/131>`_: Global variables not seen by cprofile.run() | |
417 | * `851 <https://github.com/ipython/ipython/issues/851>`_: IPython shell swallows exceptions in certain circumstances |
|
417 | * `851 <https://github.com/ipython/ipython/issues/851>`_: IPython shell swallows exceptions in certain circumstances | |
418 | * `882 <https://github.com/ipython/ipython/issues/882>`_: ipython freezes at start if IPYTHONDIR is on an NFS mount |
|
418 | * `882 <https://github.com/ipython/ipython/issues/882>`_: ipython freezes at start if IPYTHONDIR is on an NFS mount | |
419 | * `1057 <https://github.com/ipython/ipython/issues/1057>`_: Blocker: Qt console broken after "all magics" menu became dynamic |
|
419 | * `1057 <https://github.com/ipython/ipython/issues/1057>`_: Blocker: Qt console broken after "all magics" menu became dynamic | |
420 | * `1027 <https://github.com/ipython/ipython/issues/1027>`_: ipython does not like white space at end of file |
|
420 | * `1027 <https://github.com/ipython/ipython/issues/1027>`_: ipython does not like white space at end of file | |
421 | * `1058 <https://github.com/ipython/ipython/issues/1058>`_: New bug: Notebook asks for confirmation to leave even saved pages. |
|
421 | * `1058 <https://github.com/ipython/ipython/issues/1058>`_: New bug: Notebook asks for confirmation to leave even saved pages. | |
422 | * `1061 <https://github.com/ipython/ipython/issues/1061>`_: rep (magic recall) under pypy |
|
422 | * `1061 <https://github.com/ipython/ipython/issues/1061>`_: rep (magic recall) under pypy | |
423 | * `1047 <https://github.com/ipython/ipython/issues/1047>`_: Document the notebook format |
|
423 | * `1047 <https://github.com/ipython/ipython/issues/1047>`_: Document the notebook format | |
424 | * `102 <https://github.com/ipython/ipython/issues/102>`_: Properties accessed twice for classes defined interactively |
|
424 | * `102 <https://github.com/ipython/ipython/issues/102>`_: Properties accessed twice for classes defined interactively | |
425 | * `16 <https://github.com/ipython/ipython/issues/16>`_: %store raises exception when storing compiled regex |
|
425 | * `16 <https://github.com/ipython/ipython/issues/16>`_: %store raises exception when storing compiled regex | |
426 | * `67 <https://github.com/ipython/ipython/issues/67>`_: tab expansion should only take one directory level at the time |
|
426 | * `67 <https://github.com/ipython/ipython/issues/67>`_: tab expansion should only take one directory level at the time | |
427 | * `62 <https://github.com/ipython/ipython/issues/62>`_: Global variables undefined in interactive use of embedded ipython shell |
|
427 | * `62 <https://github.com/ipython/ipython/issues/62>`_: Global variables undefined in interactive use of embedded ipython shell | |
428 | * `57 <https://github.com/ipython/ipython/issues/57>`_: debugging with ipython does not work well outside ipython |
|
428 | * `57 <https://github.com/ipython/ipython/issues/57>`_: debugging with ipython does not work well outside ipython | |
429 | * `38 <https://github.com/ipython/ipython/issues/38>`_: Line entry edge case error |
|
429 | * `38 <https://github.com/ipython/ipython/issues/38>`_: Line entry edge case error | |
430 | * `980 <https://github.com/ipython/ipython/issues/980>`_: Update parallel docs for new parallel architecture |
|
430 | * `980 <https://github.com/ipython/ipython/issues/980>`_: Update parallel docs for new parallel architecture | |
431 | * `1017 <https://github.com/ipython/ipython/issues/1017>`_: Add small example about ipcluster/ssh startup |
|
431 | * `1017 <https://github.com/ipython/ipython/issues/1017>`_: Add small example about ipcluster/ssh startup | |
432 | * `1041 <https://github.com/ipython/ipython/issues/1041>`_: Proxy Issues |
|
432 | * `1041 <https://github.com/ipython/ipython/issues/1041>`_: Proxy Issues | |
433 | * `967 <https://github.com/ipython/ipython/issues/967>`_: KernelManagers don't use zmq eventloop properly |
|
433 | * `967 <https://github.com/ipython/ipython/issues/967>`_: KernelManagers don't use zmq eventloop properly | |
434 | * `1055 <https://github.com/ipython/ipython/issues/1055>`_: "All Magics" display on Ubuntu |
|
434 | * `1055 <https://github.com/ipython/ipython/issues/1055>`_: "All Magics" display on Ubuntu | |
435 | * `1054 <https://github.com/ipython/ipython/issues/1054>`_: ipython explodes on syntax error |
|
435 | * `1054 <https://github.com/ipython/ipython/issues/1054>`_: ipython explodes on syntax error | |
436 | * `1051 <https://github.com/ipython/ipython/issues/1051>`_: ipython3 set_next_input() failure |
|
436 | * `1051 <https://github.com/ipython/ipython/issues/1051>`_: ipython3 set_next_input() failure | |
437 | * `693 <https://github.com/ipython/ipython/issues/693>`_: "run -i" no longer works after %reset in terminal |
|
437 | * `693 <https://github.com/ipython/ipython/issues/693>`_: "run -i" no longer works after %reset in terminal | |
438 | * `29 <https://github.com/ipython/ipython/issues/29>`_: cPickle works in standard interpreter, but not in IPython |
|
438 | * `29 <https://github.com/ipython/ipython/issues/29>`_: cPickle works in standard interpreter, but not in IPython | |
439 | * `1050 <https://github.com/ipython/ipython/issues/1050>`_: ipython3 broken by commit 8bb887c8c2c447bf7 |
|
439 | * `1050 <https://github.com/ipython/ipython/issues/1050>`_: ipython3 broken by commit 8bb887c8c2c447bf7 | |
440 | * `1048 <https://github.com/ipython/ipython/issues/1048>`_: Update docs on notebook password |
|
440 | * `1048 <https://github.com/ipython/ipython/issues/1048>`_: Update docs on notebook password | |
441 | * `1046 <https://github.com/ipython/ipython/issues/1046>`_: Searies of questions/issues? |
|
441 | * `1046 <https://github.com/ipython/ipython/issues/1046>`_: Searies of questions/issues? | |
442 | * `1045 <https://github.com/ipython/ipython/issues/1045>`_: crash when exiting - previously launched embedded sub-shell |
|
442 | * `1045 <https://github.com/ipython/ipython/issues/1045>`_: crash when exiting - previously launched embedded sub-shell | |
443 | * `1043 <https://github.com/ipython/ipython/issues/1043>`_: pylab doesn't work in qtconsole |
|
443 | * `1043 <https://github.com/ipython/ipython/issues/1043>`_: pylab doesn't work in qtconsole | |
444 | * `1044 <https://github.com/ipython/ipython/issues/1044>`_: run -p doesn't work in python 3 |
|
444 | * `1044 <https://github.com/ipython/ipython/issues/1044>`_: run -p doesn't work in python 3 | |
445 | * `1010 <https://github.com/ipython/ipython/issues/1010>`_: emacs freezes when ipython-complete is called |
|
445 | * `1010 <https://github.com/ipython/ipython/issues/1010>`_: emacs freezes when ipython-complete is called | |
446 | * `82 <https://github.com/ipython/ipython/issues/82>`_: Update devel docs with discussion about good changelogs |
|
446 | * `82 <https://github.com/ipython/ipython/issues/82>`_: Update devel docs with discussion about good changelogs | |
447 | * `116 <https://github.com/ipython/ipython/issues/116>`_: Update release management scipts and release.revision for git |
|
447 | * `116 <https://github.com/ipython/ipython/issues/116>`_: Update release management scipts and release.revision for git | |
448 | * `1022 <https://github.com/ipython/ipython/issues/1022>`_: Pylab banner shows up with first cell to execute |
|
448 | * `1022 <https://github.com/ipython/ipython/issues/1022>`_: Pylab banner shows up with first cell to execute | |
449 | * `787 <https://github.com/ipython/ipython/issues/787>`_: Keyboard selection of multiple lines in the notebook behaves inconsistently |
|
449 | * `787 <https://github.com/ipython/ipython/issues/787>`_: Keyboard selection of multiple lines in the notebook behaves inconsistently | |
450 | * `1037 <https://github.com/ipython/ipython/issues/1037>`_: notepad + jsonlib: TypeError: Only whitespace may be used for indentation. |
|
450 | * `1037 <https://github.com/ipython/ipython/issues/1037>`_: notepad + jsonlib: TypeError: Only whitespace may be used for indentation. | |
451 | * `970 <https://github.com/ipython/ipython/issues/970>`_: Default home not writable, %HOME% does not help (windows) |
|
451 | * `970 <https://github.com/ipython/ipython/issues/970>`_: Default home not writable, %HOME% does not help (windows) | |
452 | * `747 <https://github.com/ipython/ipython/issues/747>`_: HOMESHARE not a good choice for "writable homedir" on Windows |
|
452 | * `747 <https://github.com/ipython/ipython/issues/747>`_: HOMESHARE not a good choice for "writable homedir" on Windows | |
453 | * `810 <https://github.com/ipython/ipython/issues/810>`_: cleanup utils.path.get_home_dir |
|
453 | * `810 <https://github.com/ipython/ipython/issues/810>`_: cleanup utils.path.get_home_dir | |
454 | * `2 <https://github.com/ipython/ipython/issues/2>`_: Fix the copyright statement in source code files to be accurate |
|
454 | * `2 <https://github.com/ipython/ipython/issues/2>`_: Fix the copyright statement in source code files to be accurate | |
455 | * `1031 <https://github.com/ipython/ipython/issues/1031>`_: <esc> on Firefox crash websocket |
|
455 | * `1031 <https://github.com/ipython/ipython/issues/1031>`_: <esc> on Firefox crash websocket | |
456 | * `684 <https://github.com/ipython/ipython/issues/684>`_: %Store eliminated in configuration and magic commands in 0.11 |
|
456 | * `684 <https://github.com/ipython/ipython/issues/684>`_: %Store eliminated in configuration and magic commands in 0.11 | |
457 | * `1026 <https://github.com/ipython/ipython/issues/1026>`_: BUG: wrong default parameter in ask_yes_no |
|
457 | * `1026 <https://github.com/ipython/ipython/issues/1026>`_: BUG: wrong default parameter in ask_yes_no | |
458 | * `880 <https://github.com/ipython/ipython/issues/880>`_: Better error message if %paste fails |
|
458 | * `880 <https://github.com/ipython/ipython/issues/880>`_: Better error message if %paste fails | |
459 | * `1024 <https://github.com/ipython/ipython/issues/1024>`_: autopx magic broken |
|
459 | * `1024 <https://github.com/ipython/ipython/issues/1024>`_: autopx magic broken | |
460 | * `822 <https://github.com/ipython/ipython/issues/822>`_: Unicode bug in Itpl when expanding shell variables in syscalls with ! |
|
460 | * `822 <https://github.com/ipython/ipython/issues/822>`_: Unicode bug in Itpl when expanding shell variables in syscalls with ! | |
461 | * `1009 <https://github.com/ipython/ipython/issues/1009>`_: Windows: regression in cd magic handling of paths |
|
461 | * `1009 <https://github.com/ipython/ipython/issues/1009>`_: Windows: regression in cd magic handling of paths | |
462 | * `833 <https://github.com/ipython/ipython/issues/833>`_: Crash python with matplotlib and unequal length arrays |
|
462 | * `833 <https://github.com/ipython/ipython/issues/833>`_: Crash python with matplotlib and unequal length arrays | |
463 | * `695 <https://github.com/ipython/ipython/issues/695>`_: Crash handler initialization is too aggressive |
|
463 | * `695 <https://github.com/ipython/ipython/issues/695>`_: Crash handler initialization is too aggressive | |
464 | * `1000 <https://github.com/ipython/ipython/issues/1000>`_: Remove duplicates when refilling readline history |
|
464 | * `1000 <https://github.com/ipython/ipython/issues/1000>`_: Remove duplicates when refilling readline history | |
465 | * `992 <https://github.com/ipython/ipython/issues/992>`_: Interrupting certain matplotlib operations leaves the inline backend 'wedged' |
|
465 | * `992 <https://github.com/ipython/ipython/issues/992>`_: Interrupting certain matplotlib operations leaves the inline backend 'wedged' | |
466 | * `942 <https://github.com/ipython/ipython/issues/942>`_: number traits should cast if value doesn't change |
|
466 | * `942 <https://github.com/ipython/ipython/issues/942>`_: number traits should cast if value doesn't change | |
467 | * `1006 <https://github.com/ipython/ipython/issues/1006>`_: ls crashes when run on a UNC path or with non-ascii args |
|
467 | * `1006 <https://github.com/ipython/ipython/issues/1006>`_: ls crashes when run on a UNC path or with non-ascii args | |
468 | * `944 <https://github.com/ipython/ipython/issues/944>`_: Decide the default image format for inline figures: SVG or PNG? |
|
468 | * `944 <https://github.com/ipython/ipython/issues/944>`_: Decide the default image format for inline figures: SVG or PNG? | |
469 | * `842 <https://github.com/ipython/ipython/issues/842>`_: Python 3 on Windows (pyreadline) - expected an object with the buffer interface |
|
469 | * `842 <https://github.com/ipython/ipython/issues/842>`_: Python 3 on Windows (pyreadline) - expected an object with the buffer interface | |
470 | * `1002 <https://github.com/ipython/ipython/issues/1002>`_: ImportError due to incorrect version checking |
|
470 | * `1002 <https://github.com/ipython/ipython/issues/1002>`_: ImportError due to incorrect version checking | |
471 | * `1001 <https://github.com/ipython/ipython/issues/1001>`_: Ipython "source" command? |
|
471 | * `1001 <https://github.com/ipython/ipython/issues/1001>`_: Ipython "source" command? | |
472 | * `954 <https://github.com/ipython/ipython/issues/954>`_: IPython embed doesn't respect namespaces |
|
472 | * `954 <https://github.com/ipython/ipython/issues/954>`_: IPython embed doesn't respect namespaces | |
473 | * `681 <https://github.com/ipython/ipython/issues/681>`_: pdb freezes inside qtconsole |
|
473 | * `681 <https://github.com/ipython/ipython/issues/681>`_: pdb freezes inside qtconsole | |
474 | * `698 <https://github.com/ipython/ipython/issues/698>`_: crash report "TypeError: can only concatenate list (not "unicode") to list" |
|
474 | * `698 <https://github.com/ipython/ipython/issues/698>`_: crash report "TypeError: can only concatenate list (not "unicode") to list" | |
475 | * `978 <https://github.com/ipython/ipython/issues/978>`_: ipython 0.11 buffers external command output till the cmd is done |
|
475 | * `978 <https://github.com/ipython/ipython/issues/978>`_: ipython 0.11 buffers external command output till the cmd is done | |
476 | * `952 <https://github.com/ipython/ipython/issues/952>`_: Need user-facing warning in the browser if websocket connection fails |
|
476 | * `952 <https://github.com/ipython/ipython/issues/952>`_: Need user-facing warning in the browser if websocket connection fails | |
477 | * `988 <https://github.com/ipython/ipython/issues/988>`_: Error using idlsave |
|
477 | * `988 <https://github.com/ipython/ipython/issues/988>`_: Error using idlsave | |
478 | * `990 <https://github.com/ipython/ipython/issues/990>`_: ipython notebook - kernel dies if matplotlib is not installed |
|
478 | * `990 <https://github.com/ipython/ipython/issues/990>`_: ipython notebook - kernel dies if matplotlib is not installed | |
479 | * `752 <https://github.com/ipython/ipython/issues/752>`_: Matplotlib figures showed only once in notebook |
|
479 | * `752 <https://github.com/ipython/ipython/issues/752>`_: Matplotlib figures showed only once in notebook | |
480 | * `54 <https://github.com/ipython/ipython/issues/54>`_: Exception hook should be optional for embedding IPython in GUIs |
|
480 | * `54 <https://github.com/ipython/ipython/issues/54>`_: Exception hook should be optional for embedding IPython in GUIs | |
481 | * `918 <https://github.com/ipython/ipython/issues/918>`_: IPython.frontend tests fail without tornado |
|
481 | * `918 <https://github.com/ipython/ipython/issues/918>`_: IPython.frontend tests fail without tornado | |
482 | * `986 <https://github.com/ipython/ipython/issues/986>`_: Views created with c.direct_view() fail |
|
482 | * `986 <https://github.com/ipython/ipython/issues/986>`_: Views created with c.direct_view() fail | |
483 | * `697 <https://github.com/ipython/ipython/issues/697>`_: Filter out from %who names loaded at initialization time |
|
483 | * `697 <https://github.com/ipython/ipython/issues/697>`_: Filter out from %who names loaded at initialization time | |
484 | * `932 <https://github.com/ipython/ipython/issues/932>`_: IPython 0.11 quickref card has superfluous "%recall and" |
|
484 | * `932 <https://github.com/ipython/ipython/issues/932>`_: IPython 0.11 quickref card has superfluous "%recall and" | |
485 | * `982 <https://github.com/ipython/ipython/issues/982>`_: png files with executable permissions |
|
485 | * `982 <https://github.com/ipython/ipython/issues/982>`_: png files with executable permissions | |
486 | * `914 <https://github.com/ipython/ipython/issues/914>`_: Simpler system for running code after InteractiveShell is initialised |
|
486 | * `914 <https://github.com/ipython/ipython/issues/914>`_: Simpler system for running code after InteractiveShell is initialised | |
487 | * `911 <https://github.com/ipython/ipython/issues/911>`_: ipython crashes on startup if readline is missing |
|
487 | * `911 <https://github.com/ipython/ipython/issues/911>`_: ipython crashes on startup if readline is missing | |
488 | * `971 <https://github.com/ipython/ipython/issues/971>`_: bookmarks created in 0.11 are corrupt in 0.12 |
|
488 | * `971 <https://github.com/ipython/ipython/issues/971>`_: bookmarks created in 0.11 are corrupt in 0.12 | |
489 | * `974 <https://github.com/ipython/ipython/issues/974>`_: object feature tab-completion crash |
|
489 | * `974 <https://github.com/ipython/ipython/issues/974>`_: object feature tab-completion crash | |
490 | * `939 <https://github.com/ipython/ipython/issues/939>`_: ZMQShell always uses default profile |
|
490 | * `939 <https://github.com/ipython/ipython/issues/939>`_: ZMQShell always uses default profile | |
491 | * `946 <https://github.com/ipython/ipython/issues/946>`_: Multi-tab Close action should offer option to leave all kernels alone |
|
491 | * `946 <https://github.com/ipython/ipython/issues/946>`_: Multi-tab Close action should offer option to leave all kernels alone | |
492 | * `949 <https://github.com/ipython/ipython/issues/949>`_: Test suite must not require any manual interaction |
|
492 | * `949 <https://github.com/ipython/ipython/issues/949>`_: Test suite must not require any manual interaction | |
493 | * `643 <https://github.com/ipython/ipython/issues/643>`_: enable gui eventloop integration in ipkernel |
|
493 | * `643 <https://github.com/ipython/ipython/issues/643>`_: enable gui eventloop integration in ipkernel | |
494 | * `965 <https://github.com/ipython/ipython/issues/965>`_: ipython is crashed without launch.(python3.2) |
|
494 | * `965 <https://github.com/ipython/ipython/issues/965>`_: ipython is crashed without launch.(python3.2) | |
495 | * `958 <https://github.com/ipython/ipython/issues/958>`_: Can't use os X clipboard on with qtconsole |
|
495 | * `958 <https://github.com/ipython/ipython/issues/958>`_: Can't use os X clipboard on with qtconsole | |
496 | * `962 <https://github.com/ipython/ipython/issues/962>`_: Don't require tornado in the tests |
|
496 | * `962 <https://github.com/ipython/ipython/issues/962>`_: Don't require tornado in the tests | |
497 | * `960 <https://github.com/ipython/ipython/issues/960>`_: crash on syntax error on Windows XP |
|
497 | * `960 <https://github.com/ipython/ipython/issues/960>`_: crash on syntax error on Windows XP | |
498 | * `934 <https://github.com/ipython/ipython/issues/934>`_: The latest ipython branch doesn't work in Chrome |
|
498 | * `934 <https://github.com/ipython/ipython/issues/934>`_: The latest ipython branch doesn't work in Chrome | |
499 | * `870 <https://github.com/ipython/ipython/issues/870>`_: zmq version detection |
|
499 | * `870 <https://github.com/ipython/ipython/issues/870>`_: zmq version detection | |
500 | * `943 <https://github.com/ipython/ipython/issues/943>`_: HISTIGNORE for IPython |
|
500 | * `943 <https://github.com/ipython/ipython/issues/943>`_: HISTIGNORE for IPython | |
501 | * `947 <https://github.com/ipython/ipython/issues/947>`_: qtconsole segfaults at startup |
|
501 | * `947 <https://github.com/ipython/ipython/issues/947>`_: qtconsole segfaults at startup | |
502 | * `903 <https://github.com/ipython/ipython/issues/903>`_: Expose a magic to control config of the inline pylab backend |
|
502 | * `903 <https://github.com/ipython/ipython/issues/903>`_: Expose a magic to control config of the inline pylab backend | |
503 | * `908 <https://github.com/ipython/ipython/issues/908>`_: bad user config shouldn't crash IPython |
|
503 | * `908 <https://github.com/ipython/ipython/issues/908>`_: bad user config shouldn't crash IPython | |
504 | * `935 <https://github.com/ipython/ipython/issues/935>`_: Typing `break` causes IPython to crash. |
|
504 | * `935 <https://github.com/ipython/ipython/issues/935>`_: Typing `break` causes IPython to crash. | |
505 | * `869 <https://github.com/ipython/ipython/issues/869>`_: Tab completion of `~/` shows no output post 0.10.x |
|
505 | * `869 <https://github.com/ipython/ipython/issues/869>`_: Tab completion of `~/` shows no output post 0.10.x | |
506 | * `904 <https://github.com/ipython/ipython/issues/904>`_: whos under pypy1.6 |
|
506 | * `904 <https://github.com/ipython/ipython/issues/904>`_: whos under pypy1.6 | |
507 | * `773 <https://github.com/ipython/ipython/issues/773>`_: check_security_dir() and check_pid_dir() fail on network filesystem |
|
507 | * `773 <https://github.com/ipython/ipython/issues/773>`_: check_security_dir() and check_pid_dir() fail on network filesystem | |
508 | * `915 <https://github.com/ipython/ipython/issues/915>`_: OS X Lion Terminal.app line wrap problem |
|
508 | * `915 <https://github.com/ipython/ipython/issues/915>`_: OS X Lion Terminal.app line wrap problem | |
509 | * `886 <https://github.com/ipython/ipython/issues/886>`_: Notebook kernel crash when specifying --notebook-dir on commandline |
|
509 | * `886 <https://github.com/ipython/ipython/issues/886>`_: Notebook kernel crash when specifying --notebook-dir on commandline | |
510 | * `636 <https://github.com/ipython/ipython/issues/636>`_: debugger.py: pydb broken |
|
510 | * `636 <https://github.com/ipython/ipython/issues/636>`_: debugger.py: pydb broken | |
511 | * `808 <https://github.com/ipython/ipython/issues/808>`_: Ctrl+C during %reset confirm message crash Qtconsole |
|
511 | * `808 <https://github.com/ipython/ipython/issues/808>`_: Ctrl+C during %reset confirm message crash Qtconsole | |
512 | * `927 <https://github.com/ipython/ipython/issues/927>`_: Using return outside a function crashes ipython |
|
512 | * `927 <https://github.com/ipython/ipython/issues/927>`_: Using return outside a function crashes ipython | |
513 | * `919 <https://github.com/ipython/ipython/issues/919>`_: Pop-up segfault when moving cursor out of qtconsole window |
|
513 | * `919 <https://github.com/ipython/ipython/issues/919>`_: Pop-up segfault when moving cursor out of qtconsole window | |
514 | * `181 <https://github.com/ipython/ipython/issues/181>`_: cls command does not work on windows |
|
514 | * `181 <https://github.com/ipython/ipython/issues/181>`_: cls command does not work on windows | |
515 | * `917 <https://github.com/ipython/ipython/issues/917>`_: documentation typos |
|
515 | * `917 <https://github.com/ipython/ipython/issues/917>`_: documentation typos | |
516 | * `818 <https://github.com/ipython/ipython/issues/818>`_: %run does not work with non-ascii characeters in path |
|
516 | * `818 <https://github.com/ipython/ipython/issues/818>`_: %run does not work with non-ascii characeters in path | |
517 | * `907 <https://github.com/ipython/ipython/issues/907>`_: Errors in custom completer functions can crash IPython |
|
517 | * `907 <https://github.com/ipython/ipython/issues/907>`_: Errors in custom completer functions can crash IPython | |
518 | * `867 <https://github.com/ipython/ipython/issues/867>`_: doc: notebook password authentication howto |
|
518 | * `867 <https://github.com/ipython/ipython/issues/867>`_: doc: notebook password authentication howto | |
519 | * `211 <https://github.com/ipython/ipython/issues/211>`_: paste command not working |
|
519 | * `211 <https://github.com/ipython/ipython/issues/211>`_: paste command not working | |
520 | * `900 <https://github.com/ipython/ipython/issues/900>`_: Tab key should insert 4 spaces in qt console |
|
520 | * `900 <https://github.com/ipython/ipython/issues/900>`_: Tab key should insert 4 spaces in qt console | |
521 | * `513 <https://github.com/ipython/ipython/issues/513>`_: [Qt console] cannot insert new lines into console functions using tab |
|
521 | * `513 <https://github.com/ipython/ipython/issues/513>`_: [Qt console] cannot insert new lines into console functions using tab | |
522 | * `906 <https://github.com/ipython/ipython/issues/906>`_: qtconsoleapp 'parse_command_line' doen't like --existing anymore |
|
522 | * `906 <https://github.com/ipython/ipython/issues/906>`_: qtconsoleapp 'parse_command_line' doen't like --existing anymore | |
523 | * `638 <https://github.com/ipython/ipython/issues/638>`_: Qt console --pylab=inline and getfigs(), etc. |
|
523 | * `638 <https://github.com/ipython/ipython/issues/638>`_: Qt console --pylab=inline and getfigs(), etc. | |
524 | * `710 <https://github.com/ipython/ipython/issues/710>`_: unwanted unicode passed to args |
|
524 | * `710 <https://github.com/ipython/ipython/issues/710>`_: unwanted unicode passed to args | |
525 | * `436 <https://github.com/ipython/ipython/issues/436>`_: Users should see tooltips for all buttons in the notebook UI |
|
525 | * `436 <https://github.com/ipython/ipython/issues/436>`_: Users should see tooltips for all buttons in the notebook UI | |
526 | * `207 <https://github.com/ipython/ipython/issues/207>`_: ipython crashes if atexit handler raises exception |
|
526 | * `207 <https://github.com/ipython/ipython/issues/207>`_: ipython crashes if atexit handler raises exception | |
527 | * `692 <https://github.com/ipython/ipython/issues/692>`_: use of Tracer() when debugging works but gives error messages |
|
527 | * `692 <https://github.com/ipython/ipython/issues/692>`_: use of Tracer() when debugging works but gives error messages | |
528 | * `690 <https://github.com/ipython/ipython/issues/690>`_: debugger does not print error message by default in 0.11 |
|
528 | * `690 <https://github.com/ipython/ipython/issues/690>`_: debugger does not print error message by default in 0.11 | |
529 | * `571 <https://github.com/ipython/ipython/issues/571>`_: history of multiline entries |
|
529 | * `571 <https://github.com/ipython/ipython/issues/571>`_: history of multiline entries | |
530 | * `749 <https://github.com/ipython/ipython/issues/749>`_: IPython.parallel test failure under Windows 7 and XP |
|
530 | * `749 <https://github.com/ipython/ipython/issues/749>`_: IPython.parallel test failure under Windows 7 and XP | |
531 | * `890 <https://github.com/ipython/ipython/issues/890>`_: ipclusterapp.py - helep |
|
531 | * `890 <https://github.com/ipython/ipython/issues/890>`_: ipclusterapp.py - helep | |
532 | * `885 <https://github.com/ipython/ipython/issues/885>`_: `ws-hostname` alias not recognized by notebook |
|
532 | * `885 <https://github.com/ipython/ipython/issues/885>`_: `ws-hostname` alias not recognized by notebook | |
533 | * `881 <https://github.com/ipython/ipython/issues/881>`_: Missing manual.pdf? |
|
533 | * `881 <https://github.com/ipython/ipython/issues/881>`_: Missing manual.pdf? | |
534 | * `744 <https://github.com/ipython/ipython/issues/744>`_: cannot create notebook in offline mode if mathjax not installed |
|
534 | * `744 <https://github.com/ipython/ipython/issues/744>`_: cannot create notebook in offline mode if mathjax not installed | |
535 | * `865 <https://github.com/ipython/ipython/issues/865>`_: Make tracebacks from %paste show the code |
|
535 | * `865 <https://github.com/ipython/ipython/issues/865>`_: Make tracebacks from %paste show the code | |
536 | * `535 <https://github.com/ipython/ipython/issues/535>`_: exception unicode handling in %run is faulty in qtconsole |
|
536 | * `535 <https://github.com/ipython/ipython/issues/535>`_: exception unicode handling in %run is faulty in qtconsole | |
537 | * `817 <https://github.com/ipython/ipython/issues/817>`_: iPython crashed |
|
537 | * `817 <https://github.com/ipython/ipython/issues/817>`_: iPython crashed | |
538 | * `799 <https://github.com/ipython/ipython/issues/799>`_: %edit magic not working on windows xp in qtconsole |
|
538 | * `799 <https://github.com/ipython/ipython/issues/799>`_: %edit magic not working on windows xp in qtconsole | |
539 | * `732 <https://github.com/ipython/ipython/issues/732>`_: QTConsole wrongly promotes the index of the input line on which user presses Enter |
|
539 | * `732 <https://github.com/ipython/ipython/issues/732>`_: QTConsole wrongly promotes the index of the input line on which user presses Enter | |
540 | * `662 <https://github.com/ipython/ipython/issues/662>`_: ipython test failures on Mac OS X Lion |
|
540 | * `662 <https://github.com/ipython/ipython/issues/662>`_: ipython test failures on Mac OS X Lion | |
541 | * `650 <https://github.com/ipython/ipython/issues/650>`_: Handle bad config files better |
|
541 | * `650 <https://github.com/ipython/ipython/issues/650>`_: Handle bad config files better | |
542 | * `829 <https://github.com/ipython/ipython/issues/829>`_: We should not insert new lines after all print statements in the notebook |
|
542 | * `829 <https://github.com/ipython/ipython/issues/829>`_: We should not insert new lines after all print statements in the notebook | |
543 | * `874 <https://github.com/ipython/ipython/issues/874>`_: ipython-qtconsole: pyzmq Version Comparison |
|
543 | * `874 <https://github.com/ipython/ipython/issues/874>`_: ipython-qtconsole: pyzmq Version Comparison | |
544 | * `640 <https://github.com/ipython/ipython/issues/640>`_: matplotlib macosx windows don't respond in qtconsole |
|
544 | * `640 <https://github.com/ipython/ipython/issues/640>`_: matplotlib macosx windows don't respond in qtconsole | |
545 | * `624 <https://github.com/ipython/ipython/issues/624>`_: ipython intermittently segfaults when figure is closed (Mac OS X) |
|
545 | * `624 <https://github.com/ipython/ipython/issues/624>`_: ipython intermittently segfaults when figure is closed (Mac OS X) | |
546 | * `871 <https://github.com/ipython/ipython/issues/871>`_: Notebook crashes if a profile is used |
|
546 | * `871 <https://github.com/ipython/ipython/issues/871>`_: Notebook crashes if a profile is used | |
547 | * `56 <https://github.com/ipython/ipython/issues/56>`_: Have %cpaste accept also Ctrl-D as a termination marker |
|
547 | * `56 <https://github.com/ipython/ipython/issues/56>`_: Have %cpaste accept also Ctrl-D as a termination marker | |
548 | * `849 <https://github.com/ipython/ipython/issues/849>`_: Command line options to not override profile options |
|
548 | * `849 <https://github.com/ipython/ipython/issues/849>`_: Command line options to not override profile options | |
549 | * `806 <https://github.com/ipython/ipython/issues/806>`_: Provide single-port connection to kernels |
|
549 | * `806 <https://github.com/ipython/ipython/issues/806>`_: Provide single-port connection to kernels | |
550 | * `691 <https://github.com/ipython/ipython/issues/691>`_: [wishlist] Automatically find existing kernel |
|
550 | * `691 <https://github.com/ipython/ipython/issues/691>`_: [wishlist] Automatically find existing kernel | |
551 | * `688 <https://github.com/ipython/ipython/issues/688>`_: local security vulnerability: all ports visible to any local user. |
|
551 | * `688 <https://github.com/ipython/ipython/issues/688>`_: local security vulnerability: all ports visible to any local user. | |
552 | * `866 <https://github.com/ipython/ipython/issues/866>`_: DistributionNotFound on running ipython 0.11 on Windows XP x86 |
|
552 | * `866 <https://github.com/ipython/ipython/issues/866>`_: DistributionNotFound on running ipython 0.11 on Windows XP x86 | |
553 | * `673 <https://github.com/ipython/ipython/issues/673>`_: raw_input appears to be round-robin for qtconsole |
|
553 | * `673 <https://github.com/ipython/ipython/issues/673>`_: raw_input appears to be round-robin for qtconsole | |
554 | * `863 <https://github.com/ipython/ipython/issues/863>`_: Graceful degradation when home directory not writable |
|
554 | * `863 <https://github.com/ipython/ipython/issues/863>`_: Graceful degradation when home directory not writable | |
555 | * `800 <https://github.com/ipython/ipython/issues/800>`_: Timing scripts with run -t -N <N> fails on report output |
|
555 | * `800 <https://github.com/ipython/ipython/issues/800>`_: Timing scripts with run -t -N <N> fails on report output | |
556 | * `858 <https://github.com/ipython/ipython/issues/858>`_: Typing 'continue' makes ipython0.11 crash |
|
556 | * `858 <https://github.com/ipython/ipython/issues/858>`_: Typing 'continue' makes ipython0.11 crash | |
557 | * `840 <https://github.com/ipython/ipython/issues/840>`_: all processes run on one CPU core |
|
557 | * `840 <https://github.com/ipython/ipython/issues/840>`_: all processes run on one CPU core | |
558 | * `843 <https://github.com/ipython/ipython/issues/843>`_: "import braces" crashes ipython |
|
558 | * `843 <https://github.com/ipython/ipython/issues/843>`_: "import braces" crashes ipython | |
559 | * `836 <https://github.com/ipython/ipython/issues/836>`_: Strange Output after IPython Install |
|
559 | * `836 <https://github.com/ipython/ipython/issues/836>`_: Strange Output after IPython Install | |
560 | * `839 <https://github.com/ipython/ipython/issues/839>`_: Qtconsole segfaults when mouse exits window with active tooltip |
|
560 | * `839 <https://github.com/ipython/ipython/issues/839>`_: Qtconsole segfaults when mouse exits window with active tooltip | |
561 | * `827 <https://github.com/ipython/ipython/issues/827>`_: Add support for checking several limits before running task on engine |
|
561 | * `827 <https://github.com/ipython/ipython/issues/827>`_: Add support for checking several limits before running task on engine | |
562 | * `826 <https://github.com/ipython/ipython/issues/826>`_: Add support for creation of parallel task when no engine is running |
|
562 | * `826 <https://github.com/ipython/ipython/issues/826>`_: Add support for creation of parallel task when no engine is running | |
563 | * `832 <https://github.com/ipython/ipython/issues/832>`_: Improve error message for %logstop |
|
563 | * `832 <https://github.com/ipython/ipython/issues/832>`_: Improve error message for %logstop | |
564 | * `831 <https://github.com/ipython/ipython/issues/831>`_: %logstart in read-only directory forbid any further command |
|
564 | * `831 <https://github.com/ipython/ipython/issues/831>`_: %logstart in read-only directory forbid any further command | |
565 | * `814 <https://github.com/ipython/ipython/issues/814>`_: ipython does not start -- DistributionNotFound |
|
565 | * `814 <https://github.com/ipython/ipython/issues/814>`_: ipython does not start -- DistributionNotFound | |
566 | * `794 <https://github.com/ipython/ipython/issues/794>`_: Allow >1 controller per profile |
|
566 | * `794 <https://github.com/ipython/ipython/issues/794>`_: Allow >1 controller per profile | |
567 | * `820 <https://github.com/ipython/ipython/issues/820>`_: Tab Completion feature |
|
567 | * `820 <https://github.com/ipython/ipython/issues/820>`_: Tab Completion feature | |
568 | * `812 <https://github.com/ipython/ipython/issues/812>`_: Qt console crashes on Ubuntu 11.10 |
|
568 | * `812 <https://github.com/ipython/ipython/issues/812>`_: Qt console crashes on Ubuntu 11.10 | |
569 | * `816 <https://github.com/ipython/ipython/issues/816>`_: Import error using Python 2.7 and dateutil2.0 No module named _thread |
|
569 | * `816 <https://github.com/ipython/ipython/issues/816>`_: Import error using Python 2.7 and dateutil2.0 No module named _thread | |
570 | * `756 <https://github.com/ipython/ipython/issues/756>`_: qtconsole Windows fails to print error message for '%run nonexistent_file' |
|
570 | * `756 <https://github.com/ipython/ipython/issues/756>`_: qtconsole Windows fails to print error message for '%run nonexistent_file' | |
571 | * `651 <https://github.com/ipython/ipython/issues/651>`_: Completion doesn't work on element of a list |
|
571 | * `651 <https://github.com/ipython/ipython/issues/651>`_: Completion doesn't work on element of a list | |
572 | * `617 <https://github.com/ipython/ipython/issues/617>`_: [qtconsole] %hist doesn't show anything in qtconsole |
|
572 | * `617 <https://github.com/ipython/ipython/issues/617>`_: [qtconsole] %hist doesn't show anything in qtconsole | |
573 | * `786 <https://github.com/ipython/ipython/issues/786>`_: from __future__ import unicode_literals does not work |
|
573 | * `786 <https://github.com/ipython/ipython/issues/786>`_: from __future__ import unicode_literals does not work | |
574 | * `779 <https://github.com/ipython/ipython/issues/779>`_: Using irunner from virtual evn uses systemwide ipython |
|
574 | * `779 <https://github.com/ipython/ipython/issues/779>`_: Using irunner from virtual evn uses systemwide ipython | |
575 | * `768 <https://github.com/ipython/ipython/issues/768>`_: codepage handling of output from scripts and shellcommands are not handled properly by qtconsole |
|
575 | * `768 <https://github.com/ipython/ipython/issues/768>`_: codepage handling of output from scripts and shellcommands are not handled properly by qtconsole | |
576 | * `785 <https://github.com/ipython/ipython/issues/785>`_: Don't strip leading whitespace in repr() in notebook |
|
576 | * `785 <https://github.com/ipython/ipython/issues/785>`_: Don't strip leading whitespace in repr() in notebook | |
577 | * `737 <https://github.com/ipython/ipython/issues/737>`_: in pickleshare.py line52 should be "if not os.path.isdir(self.root):"? |
|
577 | * `737 <https://github.com/ipython/ipython/issues/737>`_: in pickleshare.py line52 should be "if not os.path.isdir(self.root):"? | |
578 | * `738 <https://github.com/ipython/ipython/issues/738>`_: in ipthon_win_post_install.py line 38 |
|
578 | * `738 <https://github.com/ipython/ipython/issues/738>`_: in ipthon_win_post_install.py line 38 | |
579 | * `777 <https://github.com/ipython/ipython/issues/777>`_: print(β¦, sep=β¦) raises SyntaxError |
|
579 | * `777 <https://github.com/ipython/ipython/issues/777>`_: print(β¦, sep=β¦) raises SyntaxError | |
580 | * `728 <https://github.com/ipython/ipython/issues/728>`_: ipcontroller crash with MPI |
|
580 | * `728 <https://github.com/ipython/ipython/issues/728>`_: ipcontroller crash with MPI | |
581 | * `780 <https://github.com/ipython/ipython/issues/780>`_: qtconsole Out value prints before the print statements that precede it |
|
581 | * `780 <https://github.com/ipython/ipython/issues/780>`_: qtconsole Out value prints before the print statements that precede it | |
582 | * `632 <https://github.com/ipython/ipython/issues/632>`_: IPython Crash Report (0.10.2) |
|
582 | * `632 <https://github.com/ipython/ipython/issues/632>`_: IPython Crash Report (0.10.2) | |
583 | * `253 <https://github.com/ipython/ipython/issues/253>`_: Unable to install ipython on windows |
|
583 | * `253 <https://github.com/ipython/ipython/issues/253>`_: Unable to install ipython on windows | |
584 | * `80 <https://github.com/ipython/ipython/issues/80>`_: Split IPClusterApp into multiple Application subclasses for each subcommand |
|
584 | * `80 <https://github.com/ipython/ipython/issues/80>`_: Split IPClusterApp into multiple Application subclasses for each subcommand | |
585 | * `34 <https://github.com/ipython/ipython/issues/34>`_: non-blocking pendingResult partial results |
|
585 | * `34 <https://github.com/ipython/ipython/issues/34>`_: non-blocking pendingResult partial results | |
586 | * `739 <https://github.com/ipython/ipython/issues/739>`_: Tests fail if tornado not installed |
|
586 | * `739 <https://github.com/ipython/ipython/issues/739>`_: Tests fail if tornado not installed | |
587 | * `719 <https://github.com/ipython/ipython/issues/719>`_: Better support Pypy |
|
587 | * `719 <https://github.com/ipython/ipython/issues/719>`_: Better support Pypy | |
588 | * `667 <https://github.com/ipython/ipython/issues/667>`_: qtconsole problem with default pylab profile |
|
588 | * `667 <https://github.com/ipython/ipython/issues/667>`_: qtconsole problem with default pylab profile | |
589 | * `661 <https://github.com/ipython/ipython/issues/661>`_: ipythonrc referenced in magic command in 0.11 |
|
589 | * `661 <https://github.com/ipython/ipython/issues/661>`_: ipythonrc referenced in magic command in 0.11 | |
590 | * `665 <https://github.com/ipython/ipython/issues/665>`_: Source introspection with ?? is broken |
|
590 | * `665 <https://github.com/ipython/ipython/issues/665>`_: Source introspection with ?? is broken | |
591 | * `724 <https://github.com/ipython/ipython/issues/724>`_: crash - ipython qtconsole, %quickref |
|
591 | * `724 <https://github.com/ipython/ipython/issues/724>`_: crash - ipython qtconsole, %quickref | |
592 | * `655 <https://github.com/ipython/ipython/issues/655>`_: ipython with qtconsole crashes |
|
592 | * `655 <https://github.com/ipython/ipython/issues/655>`_: ipython with qtconsole crashes | |
593 | * `593 <https://github.com/ipython/ipython/issues/593>`_: HTML Notebook Prompt can be deleted . . . |
|
593 | * `593 <https://github.com/ipython/ipython/issues/593>`_: HTML Notebook Prompt can be deleted . . . | |
594 | * `563 <https://github.com/ipython/ipython/issues/563>`_: use argparse instead of kvloader for flags&aliases |
|
594 | * `563 <https://github.com/ipython/ipython/issues/563>`_: use argparse instead of kvloader for flags&aliases | |
595 | * `751 <https://github.com/ipython/ipython/issues/751>`_: Tornado version greater than 2.0 needed for firefox 6 |
|
595 | * `751 <https://github.com/ipython/ipython/issues/751>`_: Tornado version greater than 2.0 needed for firefox 6 | |
596 | * `720 <https://github.com/ipython/ipython/issues/720>`_: Crash report when importing easter egg |
|
596 | * `720 <https://github.com/ipython/ipython/issues/720>`_: Crash report when importing easter egg | |
597 | * `740 <https://github.com/ipython/ipython/issues/740>`_: Ctrl-Enter clears line in notebook |
|
597 | * `740 <https://github.com/ipython/ipython/issues/740>`_: Ctrl-Enter clears line in notebook | |
598 | * `772 <https://github.com/ipython/ipython/issues/772>`_: ipengine fails on Windows with "XXX lineno: 355, opcode: 0" |
|
598 | * `772 <https://github.com/ipython/ipython/issues/772>`_: ipengine fails on Windows with "XXX lineno: 355, opcode: 0" | |
599 | * `771 <https://github.com/ipython/ipython/issues/771>`_: Add python 3 tag to setup.py |
|
599 | * `771 <https://github.com/ipython/ipython/issues/771>`_: Add python 3 tag to setup.py | |
600 | * `767 <https://github.com/ipython/ipython/issues/767>`_: non-ascii in __doc__ string crashes qtconsole kernel when showing tooltip |
|
600 | * `767 <https://github.com/ipython/ipython/issues/767>`_: non-ascii in __doc__ string crashes qtconsole kernel when showing tooltip | |
601 | * `733 <https://github.com/ipython/ipython/issues/733>`_: In Windows, %run fails to strip quotes from filename |
|
601 | * `733 <https://github.com/ipython/ipython/issues/733>`_: In Windows, %run fails to strip quotes from filename | |
602 | * `721 <https://github.com/ipython/ipython/issues/721>`_: no completion in emacs by ipython(ipython.el) |
|
602 | * `721 <https://github.com/ipython/ipython/issues/721>`_: no completion in emacs by ipython(ipython.el) | |
603 | * `669 <https://github.com/ipython/ipython/issues/669>`_: Do not accept an ipython_dir that's not writeable |
|
603 | * `669 <https://github.com/ipython/ipython/issues/669>`_: Do not accept an ipython_dir that's not writeable | |
604 | * `711 <https://github.com/ipython/ipython/issues/711>`_: segfault on mac os x |
|
604 | * `711 <https://github.com/ipython/ipython/issues/711>`_: segfault on mac os x | |
605 | * `500 <https://github.com/ipython/ipython/issues/500>`_: "RuntimeError: Cannot change input buffer during execution" in console_widget.py |
|
605 | * `500 <https://github.com/ipython/ipython/issues/500>`_: "RuntimeError: Cannot change input buffer during execution" in console_widget.py | |
606 | * `707 <https://github.com/ipython/ipython/issues/707>`_: Copy and paste keyboard shortcuts do not work in Qt Console on OS X |
|
606 | * `707 <https://github.com/ipython/ipython/issues/707>`_: Copy and paste keyboard shortcuts do not work in Qt Console on OS X | |
607 | * `478 <https://github.com/ipython/ipython/issues/478>`_: PyZMQ's use of memoryviews breaks reconstruction of numpy arrays |
|
607 | * `478 <https://github.com/ipython/ipython/issues/478>`_: PyZMQ's use of memoryviews breaks reconstruction of numpy arrays | |
608 | * `694 <https://github.com/ipython/ipython/issues/694>`_: Turning off callout tips in qtconsole |
|
608 | * `694 <https://github.com/ipython/ipython/issues/694>`_: Turning off callout tips in qtconsole | |
609 | * `704 <https://github.com/ipython/ipython/issues/704>`_: return kills IPython |
|
609 | * `704 <https://github.com/ipython/ipython/issues/704>`_: return kills IPython | |
610 | * `442 <https://github.com/ipython/ipython/issues/442>`_: Users should have intelligent autoindenting in the notebook |
|
610 | * `442 <https://github.com/ipython/ipython/issues/442>`_: Users should have intelligent autoindenting in the notebook | |
611 | * `615 <https://github.com/ipython/ipython/issues/615>`_: Wireframe and implement a project dashboard page |
|
611 | * `615 <https://github.com/ipython/ipython/issues/615>`_: Wireframe and implement a project dashboard page | |
612 | * `614 <https://github.com/ipython/ipython/issues/614>`_: Wireframe and implement a notebook dashboard page |
|
612 | * `614 <https://github.com/ipython/ipython/issues/614>`_: Wireframe and implement a notebook dashboard page | |
613 | * `606 <https://github.com/ipython/ipython/issues/606>`_: Users should be able to use the notebook to import/export a notebook to .py or .rst |
|
613 | * `606 <https://github.com/ipython/ipython/issues/606>`_: Users should be able to use the notebook to import/export a notebook to .py or .rst | |
614 | * `604 <https://github.com/ipython/ipython/issues/604>`_: A user should be able to leave a kernel running in the notebook and reconnect |
|
614 | * `604 <https://github.com/ipython/ipython/issues/604>`_: A user should be able to leave a kernel running in the notebook and reconnect | |
615 | * `298 <https://github.com/ipython/ipython/issues/298>`_: Users should be able to save a notebook and then later reload it |
|
615 | * `298 <https://github.com/ipython/ipython/issues/298>`_: Users should be able to save a notebook and then later reload it | |
616 | * `649 <https://github.com/ipython/ipython/issues/649>`_: ipython qtconsole (v0.11): setting "c.IPythonWidget.in_prompt = '>>> ' crashes |
|
616 | * `649 <https://github.com/ipython/ipython/issues/649>`_: ipython qtconsole (v0.11): setting "c.IPythonWidget.in_prompt = '>>> ' crashes | |
617 | * `672 <https://github.com/ipython/ipython/issues/672>`_: What happened to Exit? |
|
617 | * `672 <https://github.com/ipython/ipython/issues/672>`_: What happened to Exit? | |
618 | * `658 <https://github.com/ipython/ipython/issues/658>`_: Put the InteractiveShellApp section first in the auto-generated config files |
|
618 | * `658 <https://github.com/ipython/ipython/issues/658>`_: Put the InteractiveShellApp section first in the auto-generated config files | |
619 | * `656 <https://github.com/ipython/ipython/issues/656>`_: [suggestion] dependency checking for pyqt for Windows installer |
|
619 | * `656 <https://github.com/ipython/ipython/issues/656>`_: [suggestion] dependency checking for pyqt for Windows installer | |
620 | * `654 <https://github.com/ipython/ipython/issues/654>`_: broken documentation link on download page |
|
620 | * `654 <https://github.com/ipython/ipython/issues/654>`_: broken documentation link on download page | |
621 | * `653 <https://github.com/ipython/ipython/issues/653>`_: Test failures in IPython.parallel |
|
621 | * `653 <https://github.com/ipython/ipython/issues/653>`_: Test failures in IPython.parallel |
@@ -1,1784 +1,1784 b'' | |||||
1 | .. _issues_list_100: |
|
1 | .. _issues_list_100: | |
2 |
|
2 | |||
3 | Issues closed in the 1.0 development cycle |
|
3 | Issues closed in the 1.0 development cycle | |
4 | ========================================== |
|
4 | ========================================== | |
5 |
|
5 | |||
6 | Issues closed in 1.1 |
|
6 | Issues closed in 1.1 | |
7 | -------------------- |
|
7 | -------------------- | |
8 |
|
8 | |||
9 | GitHub stats for 2013/08/08 - 2013/09/09 (since 1.0) |
|
9 | GitHub stats for 2013/08/08 - 2013/09/09 (since 1.0) | |
10 |
|
10 | |||
11 | These lists are automatically generated, and may be incomplete or contain duplicates. |
|
11 | These lists are automatically generated, and may be incomplete or contain duplicates. | |
12 |
|
12 | |||
13 | The following 25 authors contributed 337 commits. |
|
13 | The following 25 authors contributed 337 commits. | |
14 |
|
14 | |||
15 | * Benjamin Ragan-Kelley |
|
15 | * Benjamin Ragan-Kelley | |
16 | * Bing Xia |
|
16 | * Bing Xia | |
17 | * Bradley M. Froehle |
|
17 | * Bradley M. Froehle | |
18 | * Brian E. Granger |
|
18 | * Brian E. Granger | |
19 | * DamiΓ‘n Avila |
|
19 | * DamiΓ‘n Avila | |
20 | * dhirschfeld |
|
20 | * dhirschfeld | |
21 | * DraΕΎen LuΔanin |
|
21 | * DraΕΎen LuΔanin | |
22 | * gmbecker |
|
22 | * gmbecker | |
23 | * Jake Vanderplas |
|
23 | * Jake Vanderplas | |
24 | * Jason Grout |
|
24 | * Jason Grout | |
25 | * Jonathan Frederic |
|
25 | * Jonathan Frederic | |
26 | * Kevin Burke |
|
26 | * Kevin Burke | |
27 | * Kyle Kelley |
|
27 | * Kyle Kelley | |
28 | * Matt Henderson |
|
28 | * Matt Henderson | |
29 | * Matthew Brett |
|
29 | * Matthew Brett | |
30 | * Matthias Bussonnier |
|
30 | * Matthias Bussonnier | |
31 | * Pankaj Pandey |
|
31 | * Pankaj Pandey | |
32 | * Paul Ivanov |
|
32 | * Paul Ivanov | |
33 | * rossant |
|
33 | * rossant | |
34 | * Samuel Ainsworth |
|
34 | * Samuel Ainsworth | |
35 | * Stephan Rave |
|
35 | * Stephan Rave | |
36 | * stonebig |
|
36 | * stonebig | |
37 | * Thomas Kluyver |
|
37 | * Thomas Kluyver | |
38 | * Yaroslav Halchenko |
|
38 | * Yaroslav Halchenko | |
39 | * Zachary Sailer |
|
39 | * Zachary Sailer | |
40 |
|
40 | |||
41 |
|
41 | |||
42 | We closed a total of 76 issues, 58 pull requests and 18 regular issues; |
|
42 | We closed a total of 76 issues, 58 pull requests and 18 regular issues; | |
43 | this is the full list (generated with the script :file:`tools/github_stats.py`): |
|
43 | this is the full list (generated with the script :file:`tools/github_stats.py`): | |
44 |
|
44 | |||
45 | Pull Requests (58): |
|
45 | Pull Requests (58): | |
46 |
|
46 | |||
47 | * :ghpull:`4188`: Allow user_ns trait to be None |
|
47 | * :ghpull:`4188`: Allow user_ns trait to be None | |
48 | * :ghpull:`4189`: always fire LOCAL_IPS.extend(PUBLIC_IPS) |
|
48 | * :ghpull:`4189`: always fire LOCAL_IPS.extend(PUBLIC_IPS) | |
49 | * :ghpull:`4174`: various issues in markdown and rst templates |
|
49 | * :ghpull:`4174`: various issues in markdown and rst templates | |
50 | * :ghpull:`4178`: add missing data_javascript |
|
50 | * :ghpull:`4178`: add missing data_javascript | |
51 | * :ghpull:`4181`: nbconvert: Fix, sphinx template not removing new lines from headers |
|
51 | * :ghpull:`4181`: nbconvert: Fix, sphinx template not removing new lines from headers | |
52 | * :ghpull:`4043`: don't 'restore_bytes' in from_JSON |
|
52 | * :ghpull:`4043`: don't 'restore_bytes' in from_JSON | |
53 | * :ghpull:`4163`: Fix for incorrect default encoding on Windows. |
|
53 | * :ghpull:`4163`: Fix for incorrect default encoding on Windows. | |
54 | * :ghpull:`4136`: catch javascript errors in any output |
|
54 | * :ghpull:`4136`: catch javascript errors in any output | |
55 | * :ghpull:`4171`: add nbconvert config file when creating profiles |
|
55 | * :ghpull:`4171`: add nbconvert config file when creating profiles | |
56 | * :ghpull:`4125`: Basic exercise of `ipython [subcommand] -h` and help-all |
|
56 | * :ghpull:`4125`: Basic exercise of `ipython [subcommand] -h` and help-all | |
57 | * :ghpull:`4085`: nbconvert: Fix sphinx preprocessor date format string for Windows |
|
57 | * :ghpull:`4085`: nbconvert: Fix sphinx preprocessor date format string for Windows | |
58 | * :ghpull:`4159`: don't split `.cell` and `div.cell` CSS |
|
58 | * :ghpull:`4159`: don't split `.cell` and `div.cell` CSS | |
59 | * :ghpull:`4158`: generate choices for `--gui` configurable from real mapping |
|
59 | * :ghpull:`4158`: generate choices for `--gui` configurable from real mapping | |
60 | * :ghpull:`4065`: do not include specific css in embedable one |
|
60 | * :ghpull:`4065`: do not include specific css in embedable one | |
61 | * :ghpull:`4092`: nbconvert: Fix for unicode html headers, Windows + Python 2.x |
|
61 | * :ghpull:`4092`: nbconvert: Fix for unicode html headers, Windows + Python 2.x | |
62 | * :ghpull:`4074`: close Client sockets if connection fails |
|
62 | * :ghpull:`4074`: close Client sockets if connection fails | |
63 | * :ghpull:`4064`: Store default codemirror mode in only 1 place |
|
63 | * :ghpull:`4064`: Store default codemirror mode in only 1 place | |
64 | * :ghpull:`4104`: Add way to install MathJax to a particular profile |
|
64 | * :ghpull:`4104`: Add way to install MathJax to a particular profile | |
65 | * :ghpull:`4144`: help_end transformer shouldn't pick up ? in multiline string |
|
65 | * :ghpull:`4144`: help_end transformer shouldn't pick up ? in multiline string | |
66 | * :ghpull:`4143`: update example custom.js |
|
66 | * :ghpull:`4143`: update example custom.js | |
67 | * :ghpull:`4142`: DOC: unwrap openssl line in public_server doc |
|
67 | * :ghpull:`4142`: DOC: unwrap openssl line in public_server doc | |
68 | * :ghpull:`4141`: add files with a separate `add` call in backport_pr |
|
68 | * :ghpull:`4141`: add files with a separate `add` call in backport_pr | |
69 | * :ghpull:`4137`: Restore autorestore option for storemagic |
|
69 | * :ghpull:`4137`: Restore autorestore option for storemagic | |
70 | * :ghpull:`4098`: pass profile-dir instead of profile name to Kernel |
|
70 | * :ghpull:`4098`: pass profile-dir instead of profile name to Kernel | |
71 | * :ghpull:`4120`: support `input` in Python 2 kernels |
|
71 | * :ghpull:`4120`: support `input` in Python 2 kernels | |
72 | * :ghpull:`4088`: nbconvert: Fix coalescestreams line with incorrect nesting causing strange behavior |
|
72 | * :ghpull:`4088`: nbconvert: Fix coalescestreams line with incorrect nesting causing strange behavior | |
73 | * :ghpull:`4060`: only strip continuation prompts if regular prompts seen first |
|
73 | * :ghpull:`4060`: only strip continuation prompts if regular prompts seen first | |
74 | * :ghpull:`4132`: Fixed name error bug in function safe_unicode in module py3compat. |
|
74 | * :ghpull:`4132`: Fixed name error bug in function safe_unicode in module py3compat. | |
75 | * :ghpull:`4121`: move test_kernel from IPython.zmq to IPython.kernel |
|
75 | * :ghpull:`4121`: move test_kernel from IPython.zmq to IPython.kernel | |
76 | * :ghpull:`4118`: ZMQ heartbeat channel: catch EINTR exceptions and continue. |
|
76 | * :ghpull:`4118`: ZMQ heartbeat channel: catch EINTR exceptions and continue. | |
77 | * :ghpull:`4054`: use unicode for HTML export |
|
77 | * :ghpull:`4054`: use unicode for HTML export | |
78 | * :ghpull:`4106`: fix a couple of default block values |
|
78 | * :ghpull:`4106`: fix a couple of default block values | |
79 | * :ghpull:`4115`: Update docs on declaring a magic function |
|
79 | * :ghpull:`4115`: Update docs on declaring a magic function | |
80 | * :ghpull:`4101`: restore accidentally removed EngineError |
|
80 | * :ghpull:`4101`: restore accidentally removed EngineError | |
81 | * :ghpull:`4096`: minor docs changes |
|
81 | * :ghpull:`4096`: minor docs changes | |
82 | * :ghpull:`4056`: respect `pylab_import_all` when `--pylab` specified at the command-line |
|
82 | * :ghpull:`4056`: respect `pylab_import_all` when `--pylab` specified at the command-line | |
83 | * :ghpull:`4091`: Make Qt console banner configurable |
|
83 | * :ghpull:`4091`: Make Qt console banner configurable | |
84 | * :ghpull:`4086`: fix missing errno import |
|
84 | * :ghpull:`4086`: fix missing errno import | |
85 | * :ghpull:`4030`: exclude `.git` in MANIFEST.in |
|
85 | * :ghpull:`4030`: exclude `.git` in MANIFEST.in | |
86 | * :ghpull:`4047`: Use istype() when checking if canned object is a dict |
|
86 | * :ghpull:`4047`: Use istype() when checking if canned object is a dict | |
87 | * :ghpull:`4031`: don't close_fds on Windows |
|
87 | * :ghpull:`4031`: don't close_fds on Windows | |
88 | * :ghpull:`4029`: bson.Binary moved |
|
88 | * :ghpull:`4029`: bson.Binary moved | |
89 | * :ghpull:`4035`: Fixed custom jinja2 templates being ignored when setting template_path |
|
89 | * :ghpull:`4035`: Fixed custom jinja2 templates being ignored when setting template_path | |
90 | * :ghpull:`4026`: small doc fix in nbconvert |
|
90 | * :ghpull:`4026`: small doc fix in nbconvert | |
91 | * :ghpull:`4016`: Fix IPython.start_* functions |
|
91 | * :ghpull:`4016`: Fix IPython.start_* functions | |
92 | * :ghpull:`4021`: Fix parallel.client.View map() on numpy arrays |
|
92 | * :ghpull:`4021`: Fix parallel.client.View map() on numpy arrays | |
93 | * :ghpull:`4022`: DOC: fix links to matplotlib, notebook docs |
|
93 | * :ghpull:`4022`: DOC: fix links to matplotlib, notebook docs | |
94 | * :ghpull:`4018`: Fix warning when running IPython.kernel tests |
|
94 | * :ghpull:`4018`: Fix warning when running IPython.kernel tests | |
95 | * :ghpull:`4019`: Test skipping without unicode paths |
|
95 | * :ghpull:`4019`: Test skipping without unicode paths | |
96 | * :ghpull:`4008`: Transform code before %prun/%%prun runs |
|
96 | * :ghpull:`4008`: Transform code before %prun/%%prun runs | |
97 | * :ghpull:`4014`: Fix typo in ipapp |
|
97 | * :ghpull:`4014`: Fix typo in ipapp | |
98 | * :ghpull:`3987`: get files list in backport_pr |
|
98 | * :ghpull:`3987`: get files list in backport_pr | |
99 | * :ghpull:`3974`: nbconvert: Fix app tests on Window7 w/ Python 3.3 |
|
99 | * :ghpull:`3974`: nbconvert: Fix app tests on Window7 w/ Python 3.3 | |
100 | * :ghpull:`3978`: fix `--existing` with non-localhost IP |
|
100 | * :ghpull:`3978`: fix `--existing` with non-localhost IP | |
101 | * :ghpull:`3939`: minor checkpoint cleanup |
|
101 | * :ghpull:`3939`: minor checkpoint cleanup | |
102 | * :ghpull:`3981`: BF: fix nbconvert rst input prompt spacing |
|
102 | * :ghpull:`3981`: BF: fix nbconvert rst input prompt spacing | |
103 | * :ghpull:`3960`: Don't make sphinx a dependency for importing nbconvert |
|
103 | * :ghpull:`3960`: Don't make sphinx a dependency for importing nbconvert | |
104 | * :ghpull:`3973`: logging.Formatter is not new-style in 2.6 |
|
104 | * :ghpull:`3973`: logging.Formatter is not new-style in 2.6 | |
105 |
|
105 | |||
106 | Issues (18): |
|
106 | Issues (18): | |
107 |
|
107 | |||
108 | * :ghissue:`4024`: nbconvert markdown issues |
|
108 | * :ghissue:`4024`: nbconvert markdown issues | |
109 | * :ghissue:`4095`: Catch js error in append html in stream/pyerr |
|
109 | * :ghissue:`4095`: Catch js error in append html in stream/pyerr | |
110 | * :ghissue:`4156`: Specifying --gui=tk at the command line |
|
110 | * :ghissue:`4156`: Specifying --gui=tk at the command line | |
111 | * :ghissue:`3818`: nbconvert can't handle Heading with Chinese characters on Japanese Windows OS. |
|
111 | * :ghissue:`3818`: nbconvert can't handle Heading with Chinese characters on Japanese Windows OS. | |
112 | * :ghissue:`4134`: multi-line parser fails on ''' in comment, qtconsole and notebook. |
|
112 | * :ghissue:`4134`: multi-line parser fails on ''' in comment, qtconsole and notebook. | |
113 | * :ghissue:`3998`: sample custom.js needs to be updated |
|
113 | * :ghissue:`3998`: sample custom.js needs to be updated | |
114 | * :ghissue:`4078`: StoreMagic.autorestore not working in 1.0.0 |
|
114 | * :ghissue:`4078`: StoreMagic.autorestore not working in 1.0.0 | |
115 | * :ghissue:`3990`: Buitlin `input` doesn't work over zmq |
|
115 | * :ghissue:`3990`: Buitlin `input` doesn't work over zmq | |
116 | * :ghissue:`4015`: nbconvert fails to convert all the content of a notebook |
|
116 | * :ghissue:`4015`: nbconvert fails to convert all the content of a notebook | |
117 | * :ghissue:`4059`: Issues with Ellipsis literal in Python 3 |
|
117 | * :ghissue:`4059`: Issues with Ellipsis literal in Python 3 | |
118 | * :ghissue:`4103`: Wrong default argument of DirectView.clear |
|
118 | * :ghissue:`4103`: Wrong default argument of DirectView.clear | |
119 | * :ghissue:`4100`: parallel.client.client references undefined error.EngineError |
|
119 | * :ghissue:`4100`: parallel.client.client references undefined error.EngineError | |
120 | * :ghissue:`4005`: IPython.start_kernel doesn't work. |
|
120 | * :ghissue:`4005`: IPython.start_kernel doesn't work. | |
121 | * :ghissue:`4020`: IPython parallel map fails on numpy arrays |
|
121 | * :ghissue:`4020`: IPython parallel map fails on numpy arrays | |
122 | * :ghissue:`3945`: nbconvert: commandline tests fail Win7x64 Py3.3 |
|
122 | * :ghissue:`3945`: nbconvert: commandline tests fail Win7x64 Py3.3 | |
123 | * :ghissue:`3977`: unable to complete remote connections for two-process |
|
123 | * :ghissue:`3977`: unable to complete remote connections for two-process | |
124 | * :ghissue:`3980`: nbconvert rst output lacks needed blank lines |
|
124 | * :ghissue:`3980`: nbconvert rst output lacks needed blank lines | |
125 | * :ghissue:`3968`: TypeError: super() argument 1 must be type, not classobj (Python 2.6.6) |
|
125 | * :ghissue:`3968`: TypeError: super() argument 1 must be type, not classobj (Python 2.6.6) | |
126 |
|
126 | |||
127 | Issues closed in 1.0 |
|
127 | Issues closed in 1.0 | |
128 | -------------------- |
|
128 | -------------------- | |
129 |
|
129 | |||
130 | GitHub stats for 2012/06/30 - 2013/08/08 (since 0.13) |
|
130 | GitHub stats for 2012/06/30 - 2013/08/08 (since 0.13) | |
131 |
|
131 | |||
132 | These lists are automatically generated, and may be incomplete or contain duplicates. |
|
132 | These lists are automatically generated, and may be incomplete or contain duplicates. | |
133 |
|
133 | |||
134 | The following 155 authors contributed 4258 commits. |
|
134 | The following 155 authors contributed 4258 commits. | |
135 |
|
135 | |||
136 | * Aaron Meurer |
|
136 | * Aaron Meurer | |
137 | * Adam Davis |
|
137 | * Adam Davis | |
138 | * Ahmet Bakan |
|
138 | * Ahmet Bakan | |
139 | * Alberto Valverde |
|
139 | * Alberto Valverde | |
140 | * Allen Riddell |
|
140 | * Allen Riddell | |
141 | * Anders HovmΓΆller |
|
141 | * Anders HovmΓΆller | |
142 | * Andrea Bedini |
|
142 | * Andrea Bedini | |
143 | * Andrew Spiers |
|
143 | * Andrew Spiers | |
144 | * Andrew Vandever |
|
144 | * Andrew Vandever | |
145 | * Anthony Scopatz |
|
145 | * Anthony Scopatz | |
146 | * Anton Akhmerov |
|
146 | * Anton Akhmerov | |
147 | * Anton I. Sipos |
|
147 | * Anton I. Sipos | |
148 | * Antony Lee |
|
148 | * Antony Lee | |
149 | * Aron Ahmadia |
|
149 | * Aron Ahmadia | |
150 | * Benedikt Sauer |
|
150 | * Benedikt Sauer | |
151 | * Benjamin Jones |
|
151 | * Benjamin Jones | |
152 | * Benjamin Ragan-Kelley |
|
152 | * Benjamin Ragan-Kelley | |
153 | * Benjie Chen |
|
153 | * Benjie Chen | |
154 | * Boris de Laage |
|
154 | * Boris de Laage | |
155 | * Brad Reisfeld |
|
155 | * Brad Reisfeld | |
156 | * Bradley M. Froehle |
|
156 | * Bradley M. Froehle | |
157 | * Brian E. Granger |
|
157 | * Brian E. Granger | |
158 | * Cameron Bates |
|
158 | * Cameron Bates | |
159 | * Cavendish McKay |
|
159 | * Cavendish McKay | |
160 | * chapmanb |
|
160 | * chapmanb | |
161 | * Chris Beaumont |
|
161 | * Chris Beaumont | |
162 | * Chris Laumann |
|
162 | * Chris Laumann | |
163 | * Christoph Gohlke |
|
163 | * Christoph Gohlke | |
164 | * codebraker |
|
164 | * codebraker | |
165 | * codespaced |
|
165 | * codespaced | |
166 | * Corran Webster |
|
166 | * Corran Webster | |
167 | * DamianHeard |
|
167 | * DamianHeard | |
168 | * DamiΓ‘n Avila |
|
168 | * DamiΓ‘n Avila | |
169 | * Dan Kilman |
|
169 | * Dan Kilman | |
170 | * Dan McDougall |
|
170 | * Dan McDougall | |
171 | * Danny Staple |
|
171 | * Danny Staple | |
172 | * David Hirschfeld |
|
172 | * David Hirschfeld | |
173 | * David P. Sanders |
|
173 | * David P. Sanders | |
174 | * David Warde-Farley |
|
174 | * David Warde-Farley | |
175 | * David Wolever |
|
175 | * David Wolever | |
176 | * David Wyde |
|
176 | * David Wyde | |
177 | * debjan |
|
177 | * debjan | |
178 | * Diane Trout |
|
178 | * Diane Trout | |
179 | * dkua |
|
179 | * dkua | |
180 | * Dominik Dabrowski |
|
180 | * Dominik Dabrowski | |
181 | * Donald Curtis |
|
181 | * Donald Curtis | |
182 | * DraΕΎen LuΔanin |
|
182 | * DraΕΎen LuΔanin | |
183 | * drevicko |
|
183 | * drevicko | |
184 | * Eric O. LEBIGOT |
|
184 | * Eric O. LEBIGOT | |
185 | * Erik M. Bray |
|
185 | * Erik M. Bray | |
186 | * Erik Tollerud |
|
186 | * Erik Tollerud | |
187 | * Eugene Van den Bulke |
|
187 | * Eugene Van den Bulke | |
188 | * Evan Patterson |
|
188 | * Evan Patterson | |
189 | * Fernando Perez |
|
189 | * Fernando Perez | |
190 | * Francesco Montesano |
|
190 | * Francesco Montesano | |
191 | * Frank Murphy |
|
191 | * Frank Murphy | |
192 | * Greg Caporaso |
|
192 | * Greg Caporaso | |
193 | * Guy Haskin Fernald |
|
193 | * Guy Haskin Fernald | |
194 | * guziy |
|
194 | * guziy | |
195 | * Hans Meine |
|
195 | * Hans Meine | |
196 | * Harry Moreno |
|
196 | * Harry Moreno | |
197 | * henryiii |
|
197 | * henryiii | |
198 | * Ivan Djokic |
|
198 | * Ivan Djokic | |
199 | * Jack Feser |
|
199 | * Jack Feser | |
200 | * Jake Vanderplas |
|
200 | * Jake Vanderplas | |
201 | * jakobgager |
|
201 | * jakobgager | |
202 | * James Booth |
|
202 | * James Booth | |
203 | * Jan Schulz |
|
203 | * Jan Schulz | |
204 | * Jason Grout |
|
204 | * Jason Grout | |
205 | * Jeff Knisley |
|
205 | * Jeff Knisley | |
206 | * Jens Hedegaard Nielsen |
|
206 | * Jens Hedegaard Nielsen | |
207 | * jeremiahbuddha |
|
207 | * jeremiahbuddha | |
208 | * Jerry Fowler |
|
208 | * Jerry Fowler | |
209 | * Jessica B. Hamrick |
|
209 | * Jessica B. Hamrick | |
210 | * Jez Ng |
|
210 | * Jez Ng | |
211 | * John Zwinck |
|
211 | * John Zwinck | |
212 | * Jonathan Frederic |
|
212 | * Jonathan Frederic | |
213 | * Jonathan Taylor |
|
213 | * Jonathan Taylor | |
214 | * Joon Ro |
|
214 | * Joon Ro | |
215 | * Joseph Lansdowne |
|
215 | * Joseph Lansdowne | |
216 | * Juergen Hasch |
|
216 | * Juergen Hasch | |
217 | * Julian Taylor |
|
217 | * Julian Taylor | |
218 | * Jussi Sainio |
|
218 | * Jussi Sainio | |
219 | * JΓΆrgen Stenarson |
|
219 | * JΓΆrgen Stenarson | |
220 | * kevin |
|
220 | * kevin | |
221 | * klonuo |
|
221 | * klonuo | |
222 | * Konrad Hinsen |
|
222 | * Konrad Hinsen | |
223 | * Kyle Kelley |
|
223 | * Kyle Kelley | |
224 | * Lars Solberg |
|
224 | * Lars Solberg | |
225 | * Lessandro Mariano |
|
225 | * Lessandro Mariano | |
226 | * Mark Sienkiewicz at STScI |
|
226 | * Mark Sienkiewicz at STScI | |
227 | * Martijn Vermaat |
|
227 | * Martijn Vermaat | |
228 | * Martin Spacek |
|
228 | * Martin Spacek | |
229 | * Matthias Bussonnier |
|
229 | * Matthias Bussonnier | |
230 | * Maxim Grechkin |
|
230 | * Maxim Grechkin | |
231 | * Maximilian Albert |
|
231 | * Maximilian Albert | |
232 | * MercuryRising |
|
232 | * MercuryRising | |
233 | * Michael Droettboom |
|
233 | * Michael Droettboom | |
234 | * Michael Shuffett |
|
234 | * Michael Shuffett | |
235 | * MichaΕ GΓ³rny |
|
235 | * MichaΕ GΓ³rny | |
236 | * Mikhail Korobov |
|
236 | * Mikhail Korobov | |
237 | * mr.Shu |
|
237 | * mr.Shu | |
238 | * Nathan Goldbaum |
|
238 | * Nathan Goldbaum | |
239 | * ocefpaf |
|
239 | * ocefpaf | |
240 | * Ohad Ravid |
|
240 | * Ohad Ravid | |
241 | * Olivier Grisel |
|
241 | * Olivier Grisel | |
242 | * Olivier Verdier |
|
242 | * Olivier Verdier | |
243 | * Owen Healy |
|
243 | * Owen Healy | |
244 | * Pankaj Pandey |
|
244 | * Pankaj Pandey | |
245 | * Paul Ivanov |
|
245 | * Paul Ivanov | |
246 | * Pawel Jasinski |
|
246 | * Pawel Jasinski | |
247 | * Pietro Berkes |
|
247 | * Pietro Berkes | |
248 | * Piti Ongmongkolkul |
|
248 | * Piti Ongmongkolkul | |
249 | * Puneeth Chaganti |
|
249 | * Puneeth Chaganti | |
250 | * Rich Wareham |
|
250 | * Rich Wareham | |
251 | * Richard Everson |
|
251 | * Richard Everson | |
252 | * Rick Lupton |
|
252 | * Rick Lupton | |
253 | * Rob Young |
|
253 | * Rob Young | |
254 | * Robert Kern |
|
254 | * Robert Kern | |
255 | * Robert Marchman |
|
255 | * Robert Marchman | |
256 | * Robert McGibbon |
|
256 | * Robert McGibbon | |
257 | * Rui Pereira |
|
257 | * Rui Pereira | |
258 | * Rustam Safin |
|
258 | * Rustam Safin | |
259 | * Ryan May |
|
259 | * Ryan May | |
260 | * s8weber |
|
260 | * s8weber | |
261 | * Samuel Ainsworth |
|
261 | * Samuel Ainsworth | |
262 | * Sean Vig |
|
262 | * Sean Vig | |
263 | * Siyu Zhang |
|
263 | * Siyu Zhang | |
264 | * Skylar Saveland |
|
264 | * Skylar Saveland | |
265 | * slojo404 |
|
265 | * slojo404 | |
266 | * smithj1 |
|
266 | * smithj1 | |
267 | * Stefan Karpinski |
|
267 | * Stefan Karpinski | |
268 | * Stefan van der Walt |
|
268 | * Stefan van der Walt | |
269 | * Steven Silvester |
|
269 | * Steven Silvester | |
270 | * Takafumi Arakaki |
|
270 | * Takafumi Arakaki | |
271 | * Takeshi Kanmae |
|
271 | * Takeshi Kanmae | |
272 | * tcmulcahy |
|
272 | * tcmulcahy | |
273 | * teegaar |
|
273 | * teegaar | |
274 | * Thomas Kluyver |
|
274 | * Thomas Kluyver | |
275 | * Thomas Robitaille |
|
275 | * Thomas Robitaille | |
276 | * Thomas Spura |
|
276 | * Thomas Spura | |
277 | * Thomas WeiΓschuh |
|
277 | * Thomas WeiΓschuh | |
278 | * Timothy O'Donnell |
|
278 | * Timothy O'Donnell | |
279 | * Tom Dimiduk |
|
279 | * Tom Dimiduk | |
280 | * ugurthemaster |
|
280 | * ugurthemaster | |
281 | * urielshaolin |
|
281 | * urielshaolin | |
282 | * v923z |
|
282 | * v923z | |
283 | * Valentin Haenel |
|
283 | * Valentin Haenel | |
284 | * Victor Zverovich |
|
284 | * Victor Zverovich | |
285 | * W. Trevor King |
|
285 | * W. Trevor King | |
286 | * y-p |
|
286 | * y-p | |
287 | * Yoav Ram |
|
287 | * Yoav Ram | |
288 | * Zbigniew JΔdrzejewski-Szmek |
|
288 | * Zbigniew JΔdrzejewski-Szmek | |
289 | * ZoltΓ‘n VΓΆrΓΆs |
|
289 | * ZoltΓ‘n VΓΆrΓΆs | |
290 |
|
290 | |||
291 |
|
291 | |||
292 | We closed a total of 1484 issues, 793 pull requests and 691 regular issues; |
|
292 | We closed a total of 1484 issues, 793 pull requests and 691 regular issues; | |
293 | this is the full list (generated with the script |
|
293 | this is the full list (generated with the script | |
294 | :file:`tools/github_stats.py`): |
|
294 | :file:`tools/github_stats.py`): | |
295 |
|
295 | |||
296 | Pull Requests (793): |
|
296 | Pull Requests (793): | |
297 |
|
297 | |||
298 | * :ghpull:`3958`: doc update |
|
298 | * :ghpull:`3958`: doc update | |
299 | * :ghpull:`3965`: Fix ansi color code for background yellow |
|
299 | * :ghpull:`3965`: Fix ansi color code for background yellow | |
300 | * :ghpull:`3964`: Fix casing of message. |
|
300 | * :ghpull:`3964`: Fix casing of message. | |
301 | * :ghpull:`3942`: Pass on install docs |
|
301 | * :ghpull:`3942`: Pass on install docs | |
302 | * :ghpull:`3962`: exclude IPython.lib.kernel in iptest |
|
302 | * :ghpull:`3962`: exclude IPython.lib.kernel in iptest | |
303 | * :ghpull:`3961`: Longpath test fix |
|
303 | * :ghpull:`3961`: Longpath test fix | |
304 | * :ghpull:`3905`: Remove references to 0.11 and 0.12 from config/overview.rst |
|
304 | * :ghpull:`3905`: Remove references to 0.11 and 0.12 from config/overview.rst | |
305 | * :ghpull:`3951`: nbconvert: fixed latex characters not escaped properly in nbconvert |
|
305 | * :ghpull:`3951`: nbconvert: fixed latex characters not escaped properly in nbconvert | |
306 | * :ghpull:`3949`: log fatal error when PDF conversion fails |
|
306 | * :ghpull:`3949`: log fatal error when PDF conversion fails | |
307 | * :ghpull:`3947`: nbconvert: Make writer & post-processor aliases case insensitive. |
|
307 | * :ghpull:`3947`: nbconvert: Make writer & post-processor aliases case insensitive. | |
308 | * :ghpull:`3938`: Recompile css. |
|
308 | * :ghpull:`3938`: Recompile css. | |
309 | * :ghpull:`3948`: sphinx and PDF tweaks |
|
309 | * :ghpull:`3948`: sphinx and PDF tweaks | |
310 | * :ghpull:`3943`: nbconvert: Serve post-processor Windows fix |
|
310 | * :ghpull:`3943`: nbconvert: Serve post-processor Windows fix | |
311 | * :ghpull:`3934`: nbconvert: fix logic of verbose flag in PDF post processor |
|
311 | * :ghpull:`3934`: nbconvert: fix logic of verbose flag in PDF post processor | |
312 | * :ghpull:`3929`: swallow enter event in rename dialog |
|
312 | * :ghpull:`3929`: swallow enter event in rename dialog | |
313 | * :ghpull:`3924`: nbconvert: Backport fixes |
|
313 | * :ghpull:`3924`: nbconvert: Backport fixes | |
314 | * :ghpull:`3925`: Replace --pylab flag with --matplotlib in usage |
|
314 | * :ghpull:`3925`: Replace --pylab flag with --matplotlib in usage | |
315 | * :ghpull:`3910`: Added explicit error message for missing configuration arguments. |
|
315 | * :ghpull:`3910`: Added explicit error message for missing configuration arguments. | |
316 | * :ghpull:`3913`: grffile to support spaces in notebook names |
|
316 | * :ghpull:`3913`: grffile to support spaces in notebook names | |
317 | * :ghpull:`3918`: added check_for_tornado, closes #3916 |
|
317 | * :ghpull:`3918`: added check_for_tornado, closes #3916 | |
318 | * :ghpull:`3917`: change docs/examples refs to be just examples |
|
318 | * :ghpull:`3917`: change docs/examples refs to be just examples | |
319 | * :ghpull:`3908`: what's new tweaks |
|
319 | * :ghpull:`3908`: what's new tweaks | |
320 | * :ghpull:`3896`: two column quickhelp dialog, closes #3895 |
|
320 | * :ghpull:`3896`: two column quickhelp dialog, closes #3895 | |
321 | * :ghpull:`3911`: explicitly load python mode before IPython mode |
|
321 | * :ghpull:`3911`: explicitly load python mode before IPython mode | |
322 | * :ghpull:`3901`: don't force . relative path, fix #3897 |
|
322 | * :ghpull:`3901`: don't force . relative path, fix #3897 | |
323 | * :ghpull:`3891`: fix #3889 |
|
323 | * :ghpull:`3891`: fix #3889 | |
324 | * :ghpull:`3892`: Fix documentation of Kernel.stop_channels |
|
324 | * :ghpull:`3892`: Fix documentation of Kernel.stop_channels | |
325 | * :ghpull:`3888`: posixify paths for Windows latex |
|
325 | * :ghpull:`3888`: posixify paths for Windows latex | |
326 | * :ghpull:`3882`: quick fix for #3881 |
|
326 | * :ghpull:`3882`: quick fix for #3881 | |
327 | * :ghpull:`3877`: don't use `shell=True` in PDF export |
|
327 | * :ghpull:`3877`: don't use `shell=True` in PDF export | |
328 | * :ghpull:`3878`: minor template loading cleanup |
|
328 | * :ghpull:`3878`: minor template loading cleanup | |
329 | * :ghpull:`3855`: nbconvert: Filter tests |
|
329 | * :ghpull:`3855`: nbconvert: Filter tests | |
330 | * :ghpull:`3879`: finish 3870 |
|
330 | * :ghpull:`3879`: finish 3870 | |
331 | * :ghpull:`3870`: Fix for converting notebooks that contain unicode characters. |
|
331 | * :ghpull:`3870`: Fix for converting notebooks that contain unicode characters. | |
332 | * :ghpull:`3876`: Update parallel_winhpc.rst |
|
332 | * :ghpull:`3876`: Update parallel_winhpc.rst | |
333 | * :ghpull:`3872`: removing vim-ipython, since it has it's own repo |
|
333 | * :ghpull:`3872`: removing vim-ipython, since it has it's own repo | |
334 | * :ghpull:`3871`: updating docs |
|
334 | * :ghpull:`3871`: updating docs | |
335 | * :ghpull:`3873`: remove old examples |
|
335 | * :ghpull:`3873`: remove old examples | |
336 | * :ghpull:`3868`: update CodeMirror component to 3.15 |
|
336 | * :ghpull:`3868`: update CodeMirror component to 3.15 | |
337 | * :ghpull:`3865`: Escape filename for pdflatex in nbconvert |
|
337 | * :ghpull:`3865`: Escape filename for pdflatex in nbconvert | |
338 | * :ghpull:`3861`: remove old external.js |
|
338 | * :ghpull:`3861`: remove old external.js | |
339 | * :ghpull:`3864`: add keyboard shortcut to docs |
|
339 | * :ghpull:`3864`: add keyboard shortcut to docs | |
340 | * :ghpull:`3834`: This PR fixes a few issues with nbconvert tests |
|
340 | * :ghpull:`3834`: This PR fixes a few issues with nbconvert tests | |
341 | * :ghpull:`3840`: prevent profile_dir from being undefined |
|
341 | * :ghpull:`3840`: prevent profile_dir from being undefined | |
342 | * :ghpull:`3859`: Add "An Afternoon Hack" to docs |
|
342 | * :ghpull:`3859`: Add "An Afternoon Hack" to docs | |
343 | * :ghpull:`3854`: Catch errors filling readline history on startup |
|
343 | * :ghpull:`3854`: Catch errors filling readline history on startup | |
344 | * :ghpull:`3857`: Delete extra auto |
|
344 | * :ghpull:`3857`: Delete extra auto | |
345 | * :ghpull:`3845`: nbconvert: Serve from original build directory |
|
345 | * :ghpull:`3845`: nbconvert: Serve from original build directory | |
346 | * :ghpull:`3846`: Add basic logging to nbconvert |
|
346 | * :ghpull:`3846`: Add basic logging to nbconvert | |
347 | * :ghpull:`3850`: add missing store_history key to Notebook execute_requests |
|
347 | * :ghpull:`3850`: add missing store_history key to Notebook execute_requests | |
348 | * :ghpull:`3844`: update payload source |
|
348 | * :ghpull:`3844`: update payload source | |
349 | * :ghpull:`3830`: mention metadata / display_data similarity in pyout spec |
|
349 | * :ghpull:`3830`: mention metadata / display_data similarity in pyout spec | |
350 | * :ghpull:`3848`: fix incorrect `empty-docstring` |
|
350 | * :ghpull:`3848`: fix incorrect `empty-docstring` | |
351 | * :ghpull:`3836`: Parse markdown correctly when mathjax is disabled |
|
351 | * :ghpull:`3836`: Parse markdown correctly when mathjax is disabled | |
352 | * :ghpull:`3849`: skip a failing test on windows |
|
352 | * :ghpull:`3849`: skip a failing test on windows | |
353 | * :ghpull:`3828`: signature_scheme lives in Session |
|
353 | * :ghpull:`3828`: signature_scheme lives in Session | |
354 | * :ghpull:`3831`: update nbconvert doc with new CLI |
|
354 | * :ghpull:`3831`: update nbconvert doc with new CLI | |
355 | * :ghpull:`3822`: add output flag to nbconvert |
|
355 | * :ghpull:`3822`: add output flag to nbconvert | |
356 | * :ghpull:`3780`: Added serving the output directory if html-based format are selected. |
|
356 | * :ghpull:`3780`: Added serving the output directory if html-based format are selected. | |
357 | * :ghpull:`3764`: Cleanup nbconvert templates |
|
357 | * :ghpull:`3764`: Cleanup nbconvert templates | |
358 | * :ghpull:`3829`: remove now-duplicate 'this is dev' note |
|
358 | * :ghpull:`3829`: remove now-duplicate 'this is dev' note | |
359 | * :ghpull:`3814`: add `ConsoleWidget.execute_on_complete_input` flag |
|
359 | * :ghpull:`3814`: add `ConsoleWidget.execute_on_complete_input` flag | |
360 | * :ghpull:`3826`: try rtfd |
|
360 | * :ghpull:`3826`: try rtfd | |
361 | * :ghpull:`3821`: add sphinx prolog |
|
361 | * :ghpull:`3821`: add sphinx prolog | |
362 | * :ghpull:`3817`: relax timeouts in terminal console and tests |
|
362 | * :ghpull:`3817`: relax timeouts in terminal console and tests | |
363 | * :ghpull:`3825`: fix more tests that fail when pandoc is missing |
|
363 | * :ghpull:`3825`: fix more tests that fail when pandoc is missing | |
364 | * :ghpull:`3824`: don't set target on internal markdown links |
|
364 | * :ghpull:`3824`: don't set target on internal markdown links | |
365 | * :ghpull:`3816`: s/pylab/matplotlib in docs |
|
365 | * :ghpull:`3816`: s/pylab/matplotlib in docs | |
366 | * :ghpull:`3812`: Describe differences between start_ipython and embed |
|
366 | * :ghpull:`3812`: Describe differences between start_ipython and embed | |
367 | * :ghpull:`3805`: Print View has been removed |
|
367 | * :ghpull:`3805`: Print View has been removed | |
368 | * :ghpull:`3820`: Make it clear that 1.0 is not released yet |
|
368 | * :ghpull:`3820`: Make it clear that 1.0 is not released yet | |
369 | * :ghpull:`3784`: nbconvert: Export flavors & PDF writer (ipy dev meeting) |
|
369 | * :ghpull:`3784`: nbconvert: Export flavors & PDF writer (ipy dev meeting) | |
370 | * :ghpull:`3800`: semantic-versionify version number for non-releases |
|
370 | * :ghpull:`3800`: semantic-versionify version number for non-releases | |
371 | * :ghpull:`3802`: Documentation .txt to .rst |
|
371 | * :ghpull:`3802`: Documentation .txt to .rst | |
372 | * :ghpull:`3765`: cleanup terminal console iopub handling |
|
372 | * :ghpull:`3765`: cleanup terminal console iopub handling | |
373 | * :ghpull:`3720`: Fix for #3719 |
|
373 | * :ghpull:`3720`: Fix for #3719 | |
374 | * :ghpull:`3787`: re-raise KeyboardInterrupt in raw_input |
|
374 | * :ghpull:`3787`: re-raise KeyboardInterrupt in raw_input | |
375 | * :ghpull:`3770`: Organizing reveal's templates. |
|
375 | * :ghpull:`3770`: Organizing reveal's templates. | |
376 | * :ghpull:`3751`: Use link(2) when possible in nbconvert |
|
376 | * :ghpull:`3751`: Use link(2) when possible in nbconvert | |
377 | * :ghpull:`3792`: skip tests that require pandoc |
|
377 | * :ghpull:`3792`: skip tests that require pandoc | |
378 | * :ghpull:`3782`: add Importing Notebooks example |
|
378 | * :ghpull:`3782`: add Importing Notebooks example | |
379 | * :ghpull:`3752`: nbconvert: Add cwd to sys.path |
|
379 | * :ghpull:`3752`: nbconvert: Add cwd to sys.path | |
380 | * :ghpull:`3789`: fix raw_input in qtconsole |
|
380 | * :ghpull:`3789`: fix raw_input in qtconsole | |
381 | * :ghpull:`3756`: document the wire protocol |
|
381 | * :ghpull:`3756`: document the wire protocol | |
382 | * :ghpull:`3749`: convert IPython syntax to Python syntax in nbconvert python template |
|
382 | * :ghpull:`3749`: convert IPython syntax to Python syntax in nbconvert python template | |
383 | * :ghpull:`3793`: Closes #3788 |
|
383 | * :ghpull:`3793`: Closes #3788 | |
384 | * :ghpull:`3794`: Change logo link to ipython.org |
|
384 | * :ghpull:`3794`: Change logo link to ipython.org | |
385 | * :ghpull:`3746`: Raise a named exception when pandoc is missing |
|
385 | * :ghpull:`3746`: Raise a named exception when pandoc is missing | |
386 | * :ghpull:`3781`: comply with the message spec in the notebook |
|
386 | * :ghpull:`3781`: comply with the message spec in the notebook | |
387 | * :ghpull:`3779`: remove bad `if logged_in` preventing new-notebook without login |
|
387 | * :ghpull:`3779`: remove bad `if logged_in` preventing new-notebook without login | |
388 | * :ghpull:`3743`: remove notebook read-only view |
|
388 | * :ghpull:`3743`: remove notebook read-only view | |
389 | * :ghpull:`3732`: add delay to autosave in beforeunload |
|
389 | * :ghpull:`3732`: add delay to autosave in beforeunload | |
390 | * :ghpull:`3761`: Added rm_math_space to markdown cells in the basichtml.tpl to be rendered ok by mathjax after the nbconvertion. |
|
390 | * :ghpull:`3761`: Added rm_math_space to markdown cells in the basichtml.tpl to be rendered ok by mathjax after the nbconvertion. | |
391 | * :ghpull:`3758`: nbconvert: Filter names cleanup |
|
391 | * :ghpull:`3758`: nbconvert: Filter names cleanup | |
392 | * :ghpull:`3769`: Add configurability to tabcompletion timeout |
|
392 | * :ghpull:`3769`: Add configurability to tabcompletion timeout | |
393 | * :ghpull:`3771`: Update px pylab test to match new output of pylab |
|
393 | * :ghpull:`3771`: Update px pylab test to match new output of pylab | |
394 | * :ghpull:`3741`: better message when notebook format is not supported |
|
394 | * :ghpull:`3741`: better message when notebook format is not supported | |
395 | * :ghpull:`3753`: document Ctrl-C not working in ipython kernel |
|
395 | * :ghpull:`3753`: document Ctrl-C not working in ipython kernel | |
396 | * :ghpull:`3766`: handle empty metadata in pyout messages more gracefully. |
|
396 | * :ghpull:`3766`: handle empty metadata in pyout messages more gracefully. | |
397 | * :ghpull:`3736`: my attempt to fix #3735 |
|
397 | * :ghpull:`3736`: my attempt to fix #3735 | |
398 | * :ghpull:`3759`: nbconvert: Provide a more useful error for invalid use case. |
|
398 | * :ghpull:`3759`: nbconvert: Provide a more useful error for invalid use case. | |
399 | * :ghpull:`3760`: nbconvert: Allow notebook filenames without their extensions |
|
399 | * :ghpull:`3760`: nbconvert: Allow notebook filenames without their extensions | |
400 | * :ghpull:`3750`: nbconvert: Add cwd to default templates search path. |
|
400 | * :ghpull:`3750`: nbconvert: Add cwd to default templates search path. | |
401 | * :ghpull:`3748`: Update nbconvert docs |
|
401 | * :ghpull:`3748`: Update nbconvert docs | |
402 | * :ghpull:`3734`: Nbconvert: Export extracted files into `nbname_files` subdirectory |
|
402 | * :ghpull:`3734`: Nbconvert: Export extracted files into `nbname_files` subdirectory | |
403 | * :ghpull:`3733`: Nicer message when pandoc is missing, closes #3730 |
|
403 | * :ghpull:`3733`: Nicer message when pandoc is missing, closes #3730 | |
404 | * :ghpull:`3722`: fix two failing test in IPython.lib |
|
404 | * :ghpull:`3722`: fix two failing test in IPython.lib | |
405 | * :ghpull:`3704`: Start what's new for 1.0 |
|
405 | * :ghpull:`3704`: Start what's new for 1.0 | |
406 | * :ghpull:`3705`: Complete rewrite of IPython Notebook documentation: docs/source/interactive/htmlnotebook.txt |
|
406 | * :ghpull:`3705`: Complete rewrite of IPython Notebook documentation: docs/source/interactive/htmlnotebook.txt | |
407 | * :ghpull:`3709`: Docs cleanup |
|
407 | * :ghpull:`3709`: Docs cleanup | |
408 | * :ghpull:`3716`: raw_input fixes for kernel restarts |
|
408 | * :ghpull:`3716`: raw_input fixes for kernel restarts | |
409 | * :ghpull:`3683`: use `%matplotlib` in example notebooks |
|
409 | * :ghpull:`3683`: use `%matplotlib` in example notebooks | |
410 | * :ghpull:`3686`: remove quarantine |
|
410 | * :ghpull:`3686`: remove quarantine | |
411 | * :ghpull:`3699`: svg2pdf unicode fix |
|
411 | * :ghpull:`3699`: svg2pdf unicode fix | |
412 | * :ghpull:`3695`: fix SVG2PDF |
|
412 | * :ghpull:`3695`: fix SVG2PDF | |
413 | * :ghpull:`3685`: fix Pager.detach |
|
413 | * :ghpull:`3685`: fix Pager.detach | |
414 | * :ghpull:`3675`: document new dependencies |
|
414 | * :ghpull:`3675`: document new dependencies | |
415 | * :ghpull:`3690`: Fixing some css minors in full_html and reveal. |
|
415 | * :ghpull:`3690`: Fixing some css minors in full_html and reveal. | |
416 | * :ghpull:`3671`: nbconvert tests |
|
416 | * :ghpull:`3671`: nbconvert tests | |
417 | * :ghpull:`3692`: Fix rename notebook - show error with invalid name |
|
417 | * :ghpull:`3692`: Fix rename notebook - show error with invalid name | |
418 | * :ghpull:`3409`: Prevent qtconsole frontend freeze on lots of output. |
|
418 | * :ghpull:`3409`: Prevent qtconsole frontend freeze on lots of output. | |
419 | * :ghpull:`3660`: refocus active cell on dialog close |
|
419 | * :ghpull:`3660`: refocus active cell on dialog close | |
420 | * :ghpull:`3598`: Statelessify mathjaxutils |
|
420 | * :ghpull:`3598`: Statelessify mathjaxutils | |
421 | * :ghpull:`3673`: enable comment/uncomment selection |
|
421 | * :ghpull:`3673`: enable comment/uncomment selection | |
422 | * :ghpull:`3677`: remove special-case in get_home_dir for frozen dists |
|
422 | * :ghpull:`3677`: remove special-case in get_home_dir for frozen dists | |
423 | * :ghpull:`3674`: add CONTRIBUTING.md |
|
423 | * :ghpull:`3674`: add CONTRIBUTING.md | |
424 | * :ghpull:`3670`: use Popen command list for ipexec |
|
424 | * :ghpull:`3670`: use Popen command list for ipexec | |
425 | * :ghpull:`3568`: pylab import adjustments |
|
425 | * :ghpull:`3568`: pylab import adjustments | |
426 | * :ghpull:`3559`: add create.Cell and delete.Cell js events |
|
426 | * :ghpull:`3559`: add create.Cell and delete.Cell js events | |
427 | * :ghpull:`3606`: push cell magic to the head of the transformer line |
|
427 | * :ghpull:`3606`: push cell magic to the head of the transformer line | |
428 | * :ghpull:`3607`: NbConvert: Writers, No YAML, and stuff... |
|
428 | * :ghpull:`3607`: NbConvert: Writers, No YAML, and stuff... | |
429 | * :ghpull:`3665`: Pywin32 skips |
|
429 | * :ghpull:`3665`: Pywin32 skips | |
430 | * :ghpull:`3669`: set default client_class for QtKernelManager |
|
430 | * :ghpull:`3669`: set default client_class for QtKernelManager | |
431 | * :ghpull:`3662`: add strip_encoding_cookie transformer |
|
431 | * :ghpull:`3662`: add strip_encoding_cookie transformer | |
432 | * :ghpull:`3641`: increase patience for slow kernel startup in tests |
|
432 | * :ghpull:`3641`: increase patience for slow kernel startup in tests | |
433 | * :ghpull:`3651`: remove a bunch of unused `default_config_file` assignments |
|
433 | * :ghpull:`3651`: remove a bunch of unused `default_config_file` assignments | |
434 | * :ghpull:`3630`: CSS adjustments |
|
434 | * :ghpull:`3630`: CSS adjustments | |
435 | * :ghpull:`3645`: Don't require HistoryManager to have a shell |
|
435 | * :ghpull:`3645`: Don't require HistoryManager to have a shell | |
436 | * :ghpull:`3643`: don't assume tested ipython is on the PATH |
|
436 | * :ghpull:`3643`: don't assume tested ipython is on the PATH | |
437 | * :ghpull:`3654`: fix single-result AsyncResults |
|
437 | * :ghpull:`3654`: fix single-result AsyncResults | |
438 | * :ghpull:`3601`: Markdown in heading cells (take 2) |
|
438 | * :ghpull:`3601`: Markdown in heading cells (take 2) | |
439 | * :ghpull:`3652`: Remove old `docs/examples` |
|
439 | * :ghpull:`3652`: Remove old `docs/examples` | |
440 | * :ghpull:`3621`: catch any exception appending output |
|
440 | * :ghpull:`3621`: catch any exception appending output | |
441 | * :ghpull:`3585`: don't blacklist builtin names |
|
441 | * :ghpull:`3585`: don't blacklist builtin names | |
442 | * :ghpull:`3647`: Fix `frontend` deprecation warnings in several examples |
|
442 | * :ghpull:`3647`: Fix `frontend` deprecation warnings in several examples | |
443 | * :ghpull:`3649`: fix AsyncResult.get_dict for single result |
|
443 | * :ghpull:`3649`: fix AsyncResult.get_dict for single result | |
444 | * :ghpull:`3648`: Fix store magic test |
|
444 | * :ghpull:`3648`: Fix store magic test | |
445 | * :ghpull:`3650`: Fix, config_file_name was ignored |
|
445 | * :ghpull:`3650`: Fix, config_file_name was ignored | |
446 | * :ghpull:`3640`: Gcf.get_active() can return None |
|
446 | * :ghpull:`3640`: Gcf.get_active() can return None | |
447 | * :ghpull:`3571`: Added shorcuts to split cell, merge cell above and merge cell below. |
|
447 | * :ghpull:`3571`: Added shorcuts to split cell, merge cell above and merge cell below. | |
448 | * :ghpull:`3635`: Added missing slash to print-pdf call. |
|
448 | * :ghpull:`3635`: Added missing slash to print-pdf call. | |
449 | * :ghpull:`3487`: Drop patch for compatibility with pyreadline 1.5 |
|
449 | * :ghpull:`3487`: Drop patch for compatibility with pyreadline 1.5 | |
450 | * :ghpull:`3338`: Allow filename with extension in find_cmd in Windows. |
|
450 | * :ghpull:`3338`: Allow filename with extension in find_cmd in Windows. | |
451 | * :ghpull:`3628`: Fix test for Python 3 on Windows. |
|
451 | * :ghpull:`3628`: Fix test for Python 3 on Windows. | |
452 | * :ghpull:`3642`: Fix typo in docs |
|
452 | * :ghpull:`3642`: Fix typo in docs | |
453 | * :ghpull:`3627`: use DEFAULT_STATIC_FILES_PATH in a test instead of package dir |
|
453 | * :ghpull:`3627`: use DEFAULT_STATIC_FILES_PATH in a test instead of package dir | |
454 | * :ghpull:`3624`: fix some unicode in zmqhandlers |
|
454 | * :ghpull:`3624`: fix some unicode in zmqhandlers | |
455 | * :ghpull:`3460`: Set calling program to UNKNOWN, when argv not in sys |
|
455 | * :ghpull:`3460`: Set calling program to UNKNOWN, when argv not in sys | |
456 | * :ghpull:`3632`: Set calling program to UNKNOWN, when argv not in sys (take #2) |
|
456 | * :ghpull:`3632`: Set calling program to UNKNOWN, when argv not in sys (take #2) | |
457 | * :ghpull:`3629`: Use new entry point for python -m IPython |
|
457 | * :ghpull:`3629`: Use new entry point for python -m IPython | |
458 | * :ghpull:`3626`: passing cell to showInPager, closes #3625 |
|
458 | * :ghpull:`3626`: passing cell to showInPager, closes #3625 | |
459 | * :ghpull:`3618`: expand terminal color support |
|
459 | * :ghpull:`3618`: expand terminal color support | |
460 | * :ghpull:`3623`: raise UsageError for unsupported GUI backends |
|
460 | * :ghpull:`3623`: raise UsageError for unsupported GUI backends | |
461 | * :ghpull:`3071`: Add magic function %drun to run code in debugger |
|
461 | * :ghpull:`3071`: Add magic function %drun to run code in debugger | |
462 | * :ghpull:`3608`: a nicer error message when using %pylab magic |
|
462 | * :ghpull:`3608`: a nicer error message when using %pylab magic | |
463 | * :ghpull:`3592`: add extra_config_file |
|
463 | * :ghpull:`3592`: add extra_config_file | |
464 | * :ghpull:`3612`: updated .mailmap |
|
464 | * :ghpull:`3612`: updated .mailmap | |
465 | * :ghpull:`3616`: Add examples for interactive use of MPI. |
|
465 | * :ghpull:`3616`: Add examples for interactive use of MPI. | |
466 | * :ghpull:`3615`: fix regular expression for ANSI escapes |
|
466 | * :ghpull:`3615`: fix regular expression for ANSI escapes | |
467 | * :ghpull:`3586`: Corrected a typo in the format string for strftime the sphinx.py transformer of nbconvert |
|
467 | * :ghpull:`3586`: Corrected a typo in the format string for strftime the sphinx.py transformer of nbconvert | |
468 | * :ghpull:`3611`: check for markdown no longer needed, closes #3610 |
|
468 | * :ghpull:`3611`: check for markdown no longer needed, closes #3610 | |
469 | * :ghpull:`3555`: Simplify caching of modules with %run |
|
469 | * :ghpull:`3555`: Simplify caching of modules with %run | |
470 | * :ghpull:`3583`: notebook small things |
|
470 | * :ghpull:`3583`: notebook small things | |
471 | * :ghpull:`3594`: Fix duplicate completion in notebook |
|
471 | * :ghpull:`3594`: Fix duplicate completion in notebook | |
472 | * :ghpull:`3600`: parallel: Improved logging for errors during BatchSystemLauncher.stop |
|
472 | * :ghpull:`3600`: parallel: Improved logging for errors during BatchSystemLauncher.stop | |
473 | * :ghpull:`3595`: Revert "allow markdown in heading cells" |
|
473 | * :ghpull:`3595`: Revert "allow markdown in heading cells" | |
474 | * :ghpull:`3538`: add IPython.start_ipython |
|
474 | * :ghpull:`3538`: add IPython.start_ipython | |
475 | * :ghpull:`3562`: Allow custom nbconvert template loaders |
|
475 | * :ghpull:`3562`: Allow custom nbconvert template loaders | |
476 | * :ghpull:`3582`: pandoc adjustments |
|
476 | * :ghpull:`3582`: pandoc adjustments | |
477 | * :ghpull:`3560`: Remove max_msg_size |
|
477 | * :ghpull:`3560`: Remove max_msg_size | |
478 | * :ghpull:`3591`: Refer to Setuptools instead of Distribute |
|
478 | * :ghpull:`3591`: Refer to Setuptools instead of Distribute | |
479 | * :ghpull:`3590`: IPython.sphinxext needs an __init__.py |
|
479 | * :ghpull:`3590`: IPython.sphinxext needs an __init__.py | |
480 | * :ghpull:`3581`: Added the possibility to read a custom.css file for tweaking the final html in full_html and reveal templates. |
|
480 | * :ghpull:`3581`: Added the possibility to read a custom.css file for tweaking the final html in full_html and reveal templates. | |
481 | * :ghpull:`3576`: Added support for markdown in heading cells when they are nbconverted. |
|
481 | * :ghpull:`3576`: Added support for markdown in heading cells when they are nbconverted. | |
482 | * :ghpull:`3575`: tweak `run -d` message to 'continue execution' |
|
482 | * :ghpull:`3575`: tweak `run -d` message to 'continue execution' | |
483 | * :ghpull:`3569`: add PYTHONSTARTUP to startup files |
|
483 | * :ghpull:`3569`: add PYTHONSTARTUP to startup files | |
484 | * :ghpull:`3567`: Trigger a single event on js app initilized |
|
484 | * :ghpull:`3567`: Trigger a single event on js app initilized | |
485 | * :ghpull:`3565`: style.min.css shoudl always exist... |
|
485 | * :ghpull:`3565`: style.min.css shoudl always exist... | |
486 | * :ghpull:`3531`: allow markdown in heading cells |
|
486 | * :ghpull:`3531`: allow markdown in heading cells | |
487 | * :ghpull:`3577`: Simplify codemirror ipython-mode |
|
487 | * :ghpull:`3577`: Simplify codemirror ipython-mode | |
488 | * :ghpull:`3495`: Simplified regexp, and suggestions for clearer regexps. |
|
488 | * :ghpull:`3495`: Simplified regexp, and suggestions for clearer regexps. | |
489 | * :ghpull:`3578`: Use adjustbox to specify figure size in nbconvert -> latex |
|
489 | * :ghpull:`3578`: Use adjustbox to specify figure size in nbconvert -> latex | |
490 | * :ghpull:`3572`: Skip import irunner test on Windows. |
|
490 | * :ghpull:`3572`: Skip import irunner test on Windows. | |
491 | * :ghpull:`3574`: correct static path for CM modes autoload |
|
491 | * :ghpull:`3574`: correct static path for CM modes autoload | |
492 | * :ghpull:`3558`: Add IPython.sphinxext |
|
492 | * :ghpull:`3558`: Add IPython.sphinxext | |
493 | * :ghpull:`3561`: mention double-control-C to stop notebook server |
|
493 | * :ghpull:`3561`: mention double-control-C to stop notebook server | |
494 | * :ghpull:`3566`: fix event names |
|
494 | * :ghpull:`3566`: fix event names | |
495 | * :ghpull:`3564`: Remove trivial nbconvert example |
|
495 | * :ghpull:`3564`: Remove trivial nbconvert example | |
496 | * :ghpull:`3540`: allow cython cache dir to be deleted |
|
496 | * :ghpull:`3540`: allow cython cache dir to be deleted | |
497 | * :ghpull:`3527`: cleanup stale, unused exceptions in parallel.error |
|
497 | * :ghpull:`3527`: cleanup stale, unused exceptions in parallel.error | |
498 | * :ghpull:`3529`: ensure raw_input returns str in zmq shell |
|
498 | * :ghpull:`3529`: ensure raw_input returns str in zmq shell | |
499 | * :ghpull:`3541`: respect image size metadata in qtconsole |
|
499 | * :ghpull:`3541`: respect image size metadata in qtconsole | |
500 | * :ghpull:`3550`: Fixing issue preventing the correct read of images by full_html and reveal exporters. |
|
500 | * :ghpull:`3550`: Fixing issue preventing the correct read of images by full_html and reveal exporters. | |
501 | * :ghpull:`3557`: open markdown links in new tabs |
|
501 | * :ghpull:`3557`: open markdown links in new tabs | |
502 | * :ghpull:`3556`: remove mention of nonexistent `_margv` in macro |
|
502 | * :ghpull:`3556`: remove mention of nonexistent `_margv` in macro | |
503 | * :ghpull:`3552`: set overflow-x: hidden on Firefox only |
|
503 | * :ghpull:`3552`: set overflow-x: hidden on Firefox only | |
504 | * :ghpull:`3554`: Fix missing import os in latex exporter. |
|
504 | * :ghpull:`3554`: Fix missing import os in latex exporter. | |
505 | * :ghpull:`3546`: Don't hardcode **latex** posix paths in nbconvert |
|
505 | * :ghpull:`3546`: Don't hardcode **latex** posix paths in nbconvert | |
506 | * :ghpull:`3551`: fix path prefix in nbconvert |
|
506 | * :ghpull:`3551`: fix path prefix in nbconvert | |
507 | * :ghpull:`3533`: Use a CDN to get reveal.js library. |
|
507 | * :ghpull:`3533`: Use a CDN to get reveal.js library. | |
508 | * :ghpull:`3498`: When a notebook is written to file, name the metadata name u''. |
|
508 | * :ghpull:`3498`: When a notebook is written to file, name the metadata name u''. | |
509 | * :ghpull:`3548`: Change to standard save icon in Notebook toolbar |
|
509 | * :ghpull:`3548`: Change to standard save icon in Notebook toolbar | |
510 | * :ghpull:`3539`: Don't hardcode posix paths in nbconvert |
|
510 | * :ghpull:`3539`: Don't hardcode posix paths in nbconvert | |
511 | * :ghpull:`3508`: notebook supports raw_input and %debug now |
|
511 | * :ghpull:`3508`: notebook supports raw_input and %debug now | |
512 | * :ghpull:`3526`: ensure 'default' is first in cluster profile list |
|
512 | * :ghpull:`3526`: ensure 'default' is first in cluster profile list | |
513 | * :ghpull:`3525`: basic timezone info |
|
513 | * :ghpull:`3525`: basic timezone info | |
514 | * :ghpull:`3532`: include nbconvert templates in installation |
|
514 | * :ghpull:`3532`: include nbconvert templates in installation | |
515 | * :ghpull:`3515`: update CodeMirror component to 3.14 |
|
515 | * :ghpull:`3515`: update CodeMirror component to 3.14 | |
516 | * :ghpull:`3513`: add 'No Checkpoints' to Revert menu |
|
516 | * :ghpull:`3513`: add 'No Checkpoints' to Revert menu | |
517 | * :ghpull:`3536`: format positions are required in Python 2.6.x |
|
517 | * :ghpull:`3536`: format positions are required in Python 2.6.x | |
518 | * :ghpull:`3521`: Nbconvert fix, silent fail if template doesn't exist |
|
518 | * :ghpull:`3521`: Nbconvert fix, silent fail if template doesn't exist | |
519 | * :ghpull:`3530`: update %store magic docstring |
|
519 | * :ghpull:`3530`: update %store magic docstring | |
520 | * :ghpull:`3528`: fix local mathjax with custom base_project_url |
|
520 | * :ghpull:`3528`: fix local mathjax with custom base_project_url | |
521 | * :ghpull:`3518`: Clear up unused imports |
|
521 | * :ghpull:`3518`: Clear up unused imports | |
522 | * :ghpull:`3506`: %store -r restores saved aliases and directory history, as well as variables |
|
522 | * :ghpull:`3506`: %store -r restores saved aliases and directory history, as well as variables | |
523 | * :ghpull:`3516`: make css highlight style configurable |
|
523 | * :ghpull:`3516`: make css highlight style configurable | |
524 | * :ghpull:`3523`: Exclude frontend shim from docs build |
|
524 | * :ghpull:`3523`: Exclude frontend shim from docs build | |
525 | * :ghpull:`3514`: use bootstrap `disabled` instead of `ui-state-disabled` |
|
525 | * :ghpull:`3514`: use bootstrap `disabled` instead of `ui-state-disabled` | |
526 | * :ghpull:`3520`: Added relative import of RevealExporter to __init__.py inside exporters module |
|
526 | * :ghpull:`3520`: Added relative import of RevealExporter to __init__.py inside exporters module | |
527 | * :ghpull:`3507`: fix HTML capitalization in nbconvert exporter classes |
|
527 | * :ghpull:`3507`: fix HTML capitalization in nbconvert exporter classes | |
528 | * :ghpull:`3512`: fix nbconvert filter validation |
|
528 | * :ghpull:`3512`: fix nbconvert filter validation | |
529 | * :ghpull:`3511`: Get Tracer working after ipapi.get replaced with get_ipython |
|
529 | * :ghpull:`3511`: Get Tracer working after ipapi.get replaced with get_ipython | |
530 | * :ghpull:`3510`: use `window.onbeforeunload=` for nav-away warning |
|
530 | * :ghpull:`3510`: use `window.onbeforeunload=` for nav-away warning | |
531 | * :ghpull:`3504`: don't use parent=self in handlers |
|
531 | * :ghpull:`3504`: don't use parent=self in handlers | |
532 | * :ghpull:`3500`: Merge nbconvert into IPython |
|
532 | * :ghpull:`3500`: Merge nbconvert into IPython | |
533 | * :ghpull:`3478`: restore "unsaved changes" warning on unload |
|
533 | * :ghpull:`3478`: restore "unsaved changes" warning on unload | |
534 | * :ghpull:`3493`: add a dialog when the kernel is auto-restarted |
|
534 | * :ghpull:`3493`: add a dialog when the kernel is auto-restarted | |
535 | * :ghpull:`3488`: Add test suite for autoreload extension |
|
535 | * :ghpull:`3488`: Add test suite for autoreload extension | |
536 | * :ghpull:`3484`: Catch some pathological cases inside oinspect |
|
536 | * :ghpull:`3484`: Catch some pathological cases inside oinspect | |
537 | * :ghpull:`3481`: Display R errors without Python traceback |
|
537 | * :ghpull:`3481`: Display R errors without Python traceback | |
538 | * :ghpull:`3468`: fix `%magic` output |
|
538 | * :ghpull:`3468`: fix `%magic` output | |
539 | * :ghpull:`3430`: add parent to Configurable |
|
539 | * :ghpull:`3430`: add parent to Configurable | |
540 | * :ghpull:`3491`: Remove unexpected keyword parameter to remove_kernel |
|
540 | * :ghpull:`3491`: Remove unexpected keyword parameter to remove_kernel | |
541 | * :ghpull:`3485`: SymPy has changed its recommended way to initialize printing |
|
541 | * :ghpull:`3485`: SymPy has changed its recommended way to initialize printing | |
542 | * :ghpull:`3486`: Add test for non-ascii characters in docstrings |
|
542 | * :ghpull:`3486`: Add test for non-ascii characters in docstrings | |
543 | * :ghpull:`3483`: Inputtransformer: Allow classic prompts without space |
|
543 | * :ghpull:`3483`: Inputtransformer: Allow classic prompts without space | |
544 | * :ghpull:`3482`: Use an absolute path to iptest, because the tests are not always run from $IPYTHONDIR. |
|
544 | * :ghpull:`3482`: Use an absolute path to iptest, because the tests are not always run from $IPYTHONDIR. | |
545 | * :ghpull:`3381`: enable 2x (retina) display |
|
545 | * :ghpull:`3381`: enable 2x (retina) display | |
546 | * :ghpull:`3450`: Flatten IPython.frontend |
|
546 | * :ghpull:`3450`: Flatten IPython.frontend | |
547 | * :ghpull:`3477`: pass config to subapps |
|
547 | * :ghpull:`3477`: pass config to subapps | |
548 | * :ghpull:`3466`: Kernel fails to start when username has non-ascii characters |
|
548 | * :ghpull:`3466`: Kernel fails to start when username has non-ascii characters | |
549 | * :ghpull:`3465`: Add HTCondor bindings to IPython.parallel |
|
549 | * :ghpull:`3465`: Add HTCondor bindings to IPython.parallel | |
550 | * :ghpull:`3463`: fix typo, closes #3462 |
|
550 | * :ghpull:`3463`: fix typo, closes #3462 | |
551 | * :ghpull:`3456`: Notice for users who disable javascript |
|
551 | * :ghpull:`3456`: Notice for users who disable javascript | |
552 | * :ghpull:`3453`: fix cell execution in firefox, closes #3447 |
|
552 | * :ghpull:`3453`: fix cell execution in firefox, closes #3447 | |
553 | * :ghpull:`3393`: [WIP] bootstrapify |
|
553 | * :ghpull:`3393`: [WIP] bootstrapify | |
554 | * :ghpull:`3440`: Fix installing mathjax from downloaded file via command line |
|
554 | * :ghpull:`3440`: Fix installing mathjax from downloaded file via command line | |
555 | * :ghpull:`3431`: Provide means for starting the Qt console maximized and with the menu bar hidden |
|
555 | * :ghpull:`3431`: Provide means for starting the Qt console maximized and with the menu bar hidden | |
556 | * :ghpull:`3425`: base IPClusterApp inherits from BaseIPythonApp |
|
556 | * :ghpull:`3425`: base IPClusterApp inherits from BaseIPythonApp | |
557 | * :ghpull:`3433`: Update IPython\external\path\__init__.py |
|
557 | * :ghpull:`3433`: Update IPython\external\path\__init__.py | |
558 | * :ghpull:`3298`: Some fixes in IPython Sphinx directive |
|
558 | * :ghpull:`3298`: Some fixes in IPython Sphinx directive | |
559 | * :ghpull:`3428`: process escapes in mathjax |
|
559 | * :ghpull:`3428`: process escapes in mathjax | |
560 | * :ghpull:`3420`: thansk -> thanks |
|
560 | * :ghpull:`3420`: thansk -> thanks | |
561 | * :ghpull:`3416`: Fix doc: "principle" not "principal" |
|
561 | * :ghpull:`3416`: Fix doc: "principle" not "principal" | |
562 | * :ghpull:`3413`: more unique filename for test |
|
562 | * :ghpull:`3413`: more unique filename for test | |
563 | * :ghpull:`3364`: Inject requirejs in notebook and start using it. |
|
563 | * :ghpull:`3364`: Inject requirejs in notebook and start using it. | |
564 | * :ghpull:`3390`: Fix %paste with blank lines |
|
564 | * :ghpull:`3390`: Fix %paste with blank lines | |
565 | * :ghpull:`3403`: fix creating config objects from dicts |
|
565 | * :ghpull:`3403`: fix creating config objects from dicts | |
566 | * :ghpull:`3401`: rollback #3358 |
|
566 | * :ghpull:`3401`: rollback #3358 | |
567 | * :ghpull:`3373`: make cookie_secret configurable |
|
567 | * :ghpull:`3373`: make cookie_secret configurable | |
568 | * :ghpull:`3307`: switch default ws_url logic to js side |
|
568 | * :ghpull:`3307`: switch default ws_url logic to js side | |
569 | * :ghpull:`3392`: Restore anchor link on h2-h6 |
|
569 | * :ghpull:`3392`: Restore anchor link on h2-h6 | |
570 | * :ghpull:`3369`: Use different treshold for (auto)scroll in output |
|
570 | * :ghpull:`3369`: Use different treshold for (auto)scroll in output | |
571 | * :ghpull:`3370`: normalize unicode notebook filenames |
|
571 | * :ghpull:`3370`: normalize unicode notebook filenames | |
572 | * :ghpull:`3372`: base default cookie name on request host+port |
|
572 | * :ghpull:`3372`: base default cookie name on request host+port | |
573 | * :ghpull:`3378`: disable CodeMirror drag/drop on Safari |
|
573 | * :ghpull:`3378`: disable CodeMirror drag/drop on Safari | |
574 | * :ghpull:`3358`: workaround spurious CodeMirror scrollbars |
|
574 | * :ghpull:`3358`: workaround spurious CodeMirror scrollbars | |
575 | * :ghpull:`3371`: make setting the notebook dirty flag an event |
|
575 | * :ghpull:`3371`: make setting the notebook dirty flag an event | |
576 | * :ghpull:`3366`: remove long-dead zmq frontend.py and completer.py |
|
576 | * :ghpull:`3366`: remove long-dead zmq frontend.py and completer.py | |
577 | * :ghpull:`3382`: cull Session digest history |
|
577 | * :ghpull:`3382`: cull Session digest history | |
578 | * :ghpull:`3330`: Fix get_ipython_dir when $HOME is / |
|
578 | * :ghpull:`3330`: Fix get_ipython_dir when $HOME is / | |
579 | * :ghpull:`3319`: IPEP 13: user-expressions and user-variables |
|
579 | * :ghpull:`3319`: IPEP 13: user-expressions and user-variables | |
580 | * :ghpull:`3384`: comments in tools/gitwash_dumper.py changed (''' to """) |
|
580 | * :ghpull:`3384`: comments in tools/gitwash_dumper.py changed (''' to """) | |
581 | * :ghpull:`3387`: Make submodule checks work under Python 3. |
|
581 | * :ghpull:`3387`: Make submodule checks work under Python 3. | |
582 | * :ghpull:`3357`: move anchor-link off of heading text |
|
582 | * :ghpull:`3357`: move anchor-link off of heading text | |
583 | * :ghpull:`3351`: start basic tests of ipcluster Launchers |
|
583 | * :ghpull:`3351`: start basic tests of ipcluster Launchers | |
584 | * :ghpull:`3377`: allow class.__module__ to be None |
|
584 | * :ghpull:`3377`: allow class.__module__ to be None | |
585 | * :ghpull:`3340`: skip submodule check in package managers |
|
585 | * :ghpull:`3340`: skip submodule check in package managers | |
586 | * :ghpull:`3328`: decode subprocess output in launchers |
|
586 | * :ghpull:`3328`: decode subprocess output in launchers | |
587 | * :ghpull:`3368`: Reenable bracket matching |
|
587 | * :ghpull:`3368`: Reenable bracket matching | |
588 | * :ghpull:`3356`: Mpr fixes |
|
588 | * :ghpull:`3356`: Mpr fixes | |
589 | * :ghpull:`3336`: Use new input transformation API in %time magic |
|
589 | * :ghpull:`3336`: Use new input transformation API in %time magic | |
590 | * :ghpull:`3325`: Organize the JS and less files by component. |
|
590 | * :ghpull:`3325`: Organize the JS and less files by component. | |
591 | * :ghpull:`3342`: fix test_find_cmd_python |
|
591 | * :ghpull:`3342`: fix test_find_cmd_python | |
592 | * :ghpull:`3354`: catch socket.error in utils.localinterfaces |
|
592 | * :ghpull:`3354`: catch socket.error in utils.localinterfaces | |
593 | * :ghpull:`3341`: fix default cluster count |
|
593 | * :ghpull:`3341`: fix default cluster count | |
594 | * :ghpull:`3286`: don't use `get_ipython` from builtins in library code |
|
594 | * :ghpull:`3286`: don't use `get_ipython` from builtins in library code | |
595 | * :ghpull:`3333`: notebookapp: add missing whitespace to warnings |
|
595 | * :ghpull:`3333`: notebookapp: add missing whitespace to warnings | |
596 | * :ghpull:`3323`: Strip prompts even if the prompt isn't present on the first line. |
|
596 | * :ghpull:`3323`: Strip prompts even if the prompt isn't present on the first line. | |
597 | * :ghpull:`3321`: Reorganize the python/server side of the notebook |
|
597 | * :ghpull:`3321`: Reorganize the python/server side of the notebook | |
598 | * :ghpull:`3320`: define `__file__` in config files |
|
598 | * :ghpull:`3320`: define `__file__` in config files | |
599 | * :ghpull:`3317`: rename `%%file` to `%%writefile` |
|
599 | * :ghpull:`3317`: rename `%%file` to `%%writefile` | |
600 | * :ghpull:`3304`: set unlimited HWM for all relay devices |
|
600 | * :ghpull:`3304`: set unlimited HWM for all relay devices | |
601 | * :ghpull:`3315`: Update Sympy_printing extension load |
|
601 | * :ghpull:`3315`: Update Sympy_printing extension load | |
602 | * :ghpull:`3310`: further clarify Image docstring |
|
602 | * :ghpull:`3310`: further clarify Image docstring | |
603 | * :ghpull:`3285`: load extensions in builtin trap |
|
603 | * :ghpull:`3285`: load extensions in builtin trap | |
604 | * :ghpull:`3308`: Speed up AsyncResult._wait_for_outputs(0) |
|
604 | * :ghpull:`3308`: Speed up AsyncResult._wait_for_outputs(0) | |
605 | * :ghpull:`3294`: fix callbacks as optional in js kernel.execute |
|
605 | * :ghpull:`3294`: fix callbacks as optional in js kernel.execute | |
606 | * :ghpull:`3276`: Fix: "python ABS/PATH/TO/ipython.py" fails |
|
606 | * :ghpull:`3276`: Fix: "python ABS/PATH/TO/ipython.py" fails | |
607 | * :ghpull:`3301`: allow python3 tests without python installed |
|
607 | * :ghpull:`3301`: allow python3 tests without python installed | |
608 | * :ghpull:`3282`: allow view.map to work with a few more things |
|
608 | * :ghpull:`3282`: allow view.map to work with a few more things | |
609 | * :ghpull:`3284`: remove `ipython.py` entry point |
|
609 | * :ghpull:`3284`: remove `ipython.py` entry point | |
610 | * :ghpull:`3281`: fix ignored IOPub messages with no parent |
|
610 | * :ghpull:`3281`: fix ignored IOPub messages with no parent | |
611 | * :ghpull:`3275`: improve submodule messages / git hooks |
|
611 | * :ghpull:`3275`: improve submodule messages / git hooks | |
612 | * :ghpull:`3239`: Allow "x" icon and esc key to close pager in notebook |
|
612 | * :ghpull:`3239`: Allow "x" icon and esc key to close pager in notebook | |
613 | * :ghpull:`3290`: Improved heartbeat controller to engine monitoring for long running tasks |
|
613 | * :ghpull:`3290`: Improved heartbeat controller to engine monitoring for long running tasks | |
614 | * :ghpull:`3142`: Better error message when CWD doesn't exist on startup |
|
614 | * :ghpull:`3142`: Better error message when CWD doesn't exist on startup | |
615 | * :ghpull:`3066`: Add support for relative import to %run -m (fixes #2727) |
|
615 | * :ghpull:`3066`: Add support for relative import to %run -m (fixes #2727) | |
616 | * :ghpull:`3269`: protect highlight.js against unknown languages |
|
616 | * :ghpull:`3269`: protect highlight.js against unknown languages | |
617 | * :ghpull:`3267`: add missing return |
|
617 | * :ghpull:`3267`: add missing return | |
618 | * :ghpull:`3101`: use marked / highlight.js instead of pagedown and prettify |
|
618 | * :ghpull:`3101`: use marked / highlight.js instead of pagedown and prettify | |
619 | * :ghpull:`3264`: use https url for submodule |
|
619 | * :ghpull:`3264`: use https url for submodule | |
620 | * :ghpull:`3263`: fix set_last_checkpoint when no checkpoint |
|
620 | * :ghpull:`3263`: fix set_last_checkpoint when no checkpoint | |
621 | * :ghpull:`3258`: Fix submodule location in setup.py |
|
621 | * :ghpull:`3258`: Fix submodule location in setup.py | |
622 | * :ghpull:`3254`: fix a few URLs from previous PR |
|
622 | * :ghpull:`3254`: fix a few URLs from previous PR | |
623 | * :ghpull:`3240`: remove js components from the repo |
|
623 | * :ghpull:`3240`: remove js components from the repo | |
624 | * :ghpull:`3158`: IPEP 15: autosave the notebook |
|
624 | * :ghpull:`3158`: IPEP 15: autosave the notebook | |
625 | * :ghpull:`3252`: move images out of _static folder into _images |
|
625 | * :ghpull:`3252`: move images out of _static folder into _images | |
626 | * :ghpull:`3251`: Fix for cell magics in Qt console |
|
626 | * :ghpull:`3251`: Fix for cell magics in Qt console | |
627 | * :ghpull:`3250`: Added a simple __html__() method to the HTML class |
|
627 | * :ghpull:`3250`: Added a simple __html__() method to the HTML class | |
628 | * :ghpull:`3249`: remove copy of sphinx inheritance_diagram.py |
|
628 | * :ghpull:`3249`: remove copy of sphinx inheritance_diagram.py | |
629 | * :ghpull:`3235`: Remove the unused print notebook view |
|
629 | * :ghpull:`3235`: Remove the unused print notebook view | |
630 | * :ghpull:`3238`: Improve the design of the tab completion UI |
|
630 | * :ghpull:`3238`: Improve the design of the tab completion UI | |
631 | * :ghpull:`3242`: Make changes of Application.log_format effective |
|
631 | * :ghpull:`3242`: Make changes of Application.log_format effective | |
632 | * :ghpull:`3219`: Workaround so only one CTRL-C is required for a new prompt in --gui=qt |
|
632 | * :ghpull:`3219`: Workaround so only one CTRL-C is required for a new prompt in --gui=qt | |
633 | * :ghpull:`3190`: allow formatters to specify metadata |
|
633 | * :ghpull:`3190`: allow formatters to specify metadata | |
634 | * :ghpull:`3231`: improve discovery of public IPs |
|
634 | * :ghpull:`3231`: improve discovery of public IPs | |
635 | * :ghpull:`3233`: check prefixes for swallowing kernel args |
|
635 | * :ghpull:`3233`: check prefixes for swallowing kernel args | |
636 | * :ghpull:`3234`: Removing old autogrow JS code. |
|
636 | * :ghpull:`3234`: Removing old autogrow JS code. | |
637 | * :ghpull:`3232`: Update to CodeMirror 3 and start to ship our components |
|
637 | * :ghpull:`3232`: Update to CodeMirror 3 and start to ship our components | |
638 | * :ghpull:`3229`: The HTML output type accidentally got removed from the OutputArea. |
|
638 | * :ghpull:`3229`: The HTML output type accidentally got removed from the OutputArea. | |
639 | * :ghpull:`3228`: Typo in IPython.Parallel documentation |
|
639 | * :ghpull:`3228`: Typo in IPython.Parallel documentation | |
640 | * :ghpull:`3226`: Text in rename dialog was way too big - making it <p>. |
|
640 | * :ghpull:`3226`: Text in rename dialog was way too big - making it <p>. | |
641 | * :ghpull:`3225`: Removing old restuctured text handler and web service. |
|
641 | * :ghpull:`3225`: Removing old restuctured text handler and web service. | |
642 | * :ghpull:`3222`: make BlockingKernelClient the default Client |
|
642 | * :ghpull:`3222`: make BlockingKernelClient the default Client | |
643 | * :ghpull:`3223`: add missing mathjax_url to new settings dict |
|
643 | * :ghpull:`3223`: add missing mathjax_url to new settings dict | |
644 | * :ghpull:`3089`: add stdin to the notebook |
|
644 | * :ghpull:`3089`: add stdin to the notebook | |
645 | * :ghpull:`3221`: Remove references to HTMLCell (dead code) |
|
645 | * :ghpull:`3221`: Remove references to HTMLCell (dead code) | |
646 | * :ghpull:`3205`: add ignored *args to HasTraits constructor |
|
646 | * :ghpull:`3205`: add ignored ``*args`` to HasTraits constructor | |
647 | * :ghpull:`3088`: cleanup IPython handler settings |
|
647 | * :ghpull:`3088`: cleanup IPython handler settings | |
648 | * :ghpull:`3201`: use much faster regexp for ansi coloring |
|
648 | * :ghpull:`3201`: use much faster regexp for ansi coloring | |
649 | * :ghpull:`3220`: avoid race condition in profile creation |
|
649 | * :ghpull:`3220`: avoid race condition in profile creation | |
650 | * :ghpull:`3011`: IPEP 12: add KernelClient |
|
650 | * :ghpull:`3011`: IPEP 12: add KernelClient | |
651 | * :ghpull:`3217`: informative error when trying to load directories |
|
651 | * :ghpull:`3217`: informative error when trying to load directories | |
652 | * :ghpull:`3174`: Simple class |
|
652 | * :ghpull:`3174`: Simple class | |
653 | * :ghpull:`2979`: CM configurable Take 2 |
|
653 | * :ghpull:`2979`: CM configurable Take 2 | |
654 | * :ghpull:`3215`: Updates storemagic extension to allow for specifying variable name to load |
|
654 | * :ghpull:`3215`: Updates storemagic extension to allow for specifying variable name to load | |
655 | * :ghpull:`3181`: backport If-Modified-Since fix from tornado |
|
655 | * :ghpull:`3181`: backport If-Modified-Since fix from tornado | |
656 | * :ghpull:`3200`: IFrame (VimeoVideo, ScribdDocument, ...) |
|
656 | * :ghpull:`3200`: IFrame (VimeoVideo, ScribdDocument, ...) | |
657 | * :ghpull:`3186`: Fix small inconsistency in nbconvert: etype -> ename |
|
657 | * :ghpull:`3186`: Fix small inconsistency in nbconvert: etype -> ename | |
658 | * :ghpull:`3212`: Fix issue #2563, "core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation" |
|
658 | * :ghpull:`3212`: Fix issue #2563, "core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation" | |
659 | * :ghpull:`3211`: Fix inheritance_diagram Sphinx extension for Sphinx 1.2 |
|
659 | * :ghpull:`3211`: Fix inheritance_diagram Sphinx extension for Sphinx 1.2 | |
660 | * :ghpull:`3208`: Update link to extensions index |
|
660 | * :ghpull:`3208`: Update link to extensions index | |
661 | * :ghpull:`3203`: Separate InputSplitter for transforming whole cells |
|
661 | * :ghpull:`3203`: Separate InputSplitter for transforming whole cells | |
662 | * :ghpull:`3189`: Improve completer |
|
662 | * :ghpull:`3189`: Improve completer | |
663 | * :ghpull:`3194`: finish up PR #3116 |
|
663 | * :ghpull:`3194`: finish up PR #3116 | |
664 | * :ghpull:`3188`: Add new keycodes |
|
664 | * :ghpull:`3188`: Add new keycodes | |
665 | * :ghpull:`2695`: Key the root modules cache by sys.path entries. |
|
665 | * :ghpull:`2695`: Key the root modules cache by sys.path entries. | |
666 | * :ghpull:`3182`: clarify %%file docstring |
|
666 | * :ghpull:`3182`: clarify %%file docstring | |
667 | * :ghpull:`3163`: BUG: Fix the set and frozenset pretty printer to handle the empty case correctly |
|
667 | * :ghpull:`3163`: BUG: Fix the set and frozenset pretty printer to handle the empty case correctly | |
668 | * :ghpull:`3180`: better UsageError for cell magic with no body |
|
668 | * :ghpull:`3180`: better UsageError for cell magic with no body | |
669 | * :ghpull:`3184`: Cython cache |
|
669 | * :ghpull:`3184`: Cython cache | |
670 | * :ghpull:`3175`: Added missing s |
|
670 | * :ghpull:`3175`: Added missing s | |
671 | * :ghpull:`3173`: Little bits of documentation cleanup |
|
671 | * :ghpull:`3173`: Little bits of documentation cleanup | |
672 | * :ghpull:`2635`: Improve Windows start menu shortcuts (#2) |
|
672 | * :ghpull:`2635`: Improve Windows start menu shortcuts (#2) | |
673 | * :ghpull:`3172`: Add missing import in IPython parallel magics example |
|
673 | * :ghpull:`3172`: Add missing import in IPython parallel magics example | |
674 | * :ghpull:`3170`: default application logger shouldn't propagate |
|
674 | * :ghpull:`3170`: default application logger shouldn't propagate | |
675 | * :ghpull:`3159`: Autocompletion for zsh |
|
675 | * :ghpull:`3159`: Autocompletion for zsh | |
676 | * :ghpull:`3105`: move DEFAULT_STATIC_FILES_PATH to IPython.html |
|
676 | * :ghpull:`3105`: move DEFAULT_STATIC_FILES_PATH to IPython.html | |
677 | * :ghpull:`3144`: minor bower tweaks |
|
677 | * :ghpull:`3144`: minor bower tweaks | |
678 | * :ghpull:`3141`: Default color output for ls on OSX |
|
678 | * :ghpull:`3141`: Default color output for ls on OSX | |
679 | * :ghpull:`3137`: fix dot syntax error in inheritance diagram |
|
679 | * :ghpull:`3137`: fix dot syntax error in inheritance diagram | |
680 | * :ghpull:`3072`: raise UnsupportedOperation on iostream.fileno() |
|
680 | * :ghpull:`3072`: raise UnsupportedOperation on iostream.fileno() | |
681 | * :ghpull:`3147`: Notebook support for a reverse proxy which handles SSL |
|
681 | * :ghpull:`3147`: Notebook support for a reverse proxy which handles SSL | |
682 | * :ghpull:`3152`: make qtconsole size at startup configurable |
|
682 | * :ghpull:`3152`: make qtconsole size at startup configurable | |
683 | * :ghpull:`3162`: adding stream kwarg to current.new_output |
|
683 | * :ghpull:`3162`: adding stream kwarg to current.new_output | |
684 | * :ghpull:`2981`: IPEP 10: kernel side filtering of display formats |
|
684 | * :ghpull:`2981`: IPEP 10: kernel side filtering of display formats | |
685 | * :ghpull:`3058`: add redirect handler for notebooks by name |
|
685 | * :ghpull:`3058`: add redirect handler for notebooks by name | |
686 | * :ghpull:`3041`: support non-modules in @require |
|
686 | * :ghpull:`3041`: support non-modules in @require | |
687 | * :ghpull:`2447`: Stateful line transformers |
|
687 | * :ghpull:`2447`: Stateful line transformers | |
688 | * :ghpull:`3108`: fix some O(N) and O(N^2) operations in parallel.map |
|
688 | * :ghpull:`3108`: fix some O(N) and O(N^2) operations in parallel.map | |
689 | * :ghpull:`2791`: forward stdout from forked processes |
|
689 | * :ghpull:`2791`: forward stdout from forked processes | |
690 | * :ghpull:`3157`: use Python 3-style for pretty-printed sets |
|
690 | * :ghpull:`3157`: use Python 3-style for pretty-printed sets | |
691 | * :ghpull:`3148`: closes #3045, #3123 for tornado < version 3.0 |
|
691 | * :ghpull:`3148`: closes #3045, #3123 for tornado < version 3.0 | |
692 | * :ghpull:`3143`: minor heading-link tweaks |
|
692 | * :ghpull:`3143`: minor heading-link tweaks | |
693 | * :ghpull:`3136`: Strip useless ANSI escape codes in notebook |
|
693 | * :ghpull:`3136`: Strip useless ANSI escape codes in notebook | |
694 | * :ghpull:`3126`: Prevent errors when pressing arrow keys in an empty notebook |
|
694 | * :ghpull:`3126`: Prevent errors when pressing arrow keys in an empty notebook | |
695 | * :ghpull:`3135`: quick dev installation instructions |
|
695 | * :ghpull:`3135`: quick dev installation instructions | |
696 | * :ghpull:`2889`: Push pandas dataframes to R magic |
|
696 | * :ghpull:`2889`: Push pandas dataframes to R magic | |
697 | * :ghpull:`3068`: Don't monkeypatch doctest during IPython startup. |
|
697 | * :ghpull:`3068`: Don't monkeypatch doctest during IPython startup. | |
698 | * :ghpull:`3133`: fix argparse version check |
|
698 | * :ghpull:`3133`: fix argparse version check | |
699 | * :ghpull:`3102`: set `spellcheck=false` in CodeCell inputarea |
|
699 | * :ghpull:`3102`: set `spellcheck=false` in CodeCell inputarea | |
700 | * :ghpull:`3064`: add anchors to heading cells |
|
700 | * :ghpull:`3064`: add anchors to heading cells | |
701 | * :ghpull:`3097`: PyQt 4.10: use self._document = self.document() |
|
701 | * :ghpull:`3097`: PyQt 4.10: use self._document = self.document() | |
702 | * :ghpull:`3117`: propagate automagic change to shell |
|
702 | * :ghpull:`3117`: propagate automagic change to shell | |
703 | * :ghpull:`3118`: don't give up on weird os names |
|
703 | * :ghpull:`3118`: don't give up on weird os names | |
704 | * :ghpull:`3115`: Fix example |
|
704 | * :ghpull:`3115`: Fix example | |
705 | * :ghpull:`2640`: fix quarantine/ipy_editors.py |
|
705 | * :ghpull:`2640`: fix quarantine/ipy_editors.py | |
706 | * :ghpull:`3070`: Add info make target that was missing in old Sphinx |
|
706 | * :ghpull:`3070`: Add info make target that was missing in old Sphinx | |
707 | * :ghpull:`3082`: A few small patches to image handling |
|
707 | * :ghpull:`3082`: A few small patches to image handling | |
708 | * :ghpull:`3078`: fix regular expression for detecting links in stdout |
|
708 | * :ghpull:`3078`: fix regular expression for detecting links in stdout | |
709 | * :ghpull:`3054`: restore default behavior for automatic cluster size |
|
709 | * :ghpull:`3054`: restore default behavior for automatic cluster size | |
710 | * :ghpull:`3073`: fix ipython usage text |
|
710 | * :ghpull:`3073`: fix ipython usage text | |
711 | * :ghpull:`3083`: fix DisplayMagics.html docstring |
|
711 | * :ghpull:`3083`: fix DisplayMagics.html docstring | |
712 | * :ghpull:`3080`: noted sub_channel being renamed to iopub_channel |
|
712 | * :ghpull:`3080`: noted sub_channel being renamed to iopub_channel | |
713 | * :ghpull:`3079`: actually use IPKernelApp.kernel_class |
|
713 | * :ghpull:`3079`: actually use IPKernelApp.kernel_class | |
714 | * :ghpull:`3076`: Improve notebook.js documentation |
|
714 | * :ghpull:`3076`: Improve notebook.js documentation | |
715 | * :ghpull:`3063`: add missing `%%html` magic |
|
715 | * :ghpull:`3063`: add missing `%%html` magic | |
716 | * :ghpull:`3075`: check for SIGUSR1 before using it, closes #3074 |
|
716 | * :ghpull:`3075`: check for SIGUSR1 before using it, closes #3074 | |
717 | * :ghpull:`3051`: add width:100% to vbox for webkit / FF consistency |
|
717 | * :ghpull:`3051`: add width:100% to vbox for webkit / FF consistency | |
718 | * :ghpull:`2999`: increase registration timeout |
|
718 | * :ghpull:`2999`: increase registration timeout | |
719 | * :ghpull:`2997`: fix DictDB default size limit |
|
719 | * :ghpull:`2997`: fix DictDB default size limit | |
720 | * :ghpull:`3033`: on resume, print server info again |
|
720 | * :ghpull:`3033`: on resume, print server info again | |
721 | * :ghpull:`3062`: test double pyximport |
|
721 | * :ghpull:`3062`: test double pyximport | |
722 | * :ghpull:`3046`: cast kernel cwd to bytes on Python 2 on Windows |
|
722 | * :ghpull:`3046`: cast kernel cwd to bytes on Python 2 on Windows | |
723 | * :ghpull:`3038`: remove xml from notebook magic docstrings |
|
723 | * :ghpull:`3038`: remove xml from notebook magic docstrings | |
724 | * :ghpull:`3032`: fix time format to international time format |
|
724 | * :ghpull:`3032`: fix time format to international time format | |
725 | * :ghpull:`3022`: Fix test for Windows |
|
725 | * :ghpull:`3022`: Fix test for Windows | |
726 | * :ghpull:`3024`: changed instances of 'outout' to 'output' in alt texts |
|
726 | * :ghpull:`3024`: changed instances of 'outout' to 'output' in alt texts | |
727 | * :ghpull:`3013`: py3 workaround for reload in cythonmagic |
|
727 | * :ghpull:`3013`: py3 workaround for reload in cythonmagic | |
728 | * :ghpull:`2961`: time magic: shorten unnecessary output on windows |
|
728 | * :ghpull:`2961`: time magic: shorten unnecessary output on windows | |
729 | * :ghpull:`2987`: fix local files examples in markdown |
|
729 | * :ghpull:`2987`: fix local files examples in markdown | |
730 | * :ghpull:`2998`: fix css in .output_area pre |
|
730 | * :ghpull:`2998`: fix css in .output_area pre | |
731 | * :ghpull:`3003`: add $include /etc/inputrc to suggested ~/.inputrc |
|
731 | * :ghpull:`3003`: add $include /etc/inputrc to suggested ~/.inputrc | |
732 | * :ghpull:`2957`: Refactor qt import logic. Fixes #2955 |
|
732 | * :ghpull:`2957`: Refactor qt import logic. Fixes #2955 | |
733 | * :ghpull:`2994`: expanduser on %%file targets |
|
733 | * :ghpull:`2994`: expanduser on %%file targets | |
734 | * :ghpull:`2983`: fix run-all (that-> this) |
|
734 | * :ghpull:`2983`: fix run-all (that-> this) | |
735 | * :ghpull:`2964`: fix count when testing composite error output |
|
735 | * :ghpull:`2964`: fix count when testing composite error output | |
736 | * :ghpull:`2967`: shows entire session history when only startsess is given |
|
736 | * :ghpull:`2967`: shows entire session history when only startsess is given | |
737 | * :ghpull:`2942`: Move CM IPython theme out of codemirror folder |
|
737 | * :ghpull:`2942`: Move CM IPython theme out of codemirror folder | |
738 | * :ghpull:`2929`: Cleanup cell insertion |
|
738 | * :ghpull:`2929`: Cleanup cell insertion | |
739 | * :ghpull:`2933`: Minordocupdate |
|
739 | * :ghpull:`2933`: Minordocupdate | |
740 | * :ghpull:`2968`: fix notebook deletion. |
|
740 | * :ghpull:`2968`: fix notebook deletion. | |
741 | * :ghpull:`2966`: Added assert msg to extract_hist_ranges() |
|
741 | * :ghpull:`2966`: Added assert msg to extract_hist_ranges() | |
742 | * :ghpull:`2959`: Add command to trim the history database. |
|
742 | * :ghpull:`2959`: Add command to trim the history database. | |
743 | * :ghpull:`2681`: Don't enable pylab mode, when matplotlib is not importable |
|
743 | * :ghpull:`2681`: Don't enable pylab mode, when matplotlib is not importable | |
744 | * :ghpull:`2901`: Fix inputhook_wx on osx |
|
744 | * :ghpull:`2901`: Fix inputhook_wx on osx | |
745 | * :ghpull:`2871`: truncate potentially long CompositeErrors |
|
745 | * :ghpull:`2871`: truncate potentially long CompositeErrors | |
746 | * :ghpull:`2951`: use istype on lists/tuples |
|
746 | * :ghpull:`2951`: use istype on lists/tuples | |
747 | * :ghpull:`2946`: fix qtconsole history logic for end-of-line |
|
747 | * :ghpull:`2946`: fix qtconsole history logic for end-of-line | |
748 | * :ghpull:`2954`: fix logic for append_javascript |
|
748 | * :ghpull:`2954`: fix logic for append_javascript | |
749 | * :ghpull:`2941`: fix baseUrl |
|
749 | * :ghpull:`2941`: fix baseUrl | |
750 | * :ghpull:`2903`: Specify toggle value on cell line number |
|
750 | * :ghpull:`2903`: Specify toggle value on cell line number | |
751 | * :ghpull:`2911`: display order in output area configurable |
|
751 | * :ghpull:`2911`: display order in output area configurable | |
752 | * :ghpull:`2897`: Dont rely on BaseProjectUrl data in body tag |
|
752 | * :ghpull:`2897`: Dont rely on BaseProjectUrl data in body tag | |
753 | * :ghpull:`2894`: Cm configurable |
|
753 | * :ghpull:`2894`: Cm configurable | |
754 | * :ghpull:`2927`: next release will be 1.0 |
|
754 | * :ghpull:`2927`: next release will be 1.0 | |
755 | * :ghpull:`2932`: Simplify using notebook static files from external code |
|
755 | * :ghpull:`2932`: Simplify using notebook static files from external code | |
756 | * :ghpull:`2915`: added small config section to notebook docs page |
|
756 | * :ghpull:`2915`: added small config section to notebook docs page | |
757 | * :ghpull:`2924`: safe_run_module: Silence SystemExit codes 0 and None. |
|
757 | * :ghpull:`2924`: safe_run_module: Silence SystemExit codes 0 and None. | |
758 | * :ghpull:`2906`: Unpatch/Monkey patch CM |
|
758 | * :ghpull:`2906`: Unpatch/Monkey patch CM | |
759 | * :ghpull:`2921`: add menu item for undo delete cell |
|
759 | * :ghpull:`2921`: add menu item for undo delete cell | |
760 | * :ghpull:`2917`: Don't add logging handler if one already exists. |
|
760 | * :ghpull:`2917`: Don't add logging handler if one already exists. | |
761 | * :ghpull:`2910`: Respect DB_IP and DB_PORT in mongodb tests |
|
761 | * :ghpull:`2910`: Respect DB_IP and DB_PORT in mongodb tests | |
762 | * :ghpull:`2926`: Don't die if stderr/stdout do not support set_parent() #2925 |
|
762 | * :ghpull:`2926`: Don't die if stderr/stdout do not support set_parent() #2925 | |
763 | * :ghpull:`2885`: get monospace pager back |
|
763 | * :ghpull:`2885`: get monospace pager back | |
764 | * :ghpull:`2876`: fix celltoolbar layout on FF |
|
764 | * :ghpull:`2876`: fix celltoolbar layout on FF | |
765 | * :ghpull:`2904`: Skip remaining IPC test on Windows |
|
765 | * :ghpull:`2904`: Skip remaining IPC test on Windows | |
766 | * :ghpull:`2908`: fix last remaining KernelApp reference |
|
766 | * :ghpull:`2908`: fix last remaining KernelApp reference | |
767 | * :ghpull:`2905`: fix a few remaining KernelApp/IPKernelApp changes |
|
767 | * :ghpull:`2905`: fix a few remaining KernelApp/IPKernelApp changes | |
768 | * :ghpull:`2900`: Don't assume test case for %time will finish in 0 time |
|
768 | * :ghpull:`2900`: Don't assume test case for %time will finish in 0 time | |
769 | * :ghpull:`2893`: exclude fabfile from tests |
|
769 | * :ghpull:`2893`: exclude fabfile from tests | |
770 | * :ghpull:`2884`: Correct import for kernelmanager on Windows |
|
770 | * :ghpull:`2884`: Correct import for kernelmanager on Windows | |
771 | * :ghpull:`2882`: Utils cleanup |
|
771 | * :ghpull:`2882`: Utils cleanup | |
772 | * :ghpull:`2883`: Don't call ast.fix_missing_locations unless the AST could have been modified |
|
772 | * :ghpull:`2883`: Don't call ast.fix_missing_locations unless the AST could have been modified | |
773 | * :ghpull:`2855`: time(it) magic: Implement minutes/hour formatting and "%%time" cell magic |
|
773 | * :ghpull:`2855`: time(it) magic: Implement minutes/hour formatting and "%%time" cell magic | |
774 | * :ghpull:`2874`: Empty cell warnings |
|
774 | * :ghpull:`2874`: Empty cell warnings | |
775 | * :ghpull:`2819`: tweak history prefix search (up/^p) in qtconsole |
|
775 | * :ghpull:`2819`: tweak history prefix search (up/^p) in qtconsole | |
776 | * :ghpull:`2868`: Import performance |
|
776 | * :ghpull:`2868`: Import performance | |
777 | * :ghpull:`2877`: minor css fixes |
|
777 | * :ghpull:`2877`: minor css fixes | |
778 | * :ghpull:`2880`: update examples docs with kernel move |
|
778 | * :ghpull:`2880`: update examples docs with kernel move | |
779 | * :ghpull:`2878`: Pass host environment on to kernel |
|
779 | * :ghpull:`2878`: Pass host environment on to kernel | |
780 | * :ghpull:`2599`: func_kw_complete for builtin and cython with embededsignature=True using docstring |
|
780 | * :ghpull:`2599`: func_kw_complete for builtin and cython with embededsignature=True using docstring | |
781 | * :ghpull:`2792`: Add key "unique" to history_request protocol |
|
781 | * :ghpull:`2792`: Add key "unique" to history_request protocol | |
782 | * :ghpull:`2872`: fix payload keys |
|
782 | * :ghpull:`2872`: fix payload keys | |
783 | * :ghpull:`2869`: Fixing styling of toolbar selects on FF. |
|
783 | * :ghpull:`2869`: Fixing styling of toolbar selects on FF. | |
784 | * :ghpull:`2708`: Less css |
|
784 | * :ghpull:`2708`: Less css | |
785 | * :ghpull:`2854`: Move kernel code into IPython.kernel |
|
785 | * :ghpull:`2854`: Move kernel code into IPython.kernel | |
786 | * :ghpull:`2864`: Fix %run -t -N<N> TypeError |
|
786 | * :ghpull:`2864`: Fix %run -t -N<N> TypeError | |
787 | * :ghpull:`2852`: future pyzmq compatibility |
|
787 | * :ghpull:`2852`: future pyzmq compatibility | |
788 | * :ghpull:`2863`: whatsnew/version0.9.txt: Fix '~./ipython' -> '~/.ipython' typo |
|
788 | * :ghpull:`2863`: whatsnew/version0.9.txt: Fix '~./ipython' -> '~/.ipython' typo | |
789 | * :ghpull:`2861`: add missing KernelManager to ConsoleApp class list |
|
789 | * :ghpull:`2861`: add missing KernelManager to ConsoleApp class list | |
790 | * :ghpull:`2850`: Consolidate host IP detection in utils.localinterfaces |
|
790 | * :ghpull:`2850`: Consolidate host IP detection in utils.localinterfaces | |
791 | * :ghpull:`2859`: Correct docstring of ipython.py |
|
791 | * :ghpull:`2859`: Correct docstring of ipython.py | |
792 | * :ghpull:`2831`: avoid string version comparisons in external.qt |
|
792 | * :ghpull:`2831`: avoid string version comparisons in external.qt | |
793 | * :ghpull:`2844`: this should address the failure in #2732 |
|
793 | * :ghpull:`2844`: this should address the failure in #2732 | |
794 | * :ghpull:`2849`: utils/data: Use list comprehension for uniq_stable() |
|
794 | * :ghpull:`2849`: utils/data: Use list comprehension for uniq_stable() | |
795 | * :ghpull:`2839`: add jinja to install docs / setup.py |
|
795 | * :ghpull:`2839`: add jinja to install docs / setup.py | |
796 | * :ghpull:`2841`: Miscellaneous docs fixes |
|
796 | * :ghpull:`2841`: Miscellaneous docs fixes | |
797 | * :ghpull:`2811`: Still more KernelManager cleanup |
|
797 | * :ghpull:`2811`: Still more KernelManager cleanup | |
798 | * :ghpull:`2820`: add '=' to greedy completer delims |
|
798 | * :ghpull:`2820`: add '=' to greedy completer delims | |
799 | * :ghpull:`2818`: log user tracebacks in the kernel (INFO-level) |
|
799 | * :ghpull:`2818`: log user tracebacks in the kernel (INFO-level) | |
800 | * :ghpull:`2828`: Clean up notebook Javascript |
|
800 | * :ghpull:`2828`: Clean up notebook Javascript | |
801 | * :ghpull:`2829`: avoid comparison error in dictdb hub history |
|
801 | * :ghpull:`2829`: avoid comparison error in dictdb hub history | |
802 | * :ghpull:`2830`: BUG: Opening parenthesis after non-callable raises ValueError |
|
802 | * :ghpull:`2830`: BUG: Opening parenthesis after non-callable raises ValueError | |
803 | * :ghpull:`2718`: try to fallback to pysqlite2.dbapi2 as sqlite3 in core.history |
|
803 | * :ghpull:`2718`: try to fallback to pysqlite2.dbapi2 as sqlite3 in core.history | |
804 | * :ghpull:`2816`: in %edit, don't save "last_call" unless last call succeeded |
|
804 | * :ghpull:`2816`: in %edit, don't save "last_call" unless last call succeeded | |
805 | * :ghpull:`2817`: change ol format order |
|
805 | * :ghpull:`2817`: change ol format order | |
806 | * :ghpull:`2537`: Organize example notebooks |
|
806 | * :ghpull:`2537`: Organize example notebooks | |
807 | * :ghpull:`2815`: update release/authors |
|
807 | * :ghpull:`2815`: update release/authors | |
808 | * :ghpull:`2808`: improve patience for slow Hub in client tests |
|
808 | * :ghpull:`2808`: improve patience for slow Hub in client tests | |
809 | * :ghpull:`2812`: remove nonfunctional `-la` short arg in cython magic |
|
809 | * :ghpull:`2812`: remove nonfunctional `-la` short arg in cython magic | |
810 | * :ghpull:`2810`: remove dead utils.upgradedir |
|
810 | * :ghpull:`2810`: remove dead utils.upgradedir | |
811 | * :ghpull:`1671`: __future__ environments |
|
811 | * :ghpull:`1671`: __future__ environments | |
812 | * :ghpull:`2804`: skip ipc tests on Windows |
|
812 | * :ghpull:`2804`: skip ipc tests on Windows | |
813 | * :ghpull:`2789`: Fixing styling issues with CellToolbar. |
|
813 | * :ghpull:`2789`: Fixing styling issues with CellToolbar. | |
814 | * :ghpull:`2805`: fix KeyError creating ZMQStreams in notebook |
|
814 | * :ghpull:`2805`: fix KeyError creating ZMQStreams in notebook | |
815 | * :ghpull:`2775`: General cleanup of kernel manager code. |
|
815 | * :ghpull:`2775`: General cleanup of kernel manager code. | |
816 | * :ghpull:`2340`: Initial Code to reduce parallel.Client caching |
|
816 | * :ghpull:`2340`: Initial Code to reduce parallel.Client caching | |
817 | * :ghpull:`2799`: Exit code |
|
817 | * :ghpull:`2799`: Exit code | |
818 | * :ghpull:`2800`: use `type(obj) is cls` as switch when canning |
|
818 | * :ghpull:`2800`: use `type(obj) is cls` as switch when canning | |
819 | * :ghpull:`2801`: Fix a breakpoint bug |
|
819 | * :ghpull:`2801`: Fix a breakpoint bug | |
820 | * :ghpull:`2795`: Remove outdated code from extensions.autoreload |
|
820 | * :ghpull:`2795`: Remove outdated code from extensions.autoreload | |
821 | * :ghpull:`2796`: P3K: fix cookie parsing under Python 3.x (+ duplicate import is removed) |
|
821 | * :ghpull:`2796`: P3K: fix cookie parsing under Python 3.x (+ duplicate import is removed) | |
822 | * :ghpull:`2724`: In-process kernel support (take 3) |
|
822 | * :ghpull:`2724`: In-process kernel support (take 3) | |
823 | * :ghpull:`2687`: [WIP] Metaui slideshow |
|
823 | * :ghpull:`2687`: [WIP] Metaui slideshow | |
824 | * :ghpull:`2788`: Chrome frame awareness |
|
824 | * :ghpull:`2788`: Chrome frame awareness | |
825 | * :ghpull:`2649`: Add version_request/reply messaging protocol |
|
825 | * :ghpull:`2649`: Add version_request/reply messaging protocol | |
826 | * :ghpull:`2753`: add `%%px --local` for local execution |
|
826 | * :ghpull:`2753`: add `%%px --local` for local execution | |
827 | * :ghpull:`2783`: Prefilter shouldn't touch execution_count |
|
827 | * :ghpull:`2783`: Prefilter shouldn't touch execution_count | |
828 | * :ghpull:`2333`: UI For Metadata |
|
828 | * :ghpull:`2333`: UI For Metadata | |
829 | * :ghpull:`2396`: create a ipynbv3 json schema and a validator |
|
829 | * :ghpull:`2396`: create a ipynbv3 json schema and a validator | |
830 | * :ghpull:`2757`: check for complete pyside presence before trying to import |
|
830 | * :ghpull:`2757`: check for complete pyside presence before trying to import | |
831 | * :ghpull:`2782`: Allow the %run magic with '-b' to specify a file. |
|
831 | * :ghpull:`2782`: Allow the %run magic with '-b' to specify a file. | |
832 | * :ghpull:`2778`: P3K: fix DeprecationWarning under Python 3.x |
|
832 | * :ghpull:`2778`: P3K: fix DeprecationWarning under Python 3.x | |
833 | * :ghpull:`2776`: remove non-functional View.kill method |
|
833 | * :ghpull:`2776`: remove non-functional View.kill method | |
834 | * :ghpull:`2755`: can interactively defined classes |
|
834 | * :ghpull:`2755`: can interactively defined classes | |
835 | * :ghpull:`2774`: Removing unused code in the notebook MappingKernelManager. |
|
835 | * :ghpull:`2774`: Removing unused code in the notebook MappingKernelManager. | |
836 | * :ghpull:`2773`: Fixed minor typo causing AttributeError to be thrown. |
|
836 | * :ghpull:`2773`: Fixed minor typo causing AttributeError to be thrown. | |
837 | * :ghpull:`2609`: Add 'unique' option to history_request messaging protocol |
|
837 | * :ghpull:`2609`: Add 'unique' option to history_request messaging protocol | |
838 | * :ghpull:`2769`: Allow shutdown when no engines are registered |
|
838 | * :ghpull:`2769`: Allow shutdown when no engines are registered | |
839 | * :ghpull:`2766`: Define __file__ when we %edit a real file. |
|
839 | * :ghpull:`2766`: Define __file__ when we %edit a real file. | |
840 | * :ghpull:`2476`: allow %edit <variable> to work when interactively defined |
|
840 | * :ghpull:`2476`: allow %edit <variable> to work when interactively defined | |
841 | * :ghpull:`2763`: Reset readline delimiters after loading rmagic. |
|
841 | * :ghpull:`2763`: Reset readline delimiters after loading rmagic. | |
842 | * :ghpull:`2460`: Better handling of `__file__` when running scripts. |
|
842 | * :ghpull:`2460`: Better handling of `__file__` when running scripts. | |
843 | * :ghpull:`2617`: Fix for `units` argument. Adds a `res` argument. |
|
843 | * :ghpull:`2617`: Fix for `units` argument. Adds a `res` argument. | |
844 | * :ghpull:`2738`: Unicode content crashes the pager (console) |
|
844 | * :ghpull:`2738`: Unicode content crashes the pager (console) | |
845 | * :ghpull:`2749`: Tell Travis CI to test on Python 3.3 as well |
|
845 | * :ghpull:`2749`: Tell Travis CI to test on Python 3.3 as well | |
846 | * :ghpull:`2744`: Don't show 'try %paste' message while using magics |
|
846 | * :ghpull:`2744`: Don't show 'try %paste' message while using magics | |
847 | * :ghpull:`2728`: shift tab for tooltip |
|
847 | * :ghpull:`2728`: shift tab for tooltip | |
848 | * :ghpull:`2741`: Add note to `%cython` Black-Scholes example warning of missing erf. |
|
848 | * :ghpull:`2741`: Add note to `%cython` Black-Scholes example warning of missing erf. | |
849 | * :ghpull:`2743`: BUG: Octavemagic inline plots not working on Windows: Fixed |
|
849 | * :ghpull:`2743`: BUG: Octavemagic inline plots not working on Windows: Fixed | |
850 | * :ghpull:`2740`: Following #2737 this error is now a name error |
|
850 | * :ghpull:`2740`: Following #2737 this error is now a name error | |
851 | * :ghpull:`2737`: Rmagic: error message when moving an non-existant variable from python to R |
|
851 | * :ghpull:`2737`: Rmagic: error message when moving an non-existant variable from python to R | |
852 | * :ghpull:`2723`: diverse fixes for project url |
|
852 | * :ghpull:`2723`: diverse fixes for project url | |
853 | * :ghpull:`2731`: %Rpush: Look for variables in the local scope first. |
|
853 | * :ghpull:`2731`: %Rpush: Look for variables in the local scope first. | |
854 | * :ghpull:`2544`: Infinite loop when multiple debuggers have been attached. |
|
854 | * :ghpull:`2544`: Infinite loop when multiple debuggers have been attached. | |
855 | * :ghpull:`2726`: Add qthelp docs creation |
|
855 | * :ghpull:`2726`: Add qthelp docs creation | |
856 | * :ghpull:`2730`: added blockquote CSS |
|
856 | * :ghpull:`2730`: added blockquote CSS | |
857 | * :ghpull:`2729`: Fix Read the doc build, Again |
|
857 | * :ghpull:`2729`: Fix Read the doc build, Again | |
858 | * :ghpull:`2446`: [alternate 2267] Offline mathjax |
|
858 | * :ghpull:`2446`: [alternate 2267] Offline mathjax | |
859 | * :ghpull:`2716`: remove unexisting headings level |
|
859 | * :ghpull:`2716`: remove unexisting headings level | |
860 | * :ghpull:`2717`: One liner to fix debugger printing stack traces when lines of context are larger than source. |
|
860 | * :ghpull:`2717`: One liner to fix debugger printing stack traces when lines of context are larger than source. | |
861 | * :ghpull:`2713`: Doc bugfix: user_ns is not an attribute of Magic objects. |
|
861 | * :ghpull:`2713`: Doc bugfix: user_ns is not an attribute of Magic objects. | |
862 | * :ghpull:`2690`: Fix 'import '... completion for py3 & egg files. |
|
862 | * :ghpull:`2690`: Fix 'import '... completion for py3 & egg files. | |
863 | * :ghpull:`2691`: Document OpenMP in %%cython magic |
|
863 | * :ghpull:`2691`: Document OpenMP in %%cython magic | |
864 | * :ghpull:`2699`: fix jinja2 rendering for password protected notebooks |
|
864 | * :ghpull:`2699`: fix jinja2 rendering for password protected notebooks | |
865 | * :ghpull:`2700`: Skip notebook testing if jinja2 is not available. |
|
865 | * :ghpull:`2700`: Skip notebook testing if jinja2 is not available. | |
866 | * :ghpull:`2692`: Add %%cython magics to generated documentation. |
|
866 | * :ghpull:`2692`: Add %%cython magics to generated documentation. | |
867 | * :ghpull:`2685`: Fix pretty print of types when `__module__` is not available. |
|
867 | * :ghpull:`2685`: Fix pretty print of types when `__module__` is not available. | |
868 | * :ghpull:`2686`: Fix tox.ini |
|
868 | * :ghpull:`2686`: Fix tox.ini | |
869 | * :ghpull:`2604`: Backslashes are misinterpreted as escape-sequences by the R-interpreter. |
|
869 | * :ghpull:`2604`: Backslashes are misinterpreted as escape-sequences by the R-interpreter. | |
870 | * :ghpull:`2689`: fix error in doc (arg->kwarg) and pep-8 |
|
870 | * :ghpull:`2689`: fix error in doc (arg->kwarg) and pep-8 | |
871 | * :ghpull:`2683`: for downloads, replaced window.open with window.location.assign |
|
871 | * :ghpull:`2683`: for downloads, replaced window.open with window.location.assign | |
872 | * :ghpull:`2659`: small bugs in js are fixed |
|
872 | * :ghpull:`2659`: small bugs in js are fixed | |
873 | * :ghpull:`2363`: Refactor notebook templates to use Jinja2 |
|
873 | * :ghpull:`2363`: Refactor notebook templates to use Jinja2 | |
874 | * :ghpull:`2662`: qtconsole: wrap argument list in tooltip to match width of text body |
|
874 | * :ghpull:`2662`: qtconsole: wrap argument list in tooltip to match width of text body | |
875 | * :ghpull:`2328`: addition of classes to generate a link or list of links from files local to the IPython HTML notebook |
|
875 | * :ghpull:`2328`: addition of classes to generate a link or list of links from files local to the IPython HTML notebook | |
876 | * :ghpull:`2668`: pylab_not_importable: Catch all exceptions, not just RuntimeErrors. |
|
876 | * :ghpull:`2668`: pylab_not_importable: Catch all exceptions, not just RuntimeErrors. | |
877 | * :ghpull:`2663`: Fix issue #2660: parsing of help and version arguments |
|
877 | * :ghpull:`2663`: Fix issue #2660: parsing of help and version arguments | |
878 | * :ghpull:`2656`: Fix irunner tests when $PYTHONSTARTUP is set |
|
878 | * :ghpull:`2656`: Fix irunner tests when $PYTHONSTARTUP is set | |
879 | * :ghpull:`2312`: Add bracket matching to code cells in notebook |
|
879 | * :ghpull:`2312`: Add bracket matching to code cells in notebook | |
880 | * :ghpull:`2571`: Start to document Javascript |
|
880 | * :ghpull:`2571`: Start to document Javascript | |
881 | * :ghpull:`2641`: undefinied that -> this |
|
881 | * :ghpull:`2641`: undefinied that -> this | |
882 | * :ghpull:`2638`: Fix %paste in Python 3 on Mac |
|
882 | * :ghpull:`2638`: Fix %paste in Python 3 on Mac | |
883 | * :ghpull:`2301`: Ast transfomers |
|
883 | * :ghpull:`2301`: Ast transfomers | |
884 | * :ghpull:`2616`: Revamp API docs |
|
884 | * :ghpull:`2616`: Revamp API docs | |
885 | * :ghpull:`2572`: Make 'Paste Above' the default paste behavior. |
|
885 | * :ghpull:`2572`: Make 'Paste Above' the default paste behavior. | |
886 | * :ghpull:`2574`: Fix #2244 |
|
886 | * :ghpull:`2574`: Fix #2244 | |
887 | * :ghpull:`2582`: Fix displaying history when output cache is disabled. |
|
887 | * :ghpull:`2582`: Fix displaying history when output cache is disabled. | |
888 | * :ghpull:`2591`: Fix for Issue #2584 |
|
888 | * :ghpull:`2591`: Fix for Issue #2584 | |
889 | * :ghpull:`2526`: Don't kill paramiko tunnels when receiving ^C |
|
889 | * :ghpull:`2526`: Don't kill paramiko tunnels when receiving ^C | |
890 | * :ghpull:`2559`: Add psource, pfile, pinfo2 commands to ipdb. |
|
890 | * :ghpull:`2559`: Add psource, pfile, pinfo2 commands to ipdb. | |
891 | * :ghpull:`2546`: use 4 Pythons to build 4 Windows installers |
|
891 | * :ghpull:`2546`: use 4 Pythons to build 4 Windows installers | |
892 | * :ghpull:`2561`: Fix display of plain text containing multiple carriage returns before line feed |
|
892 | * :ghpull:`2561`: Fix display of plain text containing multiple carriage returns before line feed | |
893 | * :ghpull:`2549`: Add a simple 'undo' for cell deletion. |
|
893 | * :ghpull:`2549`: Add a simple 'undo' for cell deletion. | |
894 | * :ghpull:`2525`: Add event to kernel execution/shell reply. |
|
894 | * :ghpull:`2525`: Add event to kernel execution/shell reply. | |
895 | * :ghpull:`2554`: Avoid stopping in ipdb until we reach the main script. |
|
895 | * :ghpull:`2554`: Avoid stopping in ipdb until we reach the main script. | |
896 | * :ghpull:`2404`: Option to limit search result in history magic command |
|
896 | * :ghpull:`2404`: Option to limit search result in history magic command | |
897 | * :ghpull:`2294`: inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication |
|
897 | * :ghpull:`2294`: inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication | |
898 | * :ghpull:`2233`: Refactored Drag and Drop Support in Qt Console |
|
898 | * :ghpull:`2233`: Refactored Drag and Drop Support in Qt Console | |
899 | * :ghpull:`1747`: switch between hsplit and vsplit paging (request for feedback) |
|
899 | * :ghpull:`1747`: switch between hsplit and vsplit paging (request for feedback) | |
900 | * :ghpull:`2530`: Adding time offsets to the video |
|
900 | * :ghpull:`2530`: Adding time offsets to the video | |
901 | * :ghpull:`2542`: Allow starting IPython as `python -m IPython`. |
|
901 | * :ghpull:`2542`: Allow starting IPython as `python -m IPython`. | |
902 | * :ghpull:`2534`: Do not unescape backslashes in Windows (shellglob) |
|
902 | * :ghpull:`2534`: Do not unescape backslashes in Windows (shellglob) | |
903 | * :ghpull:`2517`: Improved MathJax, bug fixes |
|
903 | * :ghpull:`2517`: Improved MathJax, bug fixes | |
904 | * :ghpull:`2511`: trigger default remote_profile_dir when profile_dir is set |
|
904 | * :ghpull:`2511`: trigger default remote_profile_dir when profile_dir is set | |
905 | * :ghpull:`2491`: color is supported in ironpython |
|
905 | * :ghpull:`2491`: color is supported in ironpython | |
906 | * :ghpull:`2462`: Track which extensions are loaded |
|
906 | * :ghpull:`2462`: Track which extensions are loaded | |
907 | * :ghpull:`2464`: Locate URLs in text output and convert them to hyperlinks. |
|
907 | * :ghpull:`2464`: Locate URLs in text output and convert them to hyperlinks. | |
908 | * :ghpull:`2490`: add ZMQInteractiveShell to IPEngineApp class list |
|
908 | * :ghpull:`2490`: add ZMQInteractiveShell to IPEngineApp class list | |
909 | * :ghpull:`2498`: Don't catch tab press when something selected |
|
909 | * :ghpull:`2498`: Don't catch tab press when something selected | |
910 | * :ghpull:`2527`: Run All Above and Run All Below |
|
910 | * :ghpull:`2527`: Run All Above and Run All Below | |
911 | * :ghpull:`2513`: add GitHub uploads to release script |
|
911 | * :ghpull:`2513`: add GitHub uploads to release script | |
912 | * :ghpull:`2529`: Windows aware tests for shellglob |
|
912 | * :ghpull:`2529`: Windows aware tests for shellglob | |
913 | * :ghpull:`2478`: Fix doctest_run_option_parser for Windows |
|
913 | * :ghpull:`2478`: Fix doctest_run_option_parser for Windows | |
914 | * :ghpull:`2519`: clear In[ ] prompt numbers again |
|
914 | * :ghpull:`2519`: clear In[ ] prompt numbers again | |
915 | * :ghpull:`2467`: Clickable links |
|
915 | * :ghpull:`2467`: Clickable links | |
916 | * :ghpull:`2500`: Add `encoding` attribute to `OutStream` class. |
|
916 | * :ghpull:`2500`: Add `encoding` attribute to `OutStream` class. | |
917 | * :ghpull:`2349`: ENH: added StackExchange-style MathJax filtering |
|
917 | * :ghpull:`2349`: ENH: added StackExchange-style MathJax filtering | |
918 | * :ghpull:`2503`: Fix traceback handling of SyntaxErrors without line numbers. |
|
918 | * :ghpull:`2503`: Fix traceback handling of SyntaxErrors without line numbers. | |
919 | * :ghpull:`2492`: add missing 'qtconsole' extras_require |
|
919 | * :ghpull:`2492`: add missing 'qtconsole' extras_require | |
920 | * :ghpull:`2480`: Add deprecation warnings for sympyprinting |
|
920 | * :ghpull:`2480`: Add deprecation warnings for sympyprinting | |
921 | * :ghpull:`2334`: Make the ipengine monitor the ipcontroller heartbeat and die if the ipcontroller goes down |
|
921 | * :ghpull:`2334`: Make the ipengine monitor the ipcontroller heartbeat and die if the ipcontroller goes down | |
922 | * :ghpull:`2479`: use new _winapi instead of removed _subprocess |
|
922 | * :ghpull:`2479`: use new _winapi instead of removed _subprocess | |
923 | * :ghpull:`2474`: fix bootstrap name conflicts |
|
923 | * :ghpull:`2474`: fix bootstrap name conflicts | |
924 | * :ghpull:`2469`: Treat __init__.pyc same as __init__.py in module_list |
|
924 | * :ghpull:`2469`: Treat __init__.pyc same as __init__.py in module_list | |
925 | * :ghpull:`2165`: Add -g option to %run to glob expand arguments |
|
925 | * :ghpull:`2165`: Add -g option to %run to glob expand arguments | |
926 | * :ghpull:`2468`: Tell git to ignore __pycache__ directories. |
|
926 | * :ghpull:`2468`: Tell git to ignore __pycache__ directories. | |
927 | * :ghpull:`2421`: Some notebook tweaks. |
|
927 | * :ghpull:`2421`: Some notebook tweaks. | |
928 | * :ghpull:`2291`: Remove old plugin system |
|
928 | * :ghpull:`2291`: Remove old plugin system | |
929 | * :ghpull:`2127`: Ability to build toolbar in JS |
|
929 | * :ghpull:`2127`: Ability to build toolbar in JS | |
930 | * :ghpull:`2445`: changes for ironpython |
|
930 | * :ghpull:`2445`: changes for ironpython | |
931 | * :ghpull:`2420`: Pass ipython_dir to __init__() method of TerminalInteractiveShell's superclass. |
|
931 | * :ghpull:`2420`: Pass ipython_dir to __init__() method of TerminalInteractiveShell's superclass. | |
932 | * :ghpull:`2432`: Revert #1831, the `__file__` injection in safe_execfile / safe_execfile_ipy. |
|
932 | * :ghpull:`2432`: Revert #1831, the `__file__` injection in safe_execfile / safe_execfile_ipy. | |
933 | * :ghpull:`2216`: Autochange highlight with cell magics |
|
933 | * :ghpull:`2216`: Autochange highlight with cell magics | |
934 | * :ghpull:`1946`: Add image message handler in ZMQTerminalInteractiveShell |
|
934 | * :ghpull:`1946`: Add image message handler in ZMQTerminalInteractiveShell | |
935 | * :ghpull:`2424`: skip find_cmd when setting up script magics |
|
935 | * :ghpull:`2424`: skip find_cmd when setting up script magics | |
936 | * :ghpull:`2389`: Catch sqlite DatabaseErrors in more places when reading the history database |
|
936 | * :ghpull:`2389`: Catch sqlite DatabaseErrors in more places when reading the history database | |
937 | * :ghpull:`2395`: Don't catch ImportError when trying to unpack module functions |
|
937 | * :ghpull:`2395`: Don't catch ImportError when trying to unpack module functions | |
938 | * :ghpull:`1868`: enable IPC transport for kernels |
|
938 | * :ghpull:`1868`: enable IPC transport for kernels | |
939 | * :ghpull:`2437`: don't let log cleanup prevent engine start |
|
939 | * :ghpull:`2437`: don't let log cleanup prevent engine start | |
940 | * :ghpull:`2441`: `sys.maxsize` is the maximum length of a container. |
|
940 | * :ghpull:`2441`: `sys.maxsize` is the maximum length of a container. | |
941 | * :ghpull:`2442`: allow iptest to be interrupted |
|
941 | * :ghpull:`2442`: allow iptest to be interrupted | |
942 | * :ghpull:`2240`: fix message built for engine dying during task |
|
942 | * :ghpull:`2240`: fix message built for engine dying during task | |
943 | * :ghpull:`2369`: Block until kernel termination after sending a kill signal |
|
943 | * :ghpull:`2369`: Block until kernel termination after sending a kill signal | |
944 | * :ghpull:`2439`: Py3k: Octal (0777 -> 0o777) |
|
944 | * :ghpull:`2439`: Py3k: Octal (0777 -> 0o777) | |
945 | * :ghpull:`2326`: Detachable pager in notebook. |
|
945 | * :ghpull:`2326`: Detachable pager in notebook. | |
946 | * :ghpull:`2377`: Fix installation of man pages in Python 3 |
|
946 | * :ghpull:`2377`: Fix installation of man pages in Python 3 | |
947 | * :ghpull:`2407`: add IPython version to message headers |
|
947 | * :ghpull:`2407`: add IPython version to message headers | |
948 | * :ghpull:`2408`: Fix Issue #2366 |
|
948 | * :ghpull:`2408`: Fix Issue #2366 | |
949 | * :ghpull:`2405`: clarify TaskScheduler.hwm doc |
|
949 | * :ghpull:`2405`: clarify TaskScheduler.hwm doc | |
950 | * :ghpull:`2399`: IndentationError display |
|
950 | * :ghpull:`2399`: IndentationError display | |
951 | * :ghpull:`2400`: Add scroll_to_cell(cell_number) to the notebook |
|
951 | * :ghpull:`2400`: Add scroll_to_cell(cell_number) to the notebook | |
952 | * :ghpull:`2401`: unmock read-the-docs modules |
|
952 | * :ghpull:`2401`: unmock read-the-docs modules | |
953 | * :ghpull:`2311`: always perform requested trait assignments |
|
953 | * :ghpull:`2311`: always perform requested trait assignments | |
954 | * :ghpull:`2393`: New option `n` to limit history search hits |
|
954 | * :ghpull:`2393`: New option `n` to limit history search hits | |
955 | * :ghpull:`2386`: Adapt inline backend to changes in matplotlib |
|
955 | * :ghpull:`2386`: Adapt inline backend to changes in matplotlib | |
956 | * :ghpull:`2392`: Remove suspicious double quote |
|
956 | * :ghpull:`2392`: Remove suspicious double quote | |
957 | * :ghpull:`2387`: Added -L library search path to cythonmagic cell magic |
|
957 | * :ghpull:`2387`: Added -L library search path to cythonmagic cell magic | |
958 | * :ghpull:`2370`: qtconsole: Create a prompt newline by inserting a new block (w/o formatting) |
|
958 | * :ghpull:`2370`: qtconsole: Create a prompt newline by inserting a new block (w/o formatting) | |
959 | * :ghpull:`1715`: Fix for #1688, traceback-unicode issue |
|
959 | * :ghpull:`1715`: Fix for #1688, traceback-unicode issue | |
960 | * :ghpull:`2378`: use Singleton.instance() for embed() instead of manual global |
|
960 | * :ghpull:`2378`: use Singleton.instance() for embed() instead of manual global | |
961 | * :ghpull:`2373`: fix missing imports in core.interactiveshell |
|
961 | * :ghpull:`2373`: fix missing imports in core.interactiveshell | |
962 | * :ghpull:`2368`: remove notification widget leftover |
|
962 | * :ghpull:`2368`: remove notification widget leftover | |
963 | * :ghpull:`2327`: Parallel: Support get/set of nested objects in view (e.g. dv['a.b']) |
|
963 | * :ghpull:`2327`: Parallel: Support get/set of nested objects in view (e.g. dv['a.b']) | |
964 | * :ghpull:`2362`: Clean up ProgressBar class in example notebook |
|
964 | * :ghpull:`2362`: Clean up ProgressBar class in example notebook | |
965 | * :ghpull:`2346`: Extra xterm identification in set_term_title |
|
965 | * :ghpull:`2346`: Extra xterm identification in set_term_title | |
966 | * :ghpull:`2352`: Notebook: Store the username in a cookie whose name is unique. |
|
966 | * :ghpull:`2352`: Notebook: Store the username in a cookie whose name is unique. | |
967 | * :ghpull:`2358`: add backport_pr to tools |
|
967 | * :ghpull:`2358`: add backport_pr to tools | |
968 | * :ghpull:`2365`: fix names of notebooks for download/save |
|
968 | * :ghpull:`2365`: fix names of notebooks for download/save | |
969 | * :ghpull:`2364`: make clients use 'location' properly (fixes #2361) |
|
969 | * :ghpull:`2364`: make clients use 'location' properly (fixes #2361) | |
970 | * :ghpull:`2354`: Refactor notebook templates to use Jinja2 |
|
970 | * :ghpull:`2354`: Refactor notebook templates to use Jinja2 | |
971 | * :ghpull:`2339`: add bash completion example |
|
971 | * :ghpull:`2339`: add bash completion example | |
972 | * :ghpull:`2345`: Remove references to 'version' no longer in argparse. Github issue #2343. |
|
972 | * :ghpull:`2345`: Remove references to 'version' no longer in argparse. Github issue #2343. | |
973 | * :ghpull:`2347`: adjust division error message checking to account for Python 3 |
|
973 | * :ghpull:`2347`: adjust division error message checking to account for Python 3 | |
974 | * :ghpull:`2305`: RemoteError._render_traceback_ calls self.render_traceback |
|
974 | * :ghpull:`2305`: RemoteError._render_traceback_ calls self.render_traceback | |
975 | * :ghpull:`2338`: Normalize line endings for ipexec_validate, fix for #2315. |
|
975 | * :ghpull:`2338`: Normalize line endings for ipexec_validate, fix for #2315. | |
976 | * :ghpull:`2192`: Introduce Notification Area |
|
976 | * :ghpull:`2192`: Introduce Notification Area | |
977 | * :ghpull:`2329`: Better error messages for common magic commands. |
|
977 | * :ghpull:`2329`: Better error messages for common magic commands. | |
978 | * :ghpull:`2337`: ENH: added StackExchange-style MathJax filtering |
|
978 | * :ghpull:`2337`: ENH: added StackExchange-style MathJax filtering | |
979 | * :ghpull:`2331`: update css for qtconsole in doc |
|
979 | * :ghpull:`2331`: update css for qtconsole in doc | |
980 | * :ghpull:`2317`: adding cluster_id to parallel.Client.__init__ |
|
980 | * :ghpull:`2317`: adding cluster_id to parallel.Client.__init__ | |
981 | * :ghpull:`2130`: Add -l option to %R magic to allow passing in of local namespace |
|
981 | * :ghpull:`2130`: Add -l option to %R magic to allow passing in of local namespace | |
982 | * :ghpull:`2196`: Fix for bad command line argument to latex |
|
982 | * :ghpull:`2196`: Fix for bad command line argument to latex | |
983 | * :ghpull:`2300`: bug fix: was crashing when sqlite3 is not installed |
|
983 | * :ghpull:`2300`: bug fix: was crashing when sqlite3 is not installed | |
984 | * :ghpull:`2184`: Expose store_history to execute_request messages. |
|
984 | * :ghpull:`2184`: Expose store_history to execute_request messages. | |
985 | * :ghpull:`2308`: Add welcome_message option to enable_pylab |
|
985 | * :ghpull:`2308`: Add welcome_message option to enable_pylab | |
986 | * :ghpull:`2302`: Fix variable expansion on 'self' |
|
986 | * :ghpull:`2302`: Fix variable expansion on 'self' | |
987 | * :ghpull:`2299`: Remove code from prefilter that duplicates functionality in inputsplitter |
|
987 | * :ghpull:`2299`: Remove code from prefilter that duplicates functionality in inputsplitter | |
988 | * :ghpull:`2295`: allow pip install from github repository directly |
|
988 | * :ghpull:`2295`: allow pip install from github repository directly | |
989 | * :ghpull:`2280`: fix SSH passwordless check for OpenSSH |
|
989 | * :ghpull:`2280`: fix SSH passwordless check for OpenSSH | |
990 | * :ghpull:`2290`: nbmanager |
|
990 | * :ghpull:`2290`: nbmanager | |
991 | * :ghpull:`2288`: s/assertEquals/assertEqual (again) |
|
991 | * :ghpull:`2288`: s/assertEquals/assertEqual (again) | |
992 | * :ghpull:`2287`: Removed outdated dev docs. |
|
992 | * :ghpull:`2287`: Removed outdated dev docs. | |
993 | * :ghpull:`2218`: Use redirect for new notebooks |
|
993 | * :ghpull:`2218`: Use redirect for new notebooks | |
994 | * :ghpull:`2277`: nb: up/down arrow keys move to begin/end of line at top/bottom of cell |
|
994 | * :ghpull:`2277`: nb: up/down arrow keys move to begin/end of line at top/bottom of cell | |
995 | * :ghpull:`2045`: Refactoring notebook managers and adding Azure backed storage. |
|
995 | * :ghpull:`2045`: Refactoring notebook managers and adding Azure backed storage. | |
996 | * :ghpull:`2271`: use display instead of send_figure in inline backend hooks |
|
996 | * :ghpull:`2271`: use display instead of send_figure in inline backend hooks | |
997 | * :ghpull:`2278`: allow disabling SQLite history |
|
997 | * :ghpull:`2278`: allow disabling SQLite history | |
998 | * :ghpull:`2225`: Add "--annotate" option to `%%cython` magic. |
|
998 | * :ghpull:`2225`: Add "--annotate" option to `%%cython` magic. | |
999 | * :ghpull:`2246`: serialize individual args/kwargs rather than the containers |
|
999 | * :ghpull:`2246`: serialize individual args/kwargs rather than the containers | |
1000 | * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching. |
|
1000 | * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching. | |
1001 | * :ghpull:`2270`: SSHLauncher tweaks |
|
1001 | * :ghpull:`2270`: SSHLauncher tweaks | |
1002 | * :ghpull:`2269`: add missing location when disambiguating controller IP |
|
1002 | * :ghpull:`2269`: add missing location when disambiguating controller IP | |
1003 | * :ghpull:`2263`: Allow docs to build on http://readthedocs.org/ |
|
1003 | * :ghpull:`2263`: Allow docs to build on http://readthedocs.org/ | |
1004 | * :ghpull:`2256`: Adding data publication example notebook. |
|
1004 | * :ghpull:`2256`: Adding data publication example notebook. | |
1005 | * :ghpull:`2255`: better flush iopub with AsyncResults |
|
1005 | * :ghpull:`2255`: better flush iopub with AsyncResults | |
1006 | * :ghpull:`2261`: Fix: longest_substr([]) -> '' |
|
1006 | * :ghpull:`2261`: Fix: longest_substr([]) -> '' | |
1007 | * :ghpull:`2260`: fix mpr again |
|
1007 | * :ghpull:`2260`: fix mpr again | |
1008 | * :ghpull:`2242`: Document globbing in `%history -g <pattern>`. |
|
1008 | * :ghpull:`2242`: Document globbing in `%history -g <pattern>`. | |
1009 | * :ghpull:`2250`: fix html in notebook example |
|
1009 | * :ghpull:`2250`: fix html in notebook example | |
1010 | * :ghpull:`2245`: Fix regression in embed() from pull-request #2096. |
|
1010 | * :ghpull:`2245`: Fix regression in embed() from pull-request #2096. | |
1011 | * :ghpull:`2248`: track sha of master in test_pr messages |
|
1011 | * :ghpull:`2248`: track sha of master in test_pr messages | |
1012 | * :ghpull:`2238`: Fast tests |
|
1012 | * :ghpull:`2238`: Fast tests | |
1013 | * :ghpull:`2211`: add data publication message |
|
1013 | * :ghpull:`2211`: add data publication message | |
1014 | * :ghpull:`2236`: minor test_pr tweaks |
|
1014 | * :ghpull:`2236`: minor test_pr tweaks | |
1015 | * :ghpull:`2231`: Improve Image format validation and add html width,height |
|
1015 | * :ghpull:`2231`: Improve Image format validation and add html width,height | |
1016 | * :ghpull:`2232`: Reapply monkeypatch to inspect.findsource() |
|
1016 | * :ghpull:`2232`: Reapply monkeypatch to inspect.findsource() | |
1017 | * :ghpull:`2235`: remove spurious print statement from setupbase.py |
|
1017 | * :ghpull:`2235`: remove spurious print statement from setupbase.py | |
1018 | * :ghpull:`2222`: adjust how canning deals with import strings |
|
1018 | * :ghpull:`2222`: adjust how canning deals with import strings | |
1019 | * :ghpull:`2224`: fix css typo |
|
1019 | * :ghpull:`2224`: fix css typo | |
1020 | * :ghpull:`2223`: Custom tracebacks |
|
1020 | * :ghpull:`2223`: Custom tracebacks | |
1021 | * :ghpull:`2214`: use KernelApp.exec_lines/files in IPEngineApp |
|
1021 | * :ghpull:`2214`: use KernelApp.exec_lines/files in IPEngineApp | |
1022 | * :ghpull:`2199`: Wrap JS published by %%javascript in try/catch |
|
1022 | * :ghpull:`2199`: Wrap JS published by %%javascript in try/catch | |
1023 | * :ghpull:`2212`: catch errors in markdown javascript |
|
1023 | * :ghpull:`2212`: catch errors in markdown javascript | |
1024 | * :ghpull:`2190`: Update code mirror 2.22 to 2.32 |
|
1024 | * :ghpull:`2190`: Update code mirror 2.22 to 2.32 | |
1025 | * :ghpull:`2200`: documentation build broken in bb429da5b |
|
1025 | * :ghpull:`2200`: documentation build broken in bb429da5b | |
1026 | * :ghpull:`2194`: clean nan/inf in json_clean |
|
1026 | * :ghpull:`2194`: clean nan/inf in json_clean | |
1027 | * :ghpull:`2198`: fix mpr for earlier git version |
|
1027 | * :ghpull:`2198`: fix mpr for earlier git version | |
1028 | * :ghpull:`2175`: add FileFindHandler for Notebook static files |
|
1028 | * :ghpull:`2175`: add FileFindHandler for Notebook static files | |
1029 | * :ghpull:`1990`: can func_defaults |
|
1029 | * :ghpull:`1990`: can func_defaults | |
1030 | * :ghpull:`2069`: start improving serialization in parallel code |
|
1030 | * :ghpull:`2069`: start improving serialization in parallel code | |
1031 | * :ghpull:`2202`: Create a unique & temporary IPYTHONDIR for each testing group. |
|
1031 | * :ghpull:`2202`: Create a unique & temporary IPYTHONDIR for each testing group. | |
1032 | * :ghpull:`2204`: Work around lack of os.kill in win32. |
|
1032 | * :ghpull:`2204`: Work around lack of os.kill in win32. | |
1033 | * :ghpull:`2148`: win32 iptest: Use subprocess.Popen() instead of os.system(). |
|
1033 | * :ghpull:`2148`: win32 iptest: Use subprocess.Popen() instead of os.system(). | |
1034 | * :ghpull:`2179`: Pylab switch |
|
1034 | * :ghpull:`2179`: Pylab switch | |
1035 | * :ghpull:`2124`: Add an API for registering magic aliases. |
|
1035 | * :ghpull:`2124`: Add an API for registering magic aliases. | |
1036 | * :ghpull:`2169`: ipdb: pdef, pdoc, pinfo magics all broken |
|
1036 | * :ghpull:`2169`: ipdb: pdef, pdoc, pinfo magics all broken | |
1037 | * :ghpull:`2174`: Ensure consistent indentation in `%magic`. |
|
1037 | * :ghpull:`2174`: Ensure consistent indentation in `%magic`. | |
1038 | * :ghpull:`1930`: add size-limiting to the DictDB backend |
|
1038 | * :ghpull:`1930`: add size-limiting to the DictDB backend | |
1039 | * :ghpull:`2189`: Fix IPython.lib.latextools for Python 3 |
|
1039 | * :ghpull:`2189`: Fix IPython.lib.latextools for Python 3 | |
1040 | * :ghpull:`2186`: removed references to h5py dependence in octave magic documentation |
|
1040 | * :ghpull:`2186`: removed references to h5py dependence in octave magic documentation | |
1041 | * :ghpull:`2183`: Include the kernel object in the event object passed to kernel events |
|
1041 | * :ghpull:`2183`: Include the kernel object in the event object passed to kernel events | |
1042 | * :ghpull:`2185`: added test for %store, fixed storemagic |
|
1042 | * :ghpull:`2185`: added test for %store, fixed storemagic | |
1043 | * :ghpull:`2138`: Use breqn.sty in dvipng backend if possible |
|
1043 | * :ghpull:`2138`: Use breqn.sty in dvipng backend if possible | |
1044 | * :ghpull:`2182`: handle undefined param in notebooklist |
|
1044 | * :ghpull:`2182`: handle undefined param in notebooklist | |
1045 | * :ghpull:`1831`: fix #1814 set __file__ when running .ipy files |
|
1045 | * :ghpull:`1831`: fix #1814 set __file__ when running .ipy files | |
1046 | * :ghpull:`2051`: Add a metadata attribute to messages |
|
1046 | * :ghpull:`2051`: Add a metadata attribute to messages | |
1047 | * :ghpull:`1471`: simplify IPython.parallel connections and enable Controller Resume |
|
1047 | * :ghpull:`1471`: simplify IPython.parallel connections and enable Controller Resume | |
1048 | * :ghpull:`2181`: add %%javascript, %%svg, and %%latex display magics |
|
1048 | * :ghpull:`2181`: add %%javascript, %%svg, and %%latex display magics | |
1049 | * :ghpull:`2116`: different images in 00_notebook-tour |
|
1049 | * :ghpull:`2116`: different images in 00_notebook-tour | |
1050 | * :ghpull:`2092`: %prun: Restore `stats.stream` after running `print_stream`. |
|
1050 | * :ghpull:`2092`: %prun: Restore `stats.stream` after running `print_stream`. | |
1051 | * :ghpull:`2159`: show message on notebook list if server is unreachable |
|
1051 | * :ghpull:`2159`: show message on notebook list if server is unreachable | |
1052 | * :ghpull:`2176`: fix git mpr |
|
1052 | * :ghpull:`2176`: fix git mpr | |
1053 | * :ghpull:`2152`: [qtconsole] Namespace not empty at startup |
|
1053 | * :ghpull:`2152`: [qtconsole] Namespace not empty at startup | |
1054 | * :ghpull:`2177`: remove numpy install from travis/tox scripts |
|
1054 | * :ghpull:`2177`: remove numpy install from travis/tox scripts | |
1055 | * :ghpull:`2090`: New keybinding for code cell execution + cell insertion |
|
1055 | * :ghpull:`2090`: New keybinding for code cell execution + cell insertion | |
1056 | * :ghpull:`2160`: Updating the parallel options pricing example |
|
1056 | * :ghpull:`2160`: Updating the parallel options pricing example | |
1057 | * :ghpull:`2168`: expand line in cell magics |
|
1057 | * :ghpull:`2168`: expand line in cell magics | |
1058 | * :ghpull:`2170`: Fix tab completion with IPython.embed_kernel(). |
|
1058 | * :ghpull:`2170`: Fix tab completion with IPython.embed_kernel(). | |
1059 | * :ghpull:`2096`: embed(): Default to the future compiler flags of the calling frame. |
|
1059 | * :ghpull:`2096`: embed(): Default to the future compiler flags of the calling frame. | |
1060 | * :ghpull:`2163`: fix 'remote_profie_dir' typo in SSH launchers |
|
1060 | * :ghpull:`2163`: fix 'remote_profie_dir' typo in SSH launchers | |
1061 | * :ghpull:`2158`: [2to3 compat ] Tuple params in func defs |
|
1061 | * :ghpull:`2158`: [2to3 compat ] Tuple params in func defs | |
1062 | * :ghpull:`2089`: Fix unittest DeprecationWarnings |
|
1062 | * :ghpull:`2089`: Fix unittest DeprecationWarnings | |
1063 | * :ghpull:`2142`: Refactor test_pr.py |
|
1063 | * :ghpull:`2142`: Refactor test_pr.py | |
1064 | * :ghpull:`2140`: 2to3: Apply `has_key` fixer. |
|
1064 | * :ghpull:`2140`: 2to3: Apply `has_key` fixer. | |
1065 | * :ghpull:`2131`: Add option append (-a) to %save |
|
1065 | * :ghpull:`2131`: Add option append (-a) to %save | |
1066 | * :ghpull:`2117`: use explicit url in notebook example |
|
1066 | * :ghpull:`2117`: use explicit url in notebook example | |
1067 | * :ghpull:`2133`: Tell git that *.py files contain Python code, for use in word-diffs. |
|
1067 | * :ghpull:`2133`: Tell git that ``*.py`` files contain Python code, for use in word-diffs. | |
1068 | * :ghpull:`2134`: Apply 2to3 `next` fix. |
|
1068 | * :ghpull:`2134`: Apply 2to3 `next` fix. | |
1069 | * :ghpull:`2126`: ipcluster broken with any batch launcher (PBS/LSF/SGE) |
|
1069 | * :ghpull:`2126`: ipcluster broken with any batch launcher (PBS/LSF/SGE) | |
1070 | * :ghpull:`2104`: Windows make file for Sphinx documentation |
|
1070 | * :ghpull:`2104`: Windows make file for Sphinx documentation | |
1071 | * :ghpull:`2074`: Make BG color of inline plot configurable |
|
1071 | * :ghpull:`2074`: Make BG color of inline plot configurable | |
1072 | * :ghpull:`2123`: BUG: Look up the `_repr_pretty_` method on the class within the MRO rath... |
|
1072 | * :ghpull:`2123`: BUG: Look up the `_repr_pretty_` method on the class within the MRO rath... | |
1073 | * :ghpull:`2100`: [in progress] python 2 and 3 compatibility without 2to3, second try |
|
1073 | * :ghpull:`2100`: [in progress] python 2 and 3 compatibility without 2to3, second try | |
1074 | * :ghpull:`2128`: open notebook copy in different tabs |
|
1074 | * :ghpull:`2128`: open notebook copy in different tabs | |
1075 | * :ghpull:`2073`: allows password and prefix for notebook |
|
1075 | * :ghpull:`2073`: allows password and prefix for notebook | |
1076 | * :ghpull:`1993`: Print View |
|
1076 | * :ghpull:`1993`: Print View | |
1077 | * :ghpull:`2086`: re-aliad %ed to %edit in qtconsole |
|
1077 | * :ghpull:`2086`: re-aliad %ed to %edit in qtconsole | |
1078 | * :ghpull:`2110`: Fixes and improvements to the input splitter |
|
1078 | * :ghpull:`2110`: Fixes and improvements to the input splitter | |
1079 | * :ghpull:`2101`: fix completer deletting newline |
|
1079 | * :ghpull:`2101`: fix completer deletting newline | |
1080 | * :ghpull:`2102`: Fix logging on interactive shell. |
|
1080 | * :ghpull:`2102`: Fix logging on interactive shell. | |
1081 | * :ghpull:`2088`: Fix (some) Python 3.2 ResourceWarnings |
|
1081 | * :ghpull:`2088`: Fix (some) Python 3.2 ResourceWarnings | |
1082 | * :ghpull:`2064`: conform to pep 3110 |
|
1082 | * :ghpull:`2064`: conform to pep 3110 | |
1083 | * :ghpull:`2076`: Skip notebook 'static' dir in test suite. |
|
1083 | * :ghpull:`2076`: Skip notebook 'static' dir in test suite. | |
1084 | * :ghpull:`2063`: Remove umlauts so py3 installations on LANG=C systems succeed. |
|
1084 | * :ghpull:`2063`: Remove umlauts so py3 installations on LANG=C systems succeed. | |
1085 | * :ghpull:`2068`: record sysinfo in sdist |
|
1085 | * :ghpull:`2068`: record sysinfo in sdist | |
1086 | * :ghpull:`2067`: update tools/release_windows.py |
|
1086 | * :ghpull:`2067`: update tools/release_windows.py | |
1087 | * :ghpull:`2065`: Fix parentheses typo |
|
1087 | * :ghpull:`2065`: Fix parentheses typo | |
1088 | * :ghpull:`2062`: Remove duplicates and auto-generated files from repo. |
|
1088 | * :ghpull:`2062`: Remove duplicates and auto-generated files from repo. | |
1089 | * :ghpull:`2061`: use explicit tuple in exception |
|
1089 | * :ghpull:`2061`: use explicit tuple in exception | |
1090 | * :ghpull:`2060`: change minus to \- or \(hy in manpages |
|
1090 | * :ghpull:`2060`: change minus to \- or \(hy in manpages | |
1091 |
|
1091 | |||
1092 | Issues (691): |
|
1092 | Issues (691): | |
1093 |
|
1093 | |||
1094 | * :ghissue:`3940`: Install process documentation overhaul |
|
1094 | * :ghissue:`3940`: Install process documentation overhaul | |
1095 | * :ghissue:`3946`: The PDF option for `--post` should work with lowercase |
|
1095 | * :ghissue:`3946`: The PDF option for `--post` should work with lowercase | |
1096 | * :ghissue:`3957`: Notebook help page broken in Firefox |
|
1096 | * :ghissue:`3957`: Notebook help page broken in Firefox | |
1097 | * :ghissue:`3894`: nbconvert test failure |
|
1097 | * :ghissue:`3894`: nbconvert test failure | |
1098 | * :ghissue:`3887`: 1.0.0a1 shows blank screen in both firefox and chrome (windows 7) |
|
1098 | * :ghissue:`3887`: 1.0.0a1 shows blank screen in both firefox and chrome (windows 7) | |
1099 | * :ghissue:`3703`: `nbconvert`: Output options -- names and documentataion |
|
1099 | * :ghissue:`3703`: `nbconvert`: Output options -- names and documentataion | |
1100 | * :ghissue:`3931`: Tab completion not working during debugging in the notebook |
|
1100 | * :ghissue:`3931`: Tab completion not working during debugging in the notebook | |
1101 | * :ghissue:`3936`: Ipcluster plugin is not working with Ipython 1.0dev |
|
1101 | * :ghissue:`3936`: Ipcluster plugin is not working with Ipython 1.0dev | |
1102 | * :ghissue:`3941`: IPython Notebook kernel crash on Win7x64 |
|
1102 | * :ghissue:`3941`: IPython Notebook kernel crash on Win7x64 | |
1103 | * :ghissue:`3926`: Ending Notebook renaming dialog with return creates new-line |
|
1103 | * :ghissue:`3926`: Ending Notebook renaming dialog with return creates new-line | |
1104 | * :ghissue:`3932`: Incorrect empty docstring |
|
1104 | * :ghissue:`3932`: Incorrect empty docstring | |
1105 | * :ghissue:`3928`: Passing variables to script from the workspace |
|
1105 | * :ghissue:`3928`: Passing variables to script from the workspace | |
1106 | * :ghissue:`3774`: Notebooks with spaces in their names breaks nbconvert latex graphics |
|
1106 | * :ghissue:`3774`: Notebooks with spaces in their names breaks nbconvert latex graphics | |
1107 | * :ghissue:`3916`: tornado needs its own check |
|
1107 | * :ghissue:`3916`: tornado needs its own check | |
1108 | * :ghissue:`3915`: Link to Parallel examples "found on GitHub" broken in docs |
|
1108 | * :ghissue:`3915`: Link to Parallel examples "found on GitHub" broken in docs | |
1109 | * :ghissue:`3895`: Keyboard shortcuts box in notebook doesn't fit the screen |
|
1109 | * :ghissue:`3895`: Keyboard shortcuts box in notebook doesn't fit the screen | |
1110 | * :ghissue:`3912`: IPython.utils fails automated test for RC1 1.0.0 |
|
1110 | * :ghissue:`3912`: IPython.utils fails automated test for RC1 1.0.0 | |
1111 | * :ghissue:`3636`: Code cell missing highlight on load |
|
1111 | * :ghissue:`3636`: Code cell missing highlight on load | |
1112 | * :ghissue:`3897`: under Windows, "ipython3 nbconvert "C:/blabla/first_try.ipynb" --to latex --post PDF" POST processing action fails because of a bad parameter |
|
1112 | * :ghissue:`3897`: under Windows, "ipython3 nbconvert "C:/blabla/first_try.ipynb" --to latex --post PDF" POST processing action fails because of a bad parameter | |
1113 | * :ghissue:`3900`: python3 install syntax errors (OS X 10.8.4) |
|
1113 | * :ghissue:`3900`: python3 install syntax errors (OS X 10.8.4) | |
1114 | * :ghissue:`3899`: nbconvert to latex fails on notebooks with spaces in file name |
|
1114 | * :ghissue:`3899`: nbconvert to latex fails on notebooks with spaces in file name | |
1115 | * :ghissue:`3881`: Temporary Working Directory Test Fails |
|
1115 | * :ghissue:`3881`: Temporary Working Directory Test Fails | |
1116 | * :ghissue:`2750`: A way to freeze code cells in the notebook |
|
1116 | * :ghissue:`2750`: A way to freeze code cells in the notebook | |
1117 | * :ghissue:`3893`: Resize Local Image Files in Notebook doesn't work |
|
1117 | * :ghissue:`3893`: Resize Local Image Files in Notebook doesn't work | |
1118 | * :ghissue:`3823`: nbconvert on windows: tex and paths |
|
1118 | * :ghissue:`3823`: nbconvert on windows: tex and paths | |
1119 | * :ghissue:`3885`: under Windows, "ipython3 nbconvert "C:/blabla/first_try.ipynb" --to latex" write "\" instead of "/" to reference file path in the .tex file |
|
1119 | * :ghissue:`3885`: under Windows, "ipython3 nbconvert "C:/blabla/first_try.ipynb" --to latex" write "\" instead of "/" to reference file path in the .tex file | |
1120 | * :ghissue:`3889`: test_qt fails due to assertion error 'qt4' != 'qt' |
|
1120 | * :ghissue:`3889`: test_qt fails due to assertion error 'qt4' != 'qt' | |
1121 | * :ghissue:`3890`: double post, disregard this issue |
|
1121 | * :ghissue:`3890`: double post, disregard this issue | |
1122 | * :ghissue:`3689`: nbconvert, remaining tests |
|
1122 | * :ghissue:`3689`: nbconvert, remaining tests | |
1123 | * :ghissue:`3874`: Up/Down keys don't work to "Search previous command history" (besides Ctrl-p/Ctrl-n) |
|
1123 | * :ghissue:`3874`: Up/Down keys don't work to "Search previous command history" (besides Ctrl-p/Ctrl-n) | |
1124 | * :ghissue:`3853`: CodeMirror locks up in the notebook |
|
1124 | * :ghissue:`3853`: CodeMirror locks up in the notebook | |
1125 | * :ghissue:`3862`: can only connect to an ipcluster started with v1.0.0-dev (master branch) using an older ipython (v0.13.2), but cannot connect using ipython (v1.0.0-dev) |
|
1125 | * :ghissue:`3862`: can only connect to an ipcluster started with v1.0.0-dev (master branch) using an older ipython (v0.13.2), but cannot connect using ipython (v1.0.0-dev) | |
1126 | * :ghissue:`3869`: custom css not working. |
|
1126 | * :ghissue:`3869`: custom css not working. | |
1127 | * :ghissue:`2960`: Keyboard shortcuts |
|
1127 | * :ghissue:`2960`: Keyboard shortcuts | |
1128 | * :ghissue:`3795`: ipcontroller process goes to 100% CPU, ignores connection requests |
|
1128 | * :ghissue:`3795`: ipcontroller process goes to 100% CPU, ignores connection requests | |
1129 | * :ghissue:`3553`: Ipython and pylab crashes in windows and canopy |
|
1129 | * :ghissue:`3553`: Ipython and pylab crashes in windows and canopy | |
1130 | * :ghissue:`3837`: Cannot set custom mathjax url, crash notebook server. |
|
1130 | * :ghissue:`3837`: Cannot set custom mathjax url, crash notebook server. | |
1131 | * :ghissue:`3808`: "Naming" releases ? |
|
1131 | * :ghissue:`3808`: "Naming" releases ? | |
1132 | * :ghissue:`2431`: TypeError: must be string without null bytes, not str |
|
1132 | * :ghissue:`2431`: TypeError: must be string without null bytes, not str | |
1133 | * :ghissue:`3856`: `?` at end of comment causes line to execute |
|
1133 | * :ghissue:`3856`: `?` at end of comment causes line to execute | |
1134 | * :ghissue:`3731`: nbconvert: add logging for the different steps of nbconvert |
|
1134 | * :ghissue:`3731`: nbconvert: add logging for the different steps of nbconvert | |
1135 | * :ghissue:`3835`: Markdown cells do not render correctly when mathjax is disabled |
|
1135 | * :ghissue:`3835`: Markdown cells do not render correctly when mathjax is disabled | |
1136 | * :ghissue:`3843`: nbconvert to rst: leftover "In[ ]" |
|
1136 | * :ghissue:`3843`: nbconvert to rst: leftover "In[ ]" | |
1137 | * :ghissue:`3799`: nbconvert: Ability to specify name of output file |
|
1137 | * :ghissue:`3799`: nbconvert: Ability to specify name of output file | |
1138 | * :ghissue:`3726`: Document when IPython.start_ipython() should be used versus IPython.embed() |
|
1138 | * :ghissue:`3726`: Document when IPython.start_ipython() should be used versus IPython.embed() | |
1139 | * :ghissue:`3778`: Add no more readonly view in what's new |
|
1139 | * :ghissue:`3778`: Add no more readonly view in what's new | |
1140 | * :ghissue:`3754`: No Print View in Notebook in 1.0dev |
|
1140 | * :ghissue:`3754`: No Print View in Notebook in 1.0dev | |
1141 | * :ghissue:`3798`: IPython 0.12.1 Crashes on autocompleting sqlalchemy.func.row_number properties |
|
1141 | * :ghissue:`3798`: IPython 0.12.1 Crashes on autocompleting sqlalchemy.func.row_number properties | |
1142 | * :ghissue:`3811`: Opening notebook directly from the command line with multi-directory support installed |
|
1142 | * :ghissue:`3811`: Opening notebook directly from the command line with multi-directory support installed | |
1143 | * :ghissue:`3775`: Annoying behavior when clicking on cell after execution (Ctrl+Enter) |
|
1143 | * :ghissue:`3775`: Annoying behavior when clicking on cell after execution (Ctrl+Enter) | |
1144 | * :ghissue:`3809`: Possible to add some bpython features? |
|
1144 | * :ghissue:`3809`: Possible to add some bpython features? | |
1145 | * :ghissue:`3810`: Printing the contents of an image file messes up shell text |
|
1145 | * :ghissue:`3810`: Printing the contents of an image file messes up shell text | |
1146 | * :ghissue:`3702`: `nbconvert`: Default help message should be that of --help |
|
1146 | * :ghissue:`3702`: `nbconvert`: Default help message should be that of --help | |
1147 | * :ghissue:`3735`: Nbconvert 1.0.0a1 does not take into account the pdf extensions in graphs |
|
1147 | * :ghissue:`3735`: Nbconvert 1.0.0a1 does not take into account the pdf extensions in graphs | |
1148 | * :ghissue:`3719`: Bad strftime format, for windows, in nbconvert exporter |
|
1148 | * :ghissue:`3719`: Bad strftime format, for windows, in nbconvert exporter | |
1149 | * :ghissue:`3786`: Zmq errors appearing with `Ctrl-C` in console/qtconsole |
|
1149 | * :ghissue:`3786`: Zmq errors appearing with `Ctrl-C` in console/qtconsole | |
1150 | * :ghissue:`3019`: disappearing scrollbar on tooltip in Chrome 24 on Ubuntu 12.04 |
|
1150 | * :ghissue:`3019`: disappearing scrollbar on tooltip in Chrome 24 on Ubuntu 12.04 | |
1151 | * :ghissue:`3785`: ipdb completely broken in Qt console |
|
1151 | * :ghissue:`3785`: ipdb completely broken in Qt console | |
1152 | * :ghissue:`3796`: Document the meaning of milestone/issues-tags for users. |
|
1152 | * :ghissue:`3796`: Document the meaning of milestone/issues-tags for users. | |
1153 | * :ghissue:`3788`: Do not auto show tooltip if docstring empty. |
|
1153 | * :ghissue:`3788`: Do not auto show tooltip if docstring empty. | |
1154 | * :ghissue:`1366`: [Web page] No link to front page from documentation |
|
1154 | * :ghissue:`1366`: [Web page] No link to front page from documentation | |
1155 | * :ghissue:`3739`: nbconvert (to slideshow) misses some of the math in markdown cells |
|
1155 | * :ghissue:`3739`: nbconvert (to slideshow) misses some of the math in markdown cells | |
1156 | * :ghissue:`3768`: increase and make timeout configurable in console completion. |
|
1156 | * :ghissue:`3768`: increase and make timeout configurable in console completion. | |
1157 | * :ghissue:`3724`: ipcluster only running on one cpu |
|
1157 | * :ghissue:`3724`: ipcluster only running on one cpu | |
1158 | * :ghissue:`1592`: better message for unsupported nbformat |
|
1158 | * :ghissue:`1592`: better message for unsupported nbformat | |
1159 | * :ghissue:`2049`: Can not stop "ipython kernel" on windows |
|
1159 | * :ghissue:`2049`: Can not stop "ipython kernel" on windows | |
1160 | * :ghissue:`3757`: Need direct entry point to given notebook |
|
1160 | * :ghissue:`3757`: Need direct entry point to given notebook | |
1161 | * :ghissue:`3745`: ImportError: cannot import name check_linecache_ipython |
|
1161 | * :ghissue:`3745`: ImportError: cannot import name check_linecache_ipython | |
1162 | * :ghissue:`3701`: `nbconvert`: Final output file should be in same directory as input file |
|
1162 | * :ghissue:`3701`: `nbconvert`: Final output file should be in same directory as input file | |
1163 | * :ghissue:`3738`: history -o works but history with -n produces identical results |
|
1163 | * :ghissue:`3738`: history -o works but history with -n produces identical results | |
1164 | * :ghissue:`3740`: error when attempting to run 'make' in docs directory |
|
1164 | * :ghissue:`3740`: error when attempting to run 'make' in docs directory | |
1165 | * :ghissue:`3737`: ipython nbconvert crashes with ValueError: Invalid format string. |
|
1165 | * :ghissue:`3737`: ipython nbconvert crashes with ValueError: Invalid format string. | |
1166 | * :ghissue:`3730`: nbconvert: unhelpful error when pandoc isn't installed |
|
1166 | * :ghissue:`3730`: nbconvert: unhelpful error when pandoc isn't installed | |
1167 | * :ghissue:`3718`: markdown cell cursor misaligned in notebook |
|
1167 | * :ghissue:`3718`: markdown cell cursor misaligned in notebook | |
1168 | * :ghissue:`3710`: mutiple input fields for %debug in the notebook after resetting the kernel |
|
1168 | * :ghissue:`3710`: mutiple input fields for %debug in the notebook after resetting the kernel | |
1169 | * :ghissue:`3713`: PyCharm has problems with IPython working inside PyPy created by virtualenv |
|
1169 | * :ghissue:`3713`: PyCharm has problems with IPython working inside PyPy created by virtualenv | |
1170 | * :ghissue:`3712`: Code completion: Complete on dictionary keys |
|
1170 | * :ghissue:`3712`: Code completion: Complete on dictionary keys | |
1171 | * :ghissue:`3680`: --pylab and --matplotlib flag |
|
1171 | * :ghissue:`3680`: --pylab and --matplotlib flag | |
1172 | * :ghissue:`3698`: nbconvert: Unicode error with minus sign |
|
1172 | * :ghissue:`3698`: nbconvert: Unicode error with minus sign | |
1173 | * :ghissue:`3693`: nbconvert does not process SVGs into PDFs |
|
1173 | * :ghissue:`3693`: nbconvert does not process SVGs into PDFs | |
1174 | * :ghissue:`3688`: nbconvert, figures not extracting with Python 3.x |
|
1174 | * :ghissue:`3688`: nbconvert, figures not extracting with Python 3.x | |
1175 | * :ghissue:`3542`: note new dependencies in docs / setup.py |
|
1175 | * :ghissue:`3542`: note new dependencies in docs / setup.py | |
1176 | * :ghissue:`2556`: [pagedown] do not target_blank anchor link |
|
1176 | * :ghissue:`2556`: [pagedown] do not target_blank anchor link | |
1177 | * :ghissue:`3684`: bad message when %pylab fails due import *other* than matplotlib |
|
1177 | * :ghissue:`3684`: bad message when %pylab fails due import *other* than matplotlib | |
1178 | * :ghissue:`3682`: ipython notebook pylab inline import_all=False |
|
1178 | * :ghissue:`3682`: ipython notebook pylab inline import_all=False | |
1179 | * :ghissue:`3596`: MathjaxUtils race condition? |
|
1179 | * :ghissue:`3596`: MathjaxUtils race condition? | |
1180 | * :ghissue:`1540`: Comment/uncomment selection in notebook |
|
1180 | * :ghissue:`1540`: Comment/uncomment selection in notebook | |
1181 | * :ghissue:`2702`: frozen setup: permission denied for default ipython_dir |
|
1181 | * :ghissue:`2702`: frozen setup: permission denied for default ipython_dir | |
1182 | * :ghissue:`3672`: allow_none on Number-like traits. |
|
1182 | * :ghissue:`3672`: allow_none on Number-like traits. | |
1183 | * :ghissue:`2411`: add CONTRIBUTING.md |
|
1183 | * :ghissue:`2411`: add CONTRIBUTING.md | |
1184 | * :ghissue:`481`: IPython terminal issue with Qt4Agg on XP SP3 |
|
1184 | * :ghissue:`481`: IPython terminal issue with Qt4Agg on XP SP3 | |
1185 | * :ghissue:`2664`: How to preserve user variables from import clashing? |
|
1185 | * :ghissue:`2664`: How to preserve user variables from import clashing? | |
1186 | * :ghissue:`3436`: enable_pylab(import_all=False) still imports np |
|
1186 | * :ghissue:`3436`: enable_pylab(import_all=False) still imports np | |
1187 | * :ghissue:`2630`: lib.pylabtools.figsize : NameError when using Qt4Agg backend and %pylab magic. |
|
1187 | * :ghissue:`2630`: lib.pylabtools.figsize : NameError when using Qt4Agg backend and %pylab magic. | |
1188 | * :ghissue:`3154`: Notebook: no event triggered when a Cell is created |
|
1188 | * :ghissue:`3154`: Notebook: no event triggered when a Cell is created | |
1189 | * :ghissue:`3579`: Nbconvert: SVG are not transformed to PDF anymore |
|
1189 | * :ghissue:`3579`: Nbconvert: SVG are not transformed to PDF anymore | |
1190 | * :ghissue:`3604`: MathJax rendering problem in `%%latex` cell |
|
1190 | * :ghissue:`3604`: MathJax rendering problem in `%%latex` cell | |
1191 | * :ghissue:`3668`: AttributeError: 'BlockingKernelClient' object has no attribute 'started_channels' |
|
1191 | * :ghissue:`3668`: AttributeError: 'BlockingKernelClient' object has no attribute 'started_channels' | |
1192 | * :ghissue:`3245`: SyntaxError: encoding declaration in Unicode string |
|
1192 | * :ghissue:`3245`: SyntaxError: encoding declaration in Unicode string | |
1193 | * :ghissue:`3639`: %pylab inline in IPYTHON notebook throws "RuntimeError: Cannot activate multiple GUI eventloops" |
|
1193 | * :ghissue:`3639`: %pylab inline in IPYTHON notebook throws "RuntimeError: Cannot activate multiple GUI eventloops" | |
1194 | * :ghissue:`3663`: frontend deprecation warnings |
|
1194 | * :ghissue:`3663`: frontend deprecation warnings | |
1195 | * :ghissue:`3661`: run -m not behaving like python -m |
|
1195 | * :ghissue:`3661`: run -m not behaving like python -m | |
1196 | * :ghissue:`3597`: re-do PR #3531 - allow markdown in Header cell |
|
1196 | * :ghissue:`3597`: re-do PR #3531 - allow markdown in Header cell | |
1197 | * :ghissue:`3053`: Markdown in header cells is not rendered |
|
1197 | * :ghissue:`3053`: Markdown in header cells is not rendered | |
1198 | * :ghissue:`3655`: IPython finding its way into pasted strings. |
|
1198 | * :ghissue:`3655`: IPython finding its way into pasted strings. | |
1199 | * :ghissue:`3620`: uncaught errors in HTML output |
|
1199 | * :ghissue:`3620`: uncaught errors in HTML output | |
1200 | * :ghissue:`3646`: get_dict() error |
|
1200 | * :ghissue:`3646`: get_dict() error | |
1201 | * :ghissue:`3004`: `%load_ext rmagic` fails when legacy ipy_user_conf.py is installed (in ipython 0.13.1 / OSX 10.8) |
|
1201 | * :ghissue:`3004`: `%load_ext rmagic` fails when legacy ipy_user_conf.py is installed (in ipython 0.13.1 / OSX 10.8) | |
1202 | * :ghissue:`3638`: setp() issue in ipython notebook with figure references |
|
1202 | * :ghissue:`3638`: setp() issue in ipython notebook with figure references | |
1203 | * :ghissue:`3634`: nbconvert reveal to pdf conversion ignores styling, prints only a single page. |
|
1203 | * :ghissue:`3634`: nbconvert reveal to pdf conversion ignores styling, prints only a single page. | |
1204 | * :ghissue:`1307`: Remove pyreadline workarounds, we now require pyreadline >= 1.7.1 |
|
1204 | * :ghissue:`1307`: Remove pyreadline workarounds, we now require pyreadline >= 1.7.1 | |
1205 | * :ghissue:`3316`: find_cmd test failure on Windows |
|
1205 | * :ghissue:`3316`: find_cmd test failure on Windows | |
1206 | * :ghissue:`3494`: input() in notebook doesn't work in Python 3 |
|
1206 | * :ghissue:`3494`: input() in notebook doesn't work in Python 3 | |
1207 | * :ghissue:`3427`: Deprecate `$` as mathjax delimiter |
|
1207 | * :ghissue:`3427`: Deprecate `$` as mathjax delimiter | |
1208 | * :ghissue:`3625`: Pager does not open from button |
|
1208 | * :ghissue:`3625`: Pager does not open from button | |
1209 | * :ghissue:`3149`: Miscellaneous small nbconvert feedback |
|
1209 | * :ghissue:`3149`: Miscellaneous small nbconvert feedback | |
1210 | * :ghissue:`3617`: 256 color escapes support |
|
1210 | * :ghissue:`3617`: 256 color escapes support | |
1211 | * :ghissue:`3609`: %pylab inline blows up for single process ipython |
|
1211 | * :ghissue:`3609`: %pylab inline blows up for single process ipython | |
1212 | * :ghissue:`2934`: Publish the Interactive MPI Demo Notebook |
|
1212 | * :ghissue:`2934`: Publish the Interactive MPI Demo Notebook | |
1213 | * :ghissue:`3614`: ansi escapes broken in master (ls --color) |
|
1213 | * :ghissue:`3614`: ansi escapes broken in master (ls --color) | |
1214 | * :ghissue:`3610`: If you don't have markdown, python setup.py install says no pygments |
|
1214 | * :ghissue:`3610`: If you don't have markdown, python setup.py install says no pygments | |
1215 | * :ghissue:`3547`: %run modules clobber each other |
|
1215 | * :ghissue:`3547`: %run modules clobber each other | |
1216 | * :ghissue:`3602`: import_item fails when one tries to use DottedObjectName instead of a string |
|
1216 | * :ghissue:`3602`: import_item fails when one tries to use DottedObjectName instead of a string | |
1217 | * :ghissue:`3563`: Duplicate tab completions in the notebook |
|
1217 | * :ghissue:`3563`: Duplicate tab completions in the notebook | |
1218 | * :ghissue:`3599`: Problems trying to run IPython on python3 without installing... |
|
1218 | * :ghissue:`3599`: Problems trying to run IPython on python3 without installing... | |
1219 | * :ghissue:`2937`: too long completion in notebook |
|
1219 | * :ghissue:`2937`: too long completion in notebook | |
1220 | * :ghissue:`3479`: Write empty name for the notebooks |
|
1220 | * :ghissue:`3479`: Write empty name for the notebooks | |
1221 | * :ghissue:`3505`: nbconvert: Failure in specifying user filter |
|
1221 | * :ghissue:`3505`: nbconvert: Failure in specifying user filter | |
1222 | * :ghissue:`1537`: think a bit about namespaces |
|
1222 | * :ghissue:`1537`: think a bit about namespaces | |
1223 | * :ghissue:`3124`: Long multiline strings in Notebook |
|
1223 | * :ghissue:`3124`: Long multiline strings in Notebook | |
1224 | * :ghissue:`3464`: run -d message unclear |
|
1224 | * :ghissue:`3464`: run -d message unclear | |
1225 | * :ghissue:`2706`: IPython 0.13.1 ignoring $PYTHONSTARTUP |
|
1225 | * :ghissue:`2706`: IPython 0.13.1 ignoring $PYTHONSTARTUP | |
1226 | * :ghissue:`3587`: LaTeX escaping bug in nbconvert when exporting to HTML |
|
1226 | * :ghissue:`3587`: LaTeX escaping bug in nbconvert when exporting to HTML | |
1227 | * :ghissue:`3213`: Long running notebook died with a coredump |
|
1227 | * :ghissue:`3213`: Long running notebook died with a coredump | |
1228 | * :ghissue:`3580`: Running ipython with pypy on windows |
|
1228 | * :ghissue:`3580`: Running ipython with pypy on windows | |
1229 | * :ghissue:`3573`: custom.js not working |
|
1229 | * :ghissue:`3573`: custom.js not working | |
1230 | * :ghissue:`3544`: IPython.lib test failure on Windows |
|
1230 | * :ghissue:`3544`: IPython.lib test failure on Windows | |
1231 | * :ghissue:`3352`: Install Sphinx extensions |
|
1231 | * :ghissue:`3352`: Install Sphinx extensions | |
1232 | * :ghissue:`2971`: [notebook]user needs to press ctrl-c twice to stop notebook server should be put into terminal window |
|
1232 | * :ghissue:`2971`: [notebook]user needs to press ctrl-c twice to stop notebook server should be put into terminal window | |
1233 | * :ghissue:`2413`: ipython3 qtconsole fails to install: ipython 0.13 has no such extra feature 'qtconsole' |
|
1233 | * :ghissue:`2413`: ipython3 qtconsole fails to install: ipython 0.13 has no such extra feature 'qtconsole' | |
1234 | * :ghissue:`2618`: documentation is incorrect for install process |
|
1234 | * :ghissue:`2618`: documentation is incorrect for install process | |
1235 | * :ghissue:`2595`: mac 10.8 qtconsole export history |
|
1235 | * :ghissue:`2595`: mac 10.8 qtconsole export history | |
1236 | * :ghissue:`2586`: cannot store aliases |
|
1236 | * :ghissue:`2586`: cannot store aliases | |
1237 | * :ghissue:`2714`: ipython qtconsole print unittest messages in console instead his own window. |
|
1237 | * :ghissue:`2714`: ipython qtconsole print unittest messages in console instead his own window. | |
1238 | * :ghissue:`2669`: cython magic failing to work with openmp. |
|
1238 | * :ghissue:`2669`: cython magic failing to work with openmp. | |
1239 | * :ghissue:`3256`: Vagrant pandas instance of iPython Notebook does not respect additional plotting arguments |
|
1239 | * :ghissue:`3256`: Vagrant pandas instance of iPython Notebook does not respect additional plotting arguments | |
1240 | * :ghissue:`3010`: cython magic fail if cache dir is deleted while in session |
|
1240 | * :ghissue:`3010`: cython magic fail if cache dir is deleted while in session | |
1241 | * :ghissue:`2044`: prune unused names from parallel.error |
|
1241 | * :ghissue:`2044`: prune unused names from parallel.error | |
1242 | * :ghissue:`1145`: Online help utility broken in QtConsole |
|
1242 | * :ghissue:`1145`: Online help utility broken in QtConsole | |
1243 | * :ghissue:`3439`: Markdown links no longer open in new window (with change from pagedown to marked) |
|
1243 | * :ghissue:`3439`: Markdown links no longer open in new window (with change from pagedown to marked) | |
1244 | * :ghissue:`3476`: _margv for macros seems to be missing |
|
1244 | * :ghissue:`3476`: _margv for macros seems to be missing | |
1245 | * :ghissue:`3499`: Add reveal.js library (version 2.4.0) inside IPython |
|
1245 | * :ghissue:`3499`: Add reveal.js library (version 2.4.0) inside IPython | |
1246 | * :ghissue:`2771`: Wiki Migration to GitHub |
|
1246 | * :ghissue:`2771`: Wiki Migration to GitHub | |
1247 | * :ghissue:`2887`: ipcontroller purging some engines during connect |
|
1247 | * :ghissue:`2887`: ipcontroller purging some engines during connect | |
1248 | * :ghissue:`626`: Enable Resuming Controller |
|
1248 | * :ghissue:`626`: Enable Resuming Controller | |
1249 | * :ghissue:`2824`: Kernel restarting after message "Kernel XXXX failed to respond to heartbeat" |
|
1249 | * :ghissue:`2824`: Kernel restarting after message "Kernel XXXX failed to respond to heartbeat" | |
1250 | * :ghissue:`2823`: %%cython magic gives ImportError: dlopen(long_file_name.so, 2): image not found |
|
1250 | * :ghissue:`2823`: %%cython magic gives ImportError: dlopen(long_file_name.so, 2): image not found | |
1251 | * :ghissue:`2891`: In IPython for Python 3, system site-packages comes before user site-packages |
|
1251 | * :ghissue:`2891`: In IPython for Python 3, system site-packages comes before user site-packages | |
1252 | * :ghissue:`2928`: Add magic "watch" function (example) |
|
1252 | * :ghissue:`2928`: Add magic "watch" function (example) | |
1253 | * :ghissue:`2931`: Problem rendering pandas dataframe in Firefox for Windows |
|
1253 | * :ghissue:`2931`: Problem rendering pandas dataframe in Firefox for Windows | |
1254 | * :ghissue:`2939`: [notebook] Figure legend not shown in inline backend if ouside the box of the axes |
|
1254 | * :ghissue:`2939`: [notebook] Figure legend not shown in inline backend if ouside the box of the axes | |
1255 | * :ghissue:`2972`: [notebook] in Markdown mode, press Enter key at the end of <some http link>, the next line is indented unexpectly |
|
1255 | * :ghissue:`2972`: [notebook] in Markdown mode, press Enter key at the end of <some http link>, the next line is indented unexpectly | |
1256 | * :ghissue:`3069`: Instructions for installing IPython notebook on Windows |
|
1256 | * :ghissue:`3069`: Instructions for installing IPython notebook on Windows | |
1257 | * :ghissue:`3444`: Encoding problem: cannot use if user's name is not ascii? |
|
1257 | * :ghissue:`3444`: Encoding problem: cannot use if user's name is not ascii? | |
1258 | * :ghissue:`3335`: Reenable bracket matching |
|
1258 | * :ghissue:`3335`: Reenable bracket matching | |
1259 | * :ghissue:`3386`: Magic %paste not working in Python 3.3.2. TypeError: Type str doesn't support the buffer API |
|
1259 | * :ghissue:`3386`: Magic %paste not working in Python 3.3.2. TypeError: Type str doesn't support the buffer API | |
1260 | * :ghissue:`3543`: Exception shutting down kernel from notebook dashboard (0.13.1) |
|
1260 | * :ghissue:`3543`: Exception shutting down kernel from notebook dashboard (0.13.1) | |
1261 | * :ghissue:`3549`: Codecell size changes with selection |
|
1261 | * :ghissue:`3549`: Codecell size changes with selection | |
1262 | * :ghissue:`3445`: Adding newlines in %%latex cell |
|
1262 | * :ghissue:`3445`: Adding newlines in %%latex cell | |
1263 | * :ghissue:`3237`: [notebook] Can't close a notebook without errors |
|
1263 | * :ghissue:`3237`: [notebook] Can't close a notebook without errors | |
1264 | * :ghissue:`2916`: colon invokes auto(un)indent in markdown cells |
|
1264 | * :ghissue:`2916`: colon invokes auto(un)indent in markdown cells | |
1265 | * :ghissue:`2167`: Indent and dedent in htmlnotebook |
|
1265 | * :ghissue:`2167`: Indent and dedent in htmlnotebook | |
1266 | * :ghissue:`3545`: Notebook save button icon not clear |
|
1266 | * :ghissue:`3545`: Notebook save button icon not clear | |
1267 | * :ghissue:`3534`: nbconvert incompatible with Windows? |
|
1267 | * :ghissue:`3534`: nbconvert incompatible with Windows? | |
1268 | * :ghissue:`3489`: Update example notebook that raw_input is allowed |
|
1268 | * :ghissue:`3489`: Update example notebook that raw_input is allowed | |
1269 | * :ghissue:`3396`: Notebook checkpoint time is displayed an hour out |
|
1269 | * :ghissue:`3396`: Notebook checkpoint time is displayed an hour out | |
1270 | * :ghissue:`3261`: Empty revert to checkpoint menu if no checkpoint... |
|
1270 | * :ghissue:`3261`: Empty revert to checkpoint menu if no checkpoint... | |
1271 | * :ghissue:`2984`: "print" magic does not work in Python 3 |
|
1271 | * :ghissue:`2984`: "print" magic does not work in Python 3 | |
1272 | * :ghissue:`3524`: Issues with pyzmq and ipython on EPD update |
|
1272 | * :ghissue:`3524`: Issues with pyzmq and ipython on EPD update | |
1273 | * :ghissue:`2434`: %store magic not auto-restoring |
|
1273 | * :ghissue:`2434`: %store magic not auto-restoring | |
1274 | * :ghissue:`2720`: base_url and static path |
|
1274 | * :ghissue:`2720`: base_url and static path | |
1275 | * :ghissue:`2234`: Update various low resolution graphics for retina displays |
|
1275 | * :ghissue:`2234`: Update various low resolution graphics for retina displays | |
1276 | * :ghissue:`2842`: Remember passwords for pw-protected notebooks |
|
1276 | * :ghissue:`2842`: Remember passwords for pw-protected notebooks | |
1277 | * :ghissue:`3244`: qtconsole: ValueError('close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr',) |
|
1277 | * :ghissue:`3244`: qtconsole: ValueError('close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr',) | |
1278 | * :ghissue:`2215`: AsyncResult.wait(0) can hang waiting for the client to get results? |
|
1278 | * :ghissue:`2215`: AsyncResult.wait(0) can hang waiting for the client to get results? | |
1279 | * :ghissue:`2268`: provide mean to retrieve static data path |
|
1279 | * :ghissue:`2268`: provide mean to retrieve static data path | |
1280 | * :ghissue:`1905`: Expose UI for worksheets within each notebook |
|
1280 | * :ghissue:`1905`: Expose UI for worksheets within each notebook | |
1281 | * :ghissue:`2380`: Qt inputhook prevents modal dialog boxes from displaying |
|
1281 | * :ghissue:`2380`: Qt inputhook prevents modal dialog boxes from displaying | |
1282 | * :ghissue:`3185`: prettify on double // |
|
1282 | * :ghissue:`3185`: prettify on double // | |
1283 | * :ghissue:`2821`: Test failure: IPython.parallel.tests.test_client.test_resubmit_header |
|
1283 | * :ghissue:`2821`: Test failure: IPython.parallel.tests.test_client.test_resubmit_header | |
1284 | * :ghissue:`2475`: [Notebook] Line is deindented when typing eg a colon in markdown mode |
|
1284 | * :ghissue:`2475`: [Notebook] Line is deindented when typing eg a colon in markdown mode | |
1285 | * :ghissue:`2470`: Do not destroy valid notebooks |
|
1285 | * :ghissue:`2470`: Do not destroy valid notebooks | |
1286 | * :ghissue:`860`: Allow the standalone export of a notebook to HTML |
|
1286 | * :ghissue:`860`: Allow the standalone export of a notebook to HTML | |
1287 | * :ghissue:`2652`: notebook with qt backend crashes at save image location popup |
|
1287 | * :ghissue:`2652`: notebook with qt backend crashes at save image location popup | |
1288 | * :ghissue:`1587`: Improve kernel restarting in the notebook |
|
1288 | * :ghissue:`1587`: Improve kernel restarting in the notebook | |
1289 | * :ghissue:`2710`: Saving a plot in Mac OS X backend crashes IPython |
|
1289 | * :ghissue:`2710`: Saving a plot in Mac OS X backend crashes IPython | |
1290 | * :ghissue:`2596`: notebook "Last saved:" is misleading on file opening. |
|
1290 | * :ghissue:`2596`: notebook "Last saved:" is misleading on file opening. | |
1291 | * :ghissue:`2671`: TypeError :NoneType when executed "ipython qtconsole" in windows console |
|
1291 | * :ghissue:`2671`: TypeError :NoneType when executed "ipython qtconsole" in windows console | |
1292 | * :ghissue:`2703`: Notebook scrolling breaks after pager is shown |
|
1292 | * :ghissue:`2703`: Notebook scrolling breaks after pager is shown | |
1293 | * :ghissue:`2803`: KernelManager and KernelClient should be two separate objects |
|
1293 | * :ghissue:`2803`: KernelManager and KernelClient should be two separate objects | |
1294 | * :ghissue:`2693`: TerminalIPythonApp configuration fails without ipython_config.py |
|
1294 | * :ghissue:`2693`: TerminalIPythonApp configuration fails without ipython_config.py | |
1295 | * :ghissue:`2531`: IPython 0.13.1 python 2 32-bit installer includes 64-bit ipython*.exe launchers in the scripts folder |
|
1295 | * :ghissue:`2531`: IPython 0.13.1 python 2 32-bit installer includes 64-bit ipython*.exe launchers in the scripts folder | |
1296 | * :ghissue:`2520`: Control-C kills port forwarding |
|
1296 | * :ghissue:`2520`: Control-C kills port forwarding | |
1297 | * :ghissue:`2279`: Setting `__file__` to None breaks Mayavi import |
|
1297 | * :ghissue:`2279`: Setting `__file__` to None breaks Mayavi import | |
1298 | * :ghissue:`2161`: When logged into notebook, long titles are incorrectly positioned |
|
1298 | * :ghissue:`2161`: When logged into notebook, long titles are incorrectly positioned | |
1299 | * :ghissue:`1292`: Notebook, Print view should not be editable... |
|
1299 | * :ghissue:`1292`: Notebook, Print view should not be editable... | |
1300 | * :ghissue:`1731`: test parallel launchers |
|
1300 | * :ghissue:`1731`: test parallel launchers | |
1301 | * :ghissue:`3227`: Improve documentation of ipcontroller and possible BUG |
|
1301 | * :ghissue:`3227`: Improve documentation of ipcontroller and possible BUG | |
1302 | * :ghissue:`2896`: IPController very unstable |
|
1302 | * :ghissue:`2896`: IPController very unstable | |
1303 | * :ghissue:`3517`: documentation build broken in head |
|
1303 | * :ghissue:`3517`: documentation build broken in head | |
1304 | * :ghissue:`3522`: UnicodeDecodeError: 'ascii' codec can't decode byte on Pycharm on Windows |
|
1304 | * :ghissue:`3522`: UnicodeDecodeError: 'ascii' codec can't decode byte on Pycharm on Windows | |
1305 | * :ghissue:`3448`: Please include MathJax fonts with IPython Notebook |
|
1305 | * :ghissue:`3448`: Please include MathJax fonts with IPython Notebook | |
1306 | * :ghissue:`3519`: IPython Parallel map mysteriously turns pandas Series into numpy ndarray |
|
1306 | * :ghissue:`3519`: IPython Parallel map mysteriously turns pandas Series into numpy ndarray | |
1307 | * :ghissue:`3345`: IPython embedded shells ask if I want to exit, but I set confirm_exit = False |
|
1307 | * :ghissue:`3345`: IPython embedded shells ask if I want to exit, but I set confirm_exit = False | |
1308 | * :ghissue:`3509`: IPython won't close without asking "Are you sure?" in Firefox |
|
1308 | * :ghissue:`3509`: IPython won't close without asking "Are you sure?" in Firefox | |
1309 | * :ghissue:`3471`: Notebook jinja2/markupsafe depedencies in manual |
|
1309 | * :ghissue:`3471`: Notebook jinja2/markupsafe depedencies in manual | |
1310 | * :ghissue:`3502`: Notebook broken in master |
|
1310 | * :ghissue:`3502`: Notebook broken in master | |
1311 | * :ghissue:`3302`: autoreload does not work in ipython 0.13.x, python 3.3 |
|
1311 | * :ghissue:`3302`: autoreload does not work in ipython 0.13.x, python 3.3 | |
1312 | * :ghissue:`3475`: no warning when leaving/closing notebook on master without saved changes |
|
1312 | * :ghissue:`3475`: no warning when leaving/closing notebook on master without saved changes | |
1313 | * :ghissue:`3490`: No obvious feedback when kernel crashes |
|
1313 | * :ghissue:`3490`: No obvious feedback when kernel crashes | |
1314 | * :ghissue:`1912`: Move all autoreload tests to their own group |
|
1314 | * :ghissue:`1912`: Move all autoreload tests to their own group | |
1315 | * :ghissue:`2577`: sh.py and ipython for python 3.3 |
|
1315 | * :ghissue:`2577`: sh.py and ipython for python 3.3 | |
1316 | * :ghissue:`3467`: %magic doesn't work |
|
1316 | * :ghissue:`3467`: %magic doesn't work | |
1317 | * :ghissue:`3501`: Editing markdown cells that wrap has off-by-one errors in cursor positioning |
|
1317 | * :ghissue:`3501`: Editing markdown cells that wrap has off-by-one errors in cursor positioning | |
1318 | * :ghissue:`3492`: IPython for Python3 |
|
1318 | * :ghissue:`3492`: IPython for Python3 | |
1319 | * :ghissue:`3474`: unexpected keyword argument to remove_kernel |
|
1319 | * :ghissue:`3474`: unexpected keyword argument to remove_kernel | |
1320 | * :ghissue:`2283`: TypeError when using '?' after a string in a %logstart session |
|
1320 | * :ghissue:`2283`: TypeError when using '?' after a string in a %logstart session | |
1321 | * :ghissue:`2787`: rmagic and pandas DataFrame |
|
1321 | * :ghissue:`2787`: rmagic and pandas DataFrame | |
1322 | * :ghissue:`2605`: Ellipsis literal triggers AttributeError |
|
1322 | * :ghissue:`2605`: Ellipsis literal triggers AttributeError | |
1323 | * :ghissue:`1179`: Test unicode source in pinfo |
|
1323 | * :ghissue:`1179`: Test unicode source in pinfo | |
1324 | * :ghissue:`2055`: drop Python 3.1 support |
|
1324 | * :ghissue:`2055`: drop Python 3.1 support | |
1325 | * :ghissue:`2293`: IPEP 2: Input transformations |
|
1325 | * :ghissue:`2293`: IPEP 2: Input transformations | |
1326 | * :ghissue:`2790`: %paste and %cpaste not removing "..." lines |
|
1326 | * :ghissue:`2790`: %paste and %cpaste not removing "..." lines | |
1327 | * :ghissue:`3480`: Testing fails because iptest.py cannot be found |
|
1327 | * :ghissue:`3480`: Testing fails because iptest.py cannot be found | |
1328 | * :ghissue:`2580`: will not run within PIL build directory |
|
1328 | * :ghissue:`2580`: will not run within PIL build directory | |
1329 | * :ghissue:`2797`: RMagic, Dataframe Conversion Problem |
|
1329 | * :ghissue:`2797`: RMagic, Dataframe Conversion Problem | |
1330 | * :ghissue:`2838`: Empty lines disappear from triple-quoted literals. |
|
1330 | * :ghissue:`2838`: Empty lines disappear from triple-quoted literals. | |
1331 | * :ghissue:`3050`: Broken link on IPython.core.display page |
|
1331 | * :ghissue:`3050`: Broken link on IPython.core.display page | |
1332 | * :ghissue:`3473`: Config not passed down to subcommands |
|
1332 | * :ghissue:`3473`: Config not passed down to subcommands | |
1333 | * :ghissue:`3462`: Setting log_format in config file results in error (and no format changes) |
|
1333 | * :ghissue:`3462`: Setting log_format in config file results in error (and no format changes) | |
1334 | * :ghissue:`3311`: Notebook (occasionally) not working on windows (Sophos AV) |
|
1334 | * :ghissue:`3311`: Notebook (occasionally) not working on windows (Sophos AV) | |
1335 | * :ghissue:`3461`: Cursor positioning off by a character in auto-wrapped lines |
|
1335 | * :ghissue:`3461`: Cursor positioning off by a character in auto-wrapped lines | |
1336 | * :ghissue:`3454`: _repr_html_ error |
|
1336 | * :ghissue:`3454`: _repr_html_ error | |
1337 | * :ghissue:`3457`: Space in long Paragraph Markdown cell with Chinese or Japanese |
|
1337 | * :ghissue:`3457`: Space in long Paragraph Markdown cell with Chinese or Japanese | |
1338 | * :ghissue:`3447`: Run Cell Does not Work |
|
1338 | * :ghissue:`3447`: Run Cell Does not Work | |
1339 | * :ghissue:`1373`: Last lines in long cells are hidden |
|
1339 | * :ghissue:`1373`: Last lines in long cells are hidden | |
1340 | * :ghissue:`1504`: Revisit serialization in IPython.parallel |
|
1340 | * :ghissue:`1504`: Revisit serialization in IPython.parallel | |
1341 | * :ghissue:`1459`: Can't connect to 2 HTTPS notebook servers on the same host |
|
1341 | * :ghissue:`1459`: Can't connect to 2 HTTPS notebook servers on the same host | |
1342 | * :ghissue:`678`: Input prompt stripping broken with multiline data structures |
|
1342 | * :ghissue:`678`: Input prompt stripping broken with multiline data structures | |
1343 | * :ghissue:`3001`: IPython.notebook.dirty flag is not set when a cell has unsaved changes |
|
1343 | * :ghissue:`3001`: IPython.notebook.dirty flag is not set when a cell has unsaved changes | |
1344 | * :ghissue:`3077`: Multiprocessing semantics in parallel.view.map |
|
1344 | * :ghissue:`3077`: Multiprocessing semantics in parallel.view.map | |
1345 | * :ghissue:`3056`: links across notebooks |
|
1345 | * :ghissue:`3056`: links across notebooks | |
1346 | * :ghissue:`3120`: Tornado 3.0 |
|
1346 | * :ghissue:`3120`: Tornado 3.0 | |
1347 | * :ghissue:`3156`: update pretty to use Python 3 style for sets |
|
1347 | * :ghissue:`3156`: update pretty to use Python 3 style for sets | |
1348 | * :ghissue:`3197`: Can't escape multiple dollar signs in a markdown cell |
|
1348 | * :ghissue:`3197`: Can't escape multiple dollar signs in a markdown cell | |
1349 | * :ghissue:`3309`: `Image()` signature/doc improvements |
|
1349 | * :ghissue:`3309`: `Image()` signature/doc improvements | |
1350 | * :ghissue:`3415`: Bug in IPython/external/path/__init__.py |
|
1350 | * :ghissue:`3415`: Bug in IPython/external/path/__init__.py | |
1351 | * :ghissue:`3446`: Feature suggestion: Download matplotlib figure to client browser |
|
1351 | * :ghissue:`3446`: Feature suggestion: Download matplotlib figure to client browser | |
1352 | * :ghissue:`3295`: autoexported notebooks: only export explicitly marked cells |
|
1352 | * :ghissue:`3295`: autoexported notebooks: only export explicitly marked cells | |
1353 | * :ghissue:`3442`: Notebook: Summary table extracted from markdown headers |
|
1353 | * :ghissue:`3442`: Notebook: Summary table extracted from markdown headers | |
1354 | * :ghissue:`3438`: Zooming notebook in chrome is broken in master |
|
1354 | * :ghissue:`3438`: Zooming notebook in chrome is broken in master | |
1355 | * :ghissue:`1378`: Implement autosave in notebook |
|
1355 | * :ghissue:`1378`: Implement autosave in notebook | |
1356 | * :ghissue:`3437`: Highlighting matching parentheses |
|
1356 | * :ghissue:`3437`: Highlighting matching parentheses | |
1357 | * :ghissue:`3435`: module search segfault |
|
1357 | * :ghissue:`3435`: module search segfault | |
1358 | * :ghissue:`3424`: ipcluster --version |
|
1358 | * :ghissue:`3424`: ipcluster --version | |
1359 | * :ghissue:`3434`: 0.13.2 Ipython/genutils.py doesn't exist |
|
1359 | * :ghissue:`3434`: 0.13.2 Ipython/genutils.py doesn't exist | |
1360 | * :ghissue:`3426`: Feature request: Save by cell and not by line #: IPython %save magic |
|
1360 | * :ghissue:`3426`: Feature request: Save by cell and not by line #: IPython %save magic | |
1361 | * :ghissue:`3412`: Non Responsive Kernel: Running a Django development server from an IPython Notebook |
|
1361 | * :ghissue:`3412`: Non Responsive Kernel: Running a Django development server from an IPython Notebook | |
1362 | * :ghissue:`3408`: Save cell toolbar and slide type metadata in notebooks |
|
1362 | * :ghissue:`3408`: Save cell toolbar and slide type metadata in notebooks | |
1363 | * :ghissue:`3246`: %paste regression with blank lines |
|
1363 | * :ghissue:`3246`: %paste regression with blank lines | |
1364 | * :ghissue:`3404`: Weird error with $variable and grep in command line magic (!command) |
|
1364 | * :ghissue:`3404`: Weird error with $variable and grep in command line magic (!command) | |
1365 | * :ghissue:`3405`: Key auto-completion in dictionaries? |
|
1365 | * :ghissue:`3405`: Key auto-completion in dictionaries? | |
1366 | * :ghissue:`3259`: Codemirror linenumber css broken |
|
1366 | * :ghissue:`3259`: Codemirror linenumber css broken | |
1367 | * :ghissue:`3397`: Vertical text misalignment in Markdown cells |
|
1367 | * :ghissue:`3397`: Vertical text misalignment in Markdown cells | |
1368 | * :ghissue:`3391`: Revert #3358 once fix integrated into CM |
|
1368 | * :ghissue:`3391`: Revert #3358 once fix integrated into CM | |
1369 | * :ghissue:`3360`: Error 500 while saving IPython notebook |
|
1369 | * :ghissue:`3360`: Error 500 while saving IPython notebook | |
1370 | * :ghissue:`3375`: Frequent Safari/Webkit crashes |
|
1370 | * :ghissue:`3375`: Frequent Safari/Webkit crashes | |
1371 | * :ghissue:`3365`: zmq frontend |
|
1371 | * :ghissue:`3365`: zmq frontend | |
1372 | * :ghissue:`2654`: User_expression issues |
|
1372 | * :ghissue:`2654`: User_expression issues | |
1373 | * :ghissue:`3389`: Store history as plain text |
|
1373 | * :ghissue:`3389`: Store history as plain text | |
1374 | * :ghissue:`3388`: Ipython parallel: open TCP connection created for each result returned from engine |
|
1374 | * :ghissue:`3388`: Ipython parallel: open TCP connection created for each result returned from engine | |
1375 | * :ghissue:`3385`: setup.py failure on Python 3 |
|
1375 | * :ghissue:`3385`: setup.py failure on Python 3 | |
1376 | * :ghissue:`3376`: Setting `__module__` to None breaks pretty printing |
|
1376 | * :ghissue:`3376`: Setting `__module__` to None breaks pretty printing | |
1377 | * :ghissue:`3374`: ipython qtconsole does not display the prompt on OSX |
|
1377 | * :ghissue:`3374`: ipython qtconsole does not display the prompt on OSX | |
1378 | * :ghissue:`3380`: simple call to kernel |
|
1378 | * :ghissue:`3380`: simple call to kernel | |
1379 | * :ghissue:`3379`: TaskRecord key 'started' not set |
|
1379 | * :ghissue:`3379`: TaskRecord key 'started' not set | |
1380 | * :ghissue:`3241`: notebook conection time out |
|
1380 | * :ghissue:`3241`: notebook conection time out | |
1381 | * :ghissue:`3334`: magic interpreter interpretes non magic commands? |
|
1381 | * :ghissue:`3334`: magic interpreter interpretes non magic commands? | |
1382 | * :ghissue:`3326`: python3.3: Type error when launching SGE cluster in IPython notebook |
|
1382 | * :ghissue:`3326`: python3.3: Type error when launching SGE cluster in IPython notebook | |
1383 | * :ghissue:`3349`: pip3 doesn't run 2to3? |
|
1383 | * :ghissue:`3349`: pip3 doesn't run 2to3? | |
1384 | * :ghissue:`3347`: Longlist support in ipdb |
|
1384 | * :ghissue:`3347`: Longlist support in ipdb | |
1385 | * :ghissue:`3343`: Make pip install / easy_install faster |
|
1385 | * :ghissue:`3343`: Make pip install / easy_install faster | |
1386 | * :ghissue:`3337`: git submodules broke nightly PPA builds |
|
1386 | * :ghissue:`3337`: git submodules broke nightly PPA builds | |
1387 | * :ghissue:`3206`: Copy/Paste Regression in QtConsole |
|
1387 | * :ghissue:`3206`: Copy/Paste Regression in QtConsole | |
1388 | * :ghissue:`3329`: Buggy linewrap in Mac OSX Terminal (Mountain Lion) |
|
1388 | * :ghissue:`3329`: Buggy linewrap in Mac OSX Terminal (Mountain Lion) | |
1389 | * :ghissue:`3327`: Qt version check broken |
|
1389 | * :ghissue:`3327`: Qt version check broken | |
1390 | * :ghissue:`3303`: parallel tasks never finish under heavy load |
|
1390 | * :ghissue:`3303`: parallel tasks never finish under heavy load | |
1391 | * :ghissue:`1381`: '\\' for equation continuations require an extra '\' in markdown cells |
|
1391 | * :ghissue:`1381`: '\\' for equation continuations require an extra '\' in markdown cells | |
1392 | * :ghissue:`3314`: Error launching iPython |
|
1392 | * :ghissue:`3314`: Error launching iPython | |
1393 | * :ghissue:`3306`: Test failure when running on a Vagrant VM |
|
1393 | * :ghissue:`3306`: Test failure when running on a Vagrant VM | |
1394 | * :ghissue:`3280`: IPython.utils.process.getoutput returns stderr |
|
1394 | * :ghissue:`3280`: IPython.utils.process.getoutput returns stderr | |
1395 | * :ghissue:`3299`: variables named _ or __ exhibit incorrect behavior |
|
1395 | * :ghissue:`3299`: variables named _ or __ exhibit incorrect behavior | |
1396 | * :ghissue:`3196`: add an "x" or similar to htmlnotebook pager |
|
1396 | * :ghissue:`3196`: add an "x" or similar to htmlnotebook pager | |
1397 | * :ghissue:`3293`: Several 404 errors for js files Firefox |
|
1397 | * :ghissue:`3293`: Several 404 errors for js files Firefox | |
1398 | * :ghissue:`3292`: syntax highlighting in chrome on OSX 10.8.3 |
|
1398 | * :ghissue:`3292`: syntax highlighting in chrome on OSX 10.8.3 | |
1399 | * :ghissue:`3288`: Latest dev version hangs on page load |
|
1399 | * :ghissue:`3288`: Latest dev version hangs on page load | |
1400 | * :ghissue:`3283`: ipython dev retains directory information after directory change |
|
1400 | * :ghissue:`3283`: ipython dev retains directory information after directory change | |
1401 | * :ghissue:`3279`: custom.css is not overridden in the dev IPython (1.0) |
|
1401 | * :ghissue:`3279`: custom.css is not overridden in the dev IPython (1.0) | |
1402 | * :ghissue:`2727`: %run -m doesn't support relative imports |
|
1402 | * :ghissue:`2727`: %run -m doesn't support relative imports | |
1403 | * :ghissue:`3268`: GFM triple backquote and unknown language |
|
1403 | * :ghissue:`3268`: GFM triple backquote and unknown language | |
1404 | * :ghissue:`3273`: Suppressing all plot related outputs |
|
1404 | * :ghissue:`3273`: Suppressing all plot related outputs | |
1405 | * :ghissue:`3272`: Backspace while completing load previous page |
|
1405 | * :ghissue:`3272`: Backspace while completing load previous page | |
1406 | * :ghissue:`3260`: Js error in savewidget |
|
1406 | * :ghissue:`3260`: Js error in savewidget | |
1407 | * :ghissue:`3247`: scrollbar in notebook when not needed? |
|
1407 | * :ghissue:`3247`: scrollbar in notebook when not needed? | |
1408 | * :ghissue:`3243`: notebook: option to view json source from browser |
|
1408 | * :ghissue:`3243`: notebook: option to view json source from browser | |
1409 | * :ghissue:`3265`: 404 errors when running IPython 1.0dev |
|
1409 | * :ghissue:`3265`: 404 errors when running IPython 1.0dev | |
1410 | * :ghissue:`3257`: setup.py not finding submodules |
|
1410 | * :ghissue:`3257`: setup.py not finding submodules | |
1411 | * :ghissue:`3253`: Incorrect Qt and PySide version comparison |
|
1411 | * :ghissue:`3253`: Incorrect Qt and PySide version comparison | |
1412 | * :ghissue:`3248`: Cell magics broken in Qt console |
|
1412 | * :ghissue:`3248`: Cell magics broken in Qt console | |
1413 | * :ghissue:`3012`: Problems with the less based style.min.css |
|
1413 | * :ghissue:`3012`: Problems with the less based style.min.css | |
1414 | * :ghissue:`2390`: Image width/height don't work in embedded images |
|
1414 | * :ghissue:`2390`: Image width/height don't work in embedded images | |
1415 | * :ghissue:`3236`: cannot set TerminalIPythonApp.log_format |
|
1415 | * :ghissue:`3236`: cannot set TerminalIPythonApp.log_format | |
1416 | * :ghissue:`3214`: notebook kernel dies if started with invalid parameter |
|
1416 | * :ghissue:`3214`: notebook kernel dies if started with invalid parameter | |
1417 | * :ghissue:`2980`: Remove HTMLCell ? |
|
1417 | * :ghissue:`2980`: Remove HTMLCell ? | |
1418 | * :ghissue:`3128`: qtconsole hangs on importing pylab (using X forwarding) |
|
1418 | * :ghissue:`3128`: qtconsole hangs on importing pylab (using X forwarding) | |
1419 | * :ghissue:`3198`: Hitting recursive depth causing all notebook pages to hang |
|
1419 | * :ghissue:`3198`: Hitting recursive depth causing all notebook pages to hang | |
1420 | * :ghissue:`3218`: race conditions in profile directory creation |
|
1420 | * :ghissue:`3218`: race conditions in profile directory creation | |
1421 | * :ghissue:`3177`: OverflowError execption in handlers.py |
|
1421 | * :ghissue:`3177`: OverflowError execption in handlers.py | |
1422 | * :ghissue:`2563`: core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation |
|
1422 | * :ghissue:`2563`: core.profiledir.check_startup_dir() doesn't work inside py2exe'd installation | |
1423 | * :ghissue:`3207`: [Feature] folders for ipython notebook dashboard |
|
1423 | * :ghissue:`3207`: [Feature] folders for ipython notebook dashboard | |
1424 | * :ghissue:`3178`: cell magics do not work with empty lines after #2447 |
|
1424 | * :ghissue:`3178`: cell magics do not work with empty lines after #2447 | |
1425 | * :ghissue:`3204`: Default plot() colors unsuitable for red-green colorblind users |
|
1425 | * :ghissue:`3204`: Default plot() colors unsuitable for red-green colorblind users | |
1426 | * :ghissue:`1789`: :\n/*foo turns into :\n*(foo) in triple-quoted strings. |
|
1426 | * :ghissue:`1789`: ``:\n/*foo`` turns into ``:\n*(foo)`` in triple-quoted strings. | |
1427 | * :ghissue:`3202`: File cell magic fails with blank lines |
|
1427 | * :ghissue:`3202`: File cell magic fails with blank lines | |
1428 | * :ghissue:`3199`: %%cython -a stopped working? |
|
1428 | * :ghissue:`3199`: %%cython -a stopped working? | |
1429 | * :ghissue:`2688`: obsolete imports in import autocompletion |
|
1429 | * :ghissue:`2688`: obsolete imports in import autocompletion | |
1430 | * :ghissue:`3192`: Python2, Unhandled exception, __builtin__.True = False |
|
1430 | * :ghissue:`3192`: Python2, Unhandled exception, __builtin__.True = False | |
1431 | * :ghissue:`3179`: script magic error message loop |
|
1431 | * :ghissue:`3179`: script magic error message loop | |
1432 | * :ghissue:`3009`: use XDG_CACHE_HOME for cython objects |
|
1432 | * :ghissue:`3009`: use XDG_CACHE_HOME for cython objects | |
1433 | * :ghissue:`3059`: Bugs in 00_notebook_tour example. |
|
1433 | * :ghissue:`3059`: Bugs in 00_notebook_tour example. | |
1434 | * :ghissue:`3104`: Integrate a javascript file manager into the notebook front end |
|
1434 | * :ghissue:`3104`: Integrate a javascript file manager into the notebook front end | |
1435 | * :ghissue:`3176`: Particular equation not rendering (notebook) |
|
1435 | * :ghissue:`3176`: Particular equation not rendering (notebook) | |
1436 | * :ghissue:`1133`: [notebook] readonly and upload files/UI |
|
1436 | * :ghissue:`1133`: [notebook] readonly and upload files/UI | |
1437 | * :ghissue:`2975`: [notebook] python file and cell toolbar |
|
1437 | * :ghissue:`2975`: [notebook] python file and cell toolbar | |
1438 | * :ghissue:`3017`: SciPy.weave broken in IPython notebook/ qtconsole |
|
1438 | * :ghissue:`3017`: SciPy.weave broken in IPython notebook/ qtconsole | |
1439 | * :ghissue:`3161`: paste macro not reading spaces correctly |
|
1439 | * :ghissue:`3161`: paste macro not reading spaces correctly | |
1440 | * :ghissue:`2835`: %paste not working on WinXpSP3/ipython-0.13.1.py2-win32-PROPER.exe/python27 |
|
1440 | * :ghissue:`2835`: %paste not working on WinXpSP3/ipython-0.13.1.py2-win32-PROPER.exe/python27 | |
1441 | * :ghissue:`2628`: Make transformers work for lines following decorators |
|
1441 | * :ghissue:`2628`: Make transformers work for lines following decorators | |
1442 | * :ghissue:`2612`: Multiline String containing ":\n?foo\n" confuses interpreter to replace ?foo with get_ipython().magic(u'pinfo foo') |
|
1442 | * :ghissue:`2612`: Multiline String containing ":\n?foo\n" confuses interpreter to replace ?foo with get_ipython().magic(u'pinfo foo') | |
1443 | * :ghissue:`2539`: Request: Enable cell magics inside of .ipy scripts |
|
1443 | * :ghissue:`2539`: Request: Enable cell magics inside of .ipy scripts | |
1444 | * :ghissue:`2507`: Multiline string does not work (includes `...`) with doctest type input in IPython notebook |
|
1444 | * :ghissue:`2507`: Multiline string does not work (includes `...`) with doctest type input in IPython notebook | |
1445 | * :ghissue:`2164`: Request: Line breaks in line magic command |
|
1445 | * :ghissue:`2164`: Request: Line breaks in line magic command | |
1446 | * :ghissue:`3106`: poor parallel performance with many jobs |
|
1446 | * :ghissue:`3106`: poor parallel performance with many jobs | |
1447 | * :ghissue:`2438`: print inside multiprocessing crashes Ipython kernel |
|
1447 | * :ghissue:`2438`: print inside multiprocessing crashes Ipython kernel | |
1448 | * :ghissue:`3155`: Bad md5 hash for package 0.13.2 |
|
1448 | * :ghissue:`3155`: Bad md5 hash for package 0.13.2 | |
1449 | * :ghissue:`3045`: [Notebook] Ipython Kernel does not start if disconnected from internet(/network?) |
|
1449 | * :ghissue:`3045`: [Notebook] Ipython Kernel does not start if disconnected from internet(/network?) | |
1450 | * :ghissue:`3146`: Using celery in python 3.3 |
|
1450 | * :ghissue:`3146`: Using celery in python 3.3 | |
1451 | * :ghissue:`3145`: The notebook viewer is down |
|
1451 | * :ghissue:`3145`: The notebook viewer is down | |
1452 | * :ghissue:`2385`: grep --color not working well with notebook |
|
1452 | * :ghissue:`2385`: grep --color not working well with notebook | |
1453 | * :ghissue:`3131`: Quickly install from source in a clean virtualenv? |
|
1453 | * :ghissue:`3131`: Quickly install from source in a clean virtualenv? | |
1454 | * :ghissue:`3139`: Rolling log for ipython |
|
1454 | * :ghissue:`3139`: Rolling log for ipython | |
1455 | * :ghissue:`3127`: notebook with pylab=inline appears to call figure.draw twice |
|
1455 | * :ghissue:`3127`: notebook with pylab=inline appears to call figure.draw twice | |
1456 | * :ghissue:`3129`: Walking up and down the call stack |
|
1456 | * :ghissue:`3129`: Walking up and down the call stack | |
1457 | * :ghissue:`3123`: Notebook crashed if unplugged ethernet cable |
|
1457 | * :ghissue:`3123`: Notebook crashed if unplugged ethernet cable | |
1458 | * :ghissue:`3121`: NB should use normalize.css? was #3049 |
|
1458 | * :ghissue:`3121`: NB should use normalize.css? was #3049 | |
1459 | * :ghissue:`3087`: Disable spellchecking in notebook |
|
1459 | * :ghissue:`3087`: Disable spellchecking in notebook | |
1460 | * :ghissue:`3084`: ipython pyqt 4.10 incompatibilty, QTextBlockUserData |
|
1460 | * :ghissue:`3084`: ipython pyqt 4.10 incompatibilty, QTextBlockUserData | |
1461 | * :ghissue:`3113`: Fails to install under Jython 2.7 beta |
|
1461 | * :ghissue:`3113`: Fails to install under Jython 2.7 beta | |
1462 | * :ghissue:`3110`: Render of h4 headers is not correct in notebook (error in renderedhtml.css) |
|
1462 | * :ghissue:`3110`: Render of h4 headers is not correct in notebook (error in renderedhtml.css) | |
1463 | * :ghissue:`3109`: BUG: read_csv: dtype={'id' : np.str}: Datatype not understood |
|
1463 | * :ghissue:`3109`: BUG: read_csv: dtype={'id' : np.str}: Datatype not understood | |
1464 | * :ghissue:`3107`: Autocompletion of object attributes in arrays |
|
1464 | * :ghissue:`3107`: Autocompletion of object attributes in arrays | |
1465 | * :ghissue:`3103`: Reset locale setting in qtconsole |
|
1465 | * :ghissue:`3103`: Reset locale setting in qtconsole | |
1466 | * :ghissue:`3090`: python3.3 Entry Point not found |
|
1466 | * :ghissue:`3090`: python3.3 Entry Point not found | |
1467 | * :ghissue:`3081`: UnicodeDecodeError when using Image(data="some.jpeg") |
|
1467 | * :ghissue:`3081`: UnicodeDecodeError when using Image(data="some.jpeg") | |
1468 | * :ghissue:`2834`: url regexp only finds one link |
|
1468 | * :ghissue:`2834`: url regexp only finds one link | |
1469 | * :ghissue:`3091`: qtconsole breaks doctest.testmod() in Python 3.3 |
|
1469 | * :ghissue:`3091`: qtconsole breaks doctest.testmod() in Python 3.3 | |
1470 | * :ghissue:`3074`: SIGUSR1 not available on Windows |
|
1470 | * :ghissue:`3074`: SIGUSR1 not available on Windows | |
1471 | * :ghissue:`2996`: registration::purging stalled registration high occurrence in small clusters |
|
1471 | * :ghissue:`2996`: registration::purging stalled registration high occurrence in small clusters | |
1472 | * :ghissue:`3065`: diff-ability of notebooks |
|
1472 | * :ghissue:`3065`: diff-ability of notebooks | |
1473 | * :ghissue:`3067`: Crash with pygit2 |
|
1473 | * :ghissue:`3067`: Crash with pygit2 | |
1474 | * :ghissue:`3061`: Bug handling Ellipsis |
|
1474 | * :ghissue:`3061`: Bug handling Ellipsis | |
1475 | * :ghissue:`3049`: NB css inconsistent behavior between ff and webkit |
|
1475 | * :ghissue:`3049`: NB css inconsistent behavior between ff and webkit | |
1476 | * :ghissue:`3039`: unicode errors when opening a new notebook |
|
1476 | * :ghissue:`3039`: unicode errors when opening a new notebook | |
1477 | * :ghissue:`3048`: Installning ipython qtConsole should be easyer att Windows |
|
1477 | * :ghissue:`3048`: Installning ipython qtConsole should be easyer att Windows | |
1478 | * :ghissue:`3042`: Profile creation fails on 0.13.2 branch |
|
1478 | * :ghissue:`3042`: Profile creation fails on 0.13.2 branch | |
1479 | * :ghissue:`3035`: docstring typo/inconsistency: mention of an xml notebook format? |
|
1479 | * :ghissue:`3035`: docstring typo/inconsistency: mention of an xml notebook format? | |
1480 | * :ghissue:`3031`: HDF5 library segfault (possibly due to mismatching headers?) |
|
1480 | * :ghissue:`3031`: HDF5 library segfault (possibly due to mismatching headers?) | |
1481 | * :ghissue:`2991`: In notebook importing sympy closes ipython kernel |
|
1481 | * :ghissue:`2991`: In notebook importing sympy closes ipython kernel | |
1482 | * :ghissue:`3027`: f.__globals__ causes an error in Python 3.3 |
|
1482 | * :ghissue:`3027`: f.__globals__ causes an error in Python 3.3 | |
1483 | * :ghissue:`3020`: Failing test test_interactiveshell.TestAstTransform on Windows |
|
1483 | * :ghissue:`3020`: Failing test test_interactiveshell.TestAstTransform on Windows | |
1484 | * :ghissue:`3023`: alt text for "click to expand output" has typo in alt text |
|
1484 | * :ghissue:`3023`: alt text for "click to expand output" has typo in alt text | |
1485 | * :ghissue:`2963`: %history to print all input history of a previous session when line range is omitted |
|
1485 | * :ghissue:`2963`: %history to print all input history of a previous session when line range is omitted | |
1486 | * :ghissue:`3018`: IPython installed within virtualenv. WARNING "Please install IPython inside the virtualtenv" |
|
1486 | * :ghissue:`3018`: IPython installed within virtualenv. WARNING "Please install IPython inside the virtualtenv" | |
1487 | * :ghissue:`2484`: Completion in Emacs *Python* buffer causes prompt to be increased. |
|
1487 | * :ghissue:`2484`: Completion in Emacs *Python* buffer causes prompt to be increased. | |
1488 | * :ghissue:`3014`: Ctrl-C finishes notebook immediately |
|
1488 | * :ghissue:`3014`: Ctrl-C finishes notebook immediately | |
1489 | * :ghissue:`3007`: cython_pyximport reload broken in python3 |
|
1489 | * :ghissue:`3007`: cython_pyximport reload broken in python3 | |
1490 | * :ghissue:`2955`: Incompatible Qt imports when running inprocess_qtconsole |
|
1490 | * :ghissue:`2955`: Incompatible Qt imports when running inprocess_qtconsole | |
1491 | * :ghissue:`3006`: [IPython 0.13.1] The check of PyQt version is wrong |
|
1491 | * :ghissue:`3006`: [IPython 0.13.1] The check of PyQt version is wrong | |
1492 | * :ghissue:`3005`: Renaming a notebook to an existing notebook name overwrites the other file |
|
1492 | * :ghissue:`3005`: Renaming a notebook to an existing notebook name overwrites the other file | |
1493 | * :ghissue:`2940`: Abort trap in IPython Notebook after installing matplotlib |
|
1493 | * :ghissue:`2940`: Abort trap in IPython Notebook after installing matplotlib | |
1494 | * :ghissue:`3000`: issue #3000 |
|
1494 | * :ghissue:`3000`: issue #3000 | |
1495 | * :ghissue:`2995`: ipython_directive.py fails on multiline when prompt number < 100 |
|
1495 | * :ghissue:`2995`: ipython_directive.py fails on multiline when prompt number < 100 | |
1496 | * :ghissue:`2993`: File magic (%%file) does not work with paths beginning with tilde (e.g., ~/anaconda/stuff.txt) |
|
1496 | * :ghissue:`2993`: File magic (%%file) does not work with paths beginning with tilde (e.g., ~/anaconda/stuff.txt) | |
1497 | * :ghissue:`2992`: Cell-based input for console and qt frontends? |
|
1497 | * :ghissue:`2992`: Cell-based input for console and qt frontends? | |
1498 | * :ghissue:`2425`: Liaise with Spyder devs to integrate newer IPython |
|
1498 | * :ghissue:`2425`: Liaise with Spyder devs to integrate newer IPython | |
1499 | * :ghissue:`2986`: requesting help in a loop can damage a notebook |
|
1499 | * :ghissue:`2986`: requesting help in a loop can damage a notebook | |
1500 | * :ghissue:`2978`: v1.0-dev build errors on Arch with Python 3. |
|
1500 | * :ghissue:`2978`: v1.0-dev build errors on Arch with Python 3. | |
1501 | * :ghissue:`2557`: [refactor] Insert_cell_at_index() |
|
1501 | * :ghissue:`2557`: [refactor] Insert_cell_at_index() | |
1502 | * :ghissue:`2969`: ipython command does not work in terminal |
|
1502 | * :ghissue:`2969`: ipython command does not work in terminal | |
1503 | * :ghissue:`2762`: OSX wxPython (osx_cocoa, 64bit) command "%gui wx" blocks the interpreter |
|
1503 | * :ghissue:`2762`: OSX wxPython (osx_cocoa, 64bit) command "%gui wx" blocks the interpreter | |
1504 | * :ghissue:`2956`: Silent importing of submodules differs from standard Python3.2 interpreter's behavior |
|
1504 | * :ghissue:`2956`: Silent importing of submodules differs from standard Python3.2 interpreter's behavior | |
1505 | * :ghissue:`2943`: Up arrow key history search gets stuck in QTConsole |
|
1505 | * :ghissue:`2943`: Up arrow key history search gets stuck in QTConsole | |
1506 | * :ghissue:`2953`: using 'nonlocal' declaration in global scope causes ipython3 crash |
|
1506 | * :ghissue:`2953`: using 'nonlocal' declaration in global scope causes ipython3 crash | |
1507 | * :ghissue:`2952`: qtconsole ignores exec_lines |
|
1507 | * :ghissue:`2952`: qtconsole ignores exec_lines | |
1508 | * :ghissue:`2949`: ipython crashes due to atexit() |
|
1508 | * :ghissue:`2949`: ipython crashes due to atexit() | |
1509 | * :ghissue:`2947`: From rmagic to an R console |
|
1509 | * :ghissue:`2947`: From rmagic to an R console | |
1510 | * :ghissue:`2938`: docstring pane not showing in notebook |
|
1510 | * :ghissue:`2938`: docstring pane not showing in notebook | |
1511 | * :ghissue:`2936`: Tornado assumes invalid signature for parse_qs on Python 3.1 |
|
1511 | * :ghissue:`2936`: Tornado assumes invalid signature for parse_qs on Python 3.1 | |
1512 | * :ghissue:`2935`: unable to find python after easy_install / pip install |
|
1512 | * :ghissue:`2935`: unable to find python after easy_install / pip install | |
1513 | * :ghissue:`2920`: Add undo-cell deletion menu |
|
1513 | * :ghissue:`2920`: Add undo-cell deletion menu | |
1514 | * :ghissue:`2914`: BUG:saving a modified .py file after loading a module kills the kernel |
|
1514 | * :ghissue:`2914`: BUG:saving a modified .py file after loading a module kills the kernel | |
1515 | * :ghissue:`2925`: BUG: kernel dies if user sets sys.stderr or sys.stdout to a file object |
|
1515 | * :ghissue:`2925`: BUG: kernel dies if user sets sys.stderr or sys.stdout to a file object | |
1516 | * :ghissue:`2909`: LaTeX sometimes fails to render in markdown cells with some curly bracket + underscore combinations |
|
1516 | * :ghissue:`2909`: LaTeX sometimes fails to render in markdown cells with some curly bracket + underscore combinations | |
1517 | * :ghissue:`2898`: Skip ipc tests on Windows |
|
1517 | * :ghissue:`2898`: Skip ipc tests on Windows | |
1518 | * :ghissue:`2902`: ActiveState attempt to build ipython 0.12.1 for python 3.2.2 for Mac OS failed |
|
1518 | * :ghissue:`2902`: ActiveState attempt to build ipython 0.12.1 for python 3.2.2 for Mac OS failed | |
1519 | * :ghissue:`2899`: Test failure in IPython.core.tests.test_magic.test_time |
|
1519 | * :ghissue:`2899`: Test failure in IPython.core.tests.test_magic.test_time | |
1520 | * :ghissue:`2890`: Test failure when fabric not installed |
|
1520 | * :ghissue:`2890`: Test failure when fabric not installed | |
1521 | * :ghissue:`2892`: IPython tab completion bug for paths |
|
1521 | * :ghissue:`2892`: IPython tab completion bug for paths | |
1522 | * :ghissue:`1340`: Allow input cells to be collapsed |
|
1522 | * :ghissue:`1340`: Allow input cells to be collapsed | |
1523 | * :ghissue:`2881`: ? command in notebook does not show help in Safari |
|
1523 | * :ghissue:`2881`: ? command in notebook does not show help in Safari | |
1524 | * :ghissue:`2751`: %%timeit should use minutes to format running time in long running cells |
|
1524 | * :ghissue:`2751`: %%timeit should use minutes to format running time in long running cells | |
1525 | * :ghissue:`2879`: When importing a module with a wrong name, ipython crashes |
|
1525 | * :ghissue:`2879`: When importing a module with a wrong name, ipython crashes | |
1526 | * :ghissue:`2862`: %%timeit should warn of empty contents |
|
1526 | * :ghissue:`2862`: %%timeit should warn of empty contents | |
1527 | * :ghissue:`2485`: History navigation breaks in qtconsole |
|
1527 | * :ghissue:`2485`: History navigation breaks in qtconsole | |
1528 | * :ghissue:`2785`: gevent input hook |
|
1528 | * :ghissue:`2785`: gevent input hook | |
1529 | * :ghissue:`2843`: Sliently running code in clipboard (with paste, cpaste and variants) |
|
1529 | * :ghissue:`2843`: Sliently running code in clipboard (with paste, cpaste and variants) | |
1530 | * :ghissue:`2784`: %run -t -N<N> error |
|
1530 | * :ghissue:`2784`: %run -t -N<N> error | |
1531 | * :ghissue:`2732`: Test failure with FileLinks class on Windows |
|
1531 | * :ghissue:`2732`: Test failure with FileLinks class on Windows | |
1532 | * :ghissue:`2860`: ipython help notebook -> KeyError: 'KernelManager' |
|
1532 | * :ghissue:`2860`: ipython help notebook -> KeyError: 'KernelManager' | |
1533 | * :ghissue:`2858`: Where is the installed `ipython` script? |
|
1533 | * :ghissue:`2858`: Where is the installed `ipython` script? | |
1534 | * :ghissue:`2856`: Edit code entered from ipython in external editor |
|
1534 | * :ghissue:`2856`: Edit code entered from ipython in external editor | |
1535 | * :ghissue:`2722`: IPC transport option not taking effect ? |
|
1535 | * :ghissue:`2722`: IPC transport option not taking effect ? | |
1536 | * :ghissue:`2473`: Better error messages in ipengine/ipcontroller |
|
1536 | * :ghissue:`2473`: Better error messages in ipengine/ipcontroller | |
1537 | * :ghissue:`2836`: Cannot send builtin module definitions to IP engines |
|
1537 | * :ghissue:`2836`: Cannot send builtin module definitions to IP engines | |
1538 | * :ghissue:`2833`: Any reason not to use super() ? |
|
1538 | * :ghissue:`2833`: Any reason not to use super() ? | |
1539 | * :ghissue:`2781`: Cannot interrupt infinite loops in the notebook |
|
1539 | * :ghissue:`2781`: Cannot interrupt infinite loops in the notebook | |
1540 | * :ghissue:`2150`: clippath_demo.py in matplotlib example does not work with inline backend |
|
1540 | * :ghissue:`2150`: clippath_demo.py in matplotlib example does not work with inline backend | |
1541 | * :ghissue:`2634`: Numbered list in notebook markdown cell renders with Roman numerals instead of numbers |
|
1541 | * :ghissue:`2634`: Numbered list in notebook markdown cell renders with Roman numerals instead of numbers | |
1542 | * :ghissue:`2230`: IPython crashing during startup with "AttributeError: 'NoneType' object has no attribute 'rstrip'" |
|
1542 | * :ghissue:`2230`: IPython crashing during startup with "AttributeError: 'NoneType' object has no attribute 'rstrip'" | |
1543 | * :ghissue:`2483`: nbviewer bug? with multi-file gists |
|
1543 | * :ghissue:`2483`: nbviewer bug? with multi-file gists | |
1544 | * :ghissue:`2466`: mistyping `ed -p` breaks `ed -p` |
|
1544 | * :ghissue:`2466`: mistyping `ed -p` breaks `ed -p` | |
1545 | * :ghissue:`2477`: Glob expansion tests fail on Windows |
|
1545 | * :ghissue:`2477`: Glob expansion tests fail on Windows | |
1546 | * :ghissue:`2622`: doc issue: notebooks that ship with Ipython .13 are written for python 2.x |
|
1546 | * :ghissue:`2622`: doc issue: notebooks that ship with Ipython .13 are written for python 2.x | |
1547 | * :ghissue:`2626`: Add "Cell -> Run All Keep Going" for notebooks |
|
1547 | * :ghissue:`2626`: Add "Cell -> Run All Keep Going" for notebooks | |
1548 | * :ghissue:`1223`: Show last modification date of each notebook |
|
1548 | * :ghissue:`1223`: Show last modification date of each notebook | |
1549 | * :ghissue:`2621`: user request: put link to example notebooks in Dashboard |
|
1549 | * :ghissue:`2621`: user request: put link to example notebooks in Dashboard | |
1550 | * :ghissue:`2564`: grid blanks plots in ipython pylab inline mode (interactive) |
|
1550 | * :ghissue:`2564`: grid blanks plots in ipython pylab inline mode (interactive) | |
1551 | * :ghissue:`2532`: Django shell (IPython) gives NameError on dict comprehensions |
|
1551 | * :ghissue:`2532`: Django shell (IPython) gives NameError on dict comprehensions | |
1552 | * :ghissue:`2188`: ipython crashes on ctrl-c |
|
1552 | * :ghissue:`2188`: ipython crashes on ctrl-c | |
1553 | * :ghissue:`2391`: Request: nbformat API to load/save without changing version |
|
1553 | * :ghissue:`2391`: Request: nbformat API to load/save without changing version | |
1554 | * :ghissue:`2355`: Restart kernel message even though kernel is perfectly alive |
|
1554 | * :ghissue:`2355`: Restart kernel message even though kernel is perfectly alive | |
1555 | * :ghissue:`2306`: Garbled input text after reverse search on Mac OS X |
|
1555 | * :ghissue:`2306`: Garbled input text after reverse search on Mac OS X | |
1556 | * :ghissue:`2297`: ipdb with separate kernel/client pushing stdout to kernel process only |
|
1556 | * :ghissue:`2297`: ipdb with separate kernel/client pushing stdout to kernel process only | |
1557 | * :ghissue:`2180`: Have [kernel busy] overridden only by [kernel idle] |
|
1557 | * :ghissue:`2180`: Have [kernel busy] overridden only by [kernel idle] | |
1558 | * :ghissue:`1188`: Pylab with OSX backend keyboard focus issue and hang |
|
1558 | * :ghissue:`1188`: Pylab with OSX backend keyboard focus issue and hang | |
1559 | * :ghissue:`2107`: test_octavemagic.py[everything] fails |
|
1559 | * :ghissue:`2107`: test_octavemagic.py[everything] fails | |
1560 | * :ghissue:`1212`: Better understand/document browser compatibility |
|
1560 | * :ghissue:`1212`: Better understand/document browser compatibility | |
1561 | * :ghissue:`1585`: Refactor notebook templates to use Jinja2 and make each page a separate directory |
|
1561 | * :ghissue:`1585`: Refactor notebook templates to use Jinja2 and make each page a separate directory | |
1562 | * :ghissue:`1443`: xticks scaling factor partially obscured with qtconsole and inline plotting |
|
1562 | * :ghissue:`1443`: xticks scaling factor partially obscured with qtconsole and inline plotting | |
1563 | * :ghissue:`1209`: can't make %result work as in doc. |
|
1563 | * :ghissue:`1209`: can't make %result work as in doc. | |
1564 | * :ghissue:`1200`: IPython 0.12 Windows install fails on Vista |
|
1564 | * :ghissue:`1200`: IPython 0.12 Windows install fails on Vista | |
1565 | * :ghissue:`1127`: Interactive test scripts for Qt/nb issues |
|
1565 | * :ghissue:`1127`: Interactive test scripts for Qt/nb issues | |
1566 | * :ghissue:`959`: Matplotlib figures hide |
|
1566 | * :ghissue:`959`: Matplotlib figures hide | |
1567 | * :ghissue:`2071`: win32 installer issue on Windows XP |
|
1567 | * :ghissue:`2071`: win32 installer issue on Windows XP | |
1568 | * :ghissue:`2610`: ZMQInteractiveShell.colors being ignored |
|
1568 | * :ghissue:`2610`: ZMQInteractiveShell.colors being ignored | |
1569 | * :ghissue:`2505`: Markdown Cell incorrectly highlighting after "<" |
|
1569 | * :ghissue:`2505`: Markdown Cell incorrectly highlighting after "<" | |
1570 | * :ghissue:`165`: Installer fails to create Start Menu entries on Windows |
|
1570 | * :ghissue:`165`: Installer fails to create Start Menu entries on Windows | |
1571 | * :ghissue:`2356`: failing traceback in terminal ipython for first exception |
|
1571 | * :ghissue:`2356`: failing traceback in terminal ipython for first exception | |
1572 | * :ghissue:`2145`: Have dashboad show when server disconect |
|
1572 | * :ghissue:`2145`: Have dashboad show when server disconect | |
1573 | * :ghissue:`2098`: Do not crash on kernel shutdow if json file is missing |
|
1573 | * :ghissue:`2098`: Do not crash on kernel shutdow if json file is missing | |
1574 | * :ghissue:`2813`: Offline MathJax is broken on 0.14dev |
|
1574 | * :ghissue:`2813`: Offline MathJax is broken on 0.14dev | |
1575 | * :ghissue:`2807`: Test failure: IPython.parallel.tests.test_client.TestClient.test_purge_everything |
|
1575 | * :ghissue:`2807`: Test failure: IPython.parallel.tests.test_client.TestClient.test_purge_everything | |
1576 | * :ghissue:`2486`: Readline's history search in ipython console does not clear properly after cancellation with Ctrl+C |
|
1576 | * :ghissue:`2486`: Readline's history search in ipython console does not clear properly after cancellation with Ctrl+C | |
1577 | * :ghissue:`2709`: Cython -la doesn't work |
|
1577 | * :ghissue:`2709`: Cython -la doesn't work | |
1578 | * :ghissue:`2767`: What is IPython.utils.upgradedir ? |
|
1578 | * :ghissue:`2767`: What is IPython.utils.upgradedir ? | |
1579 | * :ghissue:`2210`: Placing matplotlib legend outside axis bounds causes inline display to clip it |
|
1579 | * :ghissue:`2210`: Placing matplotlib legend outside axis bounds causes inline display to clip it | |
1580 | * :ghissue:`2553`: IPython Notebooks not robust against client failures |
|
1580 | * :ghissue:`2553`: IPython Notebooks not robust against client failures | |
1581 | * :ghissue:`2536`: ImageDraw in Ipython notebook not drawing lines |
|
1581 | * :ghissue:`2536`: ImageDraw in Ipython notebook not drawing lines | |
1582 | * :ghissue:`2264`: Feature request: Versioning messaging protocol |
|
1582 | * :ghissue:`2264`: Feature request: Versioning messaging protocol | |
1583 | * :ghissue:`2589`: Creation of ~300+ MPI-spawned engines causes instability in ipcluster |
|
1583 | * :ghissue:`2589`: Creation of ~300+ MPI-spawned engines causes instability in ipcluster | |
1584 | * :ghissue:`2672`: notebook: inline option without pylab |
|
1584 | * :ghissue:`2672`: notebook: inline option without pylab | |
1585 | * :ghissue:`2673`: Indefinite Articles & Traitlets |
|
1585 | * :ghissue:`2673`: Indefinite Articles & Traitlets | |
1586 | * :ghissue:`2705`: Notebook crashes Safari with select and drag |
|
1586 | * :ghissue:`2705`: Notebook crashes Safari with select and drag | |
1587 | * :ghissue:`2721`: dreload kills ipython when it hits zmq |
|
1587 | * :ghissue:`2721`: dreload kills ipython when it hits zmq | |
1588 | * :ghissue:`2806`: ipython.parallel doesn't discover globals under Python 3.3 |
|
1588 | * :ghissue:`2806`: ipython.parallel doesn't discover globals under Python 3.3 | |
1589 | * :ghissue:`2794`: _exit_code behaves differently in terminal vs ZMQ frontends |
|
1589 | * :ghissue:`2794`: _exit_code behaves differently in terminal vs ZMQ frontends | |
1590 | * :ghissue:`2793`: IPython.parallel issue with pushing pandas TimeSeries |
|
1590 | * :ghissue:`2793`: IPython.parallel issue with pushing pandas TimeSeries | |
1591 | * :ghissue:`1085`: In process kernel for Qt frontend |
|
1591 | * :ghissue:`1085`: In process kernel for Qt frontend | |
1592 | * :ghissue:`2760`: IndexError: list index out of range with Python 3.2 |
|
1592 | * :ghissue:`2760`: IndexError: list index out of range with Python 3.2 | |
1593 | * :ghissue:`2780`: Save and load notebooks from github |
|
1593 | * :ghissue:`2780`: Save and load notebooks from github | |
1594 | * :ghissue:`2772`: AttributeError: 'Client' object has no attribute 'kill' |
|
1594 | * :ghissue:`2772`: AttributeError: 'Client' object has no attribute 'kill' | |
1595 | * :ghissue:`2754`: Fail to send class definitions from interactive session to engines namespaces |
|
1595 | * :ghissue:`2754`: Fail to send class definitions from interactive session to engines namespaces | |
1596 | * :ghissue:`2764`: TypeError while using 'cd' |
|
1596 | * :ghissue:`2764`: TypeError while using 'cd' | |
1597 | * :ghissue:`2765`: name '__file__' is not defined |
|
1597 | * :ghissue:`2765`: name '__file__' is not defined | |
1598 | * :ghissue:`2540`: Wrap tooltip if line exceeds threshold? |
|
1598 | * :ghissue:`2540`: Wrap tooltip if line exceeds threshold? | |
1599 | * :ghissue:`2394`: Startup error on ipython qtconsole (version 0.13 and 0.14-dev |
|
1599 | * :ghissue:`2394`: Startup error on ipython qtconsole (version 0.13 and 0.14-dev | |
1600 | * :ghissue:`2440`: IPEP 4: Python 3 Compatibility |
|
1600 | * :ghissue:`2440`: IPEP 4: Python 3 Compatibility | |
1601 | * :ghissue:`1814`: __file__ is not defined when file end with .ipy |
|
1601 | * :ghissue:`1814`: __file__ is not defined when file end with .ipy | |
1602 | * :ghissue:`2759`: R magic extension interferes with tab completion |
|
1602 | * :ghissue:`2759`: R magic extension interferes with tab completion | |
1603 | * :ghissue:`2615`: Small change needed to rmagic extension. |
|
1603 | * :ghissue:`2615`: Small change needed to rmagic extension. | |
1604 | * :ghissue:`2748`: collapse parts of a html notebook |
|
1604 | * :ghissue:`2748`: collapse parts of a html notebook | |
1605 | * :ghissue:`1661`: %paste still bugs about IndentationError and says to use %paste |
|
1605 | * :ghissue:`1661`: %paste still bugs about IndentationError and says to use %paste | |
1606 | * :ghissue:`2742`: Octavemagic fails to deliver inline images in IPython (on Windows) |
|
1606 | * :ghissue:`2742`: Octavemagic fails to deliver inline images in IPython (on Windows) | |
1607 | * :ghissue:`2739`: wiki.ipython.org contaminated with prescription drug spam |
|
1607 | * :ghissue:`2739`: wiki.ipython.org contaminated with prescription drug spam | |
1608 | * :ghissue:`2588`: Link error while executing code from cython example notebook |
|
1608 | * :ghissue:`2588`: Link error while executing code from cython example notebook | |
1609 | * :ghissue:`2550`: Rpush magic doesn't find local variables and doesn't support comma separated lists of variables |
|
1609 | * :ghissue:`2550`: Rpush magic doesn't find local variables and doesn't support comma separated lists of variables | |
1610 | * :ghissue:`2675`: Markdown/html blockquote need css. |
|
1610 | * :ghissue:`2675`: Markdown/html blockquote need css. | |
1611 | * :ghissue:`2419`: TerminalInteractiveShell.__init__() ignores value of ipython_dir argument |
|
1611 | * :ghissue:`2419`: TerminalInteractiveShell.__init__() ignores value of ipython_dir argument | |
1612 | * :ghissue:`1523`: Better LaTeX printing in the qtconsole with the sympy profile |
|
1612 | * :ghissue:`1523`: Better LaTeX printing in the qtconsole with the sympy profile | |
1613 | * :ghissue:`2719`: ipython fails with `pkg_resources.DistributionNotFound: ipython==0.13` |
|
1613 | * :ghissue:`2719`: ipython fails with `pkg_resources.DistributionNotFound: ipython==0.13` | |
1614 | * :ghissue:`2715`: url crashes nbviewer.ipython.org |
|
1614 | * :ghissue:`2715`: url crashes nbviewer.ipython.org | |
1615 | * :ghissue:`2555`: "import" module completion on MacOSX |
|
1615 | * :ghissue:`2555`: "import" module completion on MacOSX | |
1616 | * :ghissue:`2707`: Problem installing the new version of IPython in Windows |
|
1616 | * :ghissue:`2707`: Problem installing the new version of IPython in Windows | |
1617 | * :ghissue:`2696`: SymPy magic bug in IPython Notebook |
|
1617 | * :ghissue:`2696`: SymPy magic bug in IPython Notebook | |
1618 | * :ghissue:`2684`: pretty print broken for types created with PyType_FromSpec |
|
1618 | * :ghissue:`2684`: pretty print broken for types created with PyType_FromSpec | |
1619 | * :ghissue:`2533`: rmagic breaks on Windows |
|
1619 | * :ghissue:`2533`: rmagic breaks on Windows | |
1620 | * :ghissue:`2661`: Qtconsole tooltip is too wide when the function has many arguments |
|
1620 | * :ghissue:`2661`: Qtconsole tooltip is too wide when the function has many arguments | |
1621 | * :ghissue:`2679`: ipython3 qtconsole via Homebrew on Mac OS X 10.8 - pyqt/pyside import error |
|
1621 | * :ghissue:`2679`: ipython3 qtconsole via Homebrew on Mac OS X 10.8 - pyqt/pyside import error | |
1622 | * :ghissue:`2646`: pylab_not_importable |
|
1622 | * :ghissue:`2646`: pylab_not_importable | |
1623 | * :ghissue:`2587`: cython magic pops 2 CLI windows upon execution on Windows |
|
1623 | * :ghissue:`2587`: cython magic pops 2 CLI windows upon execution on Windows | |
1624 | * :ghissue:`2660`: Certain arguments (-h, --help, --version) never passed to scripts run with ipython |
|
1624 | * :ghissue:`2660`: Certain arguments (-h, --help, --version) never passed to scripts run with ipython | |
1625 | * :ghissue:`2665`: Missing docs for rmagic and some other extensions |
|
1625 | * :ghissue:`2665`: Missing docs for rmagic and some other extensions | |
1626 | * :ghissue:`2611`: Travis wants to drop 3.1 support |
|
1626 | * :ghissue:`2611`: Travis wants to drop 3.1 support | |
1627 | * :ghissue:`2658`: Incorrect parsing of raw multiline strings |
|
1627 | * :ghissue:`2658`: Incorrect parsing of raw multiline strings | |
1628 | * :ghissue:`2655`: Test fails if `from __future__ import print_function` in .pythonrc.py |
|
1628 | * :ghissue:`2655`: Test fails if `from __future__ import print_function` in .pythonrc.py | |
1629 | * :ghissue:`2651`: nonlocal with no existing variable produces too many errors |
|
1629 | * :ghissue:`2651`: nonlocal with no existing variable produces too many errors | |
1630 | * :ghissue:`2645`: python3 is a pain (minor unicode bug) |
|
1630 | * :ghissue:`2645`: python3 is a pain (minor unicode bug) | |
1631 | * :ghissue:`2637`: %paste in Python 3 on Mac doesn't work |
|
1631 | * :ghissue:`2637`: %paste in Python 3 on Mac doesn't work | |
1632 | * :ghissue:`2624`: Error on launching IPython on Win 7 and Python 2.7.3 |
|
1632 | * :ghissue:`2624`: Error on launching IPython on Win 7 and Python 2.7.3 | |
1633 | * :ghissue:`2608`: disk IO activity on cursor press |
|
1633 | * :ghissue:`2608`: disk IO activity on cursor press | |
1634 | * :ghissue:`1275`: Markdown parses LaTeX math symbols as its formatting syntax in notebook |
|
1634 | * :ghissue:`1275`: Markdown parses LaTeX math symbols as its formatting syntax in notebook | |
1635 | * :ghissue:`2613`: display(Math(...)) doesn't render \tau correctly |
|
1635 | * :ghissue:`2613`: display(Math(...)) doesn't render \tau correctly | |
1636 | * :ghissue:`925`: Tab-completion in Qt console needn't use pager |
|
1636 | * :ghissue:`925`: Tab-completion in Qt console needn't use pager | |
1637 | * :ghissue:`2607`: %load_ext sympy.interactive.ipythonprinting dammaging output |
|
1637 | * :ghissue:`2607`: %load_ext sympy.interactive.ipythonprinting dammaging output | |
1638 | * :ghissue:`2593`: Toolbar button to open qtconsole from notebook |
|
1638 | * :ghissue:`2593`: Toolbar button to open qtconsole from notebook | |
1639 | * :ghissue:`2602`: IPython html documentation for downloading |
|
1639 | * :ghissue:`2602`: IPython html documentation for downloading | |
1640 | * :ghissue:`2598`: ipython notebook --pylab=inline replaces built-in any() |
|
1640 | * :ghissue:`2598`: ipython notebook --pylab=inline replaces built-in any() | |
1641 | * :ghissue:`2244`: small issue: wrong printout |
|
1641 | * :ghissue:`2244`: small issue: wrong printout | |
1642 | * :ghissue:`2590`: add easier way to execute scripts in the current directory |
|
1642 | * :ghissue:`2590`: add easier way to execute scripts in the current directory | |
1643 | * :ghissue:`2581`: %hist does not work when InteractiveShell.cache_size = 0 |
|
1643 | * :ghissue:`2581`: %hist does not work when InteractiveShell.cache_size = 0 | |
1644 | * :ghissue:`2584`: No file COPYING |
|
1644 | * :ghissue:`2584`: No file COPYING | |
1645 | * :ghissue:`2578`: AttributeError: 'module' object has no attribute 'TestCase' |
|
1645 | * :ghissue:`2578`: AttributeError: 'module' object has no attribute 'TestCase' | |
1646 | * :ghissue:`2576`: One of my notebooks won't load any more -- is there a maximum notebook size? |
|
1646 | * :ghissue:`2576`: One of my notebooks won't load any more -- is there a maximum notebook size? | |
1647 | * :ghissue:`2560`: Notebook output is invisible when printing strings with \r\r\n line endings |
|
1647 | * :ghissue:`2560`: Notebook output is invisible when printing strings with \r\r\n line endings | |
1648 | * :ghissue:`2566`: if pyside partially present ipython qtconsole fails to load even if pyqt4 present |
|
1648 | * :ghissue:`2566`: if pyside partially present ipython qtconsole fails to load even if pyqt4 present | |
1649 | * :ghissue:`1308`: ipython qtconsole --ssh=server --existing ... hangs |
|
1649 | * :ghissue:`1308`: ipython qtconsole --ssh=server --existing ... hangs | |
1650 | * :ghissue:`1679`: List command doesn't work in ipdb debugger the first time |
|
1650 | * :ghissue:`1679`: List command doesn't work in ipdb debugger the first time | |
1651 | * :ghissue:`2545`: pypi win32 installer creates 64bit executibles |
|
1651 | * :ghissue:`2545`: pypi win32 installer creates 64bit executibles | |
1652 | * :ghissue:`2080`: Event loop issues with IPython 0.12 and PyQt4 (QDialog.exec_ and more) |
|
1652 | * :ghissue:`2080`: Event loop issues with IPython 0.12 and PyQt4 (``QDialog.exec_`` and more) | |
1653 | * :ghissue:`2541`: Allow `python -m IPython` |
|
1653 | * :ghissue:`2541`: Allow `python -m IPython` | |
1654 | * :ghissue:`2508`: subplots_adjust() does not work correctly in ipython notebook |
|
1654 | * :ghissue:`2508`: subplots_adjust() does not work correctly in ipython notebook | |
1655 | * :ghissue:`2289`: Incorrect mathjax rendering of certain arrays of equations |
|
1655 | * :ghissue:`2289`: Incorrect mathjax rendering of certain arrays of equations | |
1656 | * :ghissue:`2487`: Selecting and indenting |
|
1656 | * :ghissue:`2487`: Selecting and indenting | |
1657 | * :ghissue:`2521`: more fine-grained 'run' controls, such as 'run from here' and 'run until here' |
|
1657 | * :ghissue:`2521`: more fine-grained 'run' controls, such as 'run from here' and 'run until here' | |
1658 | * :ghissue:`2535`: Funny bounding box when plot with text |
|
1658 | * :ghissue:`2535`: Funny bounding box when plot with text | |
1659 | * :ghissue:`2523`: History not working |
|
1659 | * :ghissue:`2523`: History not working | |
1660 | * :ghissue:`2514`: Issue with zooming in qtconsole |
|
1660 | * :ghissue:`2514`: Issue with zooming in qtconsole | |
1661 | * :ghissue:`2220`: No sys.stdout.encoding in kernel based IPython |
|
1661 | * :ghissue:`2220`: No sys.stdout.encoding in kernel based IPython | |
1662 | * :ghissue:`2512`: ERROR: Internal Python error in the inspect module. |
|
1662 | * :ghissue:`2512`: ERROR: Internal Python error in the inspect module. | |
1663 | * :ghissue:`2496`: Function passwd does not work in QtConsole |
|
1663 | * :ghissue:`2496`: Function passwd does not work in QtConsole | |
1664 | * :ghissue:`1453`: make engines reconnect/die when controller was restarted |
|
1664 | * :ghissue:`1453`: make engines reconnect/die when controller was restarted | |
1665 | * :ghissue:`2481`: ipython notebook -- clicking in a code cell's output moves the screen to the top of the code cell |
|
1665 | * :ghissue:`2481`: ipython notebook -- clicking in a code cell's output moves the screen to the top of the code cell | |
1666 | * :ghissue:`2488`: Undesired plot outputs in Notebook inline mode |
|
1666 | * :ghissue:`2488`: Undesired plot outputs in Notebook inline mode | |
1667 | * :ghissue:`2482`: ipython notebook -- download may not get the latest notebook |
|
1667 | * :ghissue:`2482`: ipython notebook -- download may not get the latest notebook | |
1668 | * :ghissue:`2471`: _subprocess module removed in Python 3.3 |
|
1668 | * :ghissue:`2471`: _subprocess module removed in Python 3.3 | |
1669 | * :ghissue:`2374`: Issues with man pages |
|
1669 | * :ghissue:`2374`: Issues with man pages | |
1670 | * :ghissue:`2316`: parallel.Client.__init__ should take cluster_id kwarg |
|
1670 | * :ghissue:`2316`: parallel.Client.__init__ should take cluster_id kwarg | |
1671 | * :ghissue:`2457`: Can a R library wrapper be created with Rmagic? |
|
1671 | * :ghissue:`2457`: Can a R library wrapper be created with Rmagic? | |
1672 | * :ghissue:`1575`: Fallback frontend for console when connecting pylab=inlnie -enabled kernel? |
|
1672 | * :ghissue:`1575`: Fallback frontend for console when connecting pylab=inlnie -enabled kernel? | |
1673 | * :ghissue:`2097`: Do not crash if history db is corrupted |
|
1673 | * :ghissue:`2097`: Do not crash if history db is corrupted | |
1674 | * :ghissue:`2435`: ipengines fail if clean_logs enabled |
|
1674 | * :ghissue:`2435`: ipengines fail if clean_logs enabled | |
1675 | * :ghissue:`2429`: Using warnings.warn() results in TypeError |
|
1675 | * :ghissue:`2429`: Using warnings.warn() results in TypeError | |
1676 | * :ghissue:`2422`: Multiprocessing in ipython notebook kernel crash |
|
1676 | * :ghissue:`2422`: Multiprocessing in ipython notebook kernel crash | |
1677 | * :ghissue:`2426`: ipython crashes with the following message. I do not what went wrong. Can you help me identify the problem? |
|
1677 | * :ghissue:`2426`: ipython crashes with the following message. I do not what went wrong. Can you help me identify the problem? | |
1678 | * :ghissue:`2423`: Docs typo? |
|
1678 | * :ghissue:`2423`: Docs typo? | |
1679 | * :ghissue:`2257`: pip install -e fails |
|
1679 | * :ghissue:`2257`: pip install -e fails | |
1680 | * :ghissue:`2418`: rmagic can't run R's read.csv on data files with NA data |
|
1680 | * :ghissue:`2418`: rmagic can't run R's read.csv on data files with NA data | |
1681 | * :ghissue:`2417`: HTML notebook: Backspace sometimes deletes multiple characters |
|
1681 | * :ghissue:`2417`: HTML notebook: Backspace sometimes deletes multiple characters | |
1682 | * :ghissue:`2275`: notebook: "Down_Arrow" on last line of cell should move to end of line |
|
1682 | * :ghissue:`2275`: notebook: "Down_Arrow" on last line of cell should move to end of line | |
1683 | * :ghissue:`2414`: 0.13.1 does not work with current EPD 7.3-2 |
|
1683 | * :ghissue:`2414`: 0.13.1 does not work with current EPD 7.3-2 | |
1684 | * :ghissue:`2409`: there is a redundant None |
|
1684 | * :ghissue:`2409`: there is a redundant None | |
1685 | * :ghissue:`2410`: Use /usr/bin/python3 instead of /usr/bin/python |
|
1685 | * :ghissue:`2410`: Use /usr/bin/python3 instead of /usr/bin/python | |
1686 | * :ghissue:`2366`: Notebook Dashboard --notebook-dir and fullpath |
|
1686 | * :ghissue:`2366`: Notebook Dashboard --notebook-dir and fullpath | |
1687 | * :ghissue:`2406`: Inability to get docstring in debugger |
|
1687 | * :ghissue:`2406`: Inability to get docstring in debugger | |
1688 | * :ghissue:`2398`: Show line number for IndentationErrors |
|
1688 | * :ghissue:`2398`: Show line number for IndentationErrors | |
1689 | * :ghissue:`2314`: HTML lists seem to interfere with the QtConsole display |
|
1689 | * :ghissue:`2314`: HTML lists seem to interfere with the QtConsole display | |
1690 | * :ghissue:`1688`: unicode exception when using %run with failing script |
|
1690 | * :ghissue:`1688`: unicode exception when using %run with failing script | |
1691 | * :ghissue:`1884`: IPython.embed changes color on error |
|
1691 | * :ghissue:`1884`: IPython.embed changes color on error | |
1692 | * :ghissue:`2381`: %time doesn't work for multiline statements |
|
1692 | * :ghissue:`2381`: %time doesn't work for multiline statements | |
1693 | * :ghissue:`1435`: Add size keywords in Image class |
|
1693 | * :ghissue:`1435`: Add size keywords in Image class | |
1694 | * :ghissue:`2372`: interactiveshell.py misses urllib and io_open imports |
|
1694 | * :ghissue:`2372`: interactiveshell.py misses urllib and io_open imports | |
1695 | * :ghissue:`2371`: iPython not working |
|
1695 | * :ghissue:`2371`: iPython not working | |
1696 | * :ghissue:`2367`: Tab expansion moves to next cell in notebook |
|
1696 | * :ghissue:`2367`: Tab expansion moves to next cell in notebook | |
1697 | * :ghissue:`2359`: nbviever alters the order of print and display() output |
|
1697 | * :ghissue:`2359`: nbviever alters the order of print and display() output | |
1698 | * :ghissue:`2227`: print name for IPython Notebooks has become uninformative |
|
1698 | * :ghissue:`2227`: print name for IPython Notebooks has become uninformative | |
1699 | * :ghissue:`2361`: client doesn't use connection file's 'location' in disambiguating 'interface' |
|
1699 | * :ghissue:`2361`: client doesn't use connection file's 'location' in disambiguating 'interface' | |
1700 | * :ghissue:`2357`: failing traceback in terminal ipython for first exception |
|
1700 | * :ghissue:`2357`: failing traceback in terminal ipython for first exception | |
1701 | * :ghissue:`2343`: Installing in a python 3.3b2 or python 3.3rc1 virtual environment. |
|
1701 | * :ghissue:`2343`: Installing in a python 3.3b2 or python 3.3rc1 virtual environment. | |
1702 | * :ghissue:`2315`: Failure in test: "Test we're not loading modules on startup that we shouldn't." |
|
1702 | * :ghissue:`2315`: Failure in test: "Test we're not loading modules on startup that we shouldn't." | |
1703 | * :ghissue:`2351`: Multiple Notebook Apps: cookies not port specific, clash with each other |
|
1703 | * :ghissue:`2351`: Multiple Notebook Apps: cookies not port specific, clash with each other | |
1704 | * :ghissue:`2350`: running unittest from qtconsole prints output to terminal |
|
1704 | * :ghissue:`2350`: running unittest from qtconsole prints output to terminal | |
1705 | * :ghissue:`2303`: remote tracebacks broken since 952d0d6 (PR #2223) |
|
1705 | * :ghissue:`2303`: remote tracebacks broken since 952d0d6 (PR #2223) | |
1706 | * :ghissue:`2330`: qtconsole does not hightlight tab-completion suggestion with custom stylesheet |
|
1706 | * :ghissue:`2330`: qtconsole does not hightlight tab-completion suggestion with custom stylesheet | |
1707 | * :ghissue:`2325`: Parsing Tex formula fails in Notebook |
|
1707 | * :ghissue:`2325`: Parsing Tex formula fails in Notebook | |
1708 | * :ghissue:`2324`: Parsing Tex formula fails |
|
1708 | * :ghissue:`2324`: Parsing Tex formula fails | |
1709 | * :ghissue:`1474`: Add argument to `run -n` for custom namespace |
|
1709 | * :ghissue:`1474`: Add argument to `run -n` for custom namespace | |
1710 | * :ghissue:`2318`: C-m n/p don't work in Markdown cells in the notebook |
|
1710 | * :ghissue:`2318`: C-m n/p don't work in Markdown cells in the notebook | |
1711 | * :ghissue:`2309`: time.time() in ipython notebook producing impossible results |
|
1711 | * :ghissue:`2309`: time.time() in ipython notebook producing impossible results | |
1712 | * :ghissue:`2307`: schedule tasks on newly arrived engines |
|
1712 | * :ghissue:`2307`: schedule tasks on newly arrived engines | |
1713 | * :ghissue:`2313`: Allow Notebook HTML/JS to send messages to Python code |
|
1713 | * :ghissue:`2313`: Allow Notebook HTML/JS to send messages to Python code | |
1714 | * :ghissue:`2304`: ipengine throws KeyError: url |
|
1714 | * :ghissue:`2304`: ipengine throws KeyError: url | |
1715 | * :ghissue:`1878`: shell access using ! will not fill class or function scope vars |
|
1715 | * :ghissue:`1878`: shell access using ! will not fill class or function scope vars | |
1716 | * :ghissue:`2253`: %paste does not retrieve clipboard contents under screen/tmux on OS X |
|
1716 | * :ghissue:`2253`: %paste does not retrieve clipboard contents under screen/tmux on OS X | |
1717 | * :ghissue:`1510`: Add-on (or Monkey-patch) infrastructure for HTML notebook |
|
1717 | * :ghissue:`1510`: Add-on (or Monkey-patch) infrastructure for HTML notebook | |
1718 | * :ghissue:`2273`: triple quote and %s at beginning of line with %paste |
|
1718 | * :ghissue:`2273`: triple quote and %s at beginning of line with %paste | |
1719 | * :ghissue:`2243`: Regression in .embed() |
|
1719 | * :ghissue:`2243`: Regression in .embed() | |
1720 | * :ghissue:`2266`: SSH passwordless check with OpenSSH checks for the wrong thing |
|
1720 | * :ghissue:`2266`: SSH passwordless check with OpenSSH checks for the wrong thing | |
1721 | * :ghissue:`2217`: Change NewNotebook handler to use 30x redirect |
|
1721 | * :ghissue:`2217`: Change NewNotebook handler to use 30x redirect | |
1722 | * :ghissue:`2276`: config option for disabling history store |
|
1722 | * :ghissue:`2276`: config option for disabling history store | |
1723 | * :ghissue:`2239`: can't use parallel.Reference in view.map |
|
1723 | * :ghissue:`2239`: can't use parallel.Reference in view.map | |
1724 | * :ghissue:`2272`: Sympy piecewise messed up rendering |
|
1724 | * :ghissue:`2272`: Sympy piecewise messed up rendering | |
1725 | * :ghissue:`2252`: %paste throws an exception with empty clipboard |
|
1725 | * :ghissue:`2252`: %paste throws an exception with empty clipboard | |
1726 | * :ghissue:`2259`: git-mpr is currently broken |
|
1726 | * :ghissue:`2259`: git-mpr is currently broken | |
1727 | * :ghissue:`2247`: Variable expansion in shell commands should work in substrings |
|
1727 | * :ghissue:`2247`: Variable expansion in shell commands should work in substrings | |
1728 | * :ghissue:`2026`: Run 'fast' tests only |
|
1728 | * :ghissue:`2026`: Run 'fast' tests only | |
1729 | * :ghissue:`2241`: read a list of notebooks on server and bring into browser only notebook |
|
1729 | * :ghissue:`2241`: read a list of notebooks on server and bring into browser only notebook | |
1730 | * :ghissue:`2237`: please put python and text editor in the web only ipython |
|
1730 | * :ghissue:`2237`: please put python and text editor in the web only ipython | |
1731 | * :ghissue:`2053`: Improvements to the IPython.display.Image object |
|
1731 | * :ghissue:`2053`: Improvements to the IPython.display.Image object | |
1732 | * :ghissue:`1456`: ERROR: Internal Python error in the inspect module. |
|
1732 | * :ghissue:`1456`: ERROR: Internal Python error in the inspect module. | |
1733 | * :ghissue:`2221`: Avoid importing from IPython.parallel in core |
|
1733 | * :ghissue:`2221`: Avoid importing from IPython.parallel in core | |
1734 | * :ghissue:`2213`: Can't trigger startup code in Engines |
|
1734 | * :ghissue:`2213`: Can't trigger startup code in Engines | |
1735 | * :ghissue:`1464`: Strange behavior for backspace with lines ending with more than 4 spaces in notebook |
|
1735 | * :ghissue:`1464`: Strange behavior for backspace with lines ending with more than 4 spaces in notebook | |
1736 | * :ghissue:`2187`: NaN in object_info_reply JSON causes parse error |
|
1736 | * :ghissue:`2187`: NaN in object_info_reply JSON causes parse error | |
1737 | * :ghissue:`214`: system command requiring administrative privileges |
|
1737 | * :ghissue:`214`: system command requiring administrative privileges | |
1738 | * :ghissue:`2195`: Unknown option `no-edit` in git-mpr |
|
1738 | * :ghissue:`2195`: Unknown option `no-edit` in git-mpr | |
1739 | * :ghissue:`2201`: Add documentation build to tools/test_pr.py |
|
1739 | * :ghissue:`2201`: Add documentation build to tools/test_pr.py | |
1740 | * :ghissue:`2205`: Command-line option for default Notebook output collapsing behavior |
|
1740 | * :ghissue:`2205`: Command-line option for default Notebook output collapsing behavior | |
1741 | * :ghissue:`1927`: toggle between inline and floating figures |
|
1741 | * :ghissue:`1927`: toggle between inline and floating figures | |
1742 | * :ghissue:`2171`: Can't start StarCluster after upgrading to IPython 0.13 |
|
1742 | * :ghissue:`2171`: Can't start StarCluster after upgrading to IPython 0.13 | |
1743 | * :ghissue:`2173`: oct2py v >= 0.3.1 doesn't need h5py anymore |
|
1743 | * :ghissue:`2173`: oct2py v >= 0.3.1 doesn't need h5py anymore | |
1744 | * :ghissue:`2099`: storemagic needs to use self.shell |
|
1744 | * :ghissue:`2099`: storemagic needs to use self.shell | |
1745 | * :ghissue:`2166`: DirectView map_sync() with Lambdas Using Generators |
|
1745 | * :ghissue:`2166`: DirectView map_sync() with Lambdas Using Generators | |
1746 | * :ghissue:`2091`: Unable to use print_stats after %prun -r in notebook |
|
1746 | * :ghissue:`2091`: Unable to use print_stats after %prun -r in notebook | |
1747 | * :ghissue:`2132`: Add fail-over for pastebin |
|
1747 | * :ghissue:`2132`: Add fail-over for pastebin | |
1748 | * :ghissue:`2156`: Make it possible to install ipython without nasty gui dependencies |
|
1748 | * :ghissue:`2156`: Make it possible to install ipython without nasty gui dependencies | |
1749 | * :ghissue:`2154`: Scrolled long output should be off in print view by default |
|
1749 | * :ghissue:`2154`: Scrolled long output should be off in print view by default | |
1750 | * :ghissue:`2162`: Tab completion does not work with IPython.embed_kernel() |
|
1750 | * :ghissue:`2162`: Tab completion does not work with IPython.embed_kernel() | |
1751 | * :ghissue:`2157`: iPython 0.13 / github-master cannot create logfile from scratch |
|
1751 | * :ghissue:`2157`: iPython 0.13 / github-master cannot create logfile from scratch | |
1752 | * :ghissue:`2151`: missing newline when a magic is called from the qtconsole menu |
|
1752 | * :ghissue:`2151`: missing newline when a magic is called from the qtconsole menu | |
1753 | * :ghissue:`2139`: 00_notebook_tour Image example broken on master |
|
1753 | * :ghissue:`2139`: 00_notebook_tour Image example broken on master | |
1754 | * :ghissue:`2143`: Add a %%cython_annotate magic |
|
1754 | * :ghissue:`2143`: Add a %%cython_annotate magic | |
1755 | * :ghissue:`2135`: Running IPython from terminal |
|
1755 | * :ghissue:`2135`: Running IPython from terminal | |
1756 | * :ghissue:`2093`: Makefile for building Sphinx documentation on Windows |
|
1756 | * :ghissue:`2093`: Makefile for building Sphinx documentation on Windows | |
1757 | * :ghissue:`2122`: Bug in pretty printing |
|
1757 | * :ghissue:`2122`: Bug in pretty printing | |
1758 | * :ghissue:`2120`: Notebook "Make a Copy..." keeps opening duplicates in the same tab |
|
1758 | * :ghissue:`2120`: Notebook "Make a Copy..." keeps opening duplicates in the same tab | |
1759 | * :ghissue:`1997`: password cannot be used with url prefix |
|
1759 | * :ghissue:`1997`: password cannot be used with url prefix | |
1760 | * :ghissue:`2129`: help/doc displayed multiple times if requested in loop |
|
1760 | * :ghissue:`2129`: help/doc displayed multiple times if requested in loop | |
1761 | * :ghissue:`2121`: ipdb does not support input history in qtconsole |
|
1761 | * :ghissue:`2121`: ipdb does not support input history in qtconsole | |
1762 | * :ghissue:`2114`: %logstart doesn't log |
|
1762 | * :ghissue:`2114`: %logstart doesn't log | |
1763 | * :ghissue:`2085`: %ed magic fails in qtconsole |
|
1763 | * :ghissue:`2085`: %ed magic fails in qtconsole | |
1764 | * :ghissue:`2119`: iPython fails to run on MacOS Lion |
|
1764 | * :ghissue:`2119`: iPython fails to run on MacOS Lion | |
1765 | * :ghissue:`2052`: %pylab inline magic does not work on windows |
|
1765 | * :ghissue:`2052`: %pylab inline magic does not work on windows | |
1766 | * :ghissue:`2111`: Ipython won't start on W7 |
|
1766 | * :ghissue:`2111`: Ipython won't start on W7 | |
1767 | * :ghissue:`2112`: Strange internal traceback |
|
1767 | * :ghissue:`2112`: Strange internal traceback | |
1768 | * :ghissue:`2108`: Backslash (\) at the end of the line behavior different from default Python |
|
1768 | * :ghissue:`2108`: Backslash (\) at the end of the line behavior different from default Python | |
1769 | * :ghissue:`1425`: Ampersands can't be typed sometimes in notebook cells |
|
1769 | * :ghissue:`1425`: Ampersands can't be typed sometimes in notebook cells | |
1770 | * :ghissue:`1513`: Add expand/collapse support for long output elements like stdout and tracebacks |
|
1770 | * :ghissue:`1513`: Add expand/collapse support for long output elements like stdout and tracebacks | |
1771 | * :ghissue:`2087`: error when starting ipython |
|
1771 | * :ghissue:`2087`: error when starting ipython | |
1772 | * :ghissue:`2103`: Ability to run notebook file from commandline |
|
1772 | * :ghissue:`2103`: Ability to run notebook file from commandline | |
1773 | * :ghissue:`2082`: Qt Console output spacing |
|
1773 | * :ghissue:`2082`: Qt Console output spacing | |
1774 | * :ghissue:`2083`: Test failures with Python 3.2 and PYTHONWARNINGS="d" |
|
1774 | * :ghissue:`2083`: Test failures with Python 3.2 and PYTHONWARNINGS="d" | |
1775 | * :ghissue:`2094`: about inline |
|
1775 | * :ghissue:`2094`: about inline | |
1776 | * :ghissue:`2077`: Starting IPython3 on the terminal |
|
1776 | * :ghissue:`2077`: Starting IPython3 on the terminal | |
1777 | * :ghissue:`1760`: easy_install ipython fails on py3.2-win32 |
|
1777 | * :ghissue:`1760`: easy_install ipython fails on py3.2-win32 | |
1778 | * :ghissue:`2075`: Local Mathjax install causes iptest3 error under python3 |
|
1778 | * :ghissue:`2075`: Local Mathjax install causes iptest3 error under python3 | |
1779 | * :ghissue:`2057`: setup fails for python3 with LANG=C |
|
1779 | * :ghissue:`2057`: setup fails for python3 with LANG=C | |
1780 | * :ghissue:`2070`: shebang on Windows |
|
1780 | * :ghissue:`2070`: shebang on Windows | |
1781 | * :ghissue:`2054`: sys_info missing git hash in sdists |
|
1781 | * :ghissue:`2054`: sys_info missing git hash in sdists | |
1782 | * :ghissue:`2059`: duplicate and modified files in documentation |
|
1782 | * :ghissue:`2059`: duplicate and modified files in documentation | |
1783 | * :ghissue:`2056`: except-shadows-builtin osm.py:687 |
|
1783 | * :ghissue:`2056`: except-shadows-builtin osm.py:687 | |
1784 | * :ghissue:`2058`: hyphen-used-as-minus-sign in manpages |
|
1784 | * :ghissue:`2058`: hyphen-used-as-minus-sign in manpages |
General Comments 0
You need to be logged in to leave comments.
Login now