Mercurial > ~astiob > upreckon > hgweb
annotate 2.00/compat.py @ 30:f17f19d9eb0a
hasattr -> try in the newly added 2.6 zipfile
author | Oleg Oshmyan <chortos@inbox.lv> |
---|---|
date | Wed, 24 Nov 2010 23:42:06 +0000 |
parents | dc4be35d17e0 |
children | fe1463e7e24d |
rev | line source |
---|---|
21 | 1 #! /usr/bin/env python |
16 | 2 # Copyright (c) 2010 Chortos-2 <chortos@inbox.lv> |
3 | |
21 | 4 # A compatibility layer for Python 2.5+. This is what lets test.py |
5 # run on all versions of Python starting with 2.5, including Python 3. | |
6 | |
7 # A few notes regarding some compatibility-driven peculiarities | |
8 # in the use of the language that can be seen in all modules: | |
9 # | |
10 # * Except statements never specify target; instead, when needed, | |
11 # the exception is taken from sys.exc_info(). Blame the incompatible | |
12 # syntaxes of the except clause in Python 2.5 and Python 3 and the lack | |
13 # of preprocessor macros in Python of any version ;P. | |
14 # | |
15 # * Keyword-only parameters are never used, even for parameters | |
16 # that should never be given in as arguments. The reason is | |
17 # the laziness of some Python developers who have failed to finish | |
18 # implementing them in Python 2 even though they had several years | |
19 # of time and multiple version releases to sneak them in. | |
20 # | |
21 # * Abstract classes are only implemented for Python 2.6 and 2.7. | |
22 # ABC's require the abc module and the specification of metaclasses, | |
23 # but in Python 2.5, the abc module does not exist, while in Python 3, | |
24 # metaclasses are specified using a syntax totally incompatible | |
25 # with Python 2 and not usable conditionally via exec() and such | |
26 # because it is a detail of the syntax of the class statement itself. | |
27 | |
27 | 28 try: |
29 import builtins | |
30 except ImportError: | |
31 import __builtin__ as builtins | |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
32 |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
33 __all__ = ('say', 'basestring', 'range', 'map', 'zip', 'filter', 'items', |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
34 'keys', 'values', 'zip_longest', 'callable', |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
35 'ABCMeta', 'abstractmethod', 'CompatBuiltins') |
21 | 36 |
16 | 37 try: |
38 # Python 3 | |
39 exec('say = print') | |
40 except SyntaxError: | |
41 try: | |
42 # Python 2.6/2.7 | |
21 | 43 # An alternative is exec('from __future__ import print_function; say = print'); |
44 # if problems arise with the current line, one should try replacing it | |
45 # with this one with the future import before abandoning the idea altogether | |
27 | 46 say = getattr(builtins, 'print') |
16 | 47 except Exception: |
48 # Python 2.5 | |
49 import sys | |
50 # This should fully emulate the print function of Python 2.6 in Python 2.3+ | |
21 | 51 # The error messages are taken from Python 2.6 |
52 # The name bindings at the bottom of this file are in effect | |
16 | 53 def saytypeerror(value, name): |
21 | 54 return TypeError(' '.join((name, 'must be None, str or unicode, not', type(value).__name__))) |
16 | 55 def say(*values, **kwargs): |
56 sep = kwargs.pop('sep' , None) | |
57 end = kwargs.pop('end' , None) | |
58 file = kwargs.pop('file', None) | |
59 if kwargs: raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.popitem()[0]) | |
60 if sep is None: sep = ' ' | |
61 if end is None: end = '\n' | |
62 if file is None: file = sys.stdout | |
63 if not isinstance(sep, basestring): raise saytypeerror(sep, 'sep') | |
64 if not isinstance(end, basestring): raise saytypeerror(end, 'end') | |
21 | 65 file.write(sep.join(map(str, values)) + end) |
16 | 66 |
67 def import_urllib(): | |
68 try: | |
69 # Python 3 | |
70 import urllib.request | |
71 return urllib.request, lambda url: urllib.request.urlopen(url).read().decode() | |
72 except ImportError: | |
73 # Python 2 | |
74 import urllib | |
21 | 75 return urllib, lambda url: urllib.urlopen(url).read() |
76 | |
77 try: | |
78 from abc import ABCMeta, abstractmethod | |
79 except ImportError: | |
80 ABCMeta, abstractmethod = None, lambda x: x | |
81 | |
82 # In all of the following, the try clause is for Python 2 and the except | |
83 # clause is for Python 3. More checks are performed than needed | |
84 # for standard builds of Python to ensure as much as possible works | |
85 # on custom builds. | |
86 try: | |
87 basestring = basestring | |
88 except NameError: | |
89 basestring = str | |
90 | |
91 try: | |
92 range = xrange | |
93 except NameError: | |
94 range = range | |
95 | |
96 try: | |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
97 callable = callable |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
98 except NameError: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
99 callable = lambda obj: hasattr(obj, '__call__') |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
100 |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
101 try: |
21 | 102 from itertools import imap as map |
103 except ImportError: | |
104 map = map | |
105 | |
106 try: | |
107 from itertools import izip as zip | |
108 except ImportError: | |
109 zip = zip | |
110 | |
111 try: | |
112 from itertools import ifilter as filter | |
113 except ImportError: | |
114 filter = filter | |
115 | |
116 items = dict.iteritems if hasattr(dict, 'iteritems') else dict.items | |
117 keys = dict.iterkeys if hasattr(dict, 'iterkeys') else dict.keys | |
118 values = dict.itervalues if hasattr(dict, 'itervalues') else dict.values | |
119 | |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
120 try: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
121 # Python 3 |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
122 from itertools import zip_longest |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
123 except ImportError: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
124 # Python 2.6/2.7 |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
125 from itertools import izip_longest as zip_longest |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
126 except ImportError: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
127 # Python 2.5 |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
128 from itertools import chain, repeat |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
129 # Adapted from the documentation of itertools.izip_longest |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
130 def zip_longest(*args, **kwargs): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
131 fillvalue = kwargs.get('fillvalue') |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
132 def sentinel(counter=([fillvalue]*(len(args)-1)).pop): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
133 yield counter() |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
134 fillers = repeat(fillvalue) |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
135 iters = [chain(it, sentinel(), fillers) for it in args] |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
136 try: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
137 for tup in zip(*iters): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
138 yield tup |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
139 except IndexError: |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
140 pass |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
141 |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
142 # Automatically import * from this module into testconf.py's |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
143 class CompatBuiltins(object): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
144 __slots__ = 'originals' |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
145 def __init__(self): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
146 self.originals = {} |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
147 def __enter__(self): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
148 g = globals() |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
149 for name in __all__: |
27 | 150 if hasattr(builtins, name): |
151 self.originals[name] = getattr(builtins, name) | |
152 setattr(builtins, name, g[name]) | |
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
153 def __exit__(self, exc_type, exc_val, exc_tb): |
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
154 for name in self.originals: |
27 | 155 setattr(builtins, name, self.originals[name]) |
21 | 156 |
22 | 157 # Support simple testconf.py's written for test.py 1.x |
27 | 158 builtins.xrange = range |