1# Copyright (c) 2020 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4"""Miscellaneous Python 2-3 compatibility functions. 5 6Seven is an extension to the compatibility layer six. 7It contains utilities that ease migration from Python 2 8to Python 3, but aren't present in the six library. 9""" 10 11import six 12import six.moves.configparser 13import socket 14import sys 15import types 16 17if six.PY3: 18 import builtins 19 SOCKET_ERRORS = (builtins.ConnectionError, socket.timeout, socket.gaierror, 20 socket.herror) 21 string_types = (str,) 22 integer_types = (int,) 23 class_types = (type,) 24 text_type = str 25 binary_type = bytes 26 27 MAXSIZE = sys.maxsize 28else: 29 SOCKET_ERRORS = (socket.error, ) 30 string_types = (basestring,) 31 integer_types = (int, long) 32 class_types = (type, types.ClassType) 33 text_type = unicode 34 binary_type = str 35 36 MAXSIZE = float("inf") 37 38 39def exec_file(filename, globals_, locals_): 40 """exec_file compiles and runs a file with globals and locals. 41 42 exec_file does not exactly mimic all the edge cases in Python 2's 43 execfile function. Rather, it does only what is necessary to execute 44 control files in autotest and prevent compiler-wide settings like 45 'from __future__ import ...' from spilling into control files that 46 have not yet been made Python 3-compatible. 47 48 Arguments: 49 filename: path to a file 50 globals_: dictionary of globals 51 locals_: dictionary of locals 52 53 Returns: 54 None (output of six.exec_) 55 """ 56 with open(filename, "rb") as fh: 57 code_obj = compile( 58 fh.read(), 59 filename, 60 mode="exec", 61 flags=0, 62 dont_inherit=1, 63 ) 64 return six.exec_(code_obj, globals_, locals_) 65 66 67def config_parser(): 68 """config_parser returns a non-strict config parser. 69 70 Unfortunately, in six configparser is not same between 2/3. For our .ini's 71 we do not want it to be strict (ie, error upon duplicates). 72 """ 73 if six.PY3: 74 return six.moves.configparser.ConfigParser(strict=False) 75 return six.moves.configparser.ConfigParser() 76 77 78def ensure_text(s, encoding='utf-8', errors='strict'): 79 """Coerce *s* to six.text_type. Copied from six lib. 80 81 For Python 2: 82 - `unicode` -> `unicode` 83 - `str` -> `unicode` 84 For Python 3: 85 - `str` -> `str` 86 - `bytes` -> decoded to `str` 87 """ 88 if isinstance(s, binary_type): 89 return s.decode(encoding, errors) 90 elif isinstance(s, text_type): 91 return s 92 else: 93 raise TypeError("not expecting type '%s'" % type(s)) 94 95 96def ensure_long(n): 97 """ensure_long returns a long if py2, or int if py3.""" 98 if six.PY2: 99 return long(n) 100 return int(n) 101