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"""Compatibility functions. 16 17The `tf.compat` module contains two sets of compatibility functions. 18 19## Tensorflow 1.x and 2.x APIs 20 21The `compat.v1` and `compat.v2` submodules provide a complete copy of both the 22`v1` and `v2` APIs for backwards and forwards compatibility across TensorFlow 23versions 1.x and 2.x. See the 24[migration guide](https://www.tensorflow.org/guide/migrate) for details. 25 26## Utilities for writing compatible code 27 28Aside from the `compat.v1` and `compat.v2` submodules, `tf.compat` also contains 29a set of helper functions for writing code that works in both: 30 31* TensorFlow 1.x and 2.x 32* Python 2 and 3 33 34 35## Type collections 36 37The compatibility module also provides the following aliases for common 38sets of python types: 39 40* `bytes_or_text_types` 41* `complex_types` 42* `integral_types` 43* `real_types` 44""" 45 46import numbers as _numbers 47 48import numpy as _np 49import six as _six 50import codecs 51 52from tensorflow.python.util.tf_export import tf_export 53 54try: 55 # This import only works on python 3.3 and above. 56 import collections.abc as collections_abc # pylint: disable=unused-import 57except ImportError: 58 import collections as collections_abc # pylint: disable=unused-import 59 60 61def as_bytes(bytes_or_text, encoding='utf-8'): 62 """Converts `bytearray`, `bytes`, or unicode python input types to `bytes`. 63 64 Uses utf-8 encoding for text by default. 65 66 Args: 67 bytes_or_text: A `bytearray`, `bytes`, `str`, or `unicode` object. 68 encoding: A string indicating the charset for encoding unicode. 69 70 Returns: 71 A `bytes` object. 72 73 Raises: 74 TypeError: If `bytes_or_text` is not a binary or unicode string. 75 """ 76 # Validate encoding, a LookupError will be raised if invalid. 77 encoding = codecs.lookup(encoding).name 78 if isinstance(bytes_or_text, bytearray): 79 return bytes(bytes_or_text) 80 elif isinstance(bytes_or_text, _six.text_type): 81 return bytes_or_text.encode(encoding) 82 elif isinstance(bytes_or_text, bytes): 83 return bytes_or_text 84 else: 85 raise TypeError('Expected binary or unicode string, got %r' % 86 (bytes_or_text,)) 87 88 89def as_text(bytes_or_text, encoding='utf-8'): 90 """Converts any string-like python input types to unicode. 91 92 Returns the input as a unicode string. Uses utf-8 encoding for text 93 by default. 94 95 Args: 96 bytes_or_text: A `bytes`, `str`, or `unicode` object. 97 encoding: A string indicating the charset for decoding unicode. 98 99 Returns: 100 A `unicode` (Python 2) or `str` (Python 3) object. 101 102 Raises: 103 TypeError: If `bytes_or_text` is not a binary or unicode string. 104 """ 105 # Validate encoding, a LookupError will be raised if invalid. 106 encoding = codecs.lookup(encoding).name 107 if isinstance(bytes_or_text, _six.text_type): 108 return bytes_or_text 109 elif isinstance(bytes_or_text, bytes): 110 return bytes_or_text.decode(encoding) 111 else: 112 raise TypeError('Expected binary or unicode string, got %r' % bytes_or_text) 113 114 115def as_str(bytes_or_text, encoding='utf-8'): 116 return as_text(bytes_or_text, encoding) 117 118tf_export('compat.as_text')(as_text) 119tf_export('compat.as_bytes')(as_bytes) 120tf_export('compat.as_str')(as_str) 121 122 123@tf_export('compat.as_str_any') 124def as_str_any(value, encoding='utf-8'): 125 """Converts input to `str` type. 126 127 Uses `str(value)`, except for `bytes` typed inputs, which are converted 128 using `as_str`. 129 130 Args: 131 value: A object that can be converted to `str`. 132 encoding: Encoding for `bytes` typed inputs. 133 134 Returns: 135 A `str` object. 136 """ 137 if isinstance(value, bytes): 138 return as_str(value, encoding=encoding) 139 else: 140 return str(value) 141 142 143@tf_export('compat.path_to_str') 144def path_to_str(path): 145 r"""Converts input which is a `PathLike` object to `str` type. 146 147 Converts from any python constant representation of a `PathLike` object to 148 a string. If the input is not a `PathLike` object, simply returns the input. 149 150 Args: 151 path: An object that can be converted to path representation. 152 153 Returns: 154 A `str` object. 155 156 Usage: 157 In case a simplified `str` version of the path is needed from an 158 `os.PathLike` object. 159 160 Examples: 161 ```python 162 $ tf.compat.path_to_str('C:\XYZ\tensorflow\./.././tensorflow') 163 'C:\XYZ\tensorflow\./.././tensorflow' # Windows OS 164 $ tf.compat.path_to_str(Path('C:\XYZ\tensorflow\./.././tensorflow')) 165 'C:\XYZ\tensorflow\..\tensorflow' # Windows OS 166 $ tf.compat.path_to_str(Path('./corpus')) 167 'corpus' # Linux OS 168 $ tf.compat.path_to_str('./.././Corpus') 169 './.././Corpus' # Linux OS 170 $ tf.compat.path_to_str(Path('./.././Corpus')) 171 '../Corpus' # Linux OS 172 $ tf.compat.path_to_str(Path('./..////../')) 173 '../..' # Linux OS 174 175 ``` 176 """ 177 if hasattr(path, '__fspath__'): 178 path = as_str_any(path.__fspath__()) 179 return path 180 181 182def path_to_bytes(path): 183 r"""Converts input which is a `PathLike` object to `bytes`. 184 185 Converts from any python constant representation of a `PathLike` object 186 or `str` to bytes. 187 188 Args: 189 path: An object that can be converted to path representation. 190 191 Returns: 192 A `bytes` object. 193 194 Usage: 195 In case a simplified `bytes` version of the path is needed from an 196 `os.PathLike` object. 197 """ 198 if hasattr(path, '__fspath__'): 199 path = path.__fspath__() 200 return as_bytes(path) 201 202 203# Numpy 1.8 scalars don't inherit from numbers.Integral in Python 3, so we 204# need to check them specifically. The same goes from Real and Complex. 205integral_types = (_numbers.Integral, _np.integer) 206tf_export('compat.integral_types').export_constant(__name__, 'integral_types') 207real_types = (_numbers.Real, _np.integer, _np.floating) 208tf_export('compat.real_types').export_constant(__name__, 'real_types') 209complex_types = (_numbers.Complex, _np.number) 210tf_export('compat.complex_types').export_constant(__name__, 'complex_types') 211 212# Either bytes or text. 213bytes_or_text_types = (bytes, _six.text_type) 214tf_export('compat.bytes_or_text_types').export_constant(__name__, 215 'bytes_or_text_types') 216