diff --git a/python/paddle/fluid/layers/nn.py b/python/paddle/fluid/layers/nn.py index e77f58d31f7c49ebb315523e6a071136090dece2..a264f9a70fe7aa97f2b45797557677e00c45a1f1 100755 --- a/python/paddle/fluid/layers/nn.py +++ b/python/paddle/fluid/layers/nn.py @@ -12031,6 +12031,8 @@ for func in [ elementwise_floordiv, ]: op_proto = OpProtoHolder.instance().get_op_proto(func.__name__) + + # insert the c++ doc string on top of python doc string func.__doc__ = _generate_doc_string_( op_proto, additional_args_lines=[ @@ -12048,6 +12050,16 @@ for func in [ "mkldnn_data_type", "Scale_x", "Scale_y", "Scale_out" }) + """\n""" + str(func.__doc__) + doc_list = func.__doc__.splitlines() + + for idx, val in enumerate(doc_list): + if val.startswith("Warning: ") and val.endswith( + " instead." + ) and "and will be removed in future versions." in val: + doc_list.insert(0, doc_list.pop(idx)) + func.__doc__ = "\n" + "\n".join(i for i in doc_list) + break + for func in []: op_proto = OpProtoHolder.instance().get_op_proto(func.__name__) func.__doc__ = _generate_doc_string_( diff --git a/python/paddle/fluid/tests/unittests/test_deprecated_decorator.py b/python/paddle/fluid/tests/unittests/test_deprecated_decorator.py new file mode 100755 index 0000000000000000000000000000000000000000..2a80e20d692c88497e7edccd6eca5509e3522871 --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_deprecated_decorator.py @@ -0,0 +1,152 @@ +# Copyright (c) 2020 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. + +from __future__ import print_function +import paddle +import numpy as np +import paddle +import paddle.fluid as fluid +from paddle.static import Program, program_guard +import unittest +import paddle.fluid.core as core +import sys + +LOWEST_WARNING_POSTION = 3 +ERROR_WARNING_POSTION = sys.maxsize + +# custom paddle version +paddle.version.major = '1' +paddle.version.minor = '8' +paddle.version.patch = '0' +paddle.version.rc = '0' +paddle.__version__ = '1.8.0' +paddle.version.full_version = '1.8.0' +print("current paddle version: ", paddle.__version__) + +paddle.disable_static() + + +def get_warning_index(api): + """ + Given an paddle API, return the index of the Warinng information in its doc string if exists; + If Warinng information doesn't exist, return the default ERROR_WARNING_POSTION, sys.maxsize. + + Args: + API (python object) + + Returns: + index (int): the index of the Warinng information in its doc string if exists. + """ + + doc_lst = api.__doc__.splitlines() + for idx, val in enumerate(doc_lst): + if val.startswith("Warning: ") and val.endswith( + " instead." + ) and "and will be removed in future versions." in val: + return idx + return ERROR_WARNING_POSTION + + +class TestDeprecatedDocorator(unittest.TestCase): + """ + tests for paddle's Deprecated Docorator. + test_fluid_data: test for old fluid.data API. + test_fluid_elementwise_mul: test for old fluid.layers.elementwise_xxx APIs. + test_new_multiply: test for new api, which should not insert warning information. + test_ops_elementwise_mul: test for C++ elementwise_mul op, which should not insert warning information. + """ + + def test_fluid_data(self): + """ + test old fluid elementwise_mul api, it should fire Warinng function, + which insert the Warinng info on top of API's doc string. + """ + # Initialization + x = fluid.data(name='x', shape=[3, 2, 1], dtype='float32') + + # expected + expected = LOWEST_WARNING_POSTION + + # captured + captured = get_warning_index(fluid.data) + + # testting + self.assertGreater(expected, captured) + + def test_fluid_elementwise_mul(self): + """ + test old fluid elementwise_mul api, it should trigger Warinng function, + which insert the Warinng info on top of API's doc string. + """ + + # Initialization + a = np.random.uniform(0.1, 1, [51, 76]).astype(np.float32) + b = np.random.uniform(0.1, 1, [51, 76]).astype(np.float32) + x = paddle.to_tensor(a) + y = paddle.to_tensor(b) + res = fluid.layers.elementwise_mul(x, y) + + # expected + expected = LOWEST_WARNING_POSTION + + # captured + captured = get_warning_index(fluid.layers.elementwise_mul) + + # testting + self.assertGreater(expected, captured) + + def test_new_multiply(self): + """ + Test for new multiply api, expected result should be False. + """ + + a = np.random.uniform(0.1, 1, [51, 76]).astype(np.float32) + b = np.random.uniform(0.1, 1, [51, 76]).astype(np.float32) + x = paddle.to_tensor(a) + y = paddle.to_tensor(b) + res = paddle.multiply(x, y) + + # expected + expected = LOWEST_WARNING_POSTION + + # captured + captured = get_warning_index(paddle.multiply) + + # testting + self.assertLess(expected, captured) + + def test_ops_elementwise_mul(self): + """ + Test for new C++ elementwise_op, expected result should be True, + because not matter what fluid.layers.elementwise_mul is deprecated. + """ + + a = np.random.uniform(0.1, 1, [51, 76]).astype(np.float32) + b = np.random.uniform(0.1, 1, [51, 76]).astype(np.float32) + x = paddle.to_tensor(a) + y = paddle.to_tensor(b) + res = core.ops.elementwise_mul(x, y) + + # expected + expected = LOWEST_WARNING_POSTION + + # captured + captured = get_warning_index(fluid.layers.elementwise_mul) + + # testting + self.assertGreater(expected, captured) + + +if __name__ == '__main__': + unittest.main() diff --git a/python/paddle/utils/deprecated.py b/python/paddle/utils/deprecated.py index 08fd7e33479b331454f63f05f6240dd221591ee9..d4e21748b55326468edb2ba1e46114e8d66c0046 100644 --- a/python/paddle/utils/deprecated.py +++ b/python/paddle/utils/deprecated.py @@ -45,7 +45,7 @@ def deprecated(update_to="", since="", reason=""): def decorator(func): # TODO(zhiqiu): We temporally disable the warnings for 2.0-bata, and it should be re-enabled in the future. - return func + # return func """construct warning message, and return a decorated function or class.""" assert isinstance(update_to, str), 'type of "update_to" must be str.' assert isinstance(since, str), 'type of "since" must be str.' @@ -56,9 +56,10 @@ def deprecated(update_to="", since="", reason=""): _reason = reason.strip() msg = 'API "{}.{}" is deprecated'.format(func.__module__, func.__name__) + if len(_since) > 0: msg += " since {}".format(_since) - msg += ", and may be removed in future versions." + msg += ", and will be removed in future versions." if len(_update_to) > 0: assert _update_to.startswith( "paddle." @@ -67,6 +68,11 @@ def deprecated(update_to="", since="", reason=""): msg += ' Please use "{}" instead.'.format(_update_to) if len(_reason) > 0: msg += "\n reason: {}".format(_reason) + if func.__doc__: + func.__doc__ = ('\n\nWarning: ' + msg + '\n') + func.__doc__ + # TODO(Joejiong) Early returning the wrapper function, currently we disable the warning wrapper, + # because the 2.0beta APIs are still under development, we will restore the warning functionality when 2.0 rc APIs become stable. + return func @functools.wraps(func) def wrapper(*args, **kwargs): @@ -75,6 +81,7 @@ def deprecated(update_to="", since="", reason=""): 2. since version is empty, in this case, API is deprecated in all versions. 3. current version is newer than since version. """ + msg = "\033[93mWarning %s \033[0m" % (msg) v_current = [int(i) for i in paddle.__version__.split(".")] v_current += [0] * (4 - len(v_current)) v_since = [int(i) for i in _since.split(".")]