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