1# Copyright 2015 The TensorFlow Authors. 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# ==============================================================================
15"""Functions for Python 2 vs. 3 compatibility.
16
17## Conversion routines
18In addition to the functions below, `as_str` converts an object to a `str`.
19
20@@as_bytes
21@@as_text
22@@as_str_any
23@@path_to_str
24
25## Types
26The compatibility module also provides the following types:
27
28* `bytes_or_text_types`
29* `complex_types`
30* `integral_types`
31* `real_types`
32"""
33
34from __future__ import absolute_import
35from __future__ import division
36from __future__ import print_function
37
38import numbers as _numbers
39
40import numpy as _np
41import six as _six
42
43from tensorflow.python.util.all_util import remove_undocumented
44from tensorflow.python.util.tf_export import tf_export
45from tensorflow.python.util.tf_export import tf_export
46
47
48@tf_export('compat.as_bytes', 'compat.as_str')
49def as_bytes(bytes_or_text, encoding='utf-8'):
50  """Converts either bytes or unicode to `bytes`, using utf-8 encoding for text.
51
52  Args:
53    bytes_or_text: A `bytes`, `str`, or `unicode` object.
54    encoding: A string indicating the charset for encoding unicode.
55
56  Returns:
57    A `bytes` object.
58
59  Raises:
60    TypeError: If `bytes_or_text` is not a binary or unicode string.
61  """
62  if isinstance(bytes_or_text, _six.text_type):
63    return bytes_or_text.encode(encoding)
64  elif isinstance(bytes_or_text, bytes):
65    return bytes_or_text
66  else:
67    raise TypeError('Expected binary or unicode string, got %r' %
68                    (bytes_or_text,))
69
70
71@tf_export('compat.as_text')
72def as_text(bytes_or_text, encoding='utf-8'):
73  """Returns the given argument as a unicode string.
74
75  Args:
76    bytes_or_text: A `bytes`, `str`, or `unicode` object.
77    encoding: A string indicating the charset for decoding unicode.
78
79  Returns:
80    A `unicode` (Python 2) or `str` (Python 3) object.
81
82  Raises:
83    TypeError: If `bytes_or_text` is not a binary or unicode string.
84  """
85  if isinstance(bytes_or_text, _six.text_type):
86    return bytes_or_text
87  elif isinstance(bytes_or_text, bytes):
88    return bytes_or_text.decode(encoding)
89  else:
90    raise TypeError('Expected binary or unicode string, got %r' % bytes_or_text)
91
92
93# Convert an object to a `str` in both Python 2 and 3.
94if _six.PY2:
95  as_str = as_bytes
96else:
97  as_str = as_text
98
99
100@tf_export('compat.as_str_any')
101def as_str_any(value):
102  """Converts to `str` as `str(value)`, but use `as_str` for `bytes`.
103
104  Args:
105    value: A object that can be converted to `str`.
106
107  Returns:
108    A `str` object.
109  """
110  if isinstance(value, bytes):
111    return as_str(value)
112  else:
113    return str(value)
114
115
116@tf_export('compat.path_to_str')
117def path_to_str(path):
118  """Returns the file system path representation of a `PathLike` object, else as it is.
119
120  Args:
121    path: An object that can be converted to path representation.
122
123  Returns:
124    A `str` object.
125  """
126  if hasattr(path, '__fspath__'):
127    path = as_str_any(path.__fspath__())
128  return path
129
130
131# Numpy 1.8 scalars don't inherit from numbers.Integral in Python 3, so we
132# need to check them specifically.  The same goes from Real and Complex.
133integral_types = (_numbers.Integral, _np.integer)
134tf_export('compat.integral_types').export_constant(__name__, 'integral_types')
135real_types = (_numbers.Real, _np.integer, _np.floating)
136tf_export('compat.real_types').export_constant(__name__, 'real_types')
137complex_types = (_numbers.Complex, _np.number)
138tf_export('compat.complex_types').export_constant(__name__, 'complex_types')
139
140# Either bytes or text.
141bytes_or_text_types = (bytes, _six.text_type)
142tf_export('compat.bytes_or_text_types').export_constant(__name__,
143                                                        'bytes_or_text_types')
144
145_allowed_symbols = [
146    'as_str',
147    'bytes_or_text_types',
148    'complex_types',
149    'integral_types',
150    'real_types',
151]
152
153remove_undocumented(__name__, _allowed_symbols)
154