compat.py 7.3 KB
Newer Older
M
minqiyang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import six
M
minqiyang 已提交
16
import math
M
minqiyang 已提交
17

18
__all__ = [
M
minqiyang 已提交
19
    'long_type',
M
minqiyang 已提交
20
    'to_text',
21 22 23 24 25
    'to_bytes',
    'round',
    'floor_division',
    'get_exception_message',
]
M
minqiyang 已提交
26

M
minqiyang 已提交
27 28 29 30 31 32 33
if six.PY2:
    int_type = int
    long_type = long
else:
    int_type = int
    long_type = int

M
minqiyang 已提交
34

M
minqiyang 已提交
35
#  str and bytes related functions
M
minqiyang 已提交
36
def to_text(obj, encoding='utf-8', inplace=False):
37
    """
C
Chen Long 已提交
38 39
    All string in PaddlePaddle should be represented as a literal string.
    
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    This function will convert object to a literal string without any encoding.
    Especially, if the object type is a list or set container, we will iterate
    all items in the object and convert them to literal string.

    In Python3:
        Decode the bytes type object to str type with specific encoding

    In Python2:
        Decode the str type object to unicode type with specific encoding

    Args:
        obj(unicode|str|bytes|list|set) : The object to be decoded.
        encoding(str) : The encoding format to decode a string
        inplace(bool) : If we change the original object or we create a new one

    Returns:
        Decoded result of obj
C
Chen Long 已提交
57 58 59 60 61 62 63 64 65 66 67
    
    Examples:

        .. code-block:: python

            import paddle

            data = "paddlepaddle"
            data = paddle.compat.to_text(data)
            # paddlepaddle

68 69 70 71
    """
    if obj is None:
        return obj

M
minqiyang 已提交
72
    if isinstance(obj, list):
73 74
        if inplace:
            for i in six.moves.xrange(len(obj)):
M
minqiyang 已提交
75
                obj[i] = _to_text(obj[i], encoding)
76 77
            return obj
        else:
M
minqiyang 已提交
78
            return [_to_text(item, encoding) for item in obj]
M
minqiyang 已提交
79
    elif isinstance(obj, set):
80 81 82
        if inplace:
            for item in obj:
                obj.remove(item)
M
minqiyang 已提交
83
                obj.add(_to_text(item, encoding))
84 85
            return obj
        else:
M
minqiyang 已提交
86
            return set([_to_text(item, encoding) for item in obj])
87 88 89 90 91 92 93 94 95 96 97 98
    elif isinstance(obj, dict):
        if inplace:
            new_obj = {}
            for key, value in six.iteritems(obj):
                new_obj[_to_text(key, encoding)] = _to_text(value, encoding)
            obj.update(new_obj)
            return obj
        else:
            new_obj = {}
            for key, value in six.iteritems(obj):
                new_obj[_to_text(key, encoding)] = _to_text(value, encoding)
            return new_obj
M
minqiyang 已提交
99
    else:
M
minqiyang 已提交
100
        return _to_text(obj, encoding)
M
minqiyang 已提交
101 102


M
minqiyang 已提交
103
def _to_text(obj, encoding):
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    """
    In Python3:
        Decode the bytes type object to str type with specific encoding

    In Python2:
        Decode the str type object to unicode type with specific encoding,
        or we just return the unicode string of object

    Args:
        obj(unicode|str|bytes) : The object to be decoded.
        encoding(str) : The encoding format

    Returns:
        decoded result of obj
    """
    if obj is None:
        return obj

M
minqiyang 已提交
122
    if isinstance(obj, six.binary_type):
M
minqiyang 已提交
123
        return obj.decode(encoding)
M
minqiyang 已提交
124 125
    elif isinstance(obj, six.text_type):
        return obj
126 127
    elif isinstance(obj, (bool, float)):
        return obj
M
minqiyang 已提交
128 129 130 131
    else:
        return six.u(obj)


132 133
def to_bytes(obj, encoding='utf-8', inplace=False):
    """
C
Chen Long 已提交
134 135
    All string in PaddlePaddle should be represented as a literal string.
    
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    This function will convert object to a bytes with specific encoding.
    Especially, if the object type is a list or set container, we will iterate
    all items in the object and convert them to bytes.

    In Python3:
        Encode the str type object to bytes type with specific encoding

    In Python2:
        Encode the unicode type object to str type with specific encoding,
        or we just return the 8-bit string of object

    Args:
        obj(unicode|str|bytes|list|set) : The object to be encoded.
        encoding(str) : The encoding format to encode a string
        inplace(bool) : If we change the original object or we create a new one

    Returns:
        Decoded result of obj
C
Chen Long 已提交
154 155 156 157 158 159 160 161 162 163 164
    
    Examples:

        .. code-block:: python

            import paddle

            data = "paddlepaddle"
            data = paddle.compat.to_bytes(data)
            # b'paddlepaddle'

165 166 167 168
    """
    if obj is None:
        return obj

M
minqiyang 已提交
169
    if isinstance(obj, list):
170 171 172 173 174 175
        if inplace:
            for i in six.moves.xrange(len(obj)):
                obj[i] = _to_bytes(obj[i], encoding)
            return obj
        else:
            return [_to_bytes(item, encoding) for item in obj]
M
minqiyang 已提交
176
    elif isinstance(obj, set):
177 178 179 180 181 182 183
        if inplace:
            for item in obj:
                obj.remove(item)
                obj.add(_to_bytes(item, encoding))
            return obj
        else:
            return set([_to_bytes(item, encoding) for item in obj])
M
minqiyang 已提交
184
    else:
M
minqiyang 已提交
185
        return _to_bytes(obj, encoding)
M
minqiyang 已提交
186 187


M
minqiyang 已提交
188
def _to_bytes(obj, encoding):
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    """
    In Python3:
        Encode the str type object to bytes type with specific encoding

    In Python2:
        Encode the unicode type object to str type with specific encoding,
        or we just return the 8-bit string of object

    Args:
        obj(unicode|str|bytes) : The object to be encoded.
        encoding(str) : The encoding format

    Returns:
        encoded result of obj
    """
    if obj is None:
        return obj

    assert encoding is not None
M
minqiyang 已提交
208
    if isinstance(obj, six.text_type):
M
minqiyang 已提交
209
        return obj.encode(encoding)
M
minqiyang 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
    elif isinstance(obj, six.binary_type):
        return obj
    else:
        return six.b(obj)


# math related functions
def round(x, d=0):
    """
    Compatible round which act the same behaviour in Python3.

    Args:
        x(float) : The number to round halfway.

    Returns:
        round result of x
    """
227 228
    if six.PY3:
        # The official walkaround of round in Python3 is incorrect
T
tianshuo78520a 已提交
229
        # we implement according this answer: https://www.techforgeek.info/round_python.html
230
        if x > 0.0:
M
minqiyang 已提交
231
            p = 10**d
232
            return float(math.floor((x * p) + math.copysign(0.5, x))) / p
M
minqiyang 已提交
233
        elif x < 0.0:
M
minqiyang 已提交
234
            p = 10**d
235
            return float(math.ceil((x * p) + math.copysign(0.5, x))) / p
M
minqiyang 已提交
236 237
        else:
            return math.copysign(0.0, x)
238 239 240
    else:
        import __builtin__
        return __builtin__.round(x, d)
M
minqiyang 已提交
241 242 243


def floor_division(x, y):
244 245 246 247 248 249 250 251 252 253 254 255
    """
    Compatible division which act the same behaviour in Python3 and Python2,
    whose result will be a int value of floor(x / y) in Python3 and value of
    (x / y) in Python2.

    Args:
        x(int|float) : The number to divide.
        y(int|float) : The number to be divided

    Returns:
        division result of x // y
    """
M
minqiyang 已提交
256
    return x // y
M
minqiyang 已提交
257

M
minqiyang 已提交
258

M
minqiyang 已提交
259 260
# exception related functions
def get_exception_message(exc):
261 262 263 264 265 266 267 268 269 270 271
    """
    Get the error message of a specific exception

    Args:
        exec(Exception) : The exception to get error message.

    Returns:
        the error message of exec
    """
    assert exc is not None

M
minqiyang 已提交
272 273 274 275
    if six.PY2:
        return exc.message
    else:
        return str(exc)