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

Source Code for Module lib.compat

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2012-2014,2019 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  try: 
 51      import io 
 52      io_module = True 
 53      from io import IOBase 
 54  except ImportError: 
 55      io_module = False 
 56      IOBase = None 
 57  import itertools 
 58  import os 
 59  import platform 
 60  import sys 
 61  import threading 
 62   
 63   
 64  # The operating system. 
 65  SYSTEM = platform.uname()[0] 
 66  if SYSTEM == 'Microsoft': 
 67      SYSTEM == 'Windows' 
 68   
 69  # The Python version. 
 70  PY_VERSION = sys.version_info[0] 
 71   
 72   
 73  # Special Python version specific imports.  These will be imported from here from the rest of relax. 
 74  #################################################################################################### 
 75   
 76  # The built-in module. 
 77  if PY_VERSION == 2: 
 78      import __builtin__ as builtins 
 79  else: 
 80      import builtins 
 81   
 82  # The queue module. 
 83  if PY_VERSION == 2: 
 84      import Queue as queue 
 85  else: 
 86      import queue 
 87   
 88  # The queue.Queue class 
 89  if PY_VERSION == 2: 
 90      from Queue import Queue as Queue2 
 91  else: 
 92      from queue import Queue as Queue3 
 93      Queue2 = Queue3 
 94   
 95  # The StringIO class. 
 96  if PY_VERSION == 2: 
 97      from cStringIO import StringIO 
 98  elif io_module: 
 99      from io import StringIO 
100  else: 
101      StringIO = None 
102   
103  # The unit test TextTestResult class. 
104  try: 
105      from unittest import TextTestResult    # Python 2.7 and above. 
106  except ImportError: 
107      from unittest import _TextTestResult as TextTestResult    # Python 2.6 and below. 
108   
109  # The pickle package. 
110  if PY_VERSION == 2: 
111      import cPickle as pickle 
112  else: 
113      import pickle 
114   
115  # Numpy. 
116  import numpy 
117  try: 
118      numpy.linalg.norm(numpy.ones((3, 3)), axis=1) 
119      numpy_norm_axis = True 
120  except: 
121      numpy_norm_axis = False 
122   
123   
124 -def bz2_open(file, mode='r'):
125 """Abstract the numerous ways BZ2 files are handled in Python. 126 127 @param file: The file path to open. 128 @type file: str 129 @keyword mode: The mode to open the file with. Only the values of 'r' and 'w' for reading and writing respectively are supported. 130 @type mode: str 131 @return: The bzip2 file object. 132 @rtype: file object 133 """ 134 135 # Check the mode. 136 if mode not in ['r', 'w']: 137 raise RelaxError("The mode '%s' must be one or 'r' or 'w'." % mode) 138 139 # Check if the bz2 module exists. 140 if not bz2_module: 141 if mode == 'r': 142 raise RelaxError("Cannot open the file %s, try uncompressing first. %s." % (file, bz2_module_message)) 143 else: 144 raise RelaxError("Cannot create bzip2 file %s, the bz2 Python module cannot be found." % file) 145 146 # Open the file for reading. 147 if mode == 'r': 148 # Python 3.3 text mode. 149 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 150 file_obj = bz2.open(file, 't') 151 152 # Python 3.0, 3.1 and 3.2 text mode. 153 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 154 file_obj = io.TextIOWrapper(Bzip2Fixed(file, 'r')) 155 156 # Python 2 text mode. 157 else: 158 file_obj = bz2.BZ2File(file, 'r') 159 160 # Open the file for writing. 161 elif mode == 'w': 162 # Python 3.3 text mode. 163 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 164 file_obj = bz2.open(file, 'wt') 165 166 # Python 3.0, 3.1 and 3.2 text mode. 167 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 168 file_obj = io.TextIOWrapper(Bzip2Fixed(file, 'w')) 169 170 # Python 2 text mode. 171 else: 172 file_obj = bz2.BZ2File(file, 'w') 173 174 # Return the file object. 175 return file_obj
176 177
178 -def gz_open(file, mode='r'):
179 """Abstract the numerous ways gzipped files are handled in Python. 180 181 @param file: The file path to open. 182 @type file: str 183 @keyword mode: The mode to open the file with. Only the values of 'r' and 'w' for reading and writing respectively are supported. 184 @type mode: str 185 @return: The gzipped file object. 186 @rtype: file object 187 """ 188 189 # Check the mode. 190 if mode not in ['r', 'w']: 191 raise RelaxError("The mode '%s' must be one or 'r' or 'w'." % mode) 192 193 # Check if the bz2 module exists. 194 if not gzip_module: 195 if mode == 'r': 196 raise RelaxError("Cannot open the file %s, try uncompressing first. %s." % (file, gzip_module_message)) 197 else: 198 raise RelaxError("Cannot create gzipped file %s, the bz2 Python module cannot be found." % file) 199 200 # Open the file for reading. 201 if mode == 'r': 202 # Python 3.3 text mode. 203 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 204 file_obj = gzip.open(file, 'rt') 205 206 # Python 3.0, 3.1 and 3.2 text mode. 207 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 208 file_obj = io.TextIOWrapper(GzipFixed(file, 'r')) 209 210 # Python 2 text mode. 211 else: 212 file_obj = gzip.GzipFile(file, 'r') 213 214 # Open the file for writing. 215 elif mode == 'w': 216 # Python 3.3 text mode. 217 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 218 file_obj = gzip.open(file, 'wt') 219 220 # Python 3.0, 3.1 and 3.2 text mode. 221 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 222 file_obj = io.TextIOWrapper(GzipFixed(file, 'w')) 223 224 # Python 2 text mode. 225 else: 226 file_obj = gzip.GzipFile(file, 'w') 227 228 # Return the file object. 229 return file_obj
230 231
232 -def from_iterable(items):
233 """Implementation of the itertools.chain.from_iterable() function for all Python versions. 234 235 @param items: The normal argument for itertools.chain.from_iterable(). 236 @type items: list 237 @return: The items of the list. 238 @rtype: unknown 239 """ 240 241 # Default to the normal function. 242 if hasattr(itertools.chain, 'from_iterable'): 243 return itertools.chain.from_iterable(items) 244 245 # Reimplement the function for earlier Python versions. 246 return from_iterable_pre_2_6(items)
247 248
249 -def from_iterable_pre_2_6(items):
250 """Replacement itertools.chain.from_iterable() function for Python < 2.6. 251 252 @param items: The normal argument for itertools.chain.from_iterable(). 253 @type items: list 254 @return: The elements 255 @rtype: unknown 256 """ 257 258 for item in items: 259 for element in item: 260 yield element
261 262
263 -def norm(x, ord=None, axis=None):
264 """Replacement numpy.linalg.norm() function to handle the axis argument for old numpy. 265 266 @param x: Input array. If `axis` is None, `x` must be 1-D or 2-D. 267 @type x: array_like 268 @keyword ord: Order of the norm (see table under ``Notes``). inf means numpy's `inf` object. 269 @type ord: {non-zero int, inf, -inf, 'fro'}, optional 270 @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. 271 @type axis: {int, 2-tuple of ints, None}, optional 272 """ 273 274 # No axis argument given. 275 if axis == None: 276 return numpy.linalg.norm(x, ord=ord) 277 278 # The axis argument exists. 279 if numpy_norm_axis: 280 return numpy.linalg.norm(x, ord=ord, axis=axis) 281 282 # Support for older version (this is much slower). 283 return numpy.apply_along_axis(numpy.linalg.norm, axis, x)
284 285 286
287 -class Bzip2Fixed(BZ2File):
288 """Incredibly nasty hack for bzip2 files support in Python 3.0, 3.1 and 3.2.""" 289
290 - def flush(self):
291 pass
292
293 - def read1(self, n):
294 return self.read(n)
295
296 - def readable(self):
297 return True
298
299 - def seekable(self):
300 return True
301
302 - def writable(self):
303 return True
304 305 306
307 -class GzipFixed(gzip.GzipFile):
308 """Incredibly nasty hack for gzipped files support in Python 3.0, 3.1 and 3.2.""" 309 310 closed = False 311
312 - def read1(self, n):
313 return self.read(n)
314
315 - def readable(self):
316 return True
317
318 - def seekable(self):
319 return True
320
321 - def writable(self):
322 return True
323 324 325
326 -class TaskQueue(Queue2):
327 """Python 2.4 and earlier Queuing class replacement. 328 329 This code comes from http://code.activestate.com/recipes/475160/ and is part of the Python sources from 2.5 onwards. 330 """ 331
332 - def __init__(self):
333 Queue2.__init__(self) 334 self.all_tasks_done = threading.Condition(self.mutex) 335 self.unfinished_tasks = 0
336
337 - def _put(self, item):
338 Queue2._put(self, item) 339 self.unfinished_tasks += 1
340
341 - def task_done(self):
342 """Indicate that a formerly enqueued task is complete. 343 344 Used by Queue consumer threads. For each get() used to fetch a task, 345 a subsequent call to task_done() tells the queue that the processing 346 on the task is complete. 347 348 If a join() is currently blocking, it will resume when all items 349 have been processed (meaning that a task_done() call was received 350 for every item that had been put() into the queue). 351 352 Raises a ValueError if called more times than there were items 353 placed in the queue. 354 """ 355 self.all_tasks_done.acquire() 356 try: 357 unfinished = self.unfinished_tasks - 1 358 if unfinished <= 0: 359 if unfinished < 0: 360 raise ValueError('task_done() called too many times') 361 self.all_tasks_done.notifyAll() 362 self.unfinished_tasks = unfinished 363 finally: 364 self.all_tasks_done.release()
365
366 - def join(self):
367 """Blocks until all items in the Queue have been gotten and processed. 368 369 The count of unfinished tasks goes up whenever an item is added to the 370 queue. The count goes down whenever a consumer thread calls task_done() 371 to indicate the item was retrieved and all work on it is complete. 372 373 When the count of unfinished tasks drops to zero, join() unblocks. 374 """ 375 self.all_tasks_done.acquire() 376 try: 377 while self.unfinished_tasks: 378 self.all_tasks_done.wait() 379 finally: 380 self.all_tasks_done.release()
381 382 383 # Alias the correct Queue. 384 if PY_VERSION == 2 and sys.version_info[1] <= 4: 385 Queue = TaskQueue # Alias the TaskQueue for Python 2.4 and earlier. 386 elif PY_VERSION == 2: 387 Queue = Queue2 388 else: 389 Queue = Queue3 390 391 392 # Python 2 hacks. 393 if PY_VERSION == 2: 394 # Switch all range() calls to xrange() for increased speed and memory reduction. 395 # This should work as all range() usage for Python 3 in relax must match the old xrange() usage. 396 #builtins.range = builtins.xrange 397 398 # The os.devnull object for Python 2.3 and earlier. 399 if sys.version_info[1] <= 3: 400 if SYSTEM == 'Linux': 401 os.devnull = '/dev/null' 402 elif SYSTEM == 'Windows': 403 os.devnull = 'nul' 404 elif SYSTEM == 'Darwin': 405 os.devnull = 'Dev:Null' 406 else: 407 os.devnull = None 408 409 # The unicode conversion function - essential for the GUI in Python 2. 410 unicode = builtins.unicode 411 412 # Unicode string handling. 413 from codecs import unicode_escape_decode
414 - def u(text):
415 """Create a unicode string for Python 2. 416 417 @param text: The text to convert. 418 @type text: str 419 @return: The text converted to unicode. 420 @rtype: unicode 421 """ 422 423 return unicode_escape_decode(text)[0]
424 425 426 # Python 3 work-arounds. 427 if PY_VERSION == 3: 428 # The unicode conversion function - essential for the GUI in Python 2. 429 unicode = builtins.str 430 431 # Unicode string handling.
432 - def u(text):
433 """Create a unicode string for Python 3. 434 435 @param text: The text to convert. 436 @type text: str 437 @return: The unmodified text, as all strings in Python 3 are unicode and the unicode type does not exist. 438 @rtype: str 439 """ 440 441 return text
442