1# Copyright 2015 Google Inc. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Utilities for Python2 / Python3 compatibility."""
15
16import io
17import os
18import sys
19
20PY3 = sys.version_info[0] >= 3
21PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6
22
23if PY3:
24  StringIO = io.StringIO
25  BytesIO = io.BytesIO
26
27  import codecs
28
29  def open_with_encoding(filename, mode, encoding, newline=''):  # pylint: disable=unused-argument
30    return codecs.open(filename, mode=mode, encoding=encoding)
31
32  import functools
33  lru_cache = functools.lru_cache
34
35  range = range
36  ifilter = filter
37
38  def raw_input():
39    wrapper = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
40    return wrapper.buffer.raw.readall().decode('utf-8')
41
42  import configparser
43
44  # Mappings from strings to booleans (such as '1' to True, 'false' to False,
45  # etc.)
46  CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES
47else:
48  import __builtin__
49  import cStringIO
50  StringIO = BytesIO = cStringIO.StringIO
51
52  open_with_encoding = io.open
53
54  # Python 2.7 doesn't have a native LRU cache, so do nothing.
55  def lru_cache(maxsize=128, typed=False):
56
57    def fake_wrapper(user_function):
58      return user_function
59
60    return fake_wrapper
61
62  range = xrange
63
64  from itertools import ifilter
65  raw_input = raw_input
66
67  import ConfigParser as configparser
68  CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states  # pylint: disable=protected-access
69
70
71def EncodeAndWriteToStdout(s, encoding='utf-8'):
72  """Encode the given string and emit to stdout.
73
74  The string may contain non-ascii characters. This is a problem when stdout is
75  redirected, because then Python doesn't know the encoding and we may get a
76  UnicodeEncodeError.
77
78  Arguments:
79    s: (string) The string to encode.
80    encoding: (string) The encoding of the string.
81  """
82  if PY3:
83    sys.stdout.buffer.write(s.encode(encoding))
84  elif sys.platform == 'win32':
85    # On python 2 and Windows universal newline transformation will be in
86    # effect on stdout. Python 2 will not let us avoid the easily because
87    # it happens based on whether the file handle is opened in O_BINARY or
88    # O_TEXT state. However we can tell Windows itself to change the current
89    # mode, and python 2 will follow suit. However we must take care to change
90    # the mode on the actual external stdout not just the current sys.stdout
91    # which may have been monkey-patched inside the python environment.
92    import msvcrt  # pylint: disable=g-import-not-at-top
93    if sys.__stdout__ is sys.stdout:
94      msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
95    sys.stdout.write(s.encode(encoding))
96  else:
97    sys.stdout.write(s.encode(encoding))
98
99
100if PY3:
101  basestring = str
102  unicode = str  # pylint: disable=redefined-builtin,invalid-name
103else:
104  basestring = basestring
105
106  def unicode(s):  # pylint: disable=invalid-name
107    """Force conversion of s to unicode."""
108    return __builtin__.unicode(s, 'utf-8')
109
110
111# In Python 3.2+, readfp is deprecated in favor of read_file, which doesn't
112# exist in Python 2 yet. To avoid deprecation warnings, subclass ConfigParser to
113# fix this - now read_file works across all Python versions we care about.
114class ConfigParser(configparser.ConfigParser):
115  if not PY3:
116
117    def read_file(self, fp, source=None):
118      self.readfp(fp, filename=source)
119