From f9faae2038627aa846dd6e0cd8e6d4196ad5af5e Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Wed, 13 Nov 2024 04:09:07 +0000 Subject: [PATCH 01/20] improved docs --- .gitignore | 1 + param/parameterized.py | 38 ++++++++++++++++++++++++++++++++++++++ param/reactive.py | 39 +++++++++++++++++++++++++++++++++++---- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index fc5adc44..88d3bb41 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ benchmarks/param # pixi .pixi pixi.lock +script.* diff --git a/param/parameterized.py b/param/parameterized.py index 2576659d..f49a205b 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1320,6 +1320,44 @@ def schema(self, safe=False, subset=None, mode='json'): @property def rx(self): + """The reactive namespace. + + Provides reactive versions of the operations that cannot be made reactive through overloading, such as + `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. + + Reference: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + + Examples: + + Turn your parameter into a reactive expression: + + ```python + import param + + class MyClass(param.Parameterized): + value = param.Parameter() + + my_instance = MyClass(value=0) + ``` + + Get the current value: + + ```python + a = my_instance.rx.value + ``` + + Set the current value: + + ```python + my_instance.rx.value = 1 + ``` + + Call it to get a reactive expression: + + ```python + rx_value = my_instance.rx() + ``` + """ from .reactive import reactive_ops return reactive_ops(self) diff --git a/param/reactive.py b/param/reactive.py index 00e9c06e..296474f3 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -180,11 +180,42 @@ class NestedResolver(Resolver): class reactive_ops: - """ - Namespace for reactive operators. + """The reactive namespace. + + Provides reactive versions of the operations that cannot be made reactive through overloading, such as + `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. + + Reference: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + + Examples: + + Turn your parameter into a reactive expression: + + ```python + import param + + class MyClass(param.Parameterized): + value = param.Parameter() + + my_instance = MyClass(value=0) + ``` + + Get the current value: + + ```python + a = my_instance.rx.value + ``` + + Set the current value: + + ```python + my_instance.rx.value = 1 + ``` + + Call it to get a reactive expression: - Implements operators that cannot be implemented using regular - Python syntax. + ```python + rx_value = my_instance.rx() """ def __init__(self, reactive): From 563ea82ba0001286fd0c83f47fdd6f80f859025e Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Wed, 13 Nov 2024 04:12:53 +0000 Subject: [PATCH 02/20] pre-commit --- param/parameterized.py | 2 +- param/reactive.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index f49a205b..fb700d95 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1321,7 +1321,7 @@ def schema(self, safe=False, subset=None, mode='json'): @property def rx(self): """The reactive namespace. - + Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. diff --git a/param/reactive.py b/param/reactive.py index 296474f3..eae8cbef 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -181,7 +181,7 @@ class NestedResolver(Resolver): class reactive_ops: """The reactive namespace. - + Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. From c5f6167eb1318384c4ac9a3424d967da4ad25648 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Wed, 13 Nov 2024 04:42:45 +0000 Subject: [PATCH 03/20] document .param namespace --- param/parameterized.py | 31 +++++++++++++++++++++++++++++ param/reactive.py | 45 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/param/parameterized.py b/param/parameterized.py index fb700d95..26c18cc9 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -4244,6 +4244,37 @@ def __init__(self, **params): @property def param(self): + """ + The `.param` namespace for Parameterized classes and instances. + + This namespace provides access to powerful methods and properties for managing parameters in a `Parameterized` object. + It includes utilities for adding parameters, updating parameters, debugging, serialization, logging, and more. + + Reference: https://param.holoviz.org/user_guide/Parameters.html#parameter-objects-and-instances + + Example: + + ```python + import param + + class MyClass(param.Parameterized): + value = param.Parameter() + + my_instance = MyClass(value=0) + ``` + + Access the `value` parameter of `my_instance`: + + ```python + my_instance.param.value # the Parameter instance + ``` + + Note this is different from the current `value` of `my_instance`: + + ```python + my_instance.value # 0, the current parameter value + ``` + """ return Parameters(self.__class__, self=self) #PARAM3_DEPRECATION diff --git a/param/reactive.py b/param/reactive.py index eae8cbef..bb4e0443 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -225,6 +225,7 @@ def _as_rx(self): return self._reactive if isinstance(self._reactive, rx) else self() def __call__(self): + """Creates a reactive expression.""" rxi = self._reactive return rxi if isinstance(rx, rx) else rx(rxi) @@ -786,7 +787,7 @@ def __init__( ] self._setup_invalidations(depth) self._kwargs = kwargs - self.rx = reactive_ops(self) + self._rx = reactive_ops(self) self._init = True for name, accessor in _display_accessors.items(): setattr(self, name, accessor(self)) @@ -794,6 +795,48 @@ def __init__( if predicate is None or predicate(self._current): setattr(self, name, accessor(self)) + @property + def rx(self): + """The reactive namespace. + + Provides reactive versions of the operations that cannot be made reactive through overloading, such as + `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. + + Reference: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + + Examples: + + Turn your parameter into a reactive expression: + + ```python + import param + + class MyClass(param.Parameterized): + value = param.Parameter() + + my_instance = MyClass(value=0) + ``` + + Get the current value: + + ```python + a = my_instance.rx.value + ``` + + Set the current value: + + ```python + my_instance.rx.value = 1 + ``` + + Call it to get a reactive expression: + + ```python + rx_value = my_instance.rx() + ``` + """ + return self._rx + @property def _obj(self): if self._shared_obj is None: From ed229c32e12b63756c4988638555510bc414fc77 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Wed, 13 Nov 2024 06:26:22 +0000 Subject: [PATCH 04/20] fix --- param/parameterized.py | 157 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 8 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 26c18cc9..c2a03604 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -2298,12 +2298,50 @@ def set_default(self_,param_name,value): cls = self_.cls setattr(cls,param_name,value) - def add_parameter(self_, param_name, param_obj): + def add_parameter(self_, param_name: str, param_obj: Parameter): """ Add a new Parameter object into this object's class. Should result in a Parameter equivalent to one declared in the class's source code. + + Parameters + ---------- + param_name : str + The name of the parameter to add. + param_obj : Parameter + The Parameter object to add. + + Example + ------- + + ```python + import param + + + class P(param.Parameterized): + a = param.Number() + b = param.String() + + + p = P() + ``` + + Add a new parameter to the class via the class: + + ```python + P.param.add_parameter('c', param.Tuple(default=(1,2,3))) + print(p.c) + # (1, 2, 3) + ``` + + Add a new parameter to the class via the instance: + + ```python + p.param.add_parameter('d', param.Tuple(default=(3,2,1))) + print(p.d) + # (3, 2, 1) + ``` """ # Could have just done setattr(cls,param_name,param_obj), # which is supported by the metaclass's __setattr__ , but @@ -2347,12 +2385,46 @@ def params(self_, parameter_name=None): def update(self_, arg=Undefined, /, **kwargs): """ - For the given dictionary or iterable or set of param=value - keyword arguments, sets the corresponding parameter of this - object or class to the given value. + Updates one or more parameters of this object or class. + + This method allows you to set the parameters of the object or class using a dictionary, + an iterable, or keyword arguments in the form of param=value. The specified parameters + will be updated to the given values. + + This method can also be used as a context manager to temporarily set and then reset + parameter values. + + Reference: https://param.holoviz.org/user_guide/Parameters.html#other-parameterized-methods + + Examples: + + ```python + import param + + class P(param.Parameterized): + a = param.Number() + b = param.String() + + p = P() + ``` + + Update parameters permanently: + + ```python + p.param.update(a=1, b="Hello") + print(p.a, p.b) + # Output: 1 Hello + ``` - May also be used as a context manager to temporarily set and - then reset parameter values. + Update parameters temporarily: + + ```python + with p.param.update(a=2, b="World"): + print(p.a, p.b) + # Output: 2 World + print(p.a, p.b) + # Output: 1 Hello + ``` """ refs = {} if self_.self is not None: @@ -2635,7 +2707,45 @@ class or instance that contains an iterable collection of for obj in sublist: obj.param.set_dynamic_time_fn(time_fn,sublistattr) - def serialize_parameters(self_, subset=None, mode='json'): + def serialize_parameters(self_, subset=None, mode='json')->str: + """Returns the serialized parameters of the Parameterized object. + + Parameters + ---------- + subset (list, optional): + A list of parameter names to serialize. If None, all parameters will be serialized. Defaults to None. + mode (str, optional): + The serialization format. By default, only 'json' is supported. Defaults to 'json'. + + Raises: + ValueError: If the `mode` is not valid. + + Returns + ------- + dict: The serialized string + + Reference + --------- + For more details visit https://param.holoviz.org/user_guide/Serialization_and_Persistence.html#serializing-with-json + + Example + ------- + + ```python + import param + + class P(param.Parameterized): + a = param.Number() + b = param.String() + + + p = P(a=1, b="hello") + + serialized_data = p.param.serialize_parameters() + print(type(serialized_data)) + # {"name": "P00002", "a": 1, "b": "hello"} + ``` + """ self_or_cls = self_.self_or_cls if mode not in Parameter._serializers: raise ValueError(f'Mode {mode!r} not in available serialization formats {list(Parameter._serializers.keys())!r}') @@ -2649,7 +2759,38 @@ def serialize_value(self_, pname, mode='json'): serializer = Parameter._serializers[mode] return serializer.serialize_parameter_value(self_or_cls, pname) - def deserialize_parameters(self_, serialization, subset=None, mode='json'): + def deserialize_parameters(self_, serialization, subset=None, mode='json') -> dict: + """ + Deserialize the given serialized data. You may use the deserialized to create a Parameteried object or + update the parameters of a Parameterized object. + + Parameters: + - serialization (str): The serialized parameter data as a JSON string. + - subset (list, optional): A list of parameter names to deserialize. If None, all parameters will be deserialized. Defaults to None. + - mode (str, optional): The serialization format. By default, only 'json' is supported. Defaults to 'json'. + + Returns: + dict: A dictionary with parameter names as keys and deserialized values. + + Reference: https://param.holoviz.org/user_guide/Serialization_and_Persistence.html#serializing-with-json + + Example: + + ```python + import param + + class P(param.Parameterized): + a = param.Number() + b = param.String() + + serialized_data = '{"a": 1, "b": "hello"}' + deserialized_data = P.param.deserialize_parameters(serialized_data) + print(deserialized_data) + # Output: {'a': 1, 'b': 'hello'} + + instance = P(**deserialized_data) + ``` + """ self_or_cls = self_.self_or_cls serializer = Parameter._serializers[mode] return serializer.deserialize_parameters(self_or_cls, serialization, subset=subset) From 896f94d1a00c0ed0d25395c9fd361bf1fa6abe1e Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Wed, 13 Nov 2024 06:34:16 +0000 Subject: [PATCH 05/20] align rx docstring --- param/reactive.py | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/param/reactive.py b/param/reactive.py index bb4e0443..998daabc 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -180,7 +180,7 @@ class NestedResolver(Resolver): class reactive_ops: - """The reactive namespace. + """The reactive namespace. Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. @@ -189,33 +189,30 @@ class reactive_ops: Examples: - Turn your parameter into a reactive expression: + Lets create a Parameterized instance: ```python import param - class MyClass(param.Parameterized): - value = param.Parameter() + class P(param.Parameterized): + a = param.Number() + b = param.String() - my_instance = MyClass(value=0) - ``` - - Get the current value: - ```python - a = my_instance.rx.value + p = P(a=1, b="hello") ``` - Set the current value: + Get the current value: ```python - my_instance.rx.value = 1 + a = p.param.a.rx.value ``` Call it to get a reactive expression: ```python - rx_value = my_instance.rx() + rx_value = p.param.a.rx() + ``` """ def __init__(self, reactive): @@ -806,33 +803,29 @@ def rx(self): Examples: - Turn your parameter into a reactive expression: + Lets create a Parameterized instance: ```python import param - class MyClass(param.Parameterized): - value = param.Parameter() + class P(param.Parameterized): + a = param.Number() + b = param.String() - my_instance = MyClass(value=0) - ``` - - Get the current value: - ```python - a = my_instance.rx.value + p = P(a=1, b="hello") ``` - Set the current value: + Get the current value: ```python - my_instance.rx.value = 1 + a = p.param.a.rx.value ``` Call it to get a reactive expression: ```python - rx_value = my_instance.rx() + rx_value = p.param.a.rx() ``` """ return self._rx From 755496dfff877b183df38b3a2bb4f2653d884497 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Wed, 13 Nov 2024 06:36:51 +0000 Subject: [PATCH 06/20] add type --- param/reactive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/param/reactive.py b/param/reactive.py index 998daabc..a31fa6a5 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -793,7 +793,7 @@ def __init__( setattr(self, name, accessor(self)) @property - def rx(self): + def rx(self) -> reactive_ops: """The reactive namespace. Provides reactive versions of the operations that cannot be made reactive through overloading, such as From b712cc1930cb8062fa0494a86cd206464936ceb4 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Wed, 13 Nov 2024 06:40:23 +0000 Subject: [PATCH 07/20] align rx docstring --- param/parameterized.py | 10 +++++----- param/reactive.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index c2a03604..dd128f0c 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -2386,16 +2386,16 @@ def params(self_, parameter_name=None): def update(self_, arg=Undefined, /, **kwargs): """ Updates one or more parameters of this object or class. - - This method allows you to set the parameters of the object or class using a dictionary, - an iterable, or keyword arguments in the form of param=value. The specified parameters + + This method allows you to set the parameters of the object or class using a dictionary, + an iterable, or keyword arguments in the form of param=value. The specified parameters will be updated to the given values. - This method can also be used as a context manager to temporarily set and then reset + This method can also be used as a context manager to temporarily set and then reset parameter values. Reference: https://param.holoviz.org/user_guide/Parameters.html#other-parameterized-methods - + Examples: ```python diff --git a/param/reactive.py b/param/reactive.py index a31fa6a5..3920ef1b 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -180,7 +180,7 @@ class NestedResolver(Resolver): class reactive_ops: - """The reactive namespace. + """The reactive namespace. Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. From 25733d2d697b040b302cc89449ff63d2ca02856c Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Wed, 13 Nov 2024 06:44:09 +0000 Subject: [PATCH 08/20] align docstrings --- param/parameterized.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index dd128f0c..439fe211 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1329,33 +1329,29 @@ def rx(self): Examples: - Turn your parameter into a reactive expression: + Lets create a Parameterized instance: ```python import param - class MyClass(param.Parameterized): - value = param.Parameter() - - my_instance = MyClass(value=0) - ``` + class P(param.Parameterized): + a = param.Number() + b = param.String() - Get the current value: - ```python - a = my_instance.rx.value + p = P(a=1, b="hello") ``` - Set the current value: + Get the current value: ```python - my_instance.rx.value = 1 + a = p.param.a.rx.value ``` Call it to get a reactive expression: ```python - rx_value = my_instance.rx() + rx_value = p.param.a.rx() ``` """ from .reactive import reactive_ops From 65ae984cbfacb4eca6c03625b05656cfb69ecaf0 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Wed, 13 Nov 2024 14:48:52 +0000 Subject: [PATCH 09/20] fix --- .gitignore | 1 - param/parameterized.py | 3 ++- param/reactive.py | 6 ++++-- tests/testreactive.py | 9 +++++++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 88d3bb41..fc5adc44 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,3 @@ benchmarks/param # pixi .pixi pixi.lock -script.* diff --git a/param/parameterized.py b/param/parameterized.py index 439fe211..190b77b5 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1320,7 +1320,8 @@ def schema(self, safe=False, subset=None, mode='json'): @property def rx(self): - """The reactive namespace. + """ + The reactive namespace. Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. diff --git a/param/reactive.py b/param/reactive.py index 3920ef1b..d593173c 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -180,7 +180,8 @@ class NestedResolver(Resolver): class reactive_ops: - """The reactive namespace. + """ + The reactive namespace. Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. @@ -794,7 +795,8 @@ def __init__( @property def rx(self) -> reactive_ops: - """The reactive namespace. + """ + The reactive namespace. Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. diff --git a/tests/testreactive.py b/tests/testreactive.py index 68e6b9ee..97a4b6ca 100644 --- a/tests/testreactive.py +++ b/tests/testreactive.py @@ -4,6 +4,7 @@ import os import unittest import time +from textwrap import dedent try: import numpy as np @@ -24,8 +25,8 @@ import param import pytest -from param.parameterized import Skip -from param.reactive import bind, rx +from param.parameterized import Skip, Parameter +from param.reactive import bind, rx, reactive_ops from .utils import async_wait_until @@ -767,3 +768,7 @@ def test_reactive_callback_resolve_accessor(): dfx = rx(df) out = dfx["name"].str._callback() assert out is df["name"].str + +def test_docstrings_in_sync(): + assert dedent(reactive_ops.__doc__) == dedent(Parameter.rx.__doc__) + assert dedent(reactive_ops.__doc__) == dedent(rx.rx.__doc__) From 6a7be7033dbd4f45d776dbd3758bc1c58659c2a7 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Wed, 13 Nov 2024 18:39:45 +0100 Subject: [PATCH 10/20] Update tests/testreactive.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Simon Høxbro Hansen --- tests/testreactive.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/testreactive.py b/tests/testreactive.py index 97a4b6ca..a995484a 100644 --- a/tests/testreactive.py +++ b/tests/testreactive.py @@ -770,5 +770,6 @@ def test_reactive_callback_resolve_accessor(): assert out is df["name"].str def test_docstrings_in_sync(): + # The docstring needs to be explicitly written to work with LSP. assert dedent(reactive_ops.__doc__) == dedent(Parameter.rx.__doc__) assert dedent(reactive_ops.__doc__) == dedent(rx.rx.__doc__) From edda46b87429e98d67c346d190d0b32ab73e602c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Wed, 13 Nov 2024 21:29:54 +0100 Subject: [PATCH 11/20] Fix lint --- tests/testreactive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testreactive.py b/tests/testreactive.py index a995484a..afe08a1b 100644 --- a/tests/testreactive.py +++ b/tests/testreactive.py @@ -770,6 +770,6 @@ def test_reactive_callback_resolve_accessor(): assert out is df["name"].str def test_docstrings_in_sync(): - # The docstring needs to be explicitly written to work with LSP. + # The docstring needs to be explicitly written to work with LSP. assert dedent(reactive_ops.__doc__) == dedent(Parameter.rx.__doc__) assert dedent(reactive_ops.__doc__) == dedent(rx.rx.__doc__) From ecbd92b3b5baf9c4235cabc63f2c4ac70c1e1499 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 14 Nov 2024 20:26:07 +0100 Subject: [PATCH 12/20] Update param/parameterized.py Co-authored-by: Maxime Liquet <35924738+maximlt@users.noreply.github.com> --- param/parameterized.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/param/parameterized.py b/param/parameterized.py index 190b77b5..39cc4fe8 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -2393,7 +2393,8 @@ def update(self_, arg=Undefined, /, **kwargs): Reference: https://param.holoviz.org/user_guide/Parameters.html#other-parameterized-methods - Examples: + Examples + -------- ```python import param From 3a17a10f33961b44443dd134e5b8462625af8fc7 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 14 Nov 2024 20:28:11 +0100 Subject: [PATCH 13/20] Update param/parameterized.py Co-authored-by: Maxime Liquet <35924738+maximlt@users.noreply.github.com> --- param/parameterized.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 39cc4fe8..765f01b7 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -2309,8 +2309,8 @@ def add_parameter(self_, param_name: str, param_obj: Parameter): param_obj : Parameter The Parameter object to add. - Example - ------- + Examples + -------- ```python import param From b55ef26876b2ada6a3dd00af01b8ec3cd7ca6408 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 14 Nov 2024 20:28:21 +0100 Subject: [PATCH 14/20] Update param/parameterized.py Co-authored-by: Maxime Liquet <35924738+maximlt@users.noreply.github.com> --- param/parameterized.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/param/parameterized.py b/param/parameterized.py index 765f01b7..a2aecdba 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -2710,7 +2710,7 @@ def serialize_parameters(self_, subset=None, mode='json')->str: Parameters ---------- - subset (list, optional): + subset: list, optional A list of parameter names to serialize. If None, all parameters will be serialized. Defaults to None. mode (str, optional): The serialization format. By default, only 'json' is supported. Defaults to 'json'. From 173ff9c58f1f7804c319781fc432b79822221ca3 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 14 Nov 2024 20:31:28 +0100 Subject: [PATCH 15/20] Update param/reactive.py Co-authored-by: Philipp Rudiger --- param/reactive.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/param/reactive.py b/param/reactive.py index d593173c..3689d614 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -803,7 +803,8 @@ def rx(self) -> reactive_ops: Reference: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx - Examples: + Examples + -------- Lets create a Parameterized instance: From f7c92da93d169e029b24d06caab356cf9f55d316 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Thu, 14 Nov 2024 19:34:08 +0000 Subject: [PATCH 16/20] review feedback --- param/parameterized.py | 110 +++++++++++++++++++++-------------------- param/reactive.py | 4 +- 2 files changed, 59 insertions(+), 55 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 190b77b5..9962b06b 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1326,7 +1326,7 @@ def rx(self): Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. - Reference: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + User Guide: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx Examples: @@ -2391,7 +2391,7 @@ def update(self_, arg=Undefined, /, **kwargs): This method can also be used as a context manager to temporarily set and then reset parameter values. - Reference: https://param.holoviz.org/user_guide/Parameters.html#other-parameterized-methods + User Guide: https://param.holoviz.org/user_guide/Parameters.html#other-parameterized-methods Examples: @@ -2704,7 +2704,7 @@ class or instance that contains an iterable collection of for obj in sublist: obj.param.set_dynamic_time_fn(time_fn,sublistattr) - def serialize_parameters(self_, subset=None, mode='json')->str: + def serialize_parameters(self_, subset=None, mode='json'): """Returns the serialized parameters of the Parameterized object. Parameters @@ -2714,12 +2714,9 @@ def serialize_parameters(self_, subset=None, mode='json')->str: mode (str, optional): The serialization format. By default, only 'json' is supported. Defaults to 'json'. - Raises: - ValueError: If the `mode` is not valid. - Returns ------- - dict: The serialized string + Any: The serialized value Reference --------- @@ -2758,35 +2755,42 @@ def serialize_value(self_, pname, mode='json'): def deserialize_parameters(self_, serialization, subset=None, mode='json') -> dict: """ - Deserialize the given serialized data. You may use the deserialized to create a Parameteried object or - update the parameters of a Parameterized object. - - Parameters: - - serialization (str): The serialized parameter data as a JSON string. - - subset (list, optional): A list of parameter names to deserialize. If None, all parameters will be deserialized. Defaults to None. - - mode (str, optional): The serialization format. By default, only 'json' is supported. Defaults to 'json'. - - Returns: - dict: A dictionary with parameter names as keys and deserialized values. - - Reference: https://param.holoviz.org/user_guide/Serialization_and_Persistence.html#serializing-with-json - - Example: - - ```python - import param + Deserialize the given serialized data. This data can be used to create a + `Parameterized` object or update the parameters of an existing `Parameterized` object. - class P(param.Parameterized): - a = param.Number() - b = param.String() + Parameters + ---------- + serialization : str + The serialized parameter data as a JSON string. + subset : list of str, optional + A list of parameter names to deserialize. If `None`, all parameters will be + deserialized. Defaults to `None`. + mode : str, optional + The serialization format. By default, only 'json' is supported. + Defaults to 'json'. - serialized_data = '{"a": 1, "b": "hello"}' - deserialized_data = P.param.deserialize_parameters(serialized_data) - print(deserialized_data) - # Output: {'a': 1, 'b': 'hello'} + Returns + ------- + dict + A dictionary with parameter names as keys and deserialized values. - instance = P(**deserialized_data) - ``` + References + ---------- + For more details on parameter serialization, see: + https://param.holoviz.org/user_guide/Serialization_and_Persistence.html#serializing-with-json + + Examples + -------- + >>> import param + >>> class P(param.Parameterized): + ... a = param.Number() + ... b = param.String() + ... + >>> serialized_data = '{"a": 1, "b": "hello"}' + >>> deserialized_data = P.param.deserialize_parameters(serialized_data) + >>> print(deserialized_data) + {'a': 1, 'b': 'hello'} + >>> instance = P(**deserialized_data) """ self_or_cls = self_.self_or_cls serializer = Parameter._serializers[mode] @@ -4383,35 +4387,35 @@ def __init__(self, **params): @property def param(self): """ - The `.param` namespace for Parameterized classes and instances. + The `.param` namespace for `Parameterized` classes and instances. - This namespace provides access to powerful methods and properties for managing parameters in a `Parameterized` object. - It includes utilities for adding parameters, updating parameters, debugging, serialization, logging, and more. + This namespace provides access to powerful methods and properties for managing + parameters in a `Parameterized` object. It includes utilities for adding parameters, + updating parameters, debugging, serialization, logging, and more. - Reference: https://param.holoviz.org/user_guide/Parameters.html#parameter-objects-and-instances - - Example: - - ```python - import param + User Guide + ---------- + For more details on parameter objects and instances, see: + https://param.holoviz.org/user_guide/Parameters.html#parameter-objects-and-instances - class MyClass(param.Parameterized): - value = param.Parameter() + Examples + -------- + Basic usage of `.param` in a `Parameterized` class: - my_instance = MyClass(value=0) - ``` + >>> import param + >>> + >>> class MyClass(param.Parameterized): + ... value = param.Parameter() + >>> + >>> my_instance = MyClass(value=0) Access the `value` parameter of `my_instance`: - ```python - my_instance.param.value # the Parameter instance - ``` + >>> my_instance.param.value # the Parameter instance - Note this is different from the current `value` of `my_instance`: + Note that this is different from the current `value` of `my_instance`: - ```python - my_instance.value # 0, the current parameter value - ``` + >>> my_instance.value # 0, the current parameter value """ return Parameters(self.__class__, self=self) diff --git a/param/reactive.py b/param/reactive.py index d593173c..8f2c752b 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -186,7 +186,7 @@ class reactive_ops: Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. - Reference: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + User Guide: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx Examples: @@ -801,7 +801,7 @@ def rx(self) -> reactive_ops: Provides reactive versions of the operations that cannot be made reactive through overloading, such as `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. - Reference: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + User Guide: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx Examples: From 2d5b83215a58d8441424da82a0cb84bec7c3cce8 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Thu, 14 Nov 2024 20:48:49 +0100 Subject: [PATCH 17/20] Update param/parameterized.py Co-authored-by: Maxime Liquet <35924738+maximlt@users.noreply.github.com> --- param/parameterized.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/param/parameterized.py b/param/parameterized.py index d5c8f411..a262ee48 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1328,7 +1328,8 @@ def rx(self): User Guide: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx - Examples: + Examples + -------- Lets create a Parameterized instance: From 63f96dfc0a53b18db9ebcf0ea006ab9d66ba264e Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Thu, 14 Nov 2024 19:58:28 +0000 Subject: [PATCH 18/20] review feedback --- param/parameterized.py | 180 +++++++++++++++++++---------------------- param/reactive.py | 86 ++++++++++---------- 2 files changed, 130 insertions(+), 136 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index a262ee48..1efa0e8d 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1323,38 +1323,39 @@ def rx(self): """ The reactive namespace. - Provides reactive versions of the operations that cannot be made reactive through overloading, such as - `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. + Provides reactive versions of operations that cannot be made reactive through operator overloading, such as + `.rx.and_` and `.rx.bool`. Calling this namespace (`()`) returns a reactive expression. - User Guide: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx - - Examples - -------- - - Lets create a Parameterized instance: + Parameters + ---------- + None - ```python - import param + Returns + ------- + Reactive expression + The result of calling the reactive namespace is a reactive expression. - class P(param.Parameterized): - a = param.Number() - b = param.String() + User Guide + ---------- + https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + Examples + -------- + Create a Parameterized instance: - p = P(a=1, b="hello") - ``` + >>> import param + >>> class P(param.Parameterized): + >>> a = param.Number() + >>> b = param.String() + >>> p = P(a=1, b="hello") Get the current value: - ```python - a = p.param.a.rx.value - ``` + >>> a = p.param.a.rx.value Call it to get a reactive expression: - ```python - rx_value = p.param.a.rx() - ``` + >>> rx_value = p.param.a.rx() """ from .reactive import reactive_ops return reactive_ops(self) @@ -2298,10 +2299,10 @@ def set_default(self_,param_name,value): def add_parameter(self_, param_name: str, param_obj: Parameter): """ - Add a new Parameter object into this object's class. + Add a new Parameter object to this class. - Should result in a Parameter equivalent to one declared - in the class's source code. + This method allows dynamically adding a Parameter to the class, resulting in behavior equivalent to declaring + the Parameter in the class's source code. Parameters ---------- @@ -2312,34 +2313,25 @@ def add_parameter(self_, param_name: str, param_obj: Parameter): Examples -------- + Create a Parameterized class: - ```python - import param - - - class P(param.Parameterized): - a = param.Number() - b = param.String() - - - p = P() - ``` + >>> import param + >>> class P(param.Parameterized): + >>> a = param.Number() + >>> b = param.String() + >>> p = P() Add a new parameter to the class via the class: - ```python - P.param.add_parameter('c', param.Tuple(default=(1,2,3))) - print(p.c) - # (1, 2, 3) - ``` + >>> P.param.add_parameter('c', param.Tuple(default=(1, 2, 3))) + >>> print(p.c) + (1, 2, 3) Add a new parameter to the class via the instance: - ```python - p.param.add_parameter('d', param.Tuple(default=(3,2,1))) - print(p.d) - # (3, 2, 1) - ``` + >>> p.param.add_parameter('d', param.Tuple(default=(3, 2, 1))) + >>> print(p.d) + (3, 2, 1) """ # Could have just done setattr(cls,param_name,param_obj), # which is supported by the metaclass's __setattr__ , but @@ -2383,48 +2375,47 @@ def params(self_, parameter_name=None): def update(self_, arg=Undefined, /, **kwargs): """ - Updates one or more parameters of this object or class. + Update one or more parameters of this object or class. - This method allows you to set the parameters of the object or class using a dictionary, - an iterable, or keyword arguments in the form of param=value. The specified parameters - will be updated to the given values. + Allows setting the parameters of the object or class using a dictionary, an iterable, or keyword arguments + in the form of `param=value`. The specified parameters will be updated to the given values. - This method can also be used as a context manager to temporarily set and then reset - parameter values. + This method can also be used as a context manager to temporarily set and then reset parameter values. + + Parameters + ---------- + **params : dict or iterable or keyword arguments + The parameters to update, provided as a dictionary, iterable, or keyword arguments in `param=value` format. + References + ---------- User Guide: https://param.holoviz.org/user_guide/Parameters.html#other-parameterized-methods Examples -------- + Create a Parameterized instance: - ```python - import param - - class P(param.Parameterized): - a = param.Number() - b = param.String() - - p = P() - ``` + >>> import param + >>> class P(param.Parameterized): + >>> a = param.Number() + >>> b = param.String() + >>> p = P() Update parameters permanently: - ```python - p.param.update(a=1, b="Hello") - print(p.a, p.b) - # Output: 1 Hello - ``` + >>> p.param.update(a=1, b="Hello") + >>> print(p.a, p.b) + 1 Hello Update parameters temporarily: - ```python - with p.param.update(a=2, b="World"): - print(p.a, p.b) - # Output: 2 World - print(p.a, p.b) - # Output: 1 Hello - ``` + >>> with p.param.update(a=2, b="World"): + >>> print(p.a, p.b) + 2 World + >>> print(p.a, p.b) + 1 Hello """ + refs = {} if self_.self is not None: private = self_.self._param__private @@ -2707,40 +2698,40 @@ class or instance that contains an iterable collection of obj.param.set_dynamic_time_fn(time_fn,sublistattr) def serialize_parameters(self_, subset=None, mode='json'): - """Returns the serialized parameters of the Parameterized object. + """ + Return the serialized parameters of the Parameterized object. Parameters ---------- - subset: list, optional + subset : list, optional A list of parameter names to serialize. If None, all parameters will be serialized. Defaults to None. - mode (str, optional): + mode : str, optional The serialization format. By default, only 'json' is supported. Defaults to 'json'. Returns ------- - Any: The serialized value - - Reference - --------- - For more details visit https://param.holoviz.org/user_guide/Serialization_and_Persistence.html#serializing-with-json - - Example - ------- + Any + The serialized value. - ```python - import param + User Guide + ---------- + https://param.holoviz.org/user_guide/Serialization_and_Persistence.html#serializing-with-json - class P(param.Parameterized): - a = param.Number() - b = param.String() + Examples + -------- + Create a Parameterized instance and serialize its parameters: + >>> import param + >>> class P(param.Parameterized): + >>> a = param.Number() + >>> b = param.String() + >>> p = P(a=1, b="hello") - p = P(a=1, b="hello") + Serialize parameters: - serialized_data = p.param.serialize_parameters() - print(type(serialized_data)) - # {"name": "P00002", "a": 1, "b": "hello"} - ``` + >>> serialized_data = p.param.serialize_parameters() + >>> print(serialized_data) + {"name": "P00002", "a": 1, "b": "hello"} """ self_or_cls = self_.self_or_cls if mode not in Parameter._serializers: @@ -2776,9 +2767,8 @@ def deserialize_parameters(self_, serialization, subset=None, mode='json') -> di dict A dictionary with parameter names as keys and deserialized values. - References + User Guide ---------- - For more details on parameter serialization, see: https://param.holoviz.org/user_guide/Serialization_and_Persistence.html#serializing-with-json Examples diff --git a/param/reactive.py b/param/reactive.py index cc38c8bf..fec62fd4 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -183,39 +183,42 @@ class reactive_ops: """ The reactive namespace. - Provides reactive versions of the operations that cannot be made reactive through overloading, such as - `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. + Provides reactive versions of operations that cannot be made reactive through operator overloading, such as + `.rx.and_` and `.rx.bool`. Calling this namespace (`()`) returns a reactive expression. - User Guide: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx - - Examples: - - Lets create a Parameterized instance: + Parameters + ---------- + None - ```python - import param + Returns + ------- + Reactive expression + The result of calling the reactive namespace is a reactive expression. - class P(param.Parameterized): - a = param.Number() - b = param.String() + User Guide + ---------- + https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + Examples + -------- + Create a Parameterized instance: - p = P(a=1, b="hello") - ``` + >>> import param + >>> class P(param.Parameterized): + >>> a = param.Number() + >>> b = param.String() + >>> p = P(a=1, b="hello") Get the current value: - ```python - a = p.param.a.rx.value - ``` + >>> a = p.param.a.rx.value Call it to get a reactive expression: - ```python - rx_value = p.param.a.rx() - ``` + >>> rx_value = p.param.a.rx() """ + def __init__(self, reactive): self._reactive = reactive @@ -798,38 +801,39 @@ def rx(self) -> reactive_ops: """ The reactive namespace. - Provides reactive versions of the operations that cannot be made reactive through overloading, such as - `.rx.and_` and `.rx.bool`. Call it (`()`) to obtain a reactive expression. - - User Guide: https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx - - Examples - -------- + Provides reactive versions of operations that cannot be made reactive through operator overloading, such as + `.rx.and_` and `.rx.bool`. Calling this namespace (`()`) returns a reactive expression. - Lets create a Parameterized instance: + Parameters + ---------- + None - ```python - import param + Returns + ------- + Reactive expression + The result of calling the reactive namespace is a reactive expression. - class P(param.Parameterized): - a = param.Number() - b = param.String() + User Guide + ---------- + https://param.holoviz.org/user_guide/Reactive_Expressions.html#special-methods-on-rx + Examples + -------- + Create a Parameterized instance: - p = P(a=1, b="hello") - ``` + >>> import param + >>> class P(param.Parameterized): + >>> a = param.Number() + >>> b = param.String() + >>> p = P(a=1, b="hello") Get the current value: - ```python - a = p.param.a.rx.value - ``` + >>> a = p.param.a.rx.value Call it to get a reactive expression: - ```python - rx_value = p.param.a.rx() - ``` + >>> rx_value = p.param.a.rx() """ return self._rx From 9a2054bd47eb7a5e8fc32f24b603d06135031788 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Thu, 14 Nov 2024 20:07:27 +0000 Subject: [PATCH 19/20] ruff check --fix --- doc/user_guide/ParameterizedFunctions.ipynb | 2 +- numbergen/__init__.py | 4 ++-- param/_utils.py | 5 +++-- param/ipython.py | 5 +---- param/parameterized.py | 18 +++++++--------- param/parameters.py | 10 ++++++--- param/reactive.py | 1 - param/serializer.py | 6 +++--- param/version.py | 23 ++++++++++---------- pyproject.toml | 6 ++++++ tests/testcompositeparams.py | 7 +++--- tests/testdynamicparams.py | 24 +++++++++++---------- tests/testparameterizedobject.py | 8 +++---- tests/utils.py | 4 ++-- 14 files changed, 66 insertions(+), 57 deletions(-) diff --git a/doc/user_guide/ParameterizedFunctions.ipynb b/doc/user_guide/ParameterizedFunctions.ipynb index e38aff00..be389eb7 100644 --- a/doc/user_guide/ParameterizedFunctions.ipynb +++ b/doc/user_guide/ParameterizedFunctions.ipynb @@ -22,7 +22,7 @@ "from param import Parameter, ParameterizedFunction, ParamOverrides\n", "\n", "class multiply(ParameterizedFunction):\n", - " \"Function to multiply two arguments.\"\n", + " \"\"\"Function to multiply two arguments.\"\"\"\n", "\n", " left = Parameter(2, doc=\"Left-hand-side argument\")\n", " right = Parameter(4, doc=\"Right-hand-side argument\")\n", diff --git a/numbergen/__init__.py b/numbergen/__init__.py index ee1dfbf7..1b9974dc 100644 --- a/numbergen/__init__.py +++ b/numbergen/__init__.py @@ -135,7 +135,7 @@ def __abs__ (self): return UnaryOperator(self,operator.abs) } def pprint(x, *args, **kwargs): - "Pretty-print the provided item, translating operators to their symbols" + """Pretty-print the provided item, translating operators to their symbols""" return x.pprint(*args, **kwargs) if hasattr(x,'pprint') else operator_symbols.get(x, repr(x)) @@ -214,6 +214,7 @@ class Hash: for __call__ must be specified in the constructor and must stay constant across calls. """ + def __init__(self, name, input_count): self.name = name self.input_count = input_count @@ -224,7 +225,6 @@ def __init__(self, name, input_count): def _rational(self, val): """Convert the given value to a rational, if necessary.""" - I32 = 4294967296 # Maximum 32 bit unsigned int (i.e. 'I') value if isinstance(val, int): numer, denom = val, 1 diff --git a/param/_utils.py b/param/_utils.py index 650632ee..fedad877 100644 --- a/param/_utils.py +++ b/param/_utils.py @@ -122,7 +122,7 @@ def inner(*args, **kwargs): # Copy of Python 3.2 reprlib's recursive_repr but allowing extra arguments def _recursive_repr(fillvalue='...'): - 'Decorator to make a repr function return fillvalue for a recursive call' + """Decorator to make a repr function return fillvalue for a recursive call""" def decorating_function(user_function): repr_running = set() @@ -631,7 +631,8 @@ def __iter__(cls): def gen_types(gen_func): """ Decorator which takes a generator function which yields difference types - make it so it can be called with isinstance and issubclass.""" + make it so it can be called with isinstance and issubclass. + """ if not inspect.isgeneratorfunction(gen_func): msg = "gen_types decorator can only be applied to generator" raise TypeError(msg) diff --git a/param/ipython.py b/param/ipython.py index 27414f66..da3c26cc 100644 --- a/param/ipython.py +++ b/param/ipython.py @@ -61,7 +61,6 @@ def get_param_info(self, obj, include_super=True): and the dictionary of parameter values. If include_super is True, parameters are also collected from the super classes. """ - params = dict(obj.param.objects('existing')) if isinstance(obj,type): changed = [] @@ -86,7 +85,6 @@ def param_docstrings(self, info, max_col_len=100, only_changed=False): docstrings in a clean format (alternating red and blue for readability). """ - (params, val_dict, changed) = info contents = [] displayed_params = [] @@ -147,7 +145,6 @@ def _build_table(self, info, order, max_col_len=40, only_changed=False): Collect the information about parameters needed to build a properly formatted table and then tabulate it. """ - info_list, bounds_dict = [], {} (params, val_dict, changed) = info col_widths = {k:0 for k in order} @@ -209,7 +206,6 @@ def _tabulate(self, info_list, col_widths, changed, order, bounds_dict): order: The order of the table columns bound_dict: Dictionary of appropriately formatted bounds """ - contents, tail = [], [] column_set = {k for _, row in info_list for k in row} columns = [col for col in order if col in column_set] @@ -316,6 +312,7 @@ class ParamMagics(Magics): Implements the %params line magic used to inspect the parameters of a parameterized class or object. """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.param_pager = ParamPager() diff --git a/param/parameterized.py b/param/parameterized.py index 1efa0e8d..3d972915 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -456,6 +456,7 @@ class bothmethod: object (if called on the class) or the instance object (if called on the instance) as its first argument. """ + def __init__(self, method): self.method = method @@ -484,7 +485,6 @@ def no_instance_params(cls): def _instantiate_param_obj(paramobj, owner=None): """Return a Parameter object suitable for instantiation given the class's Parameter object""" - # Shallow-copy Parameter object without the watchers p = copy.copy(paramobj) p.owner = owner @@ -922,6 +922,7 @@ class ParameterMetaclass(type): """ Metaclass allowing control over creation of Parameter classes. """ + def __new__(mcs, classname, bases, classdict): # store the class's docstring in __classdoc @@ -1203,7 +1204,6 @@ def __init__(self, default=Undefined, *, doc=Undefined, # pylint: disable-msg=R0 instantiate=Undefined, constant=Undefined, readonly=Undefined, pickle_default_value=Undefined, allow_None=Undefined, per_instance=Undefined, allow_refs=Undefined, nested_refs=Undefined): - """Initialize a new Parameter object and store the supplied attributes: default: the owning class's value for the attribute represented @@ -1283,7 +1283,6 @@ def __init__(self, default=Undefined, *, doc=Undefined, # pylint: disable-msg=R0 inheritance of Parameter slots (attributes) from the owning-class' class hierarchy (see ParameterizedMetaclass). """ - self.name = None self.owner = None self.allow_refs = allow_refs @@ -1302,12 +1301,12 @@ class hierarchy (see ParameterizedMetaclass). @classmethod def serialize(cls, value): - "Given the parameter value, return a Python value suitable for serialization" + """Given the parameter value, return a Python value suitable for serialization""" return value @classmethod def deserialize(cls, value): - "Given a serializable Python value, return a value that the parameter can be set to" + """Given a serializable Python value, return a value that the parameter can be set to""" return value def schema(self, safe=False, subset=None, mode='json'): @@ -2415,7 +2414,6 @@ def update(self_, arg=Undefined, /, **kwargs): >>> print(p.a, p.b) 1 Hello """ - refs = {} if self_.self is not None: private = self_.self._param__private @@ -3488,6 +3486,7 @@ class ParameterizedMetaclass(type): attribute __abstract set to True. The 'abstract' attribute can be used to find out if a class is abstract or not. """ + def __init__(mcs, name, bases, dict_): """ Initialize the class object (not an instance of the class, but @@ -3919,7 +3918,6 @@ def script_repr(val, imports=None, prefix="\n ", settings=[], ways that are more suitable for saving as a separate script than for e.g. pretty-printing at the Python prompt. """ - if imports is None: imports = [] @@ -3977,7 +3975,6 @@ def pprint(val,imports=None, prefix="\n ", settings=[], parameter can be suppressed by returning None from the appropriate hook in script_repr_reg. """ - if imports is None: imports = [] @@ -4647,6 +4644,7 @@ class ParameterizedFunction(Parameterized): To obtain an instance of this class, call instance(). """ + __abstract = True def __str__(self): @@ -4658,7 +4656,6 @@ def instance(self_or_cls,**params): Return an instance of this class, copying parameters from any existing instance provided. """ - if isinstance (self_or_cls,ParameterizedMetaclass): cls = self_or_cls else: @@ -4707,7 +4704,7 @@ def _pprint(self, imports=None, prefix="\n ",unknown_value='', class default_label_formatter(ParameterizedFunction): - "Default formatter to turn parameter names into appropriate widget labels." + """Default formatter to turn parameter names into appropriate widget labels.""" capitalize = Parameter(default=True, doc=""" Whether or not the label should be capitalized.""") @@ -4745,6 +4742,7 @@ class overridable_property: .. deprecated:: 2.0.0 """ + # Delays looking up the accessors until they're needed, rather # than finding them when the class is first created. diff --git a/param/parameters.py b/param/parameters.py index 61f82d8a..ba84559d 100644 --- a/param/parameters.py +++ b/param/parameters.py @@ -396,7 +396,6 @@ def __call__(self, val=None, time_type=None): the current state remains consistent, this is normally the only way to change the time_type of an existing Time instance. """ - if time_type and val is None: raise Exception("Please specify a value for the new time_type.") if time_type: @@ -560,7 +559,6 @@ def _produce_value(self,gen,force=False): value will be produced and returned. Otherwise, the last value gen produced will be returned. """ - if hasattr(gen,"_Dynamic_time_fn"): time_fn = gen._Dynamic_time_fn else: @@ -613,6 +611,7 @@ def _force(self,obj,objtype=None): class __compute_set_hook: """Remove when set_hook is removed""" + def __call__(self, p): return _identity_hook @@ -1431,6 +1430,7 @@ class CalendarDateRange(Range): """ A date range specified as (start_date, end_date). """ + def _validate_value(self, val, allow_None): if allow_None and val is None: return @@ -1780,6 +1780,7 @@ class __compute_selector_default: then the object in _slot_defaults would itself be updated and the next Selector instance created wouldn't have [] as the default but a populated list. """ + def __call__(self, p): return [] @@ -1996,6 +1997,7 @@ class FileSelector(Selector): """ Given a path glob, allows one file to be selected from those matching. """ + __slots__ = ['path'] _slot_defaults = _dict_update( @@ -2106,6 +2108,7 @@ class MultiFileSelector(ListSelector): """ Given a path glob, allows multiple files to be selected from the list of matches. """ + __slots__ = ['path'] _slot_defaults = _dict_update( @@ -2523,7 +2526,7 @@ def _validate(self, val): self._validate_item_type(val, self.item_type) def _validate_bounds(self, val, bounds): - "Checks that the list is of the right length and has the right contents." + """Checks that the list is of the right length and has the right contents.""" if bounds is None or (val is None and self.allow_None): return min_length, max_length = bounds @@ -2576,6 +2579,7 @@ class HookList(List): for users to register a set of commands to be called at a specified place in some sequence of processing steps. """ + __slots__ = ['class_', 'bounds'] def _validate_value(self, val, allow_None): diff --git a/param/reactive.py b/param/reactive.py index fec62fd4..fbea21de 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -218,7 +218,6 @@ class reactive_ops: >>> rx_value = p.param.a.rx() """ - def __init__(self, reactive): self._reactive = reactive diff --git a/param/serializer.py b/param/serializer.py index ab094ba5..a04c98ba 100644 --- a/param/serializer.py +++ b/param/serializer.py @@ -13,7 +13,7 @@ class UnsafeserializableException(Exception): pass def JSONNullable(json_type): - "Express a JSON schema type as nullable to easily support Parameters that allow_None" + """Express a JSON schema type as nullable to easily support Parameters that allow_None""" return {'anyOf': [ json_type, {'type': 'null'}] } @@ -118,7 +118,7 @@ def deserialize_parameters(cls, pobj, serialization, subset=None): @classmethod def _get_method(cls, ptype, suffix): - "Returns specialized method if available, otherwise None" + """Returns specialized method if available, otherwise None""" method_name = ptype.lower()+'_' + suffix return getattr(cls, method_name, None) @@ -200,7 +200,7 @@ def number_schema(cls, p, safe=False): @classmethod def declare_numeric_bounds(cls, schema, bounds, inclusive_bounds): - "Given an applicable numeric schema, augment with bounds information" + """Given an applicable numeric schema, augment with bounds information""" if bounds is not None: (low, high) = bounds if low is not None: diff --git a/param/version.py b/param/version.py index ed863740..63aaa69a 100644 --- a/param/version.py +++ b/param/version.py @@ -81,7 +81,8 @@ class Version: obtained via git describe. This later portion is only shown if the commit count since the last tag is non zero. Instead of '.post', an alternate valid prefix such as '.rev', '_rev', '_r' or '.r' may be - supplied.""" + supplied. + """ def __new__(cls,**kw): # If called in the old way, provide the previous class. Means @@ -131,22 +132,22 @@ def prerelease(self): @property def release(self): - "Return the release tuple" + """Return the release tuple""" return self.fetch()._release @property def commit(self): - "A specification for this particular VCS version, e.g. a short git SHA" + """A specification for this particular VCS version, e.g. a short git SHA""" return self.fetch()._commit @property def commit_count(self): - "Return the number of commits since the last release" + """Return the number of commits since the last release""" return self.fetch()._commit_count @property def dirty(self): - "True if there are uncommited changes, False otherwise" + """True if there are uncommited changes, False otherwise""" return self.fetch()._dirty @@ -256,7 +257,7 @@ def _output_from_file(self, entry='git_describe'): def _update_from_vcs(self, output): - "Update state based on the VCS state e.g the output of git describe" + """Update state based on the VCS state e.g the output of git describe""" split = output[1:].split('-') dot_split = split[0].split('.') for prefix in ['a','b','rc']: @@ -599,22 +600,22 @@ def __init__(self, release=None, fpath=None, commit=None, @property def release(self): - "Return the release tuple" + """Return the release tuple""" return self.fetch()._release @property def commit(self): - "A specification for this particular VCS version, e.g. a short git SHA" + """A specification for this particular VCS version, e.g. a short git SHA""" return self.fetch()._commit @property def commit_count(self): - "Return the number of commits since the last release" + """Return the number of commits since the last release""" return self.fetch()._commit_count @property def dirty(self): - "True if there are uncommited changes, False otherwise" + """True if there are uncommited changes, False otherwise""" return self.fetch()._dirty @@ -667,7 +668,7 @@ def git_fetch(self, cmd='git'): self._update_from_vcs(output) def _update_from_vcs(self, output): - "Update state based on the VCS state e.g the output of git describe" + """Update state based on the VCS state e.g the output of git describe""" split = output[1:].split('-') if 'dev' in split[0]: dev_split = split[0].split('dev') diff --git a/pyproject.toml b/pyproject.toml index cc4dabab..56c9e645 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,3 +113,9 @@ asyncio_default_fixture_loop_scope="function" [tool.coverage.report] omit = ["param/version.py"] + +[tool.ruff.lint] +select = ["D"] + +[tool.ruff.lint.pydocstyle] +convention = "numpy" diff --git a/tests/testcompositeparams.py b/tests/testcompositeparams.py index 95c5bbaf..7df55dd6 100644 --- a/tests/testcompositeparams.py +++ b/tests/testcompositeparams.py @@ -25,7 +25,8 @@ class A(param.Parameterized): self.a = self.A() class SomeSequence: - "Can't use iter with Dynamic (doesn't pickle, doesn't copy)" + """Can't use iter with Dynamic (doesn't pickle, doesn't copy)""" + def __init__(self,sequence): self.sequence=sequence self.index=0 @@ -67,7 +68,7 @@ def test_defaults_unbound(self): assert not hasattr(c, 'objtype') def test_initialization(self): - "Make an instance and do default checks" + """Make an instance and do default checks""" self.assertEqual(self.a.x, 0) self.assertEqual(self.a.y, 0) self.assertEqual(self.a.xy, [0,0]) @@ -82,7 +83,7 @@ def test_set_compound(self): self.assertEqual(self.a.y, 3) def test_compound_class(self): - " Get the compound on the class " + """Get the compound on the class""" self.assertEqual(self.A.xy, [0,0]) def test_set_compound_class_set(self): diff --git a/tests/testdynamicparams.py b/tests/testdynamicparams.py index a25e9ce4..5b419efd 100644 --- a/tests/testdynamicparams.py +++ b/tests/testdynamicparams.py @@ -53,7 +53,7 @@ def test_set_dynamic_time_fn_y(self): self.t1.param['y']._value_is_dynamic(self.t1), False) def test_inspect_x(self): - "no value generated yet" + """No value generated yet""" self.assertEqual(self.t1.param.inspect_value('x'), None) def test_inspect_y(self): @@ -69,17 +69,17 @@ def test_set_dynamic_numbergen(self): self.assertEqual(is_numbergen, True) def test_matching_numbergen_streams(self): - "check that t2 and t3 have identical streams" + """Check that t2 and t3 have identical streams""" self.assertEqual(self.t2.x, self.t3.x) def test_numbergen_objects_distinct(self): - "check t2 and t3 do not share UniformRandom objects" + """Check t2 and t3 do not share UniformRandom objects""" self.t2.x self.assertNotEqual(self.t2.param.inspect_value('x'), self.t3.param.inspect_value('x')) def test_numbergen_inspect(self): - " inspect_value() should return last generated value " + """inspect_value() should return last generated value""" self.t2.x # Call 1 self.t2.x # Call 2 t2_last_value = self.t2.x # advance t2 beyond t3 @@ -95,7 +95,7 @@ def test_dynamic_value_instantiated(self): t6_first_value) def test_non_dynamic_value_not_instantiated(self): - " non-dynamic value not instantiated" + """non-dynamic value not instantiated""" self.TestPO2.y = 4 self.assertEqual(self.t6.y, 4) self.assertEqual(self.t7.y, 4) @@ -122,7 +122,7 @@ def test_shared_numbergen(self): self.assertEqual(self.TestPO2().param['y'].default.__class__.__name__, 'UniformRandom') def test_copy_match(self): - "check a copy is the same" + """Check a copy is the same""" t9 = copy.deepcopy(self.t7) self.assertEqual(t9.param.get_value_generator('y') is self.TestPO2().param['y'].default, True) @@ -139,7 +139,8 @@ class TestPO3(param.Parameterized): time_dependent=True)) class TestPO4(self.TestPO1): - "Nested parameterized objects" + """Nested parameterized objects""" + z = param.Parameter(default=self.TestPO1()) self.TestPO3 = TestPO3 @@ -204,21 +205,21 @@ def test_dynamic_value_change_independent(self): self.assertEqual(t12.y, t12.y) def test_dynamic_value_change_disabled(self): - " time_fn set on the UniformRandom() when t13.y was set" + """time_fn set on the UniformRandom() when t13.y was set""" t13 = self.TestPO1() t13.param.set_dynamic_time_fn(None) t13.y = numbergen.UniformRandom() self.assertNotEqual(t13.y, t13.y) def test_dynamic_value_change_enabled(self): - " time_fn set on the UniformRandom() when t13.y was set" + """time_fn set on the UniformRandom() when t13.y was set""" t14 = self.TestPO1() t14.y = numbergen.UniformRandom() self.assertEqual(t14.y, t14.y) def test_dynamic_time_fn_not_inherited(self): - " time_fn not inherited" + """time_fn not inherited""" t15 = self.TestPO4() t15.param.set_dynamic_time_fn(None) with param.Dynamic.time_fn as t: @@ -230,7 +231,8 @@ def test_dynamic_time_fn_not_inherited(self): class TestDynamicSharedNumbergen(TestDynamicParameters): - "Check shared generator" + """Check shared generator""" + def setUp(self): super().setUp() self.shared = numbergen.UniformRandom(lbound=-1,ubound=1,seed=20) diff --git a/tests/testparameterizedobject.py b/tests/testparameterizedobject.py index f9b5ea76..939a8b9f 100644 --- a/tests/testparameterizedobject.py +++ b/tests/testparameterizedobject.py @@ -272,14 +272,16 @@ class C(A, B): pass def test_constant_parameter_modify_class_before(self): """Test you can set on class and the new default is picked up - by new instances""" + by new instances + """ TestPO.const=9 testpo = TestPO() self.assertEqual(testpo.const,9) def test_constant_parameter_modify_class_after_init(self): """Test that setting the value on the class doesn't update the instance value - even when the instance value hasn't yet been set""" + even when the instance value hasn't yet been set + """ oobj = [] class P(param.Parameterized): x = param.Parameter(default=oobj, constant=True) @@ -333,7 +335,6 @@ def test_readonly_parameter(self): def test_basic_instantiation(self): """Check that instantiated parameters are copied into objects.""" - testpo = TestPO() self.assertEqual(testpo.inst,TestPO.inst) @@ -523,7 +524,6 @@ class P(param.Parameterized): def test_values(self): """Basic tests of params() method.""" - # CB: test not so good because it requires changes if params # of PO are changed assert 'name' in param.Parameterized.param.values() diff --git a/tests/utils.py b/tests/utils.py index bec38f3b..3c31666a 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -34,7 +34,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def emit(self, record): - "Store a message to the instance's messages dictionary" + """Store a message to the instance's messages dictionary""" self.acquire() try: self.messages[record.levelname].append(record.getMessage()) @@ -48,7 +48,7 @@ def reset(self): self.release() def tail(self, level, n=1): - "Returns the last n lines captured at the given level" + """Returns the last n lines captured at the given level""" return [str(el) for el in self.messages[level][-n:]] def assertEndsWith(self, level, substring): From 938d6a0ff8ad884290e455ca24ec70fd6a04f388 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Thu, 14 Nov 2024 20:15:27 +0000 Subject: [PATCH 20/20] fix --- param/parameterized.py | 61 +++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 3d972915..697901a0 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1,6 +1,4 @@ -""" -Generic support for objects with full-featured Parameters and -messaging. +"""Generic support for objects with full-featured Parameters and messaging. This file comes from the Param library (https://github.com/holoviz/param) but can be taken out of the param module and used on its own if desired, @@ -127,9 +125,7 @@ def get_logger(name=None): _reference_transforms = [] def register_reference_transform(transform): - """ - Appends a transform to extract potential parameter dependencies - from an object. + """Append a transform to extract potential parameter dependencies from an object. Arguments --------- @@ -139,9 +135,9 @@ def register_reference_transform(transform): def transform_reference(arg): """ - Applies transforms to turn objects which should be treated like - a parameter reference into a valid reference that can be resolved - by Param. This is useful for adding handling for depending on objects + Apply transforms to turn objects which should be treated like a parameter reference into a valid reference that can be resolved by Param. + + This is useful for adding handling for depending on objects that are not simple Parameters or functions with dependency definitions. """ @@ -152,7 +148,7 @@ def transform_reference(arg): return arg def eval_function_with_deps(function): - """Evaluates a function after resolving its dependencies. + """Evaluate a function after resolving its dependencies. Calls and returns a function after resolving any dependencies stored on the _dinfo attribute and passing the resolved values @@ -168,9 +164,7 @@ def eval_function_with_deps(function): return function(*args, **kwargs) def resolve_value(value, recursive=True): - """ - Resolves the current value of a dynamic reference. - """ + """Resolve the current value of a dynamic reference.""" if not recursive: pass elif isinstance(value, (list, tuple)): @@ -194,9 +188,7 @@ def resolve_value(value, recursive=True): return value def resolve_ref(reference, recursive=False): - """ - Resolves all parameters a dynamic reference depends on. - """ + """Resolve all parameters a dynamic reference depends on.""" if recursive: if isinstance(reference, (list, tuple, set)): return [r for v in reference for r in resolve_ref(v, recursive)] @@ -230,15 +222,12 @@ def resolve_ref(reference, recursive=False): return [] def _identity_hook(obj, val): - """To be removed when set_hook is removed""" + """To be removed when set_hook is removed.""" return val class _Undefined: - """ - Dummy value to signal completely undefined values rather than - simple None values. - """ + """Dummy value to signal completely undefined values rather than simple None values.""" def __bool__(self): # Haven't defined whether Undefined is falsy or truthy, @@ -255,9 +244,7 @@ def __repr__(self): @contextmanager def logging_level(level): - """ - Temporarily modify param's logging level. - """ + """Temporarily modify param's logging level.""" level = level.upper() levels = [DEBUG, INFO, WARNING, ERROR, CRITICAL, VERBOSE] level_names = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'VERBOSE'] @@ -276,8 +263,10 @@ def logging_level(level): @contextmanager def _batch_call_watchers(parameterized, enable=True, run=True): - """ - Internal version of batch_call_watchers, adding control over queueing and running. + """Add control over queueing and running. + + Internal version of batch_call_watchers. + Only actually batches events if enable=True; otherwise a no-op. Only actually calls the accumulated watchers on exit if run=True; otherwise they remain queued. """ @@ -302,8 +291,9 @@ def batch_watch(parameterized, enable=True, run=True): @contextmanager def batch_call_watchers(parameterized): """ - Context manager to batch events to provide to Watchers on a - parameterized object. This context manager queues any events + Context manager to batch events to provide to Watchers on a parameterized object. + + This context manager queues any events triggered by setting a parameter on the supplied parameterized object, saving them up to dispatch them all at once when the context manager exits. @@ -330,10 +320,7 @@ def _syncing(parameterized, parameters): @contextmanager def edit_constant(parameterized): - """ - Temporarily set parameters on Parameterized object to constant=False - to allow editing them. - """ + """Temporarily set parameters on Parameterized object to constant=False to allow editing them.""" params = parameterized.param.objects('existing').values() constants = [p.constant for p in params] for p in params: @@ -349,10 +336,7 @@ def edit_constant(parameterized): @contextmanager def discard_events(parameterized): - """ - Context manager that discards any events within its scope - triggered on the supplied parameterized object. - """ + """Context manager that discards any events within its scope triggered on the supplied parameterized object.""" batch_watch = parameterized.param._BATCH_WATCH parameterized.param._BATCH_WATCH = True watchers, events = (list(parameterized.param._state_watchers), @@ -962,10 +946,7 @@ def __getattribute__(mcs,name): class _ParameterBase(metaclass=ParameterMetaclass): - """ - Base Parameter class used to dynamically update the signature of all - the Parameters. - """ + """Base Parameter class used to dynamically update the signature of all the Parameters.""" @classmethod def _modified_slots_defaults(cls):