• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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