Show More
@@ -0,0 +1,123 b'' | |||||
|
1 | # encoding: utf-8 | |||
|
2 | ||||
|
3 | """The IPython Core Notification Center. | |||
|
4 | ||||
|
5 | See docs/source/development/notification_blueprint.txt for an overview of the | |||
|
6 | notification module. | |||
|
7 | """ | |||
|
8 | ||||
|
9 | __docformat__ = "restructuredtext en" | |||
|
10 | ||||
|
11 | #----------------------------------------------------------------------------- | |||
|
12 | # Copyright (C) 2008 The IPython Development Team | |||
|
13 | # | |||
|
14 | # Distributed under the terms of the BSD License. The full license is in | |||
|
15 | # the file COPYING, distributed as part of this software. | |||
|
16 | #----------------------------------------------------------------------------- | |||
|
17 | ||||
|
18 | ||||
|
19 | class NotificationCenter(object): | |||
|
20 | """Synchronous notification center | |||
|
21 | ||||
|
22 | Example | |||
|
23 | ------- | |||
|
24 | >>> import IPython.kernel.core.notification as notification | |||
|
25 | >>> def callback(theType, theSender, args={}): | |||
|
26 | ... print theType,theSender,args | |||
|
27 | ... | |||
|
28 | >>> notification.sharedCenter.add_observer(callback, 'NOTIFICATION_TYPE', None) | |||
|
29 | >>> notification.sharedCenter.post_notification('NOTIFICATION_TYPE', object()) # doctest:+ELLIPSIS | |||
|
30 | NOTIFICATION_TYPE ... | |||
|
31 | ||||
|
32 | """ | |||
|
33 | def __init__(self): | |||
|
34 | super(NotificationCenter, self).__init__() | |||
|
35 | self._init_observers() | |||
|
36 | ||||
|
37 | ||||
|
38 | def _init_observers(self): | |||
|
39 | """Initialize observer storage""" | |||
|
40 | ||||
|
41 | self.registered_types = set() #set of types that are observed | |||
|
42 | self.registered_senders = set() #set of senders that are observed | |||
|
43 | self.observers = {} #map (type,sender) => callback (callable) | |||
|
44 | ||||
|
45 | ||||
|
46 | def post_notification(self, theType, sender, **kwargs): | |||
|
47 | """Post notification (type,sender,**kwargs) to all registered | |||
|
48 | observers. | |||
|
49 | ||||
|
50 | Implementation | |||
|
51 | -------------- | |||
|
52 | * If no registered observers, performance is O(1). | |||
|
53 | * Notificaiton order is undefined. | |||
|
54 | * Notifications are posted synchronously. | |||
|
55 | """ | |||
|
56 | ||||
|
57 | if(theType==None or sender==None): | |||
|
58 | raise Exception("NotificationCenter.post_notification requires \ | |||
|
59 | type and sender.") | |||
|
60 | ||||
|
61 | # If there are no registered observers for the type/sender pair | |||
|
62 | if((theType not in self.registered_types and | |||
|
63 | None not in self.registered_types) or | |||
|
64 | (sender not in self.registered_senders and | |||
|
65 | None not in self.registered_senders)): | |||
|
66 | return | |||
|
67 | ||||
|
68 | for o in self._observers_for_notification(theType, sender): | |||
|
69 | o(theType, sender, args=kwargs) | |||
|
70 | ||||
|
71 | ||||
|
72 | def _observers_for_notification(self, theType, sender): | |||
|
73 | """Find all registered observers that should recieve notification""" | |||
|
74 | ||||
|
75 | keys = ( | |||
|
76 | (theType,sender), | |||
|
77 | (theType, None), | |||
|
78 | (None, sender), | |||
|
79 | (None,None) | |||
|
80 | ) | |||
|
81 | ||||
|
82 | ||||
|
83 | obs = set() | |||
|
84 | for k in keys: | |||
|
85 | obs.update(self.observers.get(k, set())) | |||
|
86 | ||||
|
87 | return obs | |||
|
88 | ||||
|
89 | ||||
|
90 | def add_observer(self, callback, theType, sender): | |||
|
91 | """Add an observer callback to this notification center. | |||
|
92 | ||||
|
93 | The given callback will be called upon posting of notifications of | |||
|
94 | the given type/sender and will receive any additional kwargs passed | |||
|
95 | to post_notification. | |||
|
96 | ||||
|
97 | Parameters | |||
|
98 | ---------- | |||
|
99 | observerCallback : callable | |||
|
100 | Callable. Must take at least two arguments:: | |||
|
101 | observerCallback(type, sender, args={}) | |||
|
102 | ||||
|
103 | theType : hashable | |||
|
104 | The notification type. If None, all notifications from sender | |||
|
105 | will be posted. | |||
|
106 | ||||
|
107 | sender : hashable | |||
|
108 | The notification sender. If None, all notifications of theType | |||
|
109 | will be posted. | |||
|
110 | """ | |||
|
111 | assert(callback != None) | |||
|
112 | self.registered_types.add(theType) | |||
|
113 | self.registered_senders.add(sender) | |||
|
114 | self.observers.setdefault((theType,sender), set()).add(callback) | |||
|
115 | ||||
|
116 | def remove_all_observers(self): | |||
|
117 | """Removes all observers from this notification center""" | |||
|
118 | ||||
|
119 | self._init_observers() | |||
|
120 | ||||
|
121 | ||||
|
122 | ||||
|
123 | sharedCenter = NotificationCenter() No newline at end of file |
@@ -0,0 +1,171 b'' | |||||
|
1 | # encoding: utf-8 | |||
|
2 | ||||
|
3 | """This file contains unittests for the notification.py module.""" | |||
|
4 | ||||
|
5 | __docformat__ = "restructuredtext en" | |||
|
6 | ||||
|
7 | #----------------------------------------------------------------------------- | |||
|
8 | # Copyright (C) 2008 The IPython Development Team | |||
|
9 | # | |||
|
10 | # Distributed under the terms of the BSD License. The full license is in | |||
|
11 | # the file COPYING, distributed as part of this software. | |||
|
12 | #----------------------------------------------------------------------------- | |||
|
13 | ||||
|
14 | #----------------------------------------------------------------------------- | |||
|
15 | # Imports | |||
|
16 | #----------------------------------------------------------------------------- | |||
|
17 | ||||
|
18 | import unittest | |||
|
19 | import IPython.kernel.core.notification as notification | |||
|
20 | from nose.tools import timed | |||
|
21 | ||||
|
22 | # | |||
|
23 | # Supporting test classes | |||
|
24 | # | |||
|
25 | ||||
|
26 | class Observer(object): | |||
|
27 | """docstring for Observer""" | |||
|
28 | def __init__(self, expectedType, expectedSender, | |||
|
29 | center=notification.sharedCenter, **kwargs): | |||
|
30 | super(Observer, self).__init__() | |||
|
31 | self.expectedType = expectedType | |||
|
32 | self.expectedSender = expectedSender | |||
|
33 | self.expectedKwArgs = kwargs | |||
|
34 | self.recieved = False | |||
|
35 | center.add_observer(self.callback, | |||
|
36 | self.expectedType, | |||
|
37 | self.expectedSender) | |||
|
38 | ||||
|
39 | ||||
|
40 | def callback(self, theType, sender, args={}): | |||
|
41 | """callback""" | |||
|
42 | ||||
|
43 | assert(theType == self.expectedType or | |||
|
44 | self.expectedType == None) | |||
|
45 | assert(sender == self.expectedSender or | |||
|
46 | self.expectedSender == None) | |||
|
47 | assert(args == self.expectedKwArgs) | |||
|
48 | self.recieved = True | |||
|
49 | ||||
|
50 | ||||
|
51 | def verify(self): | |||
|
52 | """verify""" | |||
|
53 | ||||
|
54 | assert(self.recieved) | |||
|
55 | ||||
|
56 | def reset(self): | |||
|
57 | """reset""" | |||
|
58 | ||||
|
59 | self.recieved = False | |||
|
60 | ||||
|
61 | ||||
|
62 | ||||
|
63 | class Notifier(object): | |||
|
64 | """docstring for Notifier""" | |||
|
65 | def __init__(self, theType, **kwargs): | |||
|
66 | super(Notifier, self).__init__() | |||
|
67 | self.theType = theType | |||
|
68 | self.kwargs = kwargs | |||
|
69 | ||||
|
70 | def post(self, center=notification.sharedCenter): | |||
|
71 | """fire""" | |||
|
72 | ||||
|
73 | center.post_notification(self.theType, self, | |||
|
74 | **self.kwargs) | |||
|
75 | ||||
|
76 | ||||
|
77 | # | |||
|
78 | # Test Cases | |||
|
79 | # | |||
|
80 | ||||
|
81 | class NotificationTests(unittest.TestCase): | |||
|
82 | """docstring for NotificationTests""" | |||
|
83 | ||||
|
84 | def tearDown(self): | |||
|
85 | notification.sharedCenter.remove_all_observers() | |||
|
86 | ||||
|
87 | def test_notification_delivered(self): | |||
|
88 | """Test that notifications are delivered""" | |||
|
89 | expectedType = 'EXPECTED_TYPE' | |||
|
90 | sender = Notifier(expectedType) | |||
|
91 | observer = Observer(expectedType, sender) | |||
|
92 | ||||
|
93 | sender.post() | |||
|
94 | ||||
|
95 | observer.verify() | |||
|
96 | ||||
|
97 | ||||
|
98 | def test_type_specificity(self): | |||
|
99 | """Test that observers are registered by type""" | |||
|
100 | ||||
|
101 | expectedType = 1 | |||
|
102 | unexpectedType = "UNEXPECTED_TYPE" | |||
|
103 | sender = Notifier(expectedType) | |||
|
104 | unexpectedSender = Notifier(unexpectedType) | |||
|
105 | observer = Observer(expectedType, sender) | |||
|
106 | ||||
|
107 | sender.post() | |||
|
108 | unexpectedSender.post() | |||
|
109 | ||||
|
110 | observer.verify() | |||
|
111 | ||||
|
112 | ||||
|
113 | def test_sender_specificity(self): | |||
|
114 | """Test that observers are registered by sender""" | |||
|
115 | ||||
|
116 | expectedType = "EXPECTED_TYPE" | |||
|
117 | sender1 = Notifier(expectedType) | |||
|
118 | sender2 = Notifier(expectedType) | |||
|
119 | observer = Observer(expectedType, sender1) | |||
|
120 | ||||
|
121 | sender1.post() | |||
|
122 | sender2.post() | |||
|
123 | ||||
|
124 | observer.verify() | |||
|
125 | ||||
|
126 | ||||
|
127 | def test_remove_all_observers(self): | |||
|
128 | """White-box test for remove_all_observers""" | |||
|
129 | ||||
|
130 | for i in xrange(10): | |||
|
131 | Observer('TYPE', None, center=notification.sharedCenter) | |||
|
132 | ||||
|
133 | self.assert_(len(notification.sharedCenter.observers[('TYPE',None)]) >= 10, | |||
|
134 | "observers registered") | |||
|
135 | ||||
|
136 | notification.sharedCenter.remove_all_observers() | |||
|
137 | ||||
|
138 | self.assert_(len(notification.sharedCenter.observers) == 0, "observers removed") | |||
|
139 | ||||
|
140 | ||||
|
141 | def test_any_sender(self): | |||
|
142 | """test_any_sender""" | |||
|
143 | ||||
|
144 | expectedType = "EXPECTED_TYPE" | |||
|
145 | sender1 = Notifier(expectedType) | |||
|
146 | sender2 = Notifier(expectedType) | |||
|
147 | observer = Observer(expectedType, None) | |||
|
148 | ||||
|
149 | ||||
|
150 | sender1.post() | |||
|
151 | observer.verify() | |||
|
152 | ||||
|
153 | observer.reset() | |||
|
154 | sender2.post() | |||
|
155 | observer.verify() | |||
|
156 | ||||
|
157 | ||||
|
158 | @timed(.01) | |||
|
159 | def test_post_performance(self): | |||
|
160 | """Test that post_notification, even with many registered irrelevant | |||
|
161 | observers is fast""" | |||
|
162 | ||||
|
163 | for i in xrange(10): | |||
|
164 | Observer("UNRELATED_TYPE", None) | |||
|
165 | ||||
|
166 | o = Observer('EXPECTED_TYPE', None) | |||
|
167 | ||||
|
168 | notification.sharedCenter.post_notification('EXPECTED_TYPE', self) | |||
|
169 | ||||
|
170 | o.verify() | |||
|
171 |
@@ -0,0 +1,233 b'' | |||||
|
1 | # encoding: utf-8 | |||
|
2 | ||||
|
3 | """A parallelized version of Python's builtin map.""" | |||
|
4 | ||||
|
5 | __docformat__ = "restructuredtext en" | |||
|
6 | ||||
|
7 | #---------------------------------------------------------------------------- | |||
|
8 | # Copyright (C) 2008 The IPython Development Team | |||
|
9 | # | |||
|
10 | # Distributed under the terms of the BSD License. The full license is in | |||
|
11 | # the file COPYING, distributed as part of this software. | |||
|
12 | #---------------------------------------------------------------------------- | |||
|
13 | ||||
|
14 | #---------------------------------------------------------------------------- | |||
|
15 | # Imports | |||
|
16 | #---------------------------------------------------------------------------- | |||
|
17 | ||||
|
18 | from types import FunctionType | |||
|
19 | from zope.interface import Interface, implements | |||
|
20 | from IPython.kernel.task import MapTask | |||
|
21 | from IPython.kernel.twistedutil import DeferredList, gatherBoth | |||
|
22 | from IPython.kernel.util import printer | |||
|
23 | from IPython.kernel.error import collect_exceptions | |||
|
24 | ||||
|
25 | #---------------------------------------------------------------------------- | |||
|
26 | # Code | |||
|
27 | #---------------------------------------------------------------------------- | |||
|
28 | ||||
|
29 | class IMapper(Interface): | |||
|
30 | """The basic interface for a Mapper. | |||
|
31 | ||||
|
32 | This defines a generic interface for mapping. The idea of this is | |||
|
33 | similar to that of Python's builtin `map` function, which applies a function | |||
|
34 | elementwise to a sequence. | |||
|
35 | """ | |||
|
36 | ||||
|
37 | def map(func, *seqs): | |||
|
38 | """Do map in parallel. | |||
|
39 | ||||
|
40 | Equivalent to map(func, *seqs) or: | |||
|
41 | ||||
|
42 | [func(seqs[0][0], seqs[1][0],...), func(seqs[0][1], seqs[1][1],...),...] | |||
|
43 | ||||
|
44 | :Parameters: | |||
|
45 | func : FunctionType | |||
|
46 | The function to apply to the sequence | |||
|
47 | sequences : tuple of iterables | |||
|
48 | A sequence of iterables that are used for sucessive function | |||
|
49 | arguments. This work just like map | |||
|
50 | """ | |||
|
51 | ||||
|
52 | class IMultiEngineMapperFactory(Interface): | |||
|
53 | """ | |||
|
54 | An interface for something that creates `IMapper` instances. | |||
|
55 | """ | |||
|
56 | ||||
|
57 | def mapper(dist='b', targets='all', block=True): | |||
|
58 | """ | |||
|
59 | Create an `IMapper` implementer with a given set of arguments. | |||
|
60 | ||||
|
61 | The `IMapper` created using a multiengine controller is | |||
|
62 | not load balanced. | |||
|
63 | """ | |||
|
64 | ||||
|
65 | class ITaskMapperFactory(Interface): | |||
|
66 | """ | |||
|
67 | An interface for something that creates `IMapper` instances. | |||
|
68 | """ | |||
|
69 | ||||
|
70 | def mapper(clear_before=False, clear_after=False, retries=0, | |||
|
71 | recovery_task=None, depend=None, block=True): | |||
|
72 | """ | |||
|
73 | Create an `IMapper` implementer with a given set of arguments. | |||
|
74 | ||||
|
75 | The `IMapper` created using a task controller is load balanced. | |||
|
76 | ||||
|
77 | See the documentation for `IPython.kernel.task.BaseTask` for | |||
|
78 | documentation on the arguments to this method. | |||
|
79 | """ | |||
|
80 | ||||
|
81 | ||||
|
82 | class MultiEngineMapper(object): | |||
|
83 | """ | |||
|
84 | A Mapper for `IMultiEngine` implementers. | |||
|
85 | """ | |||
|
86 | ||||
|
87 | implements(IMapper) | |||
|
88 | ||||
|
89 | def __init__(self, multiengine, dist='b', targets='all', block=True): | |||
|
90 | """ | |||
|
91 | Create a Mapper for a multiengine. | |||
|
92 | ||||
|
93 | The value of all arguments are used for all calls to `map`. This | |||
|
94 | class allows these arguemnts to be set for a series of map calls. | |||
|
95 | ||||
|
96 | :Parameters: | |||
|
97 | multiengine : `IMultiEngine` implementer | |||
|
98 | The multiengine to use for running the map commands | |||
|
99 | dist : str | |||
|
100 | The type of decomposition to use. Only block ('b') is | |||
|
101 | supported currently | |||
|
102 | targets : (str, int, tuple of ints) | |||
|
103 | The engines to use in the map | |||
|
104 | block : boolean | |||
|
105 | Whether to block when the map is applied | |||
|
106 | """ | |||
|
107 | self.multiengine = multiengine | |||
|
108 | self.dist = dist | |||
|
109 | self.targets = targets | |||
|
110 | self.block = block | |||
|
111 | ||||
|
112 | def map(self, func, *sequences): | |||
|
113 | """ | |||
|
114 | Apply func to *sequences elementwise. Like Python's builtin map. | |||
|
115 | ||||
|
116 | This version is not load balanced. | |||
|
117 | """ | |||
|
118 | max_len = max(len(s) for s in sequences) | |||
|
119 | for s in sequences: | |||
|
120 | if len(s)!=max_len: | |||
|
121 | raise ValueError('all sequences must have equal length') | |||
|
122 | assert isinstance(func, (str, FunctionType)), "func must be a fuction or str" | |||
|
123 | return self.multiengine.raw_map(func, sequences, dist=self.dist, | |||
|
124 | targets=self.targets, block=self.block) | |||
|
125 | ||||
|
126 | class TaskMapper(object): | |||
|
127 | """ | |||
|
128 | Make an `ITaskController` look like an `IMapper`. | |||
|
129 | ||||
|
130 | This class provides a load balanced version of `map`. | |||
|
131 | """ | |||
|
132 | ||||
|
133 | def __init__(self, task_controller, clear_before=False, clear_after=False, retries=0, | |||
|
134 | recovery_task=None, depend=None, block=True): | |||
|
135 | """ | |||
|
136 | Create a `IMapper` given a `TaskController` and arguments. | |||
|
137 | ||||
|
138 | The additional arguments are those that are common to all types of | |||
|
139 | tasks and are described in the documentation for | |||
|
140 | `IPython.kernel.task.BaseTask`. | |||
|
141 | ||||
|
142 | :Parameters: | |||
|
143 | task_controller : an `IBlockingTaskClient` implementer | |||
|
144 | The `TaskController` to use for calls to `map` | |||
|
145 | """ | |||
|
146 | self.task_controller = task_controller | |||
|
147 | self.clear_before = clear_before | |||
|
148 | self.clear_after = clear_after | |||
|
149 | self.retries = retries | |||
|
150 | self.recovery_task = recovery_task | |||
|
151 | self.depend = depend | |||
|
152 | self.block = block | |||
|
153 | ||||
|
154 | def map(self, func, *sequences): | |||
|
155 | """ | |||
|
156 | Apply func to *sequences elementwise. Like Python's builtin map. | |||
|
157 | ||||
|
158 | This version is load balanced. | |||
|
159 | """ | |||
|
160 | max_len = max(len(s) for s in sequences) | |||
|
161 | for s in sequences: | |||
|
162 | if len(s)!=max_len: | |||
|
163 | raise ValueError('all sequences must have equal length') | |||
|
164 | task_args = zip(*sequences) | |||
|
165 | task_ids = [] | |||
|
166 | dlist = [] | |||
|
167 | for ta in task_args: | |||
|
168 | task = MapTask(func, ta, clear_before=self.clear_before, | |||
|
169 | clear_after=self.clear_after, retries=self.retries, | |||
|
170 | recovery_task=self.recovery_task, depend=self.depend) | |||
|
171 | dlist.append(self.task_controller.run(task)) | |||
|
172 | dlist = gatherBoth(dlist, consumeErrors=1) | |||
|
173 | dlist.addCallback(collect_exceptions,'map') | |||
|
174 | if self.block: | |||
|
175 | def get_results(task_ids): | |||
|
176 | d = self.task_controller.barrier(task_ids) | |||
|
177 | d.addCallback(lambda _: gatherBoth([self.task_controller.get_task_result(tid) for tid in task_ids], consumeErrors=1)) | |||
|
178 | d.addCallback(collect_exceptions, 'map') | |||
|
179 | return d | |||
|
180 | dlist.addCallback(get_results) | |||
|
181 | return dlist | |||
|
182 | ||||
|
183 | class SynchronousTaskMapper(object): | |||
|
184 | """ | |||
|
185 | Make an `IBlockingTaskClient` look like an `IMapper`. | |||
|
186 | ||||
|
187 | This class provides a load balanced version of `map`. | |||
|
188 | """ | |||
|
189 | ||||
|
190 | def __init__(self, task_controller, clear_before=False, clear_after=False, retries=0, | |||
|
191 | recovery_task=None, depend=None, block=True): | |||
|
192 | """ | |||
|
193 | Create a `IMapper` given a `IBlockingTaskClient` and arguments. | |||
|
194 | ||||
|
195 | The additional arguments are those that are common to all types of | |||
|
196 | tasks and are described in the documentation for | |||
|
197 | `IPython.kernel.task.BaseTask`. | |||
|
198 | ||||
|
199 | :Parameters: | |||
|
200 | task_controller : an `IBlockingTaskClient` implementer | |||
|
201 | The `TaskController` to use for calls to `map` | |||
|
202 | """ | |||
|
203 | self.task_controller = task_controller | |||
|
204 | self.clear_before = clear_before | |||
|
205 | self.clear_after = clear_after | |||
|
206 | self.retries = retries | |||
|
207 | self.recovery_task = recovery_task | |||
|
208 | self.depend = depend | |||
|
209 | self.block = block | |||
|
210 | ||||
|
211 | def map(self, func, *sequences): | |||
|
212 | """ | |||
|
213 | Apply func to *sequences elementwise. Like Python's builtin map. | |||
|
214 | ||||
|
215 | This version is load balanced. | |||
|
216 | """ | |||
|
217 | max_len = max(len(s) for s in sequences) | |||
|
218 | for s in sequences: | |||
|
219 | if len(s)!=max_len: | |||
|
220 | raise ValueError('all sequences must have equal length') | |||
|
221 | task_args = zip(*sequences) | |||
|
222 | task_ids = [] | |||
|
223 | for ta in task_args: | |||
|
224 | task = MapTask(func, ta, clear_before=self.clear_before, | |||
|
225 | clear_after=self.clear_after, retries=self.retries, | |||
|
226 | recovery_task=self.recovery_task, depend=self.depend) | |||
|
227 | task_ids.append(self.task_controller.run(task)) | |||
|
228 | if self.block: | |||
|
229 | self.task_controller.barrier(task_ids) | |||
|
230 | task_results = [self.task_controller.get_task_result(tid) for tid in task_ids] | |||
|
231 | return task_results | |||
|
232 | else: | |||
|
233 | return task_ids No newline at end of file |
@@ -0,0 +1,41 b'' | |||||
|
1 | from __future__ import with_statement | |||
|
2 | ||||
|
3 | #def test_simple(): | |||
|
4 | if 0: | |||
|
5 | ||||
|
6 | # XXX - for now, we need a running cluster to be started separately. The | |||
|
7 | # daemon work is almost finished, and will make much of this unnecessary. | |||
|
8 | from IPython.kernel import client | |||
|
9 | mec = client.MultiEngineClient(('127.0.0.1',10105)) | |||
|
10 | ||||
|
11 | try: | |||
|
12 | mec.get_ids() | |||
|
13 | except ConnectionRefusedError: | |||
|
14 | import os, time | |||
|
15 | os.system('ipcluster -n 2 &') | |||
|
16 | time.sleep(2) | |||
|
17 | mec = client.MultiEngineClient(('127.0.0.1',10105)) | |||
|
18 | ||||
|
19 | mec.block = False | |||
|
20 | ||||
|
21 | import itertools | |||
|
22 | c = itertools.count() | |||
|
23 | ||||
|
24 | parallel = RemoteMultiEngine(mec) | |||
|
25 | ||||
|
26 | mec.pushAll() | |||
|
27 | ||||
|
28 | with parallel as pr: | |||
|
29 | # A comment | |||
|
30 | remote() # this means the code below only runs remotely | |||
|
31 | print 'Hello remote world' | |||
|
32 | x = range(10) | |||
|
33 | # Comments are OK | |||
|
34 | # Even misindented. | |||
|
35 | y = x+1 | |||
|
36 | ||||
|
37 | ||||
|
38 | with pfor('i',sequence) as pr: | |||
|
39 | print x[i] | |||
|
40 | ||||
|
41 | print pr.x + pr.y |
@@ -0,0 +1,146 b'' | |||||
|
1 | ## The basic trick is to generate the source code for the decorated function | |||
|
2 | ## with the right signature and to evaluate it. | |||
|
3 | ## Uncomment the statement 'print >> sys.stderr, func_src' in _decorate | |||
|
4 | ## to understand what is going on. | |||
|
5 | ||||
|
6 | __all__ = ["decorator", "update_wrapper", "getinfo"] | |||
|
7 | ||||
|
8 | import inspect, sys | |||
|
9 | ||||
|
10 | def getinfo(func): | |||
|
11 | """ | |||
|
12 | Returns an info dictionary containing: | |||
|
13 | - name (the name of the function : str) | |||
|
14 | - argnames (the names of the arguments : list) | |||
|
15 | - defaults (the values of the default arguments : tuple) | |||
|
16 | - signature (the signature : str) | |||
|
17 | - doc (the docstring : str) | |||
|
18 | - module (the module name : str) | |||
|
19 | - dict (the function __dict__ : str) | |||
|
20 | ||||
|
21 | >>> def f(self, x=1, y=2, *args, **kw): pass | |||
|
22 | ||||
|
23 | >>> info = getinfo(f) | |||
|
24 | ||||
|
25 | >>> info["name"] | |||
|
26 | 'f' | |||
|
27 | >>> info["argnames"] | |||
|
28 | ['self', 'x', 'y', 'args', 'kw'] | |||
|
29 | ||||
|
30 | >>> info["defaults"] | |||
|
31 | (1, 2) | |||
|
32 | ||||
|
33 | >>> info["signature"] | |||
|
34 | 'self, x, y, *args, **kw' | |||
|
35 | """ | |||
|
36 | assert inspect.ismethod(func) or inspect.isfunction(func) | |||
|
37 | regargs, varargs, varkwargs, defaults = inspect.getargspec(func) | |||
|
38 | argnames = list(regargs) | |||
|
39 | if varargs: | |||
|
40 | argnames.append(varargs) | |||
|
41 | if varkwargs: | |||
|
42 | argnames.append(varkwargs) | |||
|
43 | signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults, | |||
|
44 | formatvalue=lambda value: "")[1:-1] | |||
|
45 | return dict(name=func.__name__, argnames=argnames, signature=signature, | |||
|
46 | defaults = func.func_defaults, doc=func.__doc__, | |||
|
47 | module=func.__module__, dict=func.__dict__, | |||
|
48 | globals=func.func_globals, closure=func.func_closure) | |||
|
49 | ||||
|
50 | def update_wrapper(wrapper, wrapped, create=False): | |||
|
51 | """ | |||
|
52 | An improvement over functools.update_wrapper. By default it works the | |||
|
53 | same, but if the 'create' flag is set, generates a copy of the wrapper | |||
|
54 | with the right signature and update the copy, not the original. | |||
|
55 | Moreovoer, 'wrapped' can be a dictionary with keys 'name', 'doc', 'module', | |||
|
56 | 'dict', 'defaults'. | |||
|
57 | """ | |||
|
58 | if isinstance(wrapped, dict): | |||
|
59 | infodict = wrapped | |||
|
60 | else: # assume wrapped is a function | |||
|
61 | infodict = getinfo(wrapped) | |||
|
62 | assert not '_wrapper_' in infodict["argnames"], \ | |||
|
63 | '"_wrapper_" is a reserved argument name!' | |||
|
64 | if create: # create a brand new wrapper with the right signature | |||
|
65 | src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict | |||
|
66 | # import sys; print >> sys.stderr, src # for debugging purposes | |||
|
67 | wrapper = eval(src, dict(_wrapper_=wrapper)) | |||
|
68 | try: | |||
|
69 | wrapper.__name__ = infodict['name'] | |||
|
70 | except: # Python version < 2.4 | |||
|
71 | pass | |||
|
72 | wrapper.__doc__ = infodict['doc'] | |||
|
73 | wrapper.__module__ = infodict['module'] | |||
|
74 | wrapper.__dict__.update(infodict['dict']) | |||
|
75 | wrapper.func_defaults = infodict['defaults'] | |||
|
76 | return wrapper | |||
|
77 | ||||
|
78 | # the real meat is here | |||
|
79 | def _decorator(caller, func): | |||
|
80 | infodict = getinfo(func) | |||
|
81 | argnames = infodict['argnames'] | |||
|
82 | assert not ('_call_' in argnames or '_func_' in argnames), \ | |||
|
83 | 'You cannot use _call_ or _func_ as argument names!' | |||
|
84 | src = "lambda %(signature)s: _call_(_func_, %(signature)s)" % infodict | |||
|
85 | dec_func = eval(src, dict(_func_=func, _call_=caller)) | |||
|
86 | return update_wrapper(dec_func, func) | |||
|
87 | ||||
|
88 | def decorator(caller, func=None): | |||
|
89 | """ | |||
|
90 | General purpose decorator factory: takes a caller function as | |||
|
91 | input and returns a decorator with the same attributes. | |||
|
92 | A caller function is any function like this:: | |||
|
93 | ||||
|
94 | def caller(func, *args, **kw): | |||
|
95 | # do something | |||
|
96 | return func(*args, **kw) | |||
|
97 | ||||
|
98 | Here is an example of usage: | |||
|
99 | ||||
|
100 | >>> @decorator | |||
|
101 | ... def chatty(f, *args, **kw): | |||
|
102 | ... print "Calling %r" % f.__name__ | |||
|
103 | ... return f(*args, **kw) | |||
|
104 | ||||
|
105 | >>> chatty.__name__ | |||
|
106 | 'chatty' | |||
|
107 | ||||
|
108 | >>> @chatty | |||
|
109 | ... def f(): pass | |||
|
110 | ... | |||
|
111 | >>> f() | |||
|
112 | Calling 'f' | |||
|
113 | ||||
|
114 | For sake of convenience, the decorator factory can also be called with | |||
|
115 | two arguments. In this casem ``decorator(caller, func)`` is just a | |||
|
116 | shortcut for ``decorator(caller)(func)``. | |||
|
117 | """ | |||
|
118 | if func is None: # return a decorator function | |||
|
119 | return update_wrapper(lambda f : _decorator(caller, f), caller) | |||
|
120 | else: # return a decorated function | |||
|
121 | return _decorator(caller, func) | |||
|
122 | ||||
|
123 | if __name__ == "__main__": | |||
|
124 | import doctest; doctest.testmod() | |||
|
125 | ||||
|
126 | ####################### LEGALESE ################################## | |||
|
127 | ||||
|
128 | ## Redistributions of source code must retain the above copyright | |||
|
129 | ## notice, this list of conditions and the following disclaimer. | |||
|
130 | ## Redistributions in bytecode form must reproduce the above copyright | |||
|
131 | ## notice, this list of conditions and the following disclaimer in | |||
|
132 | ## the documentation and/or other materials provided with the | |||
|
133 | ## distribution. | |||
|
134 | ||||
|
135 | ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
|
136 | ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
|
137 | ## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
|
138 | ## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||
|
139 | ## HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
|
140 | ## INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |||
|
141 | ## BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | |||
|
142 | ## OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
|
143 | ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |||
|
144 | ## TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | |||
|
145 | ## USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |||
|
146 | ## DAMAGE. |
@@ -0,0 +1,133 b'' | |||||
|
1 | """Decorators for labeling test objects. | |||
|
2 | ||||
|
3 | Decorators that merely return a modified version of the original | |||
|
4 | function object are straightforward. Decorators that return a new | |||
|
5 | function object need to use | |||
|
6 | nose.tools.make_decorator(original_function)(decorator) in returning | |||
|
7 | the decorator, in order to preserve metadata such as function name, | |||
|
8 | setup and teardown functions and so on - see nose.tools for more | |||
|
9 | information. | |||
|
10 | ||||
|
11 | NOTE: This file contains IPython-specific decorators and imports the | |||
|
12 | numpy.testing.decorators file, which we've copied verbatim. Any of our own | |||
|
13 | code will be added at the bottom if we end up extending this. | |||
|
14 | """ | |||
|
15 | ||||
|
16 | # Stdlib imports | |||
|
17 | import inspect | |||
|
18 | ||||
|
19 | # Third-party imports | |||
|
20 | ||||
|
21 | # This is Michele Simionato's decorator module, also kept verbatim. | |||
|
22 | from decorator_msim import decorator, update_wrapper | |||
|
23 | ||||
|
24 | # Grab the numpy-specific decorators which we keep in a file that we | |||
|
25 | # occasionally update from upstream: decorators_numpy.py is an IDENTICAL copy | |||
|
26 | # of numpy.testing.decorators. | |||
|
27 | from decorators_numpy import * | |||
|
28 | ||||
|
29 | ############################################################################## | |||
|
30 | # Local code begins | |||
|
31 | ||||
|
32 | # Utility functions | |||
|
33 | ||||
|
34 | def apply_wrapper(wrapper,func): | |||
|
35 | """Apply a wrapper to a function for decoration. | |||
|
36 | ||||
|
37 | This mixes Michele Simionato's decorator tool with nose's make_decorator, | |||
|
38 | to apply a wrapper in a decorator so that all nose attributes, as well as | |||
|
39 | function signature and other properties, survive the decoration cleanly. | |||
|
40 | This will ensure that wrapped functions can still be well introspected via | |||
|
41 | IPython, for example. | |||
|
42 | """ | |||
|
43 | import nose.tools | |||
|
44 | ||||
|
45 | return decorator(wrapper,nose.tools.make_decorator(func)(wrapper)) | |||
|
46 | ||||
|
47 | ||||
|
48 | def make_label_dec(label,ds=None): | |||
|
49 | """Factory function to create a decorator that applies one or more labels. | |||
|
50 | ||||
|
51 | :Parameters: | |||
|
52 | label : string or sequence | |||
|
53 | One or more labels that will be applied by the decorator to the functions | |||
|
54 | it decorates. Labels are attributes of the decorated function with their | |||
|
55 | value set to True. | |||
|
56 | ||||
|
57 | :Keywords: | |||
|
58 | ds : string | |||
|
59 | An optional docstring for the resulting decorator. If not given, a | |||
|
60 | default docstring is auto-generated. | |||
|
61 | ||||
|
62 | :Returns: | |||
|
63 | A decorator. | |||
|
64 | ||||
|
65 | :Examples: | |||
|
66 | ||||
|
67 | A simple labeling decorator: | |||
|
68 | >>> slow = make_label_dec('slow') | |||
|
69 | >>> print slow.__doc__ | |||
|
70 | Labels a test as 'slow'. | |||
|
71 | ||||
|
72 | And one that uses multiple labels and a custom docstring: | |||
|
73 | >>> rare = make_label_dec(['slow','hard'], | |||
|
74 | ... "Mix labels 'slow' and 'hard' for rare tests.") | |||
|
75 | >>> print rare.__doc__ | |||
|
76 | Mix labels 'slow' and 'hard' for rare tests. | |||
|
77 | ||||
|
78 | Now, let's test using this one: | |||
|
79 | >>> @rare | |||
|
80 | ... def f(): pass | |||
|
81 | ... | |||
|
82 | >>> | |||
|
83 | >>> f.slow | |||
|
84 | True | |||
|
85 | >>> f.hard | |||
|
86 | True | |||
|
87 | """ | |||
|
88 | ||||
|
89 | if isinstance(label,basestring): | |||
|
90 | labels = [label] | |||
|
91 | else: | |||
|
92 | labels = label | |||
|
93 | ||||
|
94 | # Validate that the given label(s) are OK for use in setattr() by doing a | |||
|
95 | # dry run on a dummy function. | |||
|
96 | tmp = lambda : None | |||
|
97 | for label in labels: | |||
|
98 | setattr(tmp,label,True) | |||
|
99 | ||||
|
100 | # This is the actual decorator we'll return | |||
|
101 | def decor(f): | |||
|
102 | for label in labels: | |||
|
103 | setattr(f,label,True) | |||
|
104 | return f | |||
|
105 | ||||
|
106 | # Apply the user's docstring, or autogenerate a basic one | |||
|
107 | if ds is None: | |||
|
108 | ds = "Labels a test as %r." % label | |||
|
109 | decor.__doc__ = ds | |||
|
110 | ||||
|
111 | return decor | |||
|
112 | ||||
|
113 | #----------------------------------------------------------------------------- | |||
|
114 | # Decorators for public use | |||
|
115 | ||||
|
116 | skip_doctest = make_label_dec('skip_doctest', | |||
|
117 | """Decorator - mark a function or method for skipping its doctest. | |||
|
118 | ||||
|
119 | This decorator allows you to mark a function whose docstring you wish to | |||
|
120 | omit from testing, while preserving the docstring for introspection, help, | |||
|
121 | etc.""") | |||
|
122 | ||||
|
123 | ||||
|
124 | def skip(func): | |||
|
125 | """Decorator - mark a test function for skipping from test suite.""" | |||
|
126 | ||||
|
127 | import nose | |||
|
128 | ||||
|
129 | def wrapper(*a,**k): | |||
|
130 | raise nose.SkipTest("Skipping test for function: %s" % | |||
|
131 | func.__name__) | |||
|
132 | ||||
|
133 | return apply_wrapper(wrapper,func) |
@@ -0,0 +1,94 b'' | |||||
|
1 | """Decorators for labeling test objects | |||
|
2 | ||||
|
3 | Decorators that merely return a modified version of the original | |||
|
4 | function object are straightforward. Decorators that return a new | |||
|
5 | function object need to use | |||
|
6 | nose.tools.make_decorator(original_function)(decorator) in returning | |||
|
7 | the decorator, in order to preserve metadata such as function name, | |||
|
8 | setup and teardown functions and so on - see nose.tools for more | |||
|
9 | information. | |||
|
10 | ||||
|
11 | """ | |||
|
12 | ||||
|
13 | def slow(t): | |||
|
14 | """Labels a test as 'slow'. | |||
|
15 | ||||
|
16 | The exact definition of a slow test is obviously both subjective and | |||
|
17 | hardware-dependent, but in general any individual test that requires more | |||
|
18 | than a second or two should be labeled as slow (the whole suite consits of | |||
|
19 | thousands of tests, so even a second is significant).""" | |||
|
20 | ||||
|
21 | t.slow = True | |||
|
22 | return t | |||
|
23 | ||||
|
24 | def setastest(tf=True): | |||
|
25 | ''' Signals to nose that this function is or is not a test | |||
|
26 | ||||
|
27 | Parameters | |||
|
28 | ---------- | |||
|
29 | tf : bool | |||
|
30 | If True specifies this is a test, not a test otherwise | |||
|
31 | ||||
|
32 | e.g | |||
|
33 | >>> from numpy.testing.decorators import setastest | |||
|
34 | >>> @setastest(False) | |||
|
35 | ... def func_with_test_in_name(arg1, arg2): pass | |||
|
36 | ... | |||
|
37 | >>> | |||
|
38 | ||||
|
39 | This decorator cannot use the nose namespace, because it can be | |||
|
40 | called from a non-test module. See also istest and nottest in | |||
|
41 | nose.tools | |||
|
42 | ||||
|
43 | ''' | |||
|
44 | def set_test(t): | |||
|
45 | t.__test__ = tf | |||
|
46 | return t | |||
|
47 | return set_test | |||
|
48 | ||||
|
49 | def skipif(skip_condition, msg=None): | |||
|
50 | ''' Make function raise SkipTest exception if skip_condition is true | |||
|
51 | ||||
|
52 | Parameters | |||
|
53 | --------- | |||
|
54 | skip_condition : bool | |||
|
55 | Flag to determine whether to skip test (True) or not (False) | |||
|
56 | msg : string | |||
|
57 | Message to give on raising a SkipTest exception | |||
|
58 | ||||
|
59 | Returns | |||
|
60 | ------- | |||
|
61 | decorator : function | |||
|
62 | Decorator, which, when applied to a function, causes SkipTest | |||
|
63 | to be raised when the skip_condition was True, and the function | |||
|
64 | to be called normally otherwise. | |||
|
65 | ||||
|
66 | Notes | |||
|
67 | ----- | |||
|
68 | You will see from the code that we had to further decorate the | |||
|
69 | decorator with the nose.tools.make_decorator function in order to | |||
|
70 | transmit function name, and various other metadata. | |||
|
71 | ''' | |||
|
72 | if msg is None: | |||
|
73 | msg = 'Test skipped due to test condition' | |||
|
74 | def skip_decorator(f): | |||
|
75 | # Local import to avoid a hard nose dependency and only incur the | |||
|
76 | # import time overhead at actual test-time. | |||
|
77 | import nose | |||
|
78 | def skipper(*args, **kwargs): | |||
|
79 | if skip_condition: | |||
|
80 | raise nose.SkipTest, msg | |||
|
81 | else: | |||
|
82 | return f(*args, **kwargs) | |||
|
83 | return nose.tools.make_decorator(f)(skipper) | |||
|
84 | return skip_decorator | |||
|
85 | ||||
|
86 | def skipknownfailure(f): | |||
|
87 | ''' Decorator to raise SkipTest for test known to fail | |||
|
88 | ''' | |||
|
89 | # Local import to avoid a hard nose dependency and only incur the | |||
|
90 | # import time overhead at actual test-time. | |||
|
91 | import nose | |||
|
92 | def skipper(*args, **kwargs): | |||
|
93 | raise nose.SkipTest, 'This test is known to fail' | |||
|
94 | return nose.tools.make_decorator(f)(skipper) |
@@ -0,0 +1,17 b'' | |||||
|
1 | """Simple script to show reference holding behavior. | |||
|
2 | ||||
|
3 | This is used by a companion test case. | |||
|
4 | """ | |||
|
5 | ||||
|
6 | import gc | |||
|
7 | ||||
|
8 | class C(object): | |||
|
9 | def __del__(self): | |||
|
10 | print 'deleting object...' | |||
|
11 | ||||
|
12 | c = C() | |||
|
13 | ||||
|
14 | c_refs = gc.get_referrers(c) | |||
|
15 | ref_ids = map(id,c_refs) | |||
|
16 | ||||
|
17 | print 'c referrers:',map(type,c_refs) |
@@ -0,0 +1,180 b'' | |||||
|
1 | # Module imports | |||
|
2 | # Std lib | |||
|
3 | import inspect | |||
|
4 | ||||
|
5 | # Third party | |||
|
6 | ||||
|
7 | # Our own | |||
|
8 | from IPython.testing import decorators as dec | |||
|
9 | ||||
|
10 | #----------------------------------------------------------------------------- | |||
|
11 | # Utilities | |||
|
12 | ||||
|
13 | # Note: copied from OInspect, kept here so the testing stuff doesn't create | |||
|
14 | # circular dependencies and is easier to reuse. | |||
|
15 | def getargspec(obj): | |||
|
16 | """Get the names and default values of a function's arguments. | |||
|
17 | ||||
|
18 | A tuple of four things is returned: (args, varargs, varkw, defaults). | |||
|
19 | 'args' is a list of the argument names (it may contain nested lists). | |||
|
20 | 'varargs' and 'varkw' are the names of the * and ** arguments or None. | |||
|
21 | 'defaults' is an n-tuple of the default values of the last n arguments. | |||
|
22 | ||||
|
23 | Modified version of inspect.getargspec from the Python Standard | |||
|
24 | Library.""" | |||
|
25 | ||||
|
26 | if inspect.isfunction(obj): | |||
|
27 | func_obj = obj | |||
|
28 | elif inspect.ismethod(obj): | |||
|
29 | func_obj = obj.im_func | |||
|
30 | else: | |||
|
31 | raise TypeError, 'arg is not a Python function' | |||
|
32 | args, varargs, varkw = inspect.getargs(func_obj.func_code) | |||
|
33 | return args, varargs, varkw, func_obj.func_defaults | |||
|
34 | ||||
|
35 | #----------------------------------------------------------------------------- | |||
|
36 | # Testing functions | |||
|
37 | ||||
|
38 | def test_trivial(): | |||
|
39 | """A trivial passing test.""" | |||
|
40 | pass | |||
|
41 | ||||
|
42 | ||||
|
43 | @dec.skip | |||
|
44 | def test_deliberately_broken(): | |||
|
45 | """A deliberately broken test - we want to skip this one.""" | |||
|
46 | 1/0 | |||
|
47 | ||||
|
48 | ||||
|
49 | # Verify that we can correctly skip the doctest for a function at will, but | |||
|
50 | # that the docstring itself is NOT destroyed by the decorator. | |||
|
51 | @dec.skip_doctest | |||
|
52 | def doctest_bad(x,y=1,**k): | |||
|
53 | """A function whose doctest we need to skip. | |||
|
54 | ||||
|
55 | >>> 1+1 | |||
|
56 | 3 | |||
|
57 | """ | |||
|
58 | print 'x:',x | |||
|
59 | print 'y:',y | |||
|
60 | print 'k:',k | |||
|
61 | ||||
|
62 | ||||
|
63 | def call_doctest_bad(): | |||
|
64 | """Check that we can still call the decorated functions. | |||
|
65 | ||||
|
66 | >>> doctest_bad(3,y=4) | |||
|
67 | x: 3 | |||
|
68 | y: 4 | |||
|
69 | k: {} | |||
|
70 | """ | |||
|
71 | pass | |||
|
72 | ||||
|
73 | ||||
|
74 | # Doctest skipping should work for class methods too | |||
|
75 | class foo(object): | |||
|
76 | """Foo | |||
|
77 | ||||
|
78 | Example: | |||
|
79 | ||||
|
80 | >>> 1+1 | |||
|
81 | 2 | |||
|
82 | """ | |||
|
83 | ||||
|
84 | @dec.skip_doctest | |||
|
85 | def __init__(self,x): | |||
|
86 | """Make a foo. | |||
|
87 | ||||
|
88 | Example: | |||
|
89 | ||||
|
90 | >>> f = foo(3) | |||
|
91 | junk | |||
|
92 | """ | |||
|
93 | print 'Making a foo.' | |||
|
94 | self.x = x | |||
|
95 | ||||
|
96 | @dec.skip_doctest | |||
|
97 | def bar(self,y): | |||
|
98 | """Example: | |||
|
99 | ||||
|
100 | >>> f = foo(3) | |||
|
101 | >>> f.bar(0) | |||
|
102 | boom! | |||
|
103 | >>> 1/0 | |||
|
104 | bam! | |||
|
105 | """ | |||
|
106 | return 1/y | |||
|
107 | ||||
|
108 | def baz(self,y): | |||
|
109 | """Example: | |||
|
110 | ||||
|
111 | >>> f = foo(3) | |||
|
112 | Making a foo. | |||
|
113 | >>> f.baz(3) | |||
|
114 | True | |||
|
115 | """ | |||
|
116 | return self.x==y | |||
|
117 | ||||
|
118 | ||||
|
119 | def test_skip_dt_decorator(): | |||
|
120 | """Doctest-skipping decorator should preserve the docstring. | |||
|
121 | """ | |||
|
122 | # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring! | |||
|
123 | check = """A function whose doctest we need to skip. | |||
|
124 | ||||
|
125 | >>> 1+1 | |||
|
126 | 3 | |||
|
127 | """ | |||
|
128 | # Fetch the docstring from doctest_bad after decoration. | |||
|
129 | val = doctest_bad.__doc__ | |||
|
130 | ||||
|
131 | assert check==val,"doctest_bad docstrings don't match" | |||
|
132 | ||||
|
133 | ||||
|
134 | def test_skip_dt_decorator2(): | |||
|
135 | """Doctest-skipping decorator should preserve function signature. | |||
|
136 | """ | |||
|
137 | # Hardcoded correct answer | |||
|
138 | dtargs = (['x', 'y'], None, 'k', (1,)) | |||
|
139 | # Introspect out the value | |||
|
140 | dtargsr = getargspec(doctest_bad) | |||
|
141 | assert dtargsr==dtargs, \ | |||
|
142 | "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,) | |||
|
143 | ||||
|
144 | ||||
|
145 | def doctest_run(): | |||
|
146 | """Test running a trivial script. | |||
|
147 | ||||
|
148 | In [13]: run simplevars.py | |||
|
149 | x is: 1 | |||
|
150 | """ | |||
|
151 | ||||
|
152 | #@dec.skip_doctest | |||
|
153 | def doctest_runvars(): | |||
|
154 | """Test that variables defined in scripts get loaded correcly via %run. | |||
|
155 | ||||
|
156 | In [13]: run simplevars.py | |||
|
157 | x is: 1 | |||
|
158 | ||||
|
159 | In [14]: x | |||
|
160 | Out[14]: 1 | |||
|
161 | """ | |||
|
162 | ||||
|
163 | def doctest_ivars(): | |||
|
164 | """Test that variables defined interactively are picked up. | |||
|
165 | In [5]: zz=1 | |||
|
166 | ||||
|
167 | In [6]: zz | |||
|
168 | Out[6]: 1 | |||
|
169 | """ | |||
|
170 | ||||
|
171 | @dec.skip_doctest | |||
|
172 | def doctest_refs(): | |||
|
173 | """DocTest reference holding issues when running scripts. | |||
|
174 | ||||
|
175 | In [32]: run show_refs.py | |||
|
176 | c referrers: [<type 'dict'>] | |||
|
177 | ||||
|
178 | In [33]: map(type,gc.get_referrers(c)) | |||
|
179 | Out[33]: [<type 'dict'>] | |||
|
180 | """ |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -0,0 +1,18 b'' | |||||
|
1 | from IPython.kernel import client | |||
|
2 | ||||
|
3 | mec = client.MultiEngineClient() | |||
|
4 | ||||
|
5 | result = mec.map(lambda x: 2*x, range(10)) | |||
|
6 | print "Simple, default map: ", result | |||
|
7 | ||||
|
8 | m = mec.mapper(block=False) | |||
|
9 | pr = m.map(lambda x: 2*x, range(10)) | |||
|
10 | print "Submitted map, got PendingResult: ", pr | |||
|
11 | result = pr.r | |||
|
12 | print "Using a mapper: ", result | |||
|
13 | ||||
|
14 | @mec.parallel() | |||
|
15 | def f(x): return 2*x | |||
|
16 | ||||
|
17 | result = f(range(10)) | |||
|
18 | print "Using a parallel function: ", result No newline at end of file |
@@ -0,0 +1,19 b'' | |||||
|
1 | from IPython.kernel import client | |||
|
2 | ||||
|
3 | tc = client.TaskClient() | |||
|
4 | ||||
|
5 | result = tc.map(lambda x: 2*x, range(10)) | |||
|
6 | print "Simple, default map: ", result | |||
|
7 | ||||
|
8 | m = tc.mapper(block=False, clear_after=True, clear_before=True) | |||
|
9 | tids = m.map(lambda x: 2*x, range(10)) | |||
|
10 | print "Submitted tasks, got ids: ", tids | |||
|
11 | tc.barrier(tids) | |||
|
12 | result = [tc.get_task_result(tid) for tid in tids] | |||
|
13 | print "Using a mapper: ", result | |||
|
14 | ||||
|
15 | @tc.parallel() | |||
|
16 | def f(x): return 2*x | |||
|
17 | ||||
|
18 | result = f(range(10)) | |||
|
19 | print "Using a parallel function: ", result No newline at end of file |
@@ -0,0 +1,47 b'' | |||||
|
1 | .. Notification: | |||
|
2 | ||||
|
3 | ========================================== | |||
|
4 | IPython.kernel.core.notification blueprint | |||
|
5 | ========================================== | |||
|
6 | ||||
|
7 | Overview | |||
|
8 | ======== | |||
|
9 | The :mod:`IPython.kernel.core.notification` module will provide a simple implementation of a notification center and support for the observer pattern within the :mod:`IPython.kernel.core`. The main intended use case is to provide notification of Interpreter events to an observing frontend during the execution of a single block of code. | |||
|
10 | ||||
|
11 | Functional Requirements | |||
|
12 | ======================= | |||
|
13 | The notification center must: | |||
|
14 | * Provide synchronous notification of events to all registered observers. | |||
|
15 | * Provide typed or labeled notification types | |||
|
16 | * Allow observers to register callbacks for individual or all notification types | |||
|
17 | * Allow observers to register callbacks for events from individual or all notifying objects | |||
|
18 | * Notification to the observer consists of the notification type, notifying object and user-supplied extra information [implementation: as keyword parameters to the registered callback] | |||
|
19 | * Perform as O(1) in the case of no registered observers. | |||
|
20 | * Permit out-of-process or cross-network extension. | |||
|
21 | ||||
|
22 | What's not included | |||
|
23 | ============================================================== | |||
|
24 | As written, the :mod:`IPython.kernel.core.notificaiton` module does not: | |||
|
25 | * Provide out-of-process or network notifications [these should be handled by a separate, Twisted aware module in :mod:`IPython.kernel`]. | |||
|
26 | * Provide zope.interface-style interfaces for the notification system [these should also be provided by the :mod:`IPython.kernel` module] | |||
|
27 | ||||
|
28 | Use Cases | |||
|
29 | ========= | |||
|
30 | The following use cases describe the main intended uses of the notificaiton module and illustrate the main success scenario for each use case: | |||
|
31 | ||||
|
32 | 1. Dwight Schroot is writing a frontend for the IPython project. His frontend is stuck in the stone age and must communicate synchronously with an IPython.kernel.core.Interpreter instance. Because code is executed in blocks by the Interpreter, Dwight's UI freezes every time he executes a long block of code. To keep track of the progress of his long running block, Dwight adds the following code to his frontend's set-up code:: | |||
|
33 | from IPython.kernel.core.notification import NotificationCenter | |||
|
34 | center = NotificationCenter.sharedNotificationCenter | |||
|
35 | center.registerObserver(self, type=IPython.kernel.core.Interpreter.STDOUT_NOTIFICATION_TYPE, notifying_object=self.interpreter, callback=self.stdout_notification) | |||
|
36 | ||||
|
37 | and elsewhere in his front end:: | |||
|
38 | def stdout_notification(self, type, notifying_object, out_string=None): | |||
|
39 | self.writeStdOut(out_string) | |||
|
40 | ||||
|
41 | If everything works, the Interpreter will (according to its published API) fire a notification via the :data:`IPython.kernel.core.notification.sharedCenter` of type :const:`STD_OUT_NOTIFICATION_TYPE` before writing anything to stdout [it's up to the Intereter implementation to figure out when to do this]. The notificaiton center will then call the registered callbacks for that event type (in this case, Dwight's frontend's stdout_notification method). Again, according to its API, the Interpreter provides an additional keyword argument when firing the notificaiton of out_string, a copy of the string it will write to stdout. | |||
|
42 | ||||
|
43 | Like magic, Dwight's frontend is able to provide output, even during long-running calculations. Now if Jim could just convince Dwight to use Twisted... | |||
|
44 | ||||
|
45 | 2. Boss Hog is writing a frontend for the IPython project. Because Boss Hog is stuck in the stone age, his frontend will be written in a new Fortran-like dialect of python and will run only from the command line. Because he doesn't need any fancy notification system and is used to worrying about every cycle on his rat-wheel powered mini, Boss Hog is adamant that the new notification system not produce any performance penalty. As they say in Hazard county, there's no such thing as a free lunch. If he wanted zero overhead, he should have kept using IPython 0.8. Instead, those tricky Duke boys slide in a suped-up bridge-out jumpin' awkwardly confederate-lovin' notification module that imparts only a constant (and small) performance penalty when the Interpreter (or any other object) fires an event for which there are no registered observers. Of course, the same notificaiton-enabled Interpreter can then be used in frontends that require notifications, thus saving the IPython project from a nasty civil war. | |||
|
46 | ||||
|
47 | 3. Barry is wrting a frontend for the IPython project. Because Barry's front end is the *new hotness*, it uses an asynchronous event model to communicate with a Twisted :mod:`~IPython.kernel.engineservice` that communicates with the IPython :class:`~IPython.kernel.core.interpreter.Interpreter`. Using the :mod:`IPython.kernel.notification` module, an asynchronous wrapper on the :mod:`IPython.kernel.core.notification` module, Barry's frontend can register for notifications from the interpreter that are delivered asynchronously. Even if Barry's frontend is running on a separate process or even host from the Interpreter, the notifications are delivered, as if by dark and twisted magic. Just like Dwight's frontend, Barry's frontend can now recieve notifications of e.g. writing to stdout/stderr, opening/closing an external file, an exception in the executing code, etc. No newline at end of file |
@@ -61,9 +61,11 b' class Style(object):' | |||||
61 | ``bg`` as the background color and ``attrs`` as the attributes. |
|
61 | ``bg`` as the background color and ``attrs`` as the attributes. | |
62 |
|
62 | |||
63 | Examples: |
|
63 | Examples: | |
|
64 | >>> Style(COLOR_RED, COLOR_BLACK) | |||
|
65 | <Style fg=red bg=black attrs=0> | |||
64 |
|
66 | |||
65 |
|
|
67 | >>> Style(COLOR_YELLOW, COLOR_BLUE, A_BOLD|A_UNDERLINE) | |
66 | >>> Style(COLOR_YELLOW, COLOR_BLUE, A_BOLD|A_UNDERLINE) |
|
68 | <Style fg=yellow bg=blue attrs=bold|underline> | |
67 | """ |
|
69 | """ | |
68 | self.fg = fg |
|
70 | self.fg = fg | |
69 | self.bg = bg |
|
71 | self.bg = bg |
@@ -83,6 +83,8 b' three extensions points (all of them optional):' | |||||
83 | maxunicode |0xffff |
|
83 | maxunicode |0xffff | |
84 | """ |
|
84 | """ | |
85 |
|
85 | |||
|
86 | skip_doctest = True # ignore top-level docstring as a doctest. | |||
|
87 | ||||
86 | import sys, os, os.path, stat, glob, new, csv, datetime, types |
|
88 | import sys, os, os.path, stat, glob, new, csv, datetime, types | |
87 | import itertools, mimetypes, StringIO |
|
89 | import itertools, mimetypes, StringIO | |
88 |
|
90 | |||
@@ -123,8 +125,7 b' except ImportError:' | |||||
123 | grp = None |
|
125 | grp = None | |
124 |
|
126 | |||
125 | from IPython.external import simplegeneric |
|
127 | from IPython.external import simplegeneric | |
126 |
|
128 | from IPython.external import path | ||
127 | import path |
|
|||
128 |
|
129 | |||
129 | try: |
|
130 | try: | |
130 | from IPython import genutils, generics |
|
131 | from IPython import genutils, generics | |
@@ -1210,8 +1211,12 b' class ils(Table):' | |||||
1210 | Examples:: |
|
1211 | Examples:: | |
1211 |
|
1212 | |||
1212 | >>> ils |
|
1213 | >>> ils | |
|
1214 | <class 'IPython.Extensions.ipipe.ils'> | |||
1213 | >>> ils("/usr/local/lib/python2.4") |
|
1215 | >>> ils("/usr/local/lib/python2.4") | |
|
1216 | IPython.Extensions.ipipe.ils('/usr/local/lib/python2.4') | |||
1214 | >>> ils("~") |
|
1217 | >>> ils("~") | |
|
1218 | IPython.Extensions.ipipe.ils('/home/fperez') | |||
|
1219 | # all-random | |||
1215 | """ |
|
1220 | """ | |
1216 | def __init__(self, base=os.curdir, dirs=True, files=True): |
|
1221 | def __init__(self, base=os.curdir, dirs=True, files=True): | |
1217 | self.base = os.path.expanduser(base) |
|
1222 | self.base = os.path.expanduser(base) | |
@@ -1248,6 +1253,7 b' class iglob(Table):' | |||||
1248 | Examples:: |
|
1253 | Examples:: | |
1249 |
|
1254 | |||
1250 | >>> iglob("*.py") |
|
1255 | >>> iglob("*.py") | |
|
1256 | IPython.Extensions.ipipe.iglob('*.py') | |||
1251 | """ |
|
1257 | """ | |
1252 | def __init__(self, glob): |
|
1258 | def __init__(self, glob): | |
1253 | self.glob = glob |
|
1259 | self.glob = glob | |
@@ -1273,8 +1279,12 b' class iwalk(Table):' | |||||
1273 | List all files and directories in a directory and it's subdirectory:: |
|
1279 | List all files and directories in a directory and it's subdirectory:: | |
1274 |
|
1280 | |||
1275 | >>> iwalk |
|
1281 | >>> iwalk | |
1276 | >>> iwalk("/usr/local/lib/python2.4") |
|
1282 | <class 'IPython.Extensions.ipipe.iwalk'> | |
|
1283 | >>> iwalk("/usr/lib") | |||
|
1284 | IPython.Extensions.ipipe.iwalk('/usr/lib') | |||
1277 | >>> iwalk("~") |
|
1285 | >>> iwalk("~") | |
|
1286 | IPython.Extensions.ipipe.iwalk('/home/fperez') # random | |||
|
1287 | ||||
1278 | """ |
|
1288 | """ | |
1279 | def __init__(self, base=os.curdir, dirs=True, files=True): |
|
1289 | def __init__(self, base=os.curdir, dirs=True, files=True): | |
1280 | self.base = os.path.expanduser(base) |
|
1290 | self.base = os.path.expanduser(base) | |
@@ -1378,6 +1388,8 b' class ipwd(Table):' | |||||
1378 | Example:: |
|
1388 | Example:: | |
1379 |
|
1389 | |||
1380 | >>> ipwd | isort("uid") |
|
1390 | >>> ipwd | isort("uid") | |
|
1391 | <IPython.Extensions.ipipe.isort key='uid' reverse=False at 0x849efec> | |||
|
1392 | # random | |||
1381 | """ |
|
1393 | """ | |
1382 | def __iter__(self): |
|
1394 | def __iter__(self): | |
1383 | for entry in pwd.getpwall(): |
|
1395 | for entry in pwd.getpwall(): | |
@@ -1562,6 +1574,7 b' class ienv(Table):' | |||||
1562 | Example:: |
|
1574 | Example:: | |
1563 |
|
1575 | |||
1564 | >>> ienv |
|
1576 | >>> ienv | |
|
1577 | <class 'IPython.Extensions.ipipe.ienv'> | |||
1565 | """ |
|
1578 | """ | |
1566 |
|
1579 | |||
1567 | def __iter__(self): |
|
1580 | def __iter__(self): | |
@@ -1583,7 +1596,9 b' class ihist(Table):' | |||||
1583 | Example:: |
|
1596 | Example:: | |
1584 |
|
1597 | |||
1585 | >>> ihist |
|
1598 | >>> ihist | |
1586 | >>> ihist(True) (raw mode) |
|
1599 | <class 'IPython.Extensions.ipipe.ihist'> | |
|
1600 | >>> ihist(True) # raw mode | |||
|
1601 | <IPython.Extensions.ipipe.ihist object at 0x849602c> # random | |||
1587 | """ |
|
1602 | """ | |
1588 | def __init__(self, raw=True): |
|
1603 | def __init__(self, raw=True): | |
1589 | self.raw = raw |
|
1604 | self.raw = raw | |
@@ -1618,6 +1633,7 b' class ialias(Table):' | |||||
1618 | Example:: |
|
1633 | Example:: | |
1619 |
|
1634 | |||
1620 | >>> ialias |
|
1635 | >>> ialias | |
|
1636 | <class 'IPython.Extensions.ipipe.ialias'> | |||
1621 | """ |
|
1637 | """ | |
1622 | def __iter__(self): |
|
1638 | def __iter__(self): | |
1623 | api = ipapi.get() |
|
1639 | api = ipapi.get() | |
@@ -1680,7 +1696,11 b' class ix(Table):' | |||||
1680 | Examples:: |
|
1696 | Examples:: | |
1681 |
|
1697 | |||
1682 | >>> ix("ps x") |
|
1698 | >>> ix("ps x") | |
|
1699 | IPython.Extensions.ipipe.ix('ps x') | |||
|
1700 | ||||
1683 | >>> ix("find .") | ifile |
|
1701 | >>> ix("find .") | ifile | |
|
1702 | <IPython.Extensions.ipipe.ieval expr=<class 'IPython.Extensions.ipipe.ifile'> at 0x8509d2c> | |||
|
1703 | # random | |||
1684 | """ |
|
1704 | """ | |
1685 | def __init__(self, cmd): |
|
1705 | def __init__(self, cmd): | |
1686 | self.cmd = cmd |
|
1706 | self.cmd = cmd | |
@@ -1721,6 +1741,7 b' class ifilter(Pipe):' | |||||
1721 | >>> ils | ifilter("_.isfile() and size>1000") |
|
1741 | >>> ils | ifilter("_.isfile() and size>1000") | |
1722 | >>> igrp | ifilter("len(mem)") |
|
1742 | >>> igrp | ifilter("len(mem)") | |
1723 | >>> sys.modules | ifilter(lambda _:_.value is not None) |
|
1743 | >>> sys.modules | ifilter(lambda _:_.value is not None) | |
|
1744 | # all-random | |||
1724 | """ |
|
1745 | """ | |
1725 |
|
1746 | |||
1726 | def __init__(self, expr, globals=None, errors="raiseifallfail"): |
|
1747 | def __init__(self, expr, globals=None, errors="raiseifallfail"): | |
@@ -1811,7 +1832,9 b' class ieval(Pipe):' | |||||
1811 | Examples:: |
|
1832 | Examples:: | |
1812 |
|
1833 | |||
1813 | >>> ils | ieval("_.abspath()") |
|
1834 | >>> ils | ieval("_.abspath()") | |
|
1835 | # random | |||
1814 | >>> sys.path | ieval(ifile) |
|
1836 | >>> sys.path | ieval(ifile) | |
|
1837 | # random | |||
1815 | """ |
|
1838 | """ | |
1816 |
|
1839 | |||
1817 | def __init__(self, expr, globals=None, errors="raiseifallfail"): |
|
1840 | def __init__(self, expr, globals=None, errors="raiseifallfail"): | |
@@ -1884,6 +1907,8 b' class ienum(Pipe):' | |||||
1884 |
|
1907 | |||
1885 | >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object") |
|
1908 | >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object") | |
1886 | """ |
|
1909 | """ | |
|
1910 | skip_doctest = True | |||
|
1911 | ||||
1887 | def __iter__(self): |
|
1912 | def __iter__(self): | |
1888 | fields = ("index", "object") |
|
1913 | fields = ("index", "object") | |
1889 | for (index, object) in enumerate(xiter(self.input)): |
|
1914 | for (index, object) in enumerate(xiter(self.input)): | |
@@ -1897,7 +1922,10 b' class isort(Pipe):' | |||||
1897 | Examples:: |
|
1922 | Examples:: | |
1898 |
|
1923 | |||
1899 | >>> ils | isort("size") |
|
1924 | >>> ils | isort("size") | |
|
1925 | <IPython.Extensions.ipipe.isort key='size' reverse=False at 0x849ec2c> | |||
1900 | >>> ils | isort("_.isdir(), _.lower()", reverse=True) |
|
1926 | >>> ils | isort("_.isdir(), _.lower()", reverse=True) | |
|
1927 | <IPython.Extensions.ipipe.isort key='_.isdir(), _.lower()' reverse=True at 0x849eacc> | |||
|
1928 | # all-random | |||
1901 | """ |
|
1929 | """ | |
1902 |
|
1930 | |||
1903 | def __init__(self, key=None, globals=None, reverse=False): |
|
1931 | def __init__(self, key=None, globals=None, reverse=False): | |
@@ -2058,6 +2086,8 b' class icap(Table):' | |||||
2058 | >>> icap("for i in range(10): print i, time.sleep(0.1)") |
|
2086 | >>> icap("for i in range(10): print i, time.sleep(0.1)") | |
2059 |
|
2087 | |||
2060 | """ |
|
2088 | """ | |
|
2089 | skip_doctest = True | |||
|
2090 | ||||
2061 | def __init__(self, expr, globals=None): |
|
2091 | def __init__(self, expr, globals=None): | |
2062 | self.expr = expr |
|
2092 | self.expr = expr | |
2063 | self.globals = globals |
|
2093 | self.globals = globals |
@@ -174,23 +174,15 b' class LeoNode(object, UserDict.DictMixin):' | |||||
174 |
|
174 | |||
175 | def __get_h(self): return self.p.headString() |
|
175 | def __get_h(self): return self.p.headString() | |
176 | def __set_h(self,val): |
|
176 | def __set_h(self,val): | |
177 | print "set head",val |
|
177 | c.setHeadString(self.p,val) | |
178 |
c. |
|
178 | c.redraw() | |
179 | try: |
|
|||
180 | c.setHeadString(self.p,val) |
|
|||
181 | finally: |
|
|||
182 | c.endUpdate() |
|
|||
183 |
|
179 | |||
184 | h = property( __get_h, __set_h, doc = "Node headline string") |
|
180 | h = property( __get_h, __set_h, doc = "Node headline string") | |
185 |
|
181 | |||
186 | def __get_b(self): return self.p.bodyString() |
|
182 | def __get_b(self): return self.p.bodyString() | |
187 | def __set_b(self,val): |
|
183 | def __set_b(self,val): | |
188 | print "set body",val |
|
184 | c.setBodyString(self.p, val) | |
189 |
c. |
|
185 | c.redraw() | |
190 | try: |
|
|||
191 | c.setBodyString(self.p, val) |
|
|||
192 | finally: |
|
|||
193 | c.endUpdate() |
|
|||
194 |
|
186 | |||
195 | b = property(__get_b, __set_b, doc = "Nody body string") |
|
187 | b = property(__get_b, __set_b, doc = "Nody body string") | |
196 |
|
188 | |||
@@ -265,11 +257,8 b' class LeoNode(object, UserDict.DictMixin):' | |||||
265 |
|
257 | |||
266 | def go(self): |
|
258 | def go(self): | |
267 | """ Set node as current node (to quickly see it in Outline) """ |
|
259 | """ Set node as current node (to quickly see it in Outline) """ | |
268 | c.beginUpdate() |
|
260 | c.setCurrentPosition(self.p) | |
269 |
|
|
261 | c.redraw() | |
270 | c.setCurrentPosition(self.p) |
|
|||
271 | finally: |
|
|||
272 | c.endUpdate() |
|
|||
273 |
|
262 | |||
274 | def script(self): |
|
263 | def script(self): | |
275 | """ Method to get the 'tangled' contents of the node |
|
264 | """ Method to get the 'tangled' contents of the node | |
@@ -337,7 +326,6 b' def workbook_complete(obj, prev):' | |||||
337 |
|
326 | |||
338 |
|
327 | |||
339 | def add_var(varname): |
|
328 | def add_var(varname): | |
340 | c.beginUpdate() |
|
|||
341 | r = rootnode() |
|
329 | r = rootnode() | |
342 | try: |
|
330 | try: | |
343 | if r is None: |
|
331 | if r is None: | |
@@ -356,7 +344,7 b' def add_var(varname):' | |||||
356 | c.setHeadString(p2,varname) |
|
344 | c.setHeadString(p2,varname) | |
357 | return LeoNode(p2) |
|
345 | return LeoNode(p2) | |
358 | finally: |
|
346 | finally: | |
359 |
c. |
|
347 | c.redraw() | |
360 |
|
348 | |||
361 | def add_file(self,fname): |
|
349 | def add_file(self,fname): | |
362 | p2 = c.currentPosition().insertAfter() |
|
350 | p2 = c.currentPosition().insertAfter() | |
@@ -368,7 +356,6 b' def expose_ileo_push(f, prio = 0):' | |||||
368 |
|
356 | |||
369 | def push_ipython_script(node): |
|
357 | def push_ipython_script(node): | |
370 | """ Execute the node body in IPython, as if it was entered in interactive prompt """ |
|
358 | """ Execute the node body in IPython, as if it was entered in interactive prompt """ | |
371 | c.beginUpdate() |
|
|||
372 | try: |
|
359 | try: | |
373 | ohist = ip.IP.output_hist |
|
360 | ohist = ip.IP.output_hist | |
374 | hstart = len(ip.IP.input_hist) |
|
361 | hstart = len(ip.IP.input_hist) | |
@@ -393,7 +380,7 b' def push_ipython_script(node):' | |||||
393 | if not has_output: |
|
380 | if not has_output: | |
394 | es('ipy run: %s (%d LL)' %( node.h,len(script))) |
|
381 | es('ipy run: %s (%d LL)' %( node.h,len(script))) | |
395 | finally: |
|
382 | finally: | |
396 |
c. |
|
383 | c.redraw() | |
397 |
|
384 | |||
398 |
|
385 | |||
399 | def eval_body(body): |
|
386 | def eval_body(body): | |
@@ -495,7 +482,6 b' def lee_f(self,s):' | |||||
495 | """ |
|
482 | """ | |
496 | import os |
|
483 | import os | |
497 |
|
484 | |||
498 | c.beginUpdate() |
|
|||
499 | try: |
|
485 | try: | |
500 | if s == 'hist': |
|
486 | if s == 'hist': | |
501 | wb.ipython_history.b = get_history() |
|
487 | wb.ipython_history.b = get_history() | |
@@ -533,7 +519,7 b' def lee_f(self,s):' | |||||
533 | c.selectPosition(p) |
|
519 | c.selectPosition(p) | |
534 | print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes" |
|
520 | print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes" | |
535 | finally: |
|
521 | finally: | |
536 |
c. |
|
522 | c.redraw() | |
537 |
|
523 | |||
538 |
|
524 | |||
539 |
|
525 |
@@ -61,6 +61,8 b' from IPython import platutils' | |||||
61 | import IPython.generics |
|
61 | import IPython.generics | |
62 | import IPython.ipapi |
|
62 | import IPython.ipapi | |
63 | from IPython.ipapi import UsageError |
|
63 | from IPython.ipapi import UsageError | |
|
64 | from IPython.testing import decorators as testdec | |||
|
65 | ||||
64 | #*************************************************************************** |
|
66 | #*************************************************************************** | |
65 | # Utility functions |
|
67 | # Utility functions | |
66 | def on_off(tag): |
|
68 | def on_off(tag): | |
@@ -522,7 +524,7 b' Currently the magic system has the following functions:\\n"""' | |||||
522 | rc.automagic = not rc.automagic |
|
524 | rc.automagic = not rc.automagic | |
523 | print '\n' + Magic.auto_status[rc.automagic] |
|
525 | print '\n' + Magic.auto_status[rc.automagic] | |
524 |
|
526 | |||
525 |
|
527 | @testdec.skip_doctest | ||
526 | def magic_autocall(self, parameter_s = ''): |
|
528 | def magic_autocall(self, parameter_s = ''): | |
527 | """Make functions callable without having to type parentheses. |
|
529 | """Make functions callable without having to type parentheses. | |
528 |
|
530 | |||
@@ -551,8 +553,9 b' Currently the magic system has the following functions:\\n"""' | |||||
551 | 2 -> Active always. Even if no arguments are present, the callable |
|
553 | 2 -> Active always. Even if no arguments are present, the callable | |
552 | object is called: |
|
554 | object is called: | |
553 |
|
555 | |||
554 |
In [ |
|
556 | In [2]: float | |
555 |
------> |
|
557 | ------> float() | |
|
558 | Out[2]: 0.0 | |||
556 |
|
559 | |||
557 | Note that even with autocall off, you can still use '/' at the start of |
|
560 | Note that even with autocall off, you can still use '/' at the start of | |
558 | a line to treat the first argument on the command line as a function |
|
561 | a line to treat the first argument on the command line as a function | |
@@ -561,6 +564,8 b' Currently the magic system has the following functions:\\n"""' | |||||
561 | In [8]: /str 43 |
|
564 | In [8]: /str 43 | |
562 | ------> str(43) |
|
565 | ------> str(43) | |
563 | Out[8]: '43' |
|
566 | Out[8]: '43' | |
|
567 | ||||
|
568 | # all-random (note for auto-testing) | |||
564 | """ |
|
569 | """ | |
565 |
|
570 | |||
566 | rc = self.shell.rc |
|
571 | rc = self.shell.rc | |
@@ -1243,12 +1248,13 b' Currently the magic system has the following functions:\\n"""' | |||||
1243 |
|
1248 | |||
1244 | self.shell.debugger(force=True) |
|
1249 | self.shell.debugger(force=True) | |
1245 |
|
1250 | |||
|
1251 | @testdec.skip_doctest | |||
1246 | def magic_prun(self, parameter_s ='',user_mode=1, |
|
1252 | def magic_prun(self, parameter_s ='',user_mode=1, | |
1247 | opts=None,arg_lst=None,prog_ns=None): |
|
1253 | opts=None,arg_lst=None,prog_ns=None): | |
1248 |
|
1254 | |||
1249 | """Run a statement through the python code profiler. |
|
1255 | """Run a statement through the python code profiler. | |
1250 |
|
1256 | |||
1251 |
Usage: |
|
1257 | Usage: | |
1252 | %prun [options] statement |
|
1258 | %prun [options] statement | |
1253 |
|
1259 | |||
1254 | The given statement (which doesn't require quote marks) is run via the |
|
1260 | The given statement (which doesn't require quote marks) is run via the | |
@@ -1293,16 +1299,16 b' Currently the magic system has the following functions:\\n"""' | |||||
1293 | abbreviation is unambiguous. The following are the keys currently |
|
1299 | abbreviation is unambiguous. The following are the keys currently | |
1294 | defined: |
|
1300 | defined: | |
1295 |
|
1301 | |||
1296 |
Valid Arg Meaning |
|
1302 | Valid Arg Meaning | |
1297 |
"calls" call count |
|
1303 | "calls" call count | |
1298 |
"cumulative" cumulative time |
|
1304 | "cumulative" cumulative time | |
1299 |
"file" file name |
|
1305 | "file" file name | |
1300 |
"module" file name |
|
1306 | "module" file name | |
1301 |
"pcalls" primitive call count |
|
1307 | "pcalls" primitive call count | |
1302 |
"line" line number |
|
1308 | "line" line number | |
1303 |
"name" function name |
|
1309 | "name" function name | |
1304 |
"nfl" name/file/line |
|
1310 | "nfl" name/file/line | |
1305 |
"stdname" standard name |
|
1311 | "stdname" standard name | |
1306 | "time" internal time |
|
1312 | "time" internal time | |
1307 |
|
1313 | |||
1308 | Note that all sorts on statistics are in descending order (placing |
|
1314 | Note that all sorts on statistics are in descending order (placing | |
@@ -1328,8 +1334,10 b' Currently the magic system has the following functions:\\n"""' | |||||
1328 | '%run -p [prof_opts] filename.py [args to program]' where prof_opts |
|
1334 | '%run -p [prof_opts] filename.py [args to program]' where prof_opts | |
1329 | contains profiler specific options as described here. |
|
1335 | contains profiler specific options as described here. | |
1330 |
|
1336 | |||
1331 |
You can read the complete documentation for the profile module with: |
|
1337 | You can read the complete documentation for the profile module with:: | |
1332 | In [1]: import profile; profile.help() """ |
|
1338 | ||
|
1339 | In [1]: import profile; profile.help() | |||
|
1340 | """ | |||
1333 |
|
1341 | |||
1334 | opts_def = Struct(D=[''],l=[],s=['time'],T=['']) |
|
1342 | opts_def = Struct(D=[''],l=[],s=['time'],T=['']) | |
1335 | # protect user quote marks |
|
1343 | # protect user quote marks | |
@@ -1413,6 +1421,7 b' Currently the magic system has the following functions:\\n"""' | |||||
1413 | else: |
|
1421 | else: | |
1414 | return None |
|
1422 | return None | |
1415 |
|
1423 | |||
|
1424 | @testdec.skip_doctest | |||
1416 | def magic_run(self, parameter_s ='',runner=None): |
|
1425 | def magic_run(self, parameter_s ='',runner=None): | |
1417 | """Run the named file inside IPython as a program. |
|
1426 | """Run the named file inside IPython as a program. | |
1418 |
|
1427 | |||
@@ -1575,12 +1584,16 b' Currently the magic system has the following functions:\\n"""' | |||||
1575 |
|
1584 | |||
1576 | # pickle fix. See iplib for an explanation. But we need to make sure |
|
1585 | # pickle fix. See iplib for an explanation. But we need to make sure | |
1577 | # that, if we overwrite __main__, we replace it at the end |
|
1586 | # that, if we overwrite __main__, we replace it at the end | |
1578 |
|
|
1587 | main_mod_name = prog_ns['__name__'] | |
|
1588 | ||||
|
1589 | if main_mod_name == '__main__': | |||
1579 | restore_main = sys.modules['__main__'] |
|
1590 | restore_main = sys.modules['__main__'] | |
1580 | else: |
|
1591 | else: | |
1581 | restore_main = False |
|
1592 | restore_main = False | |
1582 |
|
1593 | |||
1583 | sys.modules[prog_ns['__name__']] = main_mod |
|
1594 | # This needs to be undone at the end to prevent holding references to | |
|
1595 | # every single object ever created. | |||
|
1596 | sys.modules[main_mod_name] = main_mod | |||
1584 |
|
1597 | |||
1585 | stats = None |
|
1598 | stats = None | |
1586 | try: |
|
1599 | try: | |
@@ -1673,9 +1686,15 b' Currently the magic system has the following functions:\\n"""' | |||||
1673 | del prog_ns['__name__'] |
|
1686 | del prog_ns['__name__'] | |
1674 | self.shell.user_ns.update(prog_ns) |
|
1687 | self.shell.user_ns.update(prog_ns) | |
1675 | finally: |
|
1688 | finally: | |
|
1689 | # Ensure key global structures are restored | |||
1676 | sys.argv = save_argv |
|
1690 | sys.argv = save_argv | |
1677 | if restore_main: |
|
1691 | if restore_main: | |
1678 | sys.modules['__main__'] = restore_main |
|
1692 | sys.modules['__main__'] = restore_main | |
|
1693 | else: | |||
|
1694 | # Remove from sys.modules the reference to main_mod we'd | |||
|
1695 | # added. Otherwise it will trap references to objects | |||
|
1696 | # contained therein. | |||
|
1697 | del sys.modules[main_mod_name] | |||
1679 | self.shell.reloadhist() |
|
1698 | self.shell.reloadhist() | |
1680 |
|
1699 | |||
1681 | return stats |
|
1700 | return stats | |
@@ -1699,6 +1718,7 b' Currently the magic system has the following functions:\\n"""' | |||||
1699 | self.shell.safe_execfile(f,self.shell.user_ns, |
|
1718 | self.shell.safe_execfile(f,self.shell.user_ns, | |
1700 | self.shell.user_ns,islog=1) |
|
1719 | self.shell.user_ns,islog=1) | |
1701 |
|
1720 | |||
|
1721 | @testdec.skip_doctest | |||
1702 | def magic_timeit(self, parameter_s =''): |
|
1722 | def magic_timeit(self, parameter_s =''): | |
1703 | """Time execution of a Python statement or expression |
|
1723 | """Time execution of a Python statement or expression | |
1704 |
|
1724 | |||
@@ -1726,7 +1746,8 b' Currently the magic system has the following functions:\\n"""' | |||||
1726 | Default: 3 |
|
1746 | Default: 3 | |
1727 |
|
1747 | |||
1728 |
|
1748 | |||
1729 |
Examples: |
|
1749 | Examples: | |
|
1750 | ||||
1730 | In [1]: %timeit pass |
|
1751 | In [1]: %timeit pass | |
1731 | 10000000 loops, best of 3: 53.3 ns per loop |
|
1752 | 10000000 loops, best of 3: 53.3 ns per loop | |
1732 |
|
1753 | |||
@@ -1755,7 +1776,7 b' Currently the magic system has the following functions:\\n"""' | |||||
1755 | import timeit |
|
1776 | import timeit | |
1756 | import math |
|
1777 | import math | |
1757 |
|
1778 | |||
1758 |
units = ["s", "ms", " |
|
1779 | units = [u"s", u"ms", u"\xb5s", u"ns"] | |
1759 | scaling = [1, 1e3, 1e6, 1e9] |
|
1780 | scaling = [1, 1e3, 1e6, 1e9] | |
1760 |
|
1781 | |||
1761 | opts, stmt = self.parse_options(parameter_s,'n:r:tcp:', |
|
1782 | opts, stmt = self.parse_options(parameter_s,'n:r:tcp:', | |
@@ -1804,13 +1825,14 b' Currently the magic system has the following functions:\\n"""' | |||||
1804 | order = min(-int(math.floor(math.log10(best)) // 3), 3) |
|
1825 | order = min(-int(math.floor(math.log10(best)) // 3), 3) | |
1805 | else: |
|
1826 | else: | |
1806 | order = 3 |
|
1827 | order = 3 | |
1807 | print "%d loops, best of %d: %.*g %s per loop" % (number, repeat, |
|
1828 | print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat, | |
1808 | precision, |
|
1829 | precision, | |
1809 | best * scaling[order], |
|
1830 | best * scaling[order], | |
1810 | units[order]) |
|
1831 | units[order]) | |
1811 | if tc > tc_min: |
|
1832 | if tc > tc_min: | |
1812 | print "Compiler time: %.2f s" % tc |
|
1833 | print "Compiler time: %.2f s" % tc | |
1813 |
|
1834 | |||
|
1835 | @testdec.skip_doctest | |||
1814 | def magic_time(self,parameter_s = ''): |
|
1836 | def magic_time(self,parameter_s = ''): | |
1815 | """Time execution of a Python statement or expression. |
|
1837 | """Time execution of a Python statement or expression. | |
1816 |
|
1838 | |||
@@ -1902,6 +1924,7 b' Currently the magic system has the following functions:\\n"""' | |||||
1902 | print "Compiler : %.2f s" % tc |
|
1924 | print "Compiler : %.2f s" % tc | |
1903 | return out |
|
1925 | return out | |
1904 |
|
1926 | |||
|
1927 | @testdec.skip_doctest | |||
1905 | def magic_macro(self,parameter_s = ''): |
|
1928 | def magic_macro(self,parameter_s = ''): | |
1906 | """Define a set of input lines as a macro for future re-execution. |
|
1929 | """Define a set of input lines as a macro for future re-execution. | |
1907 |
|
1930 | |||
@@ -1931,17 +1954,17 b' Currently the magic system has the following functions:\\n"""' | |||||
1931 |
|
1954 | |||
1932 | For example, if your history contains (%hist prints it): |
|
1955 | For example, if your history contains (%hist prints it): | |
1933 |
|
1956 | |||
1934 |
44: x=1 |
|
1957 | 44: x=1 | |
1935 |
45: y=3 |
|
1958 | 45: y=3 | |
1936 |
46: z=x+y |
|
1959 | 46: z=x+y | |
1937 |
47: print x |
|
1960 | 47: print x | |
1938 |
48: a=5 |
|
1961 | 48: a=5 | |
1939 |
49: print 'x',x,'y',y |
|
1962 | 49: print 'x',x,'y',y | |
1940 |
|
1963 | |||
1941 | you can create a macro with lines 44 through 47 (included) and line 49 |
|
1964 | you can create a macro with lines 44 through 47 (included) and line 49 | |
1942 | called my_macro with: |
|
1965 | called my_macro with: | |
1943 |
|
1966 | |||
1944 |
In [5 |
|
1967 | In [55]: %macro my_macro 44-47 49 | |
1945 |
|
1968 | |||
1946 | Now, typing `my_macro` (without quotes) will re-execute all this code |
|
1969 | Now, typing `my_macro` (without quotes) will re-execute all this code | |
1947 | in one pass. |
|
1970 | in one pass. | |
@@ -2033,6 +2056,7 b' Currently the magic system has the following functions:\\n"""' | |||||
2033 | """Alias to %edit.""" |
|
2056 | """Alias to %edit.""" | |
2034 | return self.magic_edit(parameter_s) |
|
2057 | return self.magic_edit(parameter_s) | |
2035 |
|
2058 | |||
|
2059 | @testdec.skip_doctest | |||
2036 | def magic_edit(self,parameter_s='',last_call=['','']): |
|
2060 | def magic_edit(self,parameter_s='',last_call=['','']): | |
2037 | """Bring up an editor and execute the resulting code. |
|
2061 | """Bring up an editor and execute the resulting code. | |
2038 |
|
2062 | |||
@@ -2126,47 +2150,47 b' Currently the magic system has the following functions:\\n"""' | |||||
2126 | This is an example of creating a simple function inside the editor and |
|
2150 | This is an example of creating a simple function inside the editor and | |
2127 | then modifying it. First, start up the editor: |
|
2151 | then modifying it. First, start up the editor: | |
2128 |
|
2152 | |||
2129 |
In [1]: ed |
|
2153 | In [1]: ed | |
2130 |
Editing... done. Executing edited code... |
|
2154 | Editing... done. Executing edited code... | |
2131 |
Out[1]: 'def foo(): |
|
2155 | Out[1]: 'def foo():n print "foo() was defined in an editing session"n' | |
2132 |
|
2156 | |||
2133 | We can then call the function foo(): |
|
2157 | We can then call the function foo(): | |
2134 |
|
2158 | |||
2135 |
In [2]: foo() |
|
2159 | In [2]: foo() | |
2136 | foo() was defined in an editing session |
|
2160 | foo() was defined in an editing session | |
2137 |
|
2161 | |||
2138 | Now we edit foo. IPython automatically loads the editor with the |
|
2162 | Now we edit foo. IPython automatically loads the editor with the | |
2139 | (temporary) file where foo() was previously defined: |
|
2163 | (temporary) file where foo() was previously defined: | |
2140 |
|
2164 | |||
2141 |
In [3]: ed foo |
|
2165 | In [3]: ed foo | |
2142 | Editing... done. Executing edited code... |
|
2166 | Editing... done. Executing edited code... | |
2143 |
|
2167 | |||
2144 | And if we call foo() again we get the modified version: |
|
2168 | And if we call foo() again we get the modified version: | |
2145 |
|
2169 | |||
2146 |
In [4]: foo() |
|
2170 | In [4]: foo() | |
2147 | foo() has now been changed! |
|
2171 | foo() has now been changed! | |
2148 |
|
2172 | |||
2149 | Here is an example of how to edit a code snippet successive |
|
2173 | Here is an example of how to edit a code snippet successive | |
2150 | times. First we call the editor: |
|
2174 | times. First we call the editor: | |
2151 |
|
2175 | |||
2152 |
In [ |
|
2176 | In [5]: ed | |
2153 |
Editing... done. Executing edited code... |
|
2177 | Editing... done. Executing edited code... | |
2154 |
hello |
|
2178 | hello | |
2155 |
Out[ |
|
2179 | Out[5]: "print 'hello'n" | |
2156 |
|
2180 | |||
2157 | Now we call it again with the previous output (stored in _): |
|
2181 | Now we call it again with the previous output (stored in _): | |
2158 |
|
2182 | |||
2159 |
In [ |
|
2183 | In [6]: ed _ | |
2160 |
Editing... done. Executing edited code... |
|
2184 | Editing... done. Executing edited code... | |
2161 |
hello world |
|
2185 | hello world | |
2162 |
Out[ |
|
2186 | Out[6]: "print 'hello world'n" | |
2163 |
|
2187 | |||
2164 | Now we call it with the output #8 (stored in _8, also as Out[8]): |
|
2188 | Now we call it with the output #8 (stored in _8, also as Out[8]): | |
2165 |
|
2189 | |||
2166 |
In [ |
|
2190 | In [7]: ed _8 | |
2167 |
Editing... done. Executing edited code... |
|
2191 | Editing... done. Executing edited code... | |
2168 |
hello again |
|
2192 | hello again | |
2169 |
Out[ |
|
2193 | Out[7]: "print 'hello again'n" | |
2170 |
|
2194 | |||
2171 |
|
2195 | |||
2172 | Changing the default editor hook: |
|
2196 | Changing the default editor hook: | |
@@ -2463,7 +2487,8 b' Defaulting color scheme to \'NoColor\'"""' | |||||
2463 |
|
2487 | |||
2464 | #...................................................................... |
|
2488 | #...................................................................... | |
2465 | # Functions to implement unix shell-type things |
|
2489 | # Functions to implement unix shell-type things | |
2466 |
|
2490 | |||
|
2491 | @testdec.skip_doctest | |||
2467 | def magic_alias(self, parameter_s = ''): |
|
2492 | def magic_alias(self, parameter_s = ''): | |
2468 | """Define an alias for a system command. |
|
2493 | """Define an alias for a system command. | |
2469 |
|
2494 | |||
@@ -2479,18 +2504,18 b' Defaulting color scheme to \'NoColor\'"""' | |||||
2479 | You can use the %l specifier in an alias definition to represent the |
|
2504 | You can use the %l specifier in an alias definition to represent the | |
2480 | whole line when the alias is called. For example: |
|
2505 | whole line when the alias is called. For example: | |
2481 |
|
2506 | |||
2482 |
In [2]: alias all echo "Input in brackets: <%l>" |
|
2507 | In [2]: alias all echo "Input in brackets: <%l>" | |
2483 |
In [3]: all hello world |
|
2508 | In [3]: all hello world | |
2484 | Input in brackets: <hello world> |
|
2509 | Input in brackets: <hello world> | |
2485 |
|
2510 | |||
2486 | You can also define aliases with parameters using %s specifiers (one |
|
2511 | You can also define aliases with parameters using %s specifiers (one | |
2487 | per parameter): |
|
2512 | per parameter): | |
2488 |
|
2513 | |||
2489 |
In [1]: alias parts echo first %s second %s |
|
2514 | In [1]: alias parts echo first %s second %s | |
2490 |
In [2]: %parts A B |
|
2515 | In [2]: %parts A B | |
2491 |
first A second B |
|
2516 | first A second B | |
2492 |
In [3]: %parts A |
|
2517 | In [3]: %parts A | |
2493 |
Incorrect number of arguments: 2 expected. |
|
2518 | Incorrect number of arguments: 2 expected. | |
2494 | parts is an alias to: 'echo first %s second %s' |
|
2519 | parts is an alias to: 'echo first %s second %s' | |
2495 |
|
2520 | |||
2496 | Note that %l and %s are mutually exclusive. You can only use one or |
|
2521 | Note that %l and %s are mutually exclusive. You can only use one or | |
@@ -2503,11 +2528,11 b' Defaulting color scheme to \'NoColor\'"""' | |||||
2503 | IPython for variable expansion. If you want to access a true shell |
|
2528 | IPython for variable expansion. If you want to access a true shell | |
2504 | variable, an extra $ is necessary to prevent its expansion by IPython: |
|
2529 | variable, an extra $ is necessary to prevent its expansion by IPython: | |
2505 |
|
2530 | |||
2506 |
In [6]: alias show echo |
|
2531 | In [6]: alias show echo | |
2507 |
In [7]: PATH='A Python string' |
|
2532 | In [7]: PATH='A Python string' | |
2508 |
In [8]: show $PATH |
|
2533 | In [8]: show $PATH | |
2509 |
A Python string |
|
2534 | A Python string | |
2510 |
In [9]: show $$PATH |
|
2535 | In [9]: show $$PATH | |
2511 | /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... |
|
2536 | /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... | |
2512 |
|
2537 | |||
2513 | You can use the alias facility to acess all of $PATH. See the %rehash |
|
2538 | You can use the alias facility to acess all of $PATH. See the %rehash | |
@@ -2822,7 +2847,7 b' Defaulting color scheme to \'NoColor\'"""' | |||||
2822 | header = 'Directory history (kept in _dh)', |
|
2847 | header = 'Directory history (kept in _dh)', | |
2823 | start=ini,stop=fin) |
|
2848 | start=ini,stop=fin) | |
2824 |
|
2849 | |||
2825 |
|
2850 | @testdec.skip_doctest | ||
2826 | def magic_sc(self, parameter_s=''): |
|
2851 | def magic_sc(self, parameter_s=''): | |
2827 | """Shell capture - execute a shell command and capture its output. |
|
2852 | """Shell capture - execute a shell command and capture its output. | |
2828 |
|
2853 | |||
@@ -2866,31 +2891,33 b' Defaulting color scheme to \'NoColor\'"""' | |||||
2866 |
|
2891 | |||
2867 | For example: |
|
2892 | For example: | |
2868 |
|
2893 | |||
|
2894 | # all-random | |||
|
2895 | ||||
2869 | # Capture into variable a |
|
2896 | # Capture into variable a | |
2870 |
In [ |
|
2897 | In [1]: sc a=ls *py | |
2871 |
|
2898 | |||
2872 | # a is a string with embedded newlines |
|
2899 | # a is a string with embedded newlines | |
2873 |
In [ |
|
2900 | In [2]: a | |
2874 |
Out[ |
|
2901 | Out[2]: 'setup.py\\nwin32_manual_post_install.py' | |
2875 |
|
2902 | |||
2876 | # which can be seen as a list: |
|
2903 | # which can be seen as a list: | |
2877 |
In [ |
|
2904 | In [3]: a.l | |
2878 |
Out[ |
|
2905 | Out[3]: ['setup.py', 'win32_manual_post_install.py'] | |
2879 |
|
2906 | |||
2880 | # or as a whitespace-separated string: |
|
2907 | # or as a whitespace-separated string: | |
2881 |
In [ |
|
2908 | In [4]: a.s | |
2882 |
Out[ |
|
2909 | Out[4]: 'setup.py win32_manual_post_install.py' | |
2883 |
|
2910 | |||
2884 | # a.s is useful to pass as a single command line: |
|
2911 | # a.s is useful to pass as a single command line: | |
2885 |
In [ |
|
2912 | In [5]: !wc -l $a.s | |
2886 | 146 setup.py |
|
2913 | 146 setup.py | |
2887 | 130 win32_manual_post_install.py |
|
2914 | 130 win32_manual_post_install.py | |
2888 | 276 total |
|
2915 | 276 total | |
2889 |
|
2916 | |||
2890 | # while the list form is useful to loop over: |
|
2917 | # while the list form is useful to loop over: | |
2891 |
In [ |
|
2918 | In [6]: for f in a.l: | |
2892 |
|
|
2919 | ...: !wc -l $f | |
2893 |
|
|
2920 | ...: | |
2894 | 146 setup.py |
|
2921 | 146 setup.py | |
2895 | 130 win32_manual_post_install.py |
|
2922 | 130 win32_manual_post_install.py | |
2896 |
|
2923 | |||
@@ -2898,13 +2925,13 b' Defaulting color scheme to \'NoColor\'"""' | |||||
2898 | the sense that you can equally invoke the .s attribute on them to |
|
2925 | the sense that you can equally invoke the .s attribute on them to | |
2899 | automatically get a whitespace-separated string from their contents: |
|
2926 | automatically get a whitespace-separated string from their contents: | |
2900 |
|
2927 | |||
2901 |
In [ |
|
2928 | In [7]: sc -l b=ls *py | |
2902 |
|
2929 | |||
2903 |
In [ |
|
2930 | In [8]: b | |
2904 |
Out[ |
|
2931 | Out[8]: ['setup.py', 'win32_manual_post_install.py'] | |
2905 |
|
2932 | |||
2906 |
In [ |
|
2933 | In [9]: b.s | |
2907 |
Out[ |
|
2934 | Out[9]: 'setup.py win32_manual_post_install.py' | |
2908 |
|
2935 | |||
2909 | In summary, both the lists and strings used for ouptut capture have |
|
2936 | In summary, both the lists and strings used for ouptut capture have | |
2910 | the following special attributes: |
|
2937 | the following special attributes: | |
@@ -3273,6 +3300,7 b' Defaulting color scheme to \'NoColor\'"""' | |||||
3273 | save_dstore('rc_separate_out',rc.separate_out) |
|
3300 | save_dstore('rc_separate_out',rc.separate_out) | |
3274 | save_dstore('rc_separate_out2',rc.separate_out2) |
|
3301 | save_dstore('rc_separate_out2',rc.separate_out2) | |
3275 | save_dstore('rc_prompts_pad_left',rc.prompts_pad_left) |
|
3302 | save_dstore('rc_prompts_pad_left',rc.prompts_pad_left) | |
|
3303 | save_dstore('rc_separate_in',rc.separate_in) | |||
3276 |
|
3304 | |||
3277 | if mode == False: |
|
3305 | if mode == False: | |
3278 | # turn on |
|
3306 | # turn on | |
@@ -3282,6 +3310,8 b' Defaulting color scheme to \'NoColor\'"""' | |||||
3282 | oc.prompt2.p_template = '... ' |
|
3310 | oc.prompt2.p_template = '... ' | |
3283 | oc.prompt_out.p_template = '' |
|
3311 | oc.prompt_out.p_template = '' | |
3284 |
|
3312 | |||
|
3313 | # Prompt separators like plain python | |||
|
3314 | oc.input_sep = oc.prompt1.sep = '' | |||
3285 | oc.output_sep = '' |
|
3315 | oc.output_sep = '' | |
3286 | oc.output_sep2 = '' |
|
3316 | oc.output_sep2 = '' | |
3287 |
|
3317 | |||
@@ -3300,6 +3330,8 b' Defaulting color scheme to \'NoColor\'"""' | |||||
3300 | oc.prompt2.p_template = rc.prompt_in2 |
|
3330 | oc.prompt2.p_template = rc.prompt_in2 | |
3301 | oc.prompt_out.p_template = rc.prompt_out |
|
3331 | oc.prompt_out.p_template = rc.prompt_out | |
3302 |
|
3332 | |||
|
3333 | oc.input_sep = oc.prompt1.sep = dstore.rc_separate_in | |||
|
3334 | ||||
3303 | oc.output_sep = dstore.rc_separate_out |
|
3335 | oc.output_sep = dstore.rc_separate_out | |
3304 | oc.output_sep2 = dstore.rc_separate_out2 |
|
3336 | oc.output_sep2 = dstore.rc_separate_out2 | |
3305 |
|
3337 |
@@ -24,16 +24,17 b" __all__ = ['Inspector','InspectColors']" | |||||
24 |
|
24 | |||
25 | # stdlib modules |
|
25 | # stdlib modules | |
26 | import __builtin__ |
|
26 | import __builtin__ | |
|
27 | import StringIO | |||
27 | import inspect |
|
28 | import inspect | |
28 | import linecache |
|
29 | import linecache | |
29 | import string |
|
|||
30 | import StringIO |
|
|||
31 | import types |
|
|||
32 | import os |
|
30 | import os | |
|
31 | import string | |||
33 | import sys |
|
32 | import sys | |
|
33 | import types | |||
|
34 | ||||
34 | # IPython's own |
|
35 | # IPython's own | |
35 | from IPython import PyColorize |
|
36 | from IPython import PyColorize | |
36 |
from IPython.genutils import page,indent,Term |
|
37 | from IPython.genutils import page,indent,Term | |
37 | from IPython.Itpl import itpl |
|
38 | from IPython.Itpl import itpl | |
38 | from IPython.wildcard import list_namespace |
|
39 | from IPython.wildcard import list_namespace | |
39 | from IPython.ColorANSI import * |
|
40 | from IPython.ColorANSI import * | |
@@ -136,6 +137,7 b' def getdoc(obj):' | |||||
136 | ds = '%s\n%s' % (ds,ds2) |
|
137 | ds = '%s\n%s' % (ds,ds2) | |
137 | return ds |
|
138 | return ds | |
138 |
|
139 | |||
|
140 | ||||
139 | def getsource(obj,is_binary=False): |
|
141 | def getsource(obj,is_binary=False): | |
140 | """Wrapper around inspect.getsource. |
|
142 | """Wrapper around inspect.getsource. | |
141 |
|
143 | |||
@@ -162,6 +164,26 b' def getsource(obj,is_binary=False):' | |||||
162 | src = inspect.getsource(obj.__class__) |
|
164 | src = inspect.getsource(obj.__class__) | |
163 | return src |
|
165 | return src | |
164 |
|
166 | |||
|
167 | def getargspec(obj): | |||
|
168 | """Get the names and default values of a function's arguments. | |||
|
169 | ||||
|
170 | A tuple of four things is returned: (args, varargs, varkw, defaults). | |||
|
171 | 'args' is a list of the argument names (it may contain nested lists). | |||
|
172 | 'varargs' and 'varkw' are the names of the * and ** arguments or None. | |||
|
173 | 'defaults' is an n-tuple of the default values of the last n arguments. | |||
|
174 | ||||
|
175 | Modified version of inspect.getargspec from the Python Standard | |||
|
176 | Library.""" | |||
|
177 | ||||
|
178 | if inspect.isfunction(obj): | |||
|
179 | func_obj = obj | |||
|
180 | elif inspect.ismethod(obj): | |||
|
181 | func_obj = obj.im_func | |||
|
182 | else: | |||
|
183 | raise TypeError, 'arg is not a Python function' | |||
|
184 | args, varargs, varkw = inspect.getargs(func_obj.func_code) | |||
|
185 | return args, varargs, varkw, func_obj.func_defaults | |||
|
186 | ||||
165 | #**************************************************************************** |
|
187 | #**************************************************************************** | |
166 | # Class definitions |
|
188 | # Class definitions | |
167 |
|
189 | |||
@@ -172,6 +194,7 b' class myStringIO(StringIO.StringIO):' | |||||
172 | self.write(*arg,**kw) |
|
194 | self.write(*arg,**kw) | |
173 | self.write('\n') |
|
195 | self.write('\n') | |
174 |
|
196 | |||
|
197 | ||||
175 | class Inspector: |
|
198 | class Inspector: | |
176 | def __init__(self,color_table,code_color_table,scheme, |
|
199 | def __init__(self,color_table,code_color_table,scheme, | |
177 | str_detail_level=0): |
|
200 | str_detail_level=0): | |
@@ -181,26 +204,6 b' class Inspector:' | |||||
181 | self.str_detail_level = str_detail_level |
|
204 | self.str_detail_level = str_detail_level | |
182 | self.set_active_scheme(scheme) |
|
205 | self.set_active_scheme(scheme) | |
183 |
|
206 | |||
184 | def __getargspec(self,obj): |
|
|||
185 | """Get the names and default values of a function's arguments. |
|
|||
186 |
|
||||
187 | A tuple of four things is returned: (args, varargs, varkw, defaults). |
|
|||
188 | 'args' is a list of the argument names (it may contain nested lists). |
|
|||
189 | 'varargs' and 'varkw' are the names of the * and ** arguments or None. |
|
|||
190 | 'defaults' is an n-tuple of the default values of the last n arguments. |
|
|||
191 |
|
||||
192 | Modified version of inspect.getargspec from the Python Standard |
|
|||
193 | Library.""" |
|
|||
194 |
|
||||
195 | if inspect.isfunction(obj): |
|
|||
196 | func_obj = obj |
|
|||
197 | elif inspect.ismethod(obj): |
|
|||
198 | func_obj = obj.im_func |
|
|||
199 | else: |
|
|||
200 | raise TypeError, 'arg is not a Python function' |
|
|||
201 | args, varargs, varkw = inspect.getargs(func_obj.func_code) |
|
|||
202 | return args, varargs, varkw, func_obj.func_defaults |
|
|||
203 |
|
||||
204 | def __getdef(self,obj,oname=''): |
|
207 | def __getdef(self,obj,oname=''): | |
205 | """Return the definition header for any callable object. |
|
208 | """Return the definition header for any callable object. | |
206 |
|
209 | |||
@@ -208,7 +211,7 b' class Inspector:' | |||||
208 | exception is suppressed.""" |
|
211 | exception is suppressed.""" | |
209 |
|
212 | |||
210 | try: |
|
213 | try: | |
211 |
return oname + inspect.formatargspec(* |
|
214 | return oname + inspect.formatargspec(*getargspec(obj)) | |
212 | except: |
|
215 | except: | |
213 | return None |
|
216 | return None | |
214 |
|
217 |
@@ -46,13 +46,6 b' from IPython.ipmaker import make_IPython' | |||||
46 | from IPython.Magic import Magic |
|
46 | from IPython.Magic import Magic | |
47 | from IPython.ipstruct import Struct |
|
47 | from IPython.ipstruct import Struct | |
48 |
|
48 | |||
49 | try: # Python 2.3 compatibility |
|
|||
50 | set |
|
|||
51 | except NameError: |
|
|||
52 | import sets |
|
|||
53 | set = sets.Set |
|
|||
54 |
|
||||
55 |
|
||||
56 | # Globals |
|
49 | # Globals | |
57 | # global flag to pass around information about Ctrl-C without exceptions |
|
50 | # global flag to pass around information about Ctrl-C without exceptions | |
58 | KBINT = False |
|
51 | KBINT = False | |
@@ -66,6 +59,9 b' MAIN_THREAD_ID = thread.get_ident()' | |||||
66 | # Tag when runcode() is active, for exception handling |
|
59 | # Tag when runcode() is active, for exception handling | |
67 | CODE_RUN = None |
|
60 | CODE_RUN = None | |
68 |
|
61 | |||
|
62 | # Default timeout for waiting for multithreaded shells (in seconds) | |||
|
63 | GUI_TIMEOUT = 10 | |||
|
64 | ||||
69 | #----------------------------------------------------------------------------- |
|
65 | #----------------------------------------------------------------------------- | |
70 | # This class is trivial now, but I want to have it in to publish a clean |
|
66 | # This class is trivial now, but I want to have it in to publish a clean | |
71 | # interface. Later when the internals are reorganized, code that uses this |
|
67 | # interface. Later when the internals are reorganized, code that uses this | |
@@ -359,12 +355,15 b' class MTInteractiveShell(InteractiveShell):' | |||||
359 | isthreaded = True |
|
355 | isthreaded = True | |
360 |
|
356 | |||
361 | def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), |
|
357 | def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), | |
362 |
user_ns=None,user_global_ns=None,banner2='', |
|
358 | user_ns=None,user_global_ns=None,banner2='', | |
|
359 | gui_timeout=GUI_TIMEOUT,**kw): | |||
363 | """Similar to the normal InteractiveShell, but with threading control""" |
|
360 | """Similar to the normal InteractiveShell, but with threading control""" | |
364 |
|
361 | |||
365 | InteractiveShell.__init__(self,name,usage,rc,user_ns, |
|
362 | InteractiveShell.__init__(self,name,usage,rc,user_ns, | |
366 | user_global_ns,banner2) |
|
363 | user_global_ns,banner2) | |
367 |
|
364 | |||
|
365 | # Timeout we wait for GUI thread | |||
|
366 | self.gui_timeout = gui_timeout | |||
368 |
|
367 | |||
369 | # A queue to hold the code to be executed. |
|
368 | # A queue to hold the code to be executed. | |
370 | self.code_queue = Queue.Queue() |
|
369 | self.code_queue = Queue.Queue() | |
@@ -408,11 +407,12 b' class MTInteractiveShell(InteractiveShell):' | |||||
408 | # Case 2 |
|
407 | # Case 2 | |
409 | return True |
|
408 | return True | |
410 |
|
409 | |||
411 |
# shortcut - if we are in worker thread, or the worker thread is not |
|
410 | # shortcut - if we are in worker thread, or the worker thread is not | |
412 |
# execute directly (to allow recursion and prevent deadlock if |
|
411 | # running, execute directly (to allow recursion and prevent deadlock if | |
413 | # in IPython construction) |
|
412 | # code is run early in IPython construction) | |
414 |
|
413 | |||
415 |
if (self.worker_ident is None |
|
414 | if (self.worker_ident is None | |
|
415 | or self.worker_ident == thread.get_ident() ): | |||
416 | InteractiveShell.runcode(self,code) |
|
416 | InteractiveShell.runcode(self,code) | |
417 | return |
|
417 | return | |
418 |
|
418 | |||
@@ -423,7 +423,7 b' class MTInteractiveShell(InteractiveShell):' | |||||
423 |
|
423 | |||
424 | self.code_queue.put((code,completed_ev, received_ev)) |
|
424 | self.code_queue.put((code,completed_ev, received_ev)) | |
425 | # first make sure the message was received, with timeout |
|
425 | # first make sure the message was received, with timeout | |
426 |
received_ev.wait( |
|
426 | received_ev.wait(self.gui_timeout) | |
427 | if not received_ev.isSet(): |
|
427 | if not received_ev.isSet(): | |
428 | # the mainloop is dead, start executing code directly |
|
428 | # the mainloop is dead, start executing code directly | |
429 | print "Warning: Timeout for mainloop thread exceeded" |
|
429 | print "Warning: Timeout for mainloop thread exceeded" |
@@ -39,8 +39,8 b' $Id: __init__.py 2399 2007-05-26 10:23:10Z vivainio $"""' | |||||
39 | # Enforce proper version requirements |
|
39 | # Enforce proper version requirements | |
40 | import sys |
|
40 | import sys | |
41 |
|
41 | |||
42 |
if sys.version[0:3] < '2. |
|
42 | if sys.version[0:3] < '2.4': | |
43 |
raise ImportError('Python Version 2. |
|
43 | raise ImportError('Python Version 2.4 or above is required for IPython.') | |
44 |
|
44 | |||
45 | # Make it easy to import extensions - they are always directly on pythonpath. |
|
45 | # Make it easy to import extensions - they are always directly on pythonpath. | |
46 | # Therefore, non-IPython modules can be added to Extensions directory |
|
46 | # Therefore, non-IPython modules can be added to Extensions directory | |
@@ -54,6 +54,7 b" __all__ = ['ipapi','generics','ipstruct','Release','Shell']" | |||||
54 | # access to them via IPython.<name> |
|
54 | # access to them via IPython.<name> | |
55 | glob,loc = globals(),locals() |
|
55 | glob,loc = globals(),locals() | |
56 | for name in __all__: |
|
56 | for name in __all__: | |
|
57 | #print 'Importing: ',name # dbg | |||
57 | __import__(name,glob,loc,[]) |
|
58 | __import__(name,glob,loc,[]) | |
58 |
|
59 | |||
59 | import Shell |
|
60 | import Shell |
@@ -108,13 +108,6 b' class Completer:' | |||||
108 | readline.set_completer(Completer(my_namespace).complete) |
|
108 | readline.set_completer(Completer(my_namespace).complete) | |
109 | """ |
|
109 | """ | |
110 |
|
110 | |||
111 | # some minimal strict typechecks. For some core data structures, I |
|
|||
112 | # want actual basic python types, not just anything that looks like |
|
|||
113 | # one. This is especially true for namespaces. |
|
|||
114 | for ns in (namespace,global_namespace): |
|
|||
115 | if ns is not None and type(ns) != types.DictType: |
|
|||
116 | raise TypeError,'namespace must be a dictionary' |
|
|||
117 |
|
||||
118 | # Don't bind to namespace quite yet, but flag whether the user wants a |
|
111 | # Don't bind to namespace quite yet, but flag whether the user wants a | |
119 | # specific namespace or to use __main__.__dict__. This will allow us |
|
112 | # specific namespace or to use __main__.__dict__. This will allow us | |
120 | # to bind to __main__.__dict__ at completion time, not now. |
|
113 | # to bind to __main__.__dict__ at completion time, not now. |
@@ -4,6 +4,7 b' A module to change reload() so that it acts recursively.' | |||||
4 | To enable it type: |
|
4 | To enable it type: | |
5 | >>> import __builtin__, deep_reload |
|
5 | >>> import __builtin__, deep_reload | |
6 | >>> __builtin__.reload = deep_reload.reload |
|
6 | >>> __builtin__.reload = deep_reload.reload | |
|
7 | ||||
7 | You can then disable it with: |
|
8 | You can then disable it with: | |
8 | >>> __builtin__.reload = deep_reload.original_reload |
|
9 | >>> __builtin__.reload = deep_reload.original_reload | |
9 |
|
10 |
@@ -45,9 +45,9 b' from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase' | |||||
45 | from twisted.internet.threads import blockingCallFromThread |
|
45 | from twisted.internet.threads import blockingCallFromThread | |
46 | from twisted.python.failure import Failure |
|
46 | from twisted.python.failure import Failure | |
47 |
|
47 | |||
48 |
#----------------------------------------------------------------------------- |
|
48 | #----------------------------------------------------------------------------- | |
49 | # Classes to implement the Cocoa frontend |
|
49 | # Classes to implement the Cocoa frontend | |
50 |
#----------------------------------------------------------------------------- |
|
50 | #----------------------------------------------------------------------------- | |
51 |
|
51 | |||
52 | # TODO: |
|
52 | # TODO: | |
53 | # 1. use MultiEngineClient and out-of-process engine rather than |
|
53 | # 1. use MultiEngineClient and out-of-process engine rather than | |
@@ -61,41 +61,94 b' class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):' | |||||
61 | """wrapped_execute""" |
|
61 | """wrapped_execute""" | |
62 | try: |
|
62 | try: | |
63 | p = NSAutoreleasePool.alloc().init() |
|
63 | p = NSAutoreleasePool.alloc().init() | |
64 | result = self.shell.execute(lines) |
|
64 | result = super(AutoreleasePoolWrappedThreadedEngineService, | |
65 | except Exception,e: |
|
65 | self).wrapped_execute(msg, lines) | |
66 | # This gives the following: |
|
|||
67 | # et=exception class |
|
|||
68 | # ev=exception class instance |
|
|||
69 | # tb=traceback object |
|
|||
70 | et,ev,tb = sys.exc_info() |
|
|||
71 | # This call adds attributes to the exception value |
|
|||
72 | et,ev,tb = self.shell.formatTraceback(et,ev,tb,msg) |
|
|||
73 | # Add another attribute |
|
|||
74 |
|
||||
75 | # Create a new exception with the new attributes |
|
|||
76 | e = et(ev._ipython_traceback_text) |
|
|||
77 | e._ipython_engine_info = msg |
|
|||
78 |
|
||||
79 | # Re-raise |
|
|||
80 | raise e |
|
|||
81 | finally: |
|
66 | finally: | |
82 | p.drain() |
|
67 | p.drain() | |
83 |
|
68 | |||
84 | return result |
|
69 | return result | |
85 |
|
70 | |||
86 | def execute(self, lines): |
|
71 | ||
87 | # Only import this if we are going to use this class |
|
72 | ||
88 | from twisted.internet import threads |
|
73 | class Cell(NSObject): | |
|
74 | """ | |||
|
75 | Representation of the prompts, input and output of a cell in the | |||
|
76 | frontend | |||
|
77 | """ | |||
|
78 | ||||
|
79 | blockNumber = objc.ivar().unsigned_long() | |||
|
80 | blockID = objc.ivar() | |||
|
81 | inputBlock = objc.ivar() | |||
|
82 | output = objc.ivar() | |||
|
83 | ||||
|
84 | ||||
|
85 | ||||
|
86 | class CellBlock(object): | |||
|
87 | """ | |||
|
88 | Storage for information about text ranges relating to a single cell | |||
|
89 | """ | |||
|
90 | ||||
89 |
|
91 | |||
90 | msg = {'engineid':self.id, |
|
92 | def __init__(self, inputPromptRange, inputRange=None, outputPromptRange=None, | |
91 | 'method':'execute', |
|
93 | outputRange=None): | |
92 | 'args':[lines]} |
|
94 | super(CellBlock, self).__init__() | |
|
95 | self.inputPromptRange = inputPromptRange | |||
|
96 | self.inputRange = inputRange | |||
|
97 | self.outputPromptRange = outputPromptRange | |||
|
98 | self.outputRange = outputRange | |||
|
99 | ||||
|
100 | def update_ranges_for_insertion(self, text, textRange): | |||
|
101 | """Update ranges for text insertion at textRange""" | |||
|
102 | ||||
|
103 | for r in [self.inputPromptRange,self.inputRange, | |||
|
104 | self.outputPromptRange, self.outputRange]: | |||
|
105 | if(r == None): | |||
|
106 | continue | |||
|
107 | intersection = NSIntersectionRange(r,textRange) | |||
|
108 | if(intersection.length == 0): #ranges don't intersect | |||
|
109 | if r.location >= textRange.location: | |||
|
110 | r.location += len(text) | |||
|
111 | else: #ranges intersect | |||
|
112 | if(r.location > textRange.location): | |||
|
113 | offset = len(text) - intersection.length | |||
|
114 | r.length -= offset | |||
|
115 | r.location += offset | |||
|
116 | elif(r.location == textRange.location): | |||
|
117 | r.length += len(text) - intersection.length | |||
|
118 | else: | |||
|
119 | r.length -= intersection.length | |||
|
120 | ||||
|
121 | ||||
|
122 | def update_ranges_for_deletion(self, textRange): | |||
|
123 | """Update ranges for text deletion at textRange""" | |||
93 |
|
124 | |||
94 | d = threads.deferToThread(self.wrapped_execute, msg, lines) |
|
125 | for r in [self.inputPromptRange,self.inputRange, | |
95 | d.addCallback(self.addIDToResult) |
|
126 | self.outputPromptRange, self.outputRange]: | |
96 | return d |
|
127 | if(r==None): | |
|
128 | continue | |||
|
129 | intersection = NSIntersectionRange(r, textRange) | |||
|
130 | if(intersection.length == 0): #ranges don't intersect | |||
|
131 | if r.location >= textRange.location: | |||
|
132 | r.location -= textRange.length | |||
|
133 | else: #ranges intersect | |||
|
134 | if(r.location > textRange.location): | |||
|
135 | offset = intersection.length | |||
|
136 | r.length -= offset | |||
|
137 | r.location += offset | |||
|
138 | elif(r.location == textRange.location): | |||
|
139 | r.length += intersection.length | |||
|
140 | else: | |||
|
141 | r.length -= intersection.length | |||
|
142 | ||||
|
143 | def __repr__(self): | |||
|
144 | return 'CellBlock('+ str((self.inputPromptRange, | |||
|
145 | self.inputRange, | |||
|
146 | self.outputPromptRange, | |||
|
147 | self.outputRange)) + ')' | |||
|
148 | ||||
97 |
|
149 | |||
98 |
|
150 | |||
|
151 | ||||
99 | class IPythonCocoaController(NSObject, AsyncFrontEndBase): |
|
152 | class IPythonCocoaController(NSObject, AsyncFrontEndBase): | |
100 | userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value)) |
|
153 | userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value)) | |
101 | waitingForEngine = objc.ivar().bool() |
|
154 | waitingForEngine = objc.ivar().bool() | |
@@ -120,7 +173,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
120 | self.tabSpaces = 4 |
|
173 | self.tabSpaces = 4 | |
121 | self.tabUsesSpaces = True |
|
174 | self.tabUsesSpaces = True | |
122 | self.currentBlockID = self.next_block_ID() |
|
175 | self.currentBlockID = self.next_block_ID() | |
123 |
self.blockRanges = {} # blockID=> |
|
176 | self.blockRanges = {} # blockID=>CellBlock | |
124 |
|
177 | |||
125 |
|
178 | |||
126 | def awakeFromNib(self): |
|
179 | def awakeFromNib(self): | |
@@ -148,6 +201,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
148 | self.verticalRulerView = r |
|
201 | self.verticalRulerView = r | |
149 | self.verticalRulerView.setClientView_(self.textView) |
|
202 | self.verticalRulerView.setClientView_(self.textView) | |
150 | self._start_cli_banner() |
|
203 | self._start_cli_banner() | |
|
204 | self.start_new_block() | |||
151 |
|
205 | |||
152 |
|
206 | |||
153 | def appWillTerminate_(self, notification): |
|
207 | def appWillTerminate_(self, notification): | |
@@ -239,14 +293,16 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
239 |
|
293 | |||
240 |
|
294 | |||
241 | def update_cell_prompt(self, result, blockID=None): |
|
295 | def update_cell_prompt(self, result, blockID=None): | |
|
296 | print self.blockRanges | |||
242 | if(isinstance(result, Failure)): |
|
297 | if(isinstance(result, Failure)): | |
243 |
|
|
298 | prompt = self.input_prompt() | |
244 | textRange=NSMakeRange(self.blockRanges[blockID].location,0), |
|
299 | ||
245 | scrollToVisible=False |
|
|||
246 | ) |
|
|||
247 | else: |
|
300 | else: | |
248 |
|
|
301 | prompt = self.input_prompt(number=result['number']) | |
249 | textRange=NSMakeRange(self.blockRanges[blockID].location,0), |
|
302 | ||
|
303 | r = self.blockRanges[blockID].inputPromptRange | |||
|
304 | self.insert_text(prompt, | |||
|
305 | textRange=r, | |||
250 | scrollToVisible=False |
|
306 | scrollToVisible=False | |
251 | ) |
|
307 | ) | |
252 |
|
308 | |||
@@ -255,7 +311,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
255 |
|
311 | |||
256 | def render_result(self, result): |
|
312 | def render_result(self, result): | |
257 | blockID = result['blockID'] |
|
313 | blockID = result['blockID'] | |
258 | inputRange = self.blockRanges[blockID] |
|
314 | inputRange = self.blockRanges[blockID].inputRange | |
259 | del self.blockRanges[blockID] |
|
315 | del self.blockRanges[blockID] | |
260 |
|
316 | |||
261 | #print inputRange,self.current_block_range() |
|
317 | #print inputRange,self.current_block_range() | |
@@ -269,11 +325,17 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
269 |
|
325 | |||
270 |
|
326 | |||
271 | def render_error(self, failure): |
|
327 | def render_error(self, failure): | |
|
328 | print failure | |||
|
329 | blockID = failure.blockID | |||
|
330 | inputRange = self.blockRanges[blockID].inputRange | |||
272 | self.insert_text('\n' + |
|
331 | self.insert_text('\n' + | |
273 | self.output_prompt() + |
|
332 | self.output_prompt() + | |
274 | '\n' + |
|
333 | '\n' + | |
275 | failure.getErrorMessage() + |
|
334 | failure.getErrorMessage() + | |
276 |
'\n\n' |
|
335 | '\n\n', | |
|
336 | textRange=NSMakeRange(inputRange.location + | |||
|
337 | inputRange.length, | |||
|
338 | 0)) | |||
277 | self.start_new_block() |
|
339 | self.start_new_block() | |
278 | return failure |
|
340 | return failure | |
279 |
|
341 | |||
@@ -291,6 +353,9 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
291 | """""" |
|
353 | """""" | |
292 |
|
354 | |||
293 | self.currentBlockID = self.next_block_ID() |
|
355 | self.currentBlockID = self.next_block_ID() | |
|
356 | self.blockRanges[self.currentBlockID] = self.new_cell_block() | |||
|
357 | self.insert_text(self.input_prompt(), | |||
|
358 | textRange=self.current_block_range().inputPromptRange) | |||
294 |
|
359 | |||
295 |
|
360 | |||
296 |
|
361 | |||
@@ -298,15 +363,23 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
298 |
|
363 | |||
299 | return uuid.uuid4() |
|
364 | return uuid.uuid4() | |
300 |
|
365 | |||
|
366 | def new_cell_block(self): | |||
|
367 | """A new CellBlock at the end of self.textView.textStorage()""" | |||
|
368 | ||||
|
369 | return CellBlock(NSMakeRange(self.textView.textStorage().length(), | |||
|
370 | 0), #len(self.input_prompt())), | |||
|
371 | NSMakeRange(self.textView.textStorage().length(),# + len(self.input_prompt()), | |||
|
372 | 0)) | |||
|
373 | ||||
|
374 | ||||
301 | def current_block_range(self): |
|
375 | def current_block_range(self): | |
302 | return self.blockRanges.get(self.currentBlockID, |
|
376 | return self.blockRanges.get(self.currentBlockID, | |
303 |
|
|
377 | self.new_cell_block()) | |
304 | 0)) |
|
|||
305 |
|
378 | |||
306 | def current_block(self): |
|
379 | def current_block(self): | |
307 | """The current block's text""" |
|
380 | """The current block's text""" | |
308 |
|
381 | |||
309 | return self.text_for_range(self.current_block_range()) |
|
382 | return self.text_for_range(self.current_block_range().inputRange) | |
310 |
|
383 | |||
311 | def text_for_range(self, textRange): |
|
384 | def text_for_range(self, textRange): | |
312 | """text_for_range""" |
|
385 | """text_for_range""" | |
@@ -315,7 +388,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
315 | return ts.string().substringWithRange_(textRange) |
|
388 | return ts.string().substringWithRange_(textRange) | |
316 |
|
389 | |||
317 | def current_line(self): |
|
390 | def current_line(self): | |
318 | block = self.text_for_range(self.current_block_range()) |
|
391 | block = self.text_for_range(self.current_block_range().inputRange) | |
319 | block = block.split('\n') |
|
392 | block = block.split('\n') | |
320 | return block[-1] |
|
393 | return block[-1] | |
321 |
|
394 | |||
@@ -324,38 +397,28 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
324 | """Insert text into textView at textRange, updating blockRanges |
|
397 | """Insert text into textView at textRange, updating blockRanges | |
325 | as necessary |
|
398 | as necessary | |
326 | """ |
|
399 | """ | |
327 |
|
||||
328 | if(textRange == None): |
|
400 | if(textRange == None): | |
329 | #range for end of text |
|
401 | #range for end of text | |
330 | textRange = NSMakeRange(self.textView.textStorage().length(), 0) |
|
402 | textRange = NSMakeRange(self.textView.textStorage().length(), 0) | |
331 |
|
403 | |||
332 | for r in self.blockRanges.itervalues(): |
|
|||
333 | intersection = NSIntersectionRange(r,textRange) |
|
|||
334 | if(intersection.length == 0): #ranges don't intersect |
|
|||
335 | if r.location >= textRange.location: |
|
|||
336 | r.location += len(string) |
|
|||
337 | else: #ranges intersect |
|
|||
338 | if(r.location <= textRange.location): |
|
|||
339 | assert(intersection.length == textRange.length) |
|
|||
340 | r.length += textRange.length |
|
|||
341 | else: |
|
|||
342 | r.location += intersection.length |
|
|||
343 |
|
404 | |||
344 | self.textView.replaceCharactersInRange_withString_( |
|
405 | self.textView.replaceCharactersInRange_withString_( | |
345 | textRange, string) |
|
406 | textRange, string) | |
346 | self.textView.setSelectedRange_( |
|
407 | ||
347 | NSMakeRange(textRange.location+len(string), 0)) |
|
408 | for r in self.blockRanges.itervalues(): | |
|
409 | r.update_ranges_for_insertion(string, textRange) | |||
|
410 | ||||
|
411 | self.textView.setSelectedRange_(textRange) | |||
348 | if(scrollToVisible): |
|
412 | if(scrollToVisible): | |
349 | self.textView.scrollRangeToVisible_(textRange) |
|
413 | self.textView.scrollRangeToVisible_(textRange) | |
350 |
|
||||
351 |
|
414 | |||
352 |
|
415 | |||
353 |
|
416 | |||
354 | def replace_current_block_with_string(self, textView, string): |
|
417 | def replace_current_block_with_string(self, textView, string): | |
355 | textView.replaceCharactersInRange_withString_( |
|
418 | textView.replaceCharactersInRange_withString_( | |
356 |
|
|
419 | self.current_block_range().inputRange, | |
357 |
|
|
420 | string) | |
358 | self.current_block_range().length = len(string) |
|
421 | self.current_block_range().inputRange.length = len(string) | |
359 | r = NSMakeRange(textView.textStorage().length(), 0) |
|
422 | r = NSMakeRange(textView.textStorage().length(), 0) | |
360 | textView.scrollRangeToVisible_(r) |
|
423 | textView.scrollRangeToVisible_(r) | |
361 | textView.setSelectedRange_(r) |
|
424 | textView.setSelectedRange_(r) | |
@@ -424,26 +487,18 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
424 |
|
487 | |||
425 | elif(selector == 'moveToBeginningOfParagraph:'): |
|
488 | elif(selector == 'moveToBeginningOfParagraph:'): | |
426 | textView.setSelectedRange_(NSMakeRange( |
|
489 | textView.setSelectedRange_(NSMakeRange( | |
427 |
|
|
490 | self.current_block_range().inputRange.location, | |
428 |
|
|
491 | 0)) | |
429 | return True |
|
492 | return True | |
430 | elif(selector == 'moveToEndOfParagraph:'): |
|
493 | elif(selector == 'moveToEndOfParagraph:'): | |
431 | textView.setSelectedRange_(NSMakeRange( |
|
494 | textView.setSelectedRange_(NSMakeRange( | |
432 |
|
|
495 | self.current_block_range().inputRange.location + \ | |
433 |
|
|
496 | self.current_block_range().inputRange.length, 0)) | |
434 | return True |
|
497 | return True | |
435 | elif(selector == 'deleteToEndOfParagraph:'): |
|
498 | elif(selector == 'deleteToEndOfParagraph:'): | |
436 | if(textView.selectedRange().location <= \ |
|
499 | if(textView.selectedRange().location <= \ | |
437 | self.current_block_range().location): |
|
500 | self.current_block_range().location): | |
438 | # Intersect the selected range with the current line range |
|
501 | raise NotImplemented() | |
439 | if(self.current_block_range().length < 0): |
|
|||
440 | self.blockRanges[self.currentBlockID].length = 0 |
|
|||
441 |
|
||||
442 | r = NSIntersectionRange(textView.rangesForUserTextChange()[0], |
|
|||
443 | self.current_block_range()) |
|
|||
444 |
|
||||
445 | if(r.length > 0): #no intersection |
|
|||
446 | textView.setSelectedRange_(r) |
|
|||
447 |
|
502 | |||
448 | return False # don't actually handle the delete |
|
503 | return False # don't actually handle the delete | |
449 |
|
504 | |||
@@ -457,10 +512,15 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
457 | elif(selector == 'deleteBackward:'): |
|
512 | elif(selector == 'deleteBackward:'): | |
458 | #if we're at the beginning of the current block, ignore |
|
513 | #if we're at the beginning of the current block, ignore | |
459 | if(textView.selectedRange().location == \ |
|
514 | if(textView.selectedRange().location == \ | |
460 | self.current_block_range().location): |
|
515 | self.current_block_range().inputRange.location): | |
461 | return True |
|
516 | return True | |
462 | else: |
|
517 | else: | |
463 | self.current_block_range().length-=1 |
|
518 | for r in self.blockRanges.itervalues(): | |
|
519 | deleteRange = textView.selectedRange | |||
|
520 | if(deleteRange.length == 0): | |||
|
521 | deleteRange.location -= 1 | |||
|
522 | deleteRange.length = 1 | |||
|
523 | r.update_ranges_for_deletion(deleteRange) | |||
464 | return False |
|
524 | return False | |
465 | return False |
|
525 | return False | |
466 |
|
526 | |||
@@ -479,14 +539,9 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||||
479 | for r,s in zip(ranges, replacementStrings): |
|
539 | for r,s in zip(ranges, replacementStrings): | |
480 | r = r.rangeValue() |
|
540 | r = r.rangeValue() | |
481 | if(textView.textStorage().length() > 0 and |
|
541 | if(textView.textStorage().length() > 0 and | |
482 |
|
|
542 | r.location < self.current_block_range().inputRange.location): | |
483 | self.insert_text(s) |
|
543 | self.insert_text(s) | |
484 | allow = False |
|
544 | allow = False | |
485 |
|
||||
486 |
|
||||
487 | self.blockRanges.setdefault(self.currentBlockID, |
|
|||
488 | self.current_block_range()).length +=\ |
|
|||
489 | len(s) |
|
|||
490 |
|
545 | |||
491 | return allow |
|
546 | return allow | |
492 |
|
547 |
This diff has been collapsed as it changes many lines, (1033 lines changed) Show them Hide them | |||||
@@ -37,12 +37,12 b'' | |||||
37 | <string key="NSKeyEquiv" id="255189770"/> |
|
37 | <string key="NSKeyEquiv" id="255189770"/> | |
38 | <int key="NSKeyEquivModMask">1048576</int> |
|
38 | <int key="NSKeyEquivModMask">1048576</int> | |
39 | <int key="NSMnemonicLoc">2147483647</int> |
|
39 | <int key="NSMnemonicLoc">2147483647</int> | |
40 |
<object class="NSCustomResource" key="NSOnImage" id=" |
|
40 | <object class="NSCustomResource" key="NSOnImage" id="271266416"> | |
41 |
<string key="NSClassName" id=" |
|
41 | <string key="NSClassName" id="375865337">NSImage</string> | |
42 | <string key="NSResourceName">NSMenuCheckmark</string> |
|
42 | <string key="NSResourceName">NSMenuCheckmark</string> | |
43 | </object> |
|
43 | </object> | |
44 |
<object class="NSCustomResource" key="NSMixedImage" id=" |
|
44 | <object class="NSCustomResource" key="NSMixedImage" id="508123839"> | |
45 |
<reference key="NSClassName" ref=" |
|
45 | <reference key="NSClassName" ref="375865337"/> | |
46 | <string key="NSResourceName">NSMenuMixedState</string> |
|
46 | <string key="NSResourceName">NSMenuMixedState</string> | |
47 | </object> |
|
47 | </object> | |
48 | <string key="NSAction">submenuAction:</string> |
|
48 | <string key="NSAction">submenuAction:</string> | |
@@ -55,8 +55,8 b'' | |||||
55 | <string key="NSTitle">About IPython1Sandbox</string> |
|
55 | <string key="NSTitle">About IPython1Sandbox</string> | |
56 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
56 | <reference key="NSKeyEquiv" ref="255189770"/> | |
57 | <int key="NSMnemonicLoc">2147483647</int> |
|
57 | <int key="NSMnemonicLoc">2147483647</int> | |
58 |
<reference key="NSOnImage" ref=" |
|
58 | <reference key="NSOnImage" ref="271266416"/> | |
59 |
<reference key="NSMixedImage" ref=" |
|
59 | <reference key="NSMixedImage" ref="508123839"/> | |
60 | </object> |
|
60 | </object> | |
61 | <object class="NSMenuItem" id="304266470"> |
|
61 | <object class="NSMenuItem" id="304266470"> | |
62 | <reference key="NSMenu" ref="110575045"/> |
|
62 | <reference key="NSMenu" ref="110575045"/> | |
@@ -66,8 +66,8 b'' | |||||
66 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
66 | <reference key="NSKeyEquiv" ref="255189770"/> | |
67 | <int key="NSKeyEquivModMask">1048576</int> |
|
67 | <int key="NSKeyEquivModMask">1048576</int> | |
68 | <int key="NSMnemonicLoc">2147483647</int> |
|
68 | <int key="NSMnemonicLoc">2147483647</int> | |
69 |
<reference key="NSOnImage" ref=" |
|
69 | <reference key="NSOnImage" ref="271266416"/> | |
70 |
<reference key="NSMixedImage" ref=" |
|
70 | <reference key="NSMixedImage" ref="508123839"/> | |
71 | </object> |
|
71 | </object> | |
72 | <object class="NSMenuItem" id="609285721"> |
|
72 | <object class="NSMenuItem" id="609285721"> | |
73 | <reference key="NSMenu" ref="110575045"/> |
|
73 | <reference key="NSMenu" ref="110575045"/> | |
@@ -75,8 +75,8 b'' | |||||
75 | <string key="NSKeyEquiv">,</string> |
|
75 | <string key="NSKeyEquiv">,</string> | |
76 | <int key="NSKeyEquivModMask">1048576</int> |
|
76 | <int key="NSKeyEquivModMask">1048576</int> | |
77 | <int key="NSMnemonicLoc">2147483647</int> |
|
77 | <int key="NSMnemonicLoc">2147483647</int> | |
78 |
<reference key="NSOnImage" ref=" |
|
78 | <reference key="NSOnImage" ref="271266416"/> | |
79 |
<reference key="NSMixedImage" ref=" |
|
79 | <reference key="NSMixedImage" ref="508123839"/> | |
80 | </object> |
|
80 | </object> | |
81 | <object class="NSMenuItem" id="481834944"> |
|
81 | <object class="NSMenuItem" id="481834944"> | |
82 | <reference key="NSMenu" ref="110575045"/> |
|
82 | <reference key="NSMenu" ref="110575045"/> | |
@@ -86,8 +86,8 b'' | |||||
86 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
86 | <reference key="NSKeyEquiv" ref="255189770"/> | |
87 | <int key="NSKeyEquivModMask">1048576</int> |
|
87 | <int key="NSKeyEquivModMask">1048576</int> | |
88 | <int key="NSMnemonicLoc">2147483647</int> |
|
88 | <int key="NSMnemonicLoc">2147483647</int> | |
89 |
<reference key="NSOnImage" ref=" |
|
89 | <reference key="NSOnImage" ref="271266416"/> | |
90 |
<reference key="NSMixedImage" ref=" |
|
90 | <reference key="NSMixedImage" ref="508123839"/> | |
91 | </object> |
|
91 | </object> | |
92 | <object class="NSMenuItem" id="1046388886"> |
|
92 | <object class="NSMenuItem" id="1046388886"> | |
93 | <reference key="NSMenu" ref="110575045"/> |
|
93 | <reference key="NSMenu" ref="110575045"/> | |
@@ -95,8 +95,8 b'' | |||||
95 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
95 | <reference key="NSKeyEquiv" ref="255189770"/> | |
96 | <int key="NSKeyEquivModMask">1048576</int> |
|
96 | <int key="NSKeyEquivModMask">1048576</int> | |
97 | <int key="NSMnemonicLoc">2147483647</int> |
|
97 | <int key="NSMnemonicLoc">2147483647</int> | |
98 |
<reference key="NSOnImage" ref=" |
|
98 | <reference key="NSOnImage" ref="271266416"/> | |
99 |
<reference key="NSMixedImage" ref=" |
|
99 | <reference key="NSMixedImage" ref="508123839"/> | |
100 | <string key="NSAction">submenuAction:</string> |
|
100 | <string key="NSAction">submenuAction:</string> | |
101 | <object class="NSMenu" key="NSSubmenu" id="752062318"> |
|
101 | <object class="NSMenu" key="NSSubmenu" id="752062318"> | |
102 | <reference key="NSTitle" ref="642338826"/> |
|
102 | <reference key="NSTitle" ref="642338826"/> | |
@@ -114,8 +114,8 b'' | |||||
114 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
114 | <reference key="NSKeyEquiv" ref="255189770"/> | |
115 | <int key="NSKeyEquivModMask">1048576</int> |
|
115 | <int key="NSKeyEquivModMask">1048576</int> | |
116 | <int key="NSMnemonicLoc">2147483647</int> |
|
116 | <int key="NSMnemonicLoc">2147483647</int> | |
117 |
<reference key="NSOnImage" ref=" |
|
117 | <reference key="NSOnImage" ref="271266416"/> | |
118 |
<reference key="NSMixedImage" ref=" |
|
118 | <reference key="NSMixedImage" ref="508123839"/> | |
119 | </object> |
|
119 | </object> | |
120 | <object class="NSMenuItem" id="755159360"> |
|
120 | <object class="NSMenuItem" id="755159360"> | |
121 | <reference key="NSMenu" ref="110575045"/> |
|
121 | <reference key="NSMenu" ref="110575045"/> | |
@@ -123,8 +123,8 b'' | |||||
123 | <string key="NSKeyEquiv" id="940330891">h</string> |
|
123 | <string key="NSKeyEquiv" id="940330891">h</string> | |
124 | <int key="NSKeyEquivModMask">1048576</int> |
|
124 | <int key="NSKeyEquivModMask">1048576</int> | |
125 | <int key="NSMnemonicLoc">2147483647</int> |
|
125 | <int key="NSMnemonicLoc">2147483647</int> | |
126 |
<reference key="NSOnImage" ref=" |
|
126 | <reference key="NSOnImage" ref="271266416"/> | |
127 |
<reference key="NSMixedImage" ref=" |
|
127 | <reference key="NSMixedImage" ref="508123839"/> | |
128 | </object> |
|
128 | </object> | |
129 | <object class="NSMenuItem" id="342932134"> |
|
129 | <object class="NSMenuItem" id="342932134"> | |
130 | <reference key="NSMenu" ref="110575045"/> |
|
130 | <reference key="NSMenu" ref="110575045"/> | |
@@ -132,8 +132,8 b'' | |||||
132 | <reference key="NSKeyEquiv" ref="940330891"/> |
|
132 | <reference key="NSKeyEquiv" ref="940330891"/> | |
133 | <int key="NSKeyEquivModMask">1572864</int> |
|
133 | <int key="NSKeyEquivModMask">1572864</int> | |
134 | <int key="NSMnemonicLoc">2147483647</int> |
|
134 | <int key="NSMnemonicLoc">2147483647</int> | |
135 |
<reference key="NSOnImage" ref=" |
|
135 | <reference key="NSOnImage" ref="271266416"/> | |
136 |
<reference key="NSMixedImage" ref=" |
|
136 | <reference key="NSMixedImage" ref="508123839"/> | |
137 | </object> |
|
137 | </object> | |
138 | <object class="NSMenuItem" id="908899353"> |
|
138 | <object class="NSMenuItem" id="908899353"> | |
139 | <reference key="NSMenu" ref="110575045"/> |
|
139 | <reference key="NSMenu" ref="110575045"/> | |
@@ -141,8 +141,8 b'' | |||||
141 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
141 | <reference key="NSKeyEquiv" ref="255189770"/> | |
142 | <int key="NSKeyEquivModMask">1048576</int> |
|
142 | <int key="NSKeyEquivModMask">1048576</int> | |
143 | <int key="NSMnemonicLoc">2147483647</int> |
|
143 | <int key="NSMnemonicLoc">2147483647</int> | |
144 |
<reference key="NSOnImage" ref=" |
|
144 | <reference key="NSOnImage" ref="271266416"/> | |
145 |
<reference key="NSMixedImage" ref=" |
|
145 | <reference key="NSMixedImage" ref="508123839"/> | |
146 | </object> |
|
146 | </object> | |
147 | <object class="NSMenuItem" id="1056857174"> |
|
147 | <object class="NSMenuItem" id="1056857174"> | |
148 | <reference key="NSMenu" ref="110575045"/> |
|
148 | <reference key="NSMenu" ref="110575045"/> | |
@@ -152,8 +152,8 b'' | |||||
152 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
152 | <reference key="NSKeyEquiv" ref="255189770"/> | |
153 | <int key="NSKeyEquivModMask">1048576</int> |
|
153 | <int key="NSKeyEquivModMask">1048576</int> | |
154 | <int key="NSMnemonicLoc">2147483647</int> |
|
154 | <int key="NSMnemonicLoc">2147483647</int> | |
155 |
<reference key="NSOnImage" ref=" |
|
155 | <reference key="NSOnImage" ref="271266416"/> | |
156 |
<reference key="NSMixedImage" ref=" |
|
156 | <reference key="NSMixedImage" ref="508123839"/> | |
157 | </object> |
|
157 | </object> | |
158 | <object class="NSMenuItem" id="632727374"> |
|
158 | <object class="NSMenuItem" id="632727374"> | |
159 | <reference key="NSMenu" ref="110575045"/> |
|
159 | <reference key="NSMenu" ref="110575045"/> | |
@@ -161,8 +161,8 b'' | |||||
161 | <string key="NSKeyEquiv">q</string> |
|
161 | <string key="NSKeyEquiv">q</string> | |
162 | <int key="NSKeyEquivModMask">1048576</int> |
|
162 | <int key="NSKeyEquivModMask">1048576</int> | |
163 | <int key="NSMnemonicLoc">2147483647</int> |
|
163 | <int key="NSMnemonicLoc">2147483647</int> | |
164 |
<reference key="NSOnImage" ref=" |
|
164 | <reference key="NSOnImage" ref="271266416"/> | |
165 |
<reference key="NSMixedImage" ref=" |
|
165 | <reference key="NSMixedImage" ref="508123839"/> | |
166 | </object> |
|
166 | </object> | |
167 | </object> |
|
167 | </object> | |
168 | <string key="NSName">_NSAppleMenu</string> |
|
168 | <string key="NSName">_NSAppleMenu</string> | |
@@ -174,8 +174,8 b'' | |||||
174 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
174 | <reference key="NSKeyEquiv" ref="255189770"/> | |
175 | <int key="NSKeyEquivModMask">1048576</int> |
|
175 | <int key="NSKeyEquivModMask">1048576</int> | |
176 | <int key="NSMnemonicLoc">2147483647</int> |
|
176 | <int key="NSMnemonicLoc">2147483647</int> | |
177 |
<reference key="NSOnImage" ref=" |
|
177 | <reference key="NSOnImage" ref="271266416"/> | |
178 |
<reference key="NSMixedImage" ref=" |
|
178 | <reference key="NSMixedImage" ref="508123839"/> | |
179 | <string key="NSAction">submenuAction:</string> |
|
179 | <string key="NSAction">submenuAction:</string> | |
180 | <object class="NSMenu" key="NSSubmenu" id="720053764"> |
|
180 | <object class="NSMenu" key="NSSubmenu" id="720053764"> | |
181 | <reference key="NSTitle" ref="881404960"/> |
|
181 | <reference key="NSTitle" ref="881404960"/> | |
@@ -187,8 +187,8 b'' | |||||
187 | <string key="NSKeyEquiv">n</string> |
|
187 | <string key="NSKeyEquiv">n</string> | |
188 | <int key="NSKeyEquivModMask">1048576</int> |
|
188 | <int key="NSKeyEquivModMask">1048576</int> | |
189 | <int key="NSMnemonicLoc">2147483647</int> |
|
189 | <int key="NSMnemonicLoc">2147483647</int> | |
190 |
<reference key="NSOnImage" ref=" |
|
190 | <reference key="NSOnImage" ref="271266416"/> | |
191 |
<reference key="NSMixedImage" ref=" |
|
191 | <reference key="NSMixedImage" ref="508123839"/> | |
192 | </object> |
|
192 | </object> | |
193 | <object class="NSMenuItem" id="722745758"> |
|
193 | <object class="NSMenuItem" id="722745758"> | |
194 | <reference key="NSMenu" ref="720053764"/> |
|
194 | <reference key="NSMenu" ref="720053764"/> | |
@@ -196,8 +196,8 b'' | |||||
196 | <string key="NSKeyEquiv">o</string> |
|
196 | <string key="NSKeyEquiv">o</string> | |
197 | <int key="NSKeyEquivModMask">1048576</int> |
|
197 | <int key="NSKeyEquivModMask">1048576</int> | |
198 | <int key="NSMnemonicLoc">2147483647</int> |
|
198 | <int key="NSMnemonicLoc">2147483647</int> | |
199 |
<reference key="NSOnImage" ref=" |
|
199 | <reference key="NSOnImage" ref="271266416"/> | |
200 |
<reference key="NSMixedImage" ref=" |
|
200 | <reference key="NSMixedImage" ref="508123839"/> | |
201 | </object> |
|
201 | </object> | |
202 | <object class="NSMenuItem" id="1025936716"> |
|
202 | <object class="NSMenuItem" id="1025936716"> | |
203 | <reference key="NSMenu" ref="720053764"/> |
|
203 | <reference key="NSMenu" ref="720053764"/> | |
@@ -205,8 +205,8 b'' | |||||
205 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
205 | <reference key="NSKeyEquiv" ref="255189770"/> | |
206 | <int key="NSKeyEquivModMask">1048576</int> |
|
206 | <int key="NSKeyEquivModMask">1048576</int> | |
207 | <int key="NSMnemonicLoc">2147483647</int> |
|
207 | <int key="NSMnemonicLoc">2147483647</int> | |
208 |
<reference key="NSOnImage" ref=" |
|
208 | <reference key="NSOnImage" ref="271266416"/> | |
209 |
<reference key="NSMixedImage" ref=" |
|
209 | <reference key="NSMixedImage" ref="508123839"/> | |
210 | <string key="NSAction">submenuAction:</string> |
|
210 | <string key="NSAction">submenuAction:</string> | |
211 | <object class="NSMenu" key="NSSubmenu" id="1065607017"> |
|
211 | <object class="NSMenu" key="NSSubmenu" id="1065607017"> | |
212 | <reference key="NSTitle" ref="975517829"/> |
|
212 | <reference key="NSTitle" ref="975517829"/> | |
@@ -218,8 +218,8 b'' | |||||
218 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
218 | <reference key="NSKeyEquiv" ref="255189770"/> | |
219 | <int key="NSKeyEquivModMask">1048576</int> |
|
219 | <int key="NSKeyEquivModMask">1048576</int> | |
220 | <int key="NSMnemonicLoc">2147483647</int> |
|
220 | <int key="NSMnemonicLoc">2147483647</int> | |
221 |
<reference key="NSOnImage" ref=" |
|
221 | <reference key="NSOnImage" ref="271266416"/> | |
222 |
<reference key="NSMixedImage" ref=" |
|
222 | <reference key="NSMixedImage" ref="508123839"/> | |
223 | </object> |
|
223 | </object> | |
224 | </object> |
|
224 | </object> | |
225 | <string key="NSName">_NSRecentDocumentsMenu</string> |
|
225 | <string key="NSName">_NSRecentDocumentsMenu</string> | |
@@ -233,8 +233,8 b'' | |||||
233 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
233 | <reference key="NSKeyEquiv" ref="255189770"/> | |
234 | <int key="NSKeyEquivModMask">1048576</int> |
|
234 | <int key="NSKeyEquivModMask">1048576</int> | |
235 | <int key="NSMnemonicLoc">2147483647</int> |
|
235 | <int key="NSMnemonicLoc">2147483647</int> | |
236 |
<reference key="NSOnImage" ref=" |
|
236 | <reference key="NSOnImage" ref="271266416"/> | |
237 |
<reference key="NSMixedImage" ref=" |
|
237 | <reference key="NSMixedImage" ref="508123839"/> | |
238 | </object> |
|
238 | </object> | |
239 | <object class="NSMenuItem" id="776162233"> |
|
239 | <object class="NSMenuItem" id="776162233"> | |
240 | <reference key="NSMenu" ref="720053764"/> |
|
240 | <reference key="NSMenu" ref="720053764"/> | |
@@ -242,8 +242,8 b'' | |||||
242 | <string key="NSKeyEquiv">w</string> |
|
242 | <string key="NSKeyEquiv">w</string> | |
243 | <int key="NSKeyEquivModMask">1048576</int> |
|
243 | <int key="NSKeyEquivModMask">1048576</int> | |
244 | <int key="NSMnemonicLoc">2147483647</int> |
|
244 | <int key="NSMnemonicLoc">2147483647</int> | |
245 |
<reference key="NSOnImage" ref=" |
|
245 | <reference key="NSOnImage" ref="271266416"/> | |
246 |
<reference key="NSMixedImage" ref=" |
|
246 | <reference key="NSMixedImage" ref="508123839"/> | |
247 | </object> |
|
247 | </object> | |
248 | <object class="NSMenuItem" id="1023925487"> |
|
248 | <object class="NSMenuItem" id="1023925487"> | |
249 | <reference key="NSMenu" ref="720053764"/> |
|
249 | <reference key="NSMenu" ref="720053764"/> | |
@@ -251,8 +251,8 b'' | |||||
251 | <string key="NSKeyEquiv">s</string> |
|
251 | <string key="NSKeyEquiv">s</string> | |
252 | <int key="NSKeyEquivModMask">1048576</int> |
|
252 | <int key="NSKeyEquivModMask">1048576</int> | |
253 | <int key="NSMnemonicLoc">2147483647</int> |
|
253 | <int key="NSMnemonicLoc">2147483647</int> | |
254 |
<reference key="NSOnImage" ref=" |
|
254 | <reference key="NSOnImage" ref="271266416"/> | |
255 |
<reference key="NSMixedImage" ref=" |
|
255 | <reference key="NSMixedImage" ref="508123839"/> | |
256 | </object> |
|
256 | </object> | |
257 | <object class="NSMenuItem" id="117038363"> |
|
257 | <object class="NSMenuItem" id="117038363"> | |
258 | <reference key="NSMenu" ref="720053764"/> |
|
258 | <reference key="NSMenu" ref="720053764"/> | |
@@ -260,16 +260,16 b'' | |||||
260 | <string key="NSKeyEquiv">S</string> |
|
260 | <string key="NSKeyEquiv">S</string> | |
261 | <int key="NSKeyEquivModMask">1179648</int> |
|
261 | <int key="NSKeyEquivModMask">1179648</int> | |
262 | <int key="NSMnemonicLoc">2147483647</int> |
|
262 | <int key="NSMnemonicLoc">2147483647</int> | |
263 |
<reference key="NSOnImage" ref=" |
|
263 | <reference key="NSOnImage" ref="271266416"/> | |
264 |
<reference key="NSMixedImage" ref=" |
|
264 | <reference key="NSMixedImage" ref="508123839"/> | |
265 | </object> |
|
265 | </object> | |
266 | <object class="NSMenuItem" id="579971712"> |
|
266 | <object class="NSMenuItem" id="579971712"> | |
267 | <reference key="NSMenu" ref="720053764"/> |
|
267 | <reference key="NSMenu" ref="720053764"/> | |
268 | <string key="NSTitle">Revert to Saved</string> |
|
268 | <string key="NSTitle">Revert to Saved</string> | |
269 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
269 | <reference key="NSKeyEquiv" ref="255189770"/> | |
270 | <int key="NSMnemonicLoc">2147483647</int> |
|
270 | <int key="NSMnemonicLoc">2147483647</int> | |
271 |
<reference key="NSOnImage" ref=" |
|
271 | <reference key="NSOnImage" ref="271266416"/> | |
272 |
<reference key="NSMixedImage" ref=" |
|
272 | <reference key="NSMixedImage" ref="508123839"/> | |
273 | </object> |
|
273 | </object> | |
274 | <object class="NSMenuItem" id="1010469920"> |
|
274 | <object class="NSMenuItem" id="1010469920"> | |
275 | <reference key="NSMenu" ref="720053764"/> |
|
275 | <reference key="NSMenu" ref="720053764"/> | |
@@ -279,8 +279,8 b'' | |||||
279 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
279 | <reference key="NSKeyEquiv" ref="255189770"/> | |
280 | <int key="NSKeyEquivModMask">1048576</int> |
|
280 | <int key="NSKeyEquivModMask">1048576</int> | |
281 | <int key="NSMnemonicLoc">2147483647</int> |
|
281 | <int key="NSMnemonicLoc">2147483647</int> | |
282 |
<reference key="NSOnImage" ref=" |
|
282 | <reference key="NSOnImage" ref="271266416"/> | |
283 |
<reference key="NSMixedImage" ref=" |
|
283 | <reference key="NSMixedImage" ref="508123839"/> | |
284 | </object> |
|
284 | </object> | |
285 | <object class="NSMenuItem" id="294629803"> |
|
285 | <object class="NSMenuItem" id="294629803"> | |
286 | <reference key="NSMenu" ref="720053764"/> |
|
286 | <reference key="NSMenu" ref="720053764"/> | |
@@ -288,8 +288,8 b'' | |||||
288 | <string key="NSKeyEquiv">P</string> |
|
288 | <string key="NSKeyEquiv">P</string> | |
289 | <int key="NSKeyEquivModMask">1179648</int> |
|
289 | <int key="NSKeyEquivModMask">1179648</int> | |
290 | <int key="NSMnemonicLoc">2147483647</int> |
|
290 | <int key="NSMnemonicLoc">2147483647</int> | |
291 |
<reference key="NSOnImage" ref=" |
|
291 | <reference key="NSOnImage" ref="271266416"/> | |
292 |
<reference key="NSMixedImage" ref=" |
|
292 | <reference key="NSMixedImage" ref="508123839"/> | |
293 | <reference key="NSToolTip" ref="255189770"/> |
|
293 | <reference key="NSToolTip" ref="255189770"/> | |
294 | </object> |
|
294 | </object> | |
295 | <object class="NSMenuItem" id="49223823"> |
|
295 | <object class="NSMenuItem" id="49223823"> | |
@@ -298,8 +298,8 b'' | |||||
298 | <string key="NSKeyEquiv">p</string> |
|
298 | <string key="NSKeyEquiv">p</string> | |
299 | <int key="NSKeyEquivModMask">1048576</int> |
|
299 | <int key="NSKeyEquivModMask">1048576</int> | |
300 | <int key="NSMnemonicLoc">2147483647</int> |
|
300 | <int key="NSMnemonicLoc">2147483647</int> | |
301 |
<reference key="NSOnImage" ref=" |
|
301 | <reference key="NSOnImage" ref="271266416"/> | |
302 |
<reference key="NSMixedImage" ref=" |
|
302 | <reference key="NSMixedImage" ref="508123839"/> | |
303 | </object> |
|
303 | </object> | |
304 | </object> |
|
304 | </object> | |
305 | </object> |
|
305 | </object> | |
@@ -310,8 +310,8 b'' | |||||
310 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
310 | <reference key="NSKeyEquiv" ref="255189770"/> | |
311 | <int key="NSKeyEquivModMask">1048576</int> |
|
311 | <int key="NSKeyEquivModMask">1048576</int> | |
312 | <int key="NSMnemonicLoc">2147483647</int> |
|
312 | <int key="NSMnemonicLoc">2147483647</int> | |
313 |
<reference key="NSOnImage" ref=" |
|
313 | <reference key="NSOnImage" ref="271266416"/> | |
314 |
<reference key="NSMixedImage" ref=" |
|
314 | <reference key="NSMixedImage" ref="508123839"/> | |
315 | <string key="NSAction">submenuAction:</string> |
|
315 | <string key="NSAction">submenuAction:</string> | |
316 | <object class="NSMenu" key="NSSubmenu" id="789758025"> |
|
316 | <object class="NSMenu" key="NSSubmenu" id="789758025"> | |
317 | <reference key="NSTitle" ref="1037326483"/> |
|
317 | <reference key="NSTitle" ref="1037326483"/> | |
@@ -323,8 +323,8 b'' | |||||
323 | <string key="NSKeyEquiv">z</string> |
|
323 | <string key="NSKeyEquiv">z</string> | |
324 | <int key="NSKeyEquivModMask">1048576</int> |
|
324 | <int key="NSKeyEquivModMask">1048576</int> | |
325 | <int key="NSMnemonicLoc">2147483647</int> |
|
325 | <int key="NSMnemonicLoc">2147483647</int> | |
326 |
<reference key="NSOnImage" ref=" |
|
326 | <reference key="NSOnImage" ref="271266416"/> | |
327 |
<reference key="NSMixedImage" ref=" |
|
327 | <reference key="NSMixedImage" ref="508123839"/> | |
328 | </object> |
|
328 | </object> | |
329 | <object class="NSMenuItem" id="790794224"> |
|
329 | <object class="NSMenuItem" id="790794224"> | |
330 | <reference key="NSMenu" ref="789758025"/> |
|
330 | <reference key="NSMenu" ref="789758025"/> | |
@@ -332,8 +332,8 b'' | |||||
332 | <string key="NSKeyEquiv">Z</string> |
|
332 | <string key="NSKeyEquiv">Z</string> | |
333 | <int key="NSKeyEquivModMask">1179648</int> |
|
333 | <int key="NSKeyEquivModMask">1179648</int> | |
334 | <int key="NSMnemonicLoc">2147483647</int> |
|
334 | <int key="NSMnemonicLoc">2147483647</int> | |
335 |
<reference key="NSOnImage" ref=" |
|
335 | <reference key="NSOnImage" ref="271266416"/> | |
336 |
<reference key="NSMixedImage" ref=" |
|
336 | <reference key="NSMixedImage" ref="508123839"/> | |
337 | </object> |
|
337 | </object> | |
338 | <object class="NSMenuItem" id="1040322652"> |
|
338 | <object class="NSMenuItem" id="1040322652"> | |
339 | <reference key="NSMenu" ref="789758025"/> |
|
339 | <reference key="NSMenu" ref="789758025"/> | |
@@ -343,8 +343,8 b'' | |||||
343 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
343 | <reference key="NSKeyEquiv" ref="255189770"/> | |
344 | <int key="NSKeyEquivModMask">1048576</int> |
|
344 | <int key="NSKeyEquivModMask">1048576</int> | |
345 | <int key="NSMnemonicLoc">2147483647</int> |
|
345 | <int key="NSMnemonicLoc">2147483647</int> | |
346 |
<reference key="NSOnImage" ref=" |
|
346 | <reference key="NSOnImage" ref="271266416"/> | |
347 |
<reference key="NSMixedImage" ref=" |
|
347 | <reference key="NSMixedImage" ref="508123839"/> | |
348 | </object> |
|
348 | </object> | |
349 | <object class="NSMenuItem" id="296257095"> |
|
349 | <object class="NSMenuItem" id="296257095"> | |
350 | <reference key="NSMenu" ref="789758025"/> |
|
350 | <reference key="NSMenu" ref="789758025"/> | |
@@ -352,8 +352,8 b'' | |||||
352 | <string key="NSKeyEquiv">x</string> |
|
352 | <string key="NSKeyEquiv">x</string> | |
353 | <int key="NSKeyEquivModMask">1048576</int> |
|
353 | <int key="NSKeyEquivModMask">1048576</int> | |
354 | <int key="NSMnemonicLoc">2147483647</int> |
|
354 | <int key="NSMnemonicLoc">2147483647</int> | |
355 |
<reference key="NSOnImage" ref=" |
|
355 | <reference key="NSOnImage" ref="271266416"/> | |
356 |
<reference key="NSMixedImage" ref=" |
|
356 | <reference key="NSMixedImage" ref="508123839"/> | |
357 | </object> |
|
357 | </object> | |
358 | <object class="NSMenuItem" id="860595796"> |
|
358 | <object class="NSMenuItem" id="860595796"> | |
359 | <reference key="NSMenu" ref="789758025"/> |
|
359 | <reference key="NSMenu" ref="789758025"/> | |
@@ -361,8 +361,8 b'' | |||||
361 | <string key="NSKeyEquiv">c</string> |
|
361 | <string key="NSKeyEquiv">c</string> | |
362 | <int key="NSKeyEquivModMask">1048576</int> |
|
362 | <int key="NSKeyEquivModMask">1048576</int> | |
363 | <int key="NSMnemonicLoc">2147483647</int> |
|
363 | <int key="NSMnemonicLoc">2147483647</int> | |
364 |
<reference key="NSOnImage" ref=" |
|
364 | <reference key="NSOnImage" ref="271266416"/> | |
365 |
<reference key="NSMixedImage" ref=" |
|
365 | <reference key="NSMixedImage" ref="508123839"/> | |
366 | </object> |
|
366 | </object> | |
367 | <object class="NSMenuItem" id="29853731"> |
|
367 | <object class="NSMenuItem" id="29853731"> | |
368 | <reference key="NSMenu" ref="789758025"/> |
|
368 | <reference key="NSMenu" ref="789758025"/> | |
@@ -370,8 +370,8 b'' | |||||
370 | <string key="NSKeyEquiv">v</string> |
|
370 | <string key="NSKeyEquiv">v</string> | |
371 | <int key="NSKeyEquivModMask">1048576</int> |
|
371 | <int key="NSKeyEquivModMask">1048576</int> | |
372 | <int key="NSMnemonicLoc">2147483647</int> |
|
372 | <int key="NSMnemonicLoc">2147483647</int> | |
373 |
<reference key="NSOnImage" ref=" |
|
373 | <reference key="NSOnImage" ref="271266416"/> | |
374 |
<reference key="NSMixedImage" ref=" |
|
374 | <reference key="NSMixedImage" ref="508123839"/> | |
375 | </object> |
|
375 | </object> | |
376 | <object class="NSMenuItem" id="437104165"> |
|
376 | <object class="NSMenuItem" id="437104165"> | |
377 | <reference key="NSMenu" ref="789758025"/> |
|
377 | <reference key="NSMenu" ref="789758025"/> | |
@@ -379,8 +379,8 b'' | |||||
379 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
379 | <reference key="NSKeyEquiv" ref="255189770"/> | |
380 | <int key="NSKeyEquivModMask">1048576</int> |
|
380 | <int key="NSKeyEquivModMask">1048576</int> | |
381 | <int key="NSMnemonicLoc">2147483647</int> |
|
381 | <int key="NSMnemonicLoc">2147483647</int> | |
382 |
<reference key="NSOnImage" ref=" |
|
382 | <reference key="NSOnImage" ref="271266416"/> | |
383 |
<reference key="NSMixedImage" ref=" |
|
383 | <reference key="NSMixedImage" ref="508123839"/> | |
384 | </object> |
|
384 | </object> | |
385 | <object class="NSMenuItem" id="583158037"> |
|
385 | <object class="NSMenuItem" id="583158037"> | |
386 | <reference key="NSMenu" ref="789758025"/> |
|
386 | <reference key="NSMenu" ref="789758025"/> | |
@@ -388,8 +388,8 b'' | |||||
388 | <string key="NSKeyEquiv">a</string> |
|
388 | <string key="NSKeyEquiv">a</string> | |
389 | <int key="NSKeyEquivModMask">1048576</int> |
|
389 | <int key="NSKeyEquivModMask">1048576</int> | |
390 | <int key="NSMnemonicLoc">2147483647</int> |
|
390 | <int key="NSMnemonicLoc">2147483647</int> | |
391 |
<reference key="NSOnImage" ref=" |
|
391 | <reference key="NSOnImage" ref="271266416"/> | |
392 |
<reference key="NSMixedImage" ref=" |
|
392 | <reference key="NSMixedImage" ref="508123839"/> | |
393 | </object> |
|
393 | </object> | |
394 | <object class="NSMenuItem" id="212016141"> |
|
394 | <object class="NSMenuItem" id="212016141"> | |
395 | <reference key="NSMenu" ref="789758025"/> |
|
395 | <reference key="NSMenu" ref="789758025"/> | |
@@ -399,8 +399,8 b'' | |||||
399 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
399 | <reference key="NSKeyEquiv" ref="255189770"/> | |
400 | <int key="NSKeyEquivModMask">1048576</int> |
|
400 | <int key="NSKeyEquivModMask">1048576</int> | |
401 | <int key="NSMnemonicLoc">2147483647</int> |
|
401 | <int key="NSMnemonicLoc">2147483647</int> | |
402 |
<reference key="NSOnImage" ref=" |
|
402 | <reference key="NSOnImage" ref="271266416"/> | |
403 |
<reference key="NSMixedImage" ref=" |
|
403 | <reference key="NSMixedImage" ref="508123839"/> | |
404 | </object> |
|
404 | </object> | |
405 | <object class="NSMenuItem" id="892235320"> |
|
405 | <object class="NSMenuItem" id="892235320"> | |
406 | <reference key="NSMenu" ref="789758025"/> |
|
406 | <reference key="NSMenu" ref="789758025"/> | |
@@ -408,8 +408,8 b'' | |||||
408 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
408 | <reference key="NSKeyEquiv" ref="255189770"/> | |
409 | <int key="NSKeyEquivModMask">1048576</int> |
|
409 | <int key="NSKeyEquivModMask">1048576</int> | |
410 | <int key="NSMnemonicLoc">2147483647</int> |
|
410 | <int key="NSMnemonicLoc">2147483647</int> | |
411 |
<reference key="NSOnImage" ref=" |
|
411 | <reference key="NSOnImage" ref="271266416"/> | |
412 |
<reference key="NSMixedImage" ref=" |
|
412 | <reference key="NSMixedImage" ref="508123839"/> | |
413 | <string key="NSAction">submenuAction:</string> |
|
413 | <string key="NSAction">submenuAction:</string> | |
414 | <object class="NSMenu" key="NSSubmenu" id="963351320"> |
|
414 | <object class="NSMenu" key="NSSubmenu" id="963351320"> | |
415 | <reference key="NSTitle" ref="688083180"/> |
|
415 | <reference key="NSTitle" ref="688083180"/> | |
@@ -421,8 +421,8 b'' | |||||
421 | <string key="NSKeyEquiv" id="469505129">f</string> |
|
421 | <string key="NSKeyEquiv" id="469505129">f</string> | |
422 | <int key="NSKeyEquivModMask">1048576</int> |
|
422 | <int key="NSKeyEquivModMask">1048576</int> | |
423 | <int key="NSMnemonicLoc">2147483647</int> |
|
423 | <int key="NSMnemonicLoc">2147483647</int> | |
424 |
<reference key="NSOnImage" ref=" |
|
424 | <reference key="NSOnImage" ref="271266416"/> | |
425 |
<reference key="NSMixedImage" ref=" |
|
425 | <reference key="NSMixedImage" ref="508123839"/> | |
426 | <int key="NSTag">1</int> |
|
426 | <int key="NSTag">1</int> | |
427 | </object> |
|
427 | </object> | |
428 | <object class="NSMenuItem" id="326711663"> |
|
428 | <object class="NSMenuItem" id="326711663"> | |
@@ -431,8 +431,8 b'' | |||||
431 | <string key="NSKeyEquiv" id="762398675">g</string> |
|
431 | <string key="NSKeyEquiv" id="762398675">g</string> | |
432 | <int key="NSKeyEquivModMask">1048576</int> |
|
432 | <int key="NSKeyEquivModMask">1048576</int> | |
433 | <int key="NSMnemonicLoc">2147483647</int> |
|
433 | <int key="NSMnemonicLoc">2147483647</int> | |
434 |
<reference key="NSOnImage" ref=" |
|
434 | <reference key="NSOnImage" ref="271266416"/> | |
435 |
<reference key="NSMixedImage" ref=" |
|
435 | <reference key="NSMixedImage" ref="508123839"/> | |
436 | <int key="NSTag">2</int> |
|
436 | <int key="NSTag">2</int> | |
437 | </object> |
|
437 | </object> | |
438 | <object class="NSMenuItem" id="270902937"> |
|
438 | <object class="NSMenuItem" id="270902937"> | |
@@ -441,8 +441,8 b'' | |||||
441 | <string key="NSKeyEquiv" id="819654342">G</string> |
|
441 | <string key="NSKeyEquiv" id="819654342">G</string> | |
442 | <int key="NSKeyEquivModMask">1179648</int> |
|
442 | <int key="NSKeyEquivModMask">1179648</int> | |
443 | <int key="NSMnemonicLoc">2147483647</int> |
|
443 | <int key="NSMnemonicLoc">2147483647</int> | |
444 |
<reference key="NSOnImage" ref=" |
|
444 | <reference key="NSOnImage" ref="271266416"/> | |
445 |
<reference key="NSMixedImage" ref=" |
|
445 | <reference key="NSMixedImage" ref="508123839"/> | |
446 | <int key="NSTag">3</int> |
|
446 | <int key="NSTag">3</int> | |
447 | </object> |
|
447 | </object> | |
448 | <object class="NSMenuItem" id="159080638"> |
|
448 | <object class="NSMenuItem" id="159080638"> | |
@@ -451,8 +451,8 b'' | |||||
451 | <string key="NSKeyEquiv">e</string> |
|
451 | <string key="NSKeyEquiv">e</string> | |
452 | <int key="NSKeyEquivModMask">1048576</int> |
|
452 | <int key="NSKeyEquivModMask">1048576</int> | |
453 | <int key="NSMnemonicLoc">2147483647</int> |
|
453 | <int key="NSMnemonicLoc">2147483647</int> | |
454 |
<reference key="NSOnImage" ref=" |
|
454 | <reference key="NSOnImage" ref="271266416"/> | |
455 |
<reference key="NSMixedImage" ref=" |
|
455 | <reference key="NSMixedImage" ref="508123839"/> | |
456 | <int key="NSTag">7</int> |
|
456 | <int key="NSTag">7</int> | |
457 | </object> |
|
457 | </object> | |
458 | <object class="NSMenuItem" id="88285865"> |
|
458 | <object class="NSMenuItem" id="88285865"> | |
@@ -461,8 +461,8 b'' | |||||
461 | <string key="NSKeyEquiv">j</string> |
|
461 | <string key="NSKeyEquiv">j</string> | |
462 | <int key="NSKeyEquivModMask">1048576</int> |
|
462 | <int key="NSKeyEquivModMask">1048576</int> | |
463 | <int key="NSMnemonicLoc">2147483647</int> |
|
463 | <int key="NSMnemonicLoc">2147483647</int> | |
464 |
<reference key="NSOnImage" ref=" |
|
464 | <reference key="NSOnImage" ref="271266416"/> | |
465 |
<reference key="NSMixedImage" ref=" |
|
465 | <reference key="NSMixedImage" ref="508123839"/> | |
466 | </object> |
|
466 | </object> | |
467 | </object> |
|
467 | </object> | |
468 | </object> |
|
468 | </object> | |
@@ -473,8 +473,8 b'' | |||||
473 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
473 | <reference key="NSKeyEquiv" ref="255189770"/> | |
474 | <int key="NSKeyEquivModMask">1048576</int> |
|
474 | <int key="NSKeyEquivModMask">1048576</int> | |
475 | <int key="NSMnemonicLoc">2147483647</int> |
|
475 | <int key="NSMnemonicLoc">2147483647</int> | |
476 |
<reference key="NSOnImage" ref=" |
|
476 | <reference key="NSOnImage" ref="271266416"/> | |
477 |
<reference key="NSMixedImage" ref=" |
|
477 | <reference key="NSMixedImage" ref="508123839"/> | |
478 | <string key="NSAction">submenuAction:</string> |
|
478 | <string key="NSAction">submenuAction:</string> | |
479 | <object class="NSMenu" key="NSSubmenu" id="769623530"> |
|
479 | <object class="NSMenu" key="NSSubmenu" id="769623530"> | |
480 | <reference key="NSTitle" ref="739167250"/> |
|
480 | <reference key="NSTitle" ref="739167250"/> | |
@@ -486,8 +486,8 b'' | |||||
486 | <string key="NSKeyEquiv">:</string> |
|
486 | <string key="NSKeyEquiv">:</string> | |
487 | <int key="NSKeyEquivModMask">1048576</int> |
|
487 | <int key="NSKeyEquivModMask">1048576</int> | |
488 | <int key="NSMnemonicLoc">2147483647</int> |
|
488 | <int key="NSMnemonicLoc">2147483647</int> | |
489 |
<reference key="NSOnImage" ref=" |
|
489 | <reference key="NSOnImage" ref="271266416"/> | |
490 |
<reference key="NSMixedImage" ref=" |
|
490 | <reference key="NSMixedImage" ref="508123839"/> | |
491 | </object> |
|
491 | </object> | |
492 | <object class="NSMenuItem" id="96193923"> |
|
492 | <object class="NSMenuItem" id="96193923"> | |
493 | <reference key="NSMenu" ref="769623530"/> |
|
493 | <reference key="NSMenu" ref="769623530"/> | |
@@ -495,8 +495,8 b'' | |||||
495 | <string key="NSKeyEquiv">;</string> |
|
495 | <string key="NSKeyEquiv">;</string> | |
496 | <int key="NSKeyEquivModMask">1048576</int> |
|
496 | <int key="NSKeyEquivModMask">1048576</int> | |
497 | <int key="NSMnemonicLoc">2147483647</int> |
|
497 | <int key="NSMnemonicLoc">2147483647</int> | |
498 |
<reference key="NSOnImage" ref=" |
|
498 | <reference key="NSOnImage" ref="271266416"/> | |
499 |
<reference key="NSMixedImage" ref=" |
|
499 | <reference key="NSMixedImage" ref="508123839"/> | |
500 | </object> |
|
500 | </object> | |
501 | <object class="NSMenuItem" id="948374510"> |
|
501 | <object class="NSMenuItem" id="948374510"> | |
502 | <reference key="NSMenu" ref="769623530"/> |
|
502 | <reference key="NSMenu" ref="769623530"/> | |
@@ -504,8 +504,8 b'' | |||||
504 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
504 | <reference key="NSKeyEquiv" ref="255189770"/> | |
505 | <int key="NSKeyEquivModMask">1048576</int> |
|
505 | <int key="NSKeyEquivModMask">1048576</int> | |
506 | <int key="NSMnemonicLoc">2147483647</int> |
|
506 | <int key="NSMnemonicLoc">2147483647</int> | |
507 |
<reference key="NSOnImage" ref=" |
|
507 | <reference key="NSOnImage" ref="271266416"/> | |
508 |
<reference key="NSMixedImage" ref=" |
|
508 | <reference key="NSMixedImage" ref="508123839"/> | |
509 | </object> |
|
509 | </object> | |
510 | <object class="NSMenuItem" id="967646866"> |
|
510 | <object class="NSMenuItem" id="967646866"> | |
511 | <reference key="NSMenu" ref="769623530"/> |
|
511 | <reference key="NSMenu" ref="769623530"/> | |
@@ -513,8 +513,8 b'' | |||||
513 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
513 | <reference key="NSKeyEquiv" ref="255189770"/> | |
514 | <int key="NSKeyEquivModMask">1048576</int> |
|
514 | <int key="NSKeyEquivModMask">1048576</int> | |
515 | <int key="NSMnemonicLoc">2147483647</int> |
|
515 | <int key="NSMnemonicLoc">2147483647</int> | |
516 |
<reference key="NSOnImage" ref=" |
|
516 | <reference key="NSOnImage" ref="271266416"/> | |
517 |
<reference key="NSMixedImage" ref=" |
|
517 | <reference key="NSMixedImage" ref="508123839"/> | |
518 | </object> |
|
518 | </object> | |
519 | </object> |
|
519 | </object> | |
520 | </object> |
|
520 | </object> | |
@@ -525,8 +525,8 b'' | |||||
525 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
525 | <reference key="NSKeyEquiv" ref="255189770"/> | |
526 | <int key="NSKeyEquivModMask">1048576</int> |
|
526 | <int key="NSKeyEquivModMask">1048576</int> | |
527 | <int key="NSMnemonicLoc">2147483647</int> |
|
527 | <int key="NSMnemonicLoc">2147483647</int> | |
528 |
<reference key="NSOnImage" ref=" |
|
528 | <reference key="NSOnImage" ref="271266416"/> | |
529 |
<reference key="NSMixedImage" ref=" |
|
529 | <reference key="NSMixedImage" ref="508123839"/> | |
530 | <string key="NSAction">submenuAction:</string> |
|
530 | <string key="NSAction">submenuAction:</string> | |
531 | <object class="NSMenu" key="NSSubmenu" id="698887838"> |
|
531 | <object class="NSMenu" key="NSSubmenu" id="698887838"> | |
532 | <reference key="NSTitle" ref="904739598"/> |
|
532 | <reference key="NSTitle" ref="904739598"/> | |
@@ -538,8 +538,8 b'' | |||||
538 | <reference key="NSKeyEquiv" ref="469505129"/> |
|
538 | <reference key="NSKeyEquiv" ref="469505129"/> | |
539 | <int key="NSKeyEquivModMask">1048576</int> |
|
539 | <int key="NSKeyEquivModMask">1048576</int> | |
540 | <int key="NSMnemonicLoc">2147483647</int> |
|
540 | <int key="NSMnemonicLoc">2147483647</int> | |
541 |
<reference key="NSOnImage" ref=" |
|
541 | <reference key="NSOnImage" ref="271266416"/> | |
542 |
<reference key="NSMixedImage" ref=" |
|
542 | <reference key="NSMixedImage" ref="508123839"/> | |
543 | <int key="NSTag">1</int> |
|
543 | <int key="NSTag">1</int> | |
544 | </object> |
|
544 | </object> | |
545 | <object class="NSMenuItem" id="197661976"> |
|
545 | <object class="NSMenuItem" id="197661976"> | |
@@ -548,8 +548,8 b'' | |||||
548 | <reference key="NSKeyEquiv" ref="762398675"/> |
|
548 | <reference key="NSKeyEquiv" ref="762398675"/> | |
549 | <int key="NSKeyEquivModMask">1048576</int> |
|
549 | <int key="NSKeyEquivModMask">1048576</int> | |
550 | <int key="NSMnemonicLoc">2147483647</int> |
|
550 | <int key="NSMnemonicLoc">2147483647</int> | |
551 |
<reference key="NSOnImage" ref=" |
|
551 | <reference key="NSOnImage" ref="271266416"/> | |
552 |
<reference key="NSMixedImage" ref=" |
|
552 | <reference key="NSMixedImage" ref="508123839"/> | |
553 | <int key="NSTag">2</int> |
|
553 | <int key="NSTag">2</int> | |
554 | </object> |
|
554 | </object> | |
555 | <object class="NSMenuItem" id="708854459"> |
|
555 | <object class="NSMenuItem" id="708854459"> | |
@@ -558,8 +558,8 b'' | |||||
558 | <reference key="NSKeyEquiv" ref="819654342"/> |
|
558 | <reference key="NSKeyEquiv" ref="819654342"/> | |
559 | <int key="NSKeyEquivModMask">1179648</int> |
|
559 | <int key="NSKeyEquivModMask">1179648</int> | |
560 | <int key="NSMnemonicLoc">2147483647</int> |
|
560 | <int key="NSMnemonicLoc">2147483647</int> | |
561 |
<reference key="NSOnImage" ref=" |
|
561 | <reference key="NSOnImage" ref="271266416"/> | |
562 |
<reference key="NSMixedImage" ref=" |
|
562 | <reference key="NSMixedImage" ref="508123839"/> | |
563 | <int key="NSTag">3</int> |
|
563 | <int key="NSTag">3</int> | |
564 | </object> |
|
564 | </object> | |
565 | </object> |
|
565 | </object> | |
@@ -571,8 +571,8 b'' | |||||
571 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
571 | <reference key="NSKeyEquiv" ref="255189770"/> | |
572 | <int key="NSKeyEquivModMask">1048576</int> |
|
572 | <int key="NSKeyEquivModMask">1048576</int> | |
573 | <int key="NSMnemonicLoc">2147483647</int> |
|
573 | <int key="NSMnemonicLoc">2147483647</int> | |
574 |
<reference key="NSOnImage" ref=" |
|
574 | <reference key="NSOnImage" ref="271266416"/> | |
575 |
<reference key="NSMixedImage" ref=" |
|
575 | <reference key="NSMixedImage" ref="508123839"/> | |
576 | <string key="NSAction">submenuAction:</string> |
|
576 | <string key="NSAction">submenuAction:</string> | |
577 | <object class="NSMenu" key="NSSubmenu" id="785027613"> |
|
577 | <object class="NSMenu" key="NSSubmenu" id="785027613"> | |
578 | <reference key="NSTitle" ref="812002426"/> |
|
578 | <reference key="NSTitle" ref="812002426"/> | |
@@ -584,8 +584,8 b'' | |||||
584 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
584 | <reference key="NSKeyEquiv" ref="255189770"/> | |
585 | <int key="NSKeyEquivModMask">1048576</int> |
|
585 | <int key="NSKeyEquivModMask">1048576</int> | |
586 | <int key="NSMnemonicLoc">2147483647</int> |
|
586 | <int key="NSMnemonicLoc">2147483647</int> | |
587 |
<reference key="NSOnImage" ref=" |
|
587 | <reference key="NSOnImage" ref="271266416"/> | |
588 |
<reference key="NSMixedImage" ref=" |
|
588 | <reference key="NSMixedImage" ref="508123839"/> | |
589 | </object> |
|
589 | </object> | |
590 | <object class="NSMenuItem" id="680220178"> |
|
590 | <object class="NSMenuItem" id="680220178"> | |
591 | <reference key="NSMenu" ref="785027613"/> |
|
591 | <reference key="NSMenu" ref="785027613"/> | |
@@ -593,8 +593,8 b'' | |||||
593 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
593 | <reference key="NSKeyEquiv" ref="255189770"/> | |
594 | <int key="NSKeyEquivModMask">1048576</int> |
|
594 | <int key="NSKeyEquivModMask">1048576</int> | |
595 | <int key="NSMnemonicLoc">2147483647</int> |
|
595 | <int key="NSMnemonicLoc">2147483647</int> | |
596 |
<reference key="NSOnImage" ref=" |
|
596 | <reference key="NSOnImage" ref="271266416"/> | |
597 |
<reference key="NSMixedImage" ref=" |
|
597 | <reference key="NSMixedImage" ref="508123839"/> | |
598 | </object> |
|
598 | </object> | |
599 | </object> |
|
599 | </object> | |
600 | </object> |
|
600 | </object> | |
@@ -608,8 +608,8 b'' | |||||
608 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
608 | <reference key="NSKeyEquiv" ref="255189770"/> | |
609 | <int key="NSKeyEquivModMask">1048576</int> |
|
609 | <int key="NSKeyEquivModMask">1048576</int> | |
610 | <int key="NSMnemonicLoc">2147483647</int> |
|
610 | <int key="NSMnemonicLoc">2147483647</int> | |
611 |
<reference key="NSOnImage" ref=" |
|
611 | <reference key="NSOnImage" ref="271266416"/> | |
612 |
<reference key="NSMixedImage" ref=" |
|
612 | <reference key="NSMixedImage" ref="508123839"/> | |
613 | <string key="NSAction">submenuAction:</string> |
|
613 | <string key="NSAction">submenuAction:</string> | |
614 | <object class="NSMenu" key="NSSubmenu" id="502084290"> |
|
614 | <object class="NSMenu" key="NSSubmenu" id="502084290"> | |
615 | <reference key="NSTitle" ref="241242548"/> |
|
615 | <reference key="NSTitle" ref="241242548"/> | |
@@ -621,8 +621,8 b'' | |||||
621 | <string key="NSKeyEquiv" id="806579634">t</string> |
|
621 | <string key="NSKeyEquiv" id="806579634">t</string> | |
622 | <int key="NSKeyEquivModMask">1048576</int> |
|
622 | <int key="NSKeyEquivModMask">1048576</int> | |
623 | <int key="NSMnemonicLoc">2147483647</int> |
|
623 | <int key="NSMnemonicLoc">2147483647</int> | |
624 |
<reference key="NSOnImage" ref=" |
|
624 | <reference key="NSOnImage" ref="271266416"/> | |
625 |
<reference key="NSMixedImage" ref=" |
|
625 | <reference key="NSMixedImage" ref="508123839"/> | |
626 | </object> |
|
626 | </object> | |
627 | <object class="NSMenuItem" id="1028416764"> |
|
627 | <object class="NSMenuItem" id="1028416764"> | |
628 | <reference key="NSMenu" ref="502084290"/> |
|
628 | <reference key="NSMenu" ref="502084290"/> | |
@@ -630,8 +630,8 b'' | |||||
630 | <string key="NSKeyEquiv">C</string> |
|
630 | <string key="NSKeyEquiv">C</string> | |
631 | <int key="NSKeyEquivModMask">1179648</int> |
|
631 | <int key="NSKeyEquivModMask">1179648</int> | |
632 | <int key="NSMnemonicLoc">2147483647</int> |
|
632 | <int key="NSMnemonicLoc">2147483647</int> | |
633 |
<reference key="NSOnImage" ref=" |
|
633 | <reference key="NSOnImage" ref="271266416"/> | |
634 |
<reference key="NSMixedImage" ref=" |
|
634 | <reference key="NSMixedImage" ref="508123839"/> | |
635 | </object> |
|
635 | </object> | |
636 | </object> |
|
636 | </object> | |
637 | </object> |
|
637 | </object> | |
@@ -642,8 +642,8 b'' | |||||
642 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
642 | <reference key="NSKeyEquiv" ref="255189770"/> | |
643 | <int key="NSKeyEquivModMask">1048576</int> |
|
643 | <int key="NSKeyEquivModMask">1048576</int> | |
644 | <int key="NSMnemonicLoc">2147483647</int> |
|
644 | <int key="NSMnemonicLoc">2147483647</int> | |
645 |
<reference key="NSOnImage" ref=" |
|
645 | <reference key="NSOnImage" ref="271266416"/> | |
646 |
<reference key="NSMixedImage" ref=" |
|
646 | <reference key="NSMixedImage" ref="508123839"/> | |
647 | <string key="NSAction">submenuAction:</string> |
|
647 | <string key="NSAction">submenuAction:</string> | |
648 | <object class="NSMenu" key="NSSubmenu" id="466310130"> |
|
648 | <object class="NSMenu" key="NSSubmenu" id="466310130"> | |
649 | <reference key="NSTitle" ref="809723865"/> |
|
649 | <reference key="NSTitle" ref="809723865"/> | |
@@ -655,8 +655,8 b'' | |||||
655 | <reference key="NSKeyEquiv" ref="806579634"/> |
|
655 | <reference key="NSKeyEquiv" ref="806579634"/> | |
656 | <int key="NSKeyEquivModMask">1572864</int> |
|
656 | <int key="NSKeyEquivModMask">1572864</int> | |
657 | <int key="NSMnemonicLoc">2147483647</int> |
|
657 | <int key="NSMnemonicLoc">2147483647</int> | |
658 |
<reference key="NSOnImage" ref=" |
|
658 | <reference key="NSOnImage" ref="271266416"/> | |
659 |
<reference key="NSMixedImage" ref=" |
|
659 | <reference key="NSMixedImage" ref="508123839"/> | |
660 | </object> |
|
660 | </object> | |
661 | <object class="NSMenuItem" id="237841660"> |
|
661 | <object class="NSMenuItem" id="237841660"> | |
662 | <reference key="NSMenu" ref="466310130"/> |
|
662 | <reference key="NSMenu" ref="466310130"/> | |
@@ -664,8 +664,8 b'' | |||||
664 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
664 | <reference key="NSKeyEquiv" ref="255189770"/> | |
665 | <int key="NSKeyEquivModMask">1048576</int> |
|
665 | <int key="NSKeyEquivModMask">1048576</int> | |
666 | <int key="NSMnemonicLoc">2147483647</int> |
|
666 | <int key="NSMnemonicLoc">2147483647</int> | |
667 |
<reference key="NSOnImage" ref=" |
|
667 | <reference key="NSOnImage" ref="271266416"/> | |
668 |
<reference key="NSMixedImage" ref=" |
|
668 | <reference key="NSMixedImage" ref="508123839"/> | |
669 | </object> |
|
669 | </object> | |
670 | </object> |
|
670 | </object> | |
671 | </object> |
|
671 | </object> | |
@@ -676,8 +676,8 b'' | |||||
676 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
676 | <reference key="NSKeyEquiv" ref="255189770"/> | |
677 | <int key="NSKeyEquivModMask">1048576</int> |
|
677 | <int key="NSKeyEquivModMask">1048576</int> | |
678 | <int key="NSMnemonicLoc">2147483647</int> |
|
678 | <int key="NSMnemonicLoc">2147483647</int> | |
679 |
<reference key="NSOnImage" ref=" |
|
679 | <reference key="NSOnImage" ref="271266416"/> | |
680 |
<reference key="NSMixedImage" ref=" |
|
680 | <reference key="NSMixedImage" ref="508123839"/> | |
681 | <string key="NSAction">submenuAction:</string> |
|
681 | <string key="NSAction">submenuAction:</string> | |
682 | <object class="NSMenu" key="NSSubmenu" id="835318025"> |
|
682 | <object class="NSMenu" key="NSSubmenu" id="835318025"> | |
683 | <reference key="NSTitle" ref="64165424"/> |
|
683 | <reference key="NSTitle" ref="64165424"/> | |
@@ -689,8 +689,8 b'' | |||||
689 | <string key="NSKeyEquiv">m</string> |
|
689 | <string key="NSKeyEquiv">m</string> | |
690 | <int key="NSKeyEquivModMask">1048576</int> |
|
690 | <int key="NSKeyEquivModMask">1048576</int> | |
691 | <int key="NSMnemonicLoc">2147483647</int> |
|
691 | <int key="NSMnemonicLoc">2147483647</int> | |
692 |
<reference key="NSOnImage" ref=" |
|
692 | <reference key="NSOnImage" ref="271266416"/> | |
693 |
<reference key="NSMixedImage" ref=" |
|
693 | <reference key="NSMixedImage" ref="508123839"/> | |
694 | </object> |
|
694 | </object> | |
695 | <object class="NSMenuItem" id="575023229"> |
|
695 | <object class="NSMenuItem" id="575023229"> | |
696 | <reference key="NSMenu" ref="835318025"/> |
|
696 | <reference key="NSMenu" ref="835318025"/> | |
@@ -698,8 +698,8 b'' | |||||
698 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
698 | <reference key="NSKeyEquiv" ref="255189770"/> | |
699 | <int key="NSKeyEquivModMask">1048576</int> |
|
699 | <int key="NSKeyEquivModMask">1048576</int> | |
700 | <int key="NSMnemonicLoc">2147483647</int> |
|
700 | <int key="NSMnemonicLoc">2147483647</int> | |
701 |
<reference key="NSOnImage" ref=" |
|
701 | <reference key="NSOnImage" ref="271266416"/> | |
702 |
<reference key="NSMixedImage" ref=" |
|
702 | <reference key="NSMixedImage" ref="508123839"/> | |
703 | </object> |
|
703 | </object> | |
704 | <object class="NSMenuItem" id="299356726"> |
|
704 | <object class="NSMenuItem" id="299356726"> | |
705 | <reference key="NSMenu" ref="835318025"/> |
|
705 | <reference key="NSMenu" ref="835318025"/> | |
@@ -709,8 +709,8 b'' | |||||
709 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
709 | <reference key="NSKeyEquiv" ref="255189770"/> | |
710 | <int key="NSKeyEquivModMask">1048576</int> |
|
710 | <int key="NSKeyEquivModMask">1048576</int> | |
711 | <int key="NSMnemonicLoc">2147483647</int> |
|
711 | <int key="NSMnemonicLoc">2147483647</int> | |
712 |
<reference key="NSOnImage" ref=" |
|
712 | <reference key="NSOnImage" ref="271266416"/> | |
713 |
<reference key="NSMixedImage" ref=" |
|
713 | <reference key="NSMixedImage" ref="508123839"/> | |
714 | </object> |
|
714 | </object> | |
715 | <object class="NSMenuItem" id="625202149"> |
|
715 | <object class="NSMenuItem" id="625202149"> | |
716 | <reference key="NSMenu" ref="835318025"/> |
|
716 | <reference key="NSMenu" ref="835318025"/> | |
@@ -718,8 +718,8 b'' | |||||
718 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
718 | <reference key="NSKeyEquiv" ref="255189770"/> | |
719 | <int key="NSKeyEquivModMask">1048576</int> |
|
719 | <int key="NSKeyEquivModMask">1048576</int> | |
720 | <int key="NSMnemonicLoc">2147483647</int> |
|
720 | <int key="NSMnemonicLoc">2147483647</int> | |
721 |
<reference key="NSOnImage" ref=" |
|
721 | <reference key="NSOnImage" ref="271266416"/> | |
722 |
<reference key="NSMixedImage" ref=" |
|
722 | <reference key="NSMixedImage" ref="508123839"/> | |
723 | </object> |
|
723 | </object> | |
724 | </object> |
|
724 | </object> | |
725 | <string key="NSName">_NSWindowsMenu</string> |
|
725 | <string key="NSName">_NSWindowsMenu</string> | |
@@ -731,8 +731,8 b'' | |||||
731 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
731 | <reference key="NSKeyEquiv" ref="255189770"/> | |
732 | <int key="NSKeyEquivModMask">1048576</int> |
|
732 | <int key="NSKeyEquivModMask">1048576</int> | |
733 | <int key="NSMnemonicLoc">2147483647</int> |
|
733 | <int key="NSMnemonicLoc">2147483647</int> | |
734 |
<reference key="NSOnImage" ref=" |
|
734 | <reference key="NSOnImage" ref="271266416"/> | |
735 |
<reference key="NSMixedImage" ref=" |
|
735 | <reference key="NSMixedImage" ref="508123839"/> | |
736 | <string key="NSAction">submenuAction:</string> |
|
736 | <string key="NSAction">submenuAction:</string> | |
737 | <object class="NSMenu" key="NSSubmenu" id="374024848"> |
|
737 | <object class="NSMenu" key="NSSubmenu" id="374024848"> | |
738 | <reference key="NSTitle" ref="461919786"/> |
|
738 | <reference key="NSTitle" ref="461919786"/> | |
@@ -744,8 +744,8 b'' | |||||
744 | <string key="NSKeyEquiv">?</string> |
|
744 | <string key="NSKeyEquiv">?</string> | |
745 | <int key="NSKeyEquivModMask">1048576</int> |
|
745 | <int key="NSKeyEquivModMask">1048576</int> | |
746 | <int key="NSMnemonicLoc">2147483647</int> |
|
746 | <int key="NSMnemonicLoc">2147483647</int> | |
747 |
<reference key="NSOnImage" ref=" |
|
747 | <reference key="NSOnImage" ref="271266416"/> | |
748 |
<reference key="NSMixedImage" ref=" |
|
748 | <reference key="NSMixedImage" ref="508123839"/> | |
749 | </object> |
|
749 | </object> | |
750 | </object> |
|
750 | </object> | |
751 | </object> |
|
751 | </object> | |
@@ -860,7 +860,7 b'' | |||||
860 | <bool key="EncodedWithXMLCoder">YES</bool> |
|
860 | <bool key="EncodedWithXMLCoder">YES</bool> | |
861 | <object class="NSColor"> |
|
861 | <object class="NSColor"> | |
862 | <int key="NSColorSpace">6</int> |
|
862 | <int key="NSColorSpace">6</int> | |
863 |
<string key="NSCatalogName" id=" |
|
863 | <string key="NSCatalogName" id="484387293">System</string> | |
864 | <string key="NSColorName">selectedTextBackgroundColor</string> |
|
864 | <string key="NSColorName">selectedTextBackgroundColor</string> | |
865 | <object class="NSColor" key="NSColor" id="377165725"> |
|
865 | <object class="NSColor" key="NSColor" id="377165725"> | |
866 | <int key="NSColorSpace">3</int> |
|
866 | <int key="NSColorSpace">3</int> | |
@@ -869,7 +869,7 b'' | |||||
869 | </object> |
|
869 | </object> | |
870 | <object class="NSColor"> |
|
870 | <object class="NSColor"> | |
871 | <int key="NSColorSpace">6</int> |
|
871 | <int key="NSColorSpace">6</int> | |
872 |
<reference key="NSCatalogName" ref=" |
|
872 | <reference key="NSCatalogName" ref="484387293"/> | |
873 | <string key="NSColorName">selectedTextColor</string> |
|
873 | <string key="NSColorName">selectedTextColor</string> | |
874 | <reference key="NSColor" ref="555789289"/> |
|
874 | <reference key="NSColor" ref="555789289"/> | |
875 | </object> |
|
875 | </object> | |
@@ -963,13 +963,13 b'' | |||||
963 | <int key="NSCellFlags2">0</int> |
|
963 | <int key="NSCellFlags2">0</int> | |
964 | <string key="NSContents">Console</string> |
|
964 | <string key="NSContents">Console</string> | |
965 | <object class="NSFont" key="NSSupport" id="26"> |
|
965 | <object class="NSFont" key="NSSupport" id="26"> | |
966 |
<string key="NSName" id=" |
|
966 | <string key="NSName" id="378950370">LucidaGrande</string> | |
967 | <double key="NSSize">1.100000e+01</double> |
|
967 | <double key="NSSize">1.100000e+01</double> | |
968 | <int key="NSfFlags">3100</int> |
|
968 | <int key="NSfFlags">3100</int> | |
969 | </object> |
|
969 | </object> | |
970 | <object class="NSColor" key="NSBackgroundColor" id="131515055"> |
|
970 | <object class="NSColor" key="NSBackgroundColor" id="131515055"> | |
971 | <int key="NSColorSpace">6</int> |
|
971 | <int key="NSColorSpace">6</int> | |
972 |
<reference key="NSCatalogName" ref=" |
|
972 | <reference key="NSCatalogName" ref="484387293"/> | |
973 | <string key="NSColorName">textBackgroundColor</string> |
|
973 | <string key="NSColorName">textBackgroundColor</string> | |
974 | <reference key="NSColor" ref="521347521"/> |
|
974 | <reference key="NSColor" ref="521347521"/> | |
975 | </object> |
|
975 | </object> | |
@@ -1043,7 +1043,7 b'' | |||||
1043 | </object> |
|
1043 | </object> | |
1044 | <object class="NSColor" key="NSTextColor" id="866628999"> |
|
1044 | <object class="NSColor" key="NSTextColor" id="866628999"> | |
1045 | <int key="NSColorSpace">6</int> |
|
1045 | <int key="NSColorSpace">6</int> | |
1046 |
<reference key="NSCatalogName" ref=" |
|
1046 | <reference key="NSCatalogName" ref="484387293"/> | |
1047 | <string key="NSColorName">headerTextColor</string> |
|
1047 | <string key="NSColorName">headerTextColor</string> | |
1048 | <reference key="NSColor" ref="555789289"/> |
|
1048 | <reference key="NSColor" ref="555789289"/> | |
1049 | </object> |
|
1049 | </object> | |
@@ -1051,22 +1051,22 b'' | |||||
1051 | <object class="NSTextFieldCell" key="NSDataCell" id="525071236"> |
|
1051 | <object class="NSTextFieldCell" key="NSDataCell" id="525071236"> | |
1052 | <int key="NSCellFlags">337772096</int> |
|
1052 | <int key="NSCellFlags">337772096</int> | |
1053 | <int key="NSCellFlags2">2048</int> |
|
1053 | <int key="NSCellFlags2">2048</int> | |
1054 |
<string key="NSContents" id=" |
|
1054 | <string key="NSContents" id="456204663">Text Cell</string> | |
1055 | <object class="NSFont" key="NSSupport" id="8196371"> |
|
1055 | <object class="NSFont" key="NSSupport" id="8196371"> | |
1056 |
<reference key="NSName" ref=" |
|
1056 | <reference key="NSName" ref="378950370"/> | |
1057 | <double key="NSSize">1.300000e+01</double> |
|
1057 | <double key="NSSize">1.300000e+01</double> | |
1058 | <int key="NSfFlags">1044</int> |
|
1058 | <int key="NSfFlags">1044</int> | |
1059 | </object> |
|
1059 | </object> | |
1060 | <reference key="NSControlView" ref="23853726"/> |
|
1060 | <reference key="NSControlView" ref="23853726"/> | |
1061 | <object class="NSColor" key="NSBackgroundColor" id="224028609"> |
|
1061 | <object class="NSColor" key="NSBackgroundColor" id="224028609"> | |
1062 | <int key="NSColorSpace">6</int> |
|
1062 | <int key="NSColorSpace">6</int> | |
1063 |
<reference key="NSCatalogName" ref=" |
|
1063 | <reference key="NSCatalogName" ref="484387293"/> | |
1064 | <string key="NSColorName">controlBackgroundColor</string> |
|
1064 | <string key="NSColorName">controlBackgroundColor</string> | |
1065 | <reference key="NSColor" ref="377165725"/> |
|
1065 | <reference key="NSColor" ref="377165725"/> | |
1066 | </object> |
|
1066 | </object> | |
1067 | <object class="NSColor" key="NSTextColor" id="205104690"> |
|
1067 | <object class="NSColor" key="NSTextColor" id="205104690"> | |
1068 | <int key="NSColorSpace">6</int> |
|
1068 | <int key="NSColorSpace">6</int> | |
1069 |
<reference key="NSCatalogName" ref=" |
|
1069 | <reference key="NSCatalogName" ref="484387293"/> | |
1070 | <string key="NSColorName">controlTextColor</string> |
|
1070 | <string key="NSColorName">controlTextColor</string> | |
1071 | <reference key="NSColor" ref="555789289"/> |
|
1071 | <reference key="NSColor" ref="555789289"/> | |
1072 | </object> |
|
1072 | </object> | |
@@ -1091,7 +1091,7 b'' | |||||
1091 | <object class="NSTextFieldCell" key="NSDataCell" id="377147224"> |
|
1091 | <object class="NSTextFieldCell" key="NSDataCell" id="377147224"> | |
1092 | <int key="NSCellFlags">337772096</int> |
|
1092 | <int key="NSCellFlags">337772096</int> | |
1093 | <int key="NSCellFlags2">2048</int> |
|
1093 | <int key="NSCellFlags2">2048</int> | |
1094 |
<reference key="NSContents" ref=" |
|
1094 | <reference key="NSContents" ref="456204663"/> | |
1095 | <reference key="NSSupport" ref="8196371"/> |
|
1095 | <reference key="NSSupport" ref="8196371"/> | |
1096 | <reference key="NSControlView" ref="23853726"/> |
|
1096 | <reference key="NSControlView" ref="23853726"/> | |
1097 | <reference key="NSBackgroundColor" ref="224028609"/> |
|
1097 | <reference key="NSBackgroundColor" ref="224028609"/> | |
@@ -1108,7 +1108,7 b'' | |||||
1108 | <reference key="NSBackgroundColor" ref="521347521"/> |
|
1108 | <reference key="NSBackgroundColor" ref="521347521"/> | |
1109 | <object class="NSColor" key="NSGridColor"> |
|
1109 | <object class="NSColor" key="NSGridColor"> | |
1110 | <int key="NSColorSpace">6</int> |
|
1110 | <int key="NSColorSpace">6</int> | |
1111 |
<reference key="NSCatalogName" ref=" |
|
1111 | <reference key="NSCatalogName" ref="484387293"/> | |
1112 | <string key="NSColorName">gridColor</string> |
|
1112 | <string key="NSColorName">gridColor</string> | |
1113 | <object class="NSColor" key="NSColor"> |
|
1113 | <object class="NSColor" key="NSColor"> | |
1114 | <int key="NSColorSpace">3</int> |
|
1114 | <int key="NSColorSpace">3</int> | |
@@ -2787,9 +2787,9 b'' | |||||
2787 | <reference ref="9"/> |
|
2787 | <reference ref="9"/> | |
2788 | <reference ref="113577022"/> |
|
2788 | <reference ref="113577022"/> | |
2789 | <integer value="0"/> |
|
2789 | <integer value="0"/> | |
2790 |
<string>{{ |
|
2790 | <string>{{27, 368}, {725, 337}}</string> | |
2791 | <reference ref="9"/> |
|
2791 | <reference ref="9"/> | |
2792 |
<string>{{ |
|
2792 | <string>{{27, 368}, {725, 337}}</string> | |
2793 | <reference ref="113577022"/> |
|
2793 | <reference ref="113577022"/> | |
2794 | <reference ref="113577022"/> |
|
2794 | <reference ref="113577022"/> | |
2795 | <reference ref="113577022"/> |
|
2795 | <reference ref="113577022"/> | |
@@ -2878,8 +2878,8 b'' | |||||
2878 | <object class="NSMutableArray" key="referencedPartialClassDescriptions"> |
|
2878 | <object class="NSMutableArray" key="referencedPartialClassDescriptions"> | |
2879 | <bool key="EncodedWithXMLCoder">YES</bool> |
|
2879 | <bool key="EncodedWithXMLCoder">YES</bool> | |
2880 | <object class="IBPartialClassDescription"> |
|
2880 | <object class="IBPartialClassDescription"> | |
2881 | <string key="className">IPython1SandboxAppDelegate</string> |
|
2881 | <reference key="className" ref="695797635"/> | |
2882 |
< |
|
2882 | <nil key="superclassName"/> | |
2883 | <object class="NSMutableDictionary" key="actions"> |
|
2883 | <object class="NSMutableDictionary" key="actions"> | |
2884 | <bool key="EncodedWithXMLCoder">YES</bool> |
|
2884 | <bool key="EncodedWithXMLCoder">YES</bool> | |
2885 | <object class="NSArray" key="dict.sortedKeys"> |
|
2885 | <object class="NSArray" key="dict.sortedKeys"> | |
@@ -2890,17 +2890,17 b'' | |||||
2890 | </object> |
|
2890 | </object> | |
2891 | </object> |
|
2891 | </object> | |
2892 | <object class="NSMutableDictionary" key="outlets"> |
|
2892 | <object class="NSMutableDictionary" key="outlets"> | |
2893 | <string key="NS.key.0">ipythonController</string> |
|
2893 | <reference key="NS.key.0" ref="684042788"/> | |
2894 |
<string key="NS.object.0"> |
|
2894 | <string key="NS.object.0">NSTextView</string> | |
2895 | </object> |
|
2895 | </object> | |
2896 | <object class="IBClassDescriptionSource" key="sourceIdentifier"> |
|
2896 | <object class="IBClassDescriptionSource" key="sourceIdentifier"> | |
2897 |
<string key="majorKey">IB |
|
2897 | <string key="majorKey">IBUserSource</string> | |
2898 | <string key="minorKey">IPython1SandboxAppDelegate.py</string> |
|
2898 | <reference key="minorKey" ref="255189770"/> | |
2899 | </object> |
|
2899 | </object> | |
2900 | </object> |
|
2900 | </object> | |
2901 | <object class="IBPartialClassDescription"> |
|
2901 | <object class="IBPartialClassDescription"> | |
2902 | <reference key="className" ref="695797635"/> |
|
2902 | <string key="className">IPython1SandboxAppDelegate</string> | |
2903 |
< |
|
2903 | <string key="superclassName">NSObject</string> | |
2904 | <object class="NSMutableDictionary" key="actions"> |
|
2904 | <object class="NSMutableDictionary" key="actions"> | |
2905 | <bool key="EncodedWithXMLCoder">YES</bool> |
|
2905 | <bool key="EncodedWithXMLCoder">YES</bool> | |
2906 | <object class="NSArray" key="dict.sortedKeys"> |
|
2906 | <object class="NSArray" key="dict.sortedKeys"> | |
@@ -2911,12 +2911,12 b'' | |||||
2911 | </object> |
|
2911 | </object> | |
2912 | </object> |
|
2912 | </object> | |
2913 | <object class="NSMutableDictionary" key="outlets"> |
|
2913 | <object class="NSMutableDictionary" key="outlets"> | |
2914 | <reference key="NS.key.0" ref="684042788"/> |
|
2914 | <string key="NS.key.0">ipythonController</string> | |
2915 |
<string key="NS.object.0"> |
|
2915 | <string key="NS.object.0">id</string> | |
2916 | </object> |
|
2916 | </object> | |
2917 | <object class="IBClassDescriptionSource" key="sourceIdentifier"> |
|
2917 | <object class="IBClassDescriptionSource" key="sourceIdentifier"> | |
2918 |
<string key="majorKey">IB |
|
2918 | <string key="majorKey">IBProjectSource</string> | |
2919 | <reference key="minorKey" ref="255189770"/> |
|
2919 | <string key="minorKey">IPython1SandboxAppDelegate.py</string> | |
2920 | </object> |
|
2920 | </object> | |
2921 | </object> |
|
2921 | </object> | |
2922 | </object> |
|
2922 | </object> | |
@@ -2932,18 +2932,18 b' AQUBBgEHAQgBCQEKAQsBDwEQARkBIQEmASoBLQExATUBOQE7AT0BTQFSAVUBWgFBAVQBYwFqAWsBbAFv' | |||||
2932 | AXQBdQF4AYAAkAGBAYQBhwGIAYkBjgGPAZABkwGYAZkBmwGeAasBrAGtAbEBvAG9Ab4BwQHCAcQBxQHG |
|
2932 | AXQBdQF4AYAAkAGBAYQBhwGIAYkBjgGPAZABkwGYAZkBmwGeAasBrAGtAbEBvAG9Ab4BwQHCAcQBxQHG | |
2933 | AdIB0wHbAdwB3wHkAeUB6AHtAfAB/AIAAgcCCwIdAiUCLwIzAlECUgJaAmQCZQJoAm4CbwJyAncCiAKP |
|
2933 | AdIB0wHbAdwB3wHkAeUB6AHtAfAB/AIAAgcCCwIdAiUCLwIzAlECUgJaAmQCZQJoAm4CbwJyAncCiAKP | |
2934 | ApACkwKYApkCnAKmAqcCrAKxArICtwK4ArsCwwLJAsoC0QLWAtcC2gLcAt0C5gLnAvAC8QL1AvYC9wL4 |
|
2934 | ApACkwKYApkCnAKmAqcCrAKxArICtwK4ArsCwwLJAsoC0QLWAtcC2gLcAt0C5gLnAvAC8QL1AvYC9wL4 | |
2935 |
AvkC/wMAAwIDAwMEAwcDFgMYAxsDHAMfAAsDIAMhAyIDJQNXA10Db |
|
2935 | AvkC/wMAAwIDAwMEAwcDFgMYAxsDHAMfAAsDIAMhAyIDJQNXA10DbQNzASkDdAN5A3oDewN+A4IDgwOG | |
2936 | A4gDjAOQA5cDmwOcA50DngOiA6kDqgOrA6wDsAO3A7sDvAO9A74DwgPJA80DzgPPA9AD1APcA90D3gPf |
|
2936 | A4cDiwOPA5YDmgObA5wDnQOhA6gDrAOtA64DrwOzA7wDwAPBA8IDwwPHA84D0gPTA9QD1QPZA+AD5APl | |
2937 | A+MD6wPwA/ED8gPzA/cD/gQCBAMEBAQFBAkEEAQRBBIEEwQXBB4EHwQgBCQEKwQvASkEMAQxBDcEOgQ7 |
|
2937 | A+YD6gPxA/UD9gP3A/gD/AQDBAQEBQQJBBAEEQQSBBMEFwQeBB8EIAQkBCsELwQwBDEENQQ9BD4EPwRA | |
2938 | BDwEPwRDBEoESwRMBFAEVwRcBF0EXgRfBGMEagRrBGwEcAR3BHgEeQR9BIQEhQSGBIcEjASTBJQElQSZ |
|
2938 | BEQESwRMBE0ETgRUBFcEWgRbBFwEXwRjBGoEawRsBG0EcgR1BHYEdwR7BIIEgwSEBIUEiQSQBJUElgSX | |
2939 | BKAEpASlBKYEpwSrBLIEswS0BLUEuQTABMEEwgTGBM0EzgTPBNME2gTbBNwE3QThBOgE6QTqBOsE7wT2 |
|
2939 | BJgEnASjBKQEpQSmBKoEsQSyBLMEtAS4BL8EwwTEBMUExgTKBNEE0gTTBNQE2ATfBOAE4QTiBOYE7QTx | |
2940 | BPcE+AT5BP0FBAUFBQYFBwUMBQ8FEAURBRUFHAUdBR4FIgUpBSoFKwUsBTAFNwU7BTwFPQU+BUMFRgVK |
|
2940 | BPIE8wT0BPgE/wUABQEFBgUNBQ4FDwUTBRwFHQUeBR8FJAUoBS8FMAUxBTIFNwU4BTwFQwVEBUUFRgVK | |
2941 | BVEFUgVTBVcFXgViBWMFZAVlBWkFcAV1BXYFdwV7BYIFgwWEBYgFjwWQBZEFkgWXBZgFnQWeBaIFqwWs |
|
2941 | BVEFVgVXBVgFXAVjBWQFZQVpBXAFcQVyBXcFeAV8BYMFhAWFBYkFkAWRBZIFlgWdBZ4FnwWjBaoFqwWs | |
2942 |
B |
|
2942 | BbAFtwW4BbkFugW+BcUFxgXHBcgFzAXTBdQF1QXWBeAF9gX8Bf0F/gX/BgMGCwYMBg8GEQYXBhgGGQYa | |
2943 |
B |
|
2943 | Bh0GJAYlBiYGJwYuBi8GMAY3BjgGOQZABkEGQgZDBq0GuAbCBscGyAbJBs4G1QbWBtgG2QbdBt4GyAbn | |
2944 | BuQG5QbvBvgGuAb5BwcHEgcZBxoHGwckBy0GuAcuBzMHNgc3B0AHSQdKB1MGuAdUB2IHaQdqB2sHcgdz |
|
2944 | BvAGyAbxBvgHAQbIBwIHEgcbByQHLQbIBy4HNgc9Bz4HRQdGB04HTwdQB1kGyAdaB2AHaQbIB2oHbwdw | |
2945 | B3QHfQeGB48GuAeQB6AHqQeyB7sGuAe8B8QHywfMB9MH1AfcB90H3gfnBrgH6AfvB/gGuAf5B/4IBQgG |
|
2945 | B3oHgwbIB4QHkgebB6IHowekB60HtgbIB7cHvAe/B8AHyQfKB9MGyAfUB+IH6QfqB+sH8gfzB/QH/QgG | |
2946 |
CA8G |
|
2946 | CA8GyAgQCBUIHgbICB8IJggvCDAIOQbICDoIPgg/CKkJFAl/CYAJgQmCCYMJhAmFCYYJhwmICYkJigmL | |
2947 | CYwJjQmOCY8JkAmRCZIJkwmUCZUJlgmXCZgJmQmaCZsJnAmdCZ4JnwmgCaEJogmjCaQJpQmmCacJqAmp |
|
2947 | CYwJjQmOCY8JkAmRCZIJkwmUCZUJlgmXCZgJmQmaCZsJnAmdCZ4JnwmgCaEJogmjCaQJpQmmCacJqAmp | |
2948 | CaoJqwmsCa0JrgmvCbAJsQmyCbMJtAm1CbYJtwm4CbkJugm7CbwJvQm+Cb8JwAnBCcIJwwnECcUJxgnH |
|
2948 | CaoJqwmsCa0JrgmvCbAJsQmyCbMJtAm1CbYJtwm4CbkJugm7CbwJvQm+Cb8JwAnBCcIJwwnECcUJxgnH | |
2949 | CcgJyQnKCcsJzAnNCc4JzwnQCdEJ0gnTCdQJ1QnWCdcJ2AnZCdoJ2wncCd0J3gnfCeAJ4QniCeMJ5Anl |
|
2949 | CcgJyQnKCcsJzAnNCc4JzwnQCdEJ0gnTCdQJ1QnWCdcJ2AnZCdoJ2wncCd0J3gnfCeAJ4QniCeMJ5Anl | |
@@ -3073,351 +3073,352 b' ezE2LCAxNn190gA3ADgDHQMepAMeAYwBjQA7XxATTlNQcm9ncmVzc0luZGljYXRvclp7NzI1LCAzMzd9' | |||||
3073 | XxAVe3swLCAwfSwgezEyODAsIDc3OH19XxAQaXB5dGhvbjFfc2FuZGJveNIANwA4AyMDJKIDJAA7XxAQ |
|
3073 | XxAVe3swLCAwfSwgezEyODAsIDc3OH19XxAQaXB5dGhvbjFfc2FuZGJveNIANwA4AyMDJKIDJAA7XxAQ | |
3074 | TlNXaW5kb3dUZW1wbGF0ZdIADgA+AGkDJ4A0rxAvAygDKQMqAysDLAMtAy4DLwMwAzEDMgMzAzQDNQM2 |
|
3074 | TlNXaW5kb3dUZW1wbGF0ZdIADgA+AGkDJ4A0rxAvAygDKQMqAysDLAMtAy4DLwMwAzEDMgMzAzQDNQM2 | |
3075 | AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRANFA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRA1IDUwNU |
|
3075 | AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRANFA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRA1IDUwNU | |
3076 |
A1UDVoCugLyAwoD |
|
3076 | A1UDVoCugLyAwoDIgM6A1IDZgN+A44DogOyA8YD2gPuBAQGBAQaBAQqBAQ+BARWBARqBAR+BASWBASqB | |
3077 |
AS |
|
3077 | AS+BATWBATmBAT2BAUKBAUOBAUiBAUqBAU+BAVSBAViBAVyBAV6BAWKBAWaBAWqBAW6BAXOBAXiBAX2B | |
3078 |
AY |
|
3078 | AY2BAZGBAZSBAZfTAA4DWANZA1oDWwNcWE5TU291cmNlV05TTGFiZWyAu4CvgLrYAA4DXgNfA2ADYQNi | |
3079 | A2MDZANlA2YDZwNoA2kDagNrA2wDbQBVV05TVGl0bGVfEBFOU0tleUVxdWl2TW9kTWFza1pOU0tleUVx |
|
3079 | A2MDZANlA2YDZwNoA2kDagNrA2xXTlNUaXRsZV8QEU5TS2V5RXF1aXZNb2RNYXNrWk5TS2V5RXF1aXZd | |
3080 | dWl2XU5TTW5lbW9uaWNMb2NZTlNPbkltYWdlXE5TTWl4ZWRJbWFnZVZOU01lbnVVTlNUYWeAuYCxEgAQ |
|
3080 | TlNNbmVtb25pY0xvY1lOU09uSW1hZ2VcTlNNaXhlZEltYWdlVk5TTWVudYC5gLESABAAAICyEn////+A | |
3081 | AACAshJ/////gLOAt4Cw0wAOA14DbwNwA3EDcltOU01lbnVJdGVtc4EBoIEBp4EBqVxTbWFydCBRdW90 |
|
3081 | s4C3gLDUAA4DXgHVA24DbwNwA3EDcltOU01lbnVJdGVtc4EBpIEByoEB2YEBzFhTaG93IEFsbNMADgAy | |
3082 |
|
|
3082 | A3UDdgN3A3heTlNSZXNvdXJjZU5hbWWAtoC0gLVXTlNJbWFnZV8QD05TTWVudUNoZWNrbWFya9IANwA4 | |
3083 |
|
|
3083 | A3wDfaIDfQA7XxAQTlNDdXN0b21SZXNvdXJjZdMADgAyA3UDdgN3A4GAtoC0gLhfEBBOU01lbnVNaXhl | |
3084 |
|
|
3084 | ZFN0YXRl0gA3ADgDhAOFogOFADtaTlNNZW51SXRlbV8QFnVuaGlkZUFsbEFwcGxpY2F0aW9uczrSADcA | |
3085 | b3RlU3Vic3RpdHV0aW9uOtIANwA4A4kDiqMDigOLADtfEBVOU05pYkNvbnRyb2xDb25uZWN0b3JeTlNO |
|
3085 | OAOIA4mjA4kDigA7XxAVTlNOaWJDb250cm9sQ29ubmVjdG9yXk5TTmliQ29ubmVjdG9y0wAOA1gDWQNa | |
3086 | aWJDb25uZWN0b3LTAA4DWANZA1oDjgOPgLuAvYDB2AAOA14DXwNgA2EDYgNjA2QDZgOSA2gDkwNqA2sD |
|
3086 | A40DjoC7gL2AwdgADgNeA18DYANhA2IDYwNkA2UDkQNnA5IDaQNqA2sDlYC5gL+AwICzgLeAvtMADgNe | |
3087 | bAOWgLmAv4DAgLOAt4C+0wAOA14DbwNwA5kDmoEBoIEB0oEB1F8QEUp1bXAgdG8gU2VsZWN0aW9uUWpf |
|
3087 | A24DbwOYA5mBAaSBAauBAa1eQ2hlY2sgU3BlbGxpbmdRO15jaGVja1NwZWxsaW5nOtMADgNYA1kDWgOf | |
3088 | EB1jZW50ZXJTZWxlY3Rpb25JblZpc2libGVBcmVhOtMADgNYA1kDWgOgA6GAu4DDgMbZAA4DXgNfA2AD |
|
3088 | A6CAu4DDgMfYAA4DXgNfA2ADYQNiA2MDZANlA6MDZwOkA2kDagNrA6eAuYDFgMaAs4C3gMTTAA4DXgNu | |
3089 | YQNiA2MDZANlA2YDpANoA6UDagNrA2wDbQCQgLmAxIDFgLOAt4CwXxAQU21hcnQgQ29weS9QYXN0ZVFm |
|
3089 | A28DqgOrgQGkgQHbgQHdZgBQAHIAaQBuAHQgJlFwVnByaW50OtMADgNYA1kDWgOxA7KAu4DJgM3ZAA4D | |
3090 | XxAYdG9nZ2xlU21hcnRJbnNlcnREZWxldGU60wAOA1gDWQNaA64Dr4C7gMiAzNgADgNeA18DYANhA2ID |
|
3090 | XgNfA2ADYQNiA2MDZAO0A2UDtgO3A7gDaQNqA2sDuwFYVU5TVGFngLmAyxIAEgAAgMyAs4C3gMrTAA4D | |
3091 | YwNkA2YDsgNoA7MDagNrA2wDtoC5gMqAy4CzgLeAydMADgNeA28DcAO5A7qBAaCBAcCBAcJUU2F2ZVFz |
|
3091 | XgNuA28DvgO/gQGkgQHAgQHCW1NtYXJ0IExpbmtzUUdfEB10b2dnbGVBdXRvbWF0aWNMaW5rRGV0ZWN0 | |
3092 | XXNhdmVEb2N1bWVudDrTAA4DWANZA1oDwAPBgLuAzoDS2AAOA14DXwNgA2EDYgNjA2QDZgPEA2gDxQNq |
|
3092 | aW9uOtMADgNYA1kDWgPFA8aAu4DPgNPYAA4DXgNfA2ADYQNiA2MDZANlA8kDtwPKA2kDagNrA82AuYDR | |
3093 | A2sDbAPIgLmA0IDRgLOAt4DP0wAOA14DbwNwA8sDzIEBoIEBzIEBzlRVbmRvUXpVdW5kbzrTAA4DWANZ |
|
3093 | gNKAs4C3gNDTAA4DXgNuA28D0APRgQGkgQGvgQGxVFJlZG9RWlVyZWRvOtMADgNYA1kDWgPXA9iAu4DV | |
3094 | A1oD0gPTgLuA1IDX2AAOA14DXwNgA2EDYgNjA2QDZgPWA9cD2ANqA2sDbAPIgLmA1RIAEgAAgNaAs4C3 |
|
3094 | gNjYAA4DXgNfA2ADYQNiA2MDZANlA9sDZwNoA2kDagNrA9+AuYDXgLKAs4C3gNbTAA4DXgNuA28D4gPj | |
3095 | gM9UUmVkb1FaVXJlZG860wAOA1gDWQNaA+ED4oC7gNmA3dgADgNeA18DYANhA2IDYwNkA2YD5QPmA+cD |
|
3095 | gQGkgQHEgQHGXlN0YXJ0IFNwZWFraW5nXnN0YXJ0U3BlYWtpbmc60wAOA1gDWQNaA+gD6YC7gNqA3tgA | |
3096 | agNrA2wD6oC5gNsSABgAAIDcgLOAt4Da1AAOA14B1QNvA3AD7QPuA++BAaCBAa6BAb6BAbBbSGlkZSBP |
|
3096 | DgNeA18DYANhA2IDYwNkA2UD7ANnA+0DaQNqA2sD8IC5gNyA3YCzgLeA29MADgNeA24DbwPzA/SBAaSB | |
3097 | dGhlcnNRaF8QFmhpZGVPdGhlckFwcGxpY2F0aW9uczrTAA4DWANZA1oD9QP2gLuA34Dj2AAOA14DXwNg |
|
3097 | AfGBAfNfEBRJUHl0aG9uMVNhbmRib3ggSGVscFE/WXNob3dIZWxwOtMADgNYA1kDWgP6A/uAu4DggOLY | |
3098 | A2EDYgNjA2QDZgP5A9cD+gNqA2sDbAP9gLmA4YDigLOAt4Dg0wAOA14DbwNwBAAEAYEBoIEB4YEB41tT |
|
3098 | AA4DXgNfA2ADYQNiA2MDZANlA/4DZwNoA2kDagNrA5WAuYDhgLKAs4C3gL5fEBtDaGVjayBTcGVsbGlu | |
3099 | aG93IENvbG9yc1FDXxAVb3JkZXJGcm9udENvbG9yUGFuZWw60wAOA1gDWQNaBAcECIC7gOWA6NgADgNe |
|
3099 | ZyBXaGlsZSBUeXBpbmdfEB50b2dnbGVDb250aW51b3VzU3BlbGxDaGVja2luZzrTAA4DWANZA1oEBwQI | |
3100 | A18DYANhA2IDYwNkA2YECwNoBAwDagNrA2wDyIC5gOaA54CzgLeAz1VQYXN0ZVF2VnBhc3RlOtMADgNY |
|
3100 | gLuA5IDn2AAOA14DXwNgA2EDYgNjA2QDZQQLA2cEDANpA2oDawPNgLmA5YDmgLOAt4DQWlNlbGVjdCBB | |
3101 | A1kDWgQVBBaAu4DqgOzZAA4DXgNfA2ADYQNiA2MDZANlA2YEGQNoA6UDagNrA2wDlgCQgLmA64DFgLOA |
|
3101 | bGxRYVpzZWxlY3RBbGw60wAOA1gDWQNaBBUEFoC7gOmA69gADgNeA18DYANhA2IDYwNkA2UEGQNnA2gD | |
3102 | t4C+ZQBGAGkAbgBkICZfEBdwZXJmb3JtRmluZFBhbmVsQWN0aW9uOtMADgNYA1kDWgQiBCOAu4DugPLY |
|
3102 | aQNqA2sDlYC5gOqAsoCzgLeAvl8QG0NoZWNrIEdyYW1tYXIgV2l0aCBTcGVsbGluZ18QFnRvZ2dsZUdy | |
3103 | AA4DXgNfA2ADYQNiA2MDZANmBCYDaAQnA2oDawNsBCqAuYDwgPGAs4C3gO/TAA4DXgNvA3AELQQugQGg |
|
3103 | YW1tYXJDaGVja2luZzrTAA4DWANZA1oEIgQjgLuA7YDw2AAOA14DXwNgA2EDYgNjA2QDZQQmA2cDaANp | |
3104 | gQGdgQGfXVN0b3AgU3BlYWtpbmddc3RvcFNwZWFraW5nOtQADgQyA1gDWQQzBDQAQQQ2XU5TRGVzdGlu |
|
3104 | A2oDawQqgLmA74CygLOAt4Du0wAOA14DbgNvBC0ELoEBpIEB54EB6W8QEgBDAHUAcwB0AG8AbQBpAHoA | |
3105 | YXRpb26A94D0gAeA9tIADgAyADMEOYAEgPVfEBZJUHl0aG9uQ29jb2FDb250cm9sbGVyWGRlbGVnYXRl |
|
3105 | ZQAgAFQAbwBvAGwAYgBhAHIgJl8QH3J1blRvb2xiYXJDdXN0b21pemF0aW9uUGFsZXR0ZTrTAA4DWANZ | |
3106 | 0gA3ADgEPQQ+owQ+A4sAO18QFE5TTmliT3V0bGV0Q29ubmVjdG9y0wAOA1gDWQNaBEEEQoC7gPmA+9gA |
|
3106 | A1oEMwQ0gLuA8oD12AAOA14DXwNgA2EDYgNjA2QDZQQ3BDgEOQNpA2oDawQqgLmA8xIAGAAAgPSAs4C3 | |
3107 | DgNeA18DYANhA2IDYwNkA2YERQNoBCcDagNrA2wDyIC5gPqA8YCzgLeAz1ZEZWxldGVXZGVsZXRlOtMA |
|
3107 | gO5cU2hvdyBUb29sYmFyUXRfEBN0b2dnbGVUb29sYmFyU2hvd2460wAOA1gDWQNaBEIEQ4C7gPeA+tgA | |
3108 | DgNYA1kDWgROBE+Au4D9gQEB2AAOA14DXwNgA2EDYgNjA2QDZgRSA2gEUwNqA2sDbARWgLmA/4EBAICz |
|
3108 | DgNeA18DYANhA2IDYwNkA2UERgNnBEcDaQNqA2sDp4C5gPiA+YCzgLeAxFRTYXZlUXNdc2F2ZURvY3Vt | |
3109 | gLeA/tQADgNeAdUDbwNwBFkEWgRbgQGggQHrgQHvgQHtWE1pbmltaXplUW1fEBNwZXJmb3JtTWluaWF0 |
|
3109 | ZW50OtQADgRPA1gDWQRQBFEEUgRTXU5TRGVzdGluYXRpb26BAQCA/YD8gP/SAA4AMgAzADSABIAD0gAO | |
3110 | dXJpemU60wAOA1gDWQNaBGEEYoC7gQEDgQEF2AAOA14DXwNgA2EDYgNjA2QDZgRlA2gEJwNqA2sDbARW |
|
3110 | ADIAMwRZgASA/l8QGklQeXRob24xU2FuZGJveEFwcERlbGVnYXRlWGRlbGVnYXRl0gA3ADgEXQReowRe | |
3111 | gLmBAQSA8YCzgLeA/l8QEkJyaW5nIEFsbCB0byBGcm9udF8QD2FycmFuZ2VJbkZyb250OtMADgNYA1kD |
|
3111 | A4oAO18QFE5TTmliT3V0bGV0Q29ubmVjdG9y0wAOA1gDWQNaBGEEYoC7gQECgQEF2QAOA14DXwNgA2ED | |
3112 | WgRuBG+Au4EBB4EBCdgADgNeA18DYANhA2IDYwNkA2YEcgNoBCcDagNrA2wD6oC5gQEIgPGAs4C3gNpY |
|
3112 | YgNjA2QDtANlBGUDZwRmA2kDagNrA7sAVYC5gQEDgQEEgLOAt4DKXFNtYXJ0IFF1b3Rlc1FnXxAhdG9n | |
3113 | U2hvdyBBbGxfEBZ1bmhpZGVBbGxBcHBsaWNhdGlvbnM60wAOA1gDWQNaBHsEfIC7gQELgQEO2AAOA14D |
|
3113 | Z2xlQXV0b21hdGljUXVvdGVTdWJzdGl0dXRpb2461AAOBE8DWANZBFAEbwRRBHGBAQCBAQeA/YEBCdIA | |
3114 | XwNgA2EDYgNjA2QDZgR/A2gEgANqA2sDbAO2gLmBAQyBAQ2As4C3gMlVQ2xvc2VRd11wZXJmb3JtQ2xv |
|
3114 | DgAyADMEdIAEgQEIXxAWSVB5dGhvbkNvY29hQ29udHJvbGxlcl8QEWlweXRob25Db250cm9sbGVy0wAO | |
3115 | c2U61AAOBDIDWANZA1oAHwSKBIuAu4ACgQEQgQES1wAOA14DYANhA2IDYwNkA2YEjgQnA2oDawNsA+qA |
|
3115 | A1gDWQNaBHkEeoC7gQELgQEO2AAOA14DXwNgA2EDYgNjA2QDZQR9A2cEfgNpA2oDawNsgLmBAQyBAQ2A | |
3116 | uYEBEYDxgLOAt4DaXxAVQWJvdXQgSVB5dGhvbjFTYW5kYm94XxAdb3JkZXJGcm9udFN0YW5kYXJkQWJv |
|
3116 | s4C3gLBfEBRRdWl0IElQeXRob24xU2FuZGJveFFxWnRlcm1pbmF0ZTrTAA4DWANZA1oEhwSIgLuBARCB | |
3117 | dXRQYW5lbDrTAA4DWANZA1oElwSYgLuBARSBARjYAA4DXgNfA2ADYQNiA2MDZANmBJsDaAScA2oDawNs |
|
3117 | ARTYAA4DXgNfA2ADYQNiA2MDZANlBIsDZwSMA2kDagNrBI+AuYEBEoEBE4CzgLeBARHUAA4DXgHVA24D | |
3118 | BJ+AuYEBFoEBF4CzgLeBARXTAA4DXgNvA3AEogSjgQGggQHdgQHfXkNoZWNrIFNwZWxsaW5nUTteY2hl |
|
3118 | bwSSBJMElIEBpIEB64EB74EB7VhNaW5pbWl6ZVFtXxATcGVyZm9ybU1pbmlhdHVyaXplOtMADgNYA1kD | |
3119 | Y2tTcGVsbGluZzrTAA4DWANZA1oEqQSqgLuBARqBAR3YAA4DXgNfA2ADYQNiA2MDZANmBK0DaASuA2oD |
|
3119 | WgSaBJuAu4EBFoEBGdgADgNeA18DYANhA2IDYwNkA2UEngNnBJ8DaQNqA2sDzYC5gQEXgQEYgLOAt4DQ | |
3120 | awNsA8iAuYEBG4EBHICzgLeAz1pTZWxlY3QgQWxsUWFac2VsZWN0QWxsOtMADgNYA1kDWgS3BLiAu4EB |
|
3120 | VFVuZG9RelV1bmRvOtMADgNYA1kDWgSoBKmAu4EBG4EBHtgADgNeA18DYANhA2IDYwNkA2UErANnBK0D | |
3121 | H4EBIdgADgNeA18DYANhA2IDYwNkA2YEuwNoA+cDagNrA2wD6oC5gQEggNyAs4C3gNpfEBRIaWRlIElQ |
|
3121 | aQNqA2sDlYC5gQEcgQEdgLOAt4C+bgBTAGgAbwB3ACAAUwBwAGUAbABsAGkAbgBnICZROl8QD3Nob3dH | |
3122 |
|
|
3122 | dWVzc1BhbmVsOtMADgNYA1kDWgS2BLeAu4EBIIEBJNgADgNeA18DYANhA2IDYwNkA2UEugO3BLsDaQNq | |
3123 | yANoBCcDagNrA2wEn4C5gQEkgPGAs4C3gQEVXxAbQ2hlY2sgU3BlbGxpbmcgV2hpbGUgVHlwaW5nXxAe |
|
3123 | A2sEvoC5gQEigQEjgLOAt4EBIdMADgNeA24DbwTBBMKBAaSBAZ+BAaFbU2hvdyBDb2xvcnNRQ18QFW9y | |
3124 | dG9nZ2xlQ29udGludW91c1NwZWxsQ2hlY2tpbmc60wAOA1gDWQNaBNEE0oC7gQEngQEq2AAOA14DXwNg |
|
3124 | ZGVyRnJvbnRDb2xvclBhbmVsOtMADgNYA1kDWgTIBMmAu4EBJoEBKdgADgNeA18DYANhA2IDYwNkA2UE | |
3125 | A2EDYgNjA2QDZgTVA2gE1gNqA2sDbAO2gLmBASiBASmAs4C3gMlmAFAAcgBpAG4AdCAmUXBWcHJpbnQ6 |
|
3125 | zAQ4BM0DaQNqA2sDbIC5gQEngQEogLOAt4CwW0hpZGUgT3RoZXJzUWhfEBZoaWRlT3RoZXJBcHBsaWNh | |
3126 |
0wAOA1gDWQNaBN |
|
3126 | dGlvbnM60wAOA1gDWQNaBNYE14C7gQErgQEu2AAOA14DXwNgA2EDYgNjA2QDZQTaA2cE2wNpA2oDawPN | |
3127 | AS6As4C3gMloAFMAYQB2AGUAIABBAHMgJlFTXxAPc2F2ZURvY3VtZW50QXM60wAOA1gDWQNaBO0E7oC7 |
|
3127 | gLmBASyBAS2As4C3gNBUQ29weVFjVWNvcHk60wAOA1gDWQNaBOQE5YC7gQEwgQE02QAOA14DXwNgA2ED | |
3128 | gQExgQE02AAOA14DXwNgA2EDYgNjA2QDZgTxA2gE8gNqA2sDbAPqgLmBATKBATOAs4C3gNpfEBRRdWl0 |
|
3128 | YgNjA2QDtANlBOgDZwTpA2kDagNrBOwAkIC5gQEygQEzgLOAt4EBMdMADgNeA24DbwTvBPCBAaSBAbWB | |
3129 | IElQeXRob24xU2FuZGJveFFxWnRlcm1pbmF0ZTrTAA4DWANZA1oE+wT8gLuBATaBATnZAA4DXgNfA2AD |
|
3129 | AbdlAEYAaQBuAGQgJlFmXxAXcGVyZm9ybUZpbmRQYW5lbEFjdGlvbjrTAA4DWANZA1oE9gT3gLuBATaB | |
3130 | YQNiA2MDZANlA2YE/wPXBQADagNrA2wDbQFYgLmBATeBATiAs4C3gLBbU21hcnQgTGlua3NRR18QHXRv |
|
3130 | ATjYAA4DXgNfA2ADYQNiA2MDZANlBPoDZwNoA2kDagNrA9+AuYEBN4CygLOAt4DWXVN0b3AgU3BlYWtp | |
3131 | Z2dsZUF1dG9tYXRpY0xpbmtEZXRlY3Rpb2461AAOBDIDWANZBDMENAUKBQuA94D0gQE7gQE90gAOADIA |
|
3131 | bmddc3RvcFNwZWFraW5nOtQADgRPA1gDWQNaAB8FBAUFgLuAAoEBOoEBPNcADgNeA2ADYQNiA2MDZANl | |
3132 | MwUOgASBATxfEBpJUHl0aG9uMVNhbmRib3hBcHBEZWxlZ2F0ZV8QEWlweXRob25Db250cm9sbGVy0wAO |
|
3132 | BQgDaANpA2oDawNsgLmBATuAsoCzgLeAsF8QFUFib3V0IElQeXRob24xU2FuZGJveF8QHW9yZGVyRnJv | |
3133 | A1gDWQNaBRMFFIC7gQE/gQFB2AAOA14DXwNgA2EDYgNjA2QDZgUXA2gEJwNqA2sDbARWgLmBAUCA8YCz |
|
3133 | bnRTdGFuZGFyZEFib3V0UGFuZWw60wAOA1gDWQNaBREFEoC7gQE+gQFB2QAOBRQDXgNfA2ADYQNiA2MD | |
3134 | gLeA/lRab29tXHBlcmZvcm1ab29tOtMADgNYA1kDWgUgBSGAu4EBQ4EBRtgADgNeA18DYANhA2IDYwNk |
|
3134 | ZANlA2gFFwO3BRgDaQNqA2sDp1lOU1Rvb2xUaXCAuYCygQE/gQFAgLOAt4DEXVBhZ2UgU2V0dXAuLi5R | |
3135 | A2YFJANoBSUDagNrA2wDyIC5gQFEgQFFgLOAt4DPVENvcHlRY1Vjb3B5OtMADgNYA1kDWgUuBS+Au4EB |
|
3135 | UF5ydW5QYWdlTGF5b3V0OtQADgRPA1gDWQRQBG8AQQRTgQEAgQEHgAeA/9MADgNYA1kDWgUmBSeAu4EB | |
3136 |
|
|
3136 | RIEBR9gADgNeA18DYANhA2IDYwNkA2UFKgNnBSsDaQNqA2sDzYC5gQFFgQFGgLOAt4DQVVBhc3RlUXZW | |
3137 | cAU5BTqBAaCBAeeBAelcU2hvdyBUb29sYmFyUXRfEBN0b2dnbGVUb29sYmFyU2hvd2461AAOBDIDWANZ |
|
3137 | cGFzdGU61AAOBE8DWANZBFAAyABBBTaBAQCAGIAHgQFJXxAVaW5pdGlhbEZpcnN0UmVzcG9uZGVy0wAO | |
3138 | BDMFCgVBBDaA94EBO4EBToD20gAOADIAMwA0gASAA9MADgNYA1kDWgVIBUmAu4EBUIEBUtgADgNeA18D |
|
3138 | A1gDWQNaBToFO4C7gQFLgQFO2AAOA14DXwNgA2EDYgNjA2QDZQU+A2cFPwNpA2oDawTsgLmBAUyBAU2A | |
3139 | YANhA2IDYwNkA2YFTANoBCcDagNrA2wEKoC5gQFRgPGAs4C3gO9eU3RhcnQgU3BlYWtpbmdec3RhcnRT |
|
3139 | s4C3gQExXxARSnVtcCB0byBTZWxlY3Rpb25Ral8QHWNlbnRlclNlbGVjdGlvbkluVmlzaWJsZUFyZWE6 | |
3140 | cGVha2luZzrTAA4DWANZA1oFVQVWgLuBAVSBAVjYAA4DXgNfA2ADYQNiA2MDZANmBVkDaAVaA2oDawNs |
|
3140 | 0wAOA1gDWQNaBUgFSYC7gQFQgQFT2AAOA14DXwNgA2EDYgNjA2QDZQVMA2cDaANpA2oDawVQgLmBAVKA | |
3141 | BV2AuYEBVoEBV4CzgLeBAVXTAA4DXgNvA3AFYAVhgQGggQHxgQHzXxAUSVB5dGhvbjFTYW5kYm94IEhl |
|
3141 | soCzgLeBAVHUAA4DXgHVA24DbwVTBVQFVYEBpIEBpYEBp4EBplpDbGVhciBNZW51XxAVY2xlYXJSZWNl | |
3142 | bHBRP1lzaG93SGVscDrTAA4DWANZA1oFZwVogLuBAVqBAV3YAA4DXgNfA2ADYQNiA2MDZANmBWsDaAQn |
|
3142 | bnREb2N1bWVudHM60wAOA1gDWQNaBVoFW4C7gQFVgQFX2AAOA14DXwNgA2EDYgNjA2QDZQVeA2cDaANp | |
3143 | A2oDawNsBW+AuYEBXIDxgLOAt4EBW9QADgNeAdUDbwNwBXIFcwV0gQGggQGigQGlgQGkWkNsZWFyIE1l |
|
3143 | A2oDawPNgLmBAVaAsoCzgLeA0FZEZWxldGVXZGVsZXRlOtMADgNYA1kDWgVnBWiAu4EBWYEBW9cADgNe | |
3144 | bnVfEBVjbGVhclJlY2VudERvY3VtZW50czrTAA4DWANZA1oFeQV6gLuBAV+BAWHYAA4DXgNfA2ADYQNi |
|
3144 | A2ADYQNiA2MDZANlBWsDaANpA2oDawOngLmBAVqAsoCzgLeAxF8QD1JldmVydCB0byBTYXZlZF8QFnJl | |
3145 | A2MDZANmBX0DaAQnA2oDawNsBTaAuYEBYIDxgLOAt4EBSW8QEgBDAHUAcwB0AG8AbQBpAHoAZQAgAFQA |
|
3145 | dmVydERvY3VtZW50VG9TYXZlZDrUAA4ETwNYA1kEUADIBG8FdoEBAIAYgQEHgQFdWHRleHRWaWV30wAO | |
3146 | bwBvAGwAYgBhAHIgJl8QH3J1blRvb2xiYXJDdXN0b21pemF0aW9uUGFsZXR0ZTrTAA4DWANZA1oFhgWH |
|
3146 | A1gDWQNaBXoFe4C7gQFfgQFh2AAOA14DXwNgA2EDYgNjA2QDZQV+A2cDaANpA2oDawSPgLmBAWCAsoCz | |
3147 | gLuBAWOBAWbYAA4DXgNfA2ADYQNiA2MDZANmBYoDaAWLA2oDawNsA8iAuYEBZIEBZYCzgLeAz1NDdXRR |
|
3147 | gLeBARFfEBJCcmluZyBBbGwgdG8gRnJvbnRfEA9hcnJhbmdlSW5Gcm9udDrTAA4DWANZA1oFhwWIgLuB | |
3148 | eFRjdXQ61AAOBDIDWANZBDMAyAQ0BZaA94AYgPSBAWhYdGV4dFZpZXfUAA4EMgNYA1kEMwDIAEEFnID3 |
|
3148 | AWOBAWXYAA4DXgNfA2ADYQNiA2MDZANlBYsDZwTNA2kDagNrA2yAuYEBZIEBKICzgLeAsF8QFEhpZGUg | |
3149 | gBiAB4EBal8QFWluaXRpYWxGaXJzdFJlc3BvbmRlctMADgNYA1kDWgWgBaGAu4EBbIEBb9kADgWjA14D |
|
3149 | SVB5dGhvbjFTYW5kYm94VWhpZGU60wAOA1gDWQNaBZQFlYC7gQFngQFp2AAOA14DXwNgA2EDYgNjA2QD | |
3150 | XwNgA2EDYgNjA2QDZgQnBaYD1wWnA2oDawNsA7ZZTlNUb29sVGlwgLmA8YEBbYEBboCzgLeAyV1QYWdl |
|
3150 | ZQWYA2cDaANpA2oDawSPgLmBAWiAsoCzgLeBARFUWm9vbVxwZXJmb3JtWm9vbTrTAA4DWANZA1oFoQWi | |
3151 | IFNldHVwLi4uUVBecnVuUGFnZUxheW91dDrTAA4DWANZA1oFsAWxgLuBAXGBAXTYAA4DXgNfA2ADYQNi |
|
3151 | gLuBAWuBAW3ZAA4DXgNfA2ADYQNiA2MDZAO0A2UFpQNnBOkDaQNqA2sDuwCQgLmBAWyBATOAs4C3gMpf | |
3152 | A2MDZANmBbQDaAW1A2oDawNsBJ+AuYEBcoEBc4CzgLeBARVuAFMAaABvAHcAIABTAHAAZQBsAGwAaQBu |
|
3152 | EBBTbWFydCBDb3B5L1Bhc3RlXxAYdG9nZ2xlU21hcnRJbnNlcnREZWxldGU60wAOA1gDWQNaBa4Fr4C7 | |
3153 | AGcgJlE6XxAPc2hvd0d1ZXNzUGFuZWw60wAOA1gDWQNaBb4Fv4C7gQF2gQF41wAOA14DYANhA2IDYwNk |
|
3153 | gQFvgQFy2AAOA14DXwNgA2EDYgNjA2QDZQWyA7cFswNpA2oDawOngLmBAXCBAXGAs4C3gMRoAFMAYQB2 | |
3154 | A2YFwgQnA2oDawNsA7aAuYEBd4DxgLOAt4DJXxAPUmV2ZXJ0IHRvIFNhdmVkXxAWcmV2ZXJ0RG9jdW1l |
|
3154 | AGUAIABBAHMgJlFTXxAPc2F2ZURvY3VtZW50QXM60wAOA1gDWQNaBbwFvYC7gQF0gQF32AAOA14DXwNg | |
3155 | bnRUb1NhdmVkOtMADgNYA1kDWgXLBcyAu4EBeoEBfNgADgNeA18DYANhA2IDYwNkA2YFzwNoBCcDagNr |
|
3155 | A2EDYgNjA2QDZQXAA2cFwQNpA2oDawPNgLmBAXWBAXaAs4C3gNBTQ3V0UXhUY3V0OtMADgNYA1kDWgXK | |
3156 | A2wEn4C5gQF7gPGAs4C3gQEVXxAbQ2hlY2sgR3JhbW1hciBXaXRoIFNwZWxsaW5nXxAWdG9nZ2xlR3Jh |
|
3156 | BcuAu4EBeYEBfNgADgNeA18DYANhA2IDYwNkA2UFzgNnBc8DaQNqA2sDp4C5gQF6gQF7gLOAt4DEVUNs | |
3157 |
b |
|
3157 | b3NlUXddcGVyZm9ybUNsb3NlOtcADgRPBdcF2ANYA1kF2QXaBFEF3AXdBd4F3wBVWU5TS2V5UGF0aFlO | |
3158 |
bmdfEBxOU05pYkJpbmRpbmdDb25uZWN0b3JWZXJzaW9ugQG |
|
3158 | U0JpbmRpbmdfEBxOU05pYkJpbmRpbmdDb25uZWN0b3JWZXJzaW9ugQGMgP2BAYuBAYqBAX6BAYnbBeEA | |
3159 |
5AXlBeYF5wXoBekF6gB6BewAegXuAHoF8AX |
|
3159 | DgXiBeMF5AXlBeYF5wXoBekF6gB6BewAegXuAHoF8AXxAHoAegB6BfVfEBpOU0ZpbHRlclJlc3RyaWN0 | |
3160 |
dGlvbl8QFE5TUHJlc2VydmVzU2VsZWN0aW9uXE5TSW5pdGlhbEtleVpOU0VkaXRhYmxlXk5T |
|
3160 | c0luc2VydGlvbl8QFE5TUHJlc2VydmVzU2VsZWN0aW9uXE5TSW5pdGlhbEtleVpOU0VkaXRhYmxlXk5T | |
3161 |
ZWRLZXlzXk5TSW5pdGlhbFZhbHVlXxAiTlNDbGVhcnNGaWx0ZXJQcmVkaWNhdGVPbkluc2Vy |
|
3161 | RGVjbGFyZWRLZXlzXk5TSW5pdGlhbFZhbHVlXxAiTlNDbGVhcnNGaWx0ZXJQcmVkaWNhdGVPbkluc2Vy | |
3162 |
GE5TU2VsZWN0c0luc2VydGVkT2JqZWN0c18QFk5TQXZvaWRzRW1wdHlTZWxlY3Rpb25fEBFO |
|
3162 | dGlvbl8QGE5TU2VsZWN0c0luc2VydGVkT2JqZWN0c18QFk5TQXZvaWRzRW1wdHlTZWxlY3Rpb25fEBFO | |
3163 |
ZXNjcmlwdG9ycwmBAYgJgQGBCYEBf4EBggkJCYEBg9IADgA+AGkF+IA0owX5Be4F |
|
3163 | U1NvcnREZXNjcmlwdG9ycwmBAYgJgQGBCYEBf4EBggkJCYEBg9IADgA+AGkF+IA0owX5Be4F8YEBgIEB | |
3164 |
ZXlzU2tleVV2YWx1ZdIADgA+BgAGAYEBh6EGAoEBhNQADgYEBgUGBgYHBe4GCQB6VU5TS2V5 |
|
3164 | gYEBglRrZXlzU2tleVV2YWx1ZdIADgA+BgAGAYEBh6EGAoEBhNQADgYEBgUGBgYHBe4GCQB6VU5TS2V5 | |
3165 |
ZWN0b3JbTlNBc2NlbmRpbmeBAYaBAYGBAYUJWGNvbXBhcmU60gA3ADgGDQYOogYOADtfEBBO |
|
3165 | Wk5TU2VsZWN0b3JbTlNBc2NlbmRpbmeBAYaBAYGBAYUJWGNvbXBhcmU60gA3ADgGDQYOogYOADtfEBBO | |
3166 |
ZXNjcmlwdG9y0gA3ADgGEAE4ogE4ADvSADcAOAYSBhOlBhMGFAYVBhYAO18QFk5TRGljdGl |
|
3166 | U1NvcnREZXNjcmlwdG9y0gA3ADgGEAE4ogE4ADvSADcAOAYSBhOlBhMGFAYVBhYAO18QFk5TRGljdGlv | |
3167 |
bnRyb2xsZXJfEBFOU0FycmF5Q29udHJvbGxlcl8QEk5TT2JqZWN0Q29udHJvbGxlclxOU0Nv |
|
3167 | bmFyeUNvbnRyb2xsZXJfEBFOU0FycmF5Q29udHJvbGxlcl8QEk5TT2JqZWN0Q29udHJvbGxlclxOU0Nv | |
3168 | ZXJfEBp2YWx1ZTogYXJyYW5nZWRPYmplY3RzLmtleV8QE2FycmFuZ2VkT2JqZWN0cy5rZXnSADcAOAYa |
|
3168 | bnRyb2xsZXJfEClmaWx0ZXJQcmVkaWNhdGU6IHdvcmtzcGFjZUZpbHRlclByZWRpY2F0ZV8QD2ZpbHRl | |
3169 | BhujBhsDiwA7XxAVTlNOaWJCaW5kaW5nQ29ubmVjdG9y1wAOBDIF1wXYA1gDWQXZBdoENAYfBiAF2wYi |
|
3169 | clByZWRpY2F0ZV8QGHdvcmtzcGFjZUZpbHRlclByZWRpY2F0ZdIANwA4BhsGHKMGHAOKADtfEBVOU05p | |
3170 | AFWBAYuA9IEBj4EBjoEBfoEBjV8QGWNvbnRlbnREaWN0aW9uYXJ5OiB1c2VyTlNfEBFjb250ZW50RGlj |
|
3170 | YkJpbmRpbmdDb25uZWN0b3LXAA4ETwXXBdgDWANZBdkF2gRvBiAGIQXeBiMAVYEBjIEBB4EBkIEBj4EB | |
3171 | dGlvbmFyeVZ1c2VyTlPXAA4EMgXXBdgDWANZBdkF2gXbBikF3QJ2BiwAVYEBi4EBfoEBkoEBgoCLgQGR |
|
3171 | foEBjl8QGWNvbnRlbnREaWN0aW9uYXJ5OiB1c2VyTlNfEBFjb250ZW50RGljdGlvbmFyeVZ1c2VyTlPX | |
3172 | XxAcdmFsdWU6IGFycmFuZ2VkT2JqZWN0cy52YWx1ZV8QFWFycmFuZ2VkT2JqZWN0cy52YWx1ZdcADgQy |
|
3172 | AA4ETwXXBdgDWANZBdkF2gXeBioF8QJ2Bi0AVYEBjIEBfoEBk4EBgoCLgQGSXxAcdmFsdWU6IGFycmFu | |
3173 | BdcF2ANYA1kF2QXaBQoGMgYzBdsGNQBVgQGLgQE7gQGWgQGVgQF+gQGUXxApZmlsdGVyUHJlZGljYXRl |
|
3173 | Z2VkT2JqZWN0cy52YWx1ZV8QFWFycmFuZ2VkT2JqZWN0cy52YWx1ZdcADgRPBdcF2ANYA1kF2QXaBd4G | |
3174 | OiB3b3Jrc3BhY2VGaWx0ZXJQcmVkaWNhdGVfEA9maWx0ZXJQcmVkaWNhdGVfEBh3b3Jrc3BhY2VGaWx0 |
|
3174 | MwXxAnUGNgBVgQGMgQF+gQGWgQGCgHyBAZVfEBp2YWx1ZTogYXJyYW5nZWRPYmplY3RzLmtleV8QE2Fy | |
3175 | ZXJQcmVkaWNhdGXXAA4EMgXXBdgDWANZBdkF2gQ0BjwGPQBsBj8AVYEBi4D0gQGagQGZgKOBAZhfEBlh |
|
3175 | cmFuZ2VkT2JqZWN0cy5rZXnXAA4ETwXXBdgDWANZBdkF2gRvBjwGPQBsBj8AVYEBjIEBB4EBmoEBmYCj | |
3176 | bmltYXRlOiB3YWl0aW5nRm9yRW5naW5lV2FuaW1hdGVfEBB3YWl0aW5nRm9yRW5naW5l0gAOAD4GAAZF |
|
3176 | gQGYXxAZYW5pbWF0ZTogd2FpdGluZ0ZvckVuZ2luZVdhbmltYXRlXxAQd2FpdGluZ0ZvckVuZ2luZdIA | |
3177 | gQGHrxBnA1sGRwTfAkQCdQZLBIoEQQUgBW8GUATRBbAFywZUBFYFLgZXBYYGWQIKA20GXATtBl4GXwS3 |
|
3177 | DgA+BgAGRYEBh68QZwZGAGsE5AVaBkoCwAVQBk0CgwZPBlAE1gZSBlMGVARCAE0AfgPwA7sEBwT2A7EE | |
3178 | BmEGYgBNBdsAawVVBHsFoAZpBmoAyAUKBGEGbgSpBnAAbAZyBBUD9QIaA8gAfwPqAnYEIgZ7BJcGfQOO |
|
3178 | FQP6AgoAfwNsBJoGYwOnAEECKgTIA1sEeQPfBSYFegRSBm4EbwPoAMgF3gWuBnQE7AONBUgGeAZ5BGED | |
3179 | Bn8GgAV5AioGgwSfAhAETgPSBogEBwCqBb4D4QaNBo4D/QLAA64AfgaTBG4FEwTEAKMFXQT7BpoGmwOg |
|
3179 | nwOVA80GfgQqBoAEUQaCBREEMwIaBoYGhwaIBokAqgaLBCIFBASoA9cAbAWHBcoCRAaUA8UGlgJ2ALEF | |
3180 | BTYDlgafBWcEKgPABDQFQQKDAEEAsQaoBqkFSAO2BqyAr4EBnIEBLIB0gHyBAaGBARCA+YEBQ4EBW4EB |
|
3180 | OgS+BpsFvAJ1Bp4FZwagBIcFoQS2AKMGpQIQBqcGqAWUBqoGqwSPgQGcgA6BATCBAVWBAZ2AjoEBUYEB | |
3181 | poEBJ4EBcYEBeoEBqoD+gQFIgQHDgQFjgQHwgG6AsIEB2YEBMYEBv4EBz4EBH4EB5oEB5IALgQF+gA6B |
|
3181 | qICDgQGqgQGugQErgQGygQGegQG/gPeAC4AQgNuAyoDkgQE2gMmA6YDggG6AaoCwgQEWgQHYgMSAB4By | |
3182 | AVSBAQuBAWyBAbaBAbWAGIEBO4EBA4EB6oEBGoEBxoCjgQG9gOqA34CUgM+AaoDagIuA7oEBrYEBFIEB |
|
3182 | gQEmgK+BAQuA1oEBRIEBX4D8gQHVgQEHgNqAGIEBfoEBb4EB6oEBMYC9gQFQgQHlgQHugQECgMOAvoDQ | |
3183 | y4C9gQHQgQHugQFfgHKBAbGBARWAloD9gNSBAdGA5YBYgQF2gNmBAdeBAbyA4ICOgMiAEIEB1YEBB4EB |
|
3183 | gQG4gO6BAeGA/YEBzoEBPoDygJSBAbyBAcmBAd6BAeaAWIEBtIDtgQE6gQEbgNWAo4EBY4EBeYB0gQHN | |
3184 | P4EBI4AUgQFVgQE2gQHcgQGygMOBAUmAvoEB4IEBWoDvgM6A9IEBToCDgAeAVIEBuYEByoEBUIDJgQHJ |
|
3184 | gM+BAdqAi4BUgQFLgQEhgQHwgQF0gHyBAbOBAVmBAcOBARCBAWuBASCAFIEB0YCWgQHSgQGigQFngQG6 | |
3185 | 2gAOBq4DXgNfA2ADYQNiA2MDZAGgA2YEKgQtA2gEJwNqA2sDbAPIBrZZTlNTdWJtZW51gLmA74EBnYDx |
|
3185 | gQHkgQER2gAOA14DXwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2xdTlNJc1NlcGFyYXRv | |
3186 | gLOAt4DPgQGeVlNwZWVjaF5zdWJtZW51QWN0aW9uOtIADgA+AGkGu4A0ogVIBCKBAVCA7tIANwA4Br8D |
|
3186 | clxOU0lzRGlzYWJsZWSAuYCyCYCyCYCzgLeAsNoADga5A14DXwNgA2EDYgNjA2QBoANlBL4EwQNnA2gD | |
3187 | ZKIDZAA72gAOBq4DXgNfA2ADYQNiA2MDZAGgA2YFbwVyA2gEJwNqA2sDbAO2BsiAuYEBW4EBooDxgLOA |
|
3187 | aQNqA2sGUwbBWU5TU3VibWVudYC5gQEhgQGfgLKAs4C3gQGegQGg1AAOA14B1QNuA28GxAbFBsaBAaSB | |
3188 | t4DJgQGjW09wZW4gUmVjZW500gAOAD4AaQbMgDShBWeBAVpfEBZfTlNSZWNlbnREb2N1bWVudHNNZW51 |
|
3188 | AceBAfSBAchWRm9ybWF0XnN1Ym1lbnVBY3Rpb2460gAOAD4AaQbLgDSiBqgEtoEBooEBINgADgNeA18D | |
3189 | 2gAOBq4DXgNfA2ADYQNiA2MDZAGgA2YDbQNxA2gEJwNqA2sDbAPIBteAuYCwgQGngPGAs4C3gM+BAahd |
|
3189 | YANhA2IDYwNkA2UG0ANnBDkDaQNqA2sEvoC5gQGjgPSAs4C3gQEhWlNob3cgRm9udHPSADcAOAbXA2Si | |
3190 | U3Vic3RpdHV0aW9uc9IADgA+AGkG24A0owOgA1sE+4DDgK+BATbUAA4DXgHVA28DcAbhBuIG44EBoIEB |
|
3190 | A2QAO1tPcGVuIFJlY2VudNIADgA+AGkG24A0oQVIgQFQXxAWX05TUmVjZW50RG9jdW1lbnRzTWVuddoA | |
3191 | q4EB9IEBrFlBTWFpbk1lbnXSAA4APgBpBueANKcGewZeBn0GnwZhBm4GWYEBrYEBv4EBy4EB4IEB5oEB |
|
3191 | Dga5A14DXwNgA2EDYgNjA2QBoANlBVAFUwNnA2gDaQNqA2sDpwbmgLmBAVGBAaWAsoCzgLeAxIEBqdoA | |
3192 | 6oEB8NoADgauA14DXwNgA2EDYgNjA2QBoANmA+oD7QNoBCcDagNrA2wGVAb3gLmA2oEBroDxgLOAt4EB |
|
3192 | Dga5A14DXwNgA2EDYgNjA2QBoANlA5UDmANnA2gDaQNqA2sDzQbvgLmAvoEBq4CygLOAt4DQgQGsXxAU | |
3193 | qoEBr18QD0lQeXRob24xU2FuZGJveNIADgA+AGkG+4A0qwSKBoMGmwZqBmkGjgS3A+EEbgZyBO2BARCB |
|
3193 | U3BlbGxpbmcgYW5kIEdyYW1tYXLSAA4APgBpBvOANKQEqAONA/oEFYEBG4C9gOCA6doADga5A14DXwNg | |
3194 | AbGBAbKBAbWBAbaBAbyBAR+A2YEBB4EBvYEBMdoADgNeA18HCANgBwkDYQNiA2MDZANmBCcDaAB6BCcA |
|
3194 | A2EDYgNjA2QBoANlA80D0ANnA2gDaQNqA2sGUwcAgLmA0IEBr4CygLOAt4EBnoEBsFRFZGl00gAOAD4A | |
3195 | egNqA2sDbAPqXU5TSXNTZXBhcmF0b3JcTlNJc0Rpc2FibGVkgLmA8QmA8QmAs4C3gNrYAA4DXgNfA2AD |
|
3195 | aQcEgDStBJoDxQZSBbwE1gUmBVoEBwaeBosGTwZUBqCBARaAz4EBsoEBdIEBK4EBRIEBVYDkgQGzgQG0 | |
3196 | YQNiA2MDZANmBxQDaAcVA2oDawNsA+qAuYEBs4EBtICzgLeA2mwAUAByAGUAZgBlAHIAZQBuAGMAZQBz |
|
3196 | gQGqgQG/gQHD2gAOA14DXwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA82AuYCyCYCyCYCz | |
3197 |
|
|
3197 | gLeA0NoADgNeA18GrgNgBq8DYQNiA2MDZANlA2gDZwB6A2gAegNpA2oDawPNgLmAsgmAsgmAs4C3gNDa | |
3198 |
AA4G |
|
3198 | AA4GuQNeA18DYANhA2IDYwNkAaADZQTsBO8DZwNoA2kDagNrA80HLIC5gQExgQG1gLKAs4C3gNCBAbZU | |
3199 | U2VydmljZXPUAA4DXgHVA28DcAcnBzEHMoEBoIEBt4EBu4EButIADgA+AGkHNYA0oF8QD19OU1NlcnZp |
|
3199 | RmluZNIADgA+AGkHMIA0pQTkBn4GqgaGBTqBATCBAbiBAbqBAbyBAUvZAA4DXgNfA2ADYQNiA2MDZAO0 | |
3200 | Y2VzTWVuddoADgNeA18HCANgBwkDYQNiA2MDZANmBCcDaAB6BCcAegNqA2sDbAPqgLmA8QmA8QmAs4C3 |
|
3200 | A2UHOANnBGYDaQNqA2sE7ABVgLmBAbmBAQSAs4C3gQExWUZpbmQgTmV4dNkADgNeA18DYANhA2IDYwNk | |
3201 | gNraAA4DXgNfBwgDYAcJA2EDYgNjA2QDZgQnA2gAegQnAHoDagNrA2wD6oC5gPEJgPEJgLOAt4DaXF9O |
|
3201 | A7QDZQdAA7cDuANpA2oDawTsAViAuYEBu4DMgLOAt4EBMV1GaW5kIFByZXZpb3Vz2QAOA14DXwNgA2ED | |
3202 | U0FwcGxlTWVuddoADgauA14DXwNgA2EDYgNjA2QBoANmA7YDuQNoBCcDagNrA2wGVAdSgLmAyYEBwIDx |
|
3202 | YgNjA2QDtANlB0gDZwdJA2kDagNrBOwHTYC5gQG9gQG+gLOAt4EBMRAHXxAWVXNlIFNlbGVjdGlvbiBm | |
3203 | gLOAt4EBqoEBwVRGaWxl0gAOAD4AaQdWgDSrBlcGcAZLBqwEewOuBN8FvgapBaAE0YEBw4EBxoEBoYEB |
|
3203 | b3IgRmluZFFl2gAOBrkDXgNfA2ADYQNiA2MDZAGgA2UDuwO+A2cDaANpA2oDawPNB1iAuYDKgQHAgLKA | |
3204 | yYEBC4DIgQEsgQF2gQHKgQFsgQEn2AAOA14DXwNgA2EDYgNjA2QDZgdkA2gHZQNqA2sDbAO2gLmBAcSB |
|
3204 | s4C3gNCBAcFdU3Vic3RpdHV0aW9uc9IADgA+AGkHXIA0owWhBGEDsYEBa4EBAoDJ2gAOBrkDXgNfA2AD | |
3205 | AcWAs4C3gMlTTmV3UW7YAA4DXgNfA2ADYQNiA2MDZANmB20DaAduA2oDawNsA7aAuYEBx4EByICzgLeA |
|
3205 | YQNiA2MDZAGgA2UD3wPiA2cDaANpA2oDawPNB2iAuYDWgQHEgLKAs4C3gNCBAcVWU3BlZWNo0gAOAD4A | |
3206 | yWUATwBwAGUAbiAmUW/aAA4DXgNfBwgDYAcJA2EDYgNjA2QDZgQnA2gAegQnAHoDagNrA2wDtoC5gPEJ |
|
3206 | aQdsgDSiA9cE9oDVgQE2WUFNYWluTWVuddIADgA+AGkHcoA0pwaHBpYGUAZKBokGdAabgQHJgQHagQGu | |
3207 | gPEJgLOAt4DJ2gAOA14DXwcIA2AHCQNhA2IDYwNkA2YEJwNoAHoEJwB6A2oDawNsA7aAuYDxCYDxCYCz |
|
3207 | gQGdgQHmgQHqgQHw2gAOBrkDXgNfA2ADYQNiA2MDZAGgA2UDbANwA2cDaANpA2oDawZTB4KAuYCwgQHK | |
3208 | gLeAydoADgauA14DXwNgA2EDYgNjA2QBoANmA8gDywNoBCcDagNrA2wGVAeOgLmAz4EBzIDxgLOAt4EB |
|
3208 | gLKAs4C3gQGegQHLXxAPSVB5dGhvbjFTYW5kYm940gAOAD4AaQeGgDSrBQQGlAaCBqUGpwZGBYcEyANb | |
3209 | qoEBzVRFZGl00gAOAD4AaQeSgDStA8AD0gZfBYYFIAQHBEEEqQZ/BogGmgZQBkeAzoDUgQHPgQFjgQFD |
|
3209 | BmMEeYEBOoEBzYEBzoEB0YEB0oEBnIEBY4EBJoCvgQHYgQEL2gAOA14DXwauA2AGrwNhA2IDYwNkA2UD | |
3210 | gOWA+YEBGoEB0IEB0YEB3IEBpoEBnNoADgNeA18HCANgBwkDYQNiA2MDZANmBCcDaAB6BCcAegNqA2sD |
|
3210 | aANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsNgADgNeA18DYANhA2IDYwNkA2UHnQNnB54DaQNq | |
3211 | bAPIgLmA8QmA8QmAs4C3gM/aAA4DXgNfBwgDYAcJA2EDYgNjA2QDZgQnA2gAegQnAHoDagNrA2wDyIC5 |
|
3211 | A2sDbIC5gQHPgQHQgLOAt4CwbABQAHIAZQBmAGUAcgBlAG4AYwBlAHMgJlEs2gAOA14DXwauA2AGrwNh | |
3212 | gPEJgPEJgLOAt4DP2gAOBq4DXgNfA2ADYQNiA2MDZAGgA2YDlgOZA2gEJwNqA2sDbAPIB7qAuYC+gQHS |
|
3212 | A2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsNoADga5A14DXwNgA2EDYgNjA2QB | |
3213 | gPGAs4C3gM+BAdNURmluZNIADgA+AGkHvoA0pQQVBpMGjQZcA46A6oEB1YEB14EB2YC92QAOA14DXwNg |
|
3213 | oANlBm4HsANnA2gDaQNqA2sDbAe1gLmBAdWBAdOAsoCzgLeAsIEB1FhTZXJ2aWNlc9QADgNeAdUDbgNv | |
3214 | A2EDYgNjA2QDZQNmB8YDaANpA2oDawNsA5YAVYC5gQHWgLKAs4C3gL5ZRmluZCBOZXh02QAOA14DXwNg |
|
3214 | B7AHuge7gQGkgQHTgQHXgQHW0gAOAD4AaQe+gDSgXxAPX05TU2VydmljZXNNZW512gAOA14DXwauA2AG | |
3215 | A2EDYgNjA2QDZQNmB84D1wUAA2oDawNsA5YBWIC5gQHYgQE4gLOAt4C+XUZpbmQgUHJldmlvdXPZAA4D |
|
3215 | rwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsFxfTlNBcHBsZU1lbnXaAA4G | |
3216 | XgNfA2ADYQNiA2MDZANlA2YH1gNoB9cDagNrA2wDlgfbgLmBAdqBAduAs4C3gL4QB18QFlVzZSBTZWxl |
|
3216 | uQNeA18DYANhA2IDYwNkAaADZQOnA6oDZwNoA2kDagNrBlMH0oC5gMSBAduAsoCzgLeBAZ6BAdxURmls | |
3217 | Y3Rpb24gZm9yIEZpbmRRZdoADgauA14DXwNgA2EDYgNjA2QBoANmBJ8EogNoBCcDagNrA2wDyAfmgLmB |
|
3217 | ZdIADgA+AGkH1oA0qwaIBoAGTQarBcoEQgWuBWcGeAURA5+BAd6BAeGBAaiBAeSBAXmA94EBb4EBWYEB | |
3218 | ARWBAd2A8YCzgLeAz4EB3l8QFFNwZWxsaW5nIGFuZCBHcmFtbWFy0gAOAD4AaQfqgDSkBbAElwTEBcuB |
|
3218 | 5YEBPoDD2AAOA14DXwNgA2EDYgNjA2QDZQfkA2cH5QNpA2oDawOngLmBAd+BAeCAs4C3gMRTTmV3UW7Y | |
3219 | AXGBARSBASOBAXraAA4GrgNeA18DYANhA2IDYwNkAaADZgP9BAADaAQnA2oDawNsBlQH94C5gOCBAeGA |
|
3219 | AA4DXgNfA2ADYQNiA2MDZANlB+0DZwfuA2kDagNrA6eAuYEB4oEB44CzgLeAxGUATwBwAGUAbiAmUW/a | |
3220 | 8YCzgLeBAaqBAeJWRm9ybWF00gAOAD4AaQf7gDSiBmID9YEB5IDf2AAOA14DXwNgA2EDYgNjA2QDZggA |
|
3220 | AA4DXgNfBq4DYAavA2EDYgNjA2QDZQNoA2cAegNoAHoDaQNqA2sDp4C5gLIJgLIJgLOAt4DE2gAOA14D | |
3221 | A2gFMwNqA2sDbAP9gLmBAeWBAUuAs4C3gOBaU2hvdyBGb250c9oADgauA14DXwNgA2EDYgNjA2QBoANm |
|
3221 | XwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA6eAuYCyCYCyCYCzgLeAxNoADga5A14DXwNg | |
3222 | BTYFOQNoBCcDagNrA2wGVAgOgLmBAUmBAeeA8YCzgLeBAaqBAehUVmlld9IADgA+AGkIEoA0ogUuBXmB |
|
3222 | A2EDYgNjA2QBoANlBCoELQNnA2gDaQNqA2sGUwgOgLmA7oEB54CygLOAt4EBnoEB6FRWaWV30gAOAD4A | |
3223 | AUiBAV/aAA4GrgNeA18DYANhA2IDYwNkAaADZgRWBFkDaAQnA2oDawNsBlQIHYC5gP6BAeuA8YCzgLeB |
|
3223 | aQgSgDSiBDMEIoDygO3aAA4GuQNeA18DYANhA2IDYwNkAaADZQSPBJIDZwNoA2kDagNrBlMIHYC5gQER | |
3224 | AaqBAexWV2luZG930gAOAD4AaQghgDSkBE4FEwaABGGA/YEBP4EB7oEBA9oADgNeA18HCANgBwkDYQNi |
|
3224 | gQHrgLKAs4C3gQGegQHsVldpbmRvd9IADgA+AGkIIYA0pASHBZQGeQV6gQEQgQFngQHugQFf2gAOA14D | |
3225 | A2MDZANmBCcDaAB6BCcAegNqA2sDbARWgLmA8QmA8QmAs4C3gP5eX05TV2luZG93c01lbnXaAA4GrgNe |
|
3225 | XwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrBI+AuYCyCYCyCYCzgLeBARFeX05TV2luZG93 | |
3226 | A18DYANhA2IDYwNkAaADZgVdBWADaAQnA2oDawNsBlQIOIC5gQFVgQHxgPGAs4C3gQGqgQHyVEhlbHDS |
|
3226 | c01lbnXaAA4GuQNeA18DYANhA2IDYwNkAaADZQPwA/MDZwNoA2kDagNrBlMIOIC5gNuBAfGAsoCzgLeB | |
3227 | AA4APgBpCDyANKEFVYEBVFtfTlNNYWluTWVuddIADgA+BgAIQYEBh68QZwNtA8gDtgIKAioDtgPqA8gD |
|
3227 | AZ6BAfJUSGVscNIADgA+AGkIPIA0oQPogNpbX05TTWFpbk1lbnXSAA4APgYACEGBAYevEGcDbABNBOwD | |
3228 | yAZLA8gDtgSfBJ8AHwZuBTYDtgPIBlQAfwZQA5YD6gZUA8gD6gZUA/0AQQAfAE0FXQO2A7YD6gPqAKMA |
|
3228 | zQZTAnYGTQOnAnUDzQZTA80DzQAfA80DpwBBAGsGmwZUA80D3wO7A5UDlQB/AGsGhwPNA2wGlgAfAgoD | |
3229 | HwRWBlQDyAO2AE0D6gOWA/0CCgZ9AGsGewIqBCoGVASfBlQDlgPIBFYFNgIKA+oGmgIKBFYDyAPIA8gA |
|
3229 | bANsA2wGoAPNBI8AHwanAB8D8ACjAB8DpwZTBosDlQVQA6cEjwO7A6cGTwZQBOwGiQOnAB8DbAOnBCoC | |
3230 | owO2A+oDlgPqBp8CdgO2AGsDlgPqBFYEnwB+BlkDbQPIA+oDbQZhBogGVAVvBkcDyAAfAB8CdQAfAKMG |
|
3230 | CgTsBlMDpwZTAKMDzQQqA2wDlQPfAE0DbAOnAgoDbAPNBlMCKgCjBOwGSgZTA80CKgPNA6cDzQSPA7sE | |
3231 | aQO2BCoGXgO2gLCAz4DJgG6AcoDJgNqAz4DPgQGhgM+AyYEBFYEBFYACgQHqgQFJgMmAz4EBqoBqgQGm |
|
3231 | vgB+A2wCCgNsBL4EjwTsA6cGdICwgAuBATGA0IEBnoCLgQGogMSAfIDQgQGegNCA0IACgNCAxIAHgA6B | |
3232 | gL6A2oEBqoDPgNqBAaqA4IAHgAKAC4EBVYDJgMmA2oDagBSAAoD+gQGqgM+AyYALgNqAvoDggG6BAcuA |
|
3232 | AfCBAb+A0IDWgMqAvoC+gGqADoEByYDQgLCBAdqAAoBugLCAsICwgQHDgNCBARGAAoEB0oACgNuAFIAC | |
3233 | DoEBrYBygO+BAaqBARWBAaqAvoDPgP6BAUmAboDagQHcgG6A/oDPgM+Az4AUgMmA2oC+gNqBAeCAi4DJ |
|
3233 | gMSBAZ6BAbSAvoEBUYDEgQERgMqAxIEBqoEBroEBMYEB5oDEgAKAsIDEgO6AboEBMYEBnoDEgQGegBSA | |
3234 | gA6AvoDagP6BARWAEIEB8ICwgM+A2oCwgQHmgQHRgQGqgQFbgQGcgM+AAoACgHyAAoAUgQG2gMmA74EB |
|
3234 | 0IDugLCAvoDWgAuAsIDEgG6AsIDQgQGegHKAFIEBMYEBnYEBnoDQgHKA0IDEgNCBARGAyoEBIYAQgLCA | |
3235 | v4DJ0gAOAD4GAAirgQGHrxBoA1sGRwTfAkQCdQZLBIoEQQUgBW8E0QZQBbAFywUuBlQEVgZXBYYGWQIK |
|
3235 | boCwgQEhgQERgQExgMSBAerSAA4APgYACKuBAYevEGgAawZGBOQFWgZKAsAFUAZNAoMGTwZQBNYGUgZT | |
3236 | A20GXATtBl4GXwS3BmEGYgBNBdsAawVVBHsFoAZpBmoAyAUKBGEGbgZwBKkAbAZyBBUD9QIaA8gD6gB/ |
|
3236 | BlQATQRCAH4D8AO7BAcE9gOxBBUCCgP6AH8DbABBA6cEmgZjAioEyANbBHkD3wUmBXoEUgZuBG8D6ADI | |
3237 | BCICdgZ7BJcGfQOOBn8GgAV5AioGgwSfAhAETgPSBogEBwCqBb4D4QaNBo4D/QLAA64AfgaTBG4FEwTE |
|
3237 | Bd4AHwWuBnQGeATsA40FSAZ5BGEDnwOVA80EKgZ+BoAEUQaCBREEMwIaBoYGhwaJBogAqgaLBCIFBABs | |
3238 | AKMFXQT7AB8GmgabBTYDoAafA5YFZwQqBDQDwAVBAoMAQQCxBqkGqAVIA7YGrICvgQGcgQEsgHSAfIEB |
|
3238 | BKgD1wWHBcoCRAaUA8UGlgJ2ALEEvgU6BpsFvAJ1Bp4FZwagBIcFoQS2AKMGpQIQBqcGqAWUBqoGqwSP | |
3239 | oYEBEID5gQFDgQFbgQEngQGmgQFxgQF6gQFIgQGqgP6BAcOBAWOBAfCAboCwgQHZgQExgQG/gQHPgQEf |
|
3239 | gA6BAZyBATCBAVWBAZ2AjoEBUYEBqICDgQGqgQGugQErgQGygQGegQG/gAuA94AQgNuAyoDkgQE2gMmA | |
3240 | gQHmgQHkgAuBAX6ADoEBVIEBC4EBbIEBtoEBtYAYgQE7gQEDgQHqgQHGgQEagKOBAb2A6oDfgJSAz4Da |
|
3240 | 6YBugOCAaoCwgAeAxIEBFoEB2IBygQEmgK+BAQuA1oEBRIEBX4D8gQHVgQEHgNqAGIEBfoACgQFvgQHq | |
3241 | gGqA7oCLgQGtgQEUgQHLgL2BAdCBAe6BAV+AcoEBsYEBFYCWgP2A1IEB0YDlgFiBAXaA2YEB14EBvIDg |
|
3241 | gQHlgQExgL2BAVCBAe6BAQKAw4C+gNCA7oEBuIEB4YD9gQHOgQE+gPKAlIEBvIEByYEB5oEB3oBYgQG0 | |
3242 | gI6AyIAQgQHVgQEHgQE/gQEjgBSBAVWBATaAAoEB3IEBsoEBSYDDgQHggL6BAVqA74D0gM6BAU6Ag4AH |
|
3242 | gO2BATqAo4EBG4DVgQFjgQF5gHSBAc2Az4EB2oCLgFSBASGBAUuBAfCBAXSAfIEBs4EBWYEBw4EBEIEB | |
3243 | gFSBAcqBAbmBAVCAyYEBydIADgA+BgAJFoEBh68QaAkXCRgJGQkaCRsJHAkdCR4JHwkgCSEJIgkjCSQJ |
|
3243 | a4EBIIAUgQHRgJaBAdKBAaKBAWeBAbqBAeSBARHSAA4APgYACRaBAYevEGgJFwkYCRkJGgkbCRwJHQke | |
3244 | JQkmCScJKAkpCSoJKwksCS0JLgkvCTAJMQkyCTMJNAk1CTYJNwk4CTkJOgk7CTwFDgk+CT8JQAlBCUIJ |
|
3244 | CR8JIAkhCSIJIwkkCSUJJgknCSgJKQkqCSsJLAktCS4JLwkwCTEJMgkzCTQJNQk2CTcJOAk5CToJOwk8 | |
3245 | QwlECUUJRglHCUgJSQlKCUsJTAlNCU4JTwlQCVEJUglTCVQJVQlWCVcJWAlZCVoJWwlcCV0JXglfCWAJ |
|
3245 | CT0JPgk/CUAJQQlCCUMJRAlFCUYJRwlICUkJSglLCUwJTQlOCU8JUAlRCVIEWQlUCVUJVglXCVgJWQla | |
3246 | YQliCWMJZAllCWYJZwloCWkJaglrCWwJbQluCW8JcAlxCXIJcwl0CXUJdgl3CXgJeQl6CXsJfAl9CX6B |
|
3246 | CVsJXAldCV4JXwlgCWEJYgljCWQJZQlmCWcJaAlpCWoJawlsCW0JbglvCXAJcQlyCXMJdAl1CXYJdwl4 | |
3247 | AfiBAfmBAfqBAfuBAfyBAf2BAf6BAf+BAgCBAgGBAgKBAgOBAgSBAgWBAgaBAgeBAgiBAgmBAgqBAguB |
|
3247 | CXkJegl7CXwJfQl+gQH4gQH5gQH6gQH7gQH8gQH9gQH+gQH/gQIAgQIBgQICgQIDgQIEgQIFgQIGgQIH | |
3248 | AgyBAg2BAg6BAg+BAhCBAhGBAhKBAhOBAhSBAhWBAhaBAheBAhiBAhmBAhqBAhuBAhyBAh2BATyBAh6B |
|
3248 | gQIIgQIJgQIKgQILgQIMgQINgQIOgQIPgQIQgQIRgQISgQITgQIUgQIVgQIWgQIXgQIYgQIZgQIagQIb | |
3249 | Ah+BAiCBAiGBAiKBAiOBAiSBAiWBAiaBAieBAiiBAimBAiqBAiuBAiyBAi2BAi6BAi+BAjCBAjGBAjKB |
|
3249 | gQIcgQIdgQIegQIfgQIggQIhgQIigQIjgQIkgQIlgQImgQIngQIogQIpgQIqgQIrgQIsgQItgQIugQIv | |
3250 |
|
|
3250 | gQIwgQIxgQIygQIzgP6BAjSBAjWBAjaBAjeBAjiBAjmBAjqBAjuBAjyBAj2BAj6BAj+BAkCBAkGBAkKB | |
3251 |
AkeBAkiBAkmBAkqBAkuBAkyBAk2BAk6BAk+BAlCBAlGBAlKBAlOBAlSBAlWBAla |
|
3251 | AkOBAkSBAkWBAkaBAkeBAkiBAkmBAkqBAkuBAkyBAk2BAk6BAk+BAlCBAlGBAlKBAlOBAlSBAlWBAlaB | |
3252 | AluBAlyBAl2BAl5fEBhNZW51IEl0ZW0gKFNtYXJ0IFF1b3RlcylfEBJNZW51IEl0ZW0gKFNwZWVjaClR |
|
3252 | AleBAliBAlmBAlqBAluBAlyBAl2BAl5aU3BsaXQgVmlld1tTZXBhcmF0b3ItM28QEQBNAGUAbgB1ACAA | |
3253 | OF8QEVRhYmxlIEhlYWRlciBWaWV3XxAXVGFibGUgQ29sdW1uIChWYXJpYWJsZSlfEBdNZW51IEl0ZW0g |
|
3253 | SQB0AGUAbQAgACgARgBpAG4AZCAmAClfEBJNZW51IEl0ZW0gKERlbGV0ZSlfEBJNZW51IEl0ZW0gKEZv | |
3254 | KE9wZW4gUmVjZW50KV8QIU1lbnUgSXRlbSAoQWJvdXQgSVB5dGhvbjFTYW5kYm94KV8QEk1lbnUgSXRl |
|
3254 | cm1hdClfEBtUZXh0IEZpZWxkIENlbGwgKFRleHQgQ2VsbClfEBJNZW51IChPcGVuIFJlY2VudClfEBdN | |
3255 | bSAoRGVsZXRlKV8QEE1lbnUgSXRlbSAoQ29weSlfEBJNZW51IChPcGVuIFJlY2VudClRNl8QGU1lbnUg |
|
3255 | ZW51IEl0ZW0gKE9wZW4gUmVjZW50KV8QHVRleHQgRmllbGQgQ2VsbCAoVGV4dCBDZWxsKS0xXxAgTWVu | |
3256 | SXRlbSAoU3Vic3RpdHV0aW9ucylvEBoATQBlAG4AdQAgAEkAdABlAG0AIAAoAFMAaABvAHcAIABTAHAA |
|
3256 | dSBJdGVtIChTcGVsbGluZyBhbmQgR3JhbW1hcilfEBBNZW51IEl0ZW0gKEVkaXQpXxAQTWVudSBJdGVt | |
3257 | ZQBsAGwAaQBuAGcgJgApXxAnTWVudSBJdGVtIChDaGVjayBHcmFtbWFyIFdpdGggU3BlbGxpbmcpXxAY |
|
3257 | IChDb3B5KVlTZXBhcmF0b3JYTWFpbk1lbnVfEBlNZW51IEl0ZW0gKFN1YnN0aXR1dGlvbnMpXENvbnRl | |
3258 | TWVudSBJdGVtIChTaG93IFRvb2xiYXIpWE1haW5NZW51XU1lbnUgKFdpbmRvdylROV8QD01lbnUgSXRl |
|
3258 | bnQgVmlld1EzXUJveCAoQ29uc29sZSlRMl8QFE1lbnUgKFN1YnN0aXR1dGlvbnMpXxAWTWVudSBJdGVt | |
3259 | bSAoQ3V0KVExW1Njcm9sbCBWaWV3XxAUTWVudSAoU3Vic3RpdHV0aW9ucylfECJNZW51IEl0ZW0gKFVz |
|
3259 | IChTZWxlY3QgQWxsKV8QGU1lbnUgSXRlbSAoU3RvcCBTcGVha2luZylfEBdNZW51IEl0ZW0gKFNtYXJ0 | |
3260 | ZSBTZWxlY3Rpb24gZm9yIEZpbmQpVDExMTFfEBBNZW51IEl0ZW0gKEZpbGUpW1NlcGFyYXRvci01XxAg |
|
3260 | IExpbmtzKV8QJ01lbnUgSXRlbSAoQ2hlY2sgR3JhbW1hciBXaXRoIFNwZWxsaW5nKV1TY3JvbGwgVmll | |
3261 | TWVudSBJdGVtIChIaWRlIElQeXRob24xU2FuZGJveClfEBBNZW51IEl0ZW0gKFZpZXcpXxAWTWVudSBJ |
|
3261 | dy0xXxAnTWVudSBJdGVtIChDaGVjayBTcGVsbGluZyBXaGlsZSBUeXBpbmcpXxAPQm94IChXb3Jrc3Bh | |
3262 | dGVtIChTaG93IEZvbnRzKVxDb250ZW50IFZpZXdfEBlVc2VyIE5hbWVzcGFjZSBDb250cm9sbGVyWlNw |
|
3262 | Y2UpXxAWTWVudSAoSVB5dGhvbjFTYW5kYm94KV8QGVdpbmRvdyAoSVB5dGhvbjEgKENvY29hKSlbTWVu | |
3263 | bGl0IFZpZXdfECBNZW51IEl0ZW0gKElQeXRob24xU2FuZGJveCBIZWxwKVMxLTFRNV8QFE1lbnUgSXRl |
|
3263 | dSAoRmlsZSlfEBBNZW51IEl0ZW0gKFVuZG8pW1NlcGFyYXRvci00XxAcVGFibGUgVmlldyAoVmFyaWFi | |
3264 | bSAoU2VydmljZXMpW1NlcGFyYXRvci0xWVRleHQgVmlld18QHk1lbnUgSXRlbSAoQnJpbmcgQWxsIHRv |
|
3264 | bGUsIFZhbHVlKV8QF01lbnUgSXRlbSAoSGlkZSBPdGhlcnMpXxAUTWVudSBJdGVtIChTaG93IEFsbClU | |
3265 | IEZyb250KV8QEk1lbnUgSXRlbSAoV2luZG93KW8QEQBNAGUAbgB1ACAASQB0AGUAbQAgACgATwBwAGUA |
|
3265 | MTExMV1NZW51IChTcGVlY2gpXxARTWVudSBJdGVtIChQYXN0ZSlfEB5NZW51IEl0ZW0gKEJyaW5nIEFs | |
3266 | biAmAClfEBZNZW51IEl0ZW0gKFNlbGVjdCBBbGwpXEFzeW5jIEFycm93c1tTZXBhcmF0b3ItMm8QEQBN |
|
3266 | bCB0byBGcm9udClbQXBwbGljYXRpb25fEA9NZW51IChTZXJ2aWNlcylfEBdQeXRob24gQ29jb2EgQ29u | |
3267 | AGUAbgB1ACAASQB0AGUAbQAgACgARgBpAG4AZCAmAClfEBdNZW51IEl0ZW0gKFNob3cgQ29sb3JzKV8Q |
|
3267 | dHJvbGxlcl8QIE1lbnUgSXRlbSAoSVB5dGhvbjFTYW5kYm94IEhlbHApWVRleHQgVmlld18QGVVzZXIg | |
3268 | EVZlcnRpY2FsIFNjcm9sbGVyW01lbnUgKEVkaXQpXxAWTWVudSAoSVB5dGhvbjFTYW5kYm94KV8QD0Jv |
|
3268 | TmFtZXNwYWNlIENvbnRyb2xsZXJcRmlsZSdzIE93bmVyUThfEBJNZW51IEl0ZW0gKFdpbmRvdylTMi0x | |
3269 | eCAoV29ya3NwYWNlKV8QGU1lbnUgSXRlbSAoU3RvcCBTcGVha2luZylfEBRUYWJsZSBDb2x1bW4gKFZh |
|
3269 | W01lbnUgKEZpbmQpXxAaTWVudSBJdGVtIChDaGVjayBTcGVsbGluZylfEBZNZW51IEl0ZW0gKENsZWFy | |
3270 | bHVlKV8QG01lbnUgSXRlbSAoSVB5dGhvbjFTYW5kYm94KV8QGk1lbnUgSXRlbSAoQ2hlY2sgU3BlbGxp |
|
3270 | IE1lbnUpW1NlcGFyYXRvci0yXxAYTWVudSBJdGVtIChTbWFydCBRdW90ZXMpUTZfEBtNZW51IChTcGVs | |
3271 | bmcpXxAQTWVudSBJdGVtIChFZGl0KV8QHU1lbnUgSXRlbSAoSnVtcCB0byBTZWxlY3Rpb24pW1NlcGFy |
|
3271 | bGluZyBhbmQgR3JhbW1hcilbTWVudSAoRWRpdClbTWVudSAoVmlldylfEBVNZW51IEl0ZW0gKEZpbmQg | |
3272 | YXRvci02WVNlcGFyYXRvcm8QHgBNAGUAbgB1ACAASQB0AGUAbQAgACgAQwB1AHMAdABvAG0AaQB6AGUA |
|
3272 | TmV4dClvEBEATQBlAG4AdQAgAEkAdABlAG0AIAAoAE8AcABlAG4gJgApUzEyMVE1XxAYTWVudSBJdGVt | |
3273 | IABUAG8AbwBsAGIAYQByICYAKV8QHFRhYmxlIFZpZXcgKFZhcmlhYmxlLCBWYWx1ZSlbU2VwYXJhdG9y |
|
3273 | IChTaG93IFRvb2xiYXIpXxATVmVydGljYWwgU2Nyb2xsZXItMV8QIk1lbnUgSXRlbSAoVXNlIFNlbGVj | |
3274 | LTNfEBtNZW51IChTcGVsbGluZyBhbmQgR3JhbW1hcilfEBNIb3Jpem9udGFsIFNjcm9sbGVyXxAUTWVu |
|
3274 | dGlvbiBmb3IgRmluZClfEBtNZW51IEl0ZW0gKElQeXRob24xU2FuZGJveClfEBBNZW51IEl0ZW0gKFZp | |
3275 | dSBJdGVtIChNaW5pbWl6ZSlfEBBNZW51IEl0ZW0gKFJlZG8pXxAQTWVudSBJdGVtIChGaW5kKV8QEU1l |
|
3275 | ZXcpUTlfEBNIb3Jpem9udGFsIFNjcm9sbGVyXxAQTWVudSBJdGVtIChGaW5kKW8QHgBNAGUAbgB1ACAA | |
3276 | bnUgSXRlbSAoUGFzdGUpXxAVSG9yaXpvbnRhbCBTY3JvbGxlci0xUjEwXxAXTWVudSBJdGVtIChIaWRl |
|
3276 | SQB0AGUAbQAgACgAQwB1AHMAdABvAG0AaQB6AGUAIABUAG8AbwBsAGIAYQByICYAKV8QIU1lbnUgSXRl | |
3277 | IE90aGVycylfEBlNZW51IEl0ZW0gKEZpbmQgUHJldmlvdXMpW1NlcGFyYXRvci00XU1lbnUgKEZvcm1h |
|
3277 | bSAoQWJvdXQgSVB5dGhvbjFTYW5kYm94KVxBc3luYyBBcnJvd3NvEBoATQBlAG4AdQAgAEkAdABlAG0A | |
3278 | dClfEB1UZXh0IEZpZWxkIENlbGwgKFRleHQgQ2VsbCktMVEzXUJveCAoQ29uc29sZSlfEBVNZW51IEl0 |
|
3278 | IAAoAFMAaABvAHcAIABTAHAAZQBsAGwAaQBuAGcgJgApXxAaTWVudSBJdGVtIChTdGFydCBTcGVha2lu | |
3279 | ZW0gKEZpbmQgTmV4dClfEBRNZW51IEl0ZW0gKFNob3cgQWxsKV8QEE1lbnUgSXRlbSAoWm9vbSlfECdN |
|
3279 | ZylfECBNZW51IEl0ZW0gKEhpZGUgSVB5dGhvbjFTYW5kYm94KVMxLTFfEBFUYWJsZSBIZWFkZXIgVmll | |
3280 | ZW51IEl0ZW0gKENoZWNrIFNwZWxsaW5nIFdoaWxlIFR5cGluZyldU2Nyb2xsIFZpZXctMVEyXxAXTWVu |
|
3280 | d1tTZXBhcmF0b3ItNV8QEE1lbnUgSXRlbSAoUmVkbylfEBBNZW51IEl0ZW0gKEZpbGUpXxAUVGFibGUg | |
3281 | dSBJdGVtIChTbWFydCBMaW5rcylcRmlsZSdzIE93bmVyXxAgTWVudSBJdGVtIChTcGVsbGluZyBhbmQg |
|
3281 | Q29sdW1uIChWYWx1ZSlfEBFWZXJ0aWNhbCBTY3JvbGxlcl1NZW51IChGb3JtYXQpXxAdTWVudSBJdGVt | |
3282 | R3JhbW1hcilTMTIxW01lbnUgKFZpZXcpXxAcTWVudSBJdGVtIChTbWFydCBDb3B5L1Bhc3RlKV8QEk1l |
|
3282 | IChKdW1wIHRvIFNlbGVjdGlvbilRMV8QD01lbnUgSXRlbSAoQ3V0KV8QF1RhYmxlIENvbHVtbiAoVmFy | |
3283 | bnUgSXRlbSAoRm9ybWF0KVtNZW51IChGaW5kKV8QFk1lbnUgSXRlbSAoQ2xlYXIgTWVudSldTWVudSAo |
|
3283 | aWFibGUpW1NlcGFyYXRvci0xUjEwXxASTWVudSBJdGVtIChTcGVlY2gpXxAUTWVudSBJdGVtIChNaW5p | |
3284 | U3BlZWNoKV8QF1B5dGhvbiBDb2NvYSBDb250cm9sbGVyXxAQTWVudSBJdGVtIChVbmRvKVtBcHBsaWNh |
|
3284 | bWl6ZSlfEBxNZW51IEl0ZW0gKFNtYXJ0IENvcHkvUGFzdGUpXxAXTWVudSBJdGVtIChTaG93IENvbG9y | |
3285 | dGlvbl8QG1RleHQgRmllbGQgQ2VsbCAoVGV4dCBDZWxsKV8QGVdpbmRvdyAoSVB5dGhvbjEgKENvY29h |
|
3285 | cylbU2Nyb2xsIFZpZXdbU2VwYXJhdG9yLTZfEBVIb3Jpem9udGFsIFNjcm9sbGVyLTFfEBRNZW51IEl0 | |
3286 | KSlfEBNWZXJ0aWNhbCBTY3JvbGxlci0xUzItMV8QD01lbnUgKFNlcnZpY2VzKV8QGk1lbnUgSXRlbSAo |
|
3286 | ZW0gKFNlcnZpY2VzKV8QFk1lbnUgSXRlbSAoU2hvdyBGb250cylfEBBNZW51IEl0ZW0gKFpvb20pXxAZ | |
3287 | U3RhcnQgU3BlYWtpbmcpW01lbnUgKEZpbGUpUTfSAA4APgYACeiBAYeg0gAOAD4GAAnrgQGHoNIADgA+ |
|
3287 | TWVudSBJdGVtIChGaW5kIFByZXZpb3VzKVE3XU1lbnUgKFdpbmRvdynSAA4APgYACeiBAYeg0gAOAD4G | |
3288 | BgAJ7oEBh68QlwNUA1sGRwNBA0kE3wJEAnUGSwSKBEEFIAVvA0IGUATRA0QDMgNOBbADMQNRA0sFywM+ |
|
3288 | AAnrgQGHoNIADgA+BgAJ7oEBh68QlwZGAGsDUATkBVoGSgM8Az8CwAVQBk0DLQNHA1UCgwNEBk8GUAMr | |
3289 | AzoGVARWBS4GVwNNBYYGWQMwAgoDbQZcBO0GXgZfAzkDOAS3AywDTAZhBmIDLwBNBdsDQAM0AGsFVQR7 |
|
3289 | A08E1gZSAygDSAZTBlQEQgBNAH4D8AO7BAcE9gOxA0kEFQP6AgoAfwNsBJoGYwOnAEECKgTIA0EDWwNG | |
3290 | BaAGaQZqAMgDKwUKBGEGbgSpBnAAbANHBnIEFQP1AhoDyAB/A+oCdgQiAz8GewSXBn0DjgZ/A0oDVgaA |
|
3290 | BHkD3wNKBSYFegRSAzQDTgNUA1EDMgM3A00GbgRvA+gAyAXeAB8FrgZ0BOwDjQVIBngDMQM6BnkEYQOf | |
3291 | A1UFeQIqA0MGgwSfAhADKgROA9IGiAQHAKoDOwNIBb4D4QaNAzYDPAaOA0UD/QMoAsADrgMzAH4GkwRu |
|
3291 | AzsDlQPNAzkGfgQqAykGgARRBoIFEQQzAhoDOANFAyoGhgMwBocGiAaJAKoGiwQiAywFBASoA9cAbAWH | |
3292 | BRMExACjA1IDKQVdBPsAHwaaBpsDoAU2A5YGnwMuBWcDUAQqA8AENANGBUEDNQKDA08AQQCxBqgGqQM3 |
|
3292 | A0wFygM2AkQGlAPFBpYCdgNCAzMDLgCxBToEvgabBbwCdQaeBWcGoAM1Az0EhwNLBaEEtgM+AKMDUgal | |
3293 | Az0DUwMtBUgDtgasgQGQgK+BAZyBATWBAVmBASyAdIB8gQGhgQEQgPmBAUOBAVuBATqBAaaBASeBAUKA |
|
3293 | AhADVganBqgDQANDBZQGqgMvA1MGqwSPgQGcgA6BAXOBATCBAVWBAZ2BAR+BAS+AjoEBUYEBqIDUgQFP | |
3294 | 7YEBa4EBcYDpgQF5gQFigQF6gQEmgQETgQGqgP6BAUiBAcOBAWmBAWOBAfCA5IBugLCBAdmBATGBAb+B |
|
3294 | gQGUgIOBAUOBAaqBAa6AyIEBboEBK4EBsoCugQFUgQGegQG/gPeAC4AQgNuAyoDkgQE2gMmBAViA6YDg | |
3295 | Ac+BAQ+BAQqBAR+AzYEBZ4EB5oEB5IDegAuBAX6BATCA+IAOgQFUgQELgQFsgQG2gQG1gBiAx4EBO4EB |
|
3295 | gG6AaoCwgQEWgQHYgMSAB4BygQEmgQE5gK+BAUqBAQuA1oEBXIEBRIEBX4D8gPaBAWqBAZGBAXiA7IEB | |
3296 | A4EB6oEBGoEBxoCjgQFPgQG9gOqA34CUgM+AaoDagIuA7oEBK4EBrYEBFIEBy4C9gQHQgQFegQGXgQHu |
|
3296 | BoEBZoEB1YEBB4DagBiBAX6AAoEBb4EB6oEBMYC9gQFQgQHlgOiBARWBAe6BAQKAw4EBGoC+gNCBAQ+B | |
3297 | gQGTgQFfgHKBAT6BAbGBARWAloDCgP2A1IEB0YDlgFiBARmBAVOBAXaA2YEB14EBAoEBHoEBvIEBR4Dg |
|
3297 | AbiA7oC8gQHhgP2BAc6BAT6A8oCUgQEKgQFIgMKBAbyA44EByYEB3oEB5oBYgQG0gO2AzoEBOoEBG4DV | |
3298 | gK6AjoDIgPOAEIEB1YEBB4EBP4EBI4AUgQF9gLyBAVWBATaAAoEB3IEBsoDDgQFJgL6BAeCA2IEBWoEB |
|
3298 | gKOBAWOBAWKBAXmBAQGAdIEBzYDPgQHagIuBAT2A8YDZgFSBAUuBASGBAfCBAXSAfIEBs4EBWYEBw4D7 | |
3299 | dYDvgM6A9IEBTYEBToD8gIOBAXCAB4BUgQG5gQHKgQEGgQEigQGMgNOBAVCAyYEBydIADgA+BgAKiIEB |
|
3299 | gQElgQEQgQFegQFrgQEggQEqgBSBAX2BAdGAloEBl4EB0oEBooEBNYEBQoEBZ4EBuoDfgQGNgQHkgQER | |
3300 | h68QlwqJCooKiwqMCo0KjgqPCpAKkQqSCpMKlAqVCpYKlwqYCpkKmgqbCpwKnQqeCp8KoAqhCqIKowqk |
|
3300 | 0gAOAD4GAAqIgQGHrxCXCokKigqLCowKjQqOCo8KkAqRCpIKkwqUCpUKlgqXCpgKmQqaCpsKnAqdCp4K | |
3301 | CqUKpgqnCqgKqQqqCqsKrAqtCq4KrwqwCrEKsgqzCrQKtQq2CrcKuAq5CroKuwq8Cr0Kvgq/CsAKwQrC |
|
3301 | nwqgCqEKogqjCqQKpQqmCqcKqAqpCqoKqwqsCq0KrgqvCrAKsQqyCrMKtAq1CrYKtwq4CrkKugq7CrwK | |
3302 | CsMKxArFCsYKxwrICskKygrLCswKzQrOCs8K0ArRCtIK0wrUCtUK1grXCtgK2QraCtsK3ArdCt4K3wrg |
|
3302 | vQq+Cr8KwArBCsIKwwrECsUKxgrHCsgKyQrKCssKzArNCs4KzwrQCtEK0grTCtQK1QrWCtcK2ArZCtoK | |
3303 | CuEK4grjCuQK5QrmCucK6ArpCuoK6wrsCu0K7grvCvAK8QryCvMK9Ar1CvYK9wr4CvkK+gr7CvwK/Qr+ |
|
3303 | 2wrcCt0K3grfCuAK4QriCuMK5ArlCuYK5wroCukK6grrCuwK7QruCu8K8ArxCvIK8wr0CvUK9gr3CvgK | |
3304 | Cv8LAAsBCwILAwsECwULBgsHCwgLCQsKCwsLDAsNCw4LDwsQCxELEgsTCxQLFQsWCxcLGAsZCxoLGwsc |
|
3304 | +Qr6CvsK/Ar9Cv4K/wsACwELAgsDCwQLBQsGCwcLCAsJCwoLCwsMCw0LDgsPCxALEQsSCxMLFAsVCxYL | |
3305 | Cx0LHgsfgQJjgQJkgQJlgQJmgQJngQJogQJpgQJqgQJrgQJsgQJtgQJugQJvgQJwgQJxgQJygQJzgQJ0 |
|
3305 | FwsYCxkLGgsbCxwLHQseCx+BAmOBAmSBAmWBAmaBAmeBAmiBAmmBAmqBAmuBAmyBAm2BAm6BAm+BAnCB | |
3306 | gQJ1gQJ2gQJ3gQJ4gQJ5gQJ6gQJ7gQJ8gQJ9gQJ+gQJ/gQKAgQKBgQKCgQKDgQKEgQKFgQKGgQKHgQKI |
|
3306 | AnGBAnKBAnOBAnSBAnWBAnaBAneBAniBAnmBAnqBAnuBAnyBAn2BAn6BAn+BAoCBAoGBAoKBAoOBAoSB | |
3307 | gQKJgQKKgQKLgQKMgQKNgQKOgQKPgQKQgQKRgQKSgQKTgQKUgQKVgQKWgQKXgQKYgQKZgQKagQKbgQKc |
|
3307 | AoWBAoaBAoeBAoiBAomBAoqBAouBAoyBAo2BAo6BAo+BApCBApGBApKBApOBApSBApWBApaBApeBApiB | |
3308 | gQKdgQKegQKfgQKggQKhgQKigQKjgQKkgQKlgQKmgQKngQKogQKpgQKqgQKrgQKsgQKtgQKugQKvgQKw |
|
3308 | ApmBApqBApuBApyBAp2BAp6BAp+BAqCBAqGBAqKBAqOBAqSBAqWBAqaBAqeBAqiBAqmBAqqBAquBAqyB | |
3309 | gQKxgQKygQKzgQK0gQK1gQK2gQK3gQK4gQK5gQK6gQK7gQK8gQK9gQK+gQK/gQLAgQLBgQLCgQLDgQLE |
|
3309 | Aq2BAq6BAq+BArCBArGBArKBArOBArSBArWBAraBAreBAriBArmBArqBAruBAryBAr2BAr6BAr+BAsCB | |
3310 | gQLFgQLGgQLHgQLIgQLJgQLKgQLLgQLMgQLNgQLOgQLPgQLQgQLRgQLSgQLTgQLUgQLVgQLWgQLXgQLY |
|
3310 | AsGBAsKBAsOBAsSBAsWBAsaBAseBAsiBAsmBAsqBAsuBAsyBAs2BAs6BAs+BAtCBAtGBAtKBAtOBAtSB | |
3311 | gQLZgQLagQLbgQLcgQLdgQLegQLfgQLggQLhgQLigQLjgQLkgQLlgQLmgQLngQLogQLpgQLqgQLrgQLs |
|
3311 | AtWBAtaBAteBAtiBAtmBAtqBAtuBAtyBAt2BAt6BAt+BAuCBAuGBAuKBAuOBAuSBAuWBAuaBAueBAuiB | |
3312 | gQLtgQLugQLvgQLwgQLxgQLygQLzgQL0gQL1gQL2gQL3gQL4gQL5EQGrEQFfENMRAWUQfxBQEQGYEQGc |
|
3312 | AumBAuqBAuuBAuyBAu2BAu6BAu+BAvCBAvGBAvKBAvOBAvSBAvWBAvaBAveBAviBAvkQkBEBpRDkENEQ | |
3313 | EHwQOhDKEMUQfREBuREBXBBOEOAQ4xBXEMwQ8REBWxDkEQFaEFYQ4RAdEBgRASkQUhEBvRDHEGcQ4hEB |
|
3313 | yhEBKxEBaRDxEQGeEH0QfBDpEH8RAawRAZ8Q4hDYENkRAWURAWsQxRDOEQFyEOsQHREBXBBLEQF0EQGk | |
3314 | lxEBXRDdEIgQUxDOEI4QwRCGEN8RAbwRAScRAVgRAWkRAXQRAYERAXEQ6xEBpRBvEEkQTRCDEI8RAaMR |
|
3314 | EGoRAV0QxhDDEQFiEQFsEQFaENsRAZcRAZYQORDPEJUQUREBcxEBmxCREI4QlhD1EIgQ1BEBvBDLEAUT | |
3315 | AWoRAXUQBRATEMYQSBEBtBDpEJUQ0REBWREBmRDNEQGWEDkRAZ0QwxEBaxA4EMkQ2RDSENYRAW0RAbUQ |
|
3315 | //////////0RAWoRAWMRAasQwREBbREBuRDwEIIRAaYQbxEBoxEBgREBvhBQEBMQ3BDJEH4QShEBWxDf | |
3316 | XBEBuBEBKhEBmxDwEOwQyBEBmhEBYxAXENcQ2hDLEQGiEOgRAWgQcBCRENUQJxEBbxCQEQFuEQEsEQFk |
|
3316 | EFwRAV8QThDmEMgQzRAlENARASgQ4RBIEQF1EIEQTREBKREBmREBcREBvRBWEN0Q6BA4EFIRAScRAaIQ | |
3317 | EQGeEEsRAa0RAaQQ0BCWEO8Q2xEBoBEBrBD1EGoRAWIRAb4Q2BCBEQFeEQEoENwRASsRAXAQfhEBbBDU |
|
3317 | 2hEBKhDnEDoQzBDEEQG0EIYRAW8QSREBZBEBmBDsENcQUxEBnRBXEQFuEQFoEQGhENIRASwQZxDHEQGc | |
3318 | EM8RAaYRAXYT//////////0QJREBnxDmEQFzEQGhEIIQShEBchDeEQGoEOcQxBBREE/SAA4APgBpC7mA |
|
3318 | ENYQcBDTEQF2EQFwEBcQJxEBXhEBWRDgEQGgEQG4EI8RAZoRAbUQgxEBWBDjEQGtEO8Q1RDeEQGoEE8Q | |
3319 | NKDSAA4APgYAC7yBAYeg0gAOAD4GAAu/gQGHoNIANwA4C8ELwqILwgA7Xk5TSUJPYmplY3REYXRhAAgA |
|
3319 | GNIADgA+AGkLuYA0oNIADgA+BgALvIEBh6DSAA4APgYAC7+BAYeg0gA3ADgLwQvCogvCADteTlNJQk9i | |
3320 | GQAiACcAMQA6AD8ARABSAFQAZgZmBmwGtwa+BsUG0wblBwEHDwcbBycHNQdAB04Hagd4B4sHnQe3B8EH |
|
3320 | amVjdERhdGEACAAZACIAJwAxADoAPwBEAFIAVABmBmYGbAa3Br4GxQbTBuUHAQcPBxsHJwc1B0AHTgdq | |
3321 | zgfQB9MH1gfZB9wH3gfhB+MH5gfpB+wH7wfxB/MH9gf5B/wH/wgICBQIFggYCCYILwg4CEMISAhXCGAI |
|
3321 | B3gHiwedB7cHwQfOB9AH0wfWB9kH3AfeB+EH4wfmB+kH7AfvB/EH8wf2B/kH/Af/CAgIFAgWCBgIJggv | |
3322 | cwh8CIcIiQiMCI4IuwjICNUI6wj5CQMJEQkeCTAJRAlQCVIJVAlWCVgJWglfCWEJYwllCWcJaQmECZcJ |
|
3322 | CDgIQwhICFcIYAhzCHwIhwiJCIwIjgi7CMgI1QjrCPkJAwkRCR4JMAlECVAJUglUCVYJWAlaCV8JYQlj | |
3323 | oAm9Cc8J2gnjCe8J+wn9Cf8KAQoECgYKCAoKChMKFQoaChwKHgpHCk8KXgptCnoKfAp+CoAKggqFCocK |
|
3323 | CWUJZwlpCYQJlwmgCb0JzwnaCeMJ7wn7Cf0J/woBCgQKBgoICgoKEwoVChoKHAoeCkcKTwpeCm0Kegp8 | |
3324 | iQqLCowKlQqXCpwKngqgCtkK4wrvCv0LCgsUCyYLNAs2CzgLOgs8Cz0LPwtBC0MLRQtHC0kLSwtNC1YL |
|
3324 | Cn4KgAqCCoUKhwqJCosKjAqVCpcKnAqeCqAK2QrjCu8K/QsKCxQLJgs0CzYLOAs6CzwLPQs/C0ELQwtF | |
3325 | WAtbC10Legt8C34LgAuCC4QLhguPC5ELlAuWC8cL0wvcC+gL9gv4C/oL/Av+DAEMAwwFDAcMCQwLDA0M |
|
3325 | C0cLSQtLC00LVgtYC1sLXQt6C3wLfguAC4ILhAuGC48LkQuUC5YLxwvTC9wL6Av2C/gL+gv8C/4MAQwD | |
3326 | FgwYDB8MIQwjDCUMWgxjDGwMdgyADIoMjAyODJAMkgyUDJYMmAybDJ0MnwyhDKMMpQyuDLAMswy1DOoM |
|
3326 | DAUMBwwJDAsMDQwWDBgMHwwhDCMMJQxaDGMMbAx2DIAMigyMDI4MkAySDJQMlgyYDJsMnQyfDKEMowyl | |
3327 | /A0GDRMNHw0pDTINPQ0/DUENQw1FDUcNSQ1LDU4NUA1SDVQNVg1YDWENYw2IDYoNjA2ODZANkg2UDZYN |
|
3327 | DK4MsAyzDLUM6gz8DQYNEw0fDSkNMg09DT8NQQ1DDUUNRw1JDUsNTg1QDVINVA1WDVgNYQ1jDYgNig2M | |
3328 | mA2aDZwNng2gDaINpA2mDagNqg3GDdsN+A4ZDjUOWw6BDp8Ouw7XDvQPDA8mD1oPdw+TD8APyQ/QD90P |
|
3328 | DY4NkA2SDZQNlg2YDZoNnA2eDaANog2kDaYNqA2qDcYN2w34DhkONQ5bDoEOnw67DtcO9A8MDyYPWg93 | |
3329 | 4w/6EA8QGRAkECwQPhBAEEIQSxBNEGIQdRCDEI0QjxCREJMQlRCiEKsQrRCvELEQuhDEEMYQxxDQENcQ |
|
3329 | D5MPwA/JD9AP3Q/jD/oQDxAZECQQLBA+EEAQQhBLEE0QYhB1EIMQjRCPEJEQkxCVEKIQqxCtEK8QsRC6 | |
3330 | 6RDyEPsRFxEsETURNxE6ETwRRRFMEVsRYxFsEXERehF/EaARqBHCEdUR6RIAEhUSKBIqEi8SMRIzEjUS |
|
3330 | EMQQxhDHENAQ1xDpEPIQ+xEXESwRNRE3EToRPBFFEUwRWxFjEWwRcRF6EX8RoBGoEcIR1RHpEgASFRIo | |
3331 | NxI5EjsSSBJVElsSXRJ4EoEShhKOEpsSoxKlEqcSqhK3Er8SwRLGEsgSyhLPEtES0xLoEvQTAhMEEwYT |
|
3331 | EioSLxIxEjMSNRI3EjkSOxJIElUSWxJdEngSgRKGEo4SmxKjEqUSpxKqErcSvxLBEsYSyBLKEs8S0RLT | |
3332 | CBMKExETLxM8Ez4TShNfE2ETYxNlE2cTexOEE4kTlhOjE6UTqhOsE64TsxO1E7cTwxPQE9IT2RPiE+cT |
|
3332 | EugS9BMCEwQTBhMIEwoTERMvEzwTPhNKE18TYRNjE2UTZxN7E4QTiROWE6MTpROqE6wTrhOzE7UTtxPD | |
3333 | /hQLFBMUHBQnFC4UNRRBFFgUcBR9FH8UghSPFJkUphSoFKoUshS7FMAUyRTSFN0VAhULFRQVHhUgFSIV |
|
3333 | E9AT0hPZE+IT5xP+FAsUExQcFCcULhQ1FEEUWBRwFH0UfxSCFI8UmRSmFKgUqhSyFLsUwBTJFNIU3RUC | |
3334 | JBUmFS8VMRUzFTUVPhVWFWMVbBV3FYIVjBW5FcQVxhXIFcoVzBXOFdAV0hXbFeQV/xYYFiEWKhY3Fk4W |
|
3334 | FQsVFBUeFSAVIhUkFSYVLxUxFTMVNRU+FVYVYxVsFXcVghWMFbkVxBXGFcgVyhXMFc4V0BXSFdsV5BX/ | |
3335 | VxZeFmkWcBaNFpkWpBauFrsWxxbMFs4W0BbSFtQW1hbeFu8W9hb9FwYXCBcRFxMXFhcjFywXMRc4F00X |
|
3335 | FhgWIRYqFjcWThZXFl4WaRZwFo0WmRakFq4WuxbHFswWzhbQFtIW1BbWFt4W7xb2Fv0XBhcIFxEXExcW | |
3336 | TxdRF1MXVRdrF3gXeheIF5EXmhesF7kXwBfJF9IX2BgRGBMYFRgXGBkYGhgcGB4YIBgiGCQYJhgvGDEY |
|
3336 | FyMXLBcxFzgXTRdPF1EXUxdVF2sXeBd6F4gXkReaF6wXuRfAF8kX0hfYGBEYExgVGBcYGRgaGBwYHhgg | |
3337 | NBg2GFMYVRhXGFkYWxhdGF8YaBhqGG0YbxiuGLsYzhjbGN0Y3xjhGOMY5RjnGOkY6xj+GQAZAhkEGQYZ |
|
3337 | GCIYJBgmGC8YMRg0GDYYUxhVGFcYWRhbGF0YXxhoGGoYbRhvGK4YuxjOGNsY3RjfGOEY4xjlGOcY6Rjr | |
3338 | CBkRGRMZHhkgGSIZJBkmGSgZVRlXGVkZWxldGV8ZYRljGWUZZxlwGXIZdRl3Gc4Z8Bn6GgcaHBo2GlIa |
|
3338 | GP4ZABkCGQQZBhkIGREZExkeGSAZIhkkGSYZKBlVGVcZWRlbGV0ZXxlhGWMZZRlnGXAZchl1GXcZzhnw | |
3339 | bRp3GoMalRqkGsMazxrRGtMa3BreGuAa4RrjGuwa9Rr3Gvga+hr8Gv4bABsJGxQbMRs9Gz8bQRtDG0Ub |
|
3339 | GfoaBxocGjYaUhptGncagxqVGqQawxrPGtEa0xrcGt4a4BrhGuMa7Br1Gvca+Br6Gvwa/hsAGwkbFBsx | |
3340 | RxtJG3YbeBt6G3wbfhuAG4IbhBuGG4gbkhubG6QbuBvRG9Mb1RvXG9kb2xvyG/scBBwSHBscHRwiHCQc |
|
3340 | Gz0bPxtBG0MbRRtHG0kbdht4G3obfBt+G4AbghuEG4YbiBuSG5sbpBu4G9Eb0xvVG9cb2RvbG/Ib+xwE | |
3341 | JhxPHF4caxx2HIUckBybHKgcqRyrHK0cthy4HMEcyhzLHM0c6hzvHPEc8xz1HPcc+R0CHQ8dER0dHTId |
|
3341 | HBIcGxwdHCIcJBwmHE8cXhxrHHYchRyQHJscqBypHKscrRy2HLgcwRzKHMsczRzqHO8c8RzzHPUc9xz5 | |
3342 | NB02HTgdOh1MHVUdYB10HZUdox2oHaodrB2uHbAdsh21HbcdwR3SHdQd3R3fHeId9x35Hfsd/R3/Hhge |
|
3342 | HQIdDx0RHR0dMh00HTYdOB06HUwdVR1gHXQdlR2jHagdqh2sHa4dsB2yHbUdtx3BHdId1B3dHd8d4h33 | |
3343 | LR4vHjEeMx41HkgeUR5WHmQejR6OHpAekh6bHp0enh6gHr0evx7BHsMexR7HHs0e7h7wHvIe9B72Hvge |
|
3343 | Hfkd+x39Hf8eGB4tHi8eMR4zHjUeSB5RHlYeZB6NHo4ekB6SHpsenR6eHqAevR6/HsEewx7FHscezR7u | |
3344 | +h8PHxEfEx8VHxcfIR8uHzAfNR8+H0kfYR+GH4gfih+MH44fkB+SH5QfnR+2H98f4R/jH+Uf5x/pH+sf |
|
3344 | HvAe8h70HvYe+B76Hw8fER8THxUfFx8hHy4fMB81Hz4fSR9hH4YfiB+KH4wfjh+QH5IflB+dH7Yf3x/h | |
3345 | 7R/2IA4gFyAZIBwgHiA0IE0gZCB9IJognCCeIKAgoiCkIK4guyC9INYg+SECIQshFyFAIUshViFgIW0h |
|
3345 | H+Mf5R/nH+kf6x/tH/YgDiAXIBkgHCAeIDQgTSBkIH0gmiCcIJ4goCCiIKQgriC7IL0g1iD5IQIhCyEX | |
3346 | byFxIXMhfCGFIYghiiGNIY8hkSGWIZghoSGmIbEhySHSIdsh8SH8IhQiJyIwIjUiSCJRIlMitCK2Irgi |
|
3346 | IUAhSyFWIWAhbSFvIXEhcyF8IYUhiCGKIY0hjyGRIZYhmCGhIaYhsSHJIdIh2yHxIfwiFCInIjAiNSJI | |
3347 | uiK8Ir4iwCLCIsQixiLIIsoizCLOItAi0yLWItki3CLfIuIi5SLoIusi7iLxIvQi9yL6Iv0jACMDIwYj |
|
3347 | IlEiUyK0IrYiuCK6IrwiviLAIsIixCLGIsgiyiLMIs4i0CLTItYi2SLcIt8i4iLlIugi6yLuIvEi9CL3 | |
3348 | CSMMIw8jEiMVIxgjGyMeIyEjJCMnIyojLSMwIzMjQCNJI1EjUyNVI1cjfCOEI5gjoyOxI7sjyCPPI9Uj |
|
3348 | Ivoi/SMAIwMjBiMJIwwjDyMSIxUjGCMbIx4jISMkIycjKiMtIzAjMyNAI0kjUSNTI1UjVyN4I4AjlCOf | |
3349 | 1yPZI94j4CPlI+cj6SPrI/gkBCQHJAokDSQaJBwkKSQ4JDokPCQ+JEYkWCRhJGYkeSSGJIgkiiSMJJ8k |
|
3349 | I60jtyPEI8sjzSPPI9Qj1iPbI90j3yPhI/Ij/iQBJAQkByQKJBMkICQvJDEkMyQ1JD0kTyRYJF0kcCR9 | |
3350 | qCStJLgk3CTlJOwlBCUTJSAlIiUkJSYlRyVJJUslTSVPJVElUyVgJWMlZiVpJX0lfyWfJawlriWwJbIl |
|
3350 | JH8kgSSDJJYknySkJK8kyCTRJNgk8CT/JQwlDiUQJRIlMyU1JTclOSU7JT0lPyVMJU8lUiVVJWQlZiV1 | |
3351 | 1yXZJdsl3SXfJeEl4yX2JfgmEyYgJiImJCYmJkcmSSZLJk0mTyZRJlMmYCZjJmYmaSZuJnAmfiaLJo0m |
|
3351 | JYIlhCWGJYglqSWrJa0lryWxJbMltSXCJcUlyCXLJdgl2iXhJe4l8CXyJfQmGSYfJiEmIyYoJiomLCYu | |
3352 | jyaRJrImtCa2Jrgmuia8Jr4myybOJtEm1CbZJtsm4SbuJvAm8ib0JxUnFycZJx4nICciJyQnJicrJy0n |
|
3352 | JjAmPSZAJkMmRiZSJlQmdCaBJoMmhSaHJqgmqiasJq4msCayJrQmwSbEJscmyibPJtEm1ybkJuYm6Cbq | |
3353 | MydAJ0InRCdGJ2cnaSdrJ3Ancid0J3YneCeJJ4wnjyeSJ5UnoSejJ7wnySfLJ80nzyfwJ/In9Cf2J/gn |
|
3353 | JwsnDScPJxEnEycVJxcnJCcnJyonLSc8J0snWCdaJ1wnXid/J4EngyeFJ4cniSeLJ5gnmyeeJ6EnuCe6 | |
3354 | +if8KAkoDCgPKBIoHiggKDgoRShHKEkoSyhsKG4ocChyKHQodih4KH4ogCiHKJQoliiYKJoovyjBKMMo |
|
3354 | J8Qn0SfTJ9Un1yf4J/on/Cf+KAAoAigEKCIoQyhQKFIoVChWKHcoeSh7KH0ofyiBKIMojiiQKJsoqCiq | |
3355 | xSjHKMkoyyjWKPAo/Sj/KQEpAykkKSYpKCkqKSwpLikwKT0pQClDKUYpVCliKXMpgSmDKYUphymJKZIp |
|
3355 | KKworijPKNEo0yjVKNco2SjbKPkpEikfKSEpIyklKUYpSClKKUwpTilQKVIpXyliKWUpaCmPKbEpvinA | |
3356 | lCmWKa8puCnBKcgp3ynsKe4p8CnyKhMqFSoXKhkqGyodKh8qJiouKjsqPSo/KkIqYyplKmcqaipsKm4q |
|
3356 | KcIpxCnlKecp6SnuKfAp8in0KfYqAyoFKhsqKCoqKiwqLipPKlEqUypVKlcqWSpbKmAqYipwKoEqjyqS | |
3357 | cCqBKoQqhyqKKo0qliqYKq4quyq9KsAqwyrkKuYq6SrrKu0q7yrxKwYrGCslKycrKistK04rUCtTK1Ur |
|
3357 | KpQqliqYKqEqoyqlKq4qsCqyKs8q2CrhKugq/ysMKw4rESsUKzkrOys+K0ErQytFK0crVCtWK3oriyuO | |
3358 | VytZK1srZCt9K4orjCuPK5Irsyu1K7gruyu9K78rwSvHK8kr1yvoK+or7CvvK/IsDywRLBQsFiwYLBos |
|
3358 | K5ErkyuWK58roSukK70r0SveK+Ar4yvmLAcsCSwMLA8sESwTLBUsLCwuLDksRixILEssTixvLHEsdCx3 | |
3359 | HCw0LFQsYSxjLGYsaSyKLIwsjyySLJQsliyZLKYsqSysLK8svizALM8s3CzeLOEs5C0FLQctCi0NLQ8t |
|
3359 | LHkseyx+LI8skiyVLJgsmyykLKYsvCzJLMsszizRLPIs9Cz3LPos/Cz+LQAtBS0HLQ0tGi0cLR8tIi1D | |
3360 | ES0TLR4tIC0rLTgtOi09LUAtYS1jLWYtaC1qLWwtbi2FLYstmC2aLZ0toC3BLcMtxi3ILcotzC3PLe0u |
|
3360 | LUUtSC1LLU0tTy1RLW4tcC2CLY8tkS2ULZctuC26Lb0twC3CLcQtxy3ULdct2i3dLekt6y4DLhAuEi4V | |
3361 | Di4bLh0uIC4jLkQuRi5JLkwuTi5QLlIuXy5hLmgudS53LnoufS6eLqAuoy6mLqguqi6sLr0uvy7RLt4u |
|
3361 | LhguOS47Lj4uQS5DLkUuRy5TLlUubi57Ln0ugC6DLqQupi6pLqwuri6wLrIuty65Lr8uzC7OLtEu1C75 | |
3362 | 4C7jLuYvBy8JLwwvDy8RLxMvFS8sLy4vOS9GL0gvSy9OL3MvdS94L3svfS9/L4EvjS+PL68vwC/CL8Qv |
|
3362 | Lvsu/i8BLwMvBS8ILxUvGC8bLx4vKS8rL0UvUi9UL1cvWi97L30vgC+CL4Qvhi+IL5YvpC+1L7cvuS+8 | |
3363 | xy/KL9Mv1S/YL/UwCTAWMBgwGzAeMD8wQTBEMEYwSDBKMEwwUTBeMGswbTBwMHMwlDCWMJkwnDCeMKAw |
|
3363 | L78v3C/eL+Ev4y/lL+cv6TABMCEwLjAwMDMwNjBbMGUwZzBpMGwwbzBxMHMwdTCDMIUwlDClMKgwqzCt | |
3364 | ojCnMKkwrzC8ML4wwTDEMOUw5zDqMO0w7zDxMPQxATEEMQcxCjEXMRkxLzFAMUIxRTFIMUoxUzFVMVcx |
|
3364 | MK8wvDC+MMEwxDDlMOcw6jDtMO8w8TDzMPkw+zECMRMxFjEYMRoxHTE1MUIxRDFHMUoxazFtMXAxczF1 | |
3365 | ZDFmMWkxbDGNMY8xkjGUMZYxmDGaMakxuDHFMccxyjHNMe4x8DHzMfYx+DH6Mf0yCjINMhAyEzIqMiwy |
|
3365 | MXcxejGOMZAxsDG9Mb8xwjHFMeYx6DHrMe0x7zHxMfQyBTIIMgsyDjIRMhwyNDJBMkMyRjJJMmoybDJv | |
3366 | NjJDMkUySDJLMmwybjJxMnMydTJ3MnoyizKOMpEylDKXMqIyujLHMskyzDLPMvAy8jL1Mvcy+TL7Mv4z |
|
3366 | MnEyczJ1MncyfjKGMpMylTKYMpsyuDK6Mr0yvzLBMsMyxTLXMvAzATMEMwYzCTMMMxUzIjMkMyczKjNL | |
3367 | JTNHM1QzVjNZM1wzfTN/M4IzhTOHM4kzizOPM5EzljOnM6kzqzOtM7AzuTPKM8wzzjPQM9Mz6zP4M/oz |
|
3367 | M00zUDNSM1QzVjNZM24zgDONM48zkjOVM7YzuDO7M74zwDPCM8Qz2zPhM+4z8DPzM/Y0FzQZNBw0HjQg | |
3368 | /TQANCU0LzQxNDM0NjQ5NDs0PTQ/NE00TzReNGs0bTRwNHM0lDSWNJk0nDSeNKA0ozTANMI01DThNOM0 |
|
3368 | NCI0JTQqNDc0RDRGNEk0TDRxNHM0djR5NHs0fTR/NJI0rTS6NLw0vzTCNOM05TToNOs07TTvNPE1AjUE | |
3369 | 5jTpNQY1CDULNQ01DzURNRM1JTU+NUs1TTVQNVM1dDV2NXk1ezV9NX81gjWgNbk11jXgNeo2CTYMNg82 |
|
3369 | NRY1IzUlNSg1KzVMNU41UTVUNVY1WDVaNV41YDVlNXI1dDV3NXo1mzWdNaA1ozWlNac1qTWvNbE1vzXc | |
3370 | EjYVNhc2GjZHNmQ2ezaINpM2ojaxNtY28TcKNx43HzciNyM3JjcnNyo3LTcuNy83MDczNzw3PjdFN0g3 |
|
3370 | NeY18DYPNhI2FDYXNho2HTYgNk02ajaBNo42mTaoNrc23Db3NxA3JDclNyg3KTcsNy03MDczNzQ3NTc2 | |
3371 | SzdON1M3VzddN2Y3aTdsN283gDeGN5E3nTegN6M3pjenN7A3uTe+N9E32jffN+g38zgMOCA4NThCOF84 |
|
3371 | Nzk3QjdEN0s3TjdRN1Q3WTddN2M3bDdvN3I3dTeGN4w3lzejN6Y3qTesN603tje/N8Q31zfgN+U37jf5 | |
3372 | dTh+OIU4nTi6OL04vzjCOMU4yDjLOOc4+zkCOR85IjklOSg5KzktOTA5TzlnOYQ5hzmKOY05kDmTOZY5 |
|
3372 | OBI4Jjg7OEg4dDiGOKE4qjixOMk45jjpOOw47zjyOPU4+DkUOSg5LzlMOU85UjlVOVg5WjldOXw5lDmx | |
3373 | wjnUOe86DDoPOhE6FDoXOhk6HDo4OkA6UzpcOl87MDsyOzU7ODs6Ozw7PztCO0Q7RztKO007UDtTO1Y7 |
|
3373 | ObQ5tzm6Ob05vznCOd859ToSOhU6GDobOh46IDojOj86RzpaOmM6Zjs3Ozo7PDs/O0I7RTtHO0o7TTtP | |
3374 | WTtbO147YTtkO2c7aTtrO247cTt0O3c7ejt9O4A7gjuFO4c7ijuNO5A7kzuWO5g7mzueO6E7pDunO6k7 |
|
3374 | O1I7VTtYO1s7XjthO2M7ZTtnO2k7azttO3A7cjt0O3Y7eDt6O3w7fzuCO4Q7hjuIO4s7jTuQO5I7lTuY | |
3375 | rDuuO7A7sju0O7Y7uDu6O7w7vzvCO8U7xzvKO8070DvSO9U72DvaO9w73jvhO+M75TvoO+o77TvwO/I7 |
|
3375 | O5o7nTugO6I7pDunO6o7rTuwO7I7tTu4O7s7vjvAO8I7xDvHO8k7zDvOO9E71DvWO9g72zveO+E75Dvm | |
3376 | 9Dv2O/g7+zv+PAE8BDwGPAk8DDwPPBI8FDwXPBk8HDwfPCE8IzwlPCg8KjwsPC48MTw0PDc8OTw8PGU8 |
|
3376 | O+k76zvuO/E78zv1O/g7+zv9PAA8AjwFPAc8CTwMPA88EjwVPBc8GjwdPCA8IzwmPCk8KzwuPDA8Mzw2 | |
3377 | bzxxPHM8djx4PHo8fDx+PIE8iDyXPKA8ojynPKo8rDy1PLo84zzlPOg86zztPO888TzzPPY9Aj0LPQ09 |
|
3377 | PDk8PDw/PEI8azx5PIY8iDyKPIs8jTyOPJA8kjyUPL08xzzJPMw8zzzRPNM81TzYPNs87DzvPPI89Tz4 | |
3378 | ED0TPSw9VT1XPVk9XD1ePWA9Yj1kPWc9dT1+PYA9hz2JPYs9jj2fPaI9pT2oPas9tT2+PcA9zz3SPdU9 |
|
3378 | PP89Dj0XPRk9Hj0hPSQ9RT1HPUo9TD1OPVA9Uz1ePWc9bD14PYE9gz2GPYk9oj3LPc090D3TPdU91z3Z | |
3379 | 2D3bPd494T3kPg0+Dz4RPhQ+Fj4YPho+HT4gPjI+Oz49PlQ+Vz5aPl0+YD5jPmY+aT5rPm4+cT50Pp0+ |
|
3379 | Pds93j4HPgk+Cz4OPhA+Ej4UPhY+GT4wPjk+Oz5EPkc+ST5LPk0+dj54Pno+fT5/PoE+gz6GPok+jj6X | |
3380 | qz64Pro+vD69Pr8+wD7CPsQ+xj7nPuk+7D7vPvE+8z71Pw4/ED85Pzs/PT8+P0A/QT9DP0U/Rz9wP3I/ |
|
3380 | Ppk+tD63Prk+vD6/PsI+xT7IPso+zT7QPtM+1j7ZPwI/BD8GPwc/CT8KPww/Dj8QPzk/Oz89Pz4/QD9B | |
3381 | dT94P3o/fD9+P4A/gz+MP50/oD+jP6Y/qT+yP7Q/tT/HP/A/8j/0P/U/9z/4P/o//D/+QCdAKUArQCxA |
|
3381 | P0M/RT9HP3A/cj91P3g/ej98P34/gD+DP4g/kT+TP54/oT+kP6c/qj+tP9I/1D/XP9o/3D/eP+E/60AQ | |
3382 | LkAvQDFAM0A1QEJAa0BtQG9AckB0QHZAeEB7QH5Ag0CMQI5ApUCoQKtArkCxQLRAtkC5QLxAv0DCQMVA |
|
3382 | QBJAFUAXQBlAG0AeQCxAUUBTQFZAWUBbQF1AYEBiQHtAfUCmQKhAqkCtQK9AsUCzQLVAuEDGQM9A0UDY | |
3383 | 5kDoQOtA7kDwQPJA9ED4QPpBG0EdQSBBI0ElQSdBKUE0QTZBX0FhQWNBZEFmQWdBaUFrQW1BlkGYQZpB |
|
3383 | QNtA3kDgQQlBC0ENQRBBEkEUQRZBGEEbQSJBK0EtQTJBNEE3QUFBSkFMQVtBXkFhQWRBZ0FqQW1BcEGZ | |
3384 | m0GdQZ5BoEGiQaRBzUHPQdFB1EHWQdhB2kHdQeBB5UHuQfBCC0INQg9CEkIVQhhCGkIcQh9CIkIlQihC |
|
3384 | QZtBnUGgQaJBpEGmQalBrEG+QcdByUHgQeNB5kHpQexB70HyQfVB+EH6Qf1CAEIpQitCLUIuQjBCMUIz | |
3385 | K0IuQldCWUJbQlxCXkJfQmFCY0JlQo5CkEKSQpNClUKWQphCmkKcQsVCx0LJQsxCzkLQQtJC1ELXQtxC |
|
3385 | QjVCN0JYQlpCXUJgQmJCZEJmQn9CgUKqQqxCrkKvQrFCskK0QrZCuELhQuNC5kLpQutC7ULvQvFC9EL9 | |
3386 | 5ULnQvJC9EL3QvpC/UL/QyRDJkMpQytDLUMvQzFDO0NgQ2JDZUNoQ2pDbENuQ3xDoUOjQ6ZDqUOrQ61D |
|
3386 | Qw5DEUMUQxdDGkMjQyVDJkM4Q2FDY0NlQ2ZDaENpQ2tDbUNvQ3xDpUOnQ6lDrEOuQ7BDskO1Q7hDvUPG | |
3387 | r0OxQ8pDzEP1Q/dD+kP9Q/9EAUQDRAVECEQfRChEKkQzRDZEOUQ8RD9EaERqRGxEb0RxRHNEdUR4RHtE |
|
3387 | Q8hD30PiQ+VD6EPrQ+5D8EPzQ/ZD+UP8Q/5EH0QhRCREJ0QpRCtELUQxRDNEVERWRFlEXEReRGBEYkRt | |
3388 | gkSLRI1EkkSVRJdEuES6RL1EwETCRMRExkTRRPpE/ET/RQJFBEUGRQhFC0UORRNFHEUeRSNFJkUpRVJF |
|
3388 | RG9EmESaRJxEnUSfRKBEokSkRKZEz0TRRNNE1ETWRNdE2UTbRN1FBkUIRQpFDUUPRRFFE0UWRRlFHkUn | |
3389 | VEVWRVlFW0VdRV9FYkVlRWxFdUV3RYBFgkWFRYhFi0W0RbZFuEW5RbtFvEW+RcBFwkXRRfpF/EX/RgJG |
|
3389 | RSlFLkUwRTJFW0VdRWBFY0VlRWdFaUVsRW9FdkV/RYFFikWNRZBFk0WWRb9FwUXDRcRFxkXHRclFy0XO | |
3390 | BEYGRghGC0YORhNGHEYeRiFGJEYwRjlGPEcNRw9HEUcTRxVHF0cZRxtHHUcfRyJHJEcmRylHLEcuRzFH |
|
3390 | Rd1GBkYIRgpGDUYPRhFGE0YWRhlGHkYnRilGLEYuRjpGQ0ZGRxdHGUcbRx5HIEcjRyVHKEcqRyxHLkcx | |
3391 |
|
|
3391 | RzNHNUc3RzlHO0c9Rz9HQkdFR0dHSUdLR01HT0dRR1NHVkdYR1pHXUdfR2FHY0dlR2dHakdsR29HcUd0 | |
3392 | dkd4R3tHfUeAR4JHhEeHR4pHjUePR5FHk0eWR5hHmkedR59HoUejR6VHp0epR6tHrUevR7FHtEe2R7hH |
|
3392 | R3ZHeEd6R3xHfkeBR4RHhkeJR4tHjkeQR5JHlUeYR5tHnkegR6JHpEemR6hHqketR7BHske1R7dHuUe7 | |
3393 | uke8R75HwEfDR8VHyEfKR8xHzkfQR9NH1kfZR9xH30fhR+NH5UfnR+lH60fuR/BH8kf1R/dIAEgDSNZI |
|
3393 | R71Hv0fBR8NHxUfHR8lHy0fNR9BH0kfUR9dH2kfdR99H4UfjR+VH50fqR+xH70fxR/NH9Uf3R/pH/UgA | |
3394 | 2EjbSN5I4EjiSOVI6EjqSO1I8EjzSPZI+Uj8SP9JAkkESQdJCkkNSQ9JEUkUSRdJGkkdSSBJI0kmSShJ |
|
3394 | SAJIBUgOSBFI5EjmSOlI7EjvSPJI9Ej3SPpI/Ej/SQJJBUkISQtJDkkQSRJJFEkWSRhJGkkdSR9JIUkj | |
3395 | K0ktSTBJM0k2STlJPEk+SUFJRElHSUpJTUlPSVJJVElWSVhJWklcSV5JYEliSWVJaElrSW1JcElzSXZJ |
|
3395 | SSVJJ0kpSStJLUkwSTNJNUk4STpJPUk/SUJJRUlHSUpJTUlPSVFJVElWSVlJXElfSWJJZElnSWpJbUlv | |
3396 | eEl7SX5JgEmCSYRJh0mJSYtJjkmQSZNJlkmYSZpJnEmeSaFJpEmnSapJrEmvSbJJtEm3SbpJvUm/ScJJ |
|
3396 | SXFJc0l1SXhJe0l9SYBJg0mFSYdJikmNSZBJk0mVSZhJmkmdSZ9JokmkSadJqkmsSa9JsUm0SbZJuEm7 | |
3397 | xEnHSclJy0nNSdBJ0knUSdZJ2UncSd9J4UnkSe1J8ErDSsZKyUrMSs9K0krVSthK20reSuFK5ErnSupK |
|
3397 | Sb5JwUnEScZJyUnMSc9J0knVSdhJ2kndSd9J4knlSehJ60nuSfFJ+kn9StBK00rWStlK3ErfSuJK5Uro | |
3398 | 7UrwSvNK9kr5SvxK/0sCSwVLCEsLSw5LEUsUSxdLGksdSyBLI0smSylLLEsvSzJLNUs4SztLPktBS0RL |
|
3398 | SutK7krxSvRK90r6Sv1LAEsDSwZLCUsMSw9LEksVSxhLG0seSyFLJEsnSypLLUswSzNLNks5SzxLP0tC | |
3399 | R0tKS01LUEtTS1ZLWUtcS19LYktlS2hLa0tuS3FLdEt3S3pLfUuAS4NLhkuJS4xLj0uSS5VLmEubS55L |
|
3399 | S0VLSEtLS05LUUtUS1dLWktdS2BLY0tmS2lLbEtvS3JLdUt4S3tLfkuBS4RLhkuJS4xLj0uSS5VLmEub | |
3400 |
oUukS6dLqkutS7BLs0u2S7lLvEu/S8JLxUvIS8tLzkvRS9RL10vaS91L4EvjS+ZL6UvsS+9L8kv1 |
|
3400 | S55LoUukS6dLqkutS7BLs0u2S7lLvEu/S8JLxUvIS8tLzkvRS9RL10vaS91L4EvjS+ZL6UvsS+9L8kv1 | |
3401 | +0wWTCtMLUxBTFtMdUyZTK5MwUzWTNhM9E0rTVVNcE15TYdNiU2bTZ1NqU3ATeVN6k39TglOLE4/TlhO |
|
3401 | S/hL+0v+TAFMBEwHTBJMHkxDTFhMbUyLTKBMukzaTP1NEE0jTS1NNk1STV9NYU1vTXFNiE2hTb1N104B | |
3402 | ZU6BToxOr06zTrVOzE7YTuJPA08YTz1PVk9jT29PlE+uT8JPzk/nT/lQFVAsUEpQZ1B6UJpQplCwUO9R |
|
3402 | Tg9OOU5LTmROgE6MTp9Oq07KTuRO+08ATw5PIk9DT09PYU97T55PqE/ET9FP00/oT+xP+FAVUC5QOlBV | |
3403 | DlEaUThRTlFlUXhRi1GfUbdRulHUUfBR/FIKUipSLFI6UlJSaVJ8UqZStFK2UtBS3VMAUwRTEFMvU0RT |
|
3403 | UFdQdVCBUI1QpVDKUM5Q0FDrUQFRJlFEUVdRWVFvUYJRwVHlUfJSKVJGUmlSbVKBUo1SoFKzUspS3lLs | |
3404 | UFNpU3dTkVOkU7BTzlPqVABUBFQWVDNUP1RBVEpUTVROVFdUWlRbVGRUZ1WYVZtVnVWgVaNVplWpVatV |
|
3404 | UwxTDlMgUzpTRlNJU15TdVOUU65TulPGU95T9VQOVCFUPVQ/VE1UVlRZVFpUY1RmVGdUcFRzVaRVp1Wp | |
3405 | rVWwVbNVtVW4VbtVvlXBVcRVx1XJVcxVz1XRVdRV11XaVd1V4FXjVeVV6FXrVe5V8VX0VfZV+FX6Vf1W |
|
3405 | VaxVr1WyVbVVuFW7Vb1VwFXDVcVVyFXLVc1V0FXTVdZV2FXbVd5V4VXjVeZV6VXsVe5V8FXyVfRV9lX4 | |
3406 |
|
|
3406 | VftV/VYAVgJWBFYGVghWClYNVhBWElYUVhZWGVYcVh5WIVYkViZWKVYsVi9WMVYzVjZWOVY8Vj5WQVZE | |
3407 | UlZUVlZWWFZaVlxWXlZgVmJWZVZoVmtWblZwVnNWdlZ5VnxWf1aCVoRWh1aKVo1Wj1aRVpNWlVaYVppW |
|
3407 | VkdWSlZMVk5WUVZTVlZWWVZcVl5WYVZkVmZWaVZsVm9WcVZ0VnZWeFZ7Vn5WgFaCVoVWh1aKVo1Wj1aR | |
3408 | nFafVqJWpVanVqpWrVawVrNWtla4VrpWvFa+VsBWwlbFVshWy1bOVtBW01bVVthW21bdVuBW41blVuhW |
|
3408 | VpRWl1aZVpxWnlahVqRWp1apVqxWrlawVrNWtla4VrpWvVbAVsNWxlbIVstWzVbQVtJW1VbXVtlW21be | |
3409 | 6lbtVu9W8lb1VvdW+Vb7Vv5XAVcDVwVXCFcKVwxXD1cSVxVXGFcbVx1XIFciVyVXLlcxWGJYZVhoWGtY |
|
3409 | VuFW5FbnVulW7FbvVvJW9Fb3VvpW/VcAVwNXBlcIVwtXDlcQVxNXFlcZVxxXH1ciVyVXJ1cqVy1XMFc5 | |
3410 | blhxWHRYd1h6WH1YgFiDWIZYiViMWI9YkliVWJhYm1ieWKFYpFinWKpYrViwWLNYtli5WLxYv1jCWMVY |
|
3410 | VzxYbVhwWHNYdlh5WHxYf1iCWIVYiFiLWI5YkViUWJdYmlidWKBYo1imWKlYrFivWLJYtVi4WLtYvljB | |
3411 | yFjLWM5Y0VjUWNdY2ljdWOBY41jmWOlY7FjvWPJY9Vj4WPtY/lkBWQRZB1kKWQ1ZEFkTWRZZGVkcWR9Z |
|
3411 | WMRYx1jKWM1Y0FjTWNZY2VjcWN9Y4ljlWOhY61juWPFY9Fj3WPpY/VkAWQNZBlkJWQxZD1kSWRVZGFkb | |
3412 | IlklWShZK1kuWTFZNFk3WTpZPVlAWUNZRllJWUxZT1lSWVVZWFlbWV5ZYVlkWWdZalltWXBZc1l2WXlZ |
|
3412 | WR5ZIVkkWSdZKlktWTBZM1k2WTlZPFk/WUJZRVlIWUtZTllRWVRZV1laWV1ZYFljWWZZaVlsWW9Zcll1 | |
3413 | fFl/WYJZhVmIWYtZjlmRWZRZl1maWZ1ZoFmjWaZZqVmsWa9Zslm1WbhZu1m+WcFZxFnHWcpZzVnQWdNZ |
|
3413 | WXhZe1l+WYFZhFmHWYpZjVmQWZNZllmZWZxZn1miWaVZqFmrWa5ZsVm0WbdZulm9WcBZw1nGWclZzFnP | |
3414 | 1lnZWdxZ31niWeVZ6FnrWe5Z8Vn0WfdZ+ln9WgBaA1oGWglaDFoPWhJaFVoYWhtaHlohWiRaJ1oqWi1a |
|
3414 | WdJZ1VnYWdtZ3lnhWeRZ51nqWe1Z8FnzWfZZ+Vn8Wf9aAloFWghaC1oOWhFaFFoXWhpaHVogWiNaJlop | |
3415 | L1oyWjRaNlo5WjxaPlpAWkJaRFpGWklaTFpOWlBaUlpUWlZaWFpbWl1aYFpiWmRaZlpoWmtabVpwWnJa |
|
3415 | WixaL1oyWjRaN1o5WjtaPVpAWkNaRVpIWkpaTFpOWlBaU1pWWlhaWlpcWl9aYlpkWmZaaVprWm1acFpy | |
3416 | dFp2WnlafFp+WoBaglqEWoZaiFqKWoxaj1qSWpVamFqbWp5aoVqjWqZaqFqqWqxarlqwWrNatlq5Wrta |
|
3416 | WnVaeFp6Wn1af1qBWoRah1qKWoxaj1qSWpRallqYWppanVqgWqJapFqmWqhaqlqsWq9asVqzWrxav1rC | |
3417 | vVq/WsFaxFrGWshaylrNWtBa0lrVWtda2lrcWt9a4VrjWuVa51rpWuxa71rxWvRa91r6Wvxa/lsAWwNb |
|
3417 | WsVax1rKWs1az1rRWtRa1lrZWtxa31rhWuNa5VrnWula61ruWvBa8lr1Wvda+Vr7Wv1a/1sBWwRbBlsI | |
3418 | BlsIWwpbDFsOWxFbE1sWWxhbGlscWx5bIVsjWyZbKVssWy9bMVs0WzdbOVs7Wz1bP1tCW0VbR1tJW0xb |
|
3418 | WwtbDVsPWxJbFVsYWxtbHVsfWyFbI1slWyhbK1stWzBbMls0WzZbOFs7Wz1bQFtCW0VbSFtKW0xbTltR | |
3419 |
|
|
3419 | W1NbVltZW1xbXlthW2NbZVtoW2pbbFtuW3FbdFt2W3hbe1t+W4Bbg1uGW4hbi1uOW5Bbk1uVW5hbmluc | |
3420 |
|
|
3420 | W55boVujW6VbrluwW7Fbulu9W75bx1vKW8tb1FvZAAAAAAAAAgIAAAAAAAALwwAAAAAAAAAAAAAAAAAA | |
|
3421 | W+g</bytes> | |||
3421 | </object> |
|
3422 | </object> | |
3422 | </data> |
|
3423 | </data> | |
3423 | </archive> |
|
3424 | </archive> |
@@ -28,6 +28,7 b' from zopeinterface import Interface, Attribute, implements, classProvides' | |||||
28 |
|
28 | |||
29 | from IPython.kernel.core.history import FrontEndHistory |
|
29 | from IPython.kernel.core.history import FrontEndHistory | |
30 | from IPython.kernel.core.util import Bunch |
|
30 | from IPython.kernel.core.util import Bunch | |
|
31 | from IPython.kernel.engineservice import IEngineCore | |||
31 |
|
32 | |||
32 | ############################################################################## |
|
33 | ############################################################################## | |
33 | # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or |
|
34 | # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or | |
@@ -284,7 +285,6 b' class FrontEndBase(object):' | |||||
284 |
|
285 | |||
285 | def _add_block_id_for_failure(self, failure, blockID): |
|
286 | def _add_block_id_for_failure(self, failure, blockID): | |
286 | """_add_block_id_for_failure""" |
|
287 | """_add_block_id_for_failure""" | |
287 |
|
||||
288 | failure.blockID = blockID |
|
288 | failure.blockID = blockID | |
289 | return failure |
|
289 | return failure | |
290 |
|
290 | |||
@@ -348,6 +348,7 b' class FrontEndBase(object):' | |||||
348 |
|
348 | |||
349 |
|
349 | |||
350 | def render_error(self, failure): |
|
350 | def render_error(self, failure): | |
|
351 | <<<<<<< TREE | |||
351 | """Subclasses must override to render the failure. |
|
352 | """Subclasses must override to render the failure. | |
352 |
|
353 | |||
353 | In asynchronous frontends, this method will be called as a |
|
354 | In asynchronous frontends, this method will be called as a | |
@@ -359,4 +360,63 b' class FrontEndBase(object):' | |||||
359 |
|
360 | |||
360 |
|
361 | |||
361 |
|
362 | |||
|
363 | ======= | |||
|
364 | """Subclasses must override to render the failure. Since this method | |||
|
365 | will be called as a twisted.internet.defer.Deferred's callback, | |||
|
366 | implementations should return result when finished. | |||
|
367 | """ | |||
|
368 | ||||
|
369 | return failure | |||
|
370 | ||||
|
371 | ||||
|
372 | ||||
|
373 | class AsyncFrontEndBase(FrontEndBase): | |||
|
374 | """ | |||
|
375 | Overrides FrontEndBase to wrap execute in a deferred result. | |||
|
376 | All callbacks are made as callbacks on the deferred result. | |||
|
377 | """ | |||
|
378 | ||||
|
379 | implements(IFrontEnd) | |||
|
380 | classProvides(IFrontEndFactory) | |||
|
381 | ||||
|
382 | def __init__(self, engine=None, history=None): | |||
|
383 | assert(engine==None or IEngineCore.providedBy(engine)) | |||
|
384 | self.engine = IEngineCore(engine) | |||
|
385 | if history is None: | |||
|
386 | self.history = FrontEndHistory(input_cache=['']) | |||
|
387 | else: | |||
|
388 | self.history = history | |||
|
389 | ||||
|
390 | ||||
|
391 | def execute(self, block, blockID=None): | |||
|
392 | """Execute the block and return the deferred result. | |||
|
393 | ||||
|
394 | Parameters: | |||
|
395 | block : {str, AST} | |||
|
396 | blockID : any | |||
|
397 | Caller may provide an ID to identify this block. | |||
|
398 | result['blockID'] := blockID | |||
|
399 | ||||
|
400 | Result: | |||
|
401 | Deferred result of self.interpreter.execute | |||
|
402 | """ | |||
|
403 | ||||
|
404 | if(not self.is_complete(block)): | |||
|
405 | from twisted.python.failure import Failure | |||
|
406 | return Failure(Exception("Block is not compilable")) | |||
|
407 | ||||
|
408 | if(blockID == None): | |||
|
409 | blockID = uuid.uuid4() #random UUID | |||
|
410 | ||||
|
411 | d = self.engine.execute(block) | |||
|
412 | d.addCallback(self._add_history, block=block) | |||
|
413 | d.addCallback(self._add_block_id_for_result, blockID) | |||
|
414 | d.addErrback(self._add_block_id_for_failure, blockID) | |||
|
415 | d.addBoth(self.update_cell_prompt, blockID=blockID) | |||
|
416 | d.addCallbacks(self.render_result, | |||
|
417 | errback=self.render_error) | |||
|
418 | ||||
|
419 | return d | |||
|
420 | ||||
|
421 | >>>>>>> MERGE-SOURCE | |||
362 |
|
422 |
@@ -84,7 +84,7 b' class TestAsyncFrontendBase(unittest.TestCase):' | |||||
84 | d.addCallback(self.checkBlockID, expected='TEST_ID') |
|
84 | d.addCallback(self.checkBlockID, expected='TEST_ID') | |
85 |
|
85 | |||
86 | def test_blockID_added_to_failure(self): |
|
86 | def test_blockID_added_to_failure(self): | |
87 |
block = "raise |
|
87 | block = "raise Exception()" | |
88 |
|
88 | |||
89 | d = self.fb.execute(block,blockID='TEST_ID') |
|
89 | d = self.fb.execute(block,blockID='TEST_ID') | |
90 | d.addErrback(self.checkFailureID, expected='TEST_ID') |
|
90 | d.addErrback(self.checkFailureID, expected='TEST_ID') |
@@ -97,8 +97,8 b' class IOStream:' | |||||
97 |
|
97 | |||
98 | def close(self): |
|
98 | def close(self): | |
99 | pass |
|
99 | pass | |
100 |
|
100 | |||
101 |
|
101 | |||
102 | class IOTerm: |
|
102 | class IOTerm: | |
103 | """ Term holds the file or file-like objects for handling I/O operations. |
|
103 | """ Term holds the file or file-like objects for handling I/O operations. | |
104 |
|
104 | |||
@@ -113,16 +113,16 b' class IOTerm:' | |||||
113 | self.cin = IOStream(cin,sys.stdin) |
|
113 | self.cin = IOStream(cin,sys.stdin) | |
114 | self.cout = IOStream(cout,sys.stdout) |
|
114 | self.cout = IOStream(cout,sys.stdout) | |
115 | self.cerr = IOStream(cerr,sys.stderr) |
|
115 | self.cerr = IOStream(cerr,sys.stderr) | |
116 |
|
116 | |||
117 | # Global variable to be used for all I/O |
|
117 | # Global variable to be used for all I/O | |
118 | Term = IOTerm() |
|
118 | Term = IOTerm() | |
119 |
|
119 | |||
120 | import IPython.rlineimpl as readline |
|
120 | import IPython.rlineimpl as readline | |
121 | # Remake Term to use the readline i/o facilities |
|
121 | # Remake Term to use the readline i/o facilities | |
122 | if sys.platform == 'win32' and readline.have_readline: |
|
122 | if sys.platform == 'win32' and readline.have_readline: | |
123 |
|
123 | |||
124 | Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile) |
|
124 | Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile) | |
125 |
|
125 | |||
126 |
|
126 | |||
127 | #**************************************************************************** |
|
127 | #**************************************************************************** | |
128 | # Generic warning/error printer, used by everything else |
|
128 | # Generic warning/error printer, used by everything else | |
@@ -130,9 +130,9 b' def warn(msg,level=2,exit_val=1):' | |||||
130 | """Standard warning printer. Gives formatting consistency. |
|
130 | """Standard warning printer. Gives formatting consistency. | |
131 |
|
131 | |||
132 | Output is sent to Term.cerr (sys.stderr by default). |
|
132 | Output is sent to Term.cerr (sys.stderr by default). | |
133 |
|
133 | |||
134 | Options: |
|
134 | Options: | |
135 |
|
135 | |||
136 | -level(2): allows finer control: |
|
136 | -level(2): allows finer control: | |
137 | 0 -> Do nothing, dummy function. |
|
137 | 0 -> Do nothing, dummy function. | |
138 | 1 -> Print message. |
|
138 | 1 -> Print message. | |
@@ -142,7 +142,7 b' def warn(msg,level=2,exit_val=1):' | |||||
142 |
|
142 | |||
143 | -exit_val (1): exit value returned by sys.exit() for a level 4 |
|
143 | -exit_val (1): exit value returned by sys.exit() for a level 4 | |
144 | warning. Ignored for all other levels.""" |
|
144 | warning. Ignored for all other levels.""" | |
145 |
|
145 | |||
146 | if level>0: |
|
146 | if level>0: | |
147 | header = ['','','WARNING: ','ERROR: ','FATAL ERROR: '] |
|
147 | header = ['','','WARNING: ','ERROR: ','FATAL ERROR: '] | |
148 | print >> Term.cerr, '%s%s' % (header[level],msg) |
|
148 | print >> Term.cerr, '%s%s' % (header[level],msg) | |
@@ -167,10 +167,10 b' def fatal(msg,exit_val=1):' | |||||
167 |
|
167 | |||
168 | #--------------------------------------------------------------------------- |
|
168 | #--------------------------------------------------------------------------- | |
169 | # Debugging routines |
|
169 | # Debugging routines | |
170 |
# |
|
170 | # | |
171 | def debugx(expr,pre_msg=''): |
|
171 | def debugx(expr,pre_msg=''): | |
172 | """Print the value of an expression from the caller's frame. |
|
172 | """Print the value of an expression from the caller's frame. | |
173 |
|
173 | |||
174 | Takes an expression, evaluates it in the caller's frame and prints both |
|
174 | Takes an expression, evaluates it in the caller's frame and prints both | |
175 | the given expression and the resulting value (as well as a debug mark |
|
175 | the given expression and the resulting value (as well as a debug mark | |
176 | indicating the name of the calling function. The input must be of a form |
|
176 | indicating the name of the calling function. The input must be of a form | |
@@ -178,7 +178,7 b" def debugx(expr,pre_msg=''):" | |||||
178 |
|
178 | |||
179 | An optional message can be passed, which will be prepended to the printed |
|
179 | An optional message can be passed, which will be prepended to the printed | |
180 | expr->value pair.""" |
|
180 | expr->value pair.""" | |
181 |
|
181 | |||
182 | cf = sys._getframe(1) |
|
182 | cf = sys._getframe(1) | |
183 | print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr, |
|
183 | print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr, | |
184 | eval(expr,cf.f_globals,cf.f_locals)) |
|
184 | eval(expr,cf.f_globals,cf.f_locals)) | |
@@ -200,18 +200,18 b' try:' | |||||
200 | Return the *USER* CPU time in seconds since the start of the process. |
|
200 | Return the *USER* CPU time in seconds since the start of the process. | |
201 | This is done via a call to resource.getrusage, so it avoids the |
|
201 | This is done via a call to resource.getrusage, so it avoids the | |
202 | wraparound problems in time.clock().""" |
|
202 | wraparound problems in time.clock().""" | |
203 |
|
203 | |||
204 | return resource.getrusage(resource.RUSAGE_SELF)[0] |
|
204 | return resource.getrusage(resource.RUSAGE_SELF)[0] | |
205 |
|
205 | |||
206 | def clocks(): |
|
206 | def clocks(): | |
207 | """clocks() -> floating point number |
|
207 | """clocks() -> floating point number | |
208 |
|
208 | |||
209 | Return the *SYSTEM* CPU time in seconds since the start of the process. |
|
209 | Return the *SYSTEM* CPU time in seconds since the start of the process. | |
210 | This is done via a call to resource.getrusage, so it avoids the |
|
210 | This is done via a call to resource.getrusage, so it avoids the | |
211 | wraparound problems in time.clock().""" |
|
211 | wraparound problems in time.clock().""" | |
212 |
|
212 | |||
213 | return resource.getrusage(resource.RUSAGE_SELF)[1] |
|
213 | return resource.getrusage(resource.RUSAGE_SELF)[1] | |
214 |
|
214 | |||
215 | def clock(): |
|
215 | def clock(): | |
216 | """clock() -> floating point number |
|
216 | """clock() -> floating point number | |
217 |
|
217 | |||
@@ -219,9 +219,9 b' try:' | |||||
219 | the process. This is done via a call to resource.getrusage, so it |
|
219 | the process. This is done via a call to resource.getrusage, so it | |
220 | avoids the wraparound problems in time.clock().""" |
|
220 | avoids the wraparound problems in time.clock().""" | |
221 |
|
221 | |||
222 |
u,s = resource.getrusage(resource.RUSAGE_SELF)[:2] |
|
222 | u,s = resource.getrusage(resource.RUSAGE_SELF)[:2] | |
223 | return u+s |
|
223 | return u+s | |
224 |
|
224 | |||
225 | def clock2(): |
|
225 | def clock2(): | |
226 | """clock2() -> (t_user,t_system) |
|
226 | """clock2() -> (t_user,t_system) | |
227 |
|
227 | |||
@@ -247,7 +247,7 b' def timings_out(reps,func,*args,**kw):' | |||||
247 | Under Unix, the return value is the sum of user+system time consumed by |
|
247 | Under Unix, the return value is the sum of user+system time consumed by | |
248 | the process, computed via the resource module. This prevents problems |
|
248 | the process, computed via the resource module. This prevents problems | |
249 | related to the wraparound effect which the time.clock() function has. |
|
249 | related to the wraparound effect which the time.clock() function has. | |
250 |
|
250 | |||
251 | Under Windows the return value is in wall clock seconds. See the |
|
251 | Under Windows the return value is in wall clock seconds. See the | |
252 | documentation for the time module for more details.""" |
|
252 | documentation for the time module for more details.""" | |
253 |
|
253 | |||
@@ -310,7 +310,7 b" def system(cmd,verbose=0,debug=0,header=''):" | |||||
310 | Options: |
|
310 | Options: | |
311 |
|
311 | |||
312 | - verbose (0): print the command to be executed. |
|
312 | - verbose (0): print the command to be executed. | |
313 |
|
313 | |||
314 | - debug (0): only print, do not actually execute. |
|
314 | - debug (0): only print, do not actually execute. | |
315 |
|
315 | |||
316 | - header (''): Header to print on screen prior to the executed command (it |
|
316 | - header (''): Header to print on screen prior to the executed command (it | |
@@ -334,15 +334,15 b' def abbrev_cwd():' | |||||
334 | if len(cwd) < 4: |
|
334 | if len(cwd) < 4: | |
335 | return cwd |
|
335 | return cwd | |
336 | drivepart,tail = os.path.splitdrive(cwd) |
|
336 | drivepart,tail = os.path.splitdrive(cwd) | |
337 |
|
||||
338 |
|
337 | |||
339 | parts = tail.split('/') |
|
338 | ||
|
339 | parts = tail.split('/') | |||
340 | if len(parts) > 2: |
|
340 | if len(parts) > 2: | |
341 | tail = '/'.join(parts[-2:]) |
|
341 | tail = '/'.join(parts[-2:]) | |
342 |
|
342 | |||
343 | return (drivepart + ( |
|
343 | return (drivepart + ( | |
344 | cwd == '/' and '/' or tail)) |
|
344 | cwd == '/' and '/' or tail)) | |
345 |
|
345 | |||
346 |
|
346 | |||
347 | # This function is used by ipython in a lot of places to make system calls. |
|
347 | # This function is used by ipython in a lot of places to make system calls. | |
348 | # We need it to be slightly different under win32, due to the vagaries of |
|
348 | # We need it to be slightly different under win32, due to the vagaries of | |
@@ -354,7 +354,7 b" def shell(cmd,verbose=0,debug=0,header=''):" | |||||
354 | Options: |
|
354 | Options: | |
355 |
|
355 | |||
356 | - verbose (0): print the command to be executed. |
|
356 | - verbose (0): print the command to be executed. | |
357 |
|
357 | |||
358 | - debug (0): only print, do not actually execute. |
|
358 | - debug (0): only print, do not actually execute. | |
359 |
|
359 | |||
360 | - header (''): Header to print on screen prior to the executed command (it |
|
360 | - header (''): Header to print on screen prior to the executed command (it | |
@@ -368,7 +368,7 b" def shell(cmd,verbose=0,debug=0,header=''):" | |||||
368 | if verbose or debug: print header+cmd |
|
368 | if verbose or debug: print header+cmd | |
369 | # flush stdout so we don't mangle python's buffering |
|
369 | # flush stdout so we don't mangle python's buffering | |
370 | sys.stdout.flush() |
|
370 | sys.stdout.flush() | |
371 |
|
371 | |||
372 | if not debug: |
|
372 | if not debug: | |
373 | platutils.set_term_title("IPy " + cmd) |
|
373 | platutils.set_term_title("IPy " + cmd) | |
374 | os.system(cmd) |
|
374 | os.system(cmd) | |
@@ -406,10 +406,10 b" def getoutput(cmd,verbose=0,debug=0,header='',split=0):" | |||||
406 |
|
406 | |||
407 | Note: a stateful version of this function is available through the |
|
407 | Note: a stateful version of this function is available through the | |
408 | SystemExec class. |
|
408 | SystemExec class. | |
409 |
|
409 | |||
410 |
This is pretty much deprecated and rarely used, |
|
410 | This is pretty much deprecated and rarely used, | |
411 | genutils.getoutputerror may be what you need. |
|
411 | genutils.getoutputerror may be what you need. | |
412 |
|
412 | |||
413 | """ |
|
413 | """ | |
414 |
|
414 | |||
415 | if verbose or debug: print header+cmd |
|
415 | if verbose or debug: print header+cmd | |
@@ -461,7 +461,7 b' class SystemExec:' | |||||
461 |
|
461 | |||
462 | Note: here we refer to the system and getoutput functions from this |
|
462 | Note: here we refer to the system and getoutput functions from this | |
463 | library, not the ones from the standard python library. |
|
463 | library, not the ones from the standard python library. | |
464 |
|
464 | |||
465 | This class offers the system and getoutput functions as methods, but the |
|
465 | This class offers the system and getoutput functions as methods, but the | |
466 | verbose, debug and header parameters can be set for the instance (at |
|
466 | verbose, debug and header parameters can be set for the instance (at | |
467 | creation time or later) so that they don't need to be specified on each |
|
467 | creation time or later) so that they don't need to be specified on each | |
@@ -476,13 +476,9 b' class SystemExec:' | |||||
476 | - bq: alias to getoutput |
|
476 | - bq: alias to getoutput | |
477 |
|
477 | |||
478 | An instance can then be created as: |
|
478 | An instance can then be created as: | |
479 |
|
|
479 | >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ') | |
480 |
|
||||
481 | And used as: |
|
|||
482 | >>> sysexec.xsys('pwd') |
|
|||
483 | >>> dirlist = sysexec.bq('ls -l') |
|
|||
484 | """ |
|
480 | """ | |
485 |
|
481 | |||
486 | def __init__(self,verbose=0,debug=0,header='',split=0): |
|
482 | def __init__(self,verbose=0,debug=0,header='',split=0): | |
487 | """Specify the instance's values for verbose, debug and header.""" |
|
483 | """Specify the instance's values for verbose, debug and header.""" | |
488 | setattr_list(self,'verbose debug header split') |
|
484 | setattr_list(self,'verbose debug header split') | |
@@ -634,7 +630,7 b" def process_cmdline(argv,names=[],defaults={},usage=''):" | |||||
634 | Arguments: |
|
630 | Arguments: | |
635 |
|
631 | |||
636 | - argv: list of arguments, typically sys.argv. |
|
632 | - argv: list of arguments, typically sys.argv. | |
637 |
|
633 | |||
638 | - names: list of option names. See DPyGetOpt docs for details on options |
|
634 | - names: list of option names. See DPyGetOpt docs for details on options | |
639 | syntax. |
|
635 | syntax. | |
640 |
|
636 | |||
@@ -656,7 +652,7 b" def process_cmdline(argv,names=[],defaults={},usage=''):" | |||||
656 |
|
652 | |||
657 | defaults.update(getopt.optionValues) |
|
653 | defaults.update(getopt.optionValues) | |
658 | args = getopt.freeValues |
|
654 | args = getopt.freeValues | |
659 |
|
655 | |||
660 | return defaults,args |
|
656 | return defaults,args | |
661 |
|
657 | |||
662 | #---------------------------------------------------------------------------- |
|
658 | #---------------------------------------------------------------------------- | |
@@ -684,8 +680,7 b' def optstr2types(ostr):' | |||||
684 |
|
680 | |||
685 | #---------------------------------------------------------------------------- |
|
681 | #---------------------------------------------------------------------------- | |
686 | def read_dict(filename,type_conv=None,**opt): |
|
682 | def read_dict(filename,type_conv=None,**opt): | |
687 |
|
683 | r"""Read a dictionary of key=value pairs from an input file, optionally | ||
688 | """Read a dictionary of key=value pairs from an input file, optionally |
|
|||
689 | performing conversions on the resulting values. |
|
684 | performing conversions on the resulting values. | |
690 |
|
685 | |||
691 | read_dict(filename,type_conv,**opt) -> dict |
|
686 | read_dict(filename,type_conv,**opt) -> dict | |
@@ -731,20 +726,33 b' def read_dict(filename,type_conv=None,**opt):' | |||||
731 | to make a list of all appearances. |
|
726 | to make a list of all appearances. | |
732 |
|
727 | |||
733 | Example: |
|
728 | Example: | |
734 | If the input file test.ini has: |
|
|||
735 | i 3 |
|
|||
736 | x 4.5 |
|
|||
737 | y 5.5 |
|
|||
738 | s hi ho |
|
|||
739 | Then: |
|
|||
740 |
|
729 | |||
|
730 | If the input file test.ini contains (we put it in a string to keep the test | |||
|
731 | self-contained): | |||
|
732 | ||||
|
733 | >>> test_ini = '''\ | |||
|
734 | ... i 3 | |||
|
735 | ... x 4.5 | |||
|
736 | ... y 5.5 | |||
|
737 | ... s hi ho''' | |||
|
738 | ||||
|
739 | Then we can use it as follows: | |||
741 | >>> type_conv={int:'i',float:'x',None:'s'} |
|
740 | >>> type_conv={int:'i',float:'x',None:'s'} | |
742 | >>> read_dict('test.ini') |
|
741 | ||
743 | {'i': '3', 's': 'hi ho', 'x': '4.5', 'y': '5.5'} |
|
742 | >>> d = read_dict(test_ini) | |
744 | >>> read_dict('test.ini',type_conv) |
|
743 | ||
745 | {'i': 3, 's': 'hi ho', 'x': 4.5, 'y': '5.5'} |
|
744 | >>> sorted(d.items()) | |
746 | >>> read_dict('test.ini',type_conv,purge=1) |
|
745 | [('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')] | |
747 | {'i': 3, 's': 'hi ho', 'x': 4.5} |
|
746 | ||
|
747 | >>> d = read_dict(test_ini,type_conv) | |||
|
748 | ||||
|
749 | >>> sorted(d.items()) | |||
|
750 | [('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')] | |||
|
751 | ||||
|
752 | >>> d = read_dict(test_ini,type_conv,purge=True) | |||
|
753 | ||||
|
754 | >>> sorted(d.items()) | |||
|
755 | [('i', 3), ('s', 'hi ho'), ('x', 4.5)] | |||
748 | """ |
|
756 | """ | |
749 |
|
757 | |||
750 | # starting config |
|
758 | # starting config | |
@@ -762,9 +770,15 b' def read_dict(filename,type_conv=None,**opt):' | |||||
762 | raise ValueError, 'Unique keys must be given as a string, List or Tuple' |
|
770 | raise ValueError, 'Unique keys must be given as a string, List or Tuple' | |
763 |
|
771 | |||
764 | dict = {} |
|
772 | dict = {} | |
|
773 | ||||
765 | # first read in table of values as strings |
|
774 | # first read in table of values as strings | |
766 | file = open(filename,'r') |
|
775 | if '\n' in filename: | |
767 |
|
|
776 | lines = filename.splitlines() | |
|
777 | file = None | |||
|
778 | else: | |||
|
779 | file = open(filename,'r') | |||
|
780 | lines = file.readlines() | |||
|
781 | for line in lines: | |||
768 | line = line.strip() |
|
782 | line = line.strip() | |
769 | if len(line) and line[0]=='#': continue |
|
783 | if len(line) and line[0]=='#': continue | |
770 | if len(line)>0: |
|
784 | if len(line)>0: | |
@@ -831,7 +845,7 b' def flag_calls(func):' | |||||
831 |
|
845 | |||
832 | Testing for truth in wrapper.called allows you to determine if a call to |
|
846 | Testing for truth in wrapper.called allows you to determine if a call to | |
833 | func() was attempted and succeeded.""" |
|
847 | func() was attempted and succeeded.""" | |
834 |
|
848 | |||
835 | def wrapper(*args,**kw): |
|
849 | def wrapper(*args,**kw): | |
836 | wrapper.called = False |
|
850 | wrapper.called = False | |
837 | out = func(*args,**kw) |
|
851 | out = func(*args,**kw) | |
@@ -853,7 +867,7 b' def dhook_wrap(func,*a,**k):' | |||||
853 | """ |
|
867 | """ | |
854 |
|
868 | |||
855 | def f(*a,**k): |
|
869 | def f(*a,**k): | |
856 |
|
870 | |||
857 | dhook_s = sys.displayhook |
|
871 | dhook_s = sys.displayhook | |
858 | sys.displayhook = sys.__displayhook__ |
|
872 | sys.displayhook = sys.__displayhook__ | |
859 | try: |
|
873 | try: | |
@@ -873,10 +887,10 b' def doctest_reload():' | |||||
873 | This routine: |
|
887 | This routine: | |
874 |
|
888 | |||
875 | - reloads doctest |
|
889 | - reloads doctest | |
876 |
|
890 | |||
877 | - resets its global 'master' attribute to None, so that multiple uses of |
|
891 | - resets its global 'master' attribute to None, so that multiple uses of | |
878 | the module interactively don't produce cumulative reports. |
|
892 | the module interactively don't produce cumulative reports. | |
879 |
|
893 | |||
880 | - Monkeypatches its core test runner method to protect it from IPython's |
|
894 | - Monkeypatches its core test runner method to protect it from IPython's | |
881 | modified displayhook. Doctest expects the default displayhook behavior |
|
895 | modified displayhook. Doctest expects the default displayhook behavior | |
882 | deep down, so our modification breaks it completely. For this reason, a |
|
896 | deep down, so our modification breaks it completely. For this reason, a | |
@@ -910,16 +924,16 b' def get_home_dir():' | |||||
910 |
|
924 | |||
911 | isdir = os.path.isdir |
|
925 | isdir = os.path.isdir | |
912 | env = os.environ |
|
926 | env = os.environ | |
913 |
|
927 | |||
914 | # first, check py2exe distribution root directory for _ipython. |
|
928 | # first, check py2exe distribution root directory for _ipython. | |
915 | # This overrides all. Normally does not exist. |
|
929 | # This overrides all. Normally does not exist. | |
916 |
|
930 | |||
917 | if '\\library.zip\\' in IPython.__file__.lower(): |
|
931 | if '\\library.zip\\' in IPython.__file__.lower(): | |
918 | root, rest = IPython.__file__.lower().split('library.zip') |
|
932 | root, rest = IPython.__file__.lower().split('library.zip') | |
919 | if isdir(root + '_ipython'): |
|
933 | if isdir(root + '_ipython'): | |
920 | os.environ["IPYKITROOT"] = root.rstrip('\\') |
|
934 | os.environ["IPYKITROOT"] = root.rstrip('\\') | |
921 | return root |
|
935 | return root | |
922 |
|
936 | |||
923 | try: |
|
937 | try: | |
924 | homedir = env['HOME'] |
|
938 | homedir = env['HOME'] | |
925 | if not isdir(homedir): |
|
939 | if not isdir(homedir): | |
@@ -977,7 +991,7 b' class LSString(str):' | |||||
977 | .n (or .nlstr): original value (the string itself). |
|
991 | .n (or .nlstr): original value (the string itself). | |
978 | .s (or .spstr): value as whitespace-separated string. |
|
992 | .s (or .spstr): value as whitespace-separated string. | |
979 | .p (or .paths): list of path objects |
|
993 | .p (or .paths): list of path objects | |
980 |
|
994 | |||
981 | Any values which require transformations are computed only once and |
|
995 | Any values which require transformations are computed only once and | |
982 | cached. |
|
996 | cached. | |
983 |
|
997 | |||
@@ -1013,14 +1027,14 b' class LSString(str):' | |||||
1013 | except AttributeError: |
|
1027 | except AttributeError: | |
1014 | self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)] |
|
1028 | self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)] | |
1015 | return self.__paths |
|
1029 | return self.__paths | |
1016 |
|
1030 | |||
1017 | p = paths = property(get_paths) |
|
1031 | p = paths = property(get_paths) | |
1018 |
|
1032 | |||
1019 | def print_lsstring(arg): |
|
1033 | def print_lsstring(arg): | |
1020 | """ Prettier (non-repr-like) and more informative printer for LSString """ |
|
1034 | """ Prettier (non-repr-like) and more informative printer for LSString """ | |
1021 | print "LSString (.p, .n, .l, .s available). Value:" |
|
1035 | print "LSString (.p, .n, .l, .s available). Value:" | |
1022 | print arg |
|
1036 | print arg | |
1023 |
|
1037 | |||
1024 | print_lsstring = result_display.when_type(LSString)(print_lsstring) |
|
1038 | print_lsstring = result_display.when_type(LSString)(print_lsstring) | |
1025 |
|
1039 | |||
1026 | #---------------------------------------------------------------------------- |
|
1040 | #---------------------------------------------------------------------------- | |
@@ -1033,7 +1047,7 b' class SList(list):' | |||||
1033 | .n (or .nlstr): value as a string, joined on newlines. |
|
1047 | .n (or .nlstr): value as a string, joined on newlines. | |
1034 | .s (or .spstr): value as a string, joined on spaces. |
|
1048 | .s (or .spstr): value as a string, joined on spaces. | |
1035 | .p (or .paths): list of path objects |
|
1049 | .p (or .paths): list of path objects | |
1036 |
|
1050 | |||
1037 | Any values which require transformations are computed only once and |
|
1051 | Any values which require transformations are computed only once and | |
1038 | cached.""" |
|
1052 | cached.""" | |
1039 |
|
1053 | |||
@@ -1059,32 +1073,32 b' class SList(list):' | |||||
1059 | return self.__nlstr |
|
1073 | return self.__nlstr | |
1060 |
|
1074 | |||
1061 | n = nlstr = property(get_nlstr) |
|
1075 | n = nlstr = property(get_nlstr) | |
1062 |
|
1076 | |||
1063 | def get_paths(self): |
|
1077 | def get_paths(self): | |
1064 | try: |
|
1078 | try: | |
1065 | return self.__paths |
|
1079 | return self.__paths | |
1066 | except AttributeError: |
|
1080 | except AttributeError: | |
1067 | self.__paths = [path(p) for p in self if os.path.exists(p)] |
|
1081 | self.__paths = [path(p) for p in self if os.path.exists(p)] | |
1068 | return self.__paths |
|
1082 | return self.__paths | |
1069 |
|
1083 | |||
1070 | p = paths = property(get_paths) |
|
1084 | p = paths = property(get_paths) | |
1071 |
|
1085 | |||
1072 | def grep(self, pattern, prune = False, field = None): |
|
1086 | def grep(self, pattern, prune = False, field = None): | |
1073 |
""" Return all strings matching 'pattern' (a regex or callable) |
|
1087 | """ Return all strings matching 'pattern' (a regex or callable) | |
1074 |
|
1088 | |||
1075 | This is case-insensitive. If prune is true, return all items |
|
1089 | This is case-insensitive. If prune is true, return all items | |
1076 | NOT matching the pattern. |
|
1090 | NOT matching the pattern. | |
1077 |
|
1091 | |||
1078 |
If field is specified, the match must occur in the specified |
|
1092 | If field is specified, the match must occur in the specified | |
1079 | whitespace-separated field. |
|
1093 | whitespace-separated field. | |
1080 |
|
1094 | |||
1081 | Examples:: |
|
1095 | Examples:: | |
1082 |
|
1096 | |||
1083 | a.grep( lambda x: x.startswith('C') ) |
|
1097 | a.grep( lambda x: x.startswith('C') ) | |
1084 | a.grep('Cha.*log', prune=1) |
|
1098 | a.grep('Cha.*log', prune=1) | |
1085 | a.grep('chm', field=-1) |
|
1099 | a.grep('chm', field=-1) | |
1086 | """ |
|
1100 | """ | |
1087 |
|
1101 | |||
1088 | def match_target(s): |
|
1102 | def match_target(s): | |
1089 | if field is None: |
|
1103 | if field is None: | |
1090 | return s |
|
1104 | return s | |
@@ -1094,7 +1108,7 b' class SList(list):' | |||||
1094 | return tgt |
|
1108 | return tgt | |
1095 | except IndexError: |
|
1109 | except IndexError: | |
1096 | return "" |
|
1110 | return "" | |
1097 |
|
1111 | |||
1098 | if isinstance(pattern, basestring): |
|
1112 | if isinstance(pattern, basestring): | |
1099 | pred = lambda x : re.search(pattern, x, re.IGNORECASE) |
|
1113 | pred = lambda x : re.search(pattern, x, re.IGNORECASE) | |
1100 | else: |
|
1114 | else: | |
@@ -1105,25 +1119,25 b' class SList(list):' | |||||
1105 | return SList([el for el in self if not pred(match_target(el))]) |
|
1119 | return SList([el for el in self if not pred(match_target(el))]) | |
1106 | def fields(self, *fields): |
|
1120 | def fields(self, *fields): | |
1107 | """ Collect whitespace-separated fields from string list |
|
1121 | """ Collect whitespace-separated fields from string list | |
1108 |
|
1122 | |||
1109 | Allows quick awk-like usage of string lists. |
|
1123 | Allows quick awk-like usage of string lists. | |
1110 |
|
1124 | |||
1111 | Example data (in var a, created by 'a = !ls -l'):: |
|
1125 | Example data (in var a, created by 'a = !ls -l'):: | |
1112 | -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog |
|
1126 | -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog | |
1113 |
drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython |
|
1127 | drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython | |
1114 |
|
1128 | |||
1115 | a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+'] |
|
1129 | a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+'] | |
1116 | a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+'] |
|
1130 | a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+'] | |
1117 | (note the joining by space). |
|
1131 | (note the joining by space). | |
1118 | a.fields(-1) is ['ChangeLog', 'IPython'] |
|
1132 | a.fields(-1) is ['ChangeLog', 'IPython'] | |
1119 |
|
1133 | |||
1120 | IndexErrors are ignored. |
|
1134 | IndexErrors are ignored. | |
1121 |
|
1135 | |||
1122 | Without args, fields() just split()'s the strings. |
|
1136 | Without args, fields() just split()'s the strings. | |
1123 | """ |
|
1137 | """ | |
1124 | if len(fields) == 0: |
|
1138 | if len(fields) == 0: | |
1125 | return [el.split() for el in self] |
|
1139 | return [el.split() for el in self] | |
1126 |
|
1140 | |||
1127 | res = SList() |
|
1141 | res = SList() | |
1128 | for el in [f.split() for f in self]: |
|
1142 | for el in [f.split() for f in self]: | |
1129 | lineparts = [] |
|
1143 | lineparts = [] | |
@@ -1135,18 +1149,18 b' class SList(list):' | |||||
1135 | pass |
|
1149 | pass | |
1136 | if lineparts: |
|
1150 | if lineparts: | |
1137 | res.append(" ".join(lineparts)) |
|
1151 | res.append(" ".join(lineparts)) | |
1138 |
|
1152 | |||
1139 |
return res |
|
1153 | return res | |
1140 | def sort(self,field= None, nums = False): |
|
1154 | def sort(self,field= None, nums = False): | |
1141 | """ sort by specified fields (see fields()) |
|
1155 | """ sort by specified fields (see fields()) | |
1142 |
|
1156 | |||
1143 | Example:: |
|
1157 | Example:: | |
1144 | a.sort(1, nums = True) |
|
1158 | a.sort(1, nums = True) | |
1145 |
|
1159 | |||
1146 | Sorts a by second field, in numerical order (so that 21 > 3) |
|
1160 | Sorts a by second field, in numerical order (so that 21 > 3) | |
1147 |
|
1161 | |||
1148 |
""" |
|
1162 | """ | |
1149 |
|
1163 | |||
1150 | #decorate, sort, undecorate |
|
1164 | #decorate, sort, undecorate | |
1151 | if field is not None: |
|
1165 | if field is not None: | |
1152 | dsu = [[SList([line]).fields(field), line] for line in self] |
|
1166 | dsu = [[SList([line]).fields(field), line] for line in self] | |
@@ -1160,8 +1174,8 b' class SList(list):' | |||||
1160 | except ValueError: |
|
1174 | except ValueError: | |
1161 | n = 0; |
|
1175 | n = 0; | |
1162 | dsu[i][0] = n |
|
1176 | dsu[i][0] = n | |
1163 |
|
1177 | |||
1164 |
|
1178 | |||
1165 | dsu.sort() |
|
1179 | dsu.sort() | |
1166 | return SList([t[1] for t in dsu]) |
|
1180 | return SList([t[1] for t in dsu]) | |
1167 |
|
1181 | |||
@@ -1171,9 +1185,9 b' def print_slist(arg):' | |||||
1171 | if hasattr(arg, 'hideonce') and arg.hideonce: |
|
1185 | if hasattr(arg, 'hideonce') and arg.hideonce: | |
1172 | arg.hideonce = False |
|
1186 | arg.hideonce = False | |
1173 | return |
|
1187 | return | |
1174 |
|
1188 | |||
1175 | nlprint(arg) |
|
1189 | nlprint(arg) | |
1176 |
|
1190 | |||
1177 | print_slist = result_display.when_type(SList)(print_slist) |
|
1191 | print_slist = result_display.when_type(SList)(print_slist) | |
1178 |
|
1192 | |||
1179 |
|
1193 | |||
@@ -1187,14 +1201,14 b' def esc_quotes(strng):' | |||||
1187 | #---------------------------------------------------------------------------- |
|
1201 | #---------------------------------------------------------------------------- | |
1188 | def make_quoted_expr(s): |
|
1202 | def make_quoted_expr(s): | |
1189 | """Return string s in appropriate quotes, using raw string if possible. |
|
1203 | """Return string s in appropriate quotes, using raw string if possible. | |
1190 |
|
1204 | |||
1191 | Effectively this turns string: cd \ao\ao\ |
|
1205 | Effectively this turns string: cd \ao\ao\ | |
1192 | to: r"cd \ao\ao\_"[:-1] |
|
1206 | to: r"cd \ao\ao\_"[:-1] | |
1193 |
|
1207 | |||
1194 | Note the use of raw string and padding at the end to allow trailing backslash. |
|
1208 | Note the use of raw string and padding at the end to allow trailing backslash. | |
1195 |
|
1209 | |||
1196 | """ |
|
1210 | """ | |
1197 |
|
1211 | |||
1198 | tail = '' |
|
1212 | tail = '' | |
1199 | tailpadding = '' |
|
1213 | tailpadding = '' | |
1200 | raw = '' |
|
1214 | raw = '' | |
@@ -1245,7 +1259,7 b" def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):" | |||||
1245 | while new_line.endswith('\\'): |
|
1259 | while new_line.endswith('\\'): | |
1246 | new_line = new_line[:-1] + raw_input(ps2) |
|
1260 | new_line = new_line[:-1] + raw_input(ps2) | |
1247 | lines.append(new_line) |
|
1261 | lines.append(new_line) | |
1248 |
|
1262 | |||
1249 | return lines[:-1] # don't return the termination command |
|
1263 | return lines[:-1] # don't return the termination command | |
1250 | except EOFError: |
|
1264 | except EOFError: | |
1251 |
|
1265 | |||
@@ -1287,7 +1301,7 b' def ask_yes_no(prompt,default=None):' | |||||
1287 |
|
1301 | |||
1288 | else: |
|
1302 | else: | |
1289 | raise |
|
1303 | raise | |
1290 |
|
1304 | |||
1291 | return answers[ans] |
|
1305 | return answers[ans] | |
1292 |
|
1306 | |||
1293 | #---------------------------------------------------------------------------- |
|
1307 | #---------------------------------------------------------------------------- | |
@@ -1306,9 +1320,12 b' class EvalDict:' | |||||
1306 | Emulate a dict which evaluates its contents in the caller's frame. |
|
1320 | Emulate a dict which evaluates its contents in the caller's frame. | |
1307 |
|
1321 | |||
1308 | Usage: |
|
1322 | Usage: | |
1309 | >>>number = 19 |
|
1323 | >>> number = 19 | |
1310 | >>>text = "python" |
|
1324 | ||
1311 | >>>print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict() |
|
1325 | >>> text = "python" | |
|
1326 | ||||
|
1327 | >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict() | |||
|
1328 | Python 2.1 rules! | |||
1312 | """ |
|
1329 | """ | |
1313 |
|
1330 | |||
1314 | # This version is due to sismex01@hebmex.com on c.l.py, and is basically a |
|
1331 | # This version is due to sismex01@hebmex.com on c.l.py, and is basically a | |
@@ -1328,14 +1345,19 b' def qw(words,flat=0,sep=None,maxsplit=-1):' | |||||
1328 | qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit) |
|
1345 | qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit) | |
1329 |
|
1346 | |||
1330 | words can also be a list itself, and with flat=1, the output will be |
|
1347 | words can also be a list itself, and with flat=1, the output will be | |
1331 |
recursively flattened. |
|
1348 | recursively flattened. | |
|
1349 | ||||
|
1350 | Examples: | |||
1332 |
|
1351 | |||
1333 | >>> qw('1 2') |
|
1352 | >>> qw('1 2') | |
1334 | ['1', '2'] |
|
1353 | ['1', '2'] | |
|
1354 | ||||
1335 | >>> qw(['a b','1 2',['m n','p q']]) |
|
1355 | >>> qw(['a b','1 2',['m n','p q']]) | |
1336 | [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]] |
|
1356 | [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]] | |
|
1357 | ||||
1337 | >>> qw(['a b','1 2',['m n','p q']],flat=1) |
|
1358 | >>> qw(['a b','1 2',['m n','p q']],flat=1) | |
1338 |
['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] |
|
1359 | ['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] | |
|
1360 | """ | |||
1339 |
|
1361 | |||
1340 | if type(words) in StringTypes: |
|
1362 | if type(words) in StringTypes: | |
1341 | return [word.strip() for word in words.split(sep,maxsplit) |
|
1363 | return [word.strip() for word in words.split(sep,maxsplit) | |
@@ -1415,7 +1437,7 b' def igrep(pat,list):' | |||||
1415 | #---------------------------------------------------------------------------- |
|
1437 | #---------------------------------------------------------------------------- | |
1416 | def indent(str,nspaces=4,ntabs=0): |
|
1438 | def indent(str,nspaces=4,ntabs=0): | |
1417 | """Indent a string a given number of spaces or tabstops. |
|
1439 | """Indent a string a given number of spaces or tabstops. | |
1418 |
|
1440 | |||
1419 | indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces. |
|
1441 | indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces. | |
1420 | """ |
|
1442 | """ | |
1421 | if str is None: |
|
1443 | if str is None: | |
@@ -1426,7 +1448,7 b' def indent(str,nspaces=4,ntabs=0):' | |||||
1426 | return outstr[:-len(ind)] |
|
1448 | return outstr[:-len(ind)] | |
1427 | else: |
|
1449 | else: | |
1428 | return outstr |
|
1450 | return outstr | |
1429 |
|
1451 | |||
1430 | #----------------------------------------------------------------------------- |
|
1452 | #----------------------------------------------------------------------------- | |
1431 | def native_line_ends(filename,backup=1): |
|
1453 | def native_line_ends(filename,backup=1): | |
1432 | """Convert (in-place) a file to line-ends native to the current OS. |
|
1454 | """Convert (in-place) a file to line-ends native to the current OS. | |
@@ -1452,13 +1474,13 b' def native_line_ends(filename,backup=1):' | |||||
1452 | os.remove(bak_filename) |
|
1474 | os.remove(bak_filename) | |
1453 | except: |
|
1475 | except: | |
1454 | pass |
|
1476 | pass | |
1455 |
|
1477 | |||
1456 | #---------------------------------------------------------------------------- |
|
1478 | #---------------------------------------------------------------------------- | |
1457 | def get_pager_cmd(pager_cmd = None): |
|
1479 | def get_pager_cmd(pager_cmd = None): | |
1458 | """Return a pager command. |
|
1480 | """Return a pager command. | |
1459 |
|
1481 | |||
1460 | Makes some attempts at finding an OS-correct one.""" |
|
1482 | Makes some attempts at finding an OS-correct one.""" | |
1461 |
|
1483 | |||
1462 | if os.name == 'posix': |
|
1484 | if os.name == 'posix': | |
1463 | default_pager_cmd = 'less -r' # -r for color control sequences |
|
1485 | default_pager_cmd = 'less -r' # -r for color control sequences | |
1464 | elif os.name in ['nt','dos']: |
|
1486 | elif os.name in ['nt','dos']: | |
@@ -1570,7 +1592,7 b' def page(strng,start=0,screen_lines=0,pager_cmd = None):' | |||||
1570 | return |
|
1592 | return | |
1571 | except IPython.ipapi.TryNext: |
|
1593 | except IPython.ipapi.TryNext: | |
1572 | pass |
|
1594 | pass | |
1573 |
|
1595 | |||
1574 | # Ugly kludge, but calling curses.initscr() flat out crashes in emacs |
|
1596 | # Ugly kludge, but calling curses.initscr() flat out crashes in emacs | |
1575 | TERM = os.environ.get('TERM','dumb') |
|
1597 | TERM = os.environ.get('TERM','dumb') | |
1576 | if TERM in ['dumb','emacs'] and os.name != 'nt': |
|
1598 | if TERM in ['dumb','emacs'] and os.name != 'nt': | |
@@ -1581,7 +1603,7 b' def page(strng,start=0,screen_lines=0,pager_cmd = None):' | |||||
1581 | str_toprint = os.linesep.join(str_lines) |
|
1603 | str_toprint = os.linesep.join(str_lines) | |
1582 | num_newlines = len(str_lines) |
|
1604 | num_newlines = len(str_lines) | |
1583 | len_str = len(str_toprint) |
|
1605 | len_str = len(str_toprint) | |
1584 |
|
1606 | |||
1585 | # Dumb heuristics to guesstimate number of on-screen lines the string |
|
1607 | # Dumb heuristics to guesstimate number of on-screen lines the string | |
1586 | # takes. Very basic, but good enough for docstrings in reasonable |
|
1608 | # takes. Very basic, but good enough for docstrings in reasonable | |
1587 | # terminals. If someone later feels like refining it, it's not hard. |
|
1609 | # terminals. If someone later feels like refining it, it's not hard. | |
@@ -1738,7 +1760,7 b' def uniq_stable(elems):' | |||||
1738 | Note: All elements in the input must be valid dictionary keys for this |
|
1760 | Note: All elements in the input must be valid dictionary keys for this | |
1739 | routine to work, as it internally uses a dictionary for efficiency |
|
1761 | routine to work, as it internally uses a dictionary for efficiency | |
1740 | reasons.""" |
|
1762 | reasons.""" | |
1741 |
|
1763 | |||
1742 | unique = [] |
|
1764 | unique = [] | |
1743 | unique_dict = {} |
|
1765 | unique_dict = {} | |
1744 | for nn in elems: |
|
1766 | for nn in elems: | |
@@ -1753,13 +1775,13 b' class NLprinter:' | |||||
1753 |
|
1775 | |||
1754 | An instance of this class called nlprint is available and callable as a |
|
1776 | An instance of this class called nlprint is available and callable as a | |
1755 | function. |
|
1777 | function. | |
1756 |
|
1778 | |||
1757 | nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent' |
|
1779 | nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent' | |
1758 | and using 'sep' to separate the index from the value. """ |
|
1780 | and using 'sep' to separate the index from the value. """ | |
1759 |
|
1781 | |||
1760 | def __init__(self): |
|
1782 | def __init__(self): | |
1761 | self.depth = 0 |
|
1783 | self.depth = 0 | |
1762 |
|
1784 | |||
1763 | def __call__(self,lst,pos='',**kw): |
|
1785 | def __call__(self,lst,pos='',**kw): | |
1764 | """Prints the nested list numbering levels.""" |
|
1786 | """Prints the nested list numbering levels.""" | |
1765 | kw.setdefault('indent',' ') |
|
1787 | kw.setdefault('indent',' ') | |
@@ -1772,7 +1794,7 b' class NLprinter:' | |||||
1772 | stop = kw['stop']; del kw['stop'] |
|
1794 | stop = kw['stop']; del kw['stop'] | |
1773 | if self.depth == 0 and 'header' in kw.keys(): |
|
1795 | if self.depth == 0 and 'header' in kw.keys(): | |
1774 | print kw['header'] |
|
1796 | print kw['header'] | |
1775 |
|
1797 | |||
1776 | for idx in range(start,stop): |
|
1798 | for idx in range(start,stop): | |
1777 | elem = lst[idx] |
|
1799 | elem = lst[idx] | |
1778 | if type(elem)==type([]): |
|
1800 | if type(elem)==type([]): | |
@@ -1804,20 +1826,6 b' def sort_compare(lst1,lst2,inplace = 1):' | |||||
1804 | return lst1 == lst2 |
|
1826 | return lst1 == lst2 | |
1805 |
|
1827 | |||
1806 | #---------------------------------------------------------------------------- |
|
1828 | #---------------------------------------------------------------------------- | |
1807 | def mkdict(**kwargs): |
|
|||
1808 | """Return a dict from a keyword list. |
|
|||
1809 |
|
||||
1810 | It's just syntactic sugar for making ditcionary creation more convenient: |
|
|||
1811 | # the standard way |
|
|||
1812 | >>>data = { 'red' : 1, 'green' : 2, 'blue' : 3 } |
|
|||
1813 | # a cleaner way |
|
|||
1814 | >>>data = dict(red=1, green=2, blue=3) |
|
|||
1815 |
|
||||
1816 | If you need more than this, look at the Struct() class.""" |
|
|||
1817 |
|
||||
1818 | return kwargs |
|
|||
1819 |
|
||||
1820 | #---------------------------------------------------------------------------- |
|
|||
1821 | def list2dict(lst): |
|
1829 | def list2dict(lst): | |
1822 | """Takes a list of (key,value) pairs and turns it into a dict.""" |
|
1830 | """Takes a list of (key,value) pairs and turns it into a dict.""" | |
1823 |
|
1831 | |||
@@ -1935,7 +1943,7 b' def getattr_list(obj,alist,*args):' | |||||
1935 | raise ValueError,'getattr_list() takes only one optional argument' |
|
1943 | raise ValueError,'getattr_list() takes only one optional argument' | |
1936 | else: |
|
1944 | else: | |
1937 | return map(lambda attr: getattr(obj,attr),alist) |
|
1945 | return map(lambda attr: getattr(obj,attr),alist) | |
1938 |
|
1946 | |||
1939 | #---------------------------------------------------------------------------- |
|
1947 | #---------------------------------------------------------------------------- | |
1940 | def map_method(method,object_list,*argseq,**kw): |
|
1948 | def map_method(method,object_list,*argseq,**kw): | |
1941 | """map_method(method,object_list,*args,**kw) -> list |
|
1949 | """map_method(method,object_list,*args,**kw) -> list | |
@@ -1987,7 +1995,7 b' def dir2(obj):' | |||||
1987 | are later not really valid for attribute access (many extension libraries |
|
1995 | are later not really valid for attribute access (many extension libraries | |
1988 | have such bugs). |
|
1996 | have such bugs). | |
1989 | """ |
|
1997 | """ | |
1990 |
|
1998 | |||
1991 | # Start building the attribute list via dir(), and then complete it |
|
1999 | # Start building the attribute list via dir(), and then complete it | |
1992 | # with a few extra special-purpose calls. |
|
2000 | # with a few extra special-purpose calls. | |
1993 | words = dir(obj) |
|
2001 | words = dir(obj) | |
@@ -2064,7 +2072,7 b' def popkey(dct,key,default=NotGiven):' | |||||
2064 |
|
2072 | |||
2065 | def wrap_deprecated(func, suggest = '<nothing>'): |
|
2073 | def wrap_deprecated(func, suggest = '<nothing>'): | |
2066 | def newFunc(*args, **kwargs): |
|
2074 | def newFunc(*args, **kwargs): | |
2067 |
warnings.warn("Call to deprecated function %s, use %s instead" % |
|
2075 | warnings.warn("Call to deprecated function %s, use %s instead" % | |
2068 | ( func.__name__, suggest), |
|
2076 | ( func.__name__, suggest), | |
2069 | category=DeprecationWarning, |
|
2077 | category=DeprecationWarning, | |
2070 | stacklevel = 2) |
|
2078 | stacklevel = 2) | |
@@ -2098,7 +2106,7 b' def num_cpus():' | |||||
2098 | If it can't find a sensible answer, it returns 1 (though an error *may* make |
|
2106 | If it can't find a sensible answer, it returns 1 (though an error *may* make | |
2099 | it return a large positive number that's actually incorrect). |
|
2107 | it return a large positive number that's actually incorrect). | |
2100 | """ |
|
2108 | """ | |
2101 |
|
2109 | |||
2102 | # Many thanks to the Parallel Python project (http://www.parallelpython.com) |
|
2110 | # Many thanks to the Parallel Python project (http://www.parallelpython.com) | |
2103 | # for the names of the keys we needed to look up for this function. This |
|
2111 | # for the names of the keys we needed to look up for this function. This | |
2104 | # code was inspired by their equivalent function. |
|
2112 | # code was inspired by their equivalent function. |
@@ -1,4 +1,4 b'' | |||||
1 |
|
|
1 | """IPython customization API | |
2 |
|
2 | |||
3 | Your one-stop module for configuring & extending ipython |
|
3 | Your one-stop module for configuring & extending ipython | |
4 |
|
4 | |||
@@ -29,50 +29,50 b' import IPython.ipapi' | |||||
29 | ip = IPython.ipapi.get() |
|
29 | ip = IPython.ipapi.get() | |
30 |
|
30 | |||
31 | def ankka_f(self, arg): |
|
31 | def ankka_f(self, arg): | |
32 |
print |
|
32 | print 'Ankka',self,'says uppercase:',arg.upper() | |
33 |
|
33 | |||
34 |
ip.expose_magic( |
|
34 | ip.expose_magic('ankka',ankka_f) | |
35 |
|
35 | |||
36 | ip.magic('alias sayhi echo "Testing, hi ok"') |
|
36 | ip.magic('alias sayhi echo "Testing, hi ok"') | |
37 | ip.magic('alias helloworld echo "Hello world"') |
|
37 | ip.magic('alias helloworld echo "Hello world"') | |
38 | ip.system('pwd') |
|
38 | ip.system('pwd') | |
39 |
|
39 | |||
40 | ip.ex('import re') |
|
40 | ip.ex('import re') | |
41 |
ip.ex( |
|
41 | ip.ex(''' | |
42 | def funcci(a,b): |
|
42 | def funcci(a,b): | |
43 | print a+b |
|
43 | print a+b | |
44 | print funcci(3,4) |
|
44 | print funcci(3,4) | |
45 | """) |
|
45 | ''') | |
46 |
ip.ex( |
|
46 | ip.ex('funcci(348,9)') | |
47 |
|
47 | |||
48 | def jed_editor(self,filename, linenum=None): |
|
48 | def jed_editor(self,filename, linenum=None): | |
49 |
print |
|
49 | print 'Calling my own editor, jed ... via hook!' | |
50 | import os |
|
50 | import os | |
51 | if linenum is None: linenum = 0 |
|
51 | if linenum is None: linenum = 0 | |
52 | os.system('jed +%d %s' % (linenum, filename)) |
|
52 | os.system('jed +%d %s' % (linenum, filename)) | |
53 |
print |
|
53 | print 'exiting jed' | |
54 |
|
54 | |||
55 | ip.set_hook('editor',jed_editor) |
|
55 | ip.set_hook('editor',jed_editor) | |
56 |
|
56 | |||
57 | o = ip.options |
|
57 | o = ip.options | |
58 | o.autocall = 2 # FULL autocall mode |
|
58 | o.autocall = 2 # FULL autocall mode | |
59 |
|
59 | |||
60 |
print |
|
60 | print 'done!' | |
61 | ''' |
|
61 | """ | |
|
62 | ||||
|
63 | #----------------------------------------------------------------------------- | |||
|
64 | # Modules and globals | |||
62 |
|
65 | |||
63 | # stdlib imports |
|
66 | # stdlib imports | |
64 | import __builtin__ |
|
67 | import __builtin__ | |
65 | import sys |
|
68 | import sys | |
66 |
|
69 | |||
67 | try: # Python 2.3 compatibility |
|
70 | # contains the most recently instantiated IPApi | |
68 | set |
|
71 | _RECENT_IP = None | |
69 | except NameError: |
|
72 | ||
70 | import sets |
|
73 | #----------------------------------------------------------------------------- | |
71 | set = sets.Set |
|
74 | # Code begins | |
72 |
|
75 | |||
73 | # our own |
|
|||
74 | #from IPython.genutils import warn,error |
|
|||
75 |
|
||||
76 | class TryNext(Exception): |
|
76 | class TryNext(Exception): | |
77 | """Try next hook exception. |
|
77 | """Try next hook exception. | |
78 |
|
78 | |||
@@ -86,6 +86,7 b' class TryNext(Exception):' | |||||
86 | self.args = args |
|
86 | self.args = args | |
87 | self.kwargs = kwargs |
|
87 | self.kwargs = kwargs | |
88 |
|
88 | |||
|
89 | ||||
89 | class UsageError(Exception): |
|
90 | class UsageError(Exception): | |
90 | """ Error in magic function arguments, etc. |
|
91 | """ Error in magic function arguments, etc. | |
91 |
|
92 | |||
@@ -93,6 +94,7 b' class UsageError(Exception):' | |||||
93 | nevertheless interrupt a macro / batch file. |
|
94 | nevertheless interrupt a macro / batch file. | |
94 | """ |
|
95 | """ | |
95 |
|
96 | |||
|
97 | ||||
96 | class IPyAutocall: |
|
98 | class IPyAutocall: | |
97 | """ Instances of this class are always autocalled |
|
99 | """ Instances of this class are always autocalled | |
98 |
|
100 | |||
@@ -109,8 +111,6 b' class IPyAutocall:' | |||||
109 | self._ip = ip |
|
111 | self._ip = ip | |
110 |
|
112 | |||
111 |
|
113 | |||
112 | # contains the most recently instantiated IPApi |
|
|||
113 |
|
||||
114 | class IPythonNotRunning: |
|
114 | class IPythonNotRunning: | |
115 | """Dummy do-nothing class. |
|
115 | """Dummy do-nothing class. | |
116 |
|
116 | |||
@@ -144,8 +144,6 b' class IPythonNotRunning:' | |||||
144 | """Dummy function, which doesn't do anything and emits no warnings.""" |
|
144 | """Dummy function, which doesn't do anything and emits no warnings.""" | |
145 | pass |
|
145 | pass | |
146 |
|
146 | |||
147 | _recent = None |
|
|||
148 |
|
||||
149 |
|
147 | |||
150 | def get(allow_dummy=False,dummy_warn=True): |
|
148 | def get(allow_dummy=False,dummy_warn=True): | |
151 | """Get an IPApi object. |
|
149 | """Get an IPApi object. | |
@@ -159,12 +157,13 b' def get(allow_dummy=False,dummy_warn=True):' | |||||
159 | can be imported as normal modules. You can then direct all the |
|
157 | can be imported as normal modules. You can then direct all the | |
160 | configuration operations against the returned object. |
|
158 | configuration operations against the returned object. | |
161 | """ |
|
159 | """ | |
162 |
global _ |
|
160 | global _RECENT_IP | |
163 |
if allow_dummy and not _ |
|
161 | if allow_dummy and not _RECENT_IP: | |
164 |
_ |
|
162 | _RECENT_IP = IPythonNotRunning(dummy_warn) | |
165 |
return _ |
|
163 | return _RECENT_IP | |
|
164 | ||||
166 |
|
165 | |||
167 | class IPApi: |
|
166 | class IPApi(object): | |
168 | """ The actual API class for configuring IPython |
|
167 | """ The actual API class for configuring IPython | |
169 |
|
168 | |||
170 | You should do all of the IPython configuration by getting an IPApi object |
|
169 | You should do all of the IPython configuration by getting an IPApi object | |
@@ -173,6 +172,8 b' class IPApi:' | |||||
173 |
|
172 | |||
174 | def __init__(self,ip): |
|
173 | def __init__(self,ip): | |
175 |
|
174 | |||
|
175 | global _RECENT_IP | |||
|
176 | ||||
176 | # All attributes exposed here are considered to be the public API of |
|
177 | # All attributes exposed here are considered to be the public API of | |
177 | # IPython. As needs dictate, some of these may be wrapped as |
|
178 | # IPython. As needs dictate, some of these may be wrapped as | |
178 | # properties. |
|
179 | # properties. | |
@@ -201,8 +202,7 b' class IPApi:' | |||||
201 |
|
202 | |||
202 | self.dbg = DebugTools(self) |
|
203 | self.dbg = DebugTools(self) | |
203 |
|
204 | |||
204 | global _recent |
|
205 | _RECENT_IP = self | |
205 | _recent = self |
|
|||
206 |
|
206 | |||
207 | # Use a property for some things which are added to the instance very |
|
207 | # Use a property for some things which are added to the instance very | |
208 | # late. I don't have time right now to disentangle the initialization |
|
208 | # late. I don't have time right now to disentangle the initialization | |
@@ -218,8 +218,8 b' class IPApi:' | |||||
218 | """All configurable variables.""" |
|
218 | """All configurable variables.""" | |
219 |
|
219 | |||
220 | # catch typos by disabling new attribute creation. If new attr creation |
|
220 | # catch typos by disabling new attribute creation. If new attr creation | |
221 |
# is in fact wanted (e.g. when exposing new options), do |
|
221 | # is in fact wanted (e.g. when exposing new options), do | |
222 | # for the received rc struct. |
|
222 | # allow_new_attr(True) for the received rc struct. | |
223 |
|
223 | |||
224 | self.IP.rc.allow_new_attr(False) |
|
224 | self.IP.rc.allow_new_attr(False) | |
225 | return self.IP.rc |
|
225 | return self.IP.rc | |
@@ -227,22 +227,23 b' class IPApi:' | |||||
227 | options = property(get_options,None,None,get_options.__doc__) |
|
227 | options = property(get_options,None,None,get_options.__doc__) | |
228 |
|
228 | |||
229 | def expose_magic(self,magicname, func): |
|
229 | def expose_magic(self,magicname, func): | |
230 |
|
|
230 | """Expose own function as magic function for ipython | |
231 |
|
231 | |||
232 | def foo_impl(self,parameter_s=''): |
|
232 | def foo_impl(self,parameter_s=''): | |
233 |
|
|
233 | 'My very own magic!. (Use docstrings, IPython reads them).' | |
234 |
print 'Magic function. Passed parameter is between < >: |
|
234 | print 'Magic function. Passed parameter is between < >:' | |
|
235 | print '<%s>' % parameter_s | |||
235 | print 'The self object is:',self |
|
236 | print 'The self object is:',self | |
236 |
|
237 | |||
237 |
ipapi.expose_magic( |
|
238 | ipapi.expose_magic('foo',foo_impl) | |
238 |
|
|
239 | """ | |
239 |
|
|
240 | ||
240 | import new |
|
241 | import new | |
241 | im = new.instancemethod(func,self.IP, self.IP.__class__) |
|
242 | im = new.instancemethod(func,self.IP, self.IP.__class__) | |
242 | old = getattr(self.IP, "magic_" + magicname, None) |
|
243 | old = getattr(self.IP, "magic_" + magicname, None) | |
243 | if old: |
|
244 | if old: | |
244 |
self.dbg.debug_stack("Magic redefinition '%s', old %s" % |
|
245 | self.dbg.debug_stack("Magic redefinition '%s', old %s" % | |
245 | old)) |
|
246 | (magicname,old) ) | |
246 |
|
247 | |||
247 | setattr(self.IP, "magic_" + magicname, im) |
|
248 | setattr(self.IP, "magic_" + magicname, im) | |
248 |
|
249 | |||
@@ -267,10 +268,10 b' class IPApi:' | |||||
267 | def cleanup_ipy_script(script): |
|
268 | def cleanup_ipy_script(script): | |
268 | """ Make a script safe for _ip.runlines() |
|
269 | """ Make a script safe for _ip.runlines() | |
269 |
|
270 | |||
270 | - Removes empty lines |
|
271 | - Removes empty lines Suffixes all indented blocks that end with | |
271 |
- |
|
272 | - unindented lines with empty lines | |
272 |
|
||||
273 | """ |
|
273 | """ | |
|
274 | ||||
274 | res = [] |
|
275 | res = [] | |
275 | lines = script.splitlines() |
|
276 | lines = script.splitlines() | |
276 |
|
277 | |||
@@ -290,7 +291,8 b' class IPApi:' | |||||
290 | s.startswith('finally')): |
|
291 | s.startswith('finally')): | |
291 | return True |
|
292 | return True | |
292 |
|
293 | |||
293 |
if level > 0 and newlevel == 0 and |
|
294 | if level > 0 and newlevel == 0 and \ | |
|
295 | not is_secondary_block_start(stripped): | |||
294 | # add empty line |
|
296 | # add empty line | |
295 | res.append('') |
|
297 | res.append('') | |
296 |
|
298 | |||
@@ -303,8 +305,9 b' class IPApi:' | |||||
303 | else: |
|
305 | else: | |
304 | script = '\n'.join(lines) |
|
306 | script = '\n'.join(lines) | |
305 | clean=cleanup_ipy_script(script) |
|
307 | clean=cleanup_ipy_script(script) | |
306 | # print "_ip.runlines() script:\n",clean #dbg |
|
308 | # print "_ip.runlines() script:\n",clean # dbg | |
307 | self.IP.runlines(clean) |
|
309 | self.IP.runlines(clean) | |
|
310 | ||||
308 | def to_user_ns(self,vars, interactive = True): |
|
311 | def to_user_ns(self,vars, interactive = True): | |
309 | """Inject a group of variables into the IPython user namespace. |
|
312 | """Inject a group of variables into the IPython user namespace. | |
310 |
|
313 | |||
@@ -392,7 +395,6 b' class IPApi:' | |||||
392 | for name,val in vdict.iteritems(): |
|
395 | for name,val in vdict.iteritems(): | |
393 | config_ns[name] = val |
|
396 | config_ns[name] = val | |
394 |
|
397 | |||
395 |
|
||||
396 | def expand_alias(self,line): |
|
398 | def expand_alias(self,line): | |
397 | """ Expand an alias in the command line |
|
399 | """ Expand an alias in the command line | |
398 |
|
400 | |||
@@ -425,11 +427,9 b' class IPApi:' | |||||
425 |
|
427 | |||
426 | self.dbg.check_hotname(name) |
|
428 | self.dbg.check_hotname(name) | |
427 |
|
429 | |||
428 |
|
||||
429 | if name in self.IP.alias_table: |
|
430 | if name in self.IP.alias_table: | |
430 |
self.dbg.debug_stack("Alias redefinition: '%s' => '%s' (old '%s')" |
|
431 | self.dbg.debug_stack("Alias redefinition: '%s' => '%s' (old '%s')" | |
431 | (name, cmd, self.IP.alias_table[name])) |
|
432 | % (name, cmd, self.IP.alias_table[name])) | |
432 |
|
||||
433 |
|
433 | |||
434 | if callable(cmd): |
|
434 | if callable(cmd): | |
435 | self.IP.alias_table[name] = cmd |
|
435 | self.IP.alias_table[name] = cmd | |
@@ -440,8 +440,8 b' class IPApi:' | |||||
440 | if isinstance(cmd,basestring): |
|
440 | if isinstance(cmd,basestring): | |
441 | nargs = cmd.count('%s') |
|
441 | nargs = cmd.count('%s') | |
442 | if nargs>0 and cmd.find('%l')>=0: |
|
442 | if nargs>0 and cmd.find('%l')>=0: | |
443 |
raise Exception('The %s and %l specifiers are mutually |
|
443 | raise Exception('The %s and %l specifiers are mutually ' | |
444 | 'in alias definitions.') |
|
444 | 'exclusive in alias definitions.') | |
445 |
|
445 | |||
446 | self.IP.alias_table[name] = (nargs,cmd) |
|
446 | self.IP.alias_table[name] = (nargs,cmd) | |
447 | return |
|
447 | return | |
@@ -494,8 +494,8 b' class IPApi:' | |||||
494 |
|
494 | |||
495 | - run init_ipython(ip) |
|
495 | - run init_ipython(ip) | |
496 | - run ipython_firstrun(ip) |
|
496 | - run ipython_firstrun(ip) | |
497 |
|
||||
498 | """ |
|
497 | """ | |
|
498 | ||||
499 | if mod in self.extensions: |
|
499 | if mod in self.extensions: | |
500 | # just to make sure we don't init it twice |
|
500 | # just to make sure we don't init it twice | |
501 | # note that if you 'load' a module that has already been |
|
501 | # note that if you 'load' a module that has already been | |
@@ -545,6 +545,7 b' class DebugTools:' | |||||
545 | if name in self.hotnames: |
|
545 | if name in self.hotnames: | |
546 | self.debug_stack( "HotName '%s' caught" % name) |
|
546 | self.debug_stack( "HotName '%s' caught" % name) | |
547 |
|
547 | |||
|
548 | ||||
548 | def launch_new_instance(user_ns = None,shellclass = None): |
|
549 | def launch_new_instance(user_ns = None,shellclass = None): | |
549 | """ Make and start a new ipython instance. |
|
550 | """ Make and start a new ipython instance. | |
550 |
|
551 |
@@ -212,13 +212,7 b' class InteractiveShell(object,Magic):' | |||||
212 |
|
212 | |||
213 | # log system |
|
213 | # log system | |
214 | self.logger = Logger(self,logfname='ipython_log.py',logmode='rotate') |
|
214 | self.logger = Logger(self,logfname='ipython_log.py',logmode='rotate') | |
215 |
|
215 | |||
216 | # some minimal strict typechecks. For some core data structures, I |
|
|||
217 | # want actual basic python types, not just anything that looks like |
|
|||
218 | # one. This is especially true for namespaces. |
|
|||
219 | for ns in (user_ns,user_global_ns): |
|
|||
220 | if ns is not None and type(ns) != types.DictType: |
|
|||
221 | raise TypeError,'namespace must be a dictionary' |
|
|||
222 | # Job manager (for jobs run as background threads) |
|
216 | # Job manager (for jobs run as background threads) | |
223 | self.jobs = BackgroundJobManager() |
|
217 | self.jobs = BackgroundJobManager() | |
224 |
|
218 | |||
@@ -1007,10 +1001,17 b' class InteractiveShell(object,Magic):' | |||||
1007 |
|
1001 | |||
1008 | Simple usage example: |
|
1002 | Simple usage example: | |
1009 |
|
1003 | |||
1010 |
In [ |
|
1004 | In [7]: x = 'hello' | |
|
1005 | ||||
|
1006 | In [8]: x | |||
|
1007 | Out[8]: 'hello' | |||
1011 |
|
1008 | |||
1012 |
In [ |
|
1009 | In [9]: print x | |
1013 | Out[2]: ['x.ljust', 'x.lower', 'x.lstrip']""" |
|
1010 | hello | |
|
1011 | ||||
|
1012 | In [10]: _ip.IP.complete('x.l') | |||
|
1013 | Out[10]: ['x.ljust', 'x.lower', 'x.lstrip'] # random | |||
|
1014 | """ | |||
1014 |
|
1015 | |||
1015 | complete = self.Completer.complete |
|
1016 | complete = self.Completer.complete | |
1016 | state = 0 |
|
1017 | state = 0 | |
@@ -1026,6 +1027,8 b' class InteractiveShell(object,Magic):' | |||||
1026 | state += 1 |
|
1027 | state += 1 | |
1027 | outcomps = comps.keys() |
|
1028 | outcomps = comps.keys() | |
1028 | outcomps.sort() |
|
1029 | outcomps.sort() | |
|
1030 | #print "T:",text,"OC:",outcomps # dbg | |||
|
1031 | #print "vars:",self.user_ns.keys() | |||
1029 | return outcomps |
|
1032 | return outcomps | |
1030 |
|
1033 | |||
1031 | def set_completer_frame(self, frame=None): |
|
1034 | def set_completer_frame(self, frame=None): | |
@@ -1636,6 +1639,7 b' want to merge them back into the new files.""" % locals()' | |||||
1636 | # previous call (which most likely existed in a separate scope). |
|
1639 | # previous call (which most likely existed in a separate scope). | |
1637 | local_varnames = local_ns.keys() |
|
1640 | local_varnames = local_ns.keys() | |
1638 | self.user_ns.update(local_ns) |
|
1641 | self.user_ns.update(local_ns) | |
|
1642 | #self.user_ns['local_ns'] = local_ns # dbg | |||
1639 |
|
1643 | |||
1640 | # Patch for global embedding to make sure that things don't overwrite |
|
1644 | # Patch for global embedding to make sure that things don't overwrite | |
1641 | # user globals accidentally. Thanks to Richard <rxe@renre-europe.com> |
|
1645 | # user globals accidentally. Thanks to Richard <rxe@renre-europe.com> | |
@@ -2362,14 +2366,15 b' want to merge them back into the new files.""" % locals()' | |||||
2362 | def handle_auto(self, line_info): |
|
2366 | def handle_auto(self, line_info): | |
2363 | """Hande lines which can be auto-executed, quoting if requested.""" |
|
2367 | """Hande lines which can be auto-executed, quoting if requested.""" | |
2364 |
|
2368 | |||
2365 | #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg |
|
|||
2366 | line = line_info.line |
|
2369 | line = line_info.line | |
2367 | iFun = line_info.iFun |
|
2370 | iFun = line_info.iFun | |
2368 | theRest = line_info.theRest |
|
2371 | theRest = line_info.theRest | |
2369 | pre = line_info.pre |
|
2372 | pre = line_info.pre | |
2370 | continue_prompt = line_info.continue_prompt |
|
2373 | continue_prompt = line_info.continue_prompt | |
2371 | obj = line_info.ofind(self)['obj'] |
|
2374 | obj = line_info.ofind(self)['obj'] | |
2372 |
|
2375 | |||
|
2376 | #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg | |||
|
2377 | ||||
2373 | # This should only be active for single-line input! |
|
2378 | # This should only be active for single-line input! | |
2374 | if continue_prompt: |
|
2379 | if continue_prompt: | |
2375 | self.log(line,line,continue_prompt) |
|
2380 | self.log(line,line,continue_prompt) |
@@ -88,8 +88,8 b' class Struct:' | |||||
88 | initialization): keys can't be numbers. But numeric keys can be used and |
|
88 | initialization): keys can't be numbers. But numeric keys can be used and | |
89 | accessed using the dictionary syntax. Again, an example: |
|
89 | accessed using the dictionary syntax. Again, an example: | |
90 |
|
90 | |||
91 | This doesn't work: |
|
91 | This doesn't work (prompt changed to avoid confusing the test system): | |
92 | >>> s=Struct(4='hi') #doctest: +IGNORE_EXCEPTION_DETAIL |
|
92 | ->> s=Struct(4='hi') | |
93 | Traceback (most recent call last): |
|
93 | Traceback (most recent call last): | |
94 | ... |
|
94 | ... | |
95 | SyntaxError: keyword can't be an expression |
|
95 | SyntaxError: keyword can't be an expression |
@@ -27,7 +27,7 b' from IPython.kernel import codeutil' | |||||
27 | from IPython.kernel.clientconnector import ClientConnector |
|
27 | from IPython.kernel.clientconnector import ClientConnector | |
28 |
|
28 | |||
29 | # Other things that the user will need |
|
29 | # Other things that the user will need | |
30 | from IPython.kernel.task import Task |
|
30 | from IPython.kernel.task import MapTask, StringTask | |
31 | from IPython.kernel.error import CompositeError |
|
31 | from IPython.kernel.error import CompositeError | |
32 |
|
32 | |||
33 | #------------------------------------------------------------------------------- |
|
33 | #------------------------------------------------------------------------------- |
@@ -44,7 +44,7 b' from IPython.kernel import codeutil' | |||||
44 | import IPython.kernel.magic |
|
44 | import IPython.kernel.magic | |
45 |
|
45 | |||
46 | # Other things that the user will need |
|
46 | # Other things that the user will need | |
47 | from IPython.kernel.task import Task |
|
47 | from IPython.kernel.task import MapTask, StringTask | |
48 | from IPython.kernel.error import CompositeError |
|
48 | from IPython.kernel.error import CompositeError | |
49 |
|
49 | |||
50 | #------------------------------------------------------------------------------- |
|
50 | #------------------------------------------------------------------------------- |
@@ -48,7 +48,7 b' def strip_whitespace(source,require_remote=True):' | |||||
48 | """strip leading whitespace from input source. |
|
48 | """strip leading whitespace from input source. | |
49 |
|
49 | |||
50 | :Parameters: |
|
50 | :Parameters: | |
51 |
|
51 | |||
52 | """ |
|
52 | """ | |
53 | remote_mark = 'remote()' |
|
53 | remote_mark = 'remote()' | |
54 | # Expand tabs to avoid any confusion. |
|
54 | # Expand tabs to avoid any confusion. | |
@@ -101,7 +101,7 b' def strip_whitespace(source,require_remote=True):' | |||||
101 | class RemoteContextBase(object): |
|
101 | class RemoteContextBase(object): | |
102 | def __init__(self): |
|
102 | def __init__(self): | |
103 | self.ip = ipapi.get() |
|
103 | self.ip = ipapi.get() | |
104 |
|
104 | |||
105 | def _findsource_file(self,f): |
|
105 | def _findsource_file(self,f): | |
106 | linecache.checkcache() |
|
106 | linecache.checkcache() | |
107 | s = findsource(f.f_code) |
|
107 | s = findsource(f.f_code) | |
@@ -113,10 +113,10 b' class RemoteContextBase(object):' | |||||
113 | from IPython import ipapi |
|
113 | from IPython import ipapi | |
114 | self.ip = ipapi.get() |
|
114 | self.ip = ipapi.get() | |
115 | buf = self.ip.IP.input_hist_raw[-1].splitlines()[1:] |
|
115 | buf = self.ip.IP.input_hist_raw[-1].splitlines()[1:] | |
116 |
wsource = [l+'\n' for l in buf ] |
|
116 | wsource = [l+'\n' for l in buf ] | |
117 |
|
117 | |||
118 | return strip_whitespace(wsource) |
|
118 | return strip_whitespace(wsource) | |
119 |
|
119 | |||
120 | def findsource(self,frame): |
|
120 | def findsource(self,frame): | |
121 | local_ns = frame.f_locals |
|
121 | local_ns = frame.f_locals | |
122 | global_ns = frame.f_globals |
|
122 | global_ns = frame.f_globals | |
@@ -128,7 +128,7 b' class RemoteContextBase(object):' | |||||
128 |
|
128 | |||
129 | def __enter__(self): |
|
129 | def __enter__(self): | |
130 | raise NotImplementedError |
|
130 | raise NotImplementedError | |
131 |
|
131 | |||
132 | def __exit__ (self, etype, value, tb): |
|
132 | def __exit__ (self, etype, value, tb): | |
133 | if issubclass(etype,error.StopLocalExecution): |
|
133 | if issubclass(etype,error.StopLocalExecution): | |
134 | return True |
|
134 | return True | |
@@ -141,38 +141,3 b' class RemoteMultiEngine(RemoteContextBase):' | |||||
141 | def __enter__(self): |
|
141 | def __enter__(self): | |
142 | src = self.findsource(sys._getframe(1)) |
|
142 | src = self.findsource(sys._getframe(1)) | |
143 | return self.mec.execute(src) |
|
143 | return self.mec.execute(src) | |
144 |
|
||||
145 |
|
||||
146 | # XXX - Temporary hackish testing, we'll move this into proper tests right |
|
|||
147 | # away |
|
|||
148 |
|
||||
149 | if __name__ == '__main__': |
|
|||
150 |
|
||||
151 | # XXX - for now, we need a running cluster to be started separately. The |
|
|||
152 | # daemon work is almost finished, and will make much of this unnecessary. |
|
|||
153 | from IPython.kernel import client |
|
|||
154 | mec = client.MultiEngineClient(('127.0.0.1',10105)) |
|
|||
155 |
|
||||
156 | try: |
|
|||
157 | mec.get_ids() |
|
|||
158 | except ConnectionRefusedError: |
|
|||
159 | import os, time |
|
|||
160 | os.system('ipcluster -n 2 &') |
|
|||
161 | time.sleep(2) |
|
|||
162 | mec = client.MultiEngineClient(('127.0.0.1',10105)) |
|
|||
163 |
|
||||
164 | mec.block = False |
|
|||
165 |
|
||||
166 | import itertools |
|
|||
167 | c = itertools.count() |
|
|||
168 |
|
||||
169 | parallel = RemoteMultiEngine(mec) |
|
|||
170 |
|
||||
171 | with parallel as pr: |
|
|||
172 | # A comment |
|
|||
173 | remote() # this means the code below only runs remotely |
|
|||
174 | print 'Hello remote world' |
|
|||
175 | x = 3.14 |
|
|||
176 | # Comments are OK |
|
|||
177 | # Even misindented. |
|
|||
178 | y = x+1 |
|
@@ -226,29 +226,31 b' class IEngineThreaded(zi.Interface):' | |||||
226 | class StrictDict(dict): |
|
226 | class StrictDict(dict): | |
227 | """This is a strict copying dictionary for use as the interface to the |
|
227 | """This is a strict copying dictionary for use as the interface to the | |
228 | properties of an Engine. |
|
228 | properties of an Engine. | |
|
229 | ||||
229 | :IMPORTANT: |
|
230 | :IMPORTANT: | |
230 | This object copies the values you set to it, and returns copies to you |
|
231 | This object copies the values you set to it, and returns copies to you | |
231 | when you request them. The only way to change properties os explicitly |
|
232 | when you request them. The only way to change properties os explicitly | |
232 | through the setitem and getitem of the dictionary interface. |
|
233 | through the setitem and getitem of the dictionary interface. | |
233 | Example: |
|
234 | ||
234 | >>> e = kernel.get_engine(id) |
|
235 | Example: | |
235 |
>>> |
|
236 | >>> e = get_engine(id) | |
|
237 | >>> L = [1,2,3] | |||
236 | >>> e.properties['L'] = L |
|
238 | >>> e.properties['L'] = L | |
237 | >>> L == e.properties['L'] |
|
239 | >>> L == e.properties['L'] | |
238 |
|
|
240 | True | |
239 |
>>> L.append( |
|
241 | >>> L.append(99) | |
240 | >>> L == e.properties['L'] |
|
242 | >>> L == e.properties['L'] | |
241 |
|
|
243 | False | |
|
244 | ||||
|
245 | Note that getitem copies, so calls to methods of objects do not affect | |||
|
246 | the properties, as seen here: | |||
242 |
|
247 | |||
243 | getitem copies, so calls to methods of objects do not affect the |
|
|||
244 | properties, as in the following example: |
|
|||
245 | >>> e.properties[1] = range(2) |
|
248 | >>> e.properties[1] = range(2) | |
246 | >>> print e.properties[1] |
|
249 | >>> print e.properties[1] | |
247 |
|
|
250 | [0, 1] | |
248 | >>> e.properties[1].append(2) |
|
251 | >>> e.properties[1].append(2) | |
249 | >>> print e.properties[1] |
|
252 | >>> print e.properties[1] | |
250 |
|
|
253 | [0, 1] | |
251 |
|
||||
252 | """ |
|
254 | """ | |
253 | def __init__(self, *args, **kwargs): |
|
255 | def __init__(self, *args, **kwargs): | |
254 | dict.__init__(self, *args, **kwargs) |
|
256 | dict.__init__(self, *args, **kwargs) | |
@@ -395,6 +397,7 b' class EngineService(object, service.Service):' | |||||
395 |
|
397 | |||
396 | return d |
|
398 | return d | |
397 |
|
399 | |||
|
400 | ||||
398 | # The IEngine methods. See the interface for documentation. |
|
401 | # The IEngine methods. See the interface for documentation. | |
399 |
|
402 | |||
400 | def execute(self, lines): |
|
403 | def execute(self, lines): | |
@@ -862,6 +865,30 b' class ThreadedEngineService(EngineService):' | |||||
862 | def __init__(self, shellClass=Interpreter, mpi=None): |
|
865 | def __init__(self, shellClass=Interpreter, mpi=None): | |
863 | EngineService.__init__(self, shellClass, mpi) |
|
866 | EngineService.__init__(self, shellClass, mpi) | |
864 |
|
867 | |||
|
868 | def wrapped_execute(self, msg, lines): | |||
|
869 | """Wrap self.shell.execute to add extra information to tracebacks""" | |||
|
870 | ||||
|
871 | try: | |||
|
872 | result = self.shell.execute(lines) | |||
|
873 | except Exception,e: | |||
|
874 | # This gives the following: | |||
|
875 | # et=exception class | |||
|
876 | # ev=exception class instance | |||
|
877 | # tb=traceback object | |||
|
878 | et,ev,tb = sys.exc_info() | |||
|
879 | # This call adds attributes to the exception value | |||
|
880 | et,ev,tb = self.shell.formatTraceback(et,ev,tb,msg) | |||
|
881 | # Add another attribute | |||
|
882 | ||||
|
883 | # Create a new exception with the new attributes | |||
|
884 | e = et(ev._ipython_traceback_text) | |||
|
885 | e._ipython_engine_info = msg | |||
|
886 | ||||
|
887 | # Re-raise | |||
|
888 | raise e | |||
|
889 | ||||
|
890 | return result | |||
|
891 | ||||
865 |
|
892 | |||
866 | def execute(self, lines): |
|
893 | def execute(self, lines): | |
867 | # Only import this if we are going to use this class |
|
894 | # Only import this if we are going to use this class | |
@@ -871,6 +898,6 b' class ThreadedEngineService(EngineService):' | |||||
871 | 'method':'execute', |
|
898 | 'method':'execute', | |
872 | 'args':[lines]} |
|
899 | 'args':[lines]} | |
873 |
|
900 | |||
874 |
d = threads.deferToThread(self. |
|
901 | d = threads.deferToThread(self.wrapped_execute, msg, lines) | |
875 | d.addCallback(self.addIDToResult) |
|
902 | d.addCallback(self.addIDToResult) | |
876 | return d |
|
903 | return d |
@@ -79,7 +79,7 b" def magic_px(self,parameter_s=''):" | |||||
79 | except AttributeError: |
|
79 | except AttributeError: | |
80 | print NO_ACTIVE_CONTROLLER |
|
80 | print NO_ACTIVE_CONTROLLER | |
81 | else: |
|
81 | else: | |
82 | print "Executing command on Controller" |
|
82 | print "Parallel execution on engines: %s" % activeController.targets | |
83 | result = activeController.execute(parameter_s) |
|
83 | result = activeController.execute(parameter_s) | |
84 | return result |
|
84 | return result | |
85 |
|
85 |
@@ -115,7 +115,7 b' class RoundRobinMap(Map):' | |||||
115 | # result.append(concat[i:totalLength:maxPartitionLength]) |
|
115 | # result.append(concat[i:totalLength:maxPartitionLength]) | |
116 | return self.concatenate(listOfPartitions) |
|
116 | return self.concatenate(listOfPartitions) | |
117 |
|
117 | |||
118 |
st |
|
118 | dists = {'b':Map} | |
119 |
|
119 | |||
120 |
|
120 | |||
121 |
|
121 |
@@ -653,67 +653,55 b' components.registerAdapter(SynchronousMultiEngine, IMultiEngine, ISynchronousMul' | |||||
653 | class IMultiEngineCoordinator(Interface): |
|
653 | class IMultiEngineCoordinator(Interface): | |
654 | """Methods that work on multiple engines explicitly.""" |
|
654 | """Methods that work on multiple engines explicitly.""" | |
655 |
|
655 | |||
656 |
def scatter(key, seq, st |
|
656 | def scatter(key, seq, dist='b', flatten=False, targets='all'): | |
657 | """Partition and distribute a sequence to targets. |
|
657 | """Partition and distribute a sequence to targets.""" | |
658 |
|
658 | |||
659 | :Parameters: |
|
659 | def gather(key, dist='b', targets='all'): | |
660 | key : str |
|
660 | """Gather object key from targets.""" | |
661 | The variable name to call the scattered sequence. |
|
|||
662 | seq : list, tuple, array |
|
|||
663 | The sequence to scatter. The type should be preserved. |
|
|||
664 | style : string |
|
|||
665 | A specification of how the sequence is partitioned. Currently |
|
|||
666 | only 'basic' is implemented. |
|
|||
667 | flatten : boolean |
|
|||
668 | Should single element sequences be converted to scalars. |
|
|||
669 | """ |
|
|||
670 |
|
||||
671 | def gather(key, style='basic', targets='all'): |
|
|||
672 | """Gather object key from targets. |
|
|||
673 |
|
661 | |||
674 | :Parameters: |
|
662 | def raw_map(func, seqs, dist='b', targets='all'): | |
675 | key : string |
|
|||
676 | The name of a sequence on the targets to gather. |
|
|||
677 | style : string |
|
|||
678 | A specification of how the sequence is partitioned. Currently |
|
|||
679 | only 'basic' is implemented. |
|
|||
680 |
|
|
663 | """ | |
681 |
|
664 | A parallelized version of Python's builtin `map` function. | ||
682 | def map(func, seq, style='basic', targets='all'): |
|
|||
683 | """A parallelized version of Python's builtin map. |
|
|||
684 |
|
665 | |||
685 | This function implements the following pattern: |
|
666 | This has a slightly different syntax than the builtin `map`. | |
|
667 | This is needed because we need to have keyword arguments and thus | |||
|
668 | can't use *args to capture all the sequences. Instead, they must | |||
|
669 | be passed in a list or tuple. | |||
686 |
|
670 | |||
687 | 1. The sequence seq is scattered to the given targets. |
|
671 | The equivalence is: | |
688 | 2. map(functionSource, seq) is called on each engine. |
|
|||
689 | 3. The resulting sequences are gathered back to the local machine. |
|
|||
690 |
|
||||
691 | :Parameters: |
|
|||
692 | targets : int, list or 'all' |
|
|||
693 | The engine ids the action will apply to. Call `get_ids` to see |
|
|||
694 | a list of currently available engines. |
|
|||
695 | func : str, function |
|
|||
696 | An actual function object or a Python string that names a |
|
|||
697 | callable defined on the engines. |
|
|||
698 | seq : list, tuple or numpy array |
|
|||
699 | The local sequence to be scattered. |
|
|||
700 | style : str |
|
|||
701 | Only 'basic' is supported for now. |
|
|||
702 |
|
||||
703 | :Returns: A list of len(seq) with functionSource called on each element |
|
|||
704 | of seq. |
|
|||
705 |
|
||||
706 | Example |
|
|||
707 | ======= |
|
|||
708 |
|
672 | |||
709 | >>> rc.mapAll('lambda x: x*x', range(10000)) |
|
673 | raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...) | |
710 | [0,2,4,9,25,36,...] |
|
674 | ||
|
675 | Most users will want to use parallel functions or the `mapper` | |||
|
676 | and `map` methods for an API that follows that of the builtin | |||
|
677 | `map`. | |||
711 | """ |
|
678 | """ | |
712 |
|
679 | |||
713 |
|
680 | |||
714 | class ISynchronousMultiEngineCoordinator(IMultiEngineCoordinator): |
|
681 | class ISynchronousMultiEngineCoordinator(IMultiEngineCoordinator): | |
715 | """Methods that work on multiple engines explicitly.""" |
|
682 | """Methods that work on multiple engines explicitly.""" | |
716 | pass |
|
683 | ||
|
684 | def scatter(key, seq, dist='b', flatten=False, targets='all', block=True): | |||
|
685 | """Partition and distribute a sequence to targets.""" | |||
|
686 | ||||
|
687 | def gather(key, dist='b', targets='all', block=True): | |||
|
688 | """Gather object key from targets""" | |||
|
689 | ||||
|
690 | def raw_map(func, seqs, dist='b', targets='all', block=True): | |||
|
691 | """ | |||
|
692 | A parallelized version of Python's builtin map. | |||
|
693 | ||||
|
694 | This has a slightly different syntax than the builtin `map`. | |||
|
695 | This is needed because we need to have keyword arguments and thus | |||
|
696 | can't use *args to capture all the sequences. Instead, they must | |||
|
697 | be passed in a list or tuple. | |||
|
698 | ||||
|
699 | raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...) | |||
|
700 | ||||
|
701 | Most users will want to use parallel functions or the `mapper` | |||
|
702 | and `map` methods for an API that follows that of the builtin | |||
|
703 | `map`. | |||
|
704 | """ | |||
717 |
|
705 | |||
718 |
|
706 | |||
719 | #------------------------------------------------------------------------------- |
|
707 | #------------------------------------------------------------------------------- | |
@@ -722,46 +710,31 b' class ISynchronousMultiEngineCoordinator(IMultiEngineCoordinator):' | |||||
722 |
|
710 | |||
723 | class IMultiEngineExtras(Interface): |
|
711 | class IMultiEngineExtras(Interface): | |
724 |
|
712 | |||
725 |
def zip_pull(targets, |
|
713 | def zip_pull(targets, keys): | |
726 | """Pull, but return results in a different format from `pull`. |
|
714 | """ | |
|
715 | Pull, but return results in a different format from `pull`. | |||
727 |
|
716 | |||
728 | This method basically returns zip(pull(targets, *keys)), with a few |
|
717 | This method basically returns zip(pull(targets, *keys)), with a few | |
729 | edge cases handled differently. Users of chainsaw will find this format |
|
718 | edge cases handled differently. Users of chainsaw will find this format | |
730 | familiar. |
|
719 | familiar. | |
731 |
|
||||
732 | :Parameters: |
|
|||
733 | targets : int, list or 'all' |
|
|||
734 | The engine ids the action will apply to. Call `get_ids` to see |
|
|||
735 | a list of currently available engines. |
|
|||
736 | keys: list or tuple of str |
|
|||
737 | A list of variable names as string of the Python objects to be pulled |
|
|||
738 | back to the client. |
|
|||
739 |
|
||||
740 | :Returns: A list of pulled Python objects for each target. |
|
|||
741 | """ |
|
720 | """ | |
742 |
|
721 | |||
743 | def run(targets, fname): |
|
722 | def run(targets, fname): | |
744 | """Run a .py file on targets. |
|
723 | """Run a .py file on targets.""" | |
745 |
|
||||
746 | :Parameters: |
|
|||
747 | targets : int, list or 'all' |
|
|||
748 | The engine ids the action will apply to. Call `get_ids` to see |
|
|||
749 | a list of currently available engines. |
|
|||
750 | fname : str |
|
|||
751 | The filename of a .py file on the local system to be sent to and run |
|
|||
752 | on the engines. |
|
|||
753 | block : boolean |
|
|||
754 | Should I block or not. If block=True, wait for the action to |
|
|||
755 | complete and return the result. If block=False, return a |
|
|||
756 | `PendingResult` object that can be used to later get the |
|
|||
757 | result. If block is not specified, the block attribute |
|
|||
758 | will be used instead. |
|
|||
759 | """ |
|
|||
760 |
|
724 | |||
761 |
|
725 | |||
762 | class ISynchronousMultiEngineExtras(IMultiEngineExtras): |
|
726 | class ISynchronousMultiEngineExtras(IMultiEngineExtras): | |
763 | pass |
|
727 | def zip_pull(targets, keys, block=True): | |
764 |
|
728 | """ | ||
|
729 | Pull, but return results in a different format from `pull`. | |||
|
730 | ||||
|
731 | This method basically returns zip(pull(targets, *keys)), with a few | |||
|
732 | edge cases handled differently. Users of chainsaw will find this format | |||
|
733 | familiar. | |||
|
734 | """ | |||
|
735 | ||||
|
736 | def run(targets, fname, block=True): | |||
|
737 | """Run a .py file on targets.""" | |||
765 |
|
738 | |||
766 | #------------------------------------------------------------------------------- |
|
739 | #------------------------------------------------------------------------------- | |
767 | # The full MultiEngine interface |
|
740 | # The full MultiEngine interface |
@@ -31,6 +31,11 b' from IPython.ColorANSI import TermColors' | |||||
31 | from IPython.kernel.twistedutil import blockingCallFromThread |
|
31 | from IPython.kernel.twistedutil import blockingCallFromThread | |
32 | from IPython.kernel import error |
|
32 | from IPython.kernel import error | |
33 | from IPython.kernel.parallelfunction import ParallelFunction |
|
33 | from IPython.kernel.parallelfunction import ParallelFunction | |
|
34 | from IPython.kernel.mapper import ( | |||
|
35 | MultiEngineMapper, | |||
|
36 | IMultiEngineMapperFactory, | |||
|
37 | IMapper | |||
|
38 | ) | |||
34 | from IPython.kernel import map as Map |
|
39 | from IPython.kernel import map as Map | |
35 | from IPython.kernel import multiengine as me |
|
40 | from IPython.kernel import multiengine as me | |
36 | from IPython.kernel.multiengine import (IFullMultiEngine, |
|
41 | from IPython.kernel.multiengine import (IFullMultiEngine, | |
@@ -186,10 +191,14 b' class ResultList(list):' | |||||
186 |
|
191 | |||
187 | def __repr__(self): |
|
192 | def __repr__(self): | |
188 | output = [] |
|
193 | output = [] | |
189 | blue = TermColors.Blue |
|
194 | # These colored prompts were not working on Windows | |
190 | normal = TermColors.Normal |
|
195 | if sys.platform == 'win32': | |
191 | red = TermColors.Red |
|
196 | blue = normal = red = green = '' | |
192 | green = TermColors.Green |
|
197 | else: | |
|
198 | blue = TermColors.Blue | |||
|
199 | normal = TermColors.Normal | |||
|
200 | red = TermColors.Red | |||
|
201 | green = TermColors.Green | |||
193 | output.append("<Results List>\n") |
|
202 | output.append("<Results List>\n") | |
194 | for cmd in self: |
|
203 | for cmd in self: | |
195 | if isinstance(cmd, Failure): |
|
204 | if isinstance(cmd, Failure): | |
@@ -294,35 +303,7 b' class InteractiveMultiEngineClient(object):' | |||||
294 | def __len__(self): |
|
303 | def __len__(self): | |
295 | """Return the number of available engines.""" |
|
304 | """Return the number of available engines.""" | |
296 | return len(self.get_ids()) |
|
305 | return len(self.get_ids()) | |
297 |
|
|
306 | ||
298 | def parallelize(self, func, targets=None, block=None): |
|
|||
299 | """Build a `ParallelFunction` object for functionName on engines. |
|
|||
300 |
|
||||
301 | The returned object will implement a parallel version of functionName |
|
|||
302 | that takes a local sequence as its only argument and calls (in |
|
|||
303 | parallel) functionName on each element of that sequence. The |
|
|||
304 | `ParallelFunction` object has a `targets` attribute that controls |
|
|||
305 | which engines the function is run on. |
|
|||
306 |
|
||||
307 | :Parameters: |
|
|||
308 | targets : int, list or 'all' |
|
|||
309 | The engine ids the action will apply to. Call `get_ids` to see |
|
|||
310 | a list of currently available engines. |
|
|||
311 | functionName : str |
|
|||
312 | A Python string that names a callable defined on the engines. |
|
|||
313 |
|
||||
314 | :Returns: A `ParallelFunction` object. |
|
|||
315 |
|
||||
316 | Examples |
|
|||
317 | ======== |
|
|||
318 |
|
||||
319 | >>> psin = rc.parallelize('all','lambda x:sin(x)') |
|
|||
320 | >>> psin(range(10000)) |
|
|||
321 | [0,2,4,9,25,36,...] |
|
|||
322 | """ |
|
|||
323 | targets, block = self._findTargetsAndBlock(targets, block) |
|
|||
324 | return ParallelFunction(func, self, targets, block) |
|
|||
325 |
|
||||
326 | #--------------------------------------------------------------------------- |
|
307 | #--------------------------------------------------------------------------- | |
327 | # Make this a context manager for with |
|
308 | # Make this a context manager for with | |
328 | #--------------------------------------------------------------------------- |
|
309 | #--------------------------------------------------------------------------- | |
@@ -422,7 +403,11 b' class FullBlockingMultiEngineClient(InteractiveMultiEngineClient):' | |||||
422 | engine, run code on it, etc. |
|
403 | engine, run code on it, etc. | |
423 | """ |
|
404 | """ | |
424 |
|
405 | |||
425 | implements(IFullBlockingMultiEngineClient) |
|
406 | implements( | |
|
407 | IFullBlockingMultiEngineClient, | |||
|
408 | IMultiEngineMapperFactory, | |||
|
409 | IMapper | |||
|
410 | ) | |||
426 |
|
411 | |||
427 | def __init__(self, smultiengine): |
|
412 | def __init__(self, smultiengine): | |
428 | self.smultiengine = smultiengine |
|
413 | self.smultiengine = smultiengine | |
@@ -779,29 +764,100 b' class FullBlockingMultiEngineClient(InteractiveMultiEngineClient):' | |||||
779 | # IMultiEngineCoordinator |
|
764 | # IMultiEngineCoordinator | |
780 | #--------------------------------------------------------------------------- |
|
765 | #--------------------------------------------------------------------------- | |
781 |
|
766 | |||
782 |
def scatter(self, key, seq, st |
|
767 | def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None): | |
783 | """ |
|
768 | """ | |
784 | Partition a Python sequence and send the partitions to a set of engines. |
|
769 | Partition a Python sequence and send the partitions to a set of engines. | |
785 | """ |
|
770 | """ | |
786 | targets, block = self._findTargetsAndBlock(targets, block) |
|
771 | targets, block = self._findTargetsAndBlock(targets, block) | |
787 | return self._blockFromThread(self.smultiengine.scatter, key, seq, |
|
772 | return self._blockFromThread(self.smultiengine.scatter, key, seq, | |
788 |
st |
|
773 | dist, flatten, targets=targets, block=block) | |
789 |
|
774 | |||
790 |
def gather(self, key, st |
|
775 | def gather(self, key, dist='b', targets=None, block=None): | |
791 | """ |
|
776 | """ | |
792 | Gather a partitioned sequence on a set of engines as a single local seq. |
|
777 | Gather a partitioned sequence on a set of engines as a single local seq. | |
793 | """ |
|
778 | """ | |
794 | targets, block = self._findTargetsAndBlock(targets, block) |
|
779 | targets, block = self._findTargetsAndBlock(targets, block) | |
795 |
return self._blockFromThread(self.smultiengine.gather, key, st |
|
780 | return self._blockFromThread(self.smultiengine.gather, key, dist, | |
796 | targets=targets, block=block) |
|
781 | targets=targets, block=block) | |
797 |
|
782 | |||
798 |
def map(self, func, seq, st |
|
783 | def raw_map(self, func, seq, dist='b', targets=None, block=None): | |
799 | """ |
|
784 | """ | |
800 | A parallelized version of Python's builtin map |
|
785 | A parallelized version of Python's builtin map. | |
|
786 | ||||
|
787 | This has a slightly different syntax than the builtin `map`. | |||
|
788 | This is needed because we need to have keyword arguments and thus | |||
|
789 | can't use *args to capture all the sequences. Instead, they must | |||
|
790 | be passed in a list or tuple. | |||
|
791 | ||||
|
792 | raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...) | |||
|
793 | ||||
|
794 | Most users will want to use parallel functions or the `mapper` | |||
|
795 | and `map` methods for an API that follows that of the builtin | |||
|
796 | `map`. | |||
801 | """ |
|
797 | """ | |
802 | targets, block = self._findTargetsAndBlock(targets, block) |
|
798 | targets, block = self._findTargetsAndBlock(targets, block) | |
803 | return self._blockFromThread(self.smultiengine.map, func, seq, |
|
799 | return self._blockFromThread(self.smultiengine.raw_map, func, seq, | |
804 |
st |
|
800 | dist, targets=targets, block=block) | |
|
801 | ||||
|
802 | def map(self, func, *sequences): | |||
|
803 | """ | |||
|
804 | A parallel version of Python's builtin `map` function. | |||
|
805 | ||||
|
806 | This method applies a function to sequences of arguments. It | |||
|
807 | follows the same syntax as the builtin `map`. | |||
|
808 | ||||
|
809 | This method creates a mapper objects by calling `self.mapper` with | |||
|
810 | no arguments and then uses that mapper to do the mapping. See | |||
|
811 | the documentation of `mapper` for more details. | |||
|
812 | """ | |||
|
813 | return self.mapper().map(func, *sequences) | |||
|
814 | ||||
|
815 | def mapper(self, dist='b', targets='all', block=None): | |||
|
816 | """ | |||
|
817 | Create a mapper object that has a `map` method. | |||
|
818 | ||||
|
819 | This method returns an object that implements the `IMapper` | |||
|
820 | interface. This method is a factory that is used to control how | |||
|
821 | the map happens. | |||
|
822 | ||||
|
823 | :Parameters: | |||
|
824 | dist : str | |||
|
825 | What decomposition to use, 'b' is the only one supported | |||
|
826 | currently | |||
|
827 | targets : str, int, sequence of ints | |||
|
828 | Which engines to use for the map | |||
|
829 | block : boolean | |||
|
830 | Should calls to `map` block or not | |||
|
831 | """ | |||
|
832 | return MultiEngineMapper(self, dist, targets, block) | |||
|
833 | ||||
|
834 | def parallel(self, dist='b', targets=None, block=None): | |||
|
835 | """ | |||
|
836 | A decorator that turns a function into a parallel function. | |||
|
837 | ||||
|
838 | This can be used as: | |||
|
839 | ||||
|
840 | @parallel() | |||
|
841 | def f(x, y) | |||
|
842 | ... | |||
|
843 | ||||
|
844 | f(range(10), range(10)) | |||
|
845 | ||||
|
846 | This causes f(0,0), f(1,1), ... to be called in parallel. | |||
|
847 | ||||
|
848 | :Parameters: | |||
|
849 | dist : str | |||
|
850 | What decomposition to use, 'b' is the only one supported | |||
|
851 | currently | |||
|
852 | targets : str, int, sequence of ints | |||
|
853 | Which engines to use for the map | |||
|
854 | block : boolean | |||
|
855 | Should calls to `map` block or not | |||
|
856 | """ | |||
|
857 | targets, block = self._findTargetsAndBlock(targets, block) | |||
|
858 | mapper = self.mapper(dist, targets, block) | |||
|
859 | pf = ParallelFunction(mapper) | |||
|
860 | return pf | |||
805 |
|
861 | |||
806 | #--------------------------------------------------------------------------- |
|
862 | #--------------------------------------------------------------------------- | |
807 | # IMultiEngineExtras |
|
863 | # IMultiEngineExtras |
@@ -29,6 +29,12 b' from foolscap import Referenceable' | |||||
29 | from IPython.kernel import error |
|
29 | from IPython.kernel import error | |
30 | from IPython.kernel.util import printer |
|
30 | from IPython.kernel.util import printer | |
31 | from IPython.kernel import map as Map |
|
31 | from IPython.kernel import map as Map | |
|
32 | from IPython.kernel.parallelfunction import ParallelFunction | |||
|
33 | from IPython.kernel.mapper import ( | |||
|
34 | MultiEngineMapper, | |||
|
35 | IMultiEngineMapperFactory, | |||
|
36 | IMapper | |||
|
37 | ) | |||
32 | from IPython.kernel.twistedutil import gatherBoth |
|
38 | from IPython.kernel.twistedutil import gatherBoth | |
33 | from IPython.kernel.multiengine import (MultiEngine, |
|
39 | from IPython.kernel.multiengine import (MultiEngine, | |
34 | IMultiEngine, |
|
40 | IMultiEngine, | |
@@ -280,7 +286,12 b' components.registerAdapter(FCSynchronousMultiEngineFromMultiEngine,' | |||||
280 |
|
286 | |||
281 | class FCFullSynchronousMultiEngineClient(object): |
|
287 | class FCFullSynchronousMultiEngineClient(object): | |
282 |
|
288 | |||
283 | implements(IFullSynchronousMultiEngine, IBlockingClientAdaptor) |
|
289 | implements( | |
|
290 | IFullSynchronousMultiEngine, | |||
|
291 | IBlockingClientAdaptor, | |||
|
292 | IMultiEngineMapperFactory, | |||
|
293 | IMapper | |||
|
294 | ) | |||
284 |
|
295 | |||
285 | def __init__(self, remote_reference): |
|
296 | def __init__(self, remote_reference): | |
286 | self.remote_reference = remote_reference |
|
297 | self.remote_reference = remote_reference | |
@@ -475,7 +486,7 b' class FCFullSynchronousMultiEngineClient(object):' | |||||
475 | d.addCallback(create_targets) |
|
486 | d.addCallback(create_targets) | |
476 | return d |
|
487 | return d | |
477 |
|
488 | |||
478 |
def scatter(self, key, seq, st |
|
489 | def scatter(self, key, seq, dist='b', flatten=False, targets='all', block=True): | |
479 |
|
490 | |||
480 | # Note: scatter and gather handle pending deferreds locally through self.pdm. |
|
491 | # Note: scatter and gather handle pending deferreds locally through self.pdm. | |
481 | # This enables us to collect a bunch fo deferred ids and make a secondary |
|
492 | # This enables us to collect a bunch fo deferred ids and make a secondary | |
@@ -483,7 +494,7 b' class FCFullSynchronousMultiEngineClient(object):' | |||||
483 | # difficult to get right though. |
|
494 | # difficult to get right though. | |
484 | def do_scatter(engines): |
|
495 | def do_scatter(engines): | |
485 | nEngines = len(engines) |
|
496 | nEngines = len(engines) | |
486 |
mapClass = Map.st |
|
497 | mapClass = Map.dists[dist] | |
487 | mapObject = mapClass() |
|
498 | mapObject = mapClass() | |
488 | d_list = [] |
|
499 | d_list = [] | |
489 | # Loop through and push to each engine in non-blocking mode. |
|
500 | # Loop through and push to each engine in non-blocking mode. | |
@@ -541,7 +552,7 b' class FCFullSynchronousMultiEngineClient(object):' | |||||
541 | d.addCallback(do_scatter) |
|
552 | d.addCallback(do_scatter) | |
542 | return d |
|
553 | return d | |
543 |
|
554 | |||
544 |
def gather(self, key, st |
|
555 | def gather(self, key, dist='b', targets='all', block=True): | |
545 |
|
556 | |||
546 | # Note: scatter and gather handle pending deferreds locally through self.pdm. |
|
557 | # Note: scatter and gather handle pending deferreds locally through self.pdm. | |
547 | # This enables us to collect a bunch fo deferred ids and make a secondary |
|
558 | # This enables us to collect a bunch fo deferred ids and make a secondary | |
@@ -549,7 +560,7 b' class FCFullSynchronousMultiEngineClient(object):' | |||||
549 | # difficult to get right though. |
|
560 | # difficult to get right though. | |
550 | def do_gather(engines): |
|
561 | def do_gather(engines): | |
551 | nEngines = len(engines) |
|
562 | nEngines = len(engines) | |
552 |
mapClass = Map.st |
|
563 | mapClass = Map.dists[dist] | |
553 | mapObject = mapClass() |
|
564 | mapObject = mapClass() | |
554 | d_list = [] |
|
565 | d_list = [] | |
555 | # Loop through and push to each engine in non-blocking mode. |
|
566 | # Loop through and push to each engine in non-blocking mode. | |
@@ -604,25 +615,103 b' class FCFullSynchronousMultiEngineClient(object):' | |||||
604 | d.addCallback(do_gather) |
|
615 | d.addCallback(do_gather) | |
605 | return d |
|
616 | return d | |
606 |
|
617 | |||
607 |
def map(self, func, seq, st |
|
618 | def raw_map(self, func, sequences, dist='b', targets='all', block=True): | |
608 | d_list = [] |
|
619 | """ | |
|
620 | A parallelized version of Python's builtin map. | |||
|
621 | ||||
|
622 | This has a slightly different syntax than the builtin `map`. | |||
|
623 | This is needed because we need to have keyword arguments and thus | |||
|
624 | can't use *args to capture all the sequences. Instead, they must | |||
|
625 | be passed in a list or tuple. | |||
|
626 | ||||
|
627 | raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...) | |||
|
628 | ||||
|
629 | Most users will want to use parallel functions or the `mapper` | |||
|
630 | and `map` methods for an API that follows that of the builtin | |||
|
631 | `map`. | |||
|
632 | """ | |||
|
633 | if not isinstance(sequences, (list, tuple)): | |||
|
634 | raise TypeError('sequences must be a list or tuple') | |||
|
635 | max_len = max(len(s) for s in sequences) | |||
|
636 | for s in sequences: | |||
|
637 | if len(s)!=max_len: | |||
|
638 | raise ValueError('all sequences must have equal length') | |||
609 | if isinstance(func, FunctionType): |
|
639 | if isinstance(func, FunctionType): | |
610 | d = self.push_function(dict(_ipython_map_func=func), targets=targets, block=False) |
|
640 | d = self.push_function(dict(_ipython_map_func=func), targets=targets, block=False) | |
611 | d.addCallback(lambda did: self.get_pending_deferred(did, True)) |
|
641 | d.addCallback(lambda did: self.get_pending_deferred(did, True)) | |
612 | sourceToRun = '_ipython_map_seq_result = map(_ipython_map_func, _ipython_map_seq)' |
|
642 | sourceToRun = '_ipython_map_seq_result = map(_ipython_map_func, *zip(*_ipython_map_seq))' | |
613 | elif isinstance(func, str): |
|
643 | elif isinstance(func, str): | |
614 | d = defer.succeed(None) |
|
644 | d = defer.succeed(None) | |
615 | sourceToRun = \ |
|
645 | sourceToRun = \ | |
616 | '_ipython_map_seq_result = map(%s, _ipython_map_seq)' % func |
|
646 | '_ipython_map_seq_result = map(%s, *zip(*_ipython_map_seq))' % func | |
617 | else: |
|
647 | else: | |
618 | raise TypeError("func must be a function or str") |
|
648 | raise TypeError("func must be a function or str") | |
619 |
|
649 | |||
620 |
d.addCallback(lambda _: self.scatter('_ipython_map_seq', seq, st |
|
650 | d.addCallback(lambda _: self.scatter('_ipython_map_seq', zip(*sequences), dist, targets=targets)) | |
621 | d.addCallback(lambda _: self.execute(sourceToRun, targets=targets, block=False)) |
|
651 | d.addCallback(lambda _: self.execute(sourceToRun, targets=targets, block=False)) | |
622 | d.addCallback(lambda did: self.get_pending_deferred(did, True)) |
|
652 | d.addCallback(lambda did: self.get_pending_deferred(did, True)) | |
623 |
d.addCallback(lambda _: self.gather('_ipython_map_seq_result', st |
|
653 | d.addCallback(lambda _: self.gather('_ipython_map_seq_result', dist, targets=targets, block=block)) | |
624 | return d |
|
654 | return d | |
625 |
|
655 | |||
|
656 | def map(self, func, *sequences): | |||
|
657 | """ | |||
|
658 | A parallel version of Python's builtin `map` function. | |||
|
659 | ||||
|
660 | This method applies a function to sequences of arguments. It | |||
|
661 | follows the same syntax as the builtin `map`. | |||
|
662 | ||||
|
663 | This method creates a mapper objects by calling `self.mapper` with | |||
|
664 | no arguments and then uses that mapper to do the mapping. See | |||
|
665 | the documentation of `mapper` for more details. | |||
|
666 | """ | |||
|
667 | return self.mapper().map(func, *sequences) | |||
|
668 | ||||
|
669 | def mapper(self, dist='b', targets='all', block=True): | |||
|
670 | """ | |||
|
671 | Create a mapper object that has a `map` method. | |||
|
672 | ||||
|
673 | This method returns an object that implements the `IMapper` | |||
|
674 | interface. This method is a factory that is used to control how | |||
|
675 | the map happens. | |||
|
676 | ||||
|
677 | :Parameters: | |||
|
678 | dist : str | |||
|
679 | What decomposition to use, 'b' is the only one supported | |||
|
680 | currently | |||
|
681 | targets : str, int, sequence of ints | |||
|
682 | Which engines to use for the map | |||
|
683 | block : boolean | |||
|
684 | Should calls to `map` block or not | |||
|
685 | """ | |||
|
686 | return MultiEngineMapper(self, dist, targets, block) | |||
|
687 | ||||
|
688 | def parallel(self, dist='b', targets='all', block=True): | |||
|
689 | """ | |||
|
690 | A decorator that turns a function into a parallel function. | |||
|
691 | ||||
|
692 | This can be used as: | |||
|
693 | ||||
|
694 | @parallel() | |||
|
695 | def f(x, y) | |||
|
696 | ... | |||
|
697 | ||||
|
698 | f(range(10), range(10)) | |||
|
699 | ||||
|
700 | This causes f(0,0), f(1,1), ... to be called in parallel. | |||
|
701 | ||||
|
702 | :Parameters: | |||
|
703 | dist : str | |||
|
704 | What decomposition to use, 'b' is the only one supported | |||
|
705 | currently | |||
|
706 | targets : str, int, sequence of ints | |||
|
707 | Which engines to use for the map | |||
|
708 | block : boolean | |||
|
709 | Should calls to `map` block or not | |||
|
710 | """ | |||
|
711 | mapper = self.mapper(dist, targets, block) | |||
|
712 | pf = ParallelFunction(mapper) | |||
|
713 | return pf | |||
|
714 | ||||
626 | #--------------------------------------------------------------------------- |
|
715 | #--------------------------------------------------------------------------- | |
627 | # ISynchronousMultiEngineExtras related methods |
|
716 | # ISynchronousMultiEngineExtras related methods | |
628 | #--------------------------------------------------------------------------- |
|
717 | #--------------------------------------------------------------------------- |
@@ -16,17 +16,92 b' __docformat__ = "restructuredtext en"' | |||||
16 | #------------------------------------------------------------------------------- |
|
16 | #------------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | from types import FunctionType |
|
18 | from types import FunctionType | |
|
19 | from zope.interface import Interface, implements | |||
19 |
|
20 | |||
20 | class ParallelFunction: |
|
21 | ||
21 | """A function that operates in parallel on sequences.""" |
|
22 | class IMultiEngineParallelDecorator(Interface): | |
22 | def __init__(self, func, multiengine, targets, block): |
|
23 | """A decorator that creates a parallel function.""" | |
23 | """Create a `ParallelFunction`. |
|
24 | ||
|
25 | def parallel(dist='b', targets=None, block=None): | |||
|
26 | """ | |||
|
27 | A decorator that turns a function into a parallel function. | |||
|
28 | ||||
|
29 | This can be used as: | |||
|
30 | ||||
|
31 | @parallel() | |||
|
32 | def f(x, y) | |||
|
33 | ... | |||
|
34 | ||||
|
35 | f(range(10), range(10)) | |||
|
36 | ||||
|
37 | This causes f(0,0), f(1,1), ... to be called in parallel. | |||
|
38 | ||||
|
39 | :Parameters: | |||
|
40 | dist : str | |||
|
41 | What decomposition to use, 'b' is the only one supported | |||
|
42 | currently | |||
|
43 | targets : str, int, sequence of ints | |||
|
44 | Which engines to use for the map | |||
|
45 | block : boolean | |||
|
46 | Should calls to `map` block or not | |||
|
47 | """ | |||
|
48 | ||||
|
49 | class ITaskParallelDecorator(Interface): | |||
|
50 | """A decorator that creates a parallel function.""" | |||
|
51 | ||||
|
52 | def parallel(clear_before=False, clear_after=False, retries=0, | |||
|
53 | recovery_task=None, depend=None, block=True): | |||
|
54 | """ | |||
|
55 | A decorator that turns a function into a parallel function. | |||
|
56 | ||||
|
57 | This can be used as: | |||
|
58 | ||||
|
59 | @parallel() | |||
|
60 | def f(x, y) | |||
|
61 | ... | |||
|
62 | ||||
|
63 | f(range(10), range(10)) | |||
|
64 | ||||
|
65 | This causes f(0,0), f(1,1), ... to be called in parallel. | |||
|
66 | ||||
|
67 | See the documentation for `IPython.kernel.task.BaseTask` for | |||
|
68 | documentation on the arguments to this method. | |||
|
69 | """ | |||
|
70 | ||||
|
71 | class IParallelFunction(Interface): | |||
|
72 | pass | |||
|
73 | ||||
|
74 | class ParallelFunction(object): | |||
|
75 | """ | |||
|
76 | The implementation of a parallel function. | |||
|
77 | ||||
|
78 | A parallel function is similar to Python's map function: | |||
|
79 | ||||
|
80 | map(func, *sequences) -> pfunc(*sequences) | |||
|
81 | ||||
|
82 | Parallel functions should be created by using the @parallel decorator. | |||
|
83 | """ | |||
|
84 | ||||
|
85 | implements(IParallelFunction) | |||
|
86 | ||||
|
87 | def __init__(self, mapper): | |||
|
88 | """ | |||
|
89 | Create a parallel function from an `IMapper`. | |||
|
90 | ||||
|
91 | :Parameters: | |||
|
92 | mapper : an `IMapper` implementer. | |||
|
93 | The mapper to use for the parallel function | |||
|
94 | """ | |||
|
95 | self.mapper = mapper | |||
|
96 | ||||
|
97 | def __call__(self, func): | |||
|
98 | """ | |||
|
99 | Decorate a function to make it run in parallel. | |||
24 | """ |
|
100 | """ | |
25 | assert isinstance(func, (str, FunctionType)), "func must be a fuction or str" |
|
101 | assert isinstance(func, (str, FunctionType)), "func must be a fuction or str" | |
26 | self.func = func |
|
102 | self.func = func | |
27 | self.multiengine = multiengine |
|
103 | def call_function(*sequences): | |
28 | self.targets = targets |
|
104 | return self.mapper.map(self.func, *sequences) | |
29 | self.block = block |
|
105 | return call_function | |
30 |
|
106 | |||
31 | def __call__(self, sequence): |
|
107 | No newline at end of file | |
32 | return self.multiengine.map(self.func, sequence, targets=self.targets, block=self.block) No newline at end of file |
|
This diff has been collapsed as it changes many lines, (680 lines changed) Show them Hide them | |||||
@@ -5,116 +5,404 b'' | |||||
5 |
|
5 | |||
6 | __docformat__ = "restructuredtext en" |
|
6 | __docformat__ = "restructuredtext en" | |
7 |
|
7 | |||
8 |
#----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
9 | # Copyright (C) 2008 The IPython Development Team |
|
9 | # Copyright (C) 2008 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 copy, time |
|
19 | import copy, time | |
20 |
from types import FunctionType |
|
20 | from types import FunctionType | |
21 |
|
21 | |||
22 | import zope.interface as zi, string |
|
22 | import zope.interface as zi, string | |
23 | from twisted.internet import defer, reactor |
|
23 | from twisted.internet import defer, reactor | |
24 | from twisted.python import components, log, failure |
|
24 | from twisted.python import components, log, failure | |
25 |
|
25 | |||
26 |
|
|
26 | from IPython.kernel.util import printer | |
27 |
|
||||
28 | from IPython.kernel import engineservice as es, error |
|
27 | from IPython.kernel import engineservice as es, error | |
29 | from IPython.kernel import controllerservice as cs |
|
28 | from IPython.kernel import controllerservice as cs | |
30 | from IPython.kernel.twistedutil import gatherBoth, DeferredList |
|
29 | from IPython.kernel.twistedutil import gatherBoth, DeferredList | |
31 |
|
30 | |||
32 | from IPython.kernel.pickleutil import can,uncan, CannedFunction |
|
31 | from IPython.kernel.pickleutil import can, uncan, CannedFunction | |
33 |
|
||||
34 | def canTask(task): |
|
|||
35 | t = copy.copy(task) |
|
|||
36 | t.depend = can(t.depend) |
|
|||
37 | if t.recovery_task: |
|
|||
38 | t.recovery_task = canTask(t.recovery_task) |
|
|||
39 | return t |
|
|||
40 |
|
32 | |||
41 | def uncanTask(task): |
|
33 | #----------------------------------------------------------------------------- | |
42 | t = copy.copy(task) |
|
34 | # Definition of the Task objects | |
43 | t.depend = uncan(t.depend) |
|
35 | #----------------------------------------------------------------------------- | |
44 | if t.recovery_task and t.recovery_task is not task: |
|
|||
45 | t.recovery_task = uncanTask(t.recovery_task) |
|
|||
46 | return t |
|
|||
47 |
|
36 | |||
48 | time_format = '%Y/%m/%d %H:%M:%S' |
|
37 | time_format = '%Y/%m/%d %H:%M:%S' | |
49 |
|
38 | |||
50 |
class Task( |
|
39 | class ITask(zi.Interface): | |
51 | """Our representation of a task for the `TaskController` interface. |
|
40 | """ | |
52 |
|
41 | This interface provides a generic definition of what constitutes a task. | ||
53 | The user should create instances of this class to represent a task that |
|
42 | ||
54 | needs to be done. |
|
43 | There are two sides to a task. First a task needs to take input from | |
55 |
|
44 | a user to determine what work is performed by the task. Second, the | ||
56 | :Parameters: |
|
45 | task needs to have the logic that knows how to turn that information | |
57 | expression : str |
|
46 | info specific calls to a worker, through the `IQueuedEngine` interface. | |
58 | A str that is valid python code that is the task. |
|
|||
59 | pull : str or list of str |
|
|||
60 | The names of objects to be pulled as results. If not specified, |
|
|||
61 | will return {'result', None} |
|
|||
62 | push : dict |
|
|||
63 | A dict of objects to be pushed into the engines namespace before |
|
|||
64 | execution of the expression. |
|
|||
65 | clear_before : boolean |
|
|||
66 | Should the engine's namespace be cleared before the task is run. |
|
|||
67 | Default=False. |
|
|||
68 | clear_after : boolean |
|
|||
69 | Should the engine's namespace be cleared after the task is run. |
|
|||
70 | Default=False. |
|
|||
71 | retries : int |
|
|||
72 | The number of times to resumbit the task if it fails. Default=0. |
|
|||
73 | recovery_task : Task |
|
|||
74 | This is the Task to be run when the task has exhausted its retries |
|
|||
75 | Default=None. |
|
|||
76 | depend : bool function(properties) |
|
|||
77 | This is the dependency function for the Task, which determines |
|
|||
78 | whether a task can be run on a Worker. `depend` is called with |
|
|||
79 | one argument, the worker's properties dict, and should return |
|
|||
80 | True if the worker meets the dependencies or False if it does |
|
|||
81 | not. |
|
|||
82 | Default=None - run on any worker |
|
|||
83 | options : dict |
|
|||
84 | Any other keyword options for more elaborate uses of tasks |
|
|||
85 |
|
||||
86 | Examples |
|
|||
87 | -------- |
|
|||
88 |
|
47 | |||
89 | >>> t = Task('dostuff(args)') |
|
48 | Many method in this class get two things passed to them: a Deferred | |
90 | >>> t = Task('a=5', pull='a') |
|
49 | and an IQueuedEngine implementer. Such methods should register callbacks | |
91 | >>> t = Task('a=5\nb=4', pull=['a','b']) |
|
50 | on the Deferred that use the IQueuedEngine to accomplish something. See | |
92 | >>> t = Task('os.kill(os.getpid(),9)', retries=100) # this is a bad idea |
|
51 | the existing task objects for examples. | |
93 | # A dependency case: |
|
|||
94 | >>> def hasMPI(props): |
|
|||
95 | ... return props.get('mpi') is not None |
|
|||
96 | >>> t = Task('mpi.send(blah,blah)', depend = hasMPI) |
|
|||
97 | """ |
|
52 | """ | |
98 |
|
53 | |||
99 | def __init__(self, expression, pull=None, push=None, |
|
54 | zi.Attribute('retries','How many times to retry the task') | |
100 | clear_before=False, clear_after=False, retries=0, |
|
55 | zi.Attribute('recovery_task','A task to try if the initial one fails') | |
101 | recovery_task=None, depend=None, **options): |
|
56 | zi.Attribute('taskid','the id of the task') | |
102 | self.expression = expression |
|
57 | ||
103 | if isinstance(pull, str): |
|
58 | def start_time(result): | |
104 | self.pull = [pull] |
|
59 | """ | |
105 | else: |
|
60 | Do anything needed to start the timing of the task. | |
106 | self.pull = pull |
|
61 | ||
107 | self.push = push |
|
62 | Must simply return the result after starting the timers. | |
|
63 | """ | |||
|
64 | ||||
|
65 | def stop_time(result): | |||
|
66 | """ | |||
|
67 | Do anything needed to stop the timing of the task. | |||
|
68 | ||||
|
69 | Must simply return the result after stopping the timers. This | |||
|
70 | method will usually set attributes that are used by `process_result` | |||
|
71 | in building result of the task. | |||
|
72 | """ | |||
|
73 | ||||
|
74 | def pre_task(d, queued_engine): | |||
|
75 | """Do something with the queued_engine before the task is run. | |||
|
76 | ||||
|
77 | This method should simply add callbacks to the input Deferred | |||
|
78 | that do something with the `queued_engine` before the task is run. | |||
|
79 | ||||
|
80 | :Parameters: | |||
|
81 | d : Deferred | |||
|
82 | The deferred that actions should be attached to | |||
|
83 | queued_engine : IQueuedEngine implementer | |||
|
84 | The worker that has been allocated to perform the task | |||
|
85 | """ | |||
|
86 | ||||
|
87 | def post_task(d, queued_engine): | |||
|
88 | """Do something with the queued_engine after the task is run. | |||
|
89 | ||||
|
90 | This method should simply add callbacks to the input Deferred | |||
|
91 | that do something with the `queued_engine` before the task is run. | |||
|
92 | ||||
|
93 | :Parameters: | |||
|
94 | d : Deferred | |||
|
95 | The deferred that actions should be attached to | |||
|
96 | queued_engine : IQueuedEngine implementer | |||
|
97 | The worker that has been allocated to perform the task | |||
|
98 | """ | |||
|
99 | ||||
|
100 | def submit_task(d, queued_engine): | |||
|
101 | """Submit a task using the `queued_engine` we have been allocated. | |||
|
102 | ||||
|
103 | When a task is ready to run, this method is called. This method | |||
|
104 | must take the internal information of the task and make suitable | |||
|
105 | calls on the queued_engine to have the actual work done. | |||
|
106 | ||||
|
107 | This method should simply add callbacks to the input Deferred | |||
|
108 | that do something with the `queued_engine` before the task is run. | |||
|
109 | ||||
|
110 | :Parameters: | |||
|
111 | d : Deferred | |||
|
112 | The deferred that actions should be attached to | |||
|
113 | queued_engine : IQueuedEngine implementer | |||
|
114 | The worker that has been allocated to perform the task | |||
|
115 | """ | |||
|
116 | ||||
|
117 | def process_result(d, result, engine_id): | |||
|
118 | """Take a raw task result. | |||
|
119 | ||||
|
120 | Objects that implement `ITask` can choose how the result of running | |||
|
121 | the task is presented. This method takes the raw result and | |||
|
122 | does this logic. Two example are the `MapTask` which simply returns | |||
|
123 | the raw result or a `Failure` object and the `StringTask` which | |||
|
124 | returns a `TaskResult` object. | |||
|
125 | ||||
|
126 | :Parameters: | |||
|
127 | d : Deferred | |||
|
128 | The deferred that actions should be attached to | |||
|
129 | result : object | |||
|
130 | The raw task result that needs to be wrapped | |||
|
131 | engine_id : int | |||
|
132 | The id of the engine that did the task | |||
|
133 | ||||
|
134 | :Returns: | |||
|
135 | The result, as a tuple of the form: (success, result). | |||
|
136 | Here, success is a boolean indicating if the task | |||
|
137 | succeeded or failed and result is the result. | |||
|
138 | """ | |||
|
139 | ||||
|
140 | def check_depend(properties): | |||
|
141 | """Check properties to see if the task should be run. | |||
|
142 | ||||
|
143 | :Parameters: | |||
|
144 | properties : dict | |||
|
145 | A dictionary of properties that an engine has set | |||
|
146 | ||||
|
147 | :Returns: | |||
|
148 | True if the task should be run, False otherwise | |||
|
149 | """ | |||
|
150 | ||||
|
151 | def can_task(self): | |||
|
152 | """Serialize (can) any functions in the task for pickling. | |||
|
153 | ||||
|
154 | Subclasses must override this method and make sure that all | |||
|
155 | functions in the task are canned by calling `can` on the | |||
|
156 | function. | |||
|
157 | """ | |||
|
158 | ||||
|
159 | def uncan_task(self): | |||
|
160 | """Unserialize (uncan) any canned function in the task.""" | |||
|
161 | ||||
|
162 | class BaseTask(object): | |||
|
163 | """ | |||
|
164 | Common fuctionality for all objects implementing `ITask`. | |||
|
165 | """ | |||
|
166 | ||||
|
167 | zi.implements(ITask) | |||
|
168 | ||||
|
169 | def __init__(self, clear_before=False, clear_after=False, retries=0, | |||
|
170 | recovery_task=None, depend=None): | |||
|
171 | """ | |||
|
172 | Make a generic task. | |||
|
173 | ||||
|
174 | :Parameters: | |||
|
175 | clear_before : boolean | |||
|
176 | Should the engines namespace be cleared before the task | |||
|
177 | is run | |||
|
178 | clear_after : boolean | |||
|
179 | Should the engines namespace be clear after the task is run | |||
|
180 | retries : int | |||
|
181 | The number of times a task should be retries upon failure | |||
|
182 | recovery_task : any task object | |||
|
183 | If a task fails and it has a recovery_task, that is run | |||
|
184 | upon a retry | |||
|
185 | depend : FunctionType | |||
|
186 | A function that is called to test for properties. This function | |||
|
187 | must take one argument, the properties dict and return a boolean | |||
|
188 | """ | |||
108 | self.clear_before = clear_before |
|
189 | self.clear_before = clear_before | |
109 | self.clear_after = clear_after |
|
190 | self.clear_after = clear_after | |
110 | self.retries=retries |
|
191 | self.retries = retries | |
111 | self.recovery_task = recovery_task |
|
192 | self.recovery_task = recovery_task | |
112 | self.depend = depend |
|
193 | self.depend = depend | |
113 | self.options = options |
|
|||
114 | self.taskid = None |
|
194 | self.taskid = None | |
|
195 | ||||
|
196 | def start_time(self, result): | |||
|
197 | """ | |||
|
198 | Start the basic timers. | |||
|
199 | """ | |||
|
200 | self.start = time.time() | |||
|
201 | self.start_struct = time.localtime() | |||
|
202 | return result | |||
|
203 | ||||
|
204 | def stop_time(self, result): | |||
|
205 | """ | |||
|
206 | Stop the basic timers. | |||
|
207 | """ | |||
|
208 | self.stop = time.time() | |||
|
209 | self.stop_struct = time.localtime() | |||
|
210 | self.duration = self.stop - self.start | |||
|
211 | self.submitted = time.strftime(time_format, self.start_struct) | |||
|
212 | self.completed = time.strftime(time_format) | |||
|
213 | return result | |||
|
214 | ||||
|
215 | def pre_task(self, d, queued_engine): | |||
|
216 | """ | |||
|
217 | Clear the engine before running the task if clear_before is set. | |||
|
218 | """ | |||
|
219 | if self.clear_before: | |||
|
220 | d.addCallback(lambda r: queued_engine.reset()) | |||
|
221 | ||||
|
222 | def post_task(self, d, queued_engine): | |||
|
223 | """ | |||
|
224 | Clear the engine after running the task if clear_after is set. | |||
|
225 | """ | |||
|
226 | def reseter(result): | |||
|
227 | queued_engine.reset() | |||
|
228 | return result | |||
|
229 | if self.clear_after: | |||
|
230 | d.addBoth(reseter) | |||
|
231 | ||||
|
232 | def submit_task(self, d, queued_engine): | |||
|
233 | raise NotImplementedError('submit_task must be implemented in a subclass') | |||
|
234 | ||||
|
235 | def process_result(self, result, engine_id): | |||
|
236 | """ | |||
|
237 | Process a task result. | |||
|
238 | ||||
|
239 | This is the default `process_result` that just returns the raw | |||
|
240 | result or a `Failure`. | |||
|
241 | """ | |||
|
242 | if isinstance(result, failure.Failure): | |||
|
243 | return (False, result) | |||
|
244 | else: | |||
|
245 | return (True, result) | |||
|
246 | ||||
|
247 | def check_depend(self, properties): | |||
|
248 | """ | |||
|
249 | Calls self.depend(properties) to see if a task should be run. | |||
|
250 | """ | |||
|
251 | if self.depend is not None: | |||
|
252 | return self.depend(properties) | |||
|
253 | else: | |||
|
254 | return True | |||
|
255 | ||||
|
256 | def can_task(self): | |||
|
257 | self.depend = can(self.depend) | |||
|
258 | if isinstance(self.recovery_task, BaseTask): | |||
|
259 | self.recovery_task.can_task() | |||
|
260 | ||||
|
261 | def uncan_task(self): | |||
|
262 | self.depend = uncan(self.depend) | |||
|
263 | if isinstance(self.recovery_task, BaseTask): | |||
|
264 | self.recovery_task.uncan_task() | |||
|
265 | ||||
|
266 | class MapTask(BaseTask): | |||
|
267 | """ | |||
|
268 | A task that consists of a function and arguments. | |||
|
269 | """ | |||
|
270 | ||||
|
271 | zi.implements(ITask) | |||
|
272 | ||||
|
273 | def __init__(self, function, args=None, kwargs=None, clear_before=False, | |||
|
274 | clear_after=False, retries=0, recovery_task=None, depend=None): | |||
|
275 | """ | |||
|
276 | Create a task based on a function, args and kwargs. | |||
|
277 | ||||
|
278 | This is a simple type of task that consists of calling: | |||
|
279 | function(*args, **kwargs) and wrapping the result in a `TaskResult`. | |||
|
280 | ||||
|
281 | The return value of the function, or a `Failure` wrapping an | |||
|
282 | exception is the task result for this type of task. | |||
|
283 | """ | |||
|
284 | BaseTask.__init__(self, clear_before, clear_after, retries, | |||
|
285 | recovery_task, depend) | |||
|
286 | if not isinstance(function, FunctionType): | |||
|
287 | raise TypeError('a task function must be a FunctionType') | |||
|
288 | self.function = function | |||
|
289 | if args is None: | |||
|
290 | self.args = () | |||
|
291 | else: | |||
|
292 | self.args = args | |||
|
293 | if not isinstance(self.args, (list, tuple)): | |||
|
294 | raise TypeError('a task args must be a list or tuple') | |||
|
295 | if kwargs is None: | |||
|
296 | self.kwargs = {} | |||
|
297 | else: | |||
|
298 | self.kwargs = kwargs | |||
|
299 | if not isinstance(self.kwargs, dict): | |||
|
300 | raise TypeError('a task kwargs must be a dict') | |||
|
301 | ||||
|
302 | def submit_task(self, d, queued_engine): | |||
|
303 | d.addCallback(lambda r: queued_engine.push_function( | |||
|
304 | dict(_ipython_task_function=self.function)) | |||
|
305 | ) | |||
|
306 | d.addCallback(lambda r: queued_engine.push( | |||
|
307 | dict(_ipython_task_args=self.args,_ipython_task_kwargs=self.kwargs)) | |||
|
308 | ) | |||
|
309 | d.addCallback(lambda r: queued_engine.execute( | |||
|
310 | '_ipython_task_result = _ipython_task_function(*_ipython_task_args,**_ipython_task_kwargs)') | |||
|
311 | ) | |||
|
312 | d.addCallback(lambda r: queued_engine.pull('_ipython_task_result')) | |||
|
313 | ||||
|
314 | def can_task(self): | |||
|
315 | self.function = can(self.function) | |||
|
316 | BaseTask.can_task(self) | |||
|
317 | ||||
|
318 | def uncan_task(self): | |||
|
319 | self.function = uncan(self.function) | |||
|
320 | BaseTask.uncan_task(self) | |||
|
321 | ||||
|
322 | ||||
|
323 | class StringTask(BaseTask): | |||
|
324 | """ | |||
|
325 | A task that consists of a string of Python code to run. | |||
|
326 | """ | |||
|
327 | ||||
|
328 | def __init__(self, expression, pull=None, push=None, | |||
|
329 | clear_before=False, clear_after=False, retries=0, | |||
|
330 | recovery_task=None, depend=None): | |||
|
331 | """ | |||
|
332 | Create a task based on a Python expression and variables | |||
|
333 | ||||
|
334 | This type of task lets you push a set of variables to the engines | |||
|
335 | namespace, run a Python string in that namespace and then bring back | |||
|
336 | a different set of Python variables as the result. | |||
|
337 | ||||
|
338 | Because this type of task can return many results (through the | |||
|
339 | `pull` keyword argument) it returns a special `TaskResult` object | |||
|
340 | that wraps the pulled variables, statistics about the run and | |||
|
341 | any exceptions raised. | |||
|
342 | """ | |||
|
343 | if not isinstance(expression, str): | |||
|
344 | raise TypeError('a task expression must be a string') | |||
|
345 | self.expression = expression | |||
|
346 | ||||
|
347 | if pull==None: | |||
|
348 | self.pull = () | |||
|
349 | elif isinstance(pull, str): | |||
|
350 | self.pull = (pull,) | |||
|
351 | elif isinstance(pull, (list, tuple)): | |||
|
352 | self.pull = pull | |||
|
353 | else: | |||
|
354 | raise TypeError('pull must be str or a sequence of strs') | |||
|
355 | ||||
|
356 | if push==None: | |||
|
357 | self.push = {} | |||
|
358 | elif isinstance(push, dict): | |||
|
359 | self.push = push | |||
|
360 | else: | |||
|
361 | raise TypeError('push must be a dict') | |||
|
362 | ||||
|
363 | BaseTask.__init__(self, clear_before, clear_after, retries, | |||
|
364 | recovery_task, depend) | |||
|
365 | ||||
|
366 | def submit_task(self, d, queued_engine): | |||
|
367 | if self.push is not None: | |||
|
368 | d.addCallback(lambda r: queued_engine.push(self.push)) | |||
|
369 | ||||
|
370 | d.addCallback(lambda r: queued_engine.execute(self.expression)) | |||
|
371 | ||||
|
372 | if self.pull is not None: | |||
|
373 | d.addCallback(lambda r: queued_engine.pull(self.pull)) | |||
|
374 | else: | |||
|
375 | d.addCallback(lambda r: None) | |||
|
376 | ||||
|
377 | def process_result(self, result, engine_id): | |||
|
378 | if isinstance(result, failure.Failure): | |||
|
379 | tr = TaskResult(result, engine_id) | |||
|
380 | else: | |||
|
381 | if self.pull is None: | |||
|
382 | resultDict = {} | |||
|
383 | elif len(self.pull) == 1: | |||
|
384 | resultDict = {self.pull[0]:result} | |||
|
385 | else: | |||
|
386 | resultDict = dict(zip(self.pull, result)) | |||
|
387 | tr = TaskResult(resultDict, engine_id) | |||
|
388 | # Assign task attributes | |||
|
389 | tr.submitted = self.submitted | |||
|
390 | tr.completed = self.completed | |||
|
391 | tr.duration = self.duration | |||
|
392 | if hasattr(self,'taskid'): | |||
|
393 | tr.taskid = self.taskid | |||
|
394 | else: | |||
|
395 | tr.taskid = None | |||
|
396 | if isinstance(result, failure.Failure): | |||
|
397 | return (False, tr) | |||
|
398 | else: | |||
|
399 | return (True, tr) | |||
115 |
|
400 | |||
116 | class ResultNS: |
|
401 | class ResultNS(object): | |
117 | """The result namespace object for use in TaskResult objects as tr.ns. |
|
402 | """ | |
|
403 | A dict like object for holding the results of a task. | |||
|
404 | ||||
|
405 | The result namespace object for use in `TaskResult` objects as tr.ns. | |||
118 | It builds an object from a dictionary, such that it has attributes |
|
406 | It builds an object from a dictionary, such that it has attributes | |
119 | according to the key,value pairs of the dictionary. |
|
407 | according to the key,value pairs of the dictionary. | |
120 |
|
408 | |||
@@ -128,11 +416,11 b' class ResultNS:' | |||||
128 |
|
416 | |||
129 | >>> ns = ResultNS({'a':17,'foo':range(3)}) |
|
417 | >>> ns = ResultNS({'a':17,'foo':range(3)}) | |
130 | >>> print ns |
|
418 | >>> print ns | |
131 |
|
|
419 | NS{'a': 17, 'foo': [0, 1, 2]} | |
132 | >>> ns.a |
|
420 | >>> ns.a | |
133 |
|
|
421 | 17 | |
134 | >>> ns['foo'] |
|
422 | >>> ns['foo'] | |
135 |
|
|
423 | [0, 1, 2] | |
136 | """ |
|
424 | """ | |
137 | def __init__(self, dikt): |
|
425 | def __init__(self, dikt): | |
138 | for k,v in dikt.iteritems(): |
|
426 | for k,v in dikt.iteritems(): | |
@@ -152,7 +440,7 b' class ResultNS:' | |||||
152 |
|
440 | |||
153 | class TaskResult(object): |
|
441 | class TaskResult(object): | |
154 | """ |
|
442 | """ | |
155 | An object for returning task results. |
|
443 | An object for returning task results for certain types of tasks. | |
156 |
|
444 | |||
157 | This object encapsulates the results of a task. On task |
|
445 | This object encapsulates the results of a task. On task | |
158 | success it will have a keys attribute that will have a list |
|
446 | success it will have a keys attribute that will have a list | |
@@ -162,21 +450,21 b' class TaskResult(object):' | |||||
162 |
|
450 | |||
163 | In task failure, keys will be empty, but failure will contain |
|
451 | In task failure, keys will be empty, but failure will contain | |
164 | the failure object that encapsulates the remote exception. |
|
452 | the failure object that encapsulates the remote exception. | |
165 |
One can also simply call the |
|
453 | One can also simply call the `raise_exception` method of | |
166 | this class to re-raise any remote exception in the local |
|
454 | this class to re-raise any remote exception in the local | |
167 | session. |
|
455 | session. | |
168 |
|
456 | |||
169 | The TaskResult has a .ns member, which is a property for access |
|
457 | The `TaskResult` has a `.ns` member, which is a property for access | |
170 | to the results. If the Task had pull=['a', 'b'], then the |
|
458 | to the results. If the Task had pull=['a', 'b'], then the | |
171 | Task Result will have attributes tr.ns.a, tr.ns.b for those values. |
|
459 | Task Result will have attributes `tr.ns.a`, `tr.ns.b` for those values. | |
172 | Accessing tr.ns will raise the remote failure if the task failed. |
|
460 | Accessing `tr.ns` will raise the remote failure if the task failed. | |
173 |
|
461 | |||
174 | The engineid attribute should have the engineid of the engine |
|
462 | The `engineid` attribute should have the `engineid` of the engine | |
175 |
that ran the task. But, because engines can come and go |
|
463 | that ran the task. But, because engines can come and go, | |
176 |
the |
|
464 | the `engineid` may not continue to be | |
177 | valid or accurate. |
|
465 | valid or accurate. | |
178 |
|
466 | |||
179 | The taskid attribute simply gives the taskid that the task |
|
467 | The `taskid` attribute simply gives the `taskid` that the task | |
180 | is tracked under. |
|
468 | is tracked under. | |
181 | """ |
|
469 | """ | |
182 | taskid = None |
|
470 | taskid = None | |
@@ -188,7 +476,7 b' class TaskResult(object):' | |||||
188 | return self._ns |
|
476 | return self._ns | |
189 |
|
477 | |||
190 | def _setNS(self, v): |
|
478 | def _setNS(self, v): | |
191 |
raise Exception(" |
|
479 | raise Exception("the ns attribute cannot be changed") | |
192 |
|
480 | |||
193 | ns = property(_getNS, _setNS) |
|
481 | ns = property(_getNS, _setNS) | |
194 |
|
482 | |||
@@ -214,15 +502,19 b' class TaskResult(object):' | |||||
214 |
|
502 | |||
215 | def __getitem__(self, key): |
|
503 | def __getitem__(self, key): | |
216 | if self.failure is not None: |
|
504 | if self.failure is not None: | |
217 |
self.raise |
|
505 | self.raise_exception() | |
218 | return self.results[key] |
|
506 | return self.results[key] | |
219 |
|
507 | |||
220 |
def raise |
|
508 | def raise_exception(self): | |
221 | """Re-raise any remote exceptions in the local python session.""" |
|
509 | """Re-raise any remote exceptions in the local python session.""" | |
222 | if self.failure is not None: |
|
510 | if self.failure is not None: | |
223 | self.failure.raiseException() |
|
511 | self.failure.raiseException() | |
224 |
|
512 | |||
225 |
|
513 | |||
|
514 | #----------------------------------------------------------------------------- | |||
|
515 | # The controller side of things | |||
|
516 | #----------------------------------------------------------------------------- | |||
|
517 | ||||
226 | class IWorker(zi.Interface): |
|
518 | class IWorker(zi.Interface): | |
227 | """The Basic Worker Interface. |
|
519 | """The Basic Worker Interface. | |
228 |
|
520 | |||
@@ -237,12 +529,15 b' class IWorker(zi.Interface):' | |||||
237 | :Parameters: |
|
529 | :Parameters: | |
238 | task : a `Task` object |
|
530 | task : a `Task` object | |
239 |
|
531 | |||
240 |
:Returns: `Deferred` to a |
|
532 | :Returns: `Deferred` to a tuple of (success, result) where | |
|
533 | success if a boolean that signifies success or failure | |||
|
534 | and result is the task result. | |||
241 | """ |
|
535 | """ | |
242 |
|
536 | |||
243 |
|
537 | |||
244 | class WorkerFromQueuedEngine(object): |
|
538 | class WorkerFromQueuedEngine(object): | |
245 | """Adapt an `IQueuedEngine` to an `IWorker` object""" |
|
539 | """Adapt an `IQueuedEngine` to an `IWorker` object""" | |
|
540 | ||||
246 | zi.implements(IWorker) |
|
541 | zi.implements(IWorker) | |
247 |
|
542 | |||
248 | def __init__(self, qe): |
|
543 | def __init__(self, qe): | |
@@ -257,53 +552,27 b' class WorkerFromQueuedEngine(object):' | |||||
257 | def run(self, task): |
|
552 | def run(self, task): | |
258 | """Run task in worker's namespace. |
|
553 | """Run task in worker's namespace. | |
259 |
|
554 | |||
|
555 | This takes a task and calls methods on the task that actually | |||
|
556 | cause `self.queuedEngine` to do the task. See the methods of | |||
|
557 | `ITask` for more information about how these methods are called. | |||
|
558 | ||||
260 | :Parameters: |
|
559 | :Parameters: | |
261 | task : a `Task` object |
|
560 | task : a `Task` object | |
262 |
|
561 | |||
263 |
:Returns: `Deferred` to a |
|
562 | :Returns: `Deferred` to a tuple of (success, result) where | |
|
563 | success if a boolean that signifies success or failure | |||
|
564 | and result is the task result. | |||
264 | """ |
|
565 | """ | |
265 | if task.clear_before: |
|
566 | d = defer.succeed(None) | |
266 | d = self.queuedEngine.reset() |
|
567 | d.addCallback(task.start_time) | |
267 | else: |
|
568 | task.pre_task(d, self.queuedEngine) | |
268 | d = defer.succeed(None) |
|
569 | task.submit_task(d, self.queuedEngine) | |
269 |
|
570 | task.post_task(d, self.queuedEngine) | ||
270 | if task.push is not None: |
|
571 | d.addBoth(task.stop_time) | |
271 | d.addCallback(lambda r: self.queuedEngine.push(task.push)) |
|
572 | d.addBoth(task.process_result, self.queuedEngine.id) | |
272 |
|
573 | # At this point, there will be (success, result) coming down the line | ||
273 | d.addCallback(lambda r: self.queuedEngine.execute(task.expression)) |
|
574 | return d | |
274 |
|
575 | |||
275 | if task.pull is not None: |
|
|||
276 | d.addCallback(lambda r: self.queuedEngine.pull(task.pull)) |
|
|||
277 | else: |
|
|||
278 | d.addCallback(lambda r: None) |
|
|||
279 |
|
||||
280 | def reseter(result): |
|
|||
281 | self.queuedEngine.reset() |
|
|||
282 | return result |
|
|||
283 |
|
||||
284 | if task.clear_after: |
|
|||
285 | d.addBoth(reseter) |
|
|||
286 |
|
||||
287 | return d.addBoth(self._zipResults, task.pull, time.time(), time.localtime()) |
|
|||
288 |
|
||||
289 | def _zipResults(self, result, names, start, start_struct): |
|
|||
290 | """Callback for construting the TaskResult object.""" |
|
|||
291 | if isinstance(result, failure.Failure): |
|
|||
292 | tr = TaskResult(result, self.queuedEngine.id) |
|
|||
293 | else: |
|
|||
294 | if names is None: |
|
|||
295 | resultDict = {} |
|
|||
296 | elif len(names) == 1: |
|
|||
297 | resultDict = {names[0]:result} |
|
|||
298 | else: |
|
|||
299 | resultDict = dict(zip(names, result)) |
|
|||
300 | tr = TaskResult(resultDict, self.queuedEngine.id) |
|
|||
301 | # the time info |
|
|||
302 | tr.submitted = time.strftime(time_format, start_struct) |
|
|||
303 | tr.completed = time.strftime(time_format) |
|
|||
304 | tr.duration = time.time()-start |
|
|||
305 | return tr |
|
|||
306 |
|
||||
307 |
|
576 | |||
308 | components.registerAdapter(WorkerFromQueuedEngine, es.IEngineQueued, IWorker) |
|
577 | components.registerAdapter(WorkerFromQueuedEngine, es.IEngineQueued, IWorker) | |
309 |
|
578 | |||
@@ -319,14 +588,14 b' class IScheduler(zi.Interface):' | |||||
319 | """Add a task to the queue of the Scheduler. |
|
588 | """Add a task to the queue of the Scheduler. | |
320 |
|
589 | |||
321 | :Parameters: |
|
590 | :Parameters: | |
322 |
task : a `Task` |
|
591 | task : an `ITask` implementer | |
323 | The task to be queued. |
|
592 | The task to be queued. | |
324 | flags : dict |
|
593 | flags : dict | |
325 | General keywords for more sophisticated scheduling |
|
594 | General keywords for more sophisticated scheduling | |
326 | """ |
|
595 | """ | |
327 |
|
596 | |||
328 | def pop_task(id=None): |
|
597 | def pop_task(id=None): | |
329 |
"""Pops a |
|
598 | """Pops a task object from the queue. | |
330 |
|
599 | |||
331 | This gets the next task to be run. If no `id` is requested, the highest priority |
|
600 | This gets the next task to be run. If no `id` is requested, the highest priority | |
332 | task is returned. |
|
601 | task is returned. | |
@@ -336,7 +605,7 b' class IScheduler(zi.Interface):' | |||||
336 | The id of the task to be popped. The default (None) is to return |
|
605 | The id of the task to be popped. The default (None) is to return | |
337 | the highest priority task. |
|
606 | the highest priority task. | |
338 |
|
607 | |||
339 |
:Returns: a `Task` |
|
608 | :Returns: an `ITask` implementer | |
340 |
|
609 | |||
341 | :Exceptions: |
|
610 | :Exceptions: | |
342 | IndexError : raised if no taskid in queue |
|
611 | IndexError : raised if no taskid in queue | |
@@ -346,8 +615,9 b' class IScheduler(zi.Interface):' | |||||
346 | """Add a worker to the worker queue. |
|
615 | """Add a worker to the worker queue. | |
347 |
|
616 | |||
348 | :Parameters: |
|
617 | :Parameters: | |
349 |
worker : an IWorker implement |
|
618 | worker : an `IWorker` implementer | |
350 | flags : General keywords for more sophisticated scheduling |
|
619 | flags : dict | |
|
620 | General keywords for more sophisticated scheduling | |||
351 | """ |
|
621 | """ | |
352 |
|
622 | |||
353 | def pop_worker(id=None): |
|
623 | def pop_worker(id=None): | |
@@ -370,15 +640,15 b' class IScheduler(zi.Interface):' | |||||
370 | """Returns True if there is something to do, False otherwise""" |
|
640 | """Returns True if there is something to do, False otherwise""" | |
371 |
|
641 | |||
372 | def schedule(): |
|
642 | def schedule(): | |
373 |
"""Returns |
|
643 | """Returns (worker,task) pair for the next task to be run.""" | |
374 | task to be run. |
|
|||
375 | """ |
|
|||
376 |
|
644 | |||
377 |
|
645 | |||
378 | class FIFOScheduler(object): |
|
646 | class FIFOScheduler(object): | |
379 | """A basic First-In-First-Out (Queue) Scheduler. |
|
647 | """ | |
380 | This is the default Scheduler for the TaskController. |
|
648 | A basic First-In-First-Out (Queue) Scheduler. | |
381 | See the docstrings for IScheduler for interface details. |
|
649 | ||
|
650 | This is the default Scheduler for the `TaskController`. | |||
|
651 | See the docstrings for `IScheduler` for interface details. | |||
382 | """ |
|
652 | """ | |
383 |
|
653 | |||
384 | zi.implements(IScheduler) |
|
654 | zi.implements(IScheduler) | |
@@ -435,7 +705,9 b' class FIFOScheduler(object):' | |||||
435 | for t in self.tasks: |
|
705 | for t in self.tasks: | |
436 | for w in self.workers: |
|
706 | for w in self.workers: | |
437 | try:# do not allow exceptions to break this |
|
707 | try:# do not allow exceptions to break this | |
438 | cando = t.depend is None or t.depend(w.properties) |
|
708 | # Allow the task to check itself using its | |
|
709 | # check_depend method. | |||
|
710 | cando = t.check_depend(w.properties) | |||
439 | except: |
|
711 | except: | |
440 | cando = False |
|
712 | cando = False | |
441 | if cando: |
|
713 | if cando: | |
@@ -445,9 +717,12 b' class FIFOScheduler(object):' | |||||
445 |
|
717 | |||
446 |
|
718 | |||
447 | class LIFOScheduler(FIFOScheduler): |
|
719 | class LIFOScheduler(FIFOScheduler): | |
448 | """A Last-In-First-Out (Stack) Scheduler. This scheduler should naively |
|
720 | """ | |
449 | reward fast engines by giving them more jobs. This risks starvation, but |
|
721 | A Last-In-First-Out (Stack) Scheduler. | |
450 | only in cases with low load, where starvation does not really matter. |
|
722 | ||
|
723 | This scheduler should naively reward fast engines by giving | |||
|
724 | them more jobs. This risks starvation, but only in cases with | |||
|
725 | low load, where starvation does not really matter. | |||
451 | """ |
|
726 | """ | |
452 |
|
727 | |||
453 | def add_task(self, task, **flags): |
|
728 | def add_task(self, task, **flags): | |
@@ -462,13 +737,15 b' class LIFOScheduler(FIFOScheduler):' | |||||
462 |
|
737 | |||
463 |
|
738 | |||
464 | class ITaskController(cs.IControllerBase): |
|
739 | class ITaskController(cs.IControllerBase): | |
465 | """The Task based interface to a `ControllerService` object |
|
740 | """ | |
|
741 | The Task based interface to a `ControllerService` object | |||
466 |
|
742 | |||
467 | This adapts a `ControllerService` to the ITaskController interface. |
|
743 | This adapts a `ControllerService` to the ITaskController interface. | |
468 | """ |
|
744 | """ | |
469 |
|
745 | |||
470 | def run(task): |
|
746 | def run(task): | |
471 |
""" |
|
747 | """ | |
|
748 | Run a task. | |||
472 |
|
749 | |||
473 | :Parameters: |
|
750 | :Parameters: | |
474 | task : an IPython `Task` object |
|
751 | task : an IPython `Task` object | |
@@ -477,13 +754,14 b' class ITaskController(cs.IControllerBase):' | |||||
477 | """ |
|
754 | """ | |
478 |
|
755 | |||
479 | def get_task_result(taskid, block=False): |
|
756 | def get_task_result(taskid, block=False): | |
480 | """Get the result of a task by its ID. |
|
757 | """ | |
|
758 | Get the result of a task by its ID. | |||
481 |
|
759 | |||
482 | :Parameters: |
|
760 | :Parameters: | |
483 | taskid : int |
|
761 | taskid : int | |
484 | the id of the task whose result is requested |
|
762 | the id of the task whose result is requested | |
485 |
|
763 | |||
486 |
:Returns: `Deferred` to |
|
764 | :Returns: `Deferred` to the task result if the task is done, and None | |
487 | if not. |
|
765 | if not. | |
488 |
|
766 | |||
489 | :Exceptions: |
|
767 | :Exceptions: | |
@@ -508,23 +786,35 b' class ITaskController(cs.IControllerBase):' | |||||
508 | """ |
|
786 | """ | |
509 |
|
787 | |||
510 | def barrier(taskids): |
|
788 | def barrier(taskids): | |
511 | """Block until the list of taskids are completed. |
|
789 | """ | |
|
790 | Block until the list of taskids are completed. | |||
512 |
|
791 | |||
513 | Returns None on success. |
|
792 | Returns None on success. | |
514 | """ |
|
793 | """ | |
515 |
|
794 | |||
516 | def spin(): |
|
795 | def spin(): | |
517 | """touch the scheduler, to resume scheduling without submitting |
|
796 | """ | |
518 | a task. |
|
797 | Touch the scheduler, to resume scheduling without submitting a task. | |
519 | """ |
|
798 | """ | |
520 |
|
799 | |||
521 |
def queue_status( |
|
800 | def queue_status(verbose=False): | |
522 | """Get a dictionary with the current state of the task queue. |
|
801 | """ | |
|
802 | Get a dictionary with the current state of the task queue. | |||
523 |
|
803 | |||
524 | If verbose is True, then return lists of taskids, otherwise, |
|
804 | If verbose is True, then return lists of taskids, otherwise, | |
525 | return the number of tasks with each status. |
|
805 | return the number of tasks with each status. | |
526 | """ |
|
806 | """ | |
527 |
|
807 | |||
|
808 | def clear(): | |||
|
809 | """ | |||
|
810 | Clear all previously run tasks from the task controller. | |||
|
811 | ||||
|
812 | This is needed because the task controller keep all task results | |||
|
813 | in memory. This can be a problem is there are many completed | |||
|
814 | tasks. Users should call this periodically to clean out these | |||
|
815 | cached task results. | |||
|
816 | """ | |||
|
817 | ||||
528 |
|
818 | |||
529 | class TaskController(cs.ControllerAdapterBase): |
|
819 | class TaskController(cs.ControllerAdapterBase): | |
530 | """The Task based interface to a Controller object. |
|
820 | """The Task based interface to a Controller object. | |
@@ -561,7 +851,7 b' class TaskController(cs.ControllerAdapterBase):' | |||||
561 | def registerWorker(self, id): |
|
851 | def registerWorker(self, id): | |
562 | """Called by controller.register_engine.""" |
|
852 | """Called by controller.register_engine.""" | |
563 | if self.workers.get(id): |
|
853 | if self.workers.get(id): | |
564 |
raise " |
|
854 | raise ValueError("worker with id %s already exists. This should not happen." % id) | |
565 | self.workers[id] = IWorker(self.controller.engines[id]) |
|
855 | self.workers[id] = IWorker(self.controller.engines[id]) | |
566 | self.workers[id].workerid = id |
|
856 | self.workers[id].workerid = id | |
567 | if not self.pendingTasks.has_key(id):# if not working |
|
857 | if not self.pendingTasks.has_key(id):# if not working | |
@@ -586,21 +876,25 b' class TaskController(cs.ControllerAdapterBase):' | |||||
586 | #--------------------------------------------------------------------------- |
|
876 | #--------------------------------------------------------------------------- | |
587 |
|
877 | |||
588 | def run(self, task): |
|
878 | def run(self, task): | |
589 | """Run a task and return `Deferred` to its taskid.""" |
|
879 | """ | |
|
880 | Run a task and return `Deferred` to its taskid. | |||
|
881 | """ | |||
590 | task.taskid = self.taskid |
|
882 | task.taskid = self.taskid | |
591 | task.start = time.localtime() |
|
883 | task.start = time.localtime() | |
592 | self.taskid += 1 |
|
884 | self.taskid += 1 | |
593 | d = defer.Deferred() |
|
885 | d = defer.Deferred() | |
594 | self.scheduler.add_task(task) |
|
886 | self.scheduler.add_task(task) | |
595 |
|
|
887 | log.msg('Queuing task: %i' % task.taskid) | |
596 |
|
888 | |||
597 | self.deferredResults[task.taskid] = [] |
|
889 | self.deferredResults[task.taskid] = [] | |
598 | self.distributeTasks() |
|
890 | self.distributeTasks() | |
599 | return defer.succeed(task.taskid) |
|
891 | return defer.succeed(task.taskid) | |
600 |
|
892 | |||
601 | def get_task_result(self, taskid, block=False): |
|
893 | def get_task_result(self, taskid, block=False): | |
602 | """Returns a `Deferred` to a TaskResult tuple or None.""" |
|
894 | """ | |
603 | # log.msg("Getting task result: %i" % taskid) |
|
895 | Returns a `Deferred` to the task result, or None. | |
|
896 | """ | |||
|
897 | log.msg("Getting task result: %i" % taskid) | |||
604 | if self.finishedResults.has_key(taskid): |
|
898 | if self.finishedResults.has_key(taskid): | |
605 | tr = self.finishedResults[taskid] |
|
899 | tr = self.finishedResults[taskid] | |
606 | return defer.succeed(tr) |
|
900 | return defer.succeed(tr) | |
@@ -615,7 +909,9 b' class TaskController(cs.ControllerAdapterBase):' | |||||
615 | return defer.fail(IndexError("task ID not registered: %r" % taskid)) |
|
909 | return defer.fail(IndexError("task ID not registered: %r" % taskid)) | |
616 |
|
910 | |||
617 | def abort(self, taskid): |
|
911 | def abort(self, taskid): | |
618 | """Remove a task from the queue if it has not been run already.""" |
|
912 | """ | |
|
913 | Remove a task from the queue if it has not been run already. | |||
|
914 | """ | |||
619 | if not isinstance(taskid, int): |
|
915 | if not isinstance(taskid, int): | |
620 | return defer.fail(failure.Failure(TypeError("an integer task id expected: %r" % taskid))) |
|
916 | return defer.fail(failure.Failure(TypeError("an integer task id expected: %r" % taskid))) | |
621 | try: |
|
917 | try: | |
@@ -674,8 +970,10 b' class TaskController(cs.ControllerAdapterBase):' | |||||
674 | #--------------------------------------------------------------------------- |
|
970 | #--------------------------------------------------------------------------- | |
675 |
|
971 | |||
676 | def _doAbort(self, taskid): |
|
972 | def _doAbort(self, taskid): | |
677 | """Helper function for aborting a pending task.""" |
|
973 | """ | |
678 | # log.msg("Task aborted: %i" % taskid) |
|
974 | Helper function for aborting a pending task. | |
|
975 | """ | |||
|
976 | log.msg("Task aborted: %i" % taskid) | |||
679 | result = failure.Failure(error.TaskAborted()) |
|
977 | result = failure.Failure(error.TaskAborted()) | |
680 | self._finishTask(taskid, result) |
|
978 | self._finishTask(taskid, result) | |
681 | if taskid in self.abortPending: |
|
979 | if taskid in self.abortPending: | |
@@ -683,14 +981,16 b' class TaskController(cs.ControllerAdapterBase):' | |||||
683 |
|
981 | |||
684 | def _finishTask(self, taskid, result): |
|
982 | def _finishTask(self, taskid, result): | |
685 | dlist = self.deferredResults.pop(taskid) |
|
983 | dlist = self.deferredResults.pop(taskid) | |
686 | result.taskid = taskid # The TaskResult should save the taskid |
|
984 | # result.taskid = taskid # The TaskResult should save the taskid | |
687 | self.finishedResults[taskid] = result |
|
985 | self.finishedResults[taskid] = result | |
688 | for d in dlist: |
|
986 | for d in dlist: | |
689 | d.callback(result) |
|
987 | d.callback(result) | |
690 |
|
988 | |||
691 | def distributeTasks(self): |
|
989 | def distributeTasks(self): | |
692 | """Distribute tasks while self.scheduler has things to do.""" |
|
990 | """ | |
693 | # log.msg("distributing Tasks") |
|
991 | Distribute tasks while self.scheduler has things to do. | |
|
992 | """ | |||
|
993 | log.msg("distributing Tasks") | |||
694 | worker, task = self.scheduler.schedule() |
|
994 | worker, task = self.scheduler.schedule() | |
695 | if not worker and not task: |
|
995 | if not worker and not task: | |
696 | if self.idleLater and self.idleLater.called:# we are inside failIdle |
|
996 | if self.idleLater and self.idleLater.called:# we are inside failIdle | |
@@ -705,7 +1005,7 b' class TaskController(cs.ControllerAdapterBase):' | |||||
705 | self.pendingTasks[worker.workerid] = task |
|
1005 | self.pendingTasks[worker.workerid] = task | |
706 | # run/link callbacks |
|
1006 | # run/link callbacks | |
707 | d = worker.run(task) |
|
1007 | d = worker.run(task) | |
708 |
|
|
1008 | log.msg("Running task %i on worker %i" %(task.taskid, worker.workerid)) | |
709 | d.addBoth(self.taskCompleted, task.taskid, worker.workerid) |
|
1009 | d.addBoth(self.taskCompleted, task.taskid, worker.workerid) | |
710 | worker, task = self.scheduler.schedule() |
|
1010 | worker, task = self.scheduler.schedule() | |
711 | # check for idle timeout: |
|
1011 | # check for idle timeout: | |
@@ -727,14 +1027,15 b' class TaskController(cs.ControllerAdapterBase):' | |||||
727 | t = self.scheduler.pop_task() |
|
1027 | t = self.scheduler.pop_task() | |
728 | msg = "task %i failed to execute due to unmet dependencies"%t.taskid |
|
1028 | msg = "task %i failed to execute due to unmet dependencies"%t.taskid | |
729 | msg += " for %i seconds"%self.timeout |
|
1029 | msg += " for %i seconds"%self.timeout | |
730 |
|
|
1030 | log.msg("Task aborted by timeout: %i" % t.taskid) | |
731 | f = failure.Failure(error.TaskTimeout(msg)) |
|
1031 | f = failure.Failure(error.TaskTimeout(msg)) | |
732 | self._finishTask(t.taskid, f) |
|
1032 | self._finishTask(t.taskid, f) | |
733 | self.idleLater = None |
|
1033 | self.idleLater = None | |
734 |
|
1034 | |||
735 |
|
1035 | |||
736 | def taskCompleted(self, result, taskid, workerid): |
|
1036 | def taskCompleted(self, success_and_result, taskid, workerid): | |
737 | """This is the err/callback for a completed task.""" |
|
1037 | """This is the err/callback for a completed task.""" | |
|
1038 | success, result = success_and_result | |||
738 | try: |
|
1039 | try: | |
739 | task = self.pendingTasks.pop(workerid) |
|
1040 | task = self.pendingTasks.pop(workerid) | |
740 | except: |
|
1041 | except: | |
@@ -751,7 +1052,7 b' class TaskController(cs.ControllerAdapterBase):' | |||||
751 | aborted = True |
|
1052 | aborted = True | |
752 |
|
1053 | |||
753 | if not aborted: |
|
1054 | if not aborted: | |
754 | if result.failure is not None and isinstance(result.failure, failure.Failure): # we failed |
|
1055 | if not success: | |
755 | log.msg("Task %i failed on worker %i"% (taskid, workerid)) |
|
1056 | log.msg("Task %i failed on worker %i"% (taskid, workerid)) | |
756 | if task.retries > 0: # resubmit |
|
1057 | if task.retries > 0: # resubmit | |
757 | task.retries -= 1 |
|
1058 | task.retries -= 1 | |
@@ -759,7 +1060,7 b' class TaskController(cs.ControllerAdapterBase):' | |||||
759 | s = "Resubmitting task %i, %i retries remaining" %(taskid, task.retries) |
|
1060 | s = "Resubmitting task %i, %i retries remaining" %(taskid, task.retries) | |
760 | log.msg(s) |
|
1061 | log.msg(s) | |
761 | self.distributeTasks() |
|
1062 | self.distributeTasks() | |
762 | elif isinstance(task.recovery_task, Task) and \ |
|
1063 | elif isinstance(task.recovery_task, BaseTask) and \ | |
763 | task.recovery_task.retries > -1: |
|
1064 | task.recovery_task.retries > -1: | |
764 | # retries = -1 is to prevent infinite recovery_task loop |
|
1065 | # retries = -1 is to prevent infinite recovery_task loop | |
765 | task.retries = -1 |
|
1066 | task.retries = -1 | |
@@ -775,17 +1076,18 b' class TaskController(cs.ControllerAdapterBase):' | |||||
775 | # it may have died, and not yet been unregistered |
|
1076 | # it may have died, and not yet been unregistered | |
776 | reactor.callLater(self.failurePenalty, self.readmitWorker, workerid) |
|
1077 | reactor.callLater(self.failurePenalty, self.readmitWorker, workerid) | |
777 | else: # we succeeded |
|
1078 | else: # we succeeded | |
778 |
|
|
1079 | log.msg("Task completed: %i"% taskid) | |
779 | self._finishTask(taskid, result) |
|
1080 | self._finishTask(taskid, result) | |
780 | self.readmitWorker(workerid) |
|
1081 | self.readmitWorker(workerid) | |
781 | else:# we aborted the task |
|
1082 | else: # we aborted the task | |
782 | if result.failure is not None and isinstance(result.failure, failure.Failure): # it failed, penalize worker |
|
1083 | if not success: | |
783 | reactor.callLater(self.failurePenalty, self.readmitWorker, workerid) |
|
1084 | reactor.callLater(self.failurePenalty, self.readmitWorker, workerid) | |
784 | else: |
|
1085 | else: | |
785 | self.readmitWorker(workerid) |
|
1086 | self.readmitWorker(workerid) | |
786 |
|
1087 | |||
787 | def readmitWorker(self, workerid): |
|
1088 | def readmitWorker(self, workerid): | |
788 | """Readmit a worker to the scheduler. |
|
1089 | """ | |
|
1090 | Readmit a worker to the scheduler. | |||
789 |
|
1091 | |||
790 | This is outside `taskCompleted` because of the `failurePenalty` being |
|
1092 | This is outside `taskCompleted` because of the `failurePenalty` being | |
791 | implemented through `reactor.callLater`. |
|
1093 | implemented through `reactor.callLater`. | |
@@ -794,6 +1096,18 b' class TaskController(cs.ControllerAdapterBase):' | |||||
794 | if workerid in self.workers.keys() and workerid not in self.pendingTasks.keys(): |
|
1096 | if workerid in self.workers.keys() and workerid not in self.pendingTasks.keys(): | |
795 | self.scheduler.add_worker(self.workers[workerid]) |
|
1097 | self.scheduler.add_worker(self.workers[workerid]) | |
796 | self.distributeTasks() |
|
1098 | self.distributeTasks() | |
|
1099 | ||||
|
1100 | def clear(self): | |||
|
1101 | """ | |||
|
1102 | Clear all previously run tasks from the task controller. | |||
|
1103 | ||||
|
1104 | This is needed because the task controller keep all task results | |||
|
1105 | in memory. This can be a problem is there are many completed | |||
|
1106 | tasks. Users should call this periodically to clean out these | |||
|
1107 | cached task results. | |||
|
1108 | """ | |||
|
1109 | self.finishedResults = {} | |||
|
1110 | return defer.succeed(None) | |||
797 |
|
1111 | |||
798 |
|
1112 | |||
799 | components.registerAdapter(TaskController, cs.IControllerBase, ITaskController) |
|
1113 | components.registerAdapter(TaskController, cs.IControllerBase, ITaskController) |
@@ -1,9 +1,8 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | # -*- test-case-name: IPython.kernel.tests.test_taskcontrollerxmlrpc -*- |
|
2 | # -*- test-case-name: IPython.kernel.tests.test_taskcontrollerxmlrpc -*- | |
3 |
|
3 | |||
4 | """The Generic Task Client object. |
|
4 | """ | |
5 |
|
5 | A blocking version of the task client. | ||
6 | This must be subclassed based on your connection method. |
|
|||
7 | """ |
|
6 | """ | |
8 |
|
7 | |||
9 | __docformat__ = "restructuredtext en" |
|
8 | __docformat__ = "restructuredtext en" | |
@@ -24,119 +23,100 b' from twisted.python import components, log' | |||||
24 |
|
23 | |||
25 | from IPython.kernel.twistedutil import blockingCallFromThread |
|
24 | from IPython.kernel.twistedutil import blockingCallFromThread | |
26 | from IPython.kernel import task, error |
|
25 | from IPython.kernel import task, error | |
|
26 | from IPython.kernel.mapper import ( | |||
|
27 | SynchronousTaskMapper, | |||
|
28 | ITaskMapperFactory, | |||
|
29 | IMapper | |||
|
30 | ) | |||
|
31 | from IPython.kernel.parallelfunction import ( | |||
|
32 | ParallelFunction, | |||
|
33 | ITaskParallelDecorator | |||
|
34 | ) | |||
27 |
|
35 | |||
28 | #------------------------------------------------------------------------------- |
|
36 | #------------------------------------------------------------------------------- | |
29 |
# |
|
37 | # The task client | |
30 | #------------------------------------------------------------------------------- |
|
38 | #------------------------------------------------------------------------------- | |
31 |
|
39 | |||
32 | class InteractiveTaskClient(object): |
|
|||
33 |
|
||||
34 | def irun(self, *args, **kwargs): |
|
|||
35 | """Run a task on the `TaskController`. |
|
|||
36 |
|
||||
37 | This method is a shorthand for run(task) and its arguments are simply |
|
|||
38 | passed onto a `Task` object: |
|
|||
39 |
|
||||
40 | irun(*args, **kwargs) -> run(Task(*args, **kwargs)) |
|
|||
41 |
|
||||
42 | :Parameters: |
|
|||
43 | expression : str |
|
|||
44 | A str that is valid python code that is the task. |
|
|||
45 | pull : str or list of str |
|
|||
46 | The names of objects to be pulled as results. |
|
|||
47 | push : dict |
|
|||
48 | A dict of objects to be pushed into the engines namespace before |
|
|||
49 | execution of the expression. |
|
|||
50 | clear_before : boolean |
|
|||
51 | Should the engine's namespace be cleared before the task is run. |
|
|||
52 | Default=False. |
|
|||
53 | clear_after : boolean |
|
|||
54 | Should the engine's namespace be cleared after the task is run. |
|
|||
55 | Default=False. |
|
|||
56 | retries : int |
|
|||
57 | The number of times to resumbit the task if it fails. Default=0. |
|
|||
58 | options : dict |
|
|||
59 | Any other keyword options for more elaborate uses of tasks |
|
|||
60 |
|
||||
61 | :Returns: A `TaskResult` object. |
|
|||
62 | """ |
|
|||
63 | block = kwargs.pop('block', False) |
|
|||
64 | if len(args) == 1 and isinstance(args[0], task.Task): |
|
|||
65 | t = args[0] |
|
|||
66 | else: |
|
|||
67 | t = task.Task(*args, **kwargs) |
|
|||
68 | taskid = self.run(t) |
|
|||
69 | print "TaskID = %i"%taskid |
|
|||
70 | if block: |
|
|||
71 | return self.get_task_result(taskid, block) |
|
|||
72 | else: |
|
|||
73 | return taskid |
|
|||
74 |
|
||||
75 | class IBlockingTaskClient(Interface): |
|
40 | class IBlockingTaskClient(Interface): | |
76 | """ |
|
41 | """ | |
77 |
A |
|
42 | A vague interface of the blocking task client | |
78 | """ |
|
43 | """ | |
79 | pass |
|
44 | pass | |
80 |
|
45 | |||
81 |
|
46 | class BlockingTaskClient(object): | ||
82 | class BlockingTaskClient(InteractiveTaskClient): |
|
|||
83 | """ |
|
47 | """ | |
84 | This class provides a blocking task client. |
|
48 | A blocking task client that adapts a non-blocking one. | |
85 | """ |
|
49 | """ | |
86 |
|
50 | |||
87 |
implements( |
|
51 | implements( | |
|
52 | IBlockingTaskClient, | |||
|
53 | ITaskMapperFactory, | |||
|
54 | IMapper, | |||
|
55 | ITaskParallelDecorator | |||
|
56 | ) | |||
88 |
|
57 | |||
89 | def __init__(self, task_controller): |
|
58 | def __init__(self, task_controller): | |
90 | self.task_controller = task_controller |
|
59 | self.task_controller = task_controller | |
91 | self.block = True |
|
60 | self.block = True | |
92 |
|
61 | |||
93 | def run(self, task): |
|
62 | def run(self, task, block=False): | |
94 | """ |
|
63 | """Run a task on the `TaskController`. | |
95 | Run a task and return a task id that can be used to get the task result. |
|
64 | ||
|
65 | See the documentation of the `MapTask` and `StringTask` classes for | |||
|
66 | details on how to build a task of different types. | |||
96 |
|
67 | |||
97 | :Parameters: |
|
68 | :Parameters: | |
98 | task : `Task` |
|
69 | task : an `ITask` implementer | |
99 | The `Task` object to run |
|
70 | ||
|
71 | :Returns: The int taskid of the submitted task. Pass this to | |||
|
72 | `get_task_result` to get the `TaskResult` object. | |||
100 | """ |
|
73 | """ | |
101 |
|
|
74 | tid = blockingCallFromThread(self.task_controller.run, task) | |
|
75 | if block: | |||
|
76 | return self.get_task_result(tid, block=True) | |||
|
77 | else: | |||
|
78 | return tid | |||
102 |
|
79 | |||
103 | def get_task_result(self, taskid, block=False): |
|
80 | def get_task_result(self, taskid, block=False): | |
104 | """ |
|
81 | """ | |
105 |
Get |
|
82 | Get a task result by taskid. | |
106 |
|
83 | |||
107 | :Parameters: |
|
84 | :Parameters: | |
108 | taskid : int |
|
85 | taskid : int | |
109 |
The id of the task |
|
86 | The taskid of the task to be retrieved. | |
110 | block : boolean |
|
87 | block : boolean | |
111 |
|
|
88 | Should I block until the task is done? | |
112 | `TaskResult` object. If False, just poll for the result and |
|
89 | ||
113 | return None if the task is not done. |
|
90 | :Returns: A `TaskResult` object that encapsulates the task result. | |
114 | """ |
|
91 | """ | |
115 | return blockingCallFromThread(self.task_controller.get_task_result, |
|
92 | return blockingCallFromThread(self.task_controller.get_task_result, | |
116 | taskid, block) |
|
93 | taskid, block) | |
117 |
|
94 | |||
118 | def abort(self, taskid): |
|
95 | def abort(self, taskid): | |
119 | """ |
|
96 | """ | |
120 |
Abort a task by task |
|
97 | Abort a task by taskid. | |
|
98 | ||||
|
99 | :Parameters: | |||
|
100 | taskid : int | |||
|
101 | The taskid of the task to be aborted. | |||
121 | """ |
|
102 | """ | |
122 | return blockingCallFromThread(self.task_controller.abort, taskid) |
|
103 | return blockingCallFromThread(self.task_controller.abort, taskid) | |
123 |
|
104 | |||
124 | def barrier(self, taskids): |
|
105 | def barrier(self, taskids): | |
125 | """ |
|
106 | """Block until a set of tasks are completed. | |
126 | Wait for a set of tasks to finish. |
|
|||
127 |
|
107 | |||
128 | :Parameters: |
|
108 | :Parameters: | |
129 |
taskids : list |
|
109 | taskids : list, tuple | |
130 |
A |
|
110 | A sequence of taskids to block on. | |
131 | """ |
|
111 | """ | |
132 | return blockingCallFromThread(self.task_controller.barrier, taskids) |
|
112 | return blockingCallFromThread(self.task_controller.barrier, taskids) | |
133 |
|
113 | |||
134 | def spin(self): |
|
114 | def spin(self): | |
135 | """ |
|
115 | """ | |
136 |
|
|
116 | Touch the scheduler, to resume scheduling without submitting a task. | |
137 |
|
117 | |||
138 | This method only needs to be called in unusual situations where the |
|
118 | This method only needs to be called in unusual situations where the | |
139 | scheduler is idle for some reason. |
|
119 | scheduler is idle for some reason. | |
140 | """ |
|
120 | """ | |
141 | return blockingCallFromThread(self.task_controller.spin) |
|
121 | return blockingCallFromThread(self.task_controller.spin) | |
142 |
|
122 | |||
@@ -153,7 +133,46 b' class BlockingTaskClient(InteractiveTaskClient):' | |||||
153 | A dict with the queue status. |
|
133 | A dict with the queue status. | |
154 | """ |
|
134 | """ | |
155 | return blockingCallFromThread(self.task_controller.queue_status, verbose) |
|
135 | return blockingCallFromThread(self.task_controller.queue_status, verbose) | |
|
136 | ||||
|
137 | def clear(self): | |||
|
138 | """ | |||
|
139 | Clear all previously run tasks from the task controller. | |||
|
140 | ||||
|
141 | This is needed because the task controller keep all task results | |||
|
142 | in memory. This can be a problem is there are many completed | |||
|
143 | tasks. Users should call this periodically to clean out these | |||
|
144 | cached task results. | |||
|
145 | """ | |||
|
146 | return blockingCallFromThread(self.task_controller.clear) | |||
|
147 | ||||
|
148 | def map(self, func, *sequences): | |||
|
149 | """ | |||
|
150 | Apply func to *sequences elementwise. Like Python's builtin map. | |||
|
151 | ||||
|
152 | This version is load balanced. | |||
|
153 | """ | |||
|
154 | return self.mapper().map(func, *sequences) | |||
156 |
|
155 | |||
|
156 | def mapper(self, clear_before=False, clear_after=False, retries=0, | |||
|
157 | recovery_task=None, depend=None, block=True): | |||
|
158 | """ | |||
|
159 | Create an `IMapper` implementer with a given set of arguments. | |||
|
160 | ||||
|
161 | The `IMapper` created using a task controller is load balanced. | |||
|
162 | ||||
|
163 | See the documentation for `IPython.kernel.task.BaseTask` for | |||
|
164 | documentation on the arguments to this method. | |||
|
165 | """ | |||
|
166 | return SynchronousTaskMapper(self, clear_before=clear_before, | |||
|
167 | clear_after=clear_after, retries=retries, | |||
|
168 | recovery_task=recovery_task, depend=depend, block=block) | |||
|
169 | ||||
|
170 | def parallel(self, clear_before=False, clear_after=False, retries=0, | |||
|
171 | recovery_task=None, depend=None, block=True): | |||
|
172 | mapper = self.mapper(clear_before, clear_after, retries, | |||
|
173 | recovery_task, depend, block) | |||
|
174 | pf = ParallelFunction(mapper) | |||
|
175 | return pf | |||
157 |
|
176 | |||
158 | components.registerAdapter(BlockingTaskClient, |
|
177 | components.registerAdapter(BlockingTaskClient, | |
159 | task.ITaskController, IBlockingTaskClient) |
|
178 | task.ITaskController, IBlockingTaskClient) |
@@ -34,6 +34,15 b' from IPython.kernel.clientinterfaces import (' | |||||
34 | IFCClientInterfaceProvider, |
|
34 | IFCClientInterfaceProvider, | |
35 | IBlockingClientAdaptor |
|
35 | IBlockingClientAdaptor | |
36 | ) |
|
36 | ) | |
|
37 | from IPython.kernel.mapper import ( | |||
|
38 | TaskMapper, | |||
|
39 | ITaskMapperFactory, | |||
|
40 | IMapper | |||
|
41 | ) | |||
|
42 | from IPython.kernel.parallelfunction import ( | |||
|
43 | ParallelFunction, | |||
|
44 | ITaskParallelDecorator | |||
|
45 | ) | |||
37 |
|
46 | |||
38 | #------------------------------------------------------------------------------- |
|
47 | #------------------------------------------------------------------------------- | |
39 | # The Controller side of things |
|
48 | # The Controller side of things | |
@@ -43,32 +52,38 b' from IPython.kernel.clientinterfaces import (' | |||||
43 | class IFCTaskController(Interface): |
|
52 | class IFCTaskController(Interface): | |
44 | """Foolscap interface to task controller. |
|
53 | """Foolscap interface to task controller. | |
45 |
|
54 | |||
46 |
See the documentation of ITaskController |
|
55 | See the documentation of `ITaskController` for more information. | |
47 | """ |
|
56 | """ | |
48 |
def remote_run( |
|
57 | def remote_run(binTask): | |
49 | """""" |
|
58 | """""" | |
50 |
|
59 | |||
51 |
def remote_abort( |
|
60 | def remote_abort(taskid): | |
52 | """""" |
|
61 | """""" | |
53 |
|
62 | |||
54 |
def remote_get_task_result( |
|
63 | def remote_get_task_result(taskid, block=False): | |
55 | """""" |
|
64 | """""" | |
56 |
|
65 | |||
57 |
def remote_barrier( |
|
66 | def remote_barrier(taskids): | |
|
67 | """""" | |||
|
68 | ||||
|
69 | def remote_spin(): | |||
58 | """""" |
|
70 | """""" | |
59 |
|
71 | |||
60 |
def remote_ |
|
72 | def remote_queue_status(verbose): | |
61 | """""" |
|
73 | """""" | |
62 |
|
74 | |||
63 | def remote_queue_status(request, verbose): |
|
75 | def remote_clear(): | |
64 | """""" |
|
76 | """""" | |
65 |
|
77 | |||
66 |
|
78 | |||
67 | class FCTaskControllerFromTaskController(Referenceable): |
|
79 | class FCTaskControllerFromTaskController(Referenceable): | |
68 | """XML-RPC attachmeot for controller. |
|
|||
69 |
|
||||
70 | See IXMLRPCTaskController and ITaskController (and its children) for documentation. |
|
|||
71 |
|
|
80 | """ | |
|
81 | Adapt a `TaskController` to an `IFCTaskController` | |||
|
82 | ||||
|
83 | This class is used to expose a `TaskController` over the wire using | |||
|
84 | the Foolscap network protocol. | |||
|
85 | """ | |||
|
86 | ||||
72 | implements(IFCTaskController, IFCClientInterfaceProvider) |
|
87 | implements(IFCTaskController, IFCClientInterfaceProvider) | |
73 |
|
88 | |||
74 | def __init__(self, taskController): |
|
89 | def __init__(self, taskController): | |
@@ -92,8 +107,8 b' class FCTaskControllerFromTaskController(Referenceable):' | |||||
92 |
|
107 | |||
93 | def remote_run(self, ptask): |
|
108 | def remote_run(self, ptask): | |
94 | try: |
|
109 | try: | |
95 |
|
|
110 | task = pickle.loads(ptask) | |
96 |
task |
|
111 | task.uncan_task() | |
97 | except: |
|
112 | except: | |
98 | d = defer.fail(pickle.UnpickleableError("Could not unmarshal task")) |
|
113 | d = defer.fail(pickle.UnpickleableError("Could not unmarshal task")) | |
99 | else: |
|
114 | else: | |
@@ -132,6 +147,9 b' class FCTaskControllerFromTaskController(Referenceable):' | |||||
132 | d.addErrback(self.packageFailure) |
|
147 | d.addErrback(self.packageFailure) | |
133 | return d |
|
148 | return d | |
134 |
|
149 | |||
|
150 | def remote_clear(self): | |||
|
151 | return self.taskController.clear() | |||
|
152 | ||||
135 | def remote_get_client_name(self): |
|
153 | def remote_get_client_name(self): | |
136 | return 'IPython.kernel.taskfc.FCTaskClient' |
|
154 | return 'IPython.kernel.taskfc.FCTaskClient' | |
137 |
|
155 | |||
@@ -144,13 +162,23 b' components.registerAdapter(FCTaskControllerFromTaskController,' | |||||
144 | #------------------------------------------------------------------------------- |
|
162 | #------------------------------------------------------------------------------- | |
145 |
|
163 | |||
146 | class FCTaskClient(object): |
|
164 | class FCTaskClient(object): | |
147 | """XML-RPC based TaskController client that implements ITaskController. |
|
|||
148 |
|
||||
149 | :Parameters: |
|
|||
150 | addr : (ip, port) |
|
|||
151 | The ip (str) and port (int) tuple of the `TaskController`. |
|
|||
152 |
|
|
165 | """ | |
153 | implements(taskmodule.ITaskController, IBlockingClientAdaptor) |
|
166 | Client class for Foolscap exposed `TaskController`. | |
|
167 | ||||
|
168 | This class is an adapter that makes a `RemoteReference` to a | |||
|
169 | `TaskController` look like an actual `ITaskController` on the client side. | |||
|
170 | ||||
|
171 | This class also implements `IBlockingClientAdaptor` so that clients can | |||
|
172 | automatically get a blocking version of this class. | |||
|
173 | """ | |||
|
174 | ||||
|
175 | implements( | |||
|
176 | taskmodule.ITaskController, | |||
|
177 | IBlockingClientAdaptor, | |||
|
178 | ITaskMapperFactory, | |||
|
179 | IMapper, | |||
|
180 | ITaskParallelDecorator | |||
|
181 | ) | |||
154 |
|
182 | |||
155 | def __init__(self, remote_reference): |
|
183 | def __init__(self, remote_reference): | |
156 | self.remote_reference = remote_reference |
|
184 | self.remote_reference = remote_reference | |
@@ -168,48 +196,26 b' class FCTaskClient(object):' | |||||
168 | def run(self, task): |
|
196 | def run(self, task): | |
169 | """Run a task on the `TaskController`. |
|
197 | """Run a task on the `TaskController`. | |
170 |
|
198 | |||
171 | :Parameters: |
|
199 | See the documentation of the `MapTask` and `StringTask` classes for | |
172 | task : a `Task` object |
|
200 | details on how to build a task of different types. | |
173 |
|
||||
174 | The Task object is created using the following signature: |
|
|||
175 |
|
||||
176 | Task(expression, pull=None, push={}, clear_before=False, |
|
|||
177 | clear_after=False, retries=0, **options):) |
|
|||
178 |
|
201 | |||
179 | The meaning of the arguments is as follows: |
|
202 | :Parameters: | |
|
203 | task : an `ITask` implementer | |||
180 |
|
204 | |||
181 | :Task Parameters: |
|
|||
182 | expression : str |
|
|||
183 | A str that is valid python code that is the task. |
|
|||
184 | pull : str or list of str |
|
|||
185 | The names of objects to be pulled as results. |
|
|||
186 | push : dict |
|
|||
187 | A dict of objects to be pushed into the engines namespace before |
|
|||
188 | execution of the expression. |
|
|||
189 | clear_before : boolean |
|
|||
190 | Should the engine's namespace be cleared before the task is run. |
|
|||
191 | Default=False. |
|
|||
192 | clear_after : boolean |
|
|||
193 | Should the engine's namespace be cleared after the task is run. |
|
|||
194 | Default=False. |
|
|||
195 | retries : int |
|
|||
196 | The number of times to resumbit the task if it fails. Default=0. |
|
|||
197 | options : dict |
|
|||
198 | Any other keyword options for more elaborate uses of tasks |
|
|||
199 |
|
||||
200 | :Returns: The int taskid of the submitted task. Pass this to |
|
205 | :Returns: The int taskid of the submitted task. Pass this to | |
201 | `get_task_result` to get the `TaskResult` object. |
|
206 | `get_task_result` to get the `TaskResult` object. | |
202 | """ |
|
207 | """ | |
203 | assert isinstance(task, taskmodule.Task), "task must be a Task object!" |
|
208 | assert isinstance(task, taskmodule.BaseTask), "task must be a Task object!" | |
204 | ctask = taskmodule.canTask(task) # handles arbitrary function in .depend |
|
209 | task.can_task() | |
205 | # as well as arbitrary recovery_task chains |
|
210 | ptask = pickle.dumps(task, 2) | |
206 | ptask = pickle.dumps(ctask, 2) |
|
211 | task.uncan_task() | |
207 | d = self.remote_reference.callRemote('run', ptask) |
|
212 | d = self.remote_reference.callRemote('run', ptask) | |
208 | d.addCallback(self.unpackage) |
|
213 | d.addCallback(self.unpackage) | |
209 | return d |
|
214 | return d | |
210 |
|
215 | |||
211 | def get_task_result(self, taskid, block=False): |
|
216 | def get_task_result(self, taskid, block=False): | |
212 | """The task result by taskid. |
|
217 | """ | |
|
218 | Get a task result by taskid. | |||
213 |
|
219 | |||
214 | :Parameters: |
|
220 | :Parameters: | |
215 | taskid : int |
|
221 | taskid : int | |
@@ -224,20 +230,19 b' class FCTaskClient(object):' | |||||
224 | return d |
|
230 | return d | |
225 |
|
231 | |||
226 | def abort(self, taskid): |
|
232 | def abort(self, taskid): | |
227 | """Abort a task by taskid. |
|
233 | """ | |
|
234 | Abort a task by taskid. | |||
228 |
|
235 | |||
229 | :Parameters: |
|
236 | :Parameters: | |
230 | taskid : int |
|
237 | taskid : int | |
231 | The taskid of the task to be aborted. |
|
238 | The taskid of the task to be aborted. | |
232 | block : boolean |
|
|||
233 | Should I block until the task is aborted. |
|
|||
234 | """ |
|
239 | """ | |
235 | d = self.remote_reference.callRemote('abort', taskid) |
|
240 | d = self.remote_reference.callRemote('abort', taskid) | |
236 | d.addCallback(self.unpackage) |
|
241 | d.addCallback(self.unpackage) | |
237 | return d |
|
242 | return d | |
238 |
|
243 | |||
239 | def barrier(self, taskids): |
|
244 | def barrier(self, taskids): | |
240 |
"""Block until a |
|
245 | """Block until a set of tasks are completed. | |
241 |
|
246 | |||
242 | :Parameters: |
|
247 | :Parameters: | |
243 | taskids : list, tuple |
|
248 | taskids : list, tuple | |
@@ -248,20 +253,77 b' class FCTaskClient(object):' | |||||
248 | return d |
|
253 | return d | |
249 |
|
254 | |||
250 | def spin(self): |
|
255 | def spin(self): | |
251 | """touch the scheduler, to resume scheduling without submitting |
|
256 | """ | |
252 | a task. |
|
257 | Touch the scheduler, to resume scheduling without submitting a task. | |
|
258 | ||||
|
259 | This method only needs to be called in unusual situations where the | |||
|
260 | scheduler is idle for some reason. | |||
253 | """ |
|
261 | """ | |
254 | d = self.remote_reference.callRemote('spin') |
|
262 | d = self.remote_reference.callRemote('spin') | |
255 | d.addCallback(self.unpackage) |
|
263 | d.addCallback(self.unpackage) | |
256 | return d |
|
264 | return d | |
257 |
|
265 | |||
258 | def queue_status(self, verbose=False): |
|
266 | def queue_status(self, verbose=False): | |
259 | """Return a dict with the status of the task queue.""" |
|
267 | """ | |
|
268 | Get a dictionary with the current state of the task queue. | |||
|
269 | ||||
|
270 | :Parameters: | |||
|
271 | verbose : boolean | |||
|
272 | If True, return a list of taskids. If False, simply give | |||
|
273 | the number of tasks with each status. | |||
|
274 | ||||
|
275 | :Returns: | |||
|
276 | A dict with the queue status. | |||
|
277 | """ | |||
260 | d = self.remote_reference.callRemote('queue_status', verbose) |
|
278 | d = self.remote_reference.callRemote('queue_status', verbose) | |
261 | d.addCallback(self.unpackage) |
|
279 | d.addCallback(self.unpackage) | |
262 | return d |
|
280 | return d | |
263 |
|
281 | |||
|
282 | def clear(self): | |||
|
283 | """ | |||
|
284 | Clear all previously run tasks from the task controller. | |||
|
285 | ||||
|
286 | This is needed because the task controller keep all task results | |||
|
287 | in memory. This can be a problem is there are many completed | |||
|
288 | tasks. Users should call this periodically to clean out these | |||
|
289 | cached task results. | |||
|
290 | """ | |||
|
291 | d = self.remote_reference.callRemote('clear') | |||
|
292 | return d | |||
|
293 | ||||
264 | def adapt_to_blocking_client(self): |
|
294 | def adapt_to_blocking_client(self): | |
|
295 | """ | |||
|
296 | Wrap self in a blocking version that implements `IBlockingTaskClient. | |||
|
297 | """ | |||
265 | from IPython.kernel.taskclient import IBlockingTaskClient |
|
298 | from IPython.kernel.taskclient import IBlockingTaskClient | |
266 | return IBlockingTaskClient(self) |
|
299 | return IBlockingTaskClient(self) | |
|
300 | ||||
|
301 | def map(self, func, *sequences): | |||
|
302 | """ | |||
|
303 | Apply func to *sequences elementwise. Like Python's builtin map. | |||
|
304 | ||||
|
305 | This version is load balanced. | |||
|
306 | """ | |||
|
307 | return self.mapper().map(func, *sequences) | |||
|
308 | ||||
|
309 | def mapper(self, clear_before=False, clear_after=False, retries=0, | |||
|
310 | recovery_task=None, depend=None, block=True): | |||
|
311 | """ | |||
|
312 | Create an `IMapper` implementer with a given set of arguments. | |||
|
313 | ||||
|
314 | The `IMapper` created using a task controller is load balanced. | |||
|
315 | ||||
|
316 | See the documentation for `IPython.kernel.task.BaseTask` for | |||
|
317 | documentation on the arguments to this method. | |||
|
318 | """ | |||
|
319 | return TaskMapper(self, clear_before=clear_before, | |||
|
320 | clear_after=clear_after, retries=retries, | |||
|
321 | recovery_task=recovery_task, depend=depend, block=block) | |||
|
322 | ||||
|
323 | def parallel(self, clear_before=False, clear_after=False, retries=0, | |||
|
324 | recovery_task=None, depend=None, block=True): | |||
|
325 | mapper = self.mapper(clear_before, clear_after, retries, | |||
|
326 | recovery_task, depend, block) | |||
|
327 | pf = ParallelFunction(mapper) | |||
|
328 | return pf | |||
267 |
|
329 |
@@ -163,7 +163,6 b' class IEngineCoreTestCase(object):' | |||||
163 | try: |
|
163 | try: | |
164 | import numpy |
|
164 | import numpy | |
165 | except: |
|
165 | except: | |
166 | print 'no numpy, ', |
|
|||
167 | return |
|
166 | return | |
168 | a = numpy.random.random(1000) |
|
167 | a = numpy.random.random(1000) | |
169 | d = self.engine.push(dict(a=a)) |
|
168 | d = self.engine.push(dict(a=a)) |
@@ -733,7 +733,7 b' class ISynchronousMultiEngineCoordinatorTestCase(IMultiEngineCoordinatorTestCase' | |||||
733 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
733 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
734 | d.addCallback(lambda r: self.assertEquals(r, range(16))) |
|
734 | d.addCallback(lambda r: self.assertEquals(r, range(16))) | |
735 | return d |
|
735 | return d | |
736 |
|
736 | |||
737 | def testScatterGatherNumpyNonblocking(self): |
|
737 | def testScatterGatherNumpyNonblocking(self): | |
738 | try: |
|
738 | try: | |
739 | import numpy |
|
739 | import numpy | |
@@ -749,17 +749,7 b' class ISynchronousMultiEngineCoordinatorTestCase(IMultiEngineCoordinatorTestCase' | |||||
749 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
749 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
750 | d.addCallback(lambda r: assert_array_equal(r, a)) |
|
750 | d.addCallback(lambda r: assert_array_equal(r, a)) | |
751 | return d |
|
751 | return d | |
752 |
|
752 | |||
753 | def testMapNonblocking(self): |
|
|||
754 | self.addEngine(4) |
|
|||
755 | def f(x): |
|
|||
756 | return x**2 |
|
|||
757 | data = range(16) |
|
|||
758 | d= self.multiengine.map(f, data, block=False) |
|
|||
759 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
|||
760 | d.addCallback(lambda r: self.assertEquals(r,[f(x) for x in data])) |
|
|||
761 | return d |
|
|||
762 |
|
||||
763 | def test_clear_pending_deferreds(self): |
|
753 | def test_clear_pending_deferreds(self): | |
764 | self.addEngine(4) |
|
754 | self.addEngine(4) | |
765 | did_list = [] |
|
755 | did_list = [] |
@@ -43,23 +43,23 b' class TaskTestBase(object):' | |||||
43 |
|
43 | |||
44 | class ITaskControllerTestCase(TaskTestBase): |
|
44 | class ITaskControllerTestCase(TaskTestBase): | |
45 |
|
45 | |||
46 |
def test |
|
46 | def test_task_ids(self): | |
47 | self.addEngine(1) |
|
47 | self.addEngine(1) | |
48 | d = self.tc.run(task.Task('a=5')) |
|
48 | d = self.tc.run(task.StringTask('a=5')) | |
49 | d.addCallback(lambda r: self.assertEquals(r, 0)) |
|
49 | d.addCallback(lambda r: self.assertEquals(r, 0)) | |
50 | d.addCallback(lambda r: self.tc.run(task.Task('a=5'))) |
|
50 | d.addCallback(lambda r: self.tc.run(task.StringTask('a=5'))) | |
51 | d.addCallback(lambda r: self.assertEquals(r, 1)) |
|
51 | d.addCallback(lambda r: self.assertEquals(r, 1)) | |
52 | d.addCallback(lambda r: self.tc.run(task.Task('a=5'))) |
|
52 | d.addCallback(lambda r: self.tc.run(task.StringTask('a=5'))) | |
53 | d.addCallback(lambda r: self.assertEquals(r, 2)) |
|
53 | d.addCallback(lambda r: self.assertEquals(r, 2)) | |
54 | d.addCallback(lambda r: self.tc.run(task.Task('a=5'))) |
|
54 | d.addCallback(lambda r: self.tc.run(task.StringTask('a=5'))) | |
55 | d.addCallback(lambda r: self.assertEquals(r, 3)) |
|
55 | d.addCallback(lambda r: self.assertEquals(r, 3)) | |
56 | return d |
|
56 | return d | |
57 |
|
57 | |||
58 |
def test |
|
58 | def test_abort(self): | |
59 | """Cannot do a proper abort test, because blocking execution prevents |
|
59 | """Cannot do a proper abort test, because blocking execution prevents | |
60 | abort from being called before task completes""" |
|
60 | abort from being called before task completes""" | |
61 | self.addEngine(1) |
|
61 | self.addEngine(1) | |
62 | t = task.Task('a=5') |
|
62 | t = task.StringTask('a=5') | |
63 | d = self.tc.abort(0) |
|
63 | d = self.tc.abort(0) | |
64 | d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException)) |
|
64 | d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException)) | |
65 | d.addCallback(lambda _:self.tc.run(t)) |
|
65 | d.addCallback(lambda _:self.tc.run(t)) | |
@@ -67,15 +67,15 b' class ITaskControllerTestCase(TaskTestBase):' | |||||
67 | d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException)) |
|
67 | d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException)) | |
68 | return d |
|
68 | return d | |
69 |
|
69 | |||
70 |
def test |
|
70 | def test_abort_type(self): | |
71 | self.addEngine(1) |
|
71 | self.addEngine(1) | |
72 | d = self.tc.abort('asdfadsf') |
|
72 | d = self.tc.abort('asdfadsf') | |
73 | d.addErrback(lambda f: self.assertRaises(TypeError, f.raiseException)) |
|
73 | d.addErrback(lambda f: self.assertRaises(TypeError, f.raiseException)) | |
74 | return d |
|
74 | return d | |
75 |
|
75 | |||
76 |
def test |
|
76 | def test_clear_before_and_after(self): | |
77 | self.addEngine(1) |
|
77 | self.addEngine(1) | |
78 | t = task.Task('a=1', clear_before=True, pull='b', clear_after=True) |
|
78 | t = task.StringTask('a=1', clear_before=True, pull='b', clear_after=True) | |
79 | d = self.multiengine.execute('b=1', targets=0) |
|
79 | d = self.multiengine.execute('b=1', targets=0) | |
80 | d.addCallback(lambda _: self.tc.run(t)) |
|
80 | d.addCallback(lambda _: self.tc.run(t)) | |
81 | d.addCallback(lambda tid: self.tc.get_task_result(tid,block=True)) |
|
81 | d.addCallback(lambda tid: self.tc.get_task_result(tid,block=True)) | |
@@ -85,10 +85,10 b' class ITaskControllerTestCase(TaskTestBase):' | |||||
85 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) |
|
85 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) | |
86 | return d |
|
86 | return d | |
87 |
|
87 | |||
88 |
def test |
|
88 | def test_simple_retries(self): | |
89 | self.addEngine(1) |
|
89 | self.addEngine(1) | |
90 | t = task.Task("i += 1\nassert i == 16", pull='i',retries=10) |
|
90 | t = task.StringTask("i += 1\nassert i == 16", pull='i',retries=10) | |
91 | t2 = task.Task("i += 1\nassert i == 16", pull='i',retries=10) |
|
91 | t2 = task.StringTask("i += 1\nassert i == 16", pull='i',retries=10) | |
92 | d = self.multiengine.execute('i=0', targets=0) |
|
92 | d = self.multiengine.execute('i=0', targets=0) | |
93 | d.addCallback(lambda r: self.tc.run(t)) |
|
93 | d.addCallback(lambda r: self.tc.run(t)) | |
94 | d.addCallback(self.tc.get_task_result, block=True) |
|
94 | d.addCallback(self.tc.get_task_result, block=True) | |
@@ -101,10 +101,10 b' class ITaskControllerTestCase(TaskTestBase):' | |||||
101 | d.addCallback(lambda r: self.assertEquals(r, 16)) |
|
101 | d.addCallback(lambda r: self.assertEquals(r, 16)) | |
102 | return d |
|
102 | return d | |
103 |
|
103 | |||
104 |
def test |
|
104 | def test_recovery_tasks(self): | |
105 | self.addEngine(1) |
|
105 | self.addEngine(1) | |
106 | t = task.Task("i=16", pull='i') |
|
106 | t = task.StringTask("i=16", pull='i') | |
107 | t2 = task.Task("raise Exception", recovery_task=t, retries = 2) |
|
107 | t2 = task.StringTask("raise Exception", recovery_task=t, retries = 2) | |
108 |
|
108 | |||
109 | d = self.tc.run(t2) |
|
109 | d = self.tc.run(t2) | |
110 | d.addCallback(self.tc.get_task_result, block=True) |
|
110 | d.addCallback(self.tc.get_task_result, block=True) | |
@@ -112,47 +112,76 b' class ITaskControllerTestCase(TaskTestBase):' | |||||
112 | d.addCallback(lambda r: self.assertEquals(r, 16)) |
|
112 | d.addCallback(lambda r: self.assertEquals(r, 16)) | |
113 | return d |
|
113 | return d | |
114 |
|
114 | |||
115 | # def testInfiniteRecoveryLoop(self): |
|
115 | def test_setup_ns(self): | |
116 | # self.addEngine(1) |
|
|||
117 | # t = task.Task("raise Exception", retries = 5) |
|
|||
118 | # t2 = task.Task("assert True", retries = 2, recovery_task = t) |
|
|||
119 | # t.recovery_task = t2 |
|
|||
120 | # |
|
|||
121 | # d = self.tc.run(t) |
|
|||
122 | # d.addCallback(self.tc.get_task_result, block=True) |
|
|||
123 | # d.addCallback(lambda tr: tr.ns.i) |
|
|||
124 | # d.addBoth(printer) |
|
|||
125 | # d.addErrback(lambda f: self.assertRaises(AssertionError, f.raiseException)) |
|
|||
126 | # return d |
|
|||
127 | # |
|
|||
128 | def testSetupNS(self): |
|
|||
129 | self.addEngine(1) |
|
116 | self.addEngine(1) | |
130 | d = self.multiengine.execute('a=0', targets=0) |
|
117 | d = self.multiengine.execute('a=0', targets=0) | |
131 | ns = dict(a=1, b=0) |
|
118 | ns = dict(a=1, b=0) | |
132 | t = task.Task("", push=ns, pull=['a','b']) |
|
119 | t = task.StringTask("", push=ns, pull=['a','b']) | |
133 | d.addCallback(lambda r: self.tc.run(t)) |
|
120 | d.addCallback(lambda r: self.tc.run(t)) | |
134 | d.addCallback(self.tc.get_task_result, block=True) |
|
121 | d.addCallback(self.tc.get_task_result, block=True) | |
135 | d.addCallback(lambda tr: {'a':tr.ns.a, 'b':tr['b']}) |
|
122 | d.addCallback(lambda tr: {'a':tr.ns.a, 'b':tr['b']}) | |
136 | d.addCallback(lambda r: self.assertEquals(r, ns)) |
|
123 | d.addCallback(lambda r: self.assertEquals(r, ns)) | |
137 | return d |
|
124 | return d | |
138 |
|
125 | |||
139 |
def test |
|
126 | def test_string_task_results(self): | |
140 | self.addEngine(1) |
|
127 | self.addEngine(1) | |
141 | t1 = task.Task('a=5', pull='a') |
|
128 | t1 = task.StringTask('a=5', pull='a') | |
142 | d = self.tc.run(t1) |
|
129 | d = self.tc.run(t1) | |
143 | d.addCallback(self.tc.get_task_result, block=True) |
|
130 | d.addCallback(self.tc.get_task_result, block=True) | |
144 |
d.addCallback(lambda tr: (tr.ns.a,tr['a'],tr.failure, tr.raise |
|
131 | d.addCallback(lambda tr: (tr.ns.a,tr['a'],tr.failure, tr.raise_exception())) | |
145 | d.addCallback(lambda r: self.assertEquals(r, (5,5,None,None))) |
|
132 | d.addCallback(lambda r: self.assertEquals(r, (5,5,None,None))) | |
146 |
|
133 | |||
147 | t2 = task.Task('7=5') |
|
134 | t2 = task.StringTask('7=5') | |
148 | d.addCallback(lambda r: self.tc.run(t2)) |
|
135 | d.addCallback(lambda r: self.tc.run(t2)) | |
149 | d.addCallback(self.tc.get_task_result, block=True) |
|
136 | d.addCallback(self.tc.get_task_result, block=True) | |
150 | d.addCallback(lambda tr: tr.ns) |
|
137 | d.addCallback(lambda tr: tr.ns) | |
151 | d.addErrback(lambda f: self.assertRaises(SyntaxError, f.raiseException)) |
|
138 | d.addErrback(lambda f: self.assertRaises(SyntaxError, f.raiseException)) | |
152 |
|
139 | |||
153 | t3 = task.Task('', pull='b') |
|
140 | t3 = task.StringTask('', pull='b') | |
154 | d.addCallback(lambda r: self.tc.run(t3)) |
|
141 | d.addCallback(lambda r: self.tc.run(t3)) | |
155 | d.addCallback(self.tc.get_task_result, block=True) |
|
142 | d.addCallback(self.tc.get_task_result, block=True) | |
156 | d.addCallback(lambda tr: tr.ns) |
|
143 | d.addCallback(lambda tr: tr.ns) | |
157 | d.addErrback(lambda f: self.assertRaises(NameError, f.raiseException)) |
|
144 | d.addErrback(lambda f: self.assertRaises(NameError, f.raiseException)) | |
158 | return d |
|
145 | return d | |
|
146 | ||||
|
147 | def test_map_task(self): | |||
|
148 | self.addEngine(1) | |||
|
149 | t1 = task.MapTask(lambda x: 2*x,(10,)) | |||
|
150 | d = self.tc.run(t1) | |||
|
151 | d.addCallback(self.tc.get_task_result, block=True) | |||
|
152 | d.addCallback(lambda r: self.assertEquals(r,20)) | |||
|
153 | ||||
|
154 | t2 = task.MapTask(lambda : 20) | |||
|
155 | d.addCallback(lambda _: self.tc.run(t2)) | |||
|
156 | d.addCallback(self.tc.get_task_result, block=True) | |||
|
157 | d.addCallback(lambda r: self.assertEquals(r,20)) | |||
|
158 | ||||
|
159 | t3 = task.MapTask(lambda x: x,(),{'x':20}) | |||
|
160 | d.addCallback(lambda _: self.tc.run(t3)) | |||
|
161 | d.addCallback(self.tc.get_task_result, block=True) | |||
|
162 | d.addCallback(lambda r: self.assertEquals(r,20)) | |||
|
163 | return d | |||
|
164 | ||||
|
165 | def test_map_task_failure(self): | |||
|
166 | self.addEngine(1) | |||
|
167 | t1 = task.MapTask(lambda x: 1/0,(10,)) | |||
|
168 | d = self.tc.run(t1) | |||
|
169 | d.addCallback(self.tc.get_task_result, block=True) | |||
|
170 | d.addErrback(lambda f: self.assertRaises(ZeroDivisionError, f.raiseException)) | |||
|
171 | return d | |||
|
172 | ||||
|
173 | def test_map_task_args(self): | |||
|
174 | self.assertRaises(TypeError, task.MapTask, 'asdfasdf') | |||
|
175 | self.assertRaises(TypeError, task.MapTask, lambda x: x, 10) | |||
|
176 | self.assertRaises(TypeError, task.MapTask, lambda x: x, (10,),30) | |||
|
177 | ||||
|
178 | def test_clear(self): | |||
|
179 | self.addEngine(1) | |||
|
180 | t1 = task.MapTask(lambda x: 2*x,(10,)) | |||
|
181 | d = self.tc.run(t1) | |||
|
182 | d.addCallback(lambda _: self.tc.get_task_result(0, block=True)) | |||
|
183 | d.addCallback(lambda r: self.assertEquals(r,20)) | |||
|
184 | d.addCallback(lambda _: self.tc.clear()) | |||
|
185 | d.addCallback(lambda _: self.tc.get_task_result(0, block=True)) | |||
|
186 | d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException)) | |||
|
187 | return d |
@@ -38,7 +38,7 b' try:' | |||||
38 | IEngineQueuedTestCase |
|
38 | IEngineQueuedTestCase | |
39 | except ImportError: |
|
39 | except ImportError: | |
40 | print "we got an error!!!" |
|
40 | print "we got an error!!!" | |
41 |
|
|
41 | raise | |
42 | else: |
|
42 | else: | |
43 | class EngineFCTest(DeferredTestCase, |
|
43 | class EngineFCTest(DeferredTestCase, | |
44 | IEngineCoreTestCase, |
|
44 | IEngineCoreTestCase, |
@@ -26,9 +26,20 b' try:' | |||||
26 | from IPython.kernel.multienginefc import IFCSynchronousMultiEngine |
|
26 | from IPython.kernel.multienginefc import IFCSynchronousMultiEngine | |
27 | from IPython.kernel import multiengine as me |
|
27 | from IPython.kernel import multiengine as me | |
28 | from IPython.kernel.clientconnector import ClientConnector |
|
28 | from IPython.kernel.clientconnector import ClientConnector | |
|
29 | from IPython.kernel.parallelfunction import ParallelFunction | |||
|
30 | from IPython.kernel.error import CompositeError | |||
|
31 | from IPython.kernel.util import printer | |||
29 | except ImportError: |
|
32 | except ImportError: | |
30 | pass |
|
33 | pass | |
31 | else: |
|
34 | else: | |
|
35 | ||||
|
36 | def _raise_it(f): | |||
|
37 | try: | |||
|
38 | f.raiseException() | |||
|
39 | except CompositeError, e: | |||
|
40 | e.raise_exception() | |||
|
41 | ||||
|
42 | ||||
32 | class FullSynchronousMultiEngineTestCase(DeferredTestCase, IFullSynchronousMultiEngineTestCase): |
|
43 | class FullSynchronousMultiEngineTestCase(DeferredTestCase, IFullSynchronousMultiEngineTestCase): | |
33 |
|
44 | |||
34 | def setUp(self): |
|
45 | def setUp(self): | |
@@ -68,3 +79,66 b' else:' | |||||
68 | d.addBoth(lambda _: self.controller.stopService()) |
|
79 | d.addBoth(lambda _: self.controller.stopService()) | |
69 | dlist.append(d) |
|
80 | dlist.append(d) | |
70 | return defer.DeferredList(dlist) |
|
81 | return defer.DeferredList(dlist) | |
|
82 | ||||
|
83 | def test_mapper(self): | |||
|
84 | self.addEngine(4) | |||
|
85 | m = self.multiengine.mapper() | |||
|
86 | self.assertEquals(m.multiengine,self.multiengine) | |||
|
87 | self.assertEquals(m.dist,'b') | |||
|
88 | self.assertEquals(m.targets,'all') | |||
|
89 | self.assertEquals(m.block,True) | |||
|
90 | ||||
|
91 | def test_map_default(self): | |||
|
92 | self.addEngine(4) | |||
|
93 | m = self.multiengine.mapper() | |||
|
94 | d = m.map(lambda x: 2*x, range(10)) | |||
|
95 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |||
|
96 | d.addCallback(lambda _: self.multiengine.map(lambda x: 2*x, range(10))) | |||
|
97 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |||
|
98 | return d | |||
|
99 | ||||
|
100 | def test_map_noblock(self): | |||
|
101 | self.addEngine(4) | |||
|
102 | m = self.multiengine.mapper(block=False) | |||
|
103 | d = m.map(lambda x: 2*x, range(10)) | |||
|
104 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |||
|
105 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |||
|
106 | return d | |||
|
107 | ||||
|
108 | def test_mapper_fail(self): | |||
|
109 | self.addEngine(4) | |||
|
110 | m = self.multiengine.mapper() | |||
|
111 | d = m.map(lambda x: 1/0, range(10)) | |||
|
112 | d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f)) | |||
|
113 | return d | |||
|
114 | ||||
|
115 | def test_parallel(self): | |||
|
116 | self.addEngine(4) | |||
|
117 | p = self.multiengine.parallel() | |||
|
118 | self.assert_(isinstance(p, ParallelFunction)) | |||
|
119 | @p | |||
|
120 | def f(x): return 2*x | |||
|
121 | d = f(range(10)) | |||
|
122 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |||
|
123 | return d | |||
|
124 | ||||
|
125 | def test_parallel_noblock(self): | |||
|
126 | self.addEngine(1) | |||
|
127 | p = self.multiengine.parallel(block=False) | |||
|
128 | self.assert_(isinstance(p, ParallelFunction)) | |||
|
129 | @p | |||
|
130 | def f(x): return 2*x | |||
|
131 | d = f(range(10)) | |||
|
132 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |||
|
133 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |||
|
134 | return d | |||
|
135 | ||||
|
136 | def test_parallel_fail(self): | |||
|
137 | self.addEngine(4) | |||
|
138 | p = self.multiengine.parallel() | |||
|
139 | self.assert_(isinstance(p, ParallelFunction)) | |||
|
140 | @p | |||
|
141 | def f(x): return 1/0 | |||
|
142 | d = f(range(10)) | |||
|
143 | d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f)) | |||
|
144 | return d No newline at end of file |
@@ -20,8 +20,6 b' try:' | |||||
20 | from twisted.internet import defer |
|
20 | from twisted.internet import defer | |
21 | from twisted.python import failure |
|
21 | from twisted.python import failure | |
22 |
|
22 | |||
23 | from IPython.testing import tcommon |
|
|||
24 | from IPython.testing.tcommon import * |
|
|||
25 | from IPython.testing.util import DeferredTestCase |
|
23 | from IPython.testing.util import DeferredTestCase | |
26 | import IPython.kernel.pendingdeferred as pd |
|
24 | import IPython.kernel.pendingdeferred as pd | |
27 | from IPython.kernel import error |
|
25 | from IPython.kernel import error | |
@@ -29,26 +27,7 b' try:' | |||||
29 | except ImportError: |
|
27 | except ImportError: | |
30 | pass |
|
28 | pass | |
31 | else: |
|
29 | else: | |
32 |
|
30 | |||
33 | #------------------------------------------------------------------------------- |
|
|||
34 | # Setup for inline and standalone doctests |
|
|||
35 | #------------------------------------------------------------------------------- |
|
|||
36 |
|
||||
37 |
|
||||
38 | # If you have standalone doctests in a separate file, set their names in the |
|
|||
39 | # dt_files variable (as a single string or a list thereof): |
|
|||
40 | dt_files = [] |
|
|||
41 |
|
||||
42 | # If you have any modules whose docstrings should be scanned for embedded tests |
|
|||
43 | # as examples accorging to standard doctest practice, set them here (as a |
|
|||
44 | # single string or a list thereof): |
|
|||
45 | dt_modules = [] |
|
|||
46 |
|
||||
47 | #------------------------------------------------------------------------------- |
|
|||
48 | # Regular Unittests |
|
|||
49 | #------------------------------------------------------------------------------- |
|
|||
50 |
|
||||
51 |
|
||||
52 | class Foo(object): |
|
31 | class Foo(object): | |
53 |
|
32 | |||
54 | def bar(self, bahz): |
|
33 | def bar(self, bahz): | |
@@ -205,14 +184,3 b' else:' | |||||
205 | d3 = self.pdm.get_pending_deferred(did,False) |
|
184 | d3 = self.pdm.get_pending_deferred(did,False) | |
206 | d3.addCallback(lambda r: self.assertEquals(r,'bar')) |
|
185 | d3.addCallback(lambda r: self.assertEquals(r,'bar')) | |
207 |
|
186 | |||
208 | #------------------------------------------------------------------------------- |
|
|||
209 | # Regular Unittests |
|
|||
210 | #------------------------------------------------------------------------------- |
|
|||
211 |
|
||||
212 | # This ensures that the code will run either standalone as a script, or that it |
|
|||
213 | # can be picked up by Twisted's `trial` test wrapper to run all the tests. |
|
|||
214 | if tcommon.pexpect is not None: |
|
|||
215 | if __name__ == '__main__': |
|
|||
216 | unittest.main(testLoader=IPDocTestLoader(dt_files,dt_modules)) |
|
|||
217 | else: |
|
|||
218 | testSuite = lambda : makeTestSuite(__name__,dt_files,dt_modules) |
|
@@ -30,6 +30,8 b' try:' | |||||
30 | from IPython.kernel.util import printer |
|
30 | from IPython.kernel.util import printer | |
31 | from IPython.kernel.tests.tasktest import ITaskControllerTestCase |
|
31 | from IPython.kernel.tests.tasktest import ITaskControllerTestCase | |
32 | from IPython.kernel.clientconnector import ClientConnector |
|
32 | from IPython.kernel.clientconnector import ClientConnector | |
|
33 | from IPython.kernel.error import CompositeError | |||
|
34 | from IPython.kernel.parallelfunction import ParallelFunction | |||
33 | except ImportError: |
|
35 | except ImportError: | |
34 | pass |
|
36 | pass | |
35 | else: |
|
37 | else: | |
@@ -38,6 +40,12 b' else:' | |||||
38 | # Tests |
|
40 | # Tests | |
39 | #------------------------------------------------------------------------------- |
|
41 | #------------------------------------------------------------------------------- | |
40 |
|
42 | |||
|
43 | def _raise_it(f): | |||
|
44 | try: | |||
|
45 | f.raiseException() | |||
|
46 | except CompositeError, e: | |||
|
47 | e.raise_exception() | |||
|
48 | ||||
41 | class TaskTest(DeferredTestCase, ITaskControllerTestCase): |
|
49 | class TaskTest(DeferredTestCase, ITaskControllerTestCase): | |
42 |
|
50 | |||
43 | def setUp(self): |
|
51 | def setUp(self): | |
@@ -87,4 +95,67 b' else:' | |||||
87 | d.addBoth(lambda _: self.controller.stopService()) |
|
95 | d.addBoth(lambda _: self.controller.stopService()) | |
88 | dlist.append(d) |
|
96 | dlist.append(d) | |
89 | return defer.DeferredList(dlist) |
|
97 | return defer.DeferredList(dlist) | |
90 |
|
98 | |||
|
99 | def test_mapper(self): | |||
|
100 | self.addEngine(1) | |||
|
101 | m = self.tc.mapper() | |||
|
102 | self.assertEquals(m.task_controller,self.tc) | |||
|
103 | self.assertEquals(m.clear_before,False) | |||
|
104 | self.assertEquals(m.clear_after,False) | |||
|
105 | self.assertEquals(m.retries,0) | |||
|
106 | self.assertEquals(m.recovery_task,None) | |||
|
107 | self.assertEquals(m.depend,None) | |||
|
108 | self.assertEquals(m.block,True) | |||
|
109 | ||||
|
110 | def test_map_default(self): | |||
|
111 | self.addEngine(1) | |||
|
112 | m = self.tc.mapper() | |||
|
113 | d = m.map(lambda x: 2*x, range(10)) | |||
|
114 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |||
|
115 | d.addCallback(lambda _: self.tc.map(lambda x: 2*x, range(10))) | |||
|
116 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |||
|
117 | return d | |||
|
118 | ||||
|
119 | def test_map_noblock(self): | |||
|
120 | self.addEngine(1) | |||
|
121 | m = self.tc.mapper(block=False) | |||
|
122 | d = m.map(lambda x: 2*x, range(10)) | |||
|
123 | d.addCallback(lambda r: self.assertEquals(r,[x for x in range(10)])) | |||
|
124 | return d | |||
|
125 | ||||
|
126 | def test_mapper_fail(self): | |||
|
127 | self.addEngine(1) | |||
|
128 | m = self.tc.mapper() | |||
|
129 | d = m.map(lambda x: 1/0, range(10)) | |||
|
130 | d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f)) | |||
|
131 | return d | |||
|
132 | ||||
|
133 | def test_parallel(self): | |||
|
134 | self.addEngine(1) | |||
|
135 | p = self.tc.parallel() | |||
|
136 | self.assert_(isinstance(p, ParallelFunction)) | |||
|
137 | @p | |||
|
138 | def f(x): return 2*x | |||
|
139 | d = f(range(10)) | |||
|
140 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |||
|
141 | return d | |||
|
142 | ||||
|
143 | def test_parallel_noblock(self): | |||
|
144 | self.addEngine(1) | |||
|
145 | p = self.tc.parallel(block=False) | |||
|
146 | self.assert_(isinstance(p, ParallelFunction)) | |||
|
147 | @p | |||
|
148 | def f(x): return 2*x | |||
|
149 | d = f(range(10)) | |||
|
150 | d.addCallback(lambda r: self.assertEquals(r,[x for x in range(10)])) | |||
|
151 | return d | |||
|
152 | ||||
|
153 | def test_parallel_fail(self): | |||
|
154 | self.addEngine(1) | |||
|
155 | p = self.tc.parallel() | |||
|
156 | self.assert_(isinstance(p, ParallelFunction)) | |||
|
157 | @p | |||
|
158 | def f(x): return 1/0 | |||
|
159 | d = f(range(10)) | |||
|
160 | d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f)) | |||
|
161 | return d No newline at end of file |
@@ -1,13 +1,32 b'' | |||||
|
1 | """String dispatch class to match regexps and dispatch commands. | |||
|
2 | """ | |||
|
3 | ||||
|
4 | # Stdlib imports | |||
|
5 | import re | |||
|
6 | ||||
|
7 | # Our own modules | |||
1 | from IPython.hooks import CommandChainDispatcher |
|
8 | from IPython.hooks import CommandChainDispatcher | |
2 | import IPython.hooks |
|
9 | import IPython.hooks | |
3 |
|
10 | |||
4 | import re |
|
|||
5 |
|
11 | |||
|
12 | # Code begins | |||
6 | class StrDispatch(object): |
|
13 | class StrDispatch(object): | |
7 |
""" |
|
14 | """Dispatch (lookup) a set of strings / regexps for match. | |
|
15 | ||||
|
16 | Example: | |||
|
17 | ||||
|
18 | >>> dis = StrDispatch() | |||
|
19 | >>> dis.add_s('hei',34, priority = 4) | |||
|
20 | >>> dis.add_s('hei',123, priority = 2) | |||
|
21 | >>> dis.add_re('h.i', 686) | |||
|
22 | >>> print list(dis.flat_matches('hei')) | |||
|
23 | [123, 34, 686] | |||
|
24 | """ | |||
|
25 | ||||
8 | def __init__(self): |
|
26 | def __init__(self): | |
9 | self.strs = {} |
|
27 | self.strs = {} | |
10 | self.regexs = {} |
|
28 | self.regexs = {} | |
|
29 | ||||
11 | def add_s(self, s, obj, priority= 0 ): |
|
30 | def add_s(self, s, obj, priority= 0 ): | |
12 | """ Adds a target 'string' for dispatching """ |
|
31 | """ Adds a target 'string' for dispatching """ | |
13 |
|
32 | |||
@@ -31,9 +50,8 b' class StrDispatch(object):' | |||||
31 | if re.match(r, key): |
|
50 | if re.match(r, key): | |
32 | yield obj |
|
51 | yield obj | |
33 | else: |
|
52 | else: | |
34 | #print "nomatch",key |
|
53 | #print "nomatch",key # dbg | |
35 | pass |
|
54 | pass | |
36 |
|
||||
37 |
|
55 | |||
38 | def __repr__(self): |
|
56 | def __repr__(self): | |
39 | return "<Strdispatch %s, %s>" % (self.strs, self.regexs) |
|
57 | return "<Strdispatch %s, %s>" % (self.strs, self.regexs) | |
@@ -44,22 +62,9 b' class StrDispatch(object):' | |||||
44 | for el in self.strs[key]: |
|
62 | for el in self.strs[key]: | |
45 | yield el[1] |
|
63 | yield el[1] | |
46 |
|
64 | |||
47 |
|
||||
48 | def flat_matches(self, key): |
|
65 | def flat_matches(self, key): | |
49 | """ Yield all 'value' targets, without priority """ |
|
66 | """ Yield all 'value' targets, without priority """ | |
50 | for val in self.dispatch(key): |
|
67 | for val in self.dispatch(key): | |
51 | for el in val: |
|
68 | for el in val: | |
52 | yield el[1] # only value, no priority |
|
69 | yield el[1] # only value, no priority | |
53 | return |
|
70 | return | |
54 |
|
||||
55 |
|
||||
56 | def test(): |
|
|||
57 | d = StrDispatch() |
|
|||
58 | d.add_s('hei',34, priority = 4) |
|
|||
59 | d.add_s('hei',123, priority = 2) |
|
|||
60 | print list(d.dispatch('hei')) |
|
|||
61 | d.add_re('h.i', 686) |
|
|||
62 | print list(d.flat_matches('hei')) |
|
|||
63 |
|
||||
64 | if __name__ == '__main__': |
|
|||
65 | test() No newline at end of file |
|
1 | NO CONTENT: file renamed from IPython/testing/attic/parametric.py to IPython/testing/parametric.py |
|
NO CONTENT: file renamed from IPython/testing/attic/parametric.py to IPython/testing/parametric.py |
@@ -2,17 +2,51 b'' | |||||
2 | PREFIX=~/usr/local |
|
2 | PREFIX=~/usr/local | |
3 | PREFIX=~/tmp/local |
|
3 | PREFIX=~/tmp/local | |
4 |
|
4 | |||
|
5 | NOSE0=nosetests -vs --with-doctest --doctest-tests | |||
|
6 | NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt | |||
|
7 | ||||
|
8 | #--with-color | |||
|
9 | ||||
|
10 | SRC=ipdoctest.py setup.py ../decorators.py | |||
|
11 | ||||
5 | plugin: IPython_doctest_plugin.egg-info |
|
12 | plugin: IPython_doctest_plugin.egg-info | |
6 |
|
13 | |||
|
14 | dtest: plugin dtexample.py | |||
|
15 | $(NOSE) dtexample.py | |||
|
16 | ||||
|
17 | # Note: this test is double counting!!! | |||
|
18 | rtest: plugin dtexample.py | |||
|
19 | $(NOSE) test_refs.py | |||
|
20 | ||||
|
21 | std: plugin | |||
|
22 | nosetests -vs --with-doctest --doctest-tests IPython.strdispatch | |||
|
23 | $(NOSE) IPython.strdispatch | |||
|
24 | ||||
7 | test: plugin dtexample.py |
|
25 | test: plugin dtexample.py | |
8 | nosetests -s --with-ipdoctest --doctest-tests --doctest-extension=txt \ |
|
26 | $(NOSE) dtexample.py test*.py test*.txt | |
9 | dtexample.py test*.txt |
|
|||
10 |
|
27 | |||
11 | deb: plugin dtexample.py |
|
28 | deb: plugin dtexample.py | |
12 | nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \ |
|
29 | $(NOSE) test_combo.txt | |
13 | test_combo.txt |
|
30 | ||
|
31 | iptest: plugin | |||
|
32 | $(NOSE) IPython | |||
|
33 | ||||
|
34 | deco: | |||
|
35 | $(NOSE0) IPython.testing.decorators | |||
|
36 | ||||
|
37 | mtest: plugin | |||
|
38 | $(NOSE) -x IPython.Magic | |||
|
39 | ||||
|
40 | ipipe: plugin | |||
|
41 | $(NOSE) -x IPython.Extensions.ipipe | |||
|
42 | ||||
|
43 | sr: rtest std | |||
|
44 | ||||
|
45 | base: dtest rtest test std deco | |||
|
46 | ||||
|
47 | all: base iptest | |||
14 |
|
48 | |||
15 |
IPython_doctest_plugin.egg-info: |
|
49 | IPython_doctest_plugin.egg-info: $(SRC) | |
16 | python setup.py install --prefix=$(PREFIX) |
|
50 | python setup.py install --prefix=$(PREFIX) | |
17 | touch $@ |
|
51 | touch $@ | |
18 |
|
52 |
@@ -21,9 +21,9 b' def pyfunc():' | |||||
21 | ... |
|
21 | ... | |
22 | 0 1 1 2 2 3 |
|
22 | 0 1 1 2 2 3 | |
23 | """ |
|
23 | """ | |
24 |
|
||||
25 | return 'pyfunc' |
|
24 | return 'pyfunc' | |
26 |
|
25 | |||
|
26 | ||||
27 | def ipfunc(): |
|
27 | def ipfunc(): | |
28 | """Some ipython tests... |
|
28 | """Some ipython tests... | |
29 |
|
29 | |||
@@ -67,6 +67,93 b' def ipfunc():' | |||||
67 | In [9]: ipfunc() |
|
67 | In [9]: ipfunc() | |
68 | Out[9]: 'ipfunc' |
|
68 | Out[9]: 'ipfunc' | |
69 | """ |
|
69 | """ | |
70 |
|
||||
71 | return 'ipfunc' |
|
70 | return 'ipfunc' | |
72 |
|
71 | |||
|
72 | ||||
|
73 | def ranfunc(): | |||
|
74 | """A function with some random output. | |||
|
75 | ||||
|
76 | Normal examples are verified as usual: | |||
|
77 | >>> 1+3 | |||
|
78 | 4 | |||
|
79 | ||||
|
80 | But if you put '# random' in the output, it is ignored: | |||
|
81 | >>> 1+3 | |||
|
82 | junk goes here... # random | |||
|
83 | ||||
|
84 | >>> 1+2 | |||
|
85 | again, anything goes #random | |||
|
86 | if multiline, the random mark is only needed once. | |||
|
87 | ||||
|
88 | >>> 1+2 | |||
|
89 | You can also put the random marker at the end: | |||
|
90 | # random | |||
|
91 | ||||
|
92 | >>> 1+2 | |||
|
93 | # random | |||
|
94 | .. or at the beginning. | |||
|
95 | ||||
|
96 | More correct input is properly verified: | |||
|
97 | >>> ranfunc() | |||
|
98 | 'ranfunc' | |||
|
99 | """ | |||
|
100 | return 'ranfunc' | |||
|
101 | ||||
|
102 | ||||
|
103 | def random_all(): | |||
|
104 | """A function where we ignore the output of ALL examples. | |||
|
105 | ||||
|
106 | Examples: | |||
|
107 | ||||
|
108 | # all-random | |||
|
109 | ||||
|
110 | This mark tells the testing machinery that all subsequent examples should | |||
|
111 | be treated as random (ignoring their output). They are still executed, | |||
|
112 | so if a they raise an error, it will be detected as such, but their | |||
|
113 | output is completely ignored. | |||
|
114 | ||||
|
115 | >>> 1+3 | |||
|
116 | junk goes here... | |||
|
117 | ||||
|
118 | >>> 1+3 | |||
|
119 | klasdfj; | |||
|
120 | ||||
|
121 | >>> 1+2 | |||
|
122 | again, anything goes | |||
|
123 | blah... | |||
|
124 | """ | |||
|
125 | pass | |||
|
126 | ||||
|
127 | ||||
|
128 | def iprand(): | |||
|
129 | """Some ipython tests with random output. | |||
|
130 | ||||
|
131 | In [7]: 3+4 | |||
|
132 | Out[7]: 7 | |||
|
133 | ||||
|
134 | In [8]: print 'hello' | |||
|
135 | world # random | |||
|
136 | ||||
|
137 | In [9]: iprand() | |||
|
138 | Out[9]: 'iprand' | |||
|
139 | """ | |||
|
140 | return 'iprand' | |||
|
141 | ||||
|
142 | ||||
|
143 | def iprand_all(): | |||
|
144 | """Some ipython tests with fully random output. | |||
|
145 | ||||
|
146 | # all-random | |||
|
147 | ||||
|
148 | In [7]: 1 | |||
|
149 | Out[7]: 99 | |||
|
150 | ||||
|
151 | In [8]: print 'hello' | |||
|
152 | world | |||
|
153 | ||||
|
154 | In [9]: iprand_all() | |||
|
155 | Out[9]: 'junk' | |||
|
156 | """ | |||
|
157 | return 'iprand_all' | |||
|
158 | ||||
|
159 |
@@ -43,9 +43,19 b' import logging' | |||||
43 | import os |
|
43 | import os | |
44 | import re |
|
44 | import re | |
45 | import sys |
|
45 | import sys | |
|
46 | import traceback | |||
46 | import unittest |
|
47 | import unittest | |
47 |
|
48 | |||
48 | from inspect import getmodule |
|
49 | from inspect import getmodule | |
|
50 | from StringIO import StringIO | |||
|
51 | ||||
|
52 | # We are overriding the default doctest runner, so we need to import a few | |||
|
53 | # things from doctest directly | |||
|
54 | from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE, | |||
|
55 | _unittest_reportflags, DocTestRunner, | |||
|
56 | _extract_future_flags, pdb, _OutputRedirectingPdb, | |||
|
57 | _exception_traceback, | |||
|
58 | linecache) | |||
49 |
|
59 | |||
50 | # Third-party modules |
|
60 | # Third-party modules | |
51 | import nose.core |
|
61 | import nose.core | |
@@ -68,9 +78,27 b' log = logging.getLogger(__name__)' | |||||
68 | # machinery into a fit. This code should be considered a gross hack, but it |
|
78 | # machinery into a fit. This code should be considered a gross hack, but it | |
69 | # gets the job done. |
|
79 | # gets the job done. | |
70 |
|
80 | |||
|
81 | ||||
|
82 | # XXX - Hack to modify the %run command so we can sync the user's namespace | |||
|
83 | # with the test globals. Once we move over to a clean magic system, this will | |||
|
84 | # be done with much less ugliness. | |||
|
85 | ||||
|
86 | def _run_ns_sync(self,arg_s,runner=None): | |||
|
87 | """Modified version of %run that syncs testing namespaces. | |||
|
88 | ||||
|
89 | This is strictly needed for running doctests that call %run. | |||
|
90 | """ | |||
|
91 | ||||
|
92 | out = _ip.IP.magic_run_ori(arg_s,runner) | |||
|
93 | _run_ns_sync.test_globs.update(_ip.user_ns) | |||
|
94 | return out | |||
|
95 | ||||
|
96 | ||||
71 | def start_ipython(): |
|
97 | def start_ipython(): | |
72 | """Start a global IPython shell, which we need for IPython-specific syntax. |
|
98 | """Start a global IPython shell, which we need for IPython-specific syntax. | |
73 | """ |
|
99 | """ | |
|
100 | import new | |||
|
101 | ||||
74 | import IPython |
|
102 | import IPython | |
75 |
|
103 | |||
76 | def xsys(cmd): |
|
104 | def xsys(cmd): | |
@@ -88,7 +116,7 b' def start_ipython():' | |||||
88 | _excepthook = sys.excepthook |
|
116 | _excepthook = sys.excepthook | |
89 | _main = sys.modules.get('__main__') |
|
117 | _main = sys.modules.get('__main__') | |
90 |
|
118 | |||
91 | # Start IPython instance |
|
119 | # Start IPython instance. We customize it to start with minimal frills. | |
92 | IPython.Shell.IPShell(['--classic','--noterm_title']) |
|
120 | IPython.Shell.IPShell(['--classic','--noterm_title']) | |
93 |
|
121 | |||
94 | # Deactivate the various python system hooks added by ipython for |
|
122 | # Deactivate the various python system hooks added by ipython for | |
@@ -107,6 +135,11 b' def start_ipython():' | |||||
107 | # doctest machinery would miss them. |
|
135 | # doctest machinery would miss them. | |
108 | _ip.system = xsys |
|
136 | _ip.system = xsys | |
109 |
|
137 | |||
|
138 | # Also patch our %run function in. | |||
|
139 | im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__) | |||
|
140 | _ip.IP.magic_run_ori = _ip.IP.magic_run | |||
|
141 | _ip.IP.magic_run = im | |||
|
142 | ||||
110 | # The start call MUST be made here. I'm not sure yet why it doesn't work if |
|
143 | # The start call MUST be made here. I'm not sure yet why it doesn't work if | |
111 | # it is made later, at plugin initialization time, but in all my tests, that's |
|
144 | # it is made later, at plugin initialization time, but in all my tests, that's | |
112 | # the case. |
|
145 | # the case. | |
@@ -115,7 +148,26 b' start_ipython()' | |||||
115 | # *** END HACK *** |
|
148 | # *** END HACK *** | |
116 | ########################################################################### |
|
149 | ########################################################################### | |
117 |
|
150 | |||
118 | #----------------------------------------------------------------------------- |
|
151 | # Classes and functions | |
|
152 | ||||
|
153 | def is_extension_module(filename): | |||
|
154 | """Return whether the given filename is an extension module. | |||
|
155 | ||||
|
156 | This simply checks that the extension is either .so or .pyd. | |||
|
157 | """ | |||
|
158 | return os.path.splitext(filename)[1].lower() in ('.so','.pyd') | |||
|
159 | ||||
|
160 | ||||
|
161 | class nodoc(object): | |||
|
162 | def __init__(self,obj): | |||
|
163 | self.obj = obj | |||
|
164 | ||||
|
165 | def __getattribute__(self,key): | |||
|
166 | if key == '__doc__': | |||
|
167 | return None | |||
|
168 | else: | |||
|
169 | return getattr(object.__getattribute__(self,'obj'),key) | |||
|
170 | ||||
119 | # Modified version of the one in the stdlib, that fixes a python bug (doctests |
|
171 | # Modified version of the one in the stdlib, that fixes a python bug (doctests | |
120 | # not found in extension modules, http://bugs.python.org/issue3158) |
|
172 | # not found in extension modules, http://bugs.python.org/issue3158) | |
121 | class DocTestFinder(doctest.DocTestFinder): |
|
173 | class DocTestFinder(doctest.DocTestFinder): | |
@@ -126,45 +178,38 b' class DocTestFinder(doctest.DocTestFinder):' | |||||
126 | module. |
|
178 | module. | |
127 | """ |
|
179 | """ | |
128 | if module is None: |
|
180 | if module is None: | |
129 | #print '_fm C1' # dbg |
|
|||
130 | return True |
|
181 | return True | |
131 | elif inspect.isfunction(object): |
|
182 | elif inspect.isfunction(object): | |
132 | #print '_fm C2' # dbg |
|
|||
133 | return module.__dict__ is object.func_globals |
|
183 | return module.__dict__ is object.func_globals | |
134 | elif inspect.isbuiltin(object): |
|
184 | elif inspect.isbuiltin(object): | |
135 | #print '_fm C2-1' # dbg |
|
|||
136 | return module.__name__ == object.__module__ |
|
185 | return module.__name__ == object.__module__ | |
137 | elif inspect.isclass(object): |
|
186 | elif inspect.isclass(object): | |
138 | #print '_fm C3' # dbg |
|
|||
139 | return module.__name__ == object.__module__ |
|
187 | return module.__name__ == object.__module__ | |
140 | elif inspect.ismethod(object): |
|
188 | elif inspect.ismethod(object): | |
141 | # This one may be a bug in cython that fails to correctly set the |
|
189 | # This one may be a bug in cython that fails to correctly set the | |
142 | # __module__ attribute of methods, but since the same error is easy |
|
190 | # __module__ attribute of methods, but since the same error is easy | |
143 | # to make by extension code writers, having this safety in place |
|
191 | # to make by extension code writers, having this safety in place | |
144 | # isn't such a bad idea |
|
192 | # isn't such a bad idea | |
145 | #print '_fm C3-1' # dbg |
|
|||
146 | return module.__name__ == object.im_class.__module__ |
|
193 | return module.__name__ == object.im_class.__module__ | |
147 | elif inspect.getmodule(object) is not None: |
|
194 | elif inspect.getmodule(object) is not None: | |
148 | #print '_fm C4' # dbg |
|
|||
149 | #print 'C4 mod',module,'obj',object # dbg |
|
|||
150 | return module is inspect.getmodule(object) |
|
195 | return module is inspect.getmodule(object) | |
151 | elif hasattr(object, '__module__'): |
|
196 | elif hasattr(object, '__module__'): | |
152 | #print '_fm C5' # dbg |
|
|||
153 | return module.__name__ == object.__module__ |
|
197 | return module.__name__ == object.__module__ | |
154 | elif isinstance(object, property): |
|
198 | elif isinstance(object, property): | |
155 | #print '_fm C6' # dbg |
|
|||
156 | return True # [XX] no way not be sure. |
|
199 | return True # [XX] no way not be sure. | |
157 | else: |
|
200 | else: | |
158 | raise ValueError("object must be a class or function") |
|
201 | raise ValueError("object must be a class or function") | |
159 |
|
202 | |||
160 |
|
||||
161 |
|
||||
162 | def _find(self, tests, obj, name, module, source_lines, globs, seen): |
|
203 | def _find(self, tests, obj, name, module, source_lines, globs, seen): | |
163 | """ |
|
204 | """ | |
164 | Find tests for the given object and any contained objects, and |
|
205 | Find tests for the given object and any contained objects, and | |
165 | add them to `tests`. |
|
206 | add them to `tests`. | |
166 | """ |
|
207 | """ | |
167 |
|
208 | |||
|
209 | if hasattr(obj,"skip_doctest"): | |||
|
210 | #print 'SKIPPING DOCTEST FOR:',obj # dbg | |||
|
211 | obj = nodoc(obj) | |||
|
212 | ||||
168 | doctest.DocTestFinder._find(self,tests, obj, name, module, |
|
213 | doctest.DocTestFinder._find(self,tests, obj, name, module, | |
169 | source_lines, globs, seen) |
|
214 | source_lines, globs, seen) | |
170 |
|
215 | |||
@@ -185,13 +230,10 b' class DocTestFinder(doctest.DocTestFinder):' | |||||
185 | self._find(tests, val, valname1, module, source_lines, |
|
230 | self._find(tests, val, valname1, module, source_lines, | |
186 | globs, seen) |
|
231 | globs, seen) | |
187 |
|
232 | |||
188 |
|
||||
189 | # Look for tests in a class's contained objects. |
|
233 | # Look for tests in a class's contained objects. | |
190 | if inspect.isclass(obj) and self._recurse: |
|
234 | if inspect.isclass(obj) and self._recurse: | |
191 | #print 'RECURSE into class:',obj # dbg |
|
235 | #print 'RECURSE into class:',obj # dbg | |
192 | for valname, val in obj.__dict__.items(): |
|
236 | for valname, val in obj.__dict__.items(): | |
193 | #valname1 = '%s.%s' % (name, valname) # dbg |
|
|||
194 | #print 'N',name,'VN:',valname,'val:',str(val)[:77] # dbg |
|
|||
195 | # Special handling for staticmethod/classmethod. |
|
237 | # Special handling for staticmethod/classmethod. | |
196 | if isinstance(val, staticmethod): |
|
238 | if isinstance(val, staticmethod): | |
197 | val = getattr(obj, valname) |
|
239 | val = getattr(obj, valname) | |
@@ -208,6 +250,32 b' class DocTestFinder(doctest.DocTestFinder):' | |||||
208 | globs, seen) |
|
250 | globs, seen) | |
209 |
|
251 | |||
210 |
|
252 | |||
|
253 | class IPDoctestOutputChecker(doctest.OutputChecker): | |||
|
254 | """Second-chance checker with support for random tests. | |||
|
255 | ||||
|
256 | If the default comparison doesn't pass, this checker looks in the expected | |||
|
257 | output string for flags that tell us to ignore the output. | |||
|
258 | """ | |||
|
259 | ||||
|
260 | random_re = re.compile(r'#\s*random') | |||
|
261 | ||||
|
262 | def check_output(self, want, got, optionflags): | |||
|
263 | """Check output, accepting special markers embedded in the output. | |||
|
264 | ||||
|
265 | If the output didn't pass the default validation but the special string | |||
|
266 | '#random' is included, we accept it.""" | |||
|
267 | ||||
|
268 | # Let the original tester verify first, in case people have valid tests | |||
|
269 | # that happen to have a comment saying '#random' embedded in. | |||
|
270 | ret = doctest.OutputChecker.check_output(self, want, got, | |||
|
271 | optionflags) | |||
|
272 | if not ret and self.random_re.search(want): | |||
|
273 | #print >> sys.stderr, 'RANDOM OK:',want # dbg | |||
|
274 | return True | |||
|
275 | ||||
|
276 | return ret | |||
|
277 | ||||
|
278 | ||||
211 | class DocTestCase(doctests.DocTestCase): |
|
279 | class DocTestCase(doctests.DocTestCase): | |
212 | """Proxy for DocTestCase: provides an address() method that |
|
280 | """Proxy for DocTestCase: provides an address() method that | |
213 | returns the correct address for the doctest case. Otherwise |
|
281 | returns the correct address for the doctest case. Otherwise | |
@@ -216,33 +284,70 b' class DocTestCase(doctests.DocTestCase):' | |||||
216 | for purposes of determining the test address, if it is provided. |
|
284 | for purposes of determining the test address, if it is provided. | |
217 | """ |
|
285 | """ | |
218 |
|
286 | |||
219 | # doctests loaded via find(obj) omit the module name |
|
287 | # Note: this method was taken from numpy's nosetester module. | |
220 | # so we need to override id, __repr__ and shortDescription |
|
288 | ||
221 | # bonus: this will squash a 2.3 vs 2.4 incompatiblity |
|
289 | # Subclass nose.plugins.doctests.DocTestCase to work around a bug in | |
222 | def id(self): |
|
290 | # its constructor that blocks non-default arguments from being passed | |
223 | name = self._dt_test.name |
|
291 | # down into doctest.DocTestCase | |
224 | filename = self._dt_test.filename |
|
292 | ||
225 | if filename is not None: |
|
293 | def __init__(self, test, optionflags=0, setUp=None, tearDown=None, | |
226 | pk = getpackage(filename) |
|
294 | checker=None, obj=None, result_var='_'): | |
227 | if pk is not None and not name.startswith(pk): |
|
295 | self._result_var = result_var | |
228 | name = "%s.%s" % (pk, name) |
|
296 | doctests.DocTestCase.__init__(self, test, | |
229 | return name |
|
297 | optionflags=optionflags, | |
|
298 | setUp=setUp, tearDown=tearDown, | |||
|
299 | checker=checker) | |||
|
300 | # Now we must actually copy the original constructor from the stdlib | |||
|
301 | # doctest class, because we can't call it directly and a bug in nose | |||
|
302 | # means it never gets passed the right arguments. | |||
|
303 | ||||
|
304 | self._dt_optionflags = optionflags | |||
|
305 | self._dt_checker = checker | |||
|
306 | self._dt_test = test | |||
|
307 | self._dt_setUp = setUp | |||
|
308 | self._dt_tearDown = tearDown | |||
|
309 | ||||
|
310 | # Each doctest should remember what directory it was loaded from... | |||
|
311 | self._ori_dir = os.getcwd() | |||
|
312 | ||||
|
313 | # Modified runTest from the default stdlib | |||
|
314 | def runTest(self): | |||
|
315 | test = self._dt_test | |||
|
316 | old = sys.stdout | |||
|
317 | new = StringIO() | |||
|
318 | optionflags = self._dt_optionflags | |||
|
319 | ||||
|
320 | if not (optionflags & REPORTING_FLAGS): | |||
|
321 | # The option flags don't include any reporting flags, | |||
|
322 | # so add the default reporting flags | |||
|
323 | optionflags |= _unittest_reportflags | |||
|
324 | ||||
|
325 | runner = IPDocTestRunner(optionflags=optionflags, | |||
|
326 | checker=self._dt_checker, verbose=False) | |||
230 |
|
327 | |||
|
328 | try: | |||
|
329 | # Save our current directory and switch out to the one where the | |||
|
330 | # test was originally created, in case another doctest did a | |||
|
331 | # directory change. We'll restore this in the finally clause. | |||
|
332 | curdir = os.getcwd() | |||
|
333 | os.chdir(self._ori_dir) | |||
|
334 | ||||
|
335 | runner.DIVIDER = "-"*70 | |||
|
336 | failures, tries = runner.run( | |||
|
337 | test, out=new.write, clear_globs=False) | |||
|
338 | finally: | |||
|
339 | sys.stdout = old | |||
|
340 | os.chdir(curdir) | |||
231 |
|
341 | |||
232 | # Classes and functions |
|
342 | if failures: | |
233 |
|
343 | raise self.failureException(self.format_failure(new.getvalue())) | ||
234 | def is_extension_module(filename): |
|
|||
235 | """Return whether the given filename is an extension module. |
|
|||
236 |
|
||||
237 | This simply checks that the extension is either .so or .pyd. |
|
|||
238 | """ |
|
|||
239 | return os.path.splitext(filename)[1].lower() in ('.so','.pyd') |
|
|||
240 |
|
344 | |||
241 |
|
345 | |||
242 | # A simple subclassing of the original with a different class name, so we can |
|
346 | # A simple subclassing of the original with a different class name, so we can | |
243 | # distinguish and treat differently IPython examples from pure python ones. |
|
347 | # distinguish and treat differently IPython examples from pure python ones. | |
244 | class IPExample(doctest.Example): pass |
|
348 | class IPExample(doctest.Example): pass | |
245 |
|
349 | |||
|
350 | ||||
246 | class IPExternalExample(doctest.Example): |
|
351 | class IPExternalExample(doctest.Example): | |
247 | """Doctest examples to be run in an external process.""" |
|
352 | """Doctest examples to be run in an external process.""" | |
248 |
|
353 | |||
@@ -254,6 +359,7 b' class IPExternalExample(doctest.Example):' | |||||
254 | # An EXTRA newline is needed to prevent pexpect hangs |
|
359 | # An EXTRA newline is needed to prevent pexpect hangs | |
255 | self.source += '\n' |
|
360 | self.source += '\n' | |
256 |
|
361 | |||
|
362 | ||||
257 | class IPDocTestParser(doctest.DocTestParser): |
|
363 | class IPDocTestParser(doctest.DocTestParser): | |
258 | """ |
|
364 | """ | |
259 | A class used to parse strings containing doctest examples. |
|
365 | A class used to parse strings containing doctest examples. | |
@@ -294,14 +400,22 b' class IPDocTestParser(doctest.DocTestParser):' | |||||
294 | _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP), |
|
400 | _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP), | |
295 | re.MULTILINE | re.VERBOSE) |
|
401 | re.MULTILINE | re.VERBOSE) | |
296 |
|
402 | |||
|
403 | # Mark a test as being fully random. In this case, we simply append the | |||
|
404 | # random marker ('#random') to each individual example's output. This way | |||
|
405 | # we don't need to modify any other code. | |||
|
406 | _RANDOM_TEST = re.compile(r'#\s*all-random') | |||
|
407 | ||||
|
408 | # Mark tests to be executed in an external process - currently unsupported. | |||
|
409 | _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL') | |||
|
410 | ||||
297 | def ip2py(self,source): |
|
411 | def ip2py(self,source): | |
298 | """Convert input IPython source into valid Python.""" |
|
412 | """Convert input IPython source into valid Python.""" | |
299 | out = [] |
|
413 | out = [] | |
300 | newline = out.append |
|
414 | newline = out.append | |
301 | for line in source.splitlines(): |
|
415 | for lnum,line in enumerate(source.splitlines()): | |
302 |
|
|
416 | newline(_ip.IP.prefilter(line,lnum>0)) | |
303 | newline(_ip.IP.prefilter(line,True)) |
|
|||
304 | newline('') # ensure a closing newline, needed by doctest |
|
417 | newline('') # ensure a closing newline, needed by doctest | |
|
418 | #print "PYSRC:", '\n'.join(out) # dbg | |||
305 | return '\n'.join(out) |
|
419 | return '\n'.join(out) | |
306 |
|
420 | |||
307 | def parse(self, string, name='<string>'): |
|
421 | def parse(self, string, name='<string>'): | |
@@ -324,6 +438,11 b' class IPDocTestParser(doctest.DocTestParser):' | |||||
324 | output = [] |
|
438 | output = [] | |
325 | charno, lineno = 0, 0 |
|
439 | charno, lineno = 0, 0 | |
326 |
|
440 | |||
|
441 | if self._RANDOM_TEST.search(string): | |||
|
442 | random_marker = '\n# random' | |||
|
443 | else: | |||
|
444 | random_marker = '' | |||
|
445 | ||||
327 | # Whether to convert the input from ipython to python syntax |
|
446 | # Whether to convert the input from ipython to python syntax | |
328 | ip2py = False |
|
447 | ip2py = False | |
329 | # Find all doctest examples in the string. First, try them as Python |
|
448 | # Find all doctest examples in the string. First, try them as Python | |
@@ -341,7 +460,7 b' class IPDocTestParser(doctest.DocTestParser):' | |||||
341 | # IPExternalExamples are run out-of-process (via pexpect) so they |
|
460 | # IPExternalExamples are run out-of-process (via pexpect) so they | |
342 | # don't need any filtering (a real ipython will be executing them). |
|
461 | # don't need any filtering (a real ipython will be executing them). | |
343 | terms = list(self._EXAMPLE_RE_IP.finditer(string)) |
|
462 | terms = list(self._EXAMPLE_RE_IP.finditer(string)) | |
344 | if re.search(r'#\s*ipdoctest:\s*EXTERNAL',string): |
|
463 | if self._EXTERNAL_IP.search(string): | |
345 | #print '-'*70 # dbg |
|
464 | #print '-'*70 # dbg | |
346 | #print 'IPExternalExample, Source:\n',string # dbg |
|
465 | #print 'IPExternalExample, Source:\n',string # dbg | |
347 | #print '-'*70 # dbg |
|
466 | #print '-'*70 # dbg | |
@@ -361,12 +480,17 b' class IPDocTestParser(doctest.DocTestParser):' | |||||
361 | # Extract info from the regexp match. |
|
480 | # Extract info from the regexp match. | |
362 | (source, options, want, exc_msg) = \ |
|
481 | (source, options, want, exc_msg) = \ | |
363 | self._parse_example(m, name, lineno,ip2py) |
|
482 | self._parse_example(m, name, lineno,ip2py) | |
|
483 | ||||
|
484 | # Append the random-output marker (it defaults to empty in most | |||
|
485 | # cases, it's only non-empty for 'all-random' tests): | |||
|
486 | want += random_marker | |||
|
487 | ||||
364 | if Example is IPExternalExample: |
|
488 | if Example is IPExternalExample: | |
365 | options[doctest.NORMALIZE_WHITESPACE] = True |
|
489 | options[doctest.NORMALIZE_WHITESPACE] = True | |
366 | want += '\n' |
|
490 | want += '\n' | |
|
491 | ||||
367 | # Create an Example, and add it to the list. |
|
492 | # Create an Example, and add it to the list. | |
368 | if not self._IS_BLANK_OR_COMMENT(source): |
|
493 | if not self._IS_BLANK_OR_COMMENT(source): | |
369 | #print 'Example source:', source # dbg |
|
|||
370 | output.append(Example(source, want, exc_msg, |
|
494 | output.append(Example(source, want, exc_msg, | |
371 | lineno=lineno, |
|
495 | lineno=lineno, | |
372 | indent=min_indent+len(m.group('indent')), |
|
496 | indent=min_indent+len(m.group('indent')), | |
@@ -377,7 +501,6 b' class IPDocTestParser(doctest.DocTestParser):' | |||||
377 | charno = m.end() |
|
501 | charno = m.end() | |
378 | # Add any remaining post-example text to `output`. |
|
502 | # Add any remaining post-example text to `output`. | |
379 | output.append(string[charno:]) |
|
503 | output.append(string[charno:]) | |
380 |
|
||||
381 | return output |
|
504 | return output | |
382 |
|
505 | |||
383 | def _parse_example(self, m, name, lineno,ip2py=False): |
|
506 | def _parse_example(self, m, name, lineno,ip2py=False): | |
@@ -464,9 +587,33 b' class IPDocTestParser(doctest.DocTestParser):' | |||||
464 | (lineno+i+1, name, |
|
587 | (lineno+i+1, name, | |
465 | line[indent:space_idx], line)) |
|
588 | line[indent:space_idx], line)) | |
466 |
|
589 | |||
|
590 | ||||
467 | SKIP = doctest.register_optionflag('SKIP') |
|
591 | SKIP = doctest.register_optionflag('SKIP') | |
468 |
|
592 | |||
469 | ########################################################################### |
|
593 | ||
|
594 | class IPDocTestRunner(doctest.DocTestRunner,object): | |||
|
595 | """Test runner that synchronizes the IPython namespace with test globals. | |||
|
596 | """ | |||
|
597 | ||||
|
598 | def run(self, test, compileflags=None, out=None, clear_globs=True): | |||
|
599 | ||||
|
600 | # Hack: ipython needs access to the execution context of the example, | |||
|
601 | # so that it can propagate user variables loaded by %run into | |||
|
602 | # test.globs. We put them here into our modified %run as a function | |||
|
603 | # attribute. Our new %run will then only make the namespace update | |||
|
604 | # when called (rather than unconconditionally updating test.globs here | |||
|
605 | # for all examples, most of which won't be calling %run anyway). | |||
|
606 | _run_ns_sync.test_globs = test.globs | |||
|
607 | ||||
|
608 | # dbg | |||
|
609 | ## print >> sys.stderr, "Test:",test | |||
|
610 | ## for ex in test.examples: | |||
|
611 | ## print >> sys.stderr, ex.source | |||
|
612 | ## print >> sys.stderr, 'Want:\n',ex.want,'\n--' | |||
|
613 | ||||
|
614 | return super(IPDocTestRunner,self).run(test, | |||
|
615 | compileflags,out,clear_globs) | |||
|
616 | ||||
470 |
|
617 | |||
471 | class DocFileCase(doctest.DocFileCase): |
|
618 | class DocFileCase(doctest.DocFileCase): | |
472 | """Overrides to provide filename |
|
619 | """Overrides to provide filename | |
@@ -490,7 +637,8 b' class ExtensionDoctest(doctests.Doctest):' | |||||
490 | self.extension = tolist(options.doctestExtension) |
|
637 | self.extension = tolist(options.doctestExtension) | |
491 | self.finder = DocTestFinder() |
|
638 | self.finder = DocTestFinder() | |
492 | self.parser = doctest.DocTestParser() |
|
639 | self.parser = doctest.DocTestParser() | |
493 |
|
640 | self.globs = None | ||
|
641 | self.extraglobs = None | |||
494 |
|
642 | |||
495 | def loadTestsFromExtensionModule(self,filename): |
|
643 | def loadTestsFromExtensionModule(self,filename): | |
496 | bpath,mod = os.path.split(filename) |
|
644 | bpath,mod = os.path.split(filename) | |
@@ -503,32 +651,62 b' class ExtensionDoctest(doctests.Doctest):' | |||||
503 | sys.path.pop() |
|
651 | sys.path.pop() | |
504 | return tests |
|
652 | return tests | |
505 |
|
653 | |||
|
654 | # NOTE: the method below is almost a copy of the original one in nose, with | |||
|
655 | # a few modifications to control output checking. | |||
|
656 | ||||
|
657 | def loadTestsFromModule(self, module): | |||
|
658 | #print 'lTM',module # dbg | |||
|
659 | ||||
|
660 | if not self.matches(module.__name__): | |||
|
661 | log.debug("Doctest doesn't want module %s", module) | |||
|
662 | return | |||
|
663 | ||||
|
664 | tests = self.finder.find(module,globs=self.globs, | |||
|
665 | extraglobs=self.extraglobs) | |||
|
666 | if not tests: | |||
|
667 | return | |||
|
668 | ||||
|
669 | tests.sort() | |||
|
670 | module_file = module.__file__ | |||
|
671 | if module_file[-4:] in ('.pyc', '.pyo'): | |||
|
672 | module_file = module_file[:-1] | |||
|
673 | for test in tests: | |||
|
674 | if not test.examples: | |||
|
675 | continue | |||
|
676 | if not test.filename: | |||
|
677 | test.filename = module_file | |||
|
678 | ||||
|
679 | # xxx - checker and options may be ok instantiated once outside loop | |||
|
680 | # always use whitespace and ellipsis options | |||
|
681 | optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS | |||
|
682 | checker = IPDoctestOutputChecker() | |||
|
683 | ||||
|
684 | yield DocTestCase(test, | |||
|
685 | optionflags=optionflags, | |||
|
686 | checker=checker) | |||
|
687 | ||||
506 | def loadTestsFromFile(self, filename): |
|
688 | def loadTestsFromFile(self, filename): | |
|
689 | #print 'lTF',filename # dbg | |||
|
690 | ||||
507 | if is_extension_module(filename): |
|
691 | if is_extension_module(filename): | |
508 | for t in self.loadTestsFromExtensionModule(filename): |
|
692 | for t in self.loadTestsFromExtensionModule(filename): | |
509 | yield t |
|
693 | yield t | |
510 | else: |
|
694 | else: | |
511 | ## for t in list(doctests.Doctest.loadTestsFromFile(self,filename)): |
|
695 | if self.extension and anyp(filename.endswith, self.extension): | |
512 | ## yield t |
|
696 | name = os.path.basename(filename) | |
513 | pass |
|
697 | dh = open(filename) | |
514 |
|
698 | try: | ||
515 | if self.extension and anyp(filename.endswith, self.extension): |
|
699 | doc = dh.read() | |
516 | #print 'lTF',filename # dbg |
|
700 | finally: | |
517 | name = os.path.basename(filename) |
|
701 | dh.close() | |
518 | dh = open(filename) |
|
702 | test = self.parser.get_doctest( | |
519 | try: |
|
703 | doc, globs={'__file__': filename}, name=name, | |
520 | doc = dh.read() |
|
704 | filename=filename, lineno=0) | |
521 |
|
|
705 | if test.examples: | |
522 | dh.close() |
|
706 | #print 'FileCase:',test.examples # dbg | |
523 | test = self.parser.get_doctest( |
|
707 | yield DocFileCase(test) | |
524 | doc, globs={'__file__': filename}, name=name, |
|
708 | else: | |
525 | filename=filename, lineno=0) |
|
709 | yield False # no tests to load | |
526 | if test.examples: |
|
|||
527 | #print 'FileCase:',test.examples # dbg |
|
|||
528 | yield DocFileCase(test) |
|
|||
529 | else: |
|
|||
530 | yield False # no tests to load |
|
|||
531 |
|
||||
532 |
|
710 | |||
533 | def wantFile(self,filename): |
|
711 | def wantFile(self,filename): | |
534 | """Return whether the given filename should be scanned for tests. |
|
712 | """Return whether the given filename should be scanned for tests. | |
@@ -538,38 +716,25 b' class ExtensionDoctest(doctests.Doctest):' | |||||
538 | """ |
|
716 | """ | |
539 | #print 'Filename:',filename # dbg |
|
717 | #print 'Filename:',filename # dbg | |
540 |
|
718 | |||
|
719 | # temporarily hardcoded list, will move to driver later | |||
|
720 | exclude = ['IPython/external/', | |||
|
721 | 'IPython/Extensions/ipy_', | |||
|
722 | 'IPython/platutils_win32', | |||
|
723 | 'IPython/frontend/cocoa', | |||
|
724 | 'IPython_doctest_plugin', | |||
|
725 | 'IPython/Gnuplot', | |||
|
726 | 'IPython/Extensions/PhysicalQIn'] | |||
|
727 | ||||
|
728 | for fex in exclude: | |||
|
729 | if fex in filename: # substring | |||
|
730 | #print '###>>> SKIP:',filename # dbg | |||
|
731 | return False | |||
|
732 | ||||
541 | if is_extension_module(filename): |
|
733 | if is_extension_module(filename): | |
542 | return True |
|
734 | return True | |
543 | else: |
|
735 | else: | |
544 | return doctests.Doctest.wantFile(self,filename) |
|
736 | return doctests.Doctest.wantFile(self,filename) | |
545 |
|
737 | |||
546 | # NOTE: the method below is a *copy* of the one in the nose doctests |
|
|||
547 | # plugin, but we have to replicate it here in order to have it resolve the |
|
|||
548 | # DocTestCase (last line) to our local copy, since the nose plugin doesn't |
|
|||
549 | # provide a public hook for what TestCase class to use. The alternative |
|
|||
550 | # would be to monkeypatch doctest in the stdlib, but that's ugly and |
|
|||
551 | # brittle, since a change in plugin load order can break it. So for now, |
|
|||
552 | # we just paste this in here, inelegant as this may be. |
|
|||
553 |
|
||||
554 | def loadTestsFromModule(self, module): |
|
|||
555 | #print 'lTM',module # dbg |
|
|||
556 |
|
||||
557 | if not self.matches(module.__name__): |
|
|||
558 | log.debug("Doctest doesn't want module %s", module) |
|
|||
559 | return |
|
|||
560 | tests = self.finder.find(module) |
|
|||
561 | if not tests: |
|
|||
562 | return |
|
|||
563 | tests.sort() |
|
|||
564 | module_file = module.__file__ |
|
|||
565 | if module_file[-4:] in ('.pyc', '.pyo'): |
|
|||
566 | module_file = module_file[:-1] |
|
|||
567 | for test in tests: |
|
|||
568 | if not test.examples: |
|
|||
569 | continue |
|
|||
570 | if not test.filename: |
|
|||
571 | test.filename = module_file |
|
|||
572 | yield DocTestCase(test) |
|
|||
573 |
|
738 | |||
574 | class IPythonDoctest(ExtensionDoctest): |
|
739 | class IPythonDoctest(ExtensionDoctest): | |
575 | """Nose Plugin that supports doctests in extension modules. |
|
740 | """Nose Plugin that supports doctests in extension modules. | |
@@ -583,5 +748,6 b' class IPythonDoctest(ExtensionDoctest):' | |||||
583 | self.doctest_tests = options.doctest_tests |
|
748 | self.doctest_tests = options.doctest_tests | |
584 | self.extension = tolist(options.doctestExtension) |
|
749 | self.extension = tolist(options.doctestExtension) | |
585 | self.parser = IPDocTestParser() |
|
750 | self.parser = IPDocTestParser() | |
586 | #self.finder = DocTestFinder(parser=IPDocTestParser()) |
|
|||
587 | self.finder = DocTestFinder(parser=self.parser) |
|
751 | self.finder = DocTestFinder(parser=self.parser) | |
|
752 | self.globs = None | |||
|
753 | self.extraglobs = None |
@@ -53,7 +53,7 b' class DistributedSpider(object):' | |||||
53 | self.allLinks.append(url) |
|
53 | self.allLinks.append(url) | |
54 | if url.startswith(self.site): |
|
54 | if url.startswith(self.site): | |
55 | print ' ', url |
|
55 | print ' ', url | |
56 | self.linksWorking[url] = self.tc.run(client.Task('links = fetchAndParse(url)', pull=['links'], push={'url': url})) |
|
56 | self.linksWorking[url] = self.tc.run(client.StringTask('links = fetchAndParse(url)', pull=['links'], push={'url': url})) | |
57 |
|
57 | |||
58 | def onVisitDone(self, result, url): |
|
58 | def onVisitDone(self, result, url): | |
59 | print url, ':' |
|
59 | print url, ':' |
@@ -8,7 +8,7 b' tc = client.TaskClient()' | |||||
8 | mec = client.MultiEngineClient() |
|
8 | mec = client.MultiEngineClient() | |
9 |
|
9 | |||
10 | mec.execute('import time') |
|
10 | mec.execute('import time') | |
11 | hello_taskid = tc.run(client.Task('time.sleep(3) ; word = "Hello,"', pull=('word'))) |
|
11 | hello_taskid = tc.run(client.StringTask('time.sleep(3) ; word = "Hello,"', pull=('word'))) | |
12 | world_taskid = tc.run(client.Task('time.sleep(3) ; word = "World!"', pull=('word'))) |
|
12 | world_taskid = tc.run(client.StringTask('time.sleep(3) ; word = "World!"', pull=('word'))) | |
13 | print "Submitted tasks:", hello_taskid, world_taskid |
|
13 | print "Submitted tasks:", hello_taskid, world_taskid | |
14 | print tc.get_task_result(hello_taskid,block=True).ns.word, tc.get_task_result(world_taskid,block=True).ns.word |
|
14 | print tc.get_task_result(hello_taskid,block=True).ns.word, tc.get_task_result(world_taskid,block=True).ns.word |
@@ -31,7 +31,7 b' sigma_vals = N.linspace(0.0, 0.2,5)' | |||||
31 | taskids = [] |
|
31 | taskids = [] | |
32 | for K in K_vals: |
|
32 | for K in K_vals: | |
33 | for sigma in sigma_vals: |
|
33 | for sigma in sigma_vals: | |
34 | t = client.Task(task_string, |
|
34 | t = client.StringTask(task_string, | |
35 | push=dict(sigma=sigma,K=K), |
|
35 | push=dict(sigma=sigma,K=K), | |
36 | pull=('vp','ap','vc','ac','sigma','K')) |
|
36 | pull=('vp','ap','vc','ac','sigma','K')) | |
37 | taskids.append(tc.run(t)) |
|
37 | taskids.append(tc.run(t)) |
@@ -11,8 +11,8 b' b = 10*d' | |||||
11 | c = a*b*d |
|
11 | c = a*b*d | |
12 | """ |
|
12 | """ | |
13 |
|
13 | |||
14 | t1 = client.Task(cmd1, clear_before=False, clear_after=True, pull=['a','b','c']) |
|
14 | t1 = client.StringTask(cmd1, clear_before=False, clear_after=True, pull=['a','b','c']) | |
15 | tid1 = tc.run(t1) |
|
15 | tid1 = tc.run(t1) | |
16 | tr1 = tc.get_task_result(tid1,block=True) |
|
16 | tr1 = tc.get_task_result(tid1,block=True) | |
17 |
tr1.raise |
|
17 | tr1.raise_exception() | |
18 | print "a, b: ", tr1.ns.a, tr1.ns.b No newline at end of file |
|
18 | print "a, b: ", tr1.ns.a, tr1.ns.b |
@@ -10,7 +10,7 b' mec = client.MultiEngineClient()' | |||||
10 | mec.execute('import time') |
|
10 | mec.execute('import time') | |
11 |
|
11 | |||
12 | for i in range(24): |
|
12 | for i in range(24): | |
13 |
tc. |
|
13 | tc.run(client.StringTask('time.sleep(1)')) | |
14 |
|
14 | |||
15 | for i in range(6): |
|
15 | for i in range(6): | |
16 | time.sleep(1.0) |
|
16 | time.sleep(1.0) | |
@@ -18,7 +18,7 b' for i in range(6):' | |||||
18 | print tc.queue_status() |
|
18 | print tc.queue_status() | |
19 |
|
19 | |||
20 | for i in range(24): |
|
20 | for i in range(24): | |
21 |
tc. |
|
21 | tc.run(client.StringTask('time.sleep(1)')) | |
22 |
|
22 | |||
23 | for i in range(6): |
|
23 | for i in range(6): | |
24 | time.sleep(1.0) |
|
24 | time.sleep(1.0) | |
@@ -26,7 +26,7 b' for i in range(6):' | |||||
26 | print tc.queue_status(True) |
|
26 | print tc.queue_status(True) | |
27 |
|
27 | |||
28 | for i in range(12): |
|
28 | for i in range(12): | |
29 |
tc. |
|
29 | tc.run(client.StringTask('time.sleep(2)')) | |
30 |
|
30 | |||
31 | print "Queue status (vebose=True)" |
|
31 | print "Queue status (vebose=True)" | |
32 | print tc.queue_status(True) |
|
32 | print tc.queue_status(True) |
@@ -55,7 +55,7 b' def main():' | |||||
55 |
|
55 | |||
56 | # the jobs should take a random time within a range |
|
56 | # the jobs should take a random time within a range | |
57 | times = [random.random()*(opts.tmax-opts.tmin)+opts.tmin for i in range(opts.n)] |
|
57 | times = [random.random()*(opts.tmax-opts.tmin)+opts.tmin for i in range(opts.n)] | |
58 | tasks = [client.Task("time.sleep(%f)"%t) for t in times] |
|
58 | tasks = [client.StringTask("time.sleep(%f)"%t) for t in times] | |
59 | stime = sum(times) |
|
59 | stime = sum(times) | |
60 |
|
60 | |||
61 | print "executing %i tasks, totalling %.1f secs on %i engines"%(opts.n, stime, nengines) |
|
61 | print "executing %i tasks, totalling %.1f secs on %i engines"%(opts.n, stime, nengines) |
@@ -12,6 +12,22 b' Release 0.9' | |||||
12 | New features |
|
12 | New features | |
13 | ------------ |
|
13 | ------------ | |
14 |
|
14 | |||
|
15 | * The notion of a task has been completely reworked. An `ITask` interface has | |||
|
16 | been created. This interface defines the methods that tasks need to implement. | |||
|
17 | These methods are now responsible for things like submitting tasks and processing | |||
|
18 | results. There are two basic task types: :class:`IPython.kernel.task.StringTask` | |||
|
19 | (this is the old `Task` object, but renamed) and the new | |||
|
20 | :class:`IPython.kernel.task.MapTask`, which is based on a function. | |||
|
21 | * A new interface, :class:`IPython.kernel.mapper.IMapper` has been defined to | |||
|
22 | standardize the idea of a `map` method. This interface has a single | |||
|
23 | `map` method that has the same syntax as the built-in `map`. We have also defined | |||
|
24 | a `mapper` factory interface that creates objects that implement | |||
|
25 | :class:`IPython.kernel.mapper.IMapper` for different controllers. Both | |||
|
26 | the multiengine and task controller now have mapping capabilties. | |||
|
27 | * The parallel function capabilities have been reworks. The major changes are that | |||
|
28 | i) there is now an `@parallel` magic that creates parallel functions, ii) | |||
|
29 | the syntax for mulitple variable follows that of `map`, iii) both the | |||
|
30 | multiengine and task controller now have a parallel function implementation. | |||
15 | * All of the parallel computing capabilities from `ipython1-dev` have been merged into |
|
31 | * All of the parallel computing capabilities from `ipython1-dev` have been merged into | |
16 | IPython proper. This resulted in the following new subpackages: |
|
32 | IPython proper. This resulted in the following new subpackages: | |
17 | :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`IPython.config`, |
|
33 | :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`IPython.config`, | |
@@ -38,11 +54,11 b' New features' | |||||
38 | when ipcluster is able to start things on other hosts, we will put security |
|
54 | when ipcluster is able to start things on other hosts, we will put security | |
39 | back. |
|
55 | back. | |
40 |
|
56 | |||
41 |
|
||||
42 |
|
||||
43 | Bug fixes |
|
57 | Bug fixes | |
44 | --------- |
|
58 | --------- | |
45 |
|
59 | |||
|
60 | * The colors escapes in the multiengine client are now turned off on win32 as they | |||
|
61 | don't print correctly. | |||
46 | * The :mod:`IPython.kernel.scripts.ipengine` script was exec'ing mpi_import_statement |
|
62 | * The :mod:`IPython.kernel.scripts.ipengine` script was exec'ing mpi_import_statement | |
47 | incorrectly, which was leading the engine to crash when mpi was enabled. |
|
63 | incorrectly, which was leading the engine to crash when mpi was enabled. | |
48 | * A few subpackages has missing `__init__.py` files. |
|
64 | * A few subpackages has missing `__init__.py` files. | |
@@ -52,6 +68,12 b' Bug fixes' | |||||
52 | Backwards incompatible changes |
|
68 | Backwards incompatible changes | |
53 | ------------------------------ |
|
69 | ------------------------------ | |
54 |
|
70 | |||
|
71 | * :class:`IPython.kernel.client.Task` has been renamed | |||
|
72 | :class:`IPython.kernel.client.StringTask` to make way for new task types. | |||
|
73 | * The keyword argument `style` has been renamed `dist` in `scatter`, `gather` | |||
|
74 | and `map`. | |||
|
75 | * Renamed the values that the rename `dist` keyword argument can have from | |||
|
76 | `'basic'` to `'b'`. | |||
55 | * IPython has a larger set of dependencies if you want all of its capabilities. |
|
77 | * IPython has a larger set of dependencies if you want all of its capabilities. | |
56 | See the `setup.py` script for details. |
|
78 | See the `setup.py` script for details. | |
57 | * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and |
|
79 | * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and |
@@ -1,3 +1,5 b'' | |||||
|
1 | .. _install_index: | |||
|
2 | ||||
1 | ================== |
|
3 | ================== | |
2 | Installation |
|
4 | Installation | |
3 | ================== |
|
5 | ================== |
@@ -4,18 +4,6 b'' | |||||
4 | Introduction |
|
4 | Introduction | |
5 | ============ |
|
5 | ============ | |
6 |
|
6 | |||
7 | This is the official documentation for IPython 0.x series (i.e. what |
|
|||
8 | we are used to refer to just as "IPython"). The original text of the |
|
|||
9 | manual (most of which is still in place) has been authored by Fernando |
|
|||
10 | Perez, but as recommended usage patterns and new features have |
|
|||
11 | emerged, this manual has been updated to reflect that fact. Most of |
|
|||
12 | the additions have been authored by Ville M. Vainio. |
|
|||
13 |
|
||||
14 | The manual has been generated from reStructuredText source markup with |
|
|||
15 | Sphinx, which should make it much easier to keep it up-to-date in the |
|
|||
16 | future. Some reST artifacts and bugs may still be apparent in the |
|
|||
17 | documentation, but this should improve as the toolchain matures. |
|
|||
18 |
|
||||
19 | Overview |
|
7 | Overview | |
20 | ======== |
|
8 | ======== | |
21 |
|
9 | |||
@@ -25,8 +13,19 b' creating test files as is typical in most programming languages.' | |||||
25 | However, the interpreter supplied with the standard Python distribution |
|
13 | However, the interpreter supplied with the standard Python distribution | |
26 | is somewhat limited for extended interactive use. |
|
14 | is somewhat limited for extended interactive use. | |
27 |
|
15 | |||
28 | IPython is a free software project (released under the BSD license) |
|
16 | The goal of IPython is to create a comprehensive environment for | |
29 | which tries to: |
|
17 | interactive and exploratory computing. To support, this goal, IPython | |
|
18 | has two main components: | |||
|
19 | ||||
|
20 | * An enhanced interactive Python shell. | |||
|
21 | * An architecture for interactive parallel computing. | |||
|
22 | ||||
|
23 | All of IPython is open source (released under the revised BSD license). | |||
|
24 | ||||
|
25 | Enhanced interactive Python shell | |||
|
26 | ================================= | |||
|
27 | ||||
|
28 | IPython's interactive shell (`ipython`), has the following goals: | |||
30 |
|
29 | |||
31 | 1. Provide an interactive shell superior to Python's default. IPython |
|
30 | 1. Provide an interactive shell superior to Python's default. IPython | |
32 | has many features for object introspection, system shell access, |
|
31 | has many features for object introspection, system shell access, | |
@@ -50,140 +49,126 b' which tries to:' | |||||
50 | WX applications via special threading flags. The normal Python |
|
49 | WX applications via special threading flags. The normal Python | |
51 | shell can only do this for Tkinter applications. |
|
50 | shell can only do this for Tkinter applications. | |
52 |
|
51 | |||
53 |
|
52 | Main features of the interactive shell | ||
54 | Main features |
|
53 | -------------------------------------- | |
55 | ------------- |
|
54 | ||
56 |
|
55 | * Dynamic object introspection. One can access docstrings, function | ||
57 | * Dynamic object introspection. One can access docstrings, function |
|
56 | definition prototypes, source code, source files and other details | |
58 | definition prototypes, source code, source files and other details |
|
57 | of any object accessible to the interpreter with a single | |
59 | of any object accessible to the interpreter with a single |
|
58 | keystroke (:samp:`?`, and using :samp:`??` provides additional detail). | |
60 | keystroke ('?', and using '??' provides additional detail). |
|
59 | * Searching through modules and namespaces with :samp:`*` wildcards, both | |
61 | * Searching through modules and namespaces with '*' wildcards, both |
|
60 | when using the :samp:`?` system and via the :samp:`%psearch` command. | |
62 | when using the '?' system and via the %psearch command. |
|
61 | * Completion in the local namespace, by typing :kbd:`TAB` at the prompt. | |
63 | * Completion in the local namespace, by typing TAB at the prompt. |
|
62 | This works for keywords, modules, methods, variables and files in the | |
64 | This works for keywords, modules, methods, variables and files in the |
|
63 | current directory. This is supported via the readline library, and | |
65 | current directory. This is supported via the readline library, and |
|
64 | full access to configuring readline's behavior is provided. | |
66 | full access to configuring readline's behavior is provided. |
|
65 | Custom completers can be implemented easily for different purposes | |
67 | Custom completers can be implemented easily for different purposes |
|
66 | (system commands, magic arguments etc.) | |
68 | (system commands, magic arguments etc.) |
|
67 | * Numbered input/output prompts with command history (persistent | |
69 | * Numbered input/output prompts with command history (persistent |
|
68 | across sessions and tied to each profile), full searching in this | |
70 | across sessions and tied to each profile), full searching in this |
|
69 | history and caching of all input and output. | |
71 | history and caching of all input and output. |
|
70 | * User-extensible 'magic' commands. A set of commands prefixed with | |
72 | * User-extensible 'magic' commands. A set of commands prefixed with |
|
71 | :samp:`%` is available for controlling IPython itself and provides | |
73 | % is available for controlling IPython itself and provides |
|
72 | directory control, namespace information and many aliases to | |
74 | directory control, namespace information and many aliases to |
|
73 | common system shell commands. | |
75 | common system shell commands. |
|
74 | * Alias facility for defining your own system aliases. | |
76 | * Alias facility for defining your own system aliases. |
|
75 | * Complete system shell access. Lines starting with :samp:`!` are passed | |
77 | * Complete system shell access. Lines starting with ! are passed |
|
76 | directly to the system shell, and using :samp:`!!` or :samp:`var = !cmd` | |
78 | directly to the system shell, and using !! or var = !cmd |
|
77 | captures shell output into python variables for further use. | |
79 | captures shell output into python variables for further use. |
|
78 | * Background execution of Python commands in a separate thread. | |
80 | * Background execution of Python commands in a separate thread. |
|
79 | IPython has an internal job manager called jobs, and a | |
81 | IPython has an internal job manager called jobs, and a |
|
80 | conveninence backgrounding magic function called :samp:`%bg`. | |
82 | conveninence backgrounding magic function called %bg. |
|
81 | * The ability to expand python variables when calling the system | |
83 | * The ability to expand python variables when calling the system |
|
82 | shell. In a shell command, any python variable prefixed with :samp:`$` is | |
84 | shell. In a shell command, any python variable prefixed with $ is |
|
83 | expanded. A double :samp:`$$` allows passing a literal :samp:`$` to the shell (for | |
85 | expanded. A double $$ allows passing a literal $ to the shell (for |
|
84 | access to shell and environment variables like :envvar:`PATH`). | |
86 | access to shell and environment variables like $PATH). |
|
85 | * Filesystem navigation, via a magic :samp:`%cd` command, along with a | |
87 | * Filesystem navigation, via a magic %cd command, along with a |
|
86 | persistent bookmark system (using :samp:`%bookmark`) for fast access to | |
88 | persistent bookmark system (using %bookmark) for fast access to |
|
87 | frequently visited directories. | |
89 | frequently visited directories. |
|
88 | * A lightweight persistence framework via the :samp:`%store` command, which | |
90 | * A lightweight persistence framework via the %store command, which |
|
89 | allows you to save arbitrary Python variables. These get restored | |
91 | allows you to save arbitrary Python variables. These get restored |
|
90 | automatically when your session restarts. | |
92 | automatically when your session restarts. |
|
91 | * Automatic indentation (optional) of code as you type (through the | |
93 | * Automatic indentation (optional) of code as you type (through the |
|
92 | readline library). | |
94 | readline library). |
|
93 | * Macro system for quickly re-executing multiple lines of previous | |
95 | * Macro system for quickly re-executing multiple lines of previous |
|
94 | input with a single name. Macros can be stored persistently via | |
96 | input with a single name. Macros can be stored persistently via |
|
95 | :samp:`%store` and edited via :samp:`%edit`. | |
97 | %store and edited via %edit. |
|
96 | * Session logging (you can then later use these logs as code in your | |
98 | * Session logging (you can then later use these logs as code in your |
|
97 | programs). Logs can optionally timestamp all input, and also store | |
99 | programs). Logs can optionally timestamp all input, and also store |
|
98 | session output (marked as comments, so the log remains valid | |
100 | session output (marked as comments, so the log remains valid |
|
99 | Python source code). | |
101 | Python source code). |
|
100 | * Session restoring: logs can be replayed to restore a previous | |
102 | * Session restoring: logs can be replayed to restore a previous |
|
101 | session to the state where you left it. | |
103 | session to the state where you left it. |
|
102 | * Verbose and colored exception traceback printouts. Easier to parse | |
104 | * Verbose and colored exception traceback printouts. Easier to parse |
|
103 | visually, and in verbose mode they produce a lot of useful | |
105 | visually, and in verbose mode they produce a lot of useful |
|
104 | debugging information (basically a terminal version of the cgitb | |
106 | debugging information (basically a terminal version of the cgitb |
|
105 | module). | |
107 | module). |
|
106 | * Auto-parentheses: callable objects can be executed without | |
108 | * Auto-parentheses: callable objects can be executed without |
|
107 | parentheses: :samp:`sin 3` is automatically converted to :samp:`sin(3)`. | |
109 | parentheses: 'sin 3' is automatically converted to 'sin(3)'. |
|
108 | * Auto-quoting: using :samp:`,`, or :samp:`;` as the first character forces | |
110 | * Auto-quoting: using ',' or ';' as the first character forces |
|
109 | auto-quoting of the rest of the line: :samp:`,my_function a b` becomes | |
111 | auto-quoting of the rest of the line: ',my_function a b' becomes |
|
110 | automatically :samp:`my_function("a","b")`, while :samp:`;my_function a b` | |
112 | automatically 'my_function("a","b")', while ';my_function a b' |
|
111 | becomes :samp:`my_function("a b")`. | |
113 | becomes 'my_function("a b")'. |
|
112 | * Extensible input syntax. You can define filters that pre-process | |
114 | * Extensible input syntax. You can define filters that pre-process |
|
113 | user input to simplify input in special situations. This allows | |
115 | user input to simplify input in special situations. This allows |
|
114 | for example pasting multi-line code fragments which start with | |
116 | for example pasting multi-line code fragments which start with |
|
115 | :samp:`>>>` or :samp:`...` such as those from other python sessions or the | |
117 | '>>>' or '...' such as those from other python sessions or the |
|
116 | standard Python documentation. | |
118 | standard Python documentation. |
|
117 | * Flexible configuration system. It uses a configuration file which | |
119 | * Flexible configuration system. It uses a configuration file which |
|
118 | allows permanent setting of all command-line options, module | |
120 | allows permanent setting of all command-line options, module |
|
119 | loading, code and file execution. The system allows recursive file | |
121 | loading, code and file execution. The system allows recursive file |
|
120 | inclusion, so you can have a base file with defaults and layers | |
122 | inclusion, so you can have a base file with defaults and layers |
|
121 | which load other customizations for particular projects. | |
123 | which load other customizations for particular projects. |
|
122 | * Embeddable. You can call IPython as a python shell inside your own | |
124 | * Embeddable. You can call IPython as a python shell inside your own |
|
123 | python programs. This can be used both for debugging code or for | |
125 | python programs. This can be used both for debugging code or for |
|
124 | providing interactive abilities to your programs with knowledge | |
126 | providing interactive abilities to your programs with knowledge |
|
125 | about the local namespaces (very useful in debugging and data | |
127 | about the local namespaces (very useful in debugging and data |
|
126 | analysis situations). | |
128 | analysis situations). |
|
127 | * Easy debugger access. You can set IPython to call up an enhanced | |
129 | * Easy debugger access. You can set IPython to call up an enhanced |
|
128 | version of the Python debugger (pdb) every time there is an | |
130 | version of the Python debugger (pdb) every time there is an |
|
129 | uncaught exception. This drops you inside the code which triggered | |
131 | uncaught exception. This drops you inside the code which triggered |
|
130 | the exception with all the data live and it is possible to | |
132 | the exception with all the data live and it is possible to |
|
131 | navigate the stack to rapidly isolate the source of a bug. The | |
133 | navigate the stack to rapidly isolate the source of a bug. The |
|
132 | :samp:`%run` magic command (with the :samp:`-d` option) can run any script under | |
134 | %run magic command -with the -d option- can run any script under |
|
133 | pdb's control, automatically setting initial breakpoints for you. | |
135 | pdb's control, automatically setting initial breakpoints for you. |
|
134 | This version of pdb has IPython-specific improvements, including | |
136 | This version of pdb has IPython-specific improvements, including |
|
135 | tab-completion and traceback coloring support. For even easier | |
137 | tab-completion and traceback coloring support. For even easier |
|
136 | debugger access, try :samp:`%debug` after seeing an exception. winpdb is | |
138 | debugger access, try %debug after seeing an exception. winpdb is |
|
137 | also supported, see ipy_winpdb extension. | |
139 | also supported, see ipy_winpdb extension. |
|
138 | * Profiler support. You can run single statements (similar to | |
140 | * Profiler support. You can run single statements (similar to |
|
139 | :samp:`profile.run()`) or complete programs under the profiler's control. | |
141 | profile.run()) or complete programs under the profiler's control. |
|
140 | While this is possible with standard cProfile or profile modules, | |
142 | While this is possible with standard cProfile or profile modules, |
|
141 | IPython wraps this functionality with magic commands (see :samp:`%prun` | |
143 | IPython wraps this functionality with magic commands (see '%prun' |
|
142 | and :samp:`%run -p`) convenient for rapid interactive work. | |
144 | and '%run -p') convenient for rapid interactive work. |
|
143 | * Doctest support. The special :samp:`%doctest_mode` command toggles a mode | |
145 | * Doctest support. The special %doctest_mode command toggles a mode |
|
144 | that allows you to paste existing doctests (with leading :samp:`>>>` | |
146 | that allows you to paste existing doctests (with leading '>>>' |
|
145 | prompts and whitespace) and uses doctest-compatible prompts and | |
147 | prompts and whitespace) and uses doctest-compatible prompts and |
|
146 | output, so you can use IPython sessions as doctest code. | |
148 | output, so you can use IPython sessions as doctest code. |
|
147 | ||
149 |
|
148 | Interactive parallel computing | ||
|
149 | ============================== | |||
|
150 | ||||
|
151 | Increasingly, parallel computer hardware, such as multicore CPUs, clusters and supercomputers, is becoming ubiquitous. Over the last 3 years, we have developed an | |||
|
152 | architecture within IPython that allows such hardware to be used quickly and easily | |||
|
153 | from Python. Moreover, this architecture is designed to support interactive and | |||
|
154 | collaborative parallel computing. | |||
|
155 | ||||
|
156 | For more information, see our :ref:`overview <parallel_index>` of using IPython for | |||
|
157 | parallel computing. | |||
150 |
|
158 | |||
151 | Portability and Python requirements |
|
159 | Portability and Python requirements | |
152 | ----------------------------------- |
|
160 | ----------------------------------- | |
153 |
|
161 | |||
154 | Python requirements: IPython requires with Python version 2.3 or newer. |
|
162 | As of the 0.9 release, IPython requires Python 2.4 or greater. We have | |
155 | If you are still using Python 2.2 and can not upgrade, the last version |
|
163 | not begun to test IPython on Python 2.6 or 3.0, but we expect it will | |
156 | of IPython which worked with Python 2.2 was 0.6.15, so you will have to |
|
164 | work with some minor changes. | |
157 | use that. |
|
165 | ||
158 |
|
166 | IPython is known to work on the following operating systems: | ||
159 | IPython is developed under Linux, but it should work in any reasonable |
|
167 | ||
160 | Unix-type system (tested OK under Solaris and the BSD family, for which |
|
168 | * Linux | |
161 | a port exists thanks to Dryice Liu). |
|
169 | * AIX | |
162 |
|
170 | * Most other Unix-like OSs (Solaris, BSD, etc.) | ||
163 | Mac OS X: it works, apparently without any problems (thanks to Jim Boyle |
|
171 | * Mac OS X | |
164 | at Lawrence Livermore for the information). Thanks to Andrea Riciputi, |
|
172 | * Windows (CygWin, XP, Vista, etc.) | |
165 | Fink support is available. |
|
173 | ||
166 |
|
174 | See :ref:`here <install_index>` for instructions on how to install IPython. No newline at end of file | ||
167 | CygWin: it works mostly OK, though some users have reported problems |
|
|||
168 | with prompt coloring. No satisfactory solution to this has been found so |
|
|||
169 | far, you may want to disable colors permanently in the ipythonrc |
|
|||
170 | configuration file if you experience problems. If you have proper color |
|
|||
171 | support under cygwin, please post to the IPython mailing list so this |
|
|||
172 | issue can be resolved for all users. |
|
|||
173 |
|
||||
174 | Windows: it works well under Windows Vista/XP/2k, and I suspect NT should |
|
|||
175 | behave similarly. Section "Installation under windows" describes |
|
|||
176 | installation details for Windows, including some additional tools needed |
|
|||
177 | on this platform. |
|
|||
178 |
|
||||
179 | Windows 9x support is present, and has been reported to work fine (at |
|
|||
180 | least on WinME). |
|
|||
181 |
|
||||
182 | Location |
|
|||
183 | -------- |
|
|||
184 |
|
||||
185 | IPython is generously hosted at http://ipython.scipy.org by the |
|
|||
186 | Enthought, Inc and the SciPy project. This site offers downloads, |
|
|||
187 | subversion access, mailing lists and a bug tracking system. I am very |
|
|||
188 | grateful to Enthought (http://www.enthought.com) and all of the SciPy |
|
|||
189 | team for their contribution. No newline at end of file |
|
@@ -1,3 +1,5 b'' | |||||
|
1 | .. _parallel_index: | |||
|
2 | ||||
1 | ==================================== |
|
3 | ==================================== | |
2 | Using IPython for Parallel computing |
|
4 | Using IPython for Parallel computing | |
3 | ==================================== |
|
5 | ==================================== |
@@ -24,4 +24,5 b' are trapped first by Python itself.' | |||||
24 | """ |
|
24 | """ | |
25 |
|
25 | |||
26 | import IPython.Shell |
|
26 | import IPython.Shell | |
|
27 | ||||
27 | IPython.Shell.start().mainloop() |
|
28 | IPython.Shell.start().mainloop() |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now