view 2.00/compat.py @ 21:ec6f1a132109

A pretty usable version Test groups and testconfs in non-ZIP archives or ZIP archives with comments are not yet supported.
author Oleg Oshmyan <chortos@inbox.lv>
date Fri, 06 Aug 2010 15:39:29 +0000
parents f2279b7602d3
children f07b7a431ea6
line wrap: on
line source

#! /usr/bin/env python
# Copyright (c) 2010 Chortos-2 <chortos@inbox.lv>

# A compatibility layer for Python 2.5+. This is what lets test.py
# run on all versions of Python starting with 2.5, including Python 3.

# A few notes regarding some compatibility-driven peculiarities
# in the use of the language that can be seen in all modules:
#
# * Except statements never specify target; instead, when needed,
#   the exception is taken from sys.exc_info(). Blame the incompatible
#   syntaxes of the except clause in Python 2.5 and Python 3 and the lack
#   of preprocessor macros in Python of any version ;P.
#
# * Keyword-only parameters are never used, even for parameters
#   that should never be given in as arguments. The reason is
#   the laziness of some Python developers who have failed to finish
#   implementing them in Python 2 even though they had several years
#   of time and multiple version releases to sneak them in.
#
# * Abstract classes are only implemented for Python 2.6 and 2.7.
#   ABC's require the abc module and the specification of metaclasses,
#   but in Python 2.5, the abc module does not exist, while in Python 3,
#   metaclasses are specified using a syntax totally incompatible
#   with Python 2 and not usable conditionally via exec() and such
#   because it is a detail of the syntax of the class statement itself.

__all__ = ('say', 'basestring', 'range', 'map', 'zip', 'filter',
           'items', 'keys', 'values', 'ABCMeta', 'abstractmethod')

try:
	# Python 3
	exec('say = print')
except SyntaxError:
	try:
		# Python 2.6/2.7
		# An alternative is exec('from __future__ import print_function; say = print');
		# if problems arise with the current line, one should try replacing it
		# with this one with the future import before abandoning the idea altogether
		say = __builtins__['print']
	except Exception:
		# Python 2.5
		import sys
		# This should fully emulate the print function of Python 2.6 in Python 2.3+
		# The error messages are taken from Python 2.6
		# The name bindings at the bottom of this file are in effect
		def saytypeerror(value, name):
			return TypeError(' '.join((name, 'must be None, str or unicode, not', type(value).__name__)))
		def say(*values, **kwargs):
			sep  = kwargs.pop('sep' , None)
			end  = kwargs.pop('end' , None)
			file = kwargs.pop('file', None)
			if kwargs: raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.popitem()[0])
			if sep  is None: sep  = ' '
			if end  is None: end  = '\n'
			if file is None: file = sys.stdout
			if not isinstance(sep, basestring): raise saytypeerror(sep, 'sep')
			if not isinstance(end, basestring): raise saytypeerror(end, 'end')
			file.write(sep.join(map(str, values)) + end)

def import_urllib():
	try:
		# Python 3
		import urllib.request
		return urllib.request, lambda url: urllib.request.urlopen(url).read().decode()
	except ImportError:
		# Python 2
		import urllib
		return urllib, lambda url: urllib.urlopen(url).read()

try:
	from abc import ABCMeta, abstractmethod
except ImportError:
	ABCMeta, abstractmethod = None, lambda x: x

# In all of the following, the try clause is for Python 2 and the except
# clause is for Python 3. More checks are performed than needed
# for standard builds of Python to ensure as much as possible works
# on custom builds.
try:
	basestring = basestring
except NameError:
	basestring = str

try:
	range = xrange
except NameError:
	range = range

try:
	from itertools import imap as map
except ImportError:
	map = map

try:
	from itertools import izip as zip
except ImportError:
	zip = zip

try:
	from itertools import ifilter as filter
except ImportError:
	filter = filter

items = dict.iteritems if hasattr(dict, 'iteritems') else dict.items
keys = dict.iterkeys if hasattr(dict, 'iterkeys') else dict.keys
values = dict.itervalues if hasattr(dict, 'itervalues') else dict.values

for name in __all__:
	__builtins__[name] = globals()[name]

__builtins__['xrange'] = range