From bcf9a74da4661de8eb8369852715023a6405581c Mon Sep 17 00:00:00 2001 From: Maxime Liquet <35924738+maximlt@users.noreply.github.com> Date: Fri, 21 Jul 2023 15:33:14 +0200 Subject: [PATCH] Fix `param.pprint` for `Array` parameters by replacing `all_equal` with `Comparator.is_equal` in `values()` (#795) Co-authored-by: James A. Bednar --- param/_utils.py | 5 +++++ param/parameterized.py | 19 +++++++++++++++---- tests/testdeprecations.py | 3 +++ tests/testnumpy.py | 7 +++++++ tests/testparameterizedobject.py | 8 ++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/param/_utils.py b/param/_utils.py index 53e38513e..8e2fa04e2 100644 --- a/param/_utils.py +++ b/param/_utils.py @@ -1,5 +1,6 @@ import inspect import functools +import re import warnings from textwrap import dedent @@ -109,3 +110,7 @@ def wrapper(self, *args, **kwargs): return wrapper return decorating_function + + +def _is_auto_name(class_name, instance_name): + return re.match('^'+class_name+'[0-9]{5}$', instance_name) diff --git a/param/parameterized.py b/param/parameterized.py index d79fbf319..6c72ede4c 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -37,6 +37,7 @@ from ._utils import ( _deprecated, _deprecate_positional_args, + _is_auto_name, _recursive_repr, ParamDeprecationWarning as _ParamDeprecationWarning, ) @@ -286,6 +287,8 @@ def get_occupied_slots(instance): if hasattr(instance,slot)] +# PARAM3_DEPRECATION +@_deprecated() def all_equal(arg1,arg2): """ Return a single boolean for arg1==arg2, even for numpy arrays @@ -1615,15 +1618,21 @@ class Comparator: str: operator.eq, bytes: operator.eq, type(None): operator.eq, + lambda o: hasattr(o, '_infinitely_iterable'): operator.eq, # Time } equalities.update({dtt: operator.eq for dtt in dt_types}) @classmethod def is_equal(cls, obj1, obj2): for eq_type, eq in cls.equalities.items(): - if ((isinstance(eq_type, FunctionType) - and eq_type(obj1) and eq_type(obj2)) - or (isinstance(obj1, eq_type) and isinstance(obj2, eq_type))): + try: + are_instances = isinstance(obj1, eq_type) and isinstance(obj2, eq_type) + except TypeError: + pass + else: + if are_instances: + return eq(obj1, obj2) + if isinstance(eq_type, FunctionType) and eq_type(obj1) and eq_type(obj2): return eq(obj1, obj2) if isinstance(obj2, (list, set, tuple)): return cls.compare_iterator(obj1, obj2) @@ -2408,7 +2417,9 @@ def values(self_, onlychanged=False): vals = [] for name, val in self_or_cls.param.objects('existing').items(): value = self_or_cls.param.get_value_generator(name) - if not onlychanged or not all_equal(value, val.default): + if name == 'name' and onlychanged and _is_auto_name(self_.cls.__name__, value): + continue + if not onlychanged or not Comparator.is_equal(value, val.default): vals.append((name, value)) vals.sort(key=itemgetter(0)) diff --git a/tests/testdeprecations.py b/tests/testdeprecations.py index 28436ecfd..acb6cacde 100644 --- a/tests/testdeprecations.py +++ b/tests/testdeprecations.py @@ -98,6 +98,9 @@ def test_deprecate_recursive_repr(self): with pytest.raises(param._utils.ParamDeprecationWarning): param.parameterized.recursive_repr(lambda: '') + def test_deprecate_all_equal(self): + with pytest.raises(param._utils.ParamDeprecationWarning): + param.parameterized.all_equal(1, 1) class TestDeprecateParameters: diff --git a/tests/testnumpy.py b/tests/testnumpy.py index cd8a0b919..6a9bc8033 100644 --- a/tests/testnumpy.py +++ b/tests/testnumpy.py @@ -73,3 +73,10 @@ class Z(param.Parameterized): z = Z(z=numpy.array([1,2])) _is_array_and_equal(z.z,[1,2]) + + def test_array_pprint(self): + class MatParam(param.Parameterized): + mat = param.Array(numpy.zeros((2, 2))) + + mp = MatParam() + mp.param.pprint() diff --git a/tests/testparameterizedobject.py b/tests/testparameterizedobject.py index 6db231f5e..647ba95fc 100644 --- a/tests/testparameterizedobject.py +++ b/tests/testparameterizedobject.py @@ -391,6 +391,14 @@ def test_values(self): assert 'inst' in TestPO.param.values() assert 'notinst' in TestPO.param.values() + def test_values_name_ignored_for_instances_and_onlychanged(self): + default_inst = param.Parameterized() + assert 'Parameterized' in default_inst.name + # name ignored when automatically computed (behavior inherited from all_equal) + assert 'name' not in default_inst.param.values(onlychanged=True) + # name not ignored when set + assert param.Parameterized(name='foo').param.values(onlychanged=True)['name'] == 'foo' + def test_param_iterator(self): self.assertEqual(set(TestPO.param), {'name', 'inst', 'notinst', 'const', 'dyn', 'ro', 'ro2', 'ro_label', 'ro_format'})