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