1"""Python 2/3 compat layer leftovers.""" 2 3import decimal as _decimal 4import math as _math 5import warnings 6from contextlib import redirect_stderr, redirect_stdout 7from io import BytesIO 8from io import StringIO as UnicodeIO 9from types import SimpleNamespace 10 11warnings.warn( 12 "The py23 module has been deprecated and will be removed in a future release. " 13 "Please update your code.", 14 DeprecationWarning, 15) 16 17__all__ = [ 18 "basestring", 19 "bytechr", 20 "byteord", 21 "BytesIO", 22 "bytesjoin", 23 "open", 24 "Py23Error", 25 "range", 26 "RecursionError", 27 "round", 28 "SimpleNamespace", 29 "StringIO", 30 "strjoin", 31 "Tag", 32 "tobytes", 33 "tostr", 34 "tounicode", 35 "unichr", 36 "unicode", 37 "UnicodeIO", 38 "xrange", 39 "zip", 40] 41 42 43class Py23Error(NotImplementedError): 44 pass 45 46 47RecursionError = RecursionError 48StringIO = UnicodeIO 49 50basestring = str 51isclose = _math.isclose 52isfinite = _math.isfinite 53open = open 54range = range 55round = round3 = round 56unichr = chr 57unicode = str 58zip = zip 59 60 61def bytechr(n): 62 return bytes([n]) 63 64 65def byteord(c): 66 return c if isinstance(c, int) else ord(c) 67 68 69def strjoin(iterable, joiner=""): 70 return tostr(joiner).join(iterable) 71 72 73def tobytes(s, encoding="ascii", errors="strict"): 74 if not isinstance(s, bytes): 75 return s.encode(encoding, errors) 76 else: 77 return s 78 79 80def tounicode(s, encoding="ascii", errors="strict"): 81 if not isinstance(s, unicode): 82 return s.decode(encoding, errors) 83 else: 84 return s 85 86 87tostr = tounicode 88 89 90class Tag(str): 91 @staticmethod 92 def transcode(blob): 93 if isinstance(blob, bytes): 94 blob = blob.decode("latin-1") 95 return blob 96 97 def __new__(self, content): 98 return str.__new__(self, self.transcode(content)) 99 100 def __ne__(self, other): 101 return not self.__eq__(other) 102 103 def __eq__(self, other): 104 return str.__eq__(self, self.transcode(other)) 105 106 def __hash__(self): 107 return str.__hash__(self) 108 109 def tobytes(self): 110 return self.encode("latin-1") 111 112 113def bytesjoin(iterable, joiner=b""): 114 return tobytes(joiner).join(tobytes(item) for item in iterable) 115 116 117def xrange(*args, **kwargs): 118 raise Py23Error("'xrange' is not defined. Use 'range' instead.") 119 120 121def round2(number, ndigits=None): 122 """ 123 Implementation of Python 2 built-in round() function. 124 Rounds a number to a given precision in decimal digits (default 125 0 digits). The result is a floating point number. Values are rounded 126 to the closest multiple of 10 to the power minus ndigits; if two 127 multiples are equally close, rounding is done away from 0. 128 ndigits may be negative. 129 See Python 2 documentation: 130 https://docs.python.org/2/library/functions.html?highlight=round#round 131 """ 132 if ndigits is None: 133 ndigits = 0 134 135 if ndigits < 0: 136 exponent = 10 ** (-ndigits) 137 quotient, remainder = divmod(number, exponent) 138 if remainder >= exponent // 2 and number >= 0: 139 quotient += 1 140 return float(quotient * exponent) 141 else: 142 exponent = _decimal.Decimal("10") ** (-ndigits) 143 144 d = _decimal.Decimal.from_float(number).quantize( 145 exponent, rounding=_decimal.ROUND_HALF_UP 146 ) 147 148 return float(d) 149