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