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