1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 """The non-public module for storing the API functions and classes of the multi-processor package.
26
27 This is for internal use only. To access the multi-processor API, see the __init__ module.
28 """
29
30
31 try:
32 import importlib
33 except:
34 importlib = None
35 import sys
36 import traceback, textwrap
37
38
40 """Import the python module named by module_path.
41
42 @param module_path: A module path in python dot separated format. Note: this currently doesn't
43 support relative module paths as defined by pep328 and python 2.5.
44 @type module_path: str
45 @return: The module path as a list of module instances or None if the module path
46 cannot be found in the python path.
47 @rtype: list of class module instances or None
48 """
49
50 result = None
51
52
53 if importlib != None:
54 module = importlib.import_module(module_path)
55
56
57 return [module]
58
59
60 else:
61 module = __import__(module_path, globals(), locals(), [])
62
63
64 verbosity = Verbosity()
65 if verbosity.level() > 2:
66 print('loaded module %s' % module_path)
67
68
69 if module != None:
70 result = [module]
71 components = module_path.split('.')
72 for component in components[1:]:
73 module = getattr(module, component)
74 result.append(module)
75 return result
76
77
79 """Standard function for raising NotImplementedError for unimplemented abstract methods.
80
81 @param method: The method which should be abstract.
82 @type method: class method
83 @raise NotImplementedError: A not implemented exception with the method name as a parameter.
84 """
85
86 msg = "Attempt to invoke unimplemented abstract method %s"
87 raise NotImplementedError(msg % method.__name__)
88
89
90
92 """A wrapper exception for an exception captured on a slave processor.
93
94 The wrapper will remember the stack trace on the remote machine and when raised and caught has a
95 string that includes the remote stack trace, which will be displayed along with the stack trace
96 on the master.
97 """
98
99 - def __init__(self, exc_info=None, rank='unknown', name='unknown'):
100 """Initialise the wrapping exception.
101
102 @todo: Would it be easier to pass a processor here.
103
104 @keyword exc_info: Exception information as produced by sys.exc_info().
105 @type exc_info: tuple
106 @keyword rank: The rank of the processor on which the exception was raised. The value
107 is always greater than 1.
108 @type rank: int
109 @keyword name: The name of the processor on which the exception was raised as returned
110 by processor.get_name().
111 @type name: str
112 """
113
114 Exception.__init__(self)
115 self.rank = rank
116 self.name = name
117 if exc_info == None:
118 (exception_type, exception_instance, exception_traceback) = sys.exc_info()
119 else:
120 (exception_type, exception_instance, exception_traceback) = exc_info
121
122
123 if not exception_type:
124 return
125
126
127 if isinstance(exception_type, str):
128 self.exception_name = exception_type + ' (legacy string exception)'
129 self.exception_string = exception_type
130 else:
131 self.exception_name = exception_type.__name__
132 self.exception_string = exception_instance.__str__()
133
134 self.traceback = traceback.format_tb(exception_traceback)
135
136
138 """Get the string describing this exception.
139
140 @return: The string describing this exception.
141 @rtype: str
142 """
143 message = """
144
145 %s
146
147 %s
148
149 Nested Exception from sub processor
150 Rank: %s Name: %s
151 Exception type: %s
152 Message: %s
153
154 %s
155
156
157 """
158 message = textwrap.dedent(message)
159 result = message % ('-'*120, ''.join(self.traceback), self.rank, self.name, self.exception_name, self.exception_string, '-'*120)
160 return result
161
162
163
165 """A basic result object returned from a slave processor via return_object.
166
167 This a very basic result and shouldn't be overridden unless you are also modifying the
168 process_result method in all the processors in the framework (i.e. currently for implementors
169 only). Most users should override Result_command.
170
171 This result basically acts as storage for the following fields completed, memo_id,
172 processor_rank.
173
174 Results should only be created on slave processors.
175
176 @see: multi.processor.return_object.
177 @see: multi.processor.process_result.
178 @see: multi.processor.Result_command.
179 """
180
181 - def __init__(self, processor, completed):
182 """Initialise a result.
183
184 This object is designed for subclassing and __init__ should be called via the super()
185 function.
186
187 @see: multi.processor.Processor.
188
189 @note: The requirement for the user to know about completed will hopefully disappear with
190 some slight of hand in the Slave_command and it may even disappear completely.
191
192 @param processor: Processor the processor instance we are running in.
193 @type processor: Processor instance
194 @param completed: A flag used in batching result returns to indicate that the sequence of
195 batched result commands has completed, the flag should be set by
196 slave_commands. The value should be the value passed to a Slave_commands
197 run method if it is the final result being returned otherwise it should
198 be False.
199 @type completed: bool
200 """
201
202
203
204 self.completed = completed
205 """A flag used in batching result returns to indicate that the sequence has completed.
206
207 This is an optimisation to prevent the sending an extra batched result queue completion
208 result being sent, it may be an over early optimisation."""
209 self.memo_id = None
210 """The memo_id of the Slave_command currently being processed on this processor.
211
212 This value is set by the return_object method to the current Slave_commands memo_id."""
213 self.rank = processor.rank()
214 """The rank of the current processor, used in command scheduling on the master processor."""
215
216
217
218
220 """A simple result from a slave containing a result.
221
222 The processor will print this string via sys.stdout.
223
224 @note: This may become a result_command so as to simplify things in the end.
225 """
226
227
228 - def __init__(self, processor, string, completed):
229 """Initialiser.
230
231 @todo: Check inherited parameters are documented.
232
233 @param string: A string to return the master processor for output to STDOUT (note the
234 master may split the string into components for STDOUT and STDERR depending
235 on the prefix string. This class is not really designed for subclassing.
236 @type string: str
237 """
238
239 super(Result_string, self).__init__(processor=processor, completed=completed)
240 self.string = string
241
242
243
245 """A special singleton structure for changing the verbosity level on the fly."""
246
247
248 instance = None
249
250 - def __new__(self, *args, **kargs):
251 """Replacement function for implementing the singleton design pattern."""
252
253
254 if self.instance is None:
255
256 self.instance = object.__new__(self, *args, **kargs)
257
258
259 self._value = 0
260
261
262 return self.instance
263
264
266 """Return the current verbosity level.
267
268 @return: The current verbosity level.
269 @rtype: int
270 """
271
272
273 return self._value
274
275
276 - def set(self, value=0):
277 """Set the verbosity level.
278
279 @keyword value: If given, then the verbosity level will be set. A value of 0 suppresses all output. A value of 1 causes the minimal amount of information to be printed. A value of 2 will switch on a number of debugging print outs. Values greater than 2 currently do nothing, though this might change in the future.
280 @type value: int
281 """
282
283
284 if value != None:
285 self._value = value
286