Package lib :: Module compat
[hide private]
[frames] | no frames]

Source Code for Module lib.compat

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2012-2014 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """Temporary module for allowing relax to support both Python 2 and 3.""" 
 24   
 25  # The platform script message. 
 26  try: 
 27      import platform 
 28  except ImportError: 
 29      print("The platform module cannot be imported.  For Python <= 2.2, try copying the platform.py file from http://hg.python.org/cpython/file/2.3/Lib/platform.py into your lib/pythonX.X/ directory.") 
 30      raise 
 31   
 32  # Python module imports. 
 33  try: 
 34      import bz2 
 35      from bz2 import BZ2File 
 36      bz2_module = True 
 37  except ImportError: 
 38      BZ2File = object 
 39      bz2_module = False 
 40      message = sys.exc_info()[1] 
 41      bz2_module_message = message.args[0] 
 42  try: 
 43      import gzip 
 44      gzip_module = True 
 45  except ImportError: 
 46      gzip = object 
 47      gzip_module = False 
 48      message = sys.exc_info()[1] 
 49      gzip_module_message = message.args[0] 
 50  from copy import deepcopy 
 51  try: 
 52      import io 
 53      io_module = True 
 54  except ImportError: 
 55      io_module = False 
 56  import os 
 57  import platform 
 58  import sys 
 59  import threading 
 60   
 61   
 62  # The operating system. 
 63  SYSTEM = platform.uname()[0] 
 64  if SYSTEM == 'Microsoft': 
 65      SYSTEM == 'Windows' 
 66   
 67  # The Python version. 
 68  PY_VERSION = sys.version_info[0] 
 69   
 70   
 71  # Special Python version specific imports.  These will be imported from here from the rest of relax. 
 72  #################################################################################################### 
 73   
 74  # The built-in module. 
 75  if PY_VERSION == 2: 
 76      import __builtin__ as builtins 
 77  else: 
 78      import builtins 
 79   
 80  # The queue module. 
 81  if PY_VERSION == 2: 
 82      import Queue as queue 
 83  else: 
 84      import queue 
 85   
 86  # The queue.Queue class 
 87  if PY_VERSION == 2: 
 88      from Queue import Queue as Queue2 
 89  else: 
 90      from queue import Queue as Queue3 
 91      Queue2 = Queue3 
 92   
 93  # The StringIO class. 
 94  if PY_VERSION == 2: 
 95      from cStringIO import StringIO 
 96  elif io_module: 
 97      from io import StringIO 
 98  else: 
 99      StringIO = None 
100   
101  # The unit test TextTestResult class. 
102  try: 
103      from unittest import TextTestResult    # Python 2.7 and above. 
104  except ImportError: 
105      from unittest import _TextTestResult as TextTestResult    # Python 2.6 and below. 
106   
107  # The pickle package. 
108  if PY_VERSION == 2: 
109      import cPickle as pickle 
110  else: 
111      import pickle 
112   
113  # Numpy. 
114  import numpy 
115  try: 
116      numpy.linalg.norm(numpy.ones((3, 3)), axis=1) 
117      numpy_norm_axis = True 
118  except: 
119      numpy_norm_axis = False 
120   
121   
122 -def bz2_open(file, mode='r'):
123 """Abstract the numerous ways BZ2 files are handled in Python. 124 125 @param file: The file path to open. 126 @type file: str 127 @keyword mode: The mode to open the file with. Only the values of 'r' and 'w' for reading and writing respectively are supported. 128 @type mode: str 129 @return: The bzip2 file object. 130 @rtype: file object 131 """ 132 133 # Check the mode. 134 if mode not in ['r', 'w']: 135 raise RelaxError("The mode '%s' must be one or 'r' or 'w'." % mode) 136 137 # Check if the bz2 module exists. 138 if not bz2_module: 139 if mode == 'r': 140 raise RelaxError("Cannot open the file %s, try uncompressing first. %s." % (file, bz2_module_message)) 141 else: 142 raise RelaxError("Cannot create bzip2 file %s, the bz2 Python module cannot be found." % file) 143 144 # Open the file for reading. 145 if mode == 'r': 146 # Python 3.3 text mode. 147 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 148 file_obj = bz2.open(file, 't') 149 150 # Python 3.0, 3.1 and 3.2 text mode. 151 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 152 file_obj = io.TextIOWrapper(Bzip2Fixed(file, 'r')) 153 154 # Python 2 text mode. 155 else: 156 file_obj = bz2.BZ2File(file, 'r') 157 158 # Open the file for writing. 159 elif mode == 'w': 160 # Python 3.3 text mode. 161 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 162 file_obj = bz2.open(file, 'wt') 163 164 # Python 3.0, 3.1 and 3.2 text mode. 165 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 166 file_obj = io.TextIOWrapper(Bzip2Fixed(file, 'w')) 167 168 # Python 2 text mode. 169 else: 170 file_obj = bz2.BZ2File(file, 'w') 171 172 # Return the file object. 173 return file_obj
174 175
176 -def gz_open(file, mode='r'):
177 """Abstract the numerous ways gzipped files are handled in Python. 178 179 @param file: The file path to open. 180 @type file: str 181 @keyword mode: The mode to open the file with. Only the values of 'r' and 'w' for reading and writing respectively are supported. 182 @type mode: str 183 @return: The gzipped file object. 184 @rtype: file object 185 """ 186 187 # Check the mode. 188 if mode not in ['r', 'w']: 189 raise RelaxError("The mode '%s' must be one or 'r' or 'w'." % mode) 190 191 # Check if the bz2 module exists. 192 if not gzip_module: 193 if mode == 'r': 194 raise RelaxError("Cannot open the file %s, try uncompressing first. %s." % (file, gzip_module_message)) 195 else: 196 raise RelaxError("Cannot create gzipped file %s, the bz2 Python module cannot be found." % file) 197 198 # Open the file for reading. 199 if mode == 'r': 200 # Python 3.3 text mode. 201 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 202 file_obj = gzip.open(file, 'rt') 203 204 # Python 3.0, 3.1 and 3.2 text mode. 205 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 206 file_obj = io.TextIOWrapper(GzipFixed(file, 'r')) 207 208 # Python 2 text mode. 209 else: 210 file_obj = gzip.GzipFile(file, 'r') 211 212 # Open the file for writing. 213 elif mode == 'w': 214 # Python 3.3 text mode. 215 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 216 file_obj = gzip.open(file, 'wt') 217 218 # Python 3.0, 3.1 and 3.2 text mode. 219 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 220 file_obj = io.TextIOWrapper(GzipFixed(file, 'w')) 221 222 # Python 2 text mode. 223 else: 224 file_obj = gzip.GzipFile(file, 'w') 225 226 # Return the file object. 227 return file_obj
228 229
230 -def norm(x, ord=None, axis=None):
231 """Replacement numpy.linalg.norm() function to handle the axis argument for old numpy. 232 @param x: Input array. If `axis` is None, `x` must be 1-D or 2-D. 233 @type x: array_like 234 @keyword ord: Order of the norm (see table under ``Notes``). inf means numpy's `inf` object. 235 @type ord: {non-zero int, inf, -inf, 'fro'}, optional 236 @keyword axis: If `axis` is an integer, it specifies the axis of `x` along which to compute the vector norms. If `axis` is a 2-tuple, it specifies the axes that hold 2-D matrices, and the matrix norms of these matrices are computed. If `axis` is None then either a vector norm (when `x` is 1-D) or a matrix norm (when `x` is 2-D) is returned. 237 @type axis: {int, 2-tuple of ints, None}, optional 238 """ 239 240 # No axis argument given. 241 if axis == None: 242 return numpy.linalg.norm(x, ord=ord) 243 244 # The axis argument exists. 245 if numpy_norm_axis: 246 return numpy.linalg.norm(x, ord=ord, axis=axis) 247 248 # Support for older version (this is much slower). 249 return numpy.apply_along_axis(numpy.linalg.norm, axis, x)
250 251 252
253 -class Bzip2Fixed(BZ2File):
254 """Incredibly nasty hack for bzip2 files support in Python 3.0, 3.1 and 3.2.""" 255
256 - def flush(self):
257 pass
258
259 - def read1(self, n):
260 return self.read(n)
261
262 - def readable(self):
263 return True
264
265 - def seekable(self):
266 return True
267
268 - def writable(self):
269 return True
270 271 272
273 -class GzipFixed(gzip.GzipFile):
274 """Incredibly nasty hack for gzipped files support in Python 3.0, 3.1 and 3.2.""" 275 276 closed = False 277
278 - def read1(self, n):
279 return self.read(n)
280
281 - def readable(self):
282 return True
283
284 - def seekable(self):
285 return True
286
287 - def writable(self):
288 return True
289 290 291
292 -class TaskQueue(Queue2):
293 """Python 2.4 and earlier Queuing class replacement. 294 295 This code comes from http://code.activestate.com/recipes/475160/ and is part of the Python sources from 2.5 onwards. 296 """ 297
298 - def __init__(self):
299 Queue2.__init__(self) 300 self.all_tasks_done = threading.Condition(self.mutex) 301 self.unfinished_tasks = 0
302
303 - def _put(self, item):
304 Queue2._put(self, item) 305 self.unfinished_tasks += 1
306
307 - def task_done(self):
308 """Indicate that a formerly enqueued task is complete. 309 310 Used by Queue consumer threads. For each get() used to fetch a task, 311 a subsequent call to task_done() tells the queue that the processing 312 on the task is complete. 313 314 If a join() is currently blocking, it will resume when all items 315 have been processed (meaning that a task_done() call was received 316 for every item that had been put() into the queue). 317 318 Raises a ValueError if called more times than there were items 319 placed in the queue. 320 """ 321 self.all_tasks_done.acquire() 322 try: 323 unfinished = self.unfinished_tasks - 1 324 if unfinished <= 0: 325 if unfinished < 0: 326 raise ValueError('task_done() called too many times') 327 self.all_tasks_done.notifyAll() 328 self.unfinished_tasks = unfinished 329 finally: 330 self.all_tasks_done.release()
331
332 - def join(self):
333 """Blocks until all items in the Queue have been gotten and processed. 334 335 The count of unfinished tasks goes up whenever an item is added to the 336 queue. The count goes down whenever a consumer thread calls task_done() 337 to indicate the item was retrieved and all work on it is complete. 338 339 When the count of unfinished tasks drops to zero, join() unblocks. 340 """ 341 self.all_tasks_done.acquire() 342 try: 343 while self.unfinished_tasks: 344 self.all_tasks_done.wait() 345 finally: 346 self.all_tasks_done.release()
347 348 349 # Alias the correct Queue. 350 if PY_VERSION == 2 and sys.version_info[1] <= 4: 351 Queue = TaskQueue # Alias the TaskQueue for Python 2.4 and earlier. 352 elif PY_VERSION == 2: 353 Queue = Queue2 354 else: 355 Queue = Queue3 356 357 358 # Python 2 hacks. 359 if PY_VERSION == 2: 360 # Switch all range() calls to xrange() for increased speed and memory reduction. 361 # This should work as all range() usage for Python 3 in relax must match the old xrange() usage. 362 #builtins.range = builtins.xrange 363 364 # The os.devnull object for Python 2.3 and earlier. 365 if sys.version_info[1] <= 3: 366 if SYSTEM == 'Linux': 367 os.devnull = '/dev/null' 368 elif SYSTEM == 'Windows': 369 os.devnull = 'nul' 370 elif SYSTEM == 'Darwin': 371 os.devnull = 'Dev:Null' 372 else: 373 os.devnull = None 374 375 # Unicode string handling. 376 from codecs import unicode_escape_decode
377 - def u(text):
378 """Create a unicode string for Python 2. 379 380 @param text: The text to convert. 381 @type text: str 382 @return: The text converted to unicode. 383 @rtype: unicode 384 """ 385 386 return unicode_escape_decode(text)[0]
387 388 389 # Python 3 work-arounds. 390 if PY_VERSION == 3: 391 # The unicode conversion function - essential for the GUI in Python 2. 392 builtins.unicode = builtins.str 393 394 # Unicode string handling.
395 - def u(text):
396 """Create a unicode string for Python 3. 397 398 @param text: The text to convert. 399 @type text: str 400 @return: The unmodified text, as all strings in Python 3 are unicode and the unicode type does not exist. 401 @rtype: str 402 """ 403 404 return text
405