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 (http://www.nmr-relax.com).          # 
  7  #                                                                             # 
  8  # This program 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 3 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 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  # Python module imports. 
 30  try: 
 31      import importlib 
 32  except: 
 33      importlib = None 
 34  import sys 
 35  import traceback, textwrap 
 36   
 37   
38 -def import_module(module_path):
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 # Import the module using the new Python 2.7 way. 52 if importlib != None: 53 module = importlib.import_module(module_path) 54 55 # Return the module as a list. 56 return [module] 57 58 # Import the module using the old way. 59 else: 60 module = __import__(module_path, globals(), locals(), []) 61 62 # Debugging. 63 verbosity = Verbosity() 64 if verbosity.level() > 2: 65 print('loaded module %s' % module_path) 66 67 #FIXME: needs more failure checking 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
77 -def raise_unimplemented(method):
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
90 -class Capturing_exception(Exception):
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 # This is not an exception! 122 if not exception_type: 123 return 124 125 #PY3K: this check can be removed once string based exceptions are no longer used 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
136 - def __str__(self):
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
163 -class Result(object):
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 #TODO: assert on slave if processor_size > 1 202 #TODO: check if a completed command will add a noticeable overhead (I doubt it will) 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 # TODO: make this a result_command
218 -class Result_string(Result):
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 #TODO: correct order of parameters should be string, processor, completed
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
243 -class Verbosity(object):
244 """A special singleton structure for changing the verbosity level on the fly.""" 245 246 # Class variable for storing the class instance. 247 instance = None 248
249 - def __new__(self, *args, **kargs):
250 """Replacement function for implementing the singleton design pattern.""" 251 252 # First initialisation. 253 if self.instance is None: 254 # Create a new object. 255 self.instance = object.__new__(self, *args, **kargs) 256 257 # Set the initial verbosity level to nothing. 258 self._value = 0 259 260 # Already initialised, so return the instance. 261 return self.instance
262 263
264 - def level(self):
265 """Return the current verbosity level. 266 267 @return: The current verbosity level. 268 @rtype: int 269 """ 270 271 # Return the level. 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 # Set the value if given. 283 if value != None: 284 self._value = value
285