Package multi :: Module misc
[hide private]
[frames] | no frames]

Source Code for Module multi.misc

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2007 Gary S Thompson (https://gna.org/users/varioustoxins)    # 
  4  # Copyright (C) 2011-2012 Edward d'Auvergne                                   # 
  5  #                                                                             # 
  6  # This file is part of the program relax.                                     # 
  7  #                                                                             # 
  8  # relax is free software; you can redistribute it and/or modify               # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation; either version 2 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # relax is distributed in the hope that it will be useful,                    # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with relax; if not, write to the Free Software                        # 
 20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 21  #                                                                             # 
 22  ############################################################################### 
 23   
 24  # Module docstring. 
 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  # Python module imports. 
 31  try: 
 32      import importlib 
 33  except: 
 34      importlib = None 
 35  import sys 
 36  import traceback, textwrap 
 37   
 38   
39 -def import_module(module_path):
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 # Import the module using the new Python 2.7 way. 53 if importlib != None: 54 module = importlib.import_module(module_path) 55 56 # Return the module as a list. 57 return [module] 58 59 # Import the module using the old way. 60 else: 61 module = __import__(module_path, globals(), locals(), []) 62 63 # Debugging. 64 verbosity = Verbosity() 65 if verbosity.level() > 2: 66 print('loaded module %s' % module_path) 67 68 #FIXME: needs more failure checking 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
78 -def raise_unimplemented(method):
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
91 -class Capturing_exception(Exception):
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 # This is not an exception! 123 if not exception_type: 124 return 125 126 #PY3K: this check can be removed once string based exceptions are no longer used 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
137 - def __str__(self):
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
164 -class Result(object):
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 #TODO: assert on slave if processor_size > 1 203 #TODO: check if a completed command will add a noticeable overhead (I doubt it will) 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 # TODO: make this a result_command
219 -class Result_string(Result):
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 #TODO: correct order of parameters should be string, processor, completed
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
244 -class Verbosity(object):
245 """A special singleton structure for changing the verbosity level on the fly.""" 246 247 # Class variable for storing the class instance. 248 instance = None 249
250 - def __new__(self, *args, **kargs):
251 """Replacement function for implementing the singleton design pattern.""" 252 253 # First initialisation. 254 if self.instance is None: 255 # Create a new object. 256 self.instance = object.__new__(self, *args, **kargs) 257 258 # Set the initial verbosity level to nothing. 259 self._value = 0 260 261 # Already initialised, so return the instance. 262 return self.instance
263 264
265 - def level(self):
266 """Return the current verbosity level. 267 268 @return: The current verbosity level. 269 @rtype: int 270 """ 271 272 # Return the level. 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 # Set the value if given. 284 if value != None: 285 self._value = value
286