From 91e353bd07bb183009407afe37a8d06f421cec0e Mon Sep 17 00:00:00 2001 From: lanxianghit <47554610+lanxianghit@users.noreply.github.com> Date: Sat, 12 Oct 2019 23:29:34 +0800 Subject: [PATCH] [Cherry-pick #20263] to Add API 'fluid.requird_version(min_version, max_version=None)' to check if the installed PaddlePaddle version is satisfied please see #20263 for details --- paddle/fluid/API.spec | 1 + python/paddle/fluid/framework.py | 110 ++++++++++++++ .../tests/unittests/test_require_version.py | 141 ++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 python/paddle/fluid/tests/unittests/test_require_version.py diff --git a/paddle/fluid/API.spec b/paddle/fluid/API.spec index d0738633780..d9082617a41 100644 --- a/paddle/fluid/API.spec +++ b/paddle/fluid/API.spec @@ -27,6 +27,7 @@ paddle.fluid.Variable.numpy (ArgSpec(args=['self'], varargs=None, keywords=None, paddle.fluid.Variable.set_value (ArgSpec(args=['self', 'value'], varargs=None, keywords=None, defaults=None), ('document', '69deb77a9dedc61f7b731a6a7709fa5b')) paddle.fluid.Variable.to_string (ArgSpec(args=['self', 'throw_on_error', 'with_details'], varargs=None, keywords=None, defaults=(False,)), ('document', '65cd237e2d30c12e412c9cafbbd00791')) paddle.fluid.load_op_library (ArgSpec(args=['lib_filename'], varargs=None, keywords=None, defaults=None), ('document', 'c009b2ea5fb6520f2d2f53aafec788e0')) +paddle.fluid.require_version (ArgSpec(args=['min_version', 'max_version'], varargs=None, keywords=None, defaults=(None,)), ('document', '5d8f572d72b582afc085bf307284be93')) paddle.fluid.Executor ('paddle.fluid.executor.Executor', ('document', '4d963107d87438b5add4a5288855bd04')) paddle.fluid.Executor.__init__ (ArgSpec(args=['self', 'place'], varargs=None, keywords=None, defaults=None), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) paddle.fluid.Executor.close (ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None), ('document', '90b3268b71a8aceedd0dc9e311921d15')) diff --git a/python/paddle/fluid/framework.py b/python/paddle/fluid/framework.py index 74452c97d44..740e86856ad 100644 --- a/python/paddle/fluid/framework.py +++ b/python/paddle/fluid/framework.py @@ -34,6 +34,8 @@ from .proto import framework_pb2 from . import core from . import unique_name +import paddle.version as fluid_version +import warnings __all__ = [ 'Program', @@ -48,6 +50,7 @@ __all__ = [ 'is_compiled_with_cuda', 'Variable', 'load_op_library', + 'require_version', ] EMPTY_VAR_NAME = core.kEmptyVarName() @@ -60,6 +63,113 @@ _dygraph_tracer_ = None _dygraph_current_expected_place_ = None +def require_version(min_version, max_version=None): + """ + Check if the installed version of PaddlePaddle is in [min_version, max_version], + if the installed version is lower than ``min_version`` or higher than ``max_version``, + an exception will be thrown, NO returns if the installed version is satisfied. + + Args: + min_version (str): the minimum version required (like '1.4.0'). + max_version (str, optional): the max version required (like '1.6.0'), default is None, + meaning any version equal or higher than ``min_version`` is acceptable. + + Returns: + None. + + Raises: + TypeError: if the type of ``min_version`` is not str. + TypeError: if the type of ``max_version`` is not str or type(None). + ValueError: if the value of ``min_version`` is not in version format. + ValueError: if the value of ``max_version`` is not in version format or None. + Exception: if the installed version is lower than ``min_version`` or higher than ``max_version``. + + Examples: + .. code-block:: python + + import paddle.fluid as fluid + + # any version >= 0.1.0 is acceptable. + fluid.require_version('0.1.0') + + # if 0.1.0 <= version <= 10.0.0, it is acceptable. + fluid.require_version(min_version='0.1.0', max_version='10.0.0') + """ + if not isinstance(min_version, str): + raise TypeError( + "The type of 'min_version' in require_version must be str, but received %s." + % (type(min_version))) + + if not isinstance(max_version, (str, type(None))): + raise TypeError( + "The type of 'max_version' in require_version must be str or type(None), but received %s." + % (type(max_version))) + + check_format = re.match(r'\d+(\.\d+){0,3}', min_version) + if check_format is None or check_format.group() != min_version: + raise ValueError( + "The value of 'min_version' in require_version must be in format '\\d+(\\.\\d+){0,3}', " + "like '1.5.2.0', but received %s" % min_version) + + if max_version is not None: + check_format = re.match(r'\d+(\.\d+){0,3}', max_version) + if check_format is None or check_format.group() != max_version: + raise ValueError( + "The value of 'max_version' in require_version must be in format '\\d+(\\.\\d+){0,3}', " + "like '1.5.2.0', but received %s" % max_version) + + version_installed = [ + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc + ] + zero_version = ['0', '0', '0', '0'] + + def version_cmp(ver_a, ver_b): + for i in six.moves.range(len(ver_a)): + if int(ver_a[i]) > int(ver_b[i]): + return 1 + elif int(ver_a[i]) < int(ver_b[i]): + return -1 + return 0 + + if version_cmp(version_installed, zero_version) == 0: + if max_version is not None: + warnings.warn( + "PaddlePaddle version in [%s, %s] required, but %s installed. " + "Maybe you are using a develop version, " + "please make sure the version is good with your code." % + (min_version, max_version, fluid_version.full_version)) + else: + warnings.warn( + "PaddlePaddle version %s or higher is required, but %s installed, " + "Maybe you are using a develop version, " + "please make sure the version is good with your code." % + (min_version, fluid_version.full_version)) + return + + min_version_split = min_version.split('.') + min_version_to_check = min_version_split + zero_version[len( + min_version_split):] + + if max_version is not None: + max_version_split = max_version.split('.') + max_version_to_check = max_version_split + zero_version[len( + max_version_split):] + + if version_cmp(version_installed, + max_version_to_check) > 0 or version_cmp( + version_installed, min_version_to_check) < 0: + raise Exception( + "VersionError: PaddlePaddle version in [%s, %s] required, but %s installed." + % (min_version, max_version, fluid_version.full_version)) + else: + if version_cmp(version_installed, min_version_to_check) < 0: + raise Exception( + "VersionError: PaddlePaddle version %s or higher is required, but %s installed, " + "please upgrade your PaddlePaddle to %s or other higher version." + % (min_version, fluid_version.full_version, min_version)) + + def in_dygraph_mode(): """ This function checks whether the program runs in dynamic graph mode or not. diff --git a/python/paddle/fluid/tests/unittests/test_require_version.py b/python/paddle/fluid/tests/unittests/test_require_version.py new file mode 100644 index 00000000000..80d595c1ef1 --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_require_version.py @@ -0,0 +1,141 @@ +# Copyright (c) 2019 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 unittest +import paddle.fluid as fluid +import paddle.version as fluid_version +import warnings +import paddle + + +class VersionTest(unittest.TestCase): + def test_check_output(self): + warnings.warn( + "paddle.__version__: %s, fluid_version.full_version: %s, fluid_version.major: %s, fluid_version.minor: %s, fluid_version.patch: %s, fluid_version.rc: %s." + % (paddle.__version__, fluid_version.full_version, + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc)) + ori_full_version = fluid_version.full_version + ori_sep_version = [ + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc + ] + [ + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc + ] = ['1', '4', '1', '0'] + + fluid.require_version('1') + fluid.require_version('1.4') + fluid.require_version('1.4.1.0') + + # any version >= 1.4.1 is acceptable. + fluid.require_version('1.4.1') + + # if 1.4.1 <= version <= 1.6.0, it is acceptable. + fluid.require_version(min_version='1.4.1', max_version='1.6.0') + + # only version 1.4.1 is acceptable. + fluid.require_version(min_version='1.4.1', max_version='1.4.1') + + # if installed version is 0.0.0.0, throw warning and skip the checking. + [ + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc + ] = ['0', '0', '0', '0'] + fluid.require_version('0.0.0') + + fluid_version.full_version = ori_full_version + [ + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc + ] = ori_sep_version + + +# Test Errors +class TestErrors(unittest.TestCase): + def test_errors(self): + # The type of params must be str. + def test_input_type(): + fluid.require_version(100) + + self.assertRaises(TypeError, test_input_type) + + def test_input_type_1(): + fluid.require_version('0', 200) + + self.assertRaises(TypeError, test_input_type_1) + + # The value of params must be in format '\d+(\.\d+){0,3}', like '1.5.2.0', '1.6' ... + def test_input_value_1(): + fluid.require_version('string') + + self.assertRaises(ValueError, test_input_value_1) + + def test_input_value_1_1(): + fluid.require_version('1.5', 'string') + + self.assertRaises(ValueError, test_input_value_1_1) + + def test_input_value_2(): + fluid.require_version('1.5.2.0.0') + + self.assertRaises(ValueError, test_input_value_2) + + def test_input_value_2_1(): + fluid.require_version('1.5', '1.5.2.0.0') + + self.assertRaises(ValueError, test_input_value_2_1) + + def test_input_value_3(): + fluid.require_version('1.5.2a.0') + + self.assertRaises(ValueError, test_input_value_3) + + # The installed version must be equal or greater than the required version. + def test_version(): + fluid.require_version('100') + + # The installed version must be in [min_version, max_version] + def test_version_1(): + fluid.require_version('0.0.0', '1.4') + + def test_version_2(): + fluid.require_version('1.4.0', '1.2') + + ori_full_version = fluid_version.full_version + ori_sep_version = [ + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc + ] + [ + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc + ] = ['1', '4', '1', '0'] + + self.assertRaises(Exception, test_version) + self.assertRaises(Exception, test_version_1) + self.assertRaises(Exception, test_version_2) + + fluid_version.full_version = ori_full_version + [ + fluid_version.major, fluid_version.minor, fluid_version.patch, + fluid_version.rc + ] = ori_sep_version + + +if __name__ == "__main__": + unittest.main() -- GitLab