Mercurial > ~astiob > upreckon > hgweb
annotate 2.00/compat.py @ 25:b500e117080e
Bug fixes and overhead reduction
Added the --problem/-p option. (WARNING: not the same as the -p option of test.py 1.x.) The problem names supplied are not validated.
Added zip_longest to compat.py.
Experimental: problem names are now _always_ printed for multi-problem sets.
Overhead: Escape presses are now checked only once every .15 seconds (at least kbhit() on Windows is very slow).
Overhead: sleep(0) is now called in the time-control-and-Escape-watching loop (at least on Windows, it immediately transfers control to some waiting thread).
Bug fix: compat.py now overwrites built-ins only while including testconfs (--help was broken in Python 2).
Bug fix: ReadDeleting in config.py now closes the file it opens (especially important on Windows, where open files cannot be deleted).
Bug fix: added callable to compat.py (it is absent from Python 3).
Bug fix: the default (built-in) output validator now properly handles unwanted trailing data.
Bug fix: testconfs in custom archives no more raise NameError.
Bug fix: if a validator program cannot be launched, CannotStartValidator is now raised instead of the fatal OSError.
| author | Oleg Oshmyan <chortos@inbox.lv> |
|---|---|
| date | Thu, 23 Sep 2010 23:05:58 +0000 |
| parents | f07b7a431ea6 |
| children | dc4be35d17e0 |
| 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 | |
|
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
28 import __builtin__ |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
29 |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
30 __all__ = ('say', 'basestring', 'range', 'map', 'zip', 'filter', 'items', |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
31 'keys', 'values', 'zip_longest', 'callable', |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
32 'ABCMeta', 'abstractmethod', 'CompatBuiltins') |
| 21 | 33 |
| 16 | 34 try: |
| 35 # Python 3 | |
| 36 exec('say = print') | |
| 37 except SyntaxError: | |
| 38 try: | |
| 39 # Python 2.6/2.7 | |
| 21 | 40 # An alternative is exec('from __future__ import print_function; say = print'); |
| 41 # if problems arise with the current line, one should try replacing it | |
| 42 # with this one with the future import before abandoning the idea altogether | |
| 43 say = __builtins__['print'] | |
| 16 | 44 except Exception: |
| 45 # Python 2.5 | |
| 46 import sys | |
| 47 # This should fully emulate the print function of Python 2.6 in Python 2.3+ | |
| 21 | 48 # The error messages are taken from Python 2.6 |
| 49 # The name bindings at the bottom of this file are in effect | |
| 16 | 50 def saytypeerror(value, name): |
| 21 | 51 return TypeError(' '.join((name, 'must be None, str or unicode, not', type(value).__name__))) |
| 16 | 52 def say(*values, **kwargs): |
| 53 sep = kwargs.pop('sep' , None) | |
| 54 end = kwargs.pop('end' , None) | |
| 55 file = kwargs.pop('file', None) | |
| 56 if kwargs: raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.popitem()[0]) | |
| 57 if sep is None: sep = ' ' | |
| 58 if end is None: end = '\n' | |
| 59 if file is None: file = sys.stdout | |
| 60 if not isinstance(sep, basestring): raise saytypeerror(sep, 'sep') | |
| 61 if not isinstance(end, basestring): raise saytypeerror(end, 'end') | |
| 21 | 62 file.write(sep.join(map(str, values)) + end) |
| 16 | 63 |
| 64 def import_urllib(): | |
| 65 try: | |
| 66 # Python 3 | |
| 67 import urllib.request | |
| 68 return urllib.request, lambda url: urllib.request.urlopen(url).read().decode() | |
| 69 except ImportError: | |
| 70 # Python 2 | |
| 71 import urllib | |
| 21 | 72 return urllib, lambda url: urllib.urlopen(url).read() |
| 73 | |
| 74 try: | |
| 75 from abc import ABCMeta, abstractmethod | |
| 76 except ImportError: | |
| 77 ABCMeta, abstractmethod = None, lambda x: x | |
| 78 | |
| 79 # In all of the following, the try clause is for Python 2 and the except | |
| 80 # clause is for Python 3. More checks are performed than needed | |
| 81 # for standard builds of Python to ensure as much as possible works | |
| 82 # on custom builds. | |
| 83 try: | |
| 84 basestring = basestring | |
| 85 except NameError: | |
| 86 basestring = str | |
| 87 | |
| 88 try: | |
| 89 range = xrange | |
| 90 except NameError: | |
| 91 range = range | |
| 92 | |
| 93 try: | |
|
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
94 callable = callable |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
95 except NameError: |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
96 callable = lambda obj: hasattr(obj, '__call__') |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
97 |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
98 try: |
| 21 | 99 from itertools import imap as map |
| 100 except ImportError: | |
| 101 map = map | |
| 102 | |
| 103 try: | |
| 104 from itertools import izip as zip | |
| 105 except ImportError: | |
| 106 zip = zip | |
| 107 | |
| 108 try: | |
| 109 from itertools import ifilter as filter | |
| 110 except ImportError: | |
| 111 filter = filter | |
| 112 | |
| 113 items = dict.iteritems if hasattr(dict, 'iteritems') else dict.items | |
| 114 keys = dict.iterkeys if hasattr(dict, 'iterkeys') else dict.keys | |
| 115 values = dict.itervalues if hasattr(dict, 'itervalues') else dict.values | |
| 116 | |
|
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
117 try: |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
118 # Python 3 |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
119 from itertools import zip_longest |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
120 except ImportError: |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
121 # Python 2.6/2.7 |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
122 from itertools import izip_longest as 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.5 |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
125 from itertools import chain, repeat |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
126 # Adapted from the documentation of itertools.izip_longest |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
127 def zip_longest(*args, **kwargs): |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
128 fillvalue = kwargs.get('fillvalue') |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
129 def sentinel(counter=([fillvalue]*(len(args)-1)).pop): |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
130 yield counter() |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
131 fillers = repeat(fillvalue) |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
132 iters = [chain(it, sentinel(), fillers) for it in args] |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
133 try: |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
134 for tup in zip(*iters): |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
135 yield tup |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
136 except IndexError: |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
137 pass |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
138 |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
139 # Automatically import * from this module into testconf.py's |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
140 class CompatBuiltins(object): |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
141 __slots__ = 'originals' |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
142 def __init__(self): |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
143 self.originals = {} |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
144 def __enter__(self): |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
145 g = globals() |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
146 for name in __all__: |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
147 if hasattr(__builtin__, name): |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
148 self.originals[name] = getattr(__builtin__, name) |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
149 setattr(__builtin__, name, g[name]) |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
150 def __exit__(self, exc_type, exc_val, exc_tb): |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
151 for name in self.originals: |
|
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
152 setattr(__builtin__, name, self.originals[name]) |
| 21 | 153 |
| 22 | 154 # Support simple testconf.py's written for test.py 1.x |
|
25
b500e117080e
Bug fixes and overhead reduction
Oleg Oshmyan <chortos@inbox.lv>
parents:
22
diff
changeset
|
155 __builtin__.xrange = range |
