Module compat
[hide private]
[frames] | no frames]

Source Code for Module compat

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2012-2013 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  # Dependency check module. 
 33  import dep_check 
 34   
 35  # Python module imports. 
 36  if dep_check.bz2_module: 
 37      import bz2 
 38      from bz2 import BZ2File 
 39  else: 
 40      BZ2File = object 
 41  if dep_check.gzip_module: 
 42      import gzip 
 43  else: 
 44      gzip = object 
 45  from copy import deepcopy 
 46  if dep_check.io_module: 
 47      import io 
 48  import os 
 49  import platform 
 50  import sys 
 51  import threading 
 52   
 53   
 54  # The operating system. 
 55  SYSTEM = platform.uname()[0] 
 56   
 57  # The Python version. 
 58  PY_VERSION = sys.version_info[0] 
 59   
 60   
 61  # Special Python version specific imports.  These will be imported from here from the rest of relax. 
 62  #################################################################################################### 
 63   
 64  # The built-in module. 
 65  if PY_VERSION == 2: 
 66      import __builtin__ as builtins 
 67  else: 
 68      import builtins 
 69   
 70  # The queue module. 
 71  if PY_VERSION == 2: 
 72      import Queue as queue 
 73  else: 
 74      import queue 
 75   
 76  # The queue.Queue class 
 77  if PY_VERSION == 2: 
 78      from Queue import Queue as Queue2 
 79  else: 
 80      from queue import Queue as Queue3 
 81      Queue2 = Queue3 
 82   
 83  # The StringIO class. 
 84  if PY_VERSION == 2: 
 85      from cStringIO import StringIO 
 86  elif dep_check.io_module: 
 87      from io import StringIO 
 88  else: 
 89      StringIO = None 
 90   
 91  # The unit test TextTestResult class. 
 92  try: 
 93      from unittest import TextTestResult    # Python 2.7 and above. 
 94  except ImportError: 
 95      from unittest import _TextTestResult as TextTestResult    # Python 2.6 and below. 
 96   
 97  # The pickle package. 
 98  if PY_VERSION == 2: 
 99      import cPickle as pickle 
100  else: 
101      import pickle 
102   
103   
104 -def bz2_open(file, mode='r'):
105 """Abstract the numerous ways BZ2 files are handled in Python. 106 107 @param file: The file path to open. 108 @type file: str 109 @keyword mode: The mode to open the file with. Only the values of 'r' and 'w' for reading and writing respectively are supported. 110 @type model: str 111 @return: The bzip2 file object. 112 @rtype: file object 113 """ 114 115 # Check the mode. 116 if mode not in ['r', 'w']: 117 raise RelaxError("The mode '%s' must be one or 'r' or 'w'." % mode) 118 119 # Check if the bz2 module exists. 120 if not dep_check.bz2_module: 121 if mode == 'r': 122 raise RelaxError("Cannot open the file %s, try uncompressing first. %s." % (file, dep_check.bz2_module_message)) 123 else: 124 raise RelaxError("Cannot create bzip2 file %s, the bz2 Python module cannot be found." % file) 125 126 # Open the file for reading. 127 if mode == 'r': 128 # Python 3.3 text mode. 129 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 130 file_obj = bz2.open(file, 't') 131 132 # Python 3.0, 3.1 and 3.2 text mode. 133 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 134 file_obj = io.TextIOWrapper(Bzip2Fixed(file, 'r')) 135 136 # Python 2 text mode. 137 else: 138 file_obj = bz2.BZ2File(file, 'r') 139 140 # Open the file for writing. 141 elif mode == 'w': 142 # Python 3.3 text mode. 143 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 144 file_obj = bz2.open(file, 'wt') 145 146 # Python 3.0, 3.1 and 3.2 text mode. 147 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 148 file_obj = io.TextIOWrapper(Bzip2Fixed(file, 'w')) 149 150 # Python 2 text mode. 151 else: 152 file_obj = bz2.BZ2File(file, 'w') 153 154 # Return the file object. 155 return file_obj
156 157
158 -def gz_open(file, mode='r'):
159 """Abstract the numerous ways gzipped files are handled in Python. 160 161 @param file: The file path to open. 162 @type file: str 163 @keyword mode: The mode to open the file with. Only the values of 'r' and 'w' for reading and writing respectively are supported. 164 @type model: str 165 @return: The gzipped file object. 166 @rtype: file object 167 """ 168 169 # Check the mode. 170 if mode not in ['r', 'w']: 171 raise RelaxError("The mode '%s' must be one or 'r' or 'w'." % mode) 172 173 # Check if the bz2 module exists. 174 if not dep_check.gzip_module: 175 if mode == 'r': 176 raise RelaxError("Cannot open the file %s, try uncompressing first. %s." % (file, dep_check.gzip_module_message)) 177 else: 178 raise RelaxError("Cannot create gzipped file %s, the bz2 Python module cannot be found." % file) 179 180 # Open the file for reading. 181 if mode == 'r': 182 # Python 3.3 text mode. 183 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 184 file_obj = gzip.open(file, 'rt') 185 186 # Python 3.0, 3.1 and 3.2 text mode. 187 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 188 file_obj = io.TextIOWrapper(GzipFixed(file, 'r')) 189 190 # Python 2 text mode. 191 else: 192 file_obj = gzip.GzipFile(file, 'r') 193 194 # Open the file for writing. 195 elif mode == 'w': 196 # Python 3.3 text mode. 197 if sys.version_info[0] == 3 and sys.version_info[1] >= 3: 198 file_obj = gzip.open(file, 'wt') 199 200 # Python 3.0, 3.1 and 3.2 text mode. 201 elif sys.version_info[0] == 3 and sys.version_info[1] < 3: 202 file_obj = io.TextIOWrapper(GzipFixed(file, 'w')) 203 204 # Python 2 text mode. 205 else: 206 file_obj = gzip.GzipFile(file, 'w') 207 208 # Return the file object. 209 return file_obj
210 211
212 -def sorted(data):
213 """Python 2.3 and earlier replacement function for the builtin sorted() function.""" 214 215 # Make a copy of the data. 216 new_data = deepcopy(data) 217 218 # Sort. 219 new_data.sort() 220 221 # Return the new data. 222 return new_data
223 224 225
226 -class Bzip2Fixed(BZ2File):
227 """Incredibly nasty hack for bzip2 files support in Python 3.0, 3.1 and 3.2.""" 228
229 - def flush(self):
230 pass
231
232 - def read1(self, n):
233 return self.read(n)
234
235 - def readable(self):
236 return True
237
238 - def seekable(self):
239 return True
240
241 - def writable(self):
242 return True
243 244 245
246 -class GzipFixed(gzip.GzipFile):
247 """Incredibly nasty hack for gzipped files support in Python 3.0, 3.1 and 3.2.""" 248 249 closed = False 250
251 - def read1(self, n):
252 return self.read(n)
253
254 - def readable(self):
255 return True
256
257 - def seekable(self):
258 return True
259
260 - def writable(self):
261 return True
262 263 264
265 -class TaskQueue(Queue2):
266 """Python 2.4 and earlier Queuing class replacement. 267 268 This code comes from http://code.activestate.com/recipes/475160/ and is part of the Python sources from 2.5 onwards. 269 """ 270
271 - def __init__(self):
272 Queue2.__init__(self) 273 self.all_tasks_done = threading.Condition(self.mutex) 274 self.unfinished_tasks = 0
275
276 - def _put(self, item):
277 Queue2._put(self, item) 278 self.unfinished_tasks += 1
279
280 - def task_done(self):
281 """Indicate that a formerly enqueued task is complete. 282 283 Used by Queue consumer threads. For each get() used to fetch a task, 284 a subsequent call to task_done() tells the queue that the processing 285 on the task is complete. 286 287 If a join() is currently blocking, it will resume when all items 288 have been processed (meaning that a task_done() call was received 289 for every item that had been put() into the queue). 290 291 Raises a ValueError if called more times than there were items 292 placed in the queue. 293 """ 294 self.all_tasks_done.acquire() 295 try: 296 unfinished = self.unfinished_tasks - 1 297 if unfinished <= 0: 298 if unfinished < 0: 299 raise ValueError('task_done() called too many times') 300 self.all_tasks_done.notifyAll() 301 self.unfinished_tasks = unfinished 302 finally: 303 self.all_tasks_done.release()
304
305 - def join(self):
306 """Blocks until all items in the Queue have been gotten and processed. 307 308 The count of unfinished tasks goes up whenever an item is added to the 309 queue. The count goes down whenever a consumer thread calls task_done() 310 to indicate the item was retrieved and all work on it is complete. 311 312 When the count of unfinished tasks drops to zero, join() unblocks. 313 """ 314 self.all_tasks_done.acquire() 315 try: 316 while self.unfinished_tasks: 317 self.all_tasks_done.wait() 318 finally: 319 self.all_tasks_done.release()
320 321 322 # Alias the correct Queue. 323 if PY_VERSION == 2 and sys.version_info[1] <= 4: 324 Queue = TaskQueue # Alias the TaskQueue for Python 2.4 and earlier. 325 elif PY_VERSION == 2: 326 Queue = Queue2 327 else: 328 Queue = Queue3 329 330 331 # Python 2 hacks. 332 if PY_VERSION == 2: 333 # Switch all range() calls to xrange() for increased speed and memory reduction. 334 # This should work as all range() usage for Python 3 in relax must match the old xrange() usage. 335 builtins.range = builtins.xrange 336 337 # The sorted() builtin function for Python 2.3 and earlier. 338 if sys.version_info[1] <= 3: 339 setattr(builtins, 'sorted', sorted) 340 341 # The os.devnull object for Python 2.3 and earlier. 342 if sys.version_info[1] <= 3: 343 if SYSTEM == 'Linux': 344 os.devnull = '/dev/null' 345 elif SYSTEM == 'Windows' or SYSTEM == 'Microsoft': 346 os.devnull = 'nul' 347 elif SYSTEM == 'Darwin': 348 os.devnull = 'Dev:Null' 349 else: 350 os.devnull = None 351 352 353 # Python 3 work-arounds. 354 if PY_VERSION == 3: 355 # The unicode conversion function - essential for the GUI in Python 2. 356 builtins.unicode = builtins.str 357