• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015-2017 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  raw_input = input
38
39  import configparser
40
41  # Mappings from strings to booleans (such as '1' to True, 'false' to False,
42  # etc.)
43  CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES
44else:
45  import __builtin__
46  import cStringIO
47  StringIO = BytesIO = cStringIO.StringIO
48
49  open_with_encoding = io.open
50
51  # Python 2.7 doesn't have a native LRU cache, so do nothing.
52  def lru_cache(maxsize=128, typed=False):
53
54    def fake_wrapper(user_function):
55      return user_function
56
57    return fake_wrapper
58
59  range = xrange
60
61  from itertools import ifilter
62  raw_input = raw_input
63
64  import ConfigParser as configparser
65  CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states  # pylint: disable=protected-access
66
67
68def EncodeAndWriteToStdout(s, encoding='utf-8'):
69  """Encode the given string and emit to stdout.
70
71  The string may contain non-ascii characters. This is a problem when stdout is
72  redirected, because then Python doesn't know the encoding and we may get a
73  UnicodeEncodeError.
74
75  Arguments:
76    s: (string) The string to encode.
77    encoding: (string) The encoding of the string.
78  """
79  if PY3:
80    sys.stdout.buffer.write(s.encode(encoding))
81  elif sys.platform == 'win32':
82    # On python 2 and Windows universal newline transformation will be in
83    # effect on stdout. Python 2 will not let us avoid the easily because
84    # it happens based on whether the file handle is opened in O_BINARY or
85    # O_TEXT state. However we can tell Windows itself to change the current
86    # mode, and python 2 will follow suit. However we must take care to change
87    # the mode on the actual external stdout not just the current sys.stdout
88    # which may have been monkey-patched inside the python environment.
89    import msvcrt  # pylint: disable=g-import-not-at-top
90    if sys.__stdout__ is sys.stdout:
91      msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
92    sys.stdout.write(s.encode(encoding))
93  else:
94    sys.stdout.write(s.encode(encoding))
95
96
97if PY3:
98  unicode = str  # pylint: disable=redefined-builtin,invalid-name
99else:
100
101  def unicode(s):  # pylint: disable=invalid-name
102    """Force conversion of s to unicode."""
103    return __builtin__.unicode(s, 'utf-8')
104
105
106# In Python 3.2+, readfp is deprecated in favor of read_file, which doesn't
107# exist in Python 2 yet. To avoid deprecation warnings, subclass ConfigParser to
108# fix this - now read_file works across all Python versions we care about.
109class ConfigParser(configparser.ConfigParser):
110  if not PY3:
111
112    def read_file(self, fp, source=None):
113      self.readfp(fp, filename=source)
114