From f7d679d9b608d8e22857f427716e00dcbe5878f6 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Wed, 25 Dec 2024 05:00:03 +0000 Subject: [PATCH 01/15] ruff D400 implementation --- numbergen/__init__.py | 4 +-- param/_utils.py | 22 +++++++------- param/parameterized.py | 52 +++++++++++++++++--------------- param/parameters.py | 4 +-- param/reactive.py | 2 +- param/serializer.py | 6 ++-- param/version.py | 20 ++++++------ pyproject.toml | 1 - tests/testaddparameter.py | 2 ++ tests/testbytesparam.py | 2 +- tests/testcompositeparams.py | 6 ++-- tests/testdefaults.py | 2 +- tests/testdynamicparams.py | 24 +++++++-------- tests/testfiledeserialization.py | 2 +- tests/testipythonmagic.py | 2 +- tests/testjsonserialization.py | 2 +- tests/testnumpy.py | 2 +- tests/testpandas.py | 2 +- tests/testparameterizedobject.py | 6 ++-- tests/testparamunion.py | 2 +- tests/teststringparam.py | 2 +- tests/testwatch.py | 2 +- tests/utils.py | 4 +-- 23 files changed, 89 insertions(+), 84 deletions(-) diff --git a/numbergen/__init__.py b/numbergen/__init__.py index 975a3e716..b2fbcdb1b 100644 --- a/numbergen/__init__.py +++ b/numbergen/__init__.py @@ -133,7 +133,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)) @@ -239,7 +239,7 @@ def _rational(self, val): def __getstate__(self): - """Avoid Hashlib.md5 TypeError in deepcopy (hashlib issue)""" + """Avoid Hashlib.md5 TypeError in deepcopy (hashlib issue).""" d = self.__dict__.copy() d.pop('_digest') d.pop('_hash_struct') diff --git a/param/_utils.py b/param/_utils.py index 56aae1374..6e5c51fd8 100644 --- a/param/_utils.py +++ b/param/_utils.py @@ -34,11 +34,11 @@ MUTABLE_TYPES = (abc.MutableSequence, abc.MutableSet, abc.MutableMapping) class ParamWarning(Warning): - """Base Param Warning""" + """Base Param Warning.""" class ParamPendingDeprecationWarning(ParamWarning, PendingDeprecationWarning): """ - Param PendingDeprecationWarning + Param PendingDeprecationWarning. This warning type is useful when the warning is not meant to be displayed to REPL/notebooks users, as DeprecationWarning are displayed when triggered @@ -48,7 +48,7 @@ class ParamPendingDeprecationWarning(ParamWarning, PendingDeprecationWarning): class ParamDeprecationWarning(ParamWarning, DeprecationWarning): """ - Param DeprecationWarning + Param DeprecationWarning. Ignored by default except when triggered by code in __main__ """ @@ -56,7 +56,7 @@ class ParamDeprecationWarning(ParamWarning, DeprecationWarning): class ParamFutureWarning(ParamWarning, FutureWarning): """ - Param FutureWarning + Param FutureWarning. Always displayed. """ @@ -85,7 +85,7 @@ def _deprecate_positional_args(func): Internal decorator for methods that issues warnings for positional arguments Using the keyword-only argument syntax in pep 3102, arguments after the ``*`` will issue a warning when passed as a positional argument. - Adapted from scikit-learn + Adapted from scikit-learn. """ signature = inspect.signature(func) @@ -124,7 +124,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() @@ -201,12 +201,12 @@ def _validate_error_prefix(parameter, attribute=None): def _is_mutable_container(value): - """True for mutable containers, which typically need special handling when being copied""" + """True for mutable containers, which typically need special handling when being copied.""" return isinstance(value, MUTABLE_TYPES) def full_groupby(l, key=lambda x: x): - """Groupby implementation which does not require a prior sort""" + """Groupby implementation which does not require a prior sort.""" d = defaultdict(list) for item in l: d[key(item)].append(item) @@ -225,7 +225,7 @@ def iscoroutinefunction(function): ) async def _to_thread(func, /, *args, **kwargs): - """Polyfill for asyncio.to_thread in Python < 3.9""" + """Polyfill for asyncio.to_thread in Python < 3.9.""" loop = asyncio.get_running_loop() ctx = contextvars.copy_context() func_call = functools.partial(ctx.run, func, *args, **kwargs) @@ -281,7 +281,7 @@ def flatten(line): def accept_arguments( f: Callable[Concatenate[CallableT, P], R] ) -> Callable[P, Callable[[CallableT], R]]: - """Decorator for decorators that accept arguments""" + """Decorator for decorators that accept arguments.""" @functools.wraps(f) def _f(*args: P.args, **kwargs: P.kwargs) -> Callable[[CallableT], R]: return lambda actual_f: f(actual_f, *args, **kwargs) @@ -330,7 +330,7 @@ def as_unicode(obj): def is_ordered_dict(d): """ Predicate checking for ordered dictionaries. OrderedDict is always - ordered, and vanilla Python dictionaries are ordered for Python 3.6+ + ordered, and vanilla Python dictionaries are ordered for Python 3.6+. .. deprecated:: 2.0.0 """ diff --git a/param/parameterized.py b/param/parameterized.py index ac0df0343..27439e049 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -221,7 +221,7 @@ 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 @@ -436,7 +436,7 @@ def wrapper(cls): class bothmethod: """ - 'optional @classmethod' + 'optional @classmethod'. A decorator that allows a method to receive either the class object (if called on the class) or the instance object @@ -462,13 +462,13 @@ def _getattr(obj, attr): def no_instance_params(cls): - """Disables instance parameters on the class""" + """Disables instance parameters on the class.""" cls._param__private.disable_instance_params = True return cls def _instantiate_param_obj(paramobj, owner=None): - """Return a Parameter object suitable for instantiation given the class's Parameter object""" + """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 @@ -519,7 +519,7 @@ def _f(self, obj, val): def get_method_owner(method): - """Gets the instance that owns the supplied method""" + """Gets the instance that owns the supplied method.""" if not inspect.ismethod(method): return None if isinstance(method, partial): @@ -530,7 +530,7 @@ def get_method_owner(method): # PARAM3_DEPRECATION 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. .. deprecated:: 1.12.0 """ @@ -632,7 +632,9 @@ def _output(*args,**kw): def _parse_dependency_spec(spec): """ - Parses param.depends specifications into three components: + Parses param.depends string specifications into three components. + + The 3 components are: 1. The dotted path to the sub-object 2. The attribute being depended on, i.e. either a parameter or method @@ -781,7 +783,7 @@ def _m_caller(self, method_name, what='value', changed=None, callback=None): def _add_doc(obj, docstring): - """Add a docstring to a namedtuple""" + """Add a docstring to a namedtuple.""" obj.__doc__ = docstring @@ -1181,7 +1183,7 @@ def __init__(self, default=Undefined, *, doc=Undefined, # pylint: disable-msg=R0 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: + Initialize a new Parameter object and store the supplied attributes. default: the owning class's value for the attribute represented by this Parameter, which can be overridden in an instance. @@ -1278,12 +1280,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'): @@ -1566,14 +1568,14 @@ def __set__(self, obj, val): obj.param._batch_call_watchers() def _validate_value(self, value, allow_None): - """Implements validation for parameter value""" + """Implements validation for parameter value.""" def _validate(self, val): - """Implements validation for the parameter value and attributes""" + """Implements validation for the parameter value and attributes.""" self._validate_value(val, self.allow_None) def _post_setter(self, obj, val): - """Called after the parameter value has been validated and set""" + """Called after the parameter value has been validated and set.""" def __delete__(self,obj): raise TypeError("Cannot delete '%s': Parameters deletion not allowed." % self.name) @@ -1871,7 +1873,7 @@ def __setstate__(self, state): setattr(self, k, v) def __getitem__(self_, key): - """Returns the class or instance parameter""" + """Returns the class or instance parameter.""" inst = self_.self if inst is None: return self_._cls_parameters[key] @@ -1879,7 +1881,7 @@ def __getitem__(self_, key): return _instantiated_parameter(inst, p) def __dir__(self_): - """Adds parameters to dir""" + """Adds parameters to dir.""" return super().__dir__() + list(self_._cls_parameters) def __iter__(self_): @@ -2321,7 +2323,7 @@ def _add_parameter(self_,param_name, param_obj): def params(self_, parameter_name=None): """ Return the Parameters of this class as the - dictionary {name: parameter_object} + dictionary {name: parameter_object}. Includes Parameters from this class and its superclasses. @@ -2473,7 +2475,7 @@ def set_param(self_, *args,**kwargs): def _cls_parameters(self_): """ Class parameters are cached because they are accessed often, - and parameters are rarely added (and cannot be deleted) + and parameters are rarely added (and cannot be deleted). """ cls = self_.cls pdict = cls._param__private.params @@ -2496,7 +2498,7 @@ def _cls_parameters(self_): def objects(self_, instance=True): """ - Returns the Parameters of this instance or class + Returns the Parameters of this instance or class. If instance=True and called on a Parameterized instance it will create instance parameters for all Parameters defined on @@ -4013,13 +4015,13 @@ def type_script_repr(type_,imports,prefix,settings): def truncate(str_, maxlen = 30): - """Return HTML-safe truncated version of given string""" + """Return HTML-safe truncated version of given string.""" rep = (str_[:(maxlen-2)] + '..') if (len(str_) > (maxlen-2)) else str_ return html.escape(rep) def _get_param_repr(key, val, p, vallen=30, doclen=40): - """HTML representation for a single Parameter object and its value""" + """HTML representation for a single Parameter object and its value.""" if isinstance(val, Parameterized) or (type(val) is type and issubclass(val, Parameterized)): value = val.param._repr_html_(open=False) elif hasattr(val, "_repr_html_"): @@ -4073,7 +4075,7 @@ def _get_param_repr(key, val, p, vallen=30, doclen=40): def _parameterized_repr_html(p, open): - """HTML representation for a Parameterized object""" + """HTML representation for a Parameterized object.""" if isinstance(p, Parameterized): cls = p.__class__ title = cls.name + "()" @@ -4142,7 +4144,7 @@ class _ClassPrivate: renamed: bool Whethe the class has been renamed by a super class params: dict - Dict of parameter_name:parameter + Dict of parameter_name:parameter. """ __slots__ = [ @@ -4205,7 +4207,7 @@ class _InstancePrivate: parameter_name: parameter_attribute (e.g. 'value'): list of `Watcher`s values: dict - Dict of parameter name: value + Dict of parameter name: value. """ __slots__ = [ @@ -4642,7 +4644,7 @@ def _pprint(self, imports=None, prefix="\n ",unknown_value='', qualify=False, separator=""): """ Same as self.param.pprint, except that X.classname(Y - is replaced with X.classname.instance(Y + is replaced with X.classname.instance(Y. """ r = self.param.pprint(imports,prefix, unknown_value=unknown_value, diff --git a/param/parameters.py b/param/parameters.py index 0259e2ae0..d0791cff5 100644 --- a/param/parameters.py +++ b/param/parameters.py @@ -608,7 +608,7 @@ def _force(self,obj,objtype=None): class __compute_set_hook: - """Remove when set_hook is removed""" + """Remove when set_hook is removed.""" def __call__(self, p): return _identity_hook @@ -839,7 +839,7 @@ def __setstate__(self,state): class Integer(Number): - """Numeric Parameter required to be an Integer""" + """Numeric Parameter required to be an Integer.""" _slot_defaults = dict(Number._slot_defaults, default=0) diff --git a/param/reactive.py b/param/reactive.py index deb9171e7..19cccd695 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -1,5 +1,5 @@ """ -reactive API +reactive API. `rx` is a wrapper around a Python object that lets users create reactive expression pipelines by calling existing APIs on an object with dynamic diff --git a/param/serializer.py b/param/serializer.py index b72eaf400..664f568be 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'}] } @@ -112,7 +112,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) @@ -194,7 +194,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 2f3042eaa..ebaafee2f 100644 --- a/param/version.py +++ b/param/version.py @@ -134,22 +134,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 @@ -259,7 +259,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 +599,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 +667,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 7f7fb2dcf..60b8ad141 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -128,7 +128,6 @@ ignore = [ "D105", # Missing docstring in magic method" "D107", # Missing docstring in `__init__`" "D205", # 1 blank line required between summary line and description - "D400", # First line should end with a period" "D401", # First line of docstring should be in imperative mood: "Returns the last n lines captured at the given level" "D415", # First line should end with a period, question mark, or exclamation point "D417", # Missing argument description in the docstring for `param_union`: `*parameterizeds` diff --git a/tests/testaddparameter.py b/tests/testaddparameter.py index 4da4a35f2..797ca1ce9 100644 --- a/tests/testaddparameter.py +++ b/tests/testaddparameter.py @@ -1,4 +1,6 @@ """ +Test of add_parameter class method. + At the time of adding these tests, the implementation of add_parameter had not changed since it was committed (f10b324 in July 2012). The tests are checking that (not fully understood) implementation: diff --git a/tests/testbytesparam.py b/tests/testbytesparam.py index df7ea8bca..11c59c70d 100644 --- a/tests/testbytesparam.py +++ b/tests/testbytesparam.py @@ -1,4 +1,4 @@ -"""Unit test for Bytes parameters""" +"""Unit test for Bytes parameters.""" import unittest import pytest diff --git a/tests/testcompositeparams.py b/tests/testcompositeparams.py index 7df55dd6c..fbefd2245 100644 --- a/tests/testcompositeparams.py +++ b/tests/testcompositeparams.py @@ -25,7 +25,7 @@ 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 @@ -68,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]) @@ -83,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/testdefaults.py b/tests/testdefaults.py index e7dc4c737..e45b02ca4 100644 --- a/tests/testdefaults.py +++ b/tests/testdefaults.py @@ -1,4 +1,4 @@ -"""Do all subclasses of Parameter supply a valid default?""" +"""Test that all subclasses of Parameter supply a valid default.""" import unittest import pytest diff --git a/tests/testdynamicparams.py b/tests/testdynamicparams.py index 5b419efde..bf511089f 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) @@ -115,14 +115,14 @@ def test_setting_y_param_numbergen(self): def test_shared_numbergen(self): """ Instances of TestPO2 that don't have their own value for the - parameter share one UniformRandom object + parameter share one UniformRandom object. """ self.TestPO2.y=numbergen.UniformRandom() # now the Parameter instantiate should be true self.assertEqual(self.t7.param.get_value_generator('y') is self.TestPO2().param['y'].default, True) 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,7 @@ class TestPO3(param.Parameterized): time_dependent=True)) class TestPO4(self.TestPO1): - """Nested parameterized objects""" + """Nested parameterized objects.""" z = param.Parameter(default=self.TestPO1()) @@ -205,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: @@ -231,7 +231,7 @@ def test_dynamic_time_fn_not_inherited(self): class TestDynamicSharedNumbergen(TestDynamicParameters): - """Check shared generator""" + """Check shared generator.""" def setUp(self): super().setUp() diff --git a/tests/testfiledeserialization.py b/tests/testfiledeserialization.py index 21724afec..32a9a9458 100644 --- a/tests/testfiledeserialization.py +++ b/tests/testfiledeserialization.py @@ -1,4 +1,4 @@ -"""Test deserialization routines that read from file""" +"""Test deserialization routines that read from file.""" import unittest import param import sys diff --git a/tests/testipythonmagic.py b/tests/testipythonmagic.py index 230a18844..6c5278ca7 100644 --- a/tests/testipythonmagic.py +++ b/tests/testipythonmagic.py @@ -1,4 +1,4 @@ -"""Unit test for the IPython magic""" +"""Unit test for the IPython magic.""" import re import sys import unittest diff --git a/tests/testjsonserialization.py b/tests/testjsonserialization.py index 48586efb3..45cfdd80b 100644 --- a/tests/testjsonserialization.py +++ b/tests/testjsonserialization.py @@ -99,7 +99,7 @@ class TestSet(param.Parameterized): class TestSerialization(unittest.TestCase): - """Base class for testing serialization of Parameter values""" + """Base class for testing serialization of Parameter values.""" mode = None diff --git a/tests/testnumpy.py b/tests/testnumpy.py index 42b99d5db..c1ed5e7d6 100644 --- a/tests/testnumpy.py +++ b/tests/testnumpy.py @@ -1,4 +1,4 @@ -"""If numpy's present, is numpy stuff ok?""" +"""If numpy is present, test if numpy stuff is ok.""" import os import unittest diff --git a/tests/testpandas.py b/tests/testpandas.py index 462c4571d..36dbe2950 100644 --- a/tests/testpandas.py +++ b/tests/testpandas.py @@ -1,4 +1,4 @@ -"""Test Parameters based on pandas""" +"""Test Parameters based on pandas.""" import os import re import unittest diff --git a/tests/testparameterizedobject.py b/tests/testparameterizedobject.py index 850582be5..9bb85d002 100644 --- a/tests/testparameterizedobject.py +++ b/tests/testparameterizedobject.py @@ -270,7 +270,7 @@ 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() @@ -279,7 +279,7 @@ def test_constant_parameter_modify_class_before(self): 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): @@ -1135,6 +1135,8 @@ class B(A): def test_inheritance_diamond_not_supported(): """ + Test that Parameters don't respect diamond inheritance. + In regular Python, the value of the class attribute p on D is resolved to 2: diff --git a/tests/testparamunion.py b/tests/testparamunion.py index 4cdff64d4..e939d9c89 100644 --- a/tests/testparamunion.py +++ b/tests/testparamunion.py @@ -1,4 +1,4 @@ -"""UnitTest for param_union helper""" +"""UnitTest for param_union helper.""" import logging import unittest diff --git a/tests/teststringparam.py b/tests/teststringparam.py index 7f6fe158d..baa6aa4c9 100644 --- a/tests/teststringparam.py +++ b/tests/teststringparam.py @@ -1,4 +1,4 @@ -"""Unit test for String parameters""" +"""Unit test for String parameters.""" import unittest import param diff --git a/tests/testwatch.py b/tests/testwatch.py index dd53427d6..3ea87d2e5 100644 --- a/tests/testwatch.py +++ b/tests/testwatch.py @@ -1,4 +1,4 @@ -"""Unit test for watch mechanism""" +"""Unit test for watch mechanism.""" import copy import re import unittest diff --git a/tests/utils.py b/tests/utils.py index 8c9a18369..51424d5e4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -35,7 +35,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()) @@ -49,7 +49,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 7843a0a9e10f52a472794e0a22ab1520f6b33d16 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Wed, 25 Dec 2024 06:11:35 +0000 Subject: [PATCH 02/15] Enable ruff D401 --- numbergen/__init__.py | 42 ++++++--- param/_utils.py | 105 +++++++++++++++------ param/ipython.py | 25 +++-- param/parameterized.py | 187 +++++++++++++++++++++++++++++--------- param/parameters.py | 22 +++-- param/reactive.py | 95 ++++++++++++++----- param/serializer.py | 2 +- param/version.py | 12 ++- pyproject.toml | 1 - tests/testdeprecations.py | 2 +- tests/utils.py | 2 +- 11 files changed, 364 insertions(+), 131 deletions(-) diff --git a/numbergen/__init__.py b/numbergen/__init__.py index b2fbcdb1b..881941c5a 100644 --- a/numbergen/__init__.py +++ b/numbergen/__init__.py @@ -141,14 +141,20 @@ class BinaryOperator(NumberGenerator): """Applies any binary operator to NumberGenerators or numbers to yield a NumberGenerator.""" def __init__(self,lhs,rhs,operator,reverse=False,**args): + """Initialize a BinaryOperator with operands, an operator, and optional arguments. + + Args: + lhs: The left-hand side operand, which can be a NumberGenerator or a number. + rhs: The right-hand side operand, which can be a NumberGenerator or a number. + operator (Callable): The binary operator to apply to the operands. + reverse (bool, optional): If `True`, swaps the left and right operands. Defaults to `False`. + **args: Optional keyword arguments to pass to the operator when it is called. + + Notes + ----- + It is currently not possible to set parameters in the superclass during + initialization because `**args` is used by this class itself. """ - Accepts two NumberGenerator operands, an operator, and - optional arguments to be provided to the operator when calling - it on the two operands. - """ - # Note that it's currently not possible to set - # parameters in the superclass when creating an instance, - # because **args is used by this class itself. super().__init__() if reverse: @@ -174,14 +180,18 @@ class UnaryOperator(NumberGenerator): """Applies any unary operator to a NumberGenerator to yield another NumberGenerator.""" def __init__(self,operand,operator,**args): + """Initialize a UnaryOperator with an operand, operator, and optional arguments. + + Args: + operand (NumberGenerator): The NumberGenerator to which the operator is applied. + operator (Callable): The unary operator to apply to the operand. + **args: Optional keyword arguments to pass to the operator when it is called. + + Notes + ----- + It is currently not possible to set parameters in the superclass during + initialization because `**args` is used by this class itself. """ - Accepts a NumberGenerator operand, an operator, and - optional arguments to be provided to the operator when calling - it on the operand. - """ - # Note that it's currently not possible to set - # parameters in the superclass when creating an instance, - # because **args is used by this class itself. super().__init__() self.operand=operand @@ -330,7 +340,9 @@ class TimeAwareRandomState(TimeAware): def _initialize_random_state(self, seed=None, shared=True, name=None): """ - Initialization method to be called in the constructor of + Initialize the random state correctly. + + Method to be called in the constructor of subclasses to initialize the random state correctly. If seed is None, there is no control over the random stream diff --git a/param/_utils.py b/param/_utils.py index 6e5c51fd8..8af83282c 100644 --- a/param/_utils.py +++ b/param/_utils.py @@ -66,7 +66,19 @@ class Skip(Exception): def _deprecated(extra_msg="", warning_cat=ParamDeprecationWarning): def decorator(func): - """Internal decorator used to mark functions/methods as deprecated.""" + """Mark a function or method as deprecated. + + This internal decorator issues a warning when the decorated function + or method is called, indicating that it has been deprecated and will + be removed in a future version. + + Args: + func: The function or method to mark as deprecated. + + Returns + ------- + Callable: The wrapped function that issues a deprecation warning. + """ @functools.wraps(func) def inner(*args, **kwargs): msg = f"{func.__name__!r} has been deprecated and will be removed in a future version." @@ -81,11 +93,19 @@ def inner(*args, **kwargs): def _deprecate_positional_args(func): - """ - Internal decorator for methods that issues warnings for positional arguments - Using the keyword-only argument syntax in pep 3102, arguments after the - ``*`` will issue a warning when passed as a positional argument. - Adapted from scikit-learn. + """Issue warnings for methods using deprecated positional arguments. + + This internal decorator warns when arguments after the `*` separator + are passed as positional arguments, in accordance with PEP 3102. + It adapts the behavior from scikit-learn. + + Args: + func: The function to wrap with positional argument deprecation warnings. + + Returns + ------- + Callable: The wrapped function that issues warnings for deprecated + positional arguments. """ signature = inspect.signature(func) @@ -124,7 +144,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.""" + """Decorate a repr function to return a fill value for recursive calls.""" def decorating_function(user_function): repr_running = set() @@ -201,7 +221,10 @@ def _validate_error_prefix(parameter, attribute=None): def _is_mutable_container(value): - """True for mutable containers, which typically need special handling when being copied.""" + """Determine if the value is a mutable container. + + Mutable containers typically require special handling when being copied. + """ return isinstance(value, MUTABLE_TYPES) @@ -281,7 +304,7 @@ def flatten(line): def accept_arguments( f: Callable[Concatenate[CallableT, P], R] ) -> Callable[P, Callable[[CallableT], R]]: - """Decorator for decorators that accept arguments.""" + """Decorate a decorator to accept arguments.""" @functools.wraps(f) def _f(*args: P.args, **kwargs: P.kwargs) -> Callable[[CallableT], R]: return lambda actual_f: f(actual_f, *args, **kwargs) @@ -289,10 +312,9 @@ def _f(*args: P.args, **kwargs: P.kwargs) -> Callable[[CallableT], R]: def _produce_value(value_obj): - """ - A helper function that produces an actual parameter from a stored - object: if the object is callable, call it, otherwise return the - object. + """Produce an actual value from a stored object. + + If the object is callable, call it; otherwise, return the object. """ if callable(value_obj): return value_obj() @@ -303,10 +325,9 @@ def _produce_value(value_obj): # PARAM3_DEPRECATION @_deprecated(warning_cat=ParamFutureWarning) def produce_value(value_obj): - """ - A helper function that produces an actual parameter from a stored - object: if the object is callable, call it, otherwise return the - object. + """Produce an actual value from a stored object. + + If the object is callable, call it; otherwise, return the object. .. deprecated:: 2.0.0 """ @@ -556,9 +577,18 @@ def abbreviate_paths(pathspec,named_paths): def _to_datetime(x): - """ - Internal function that will convert date objs to datetime objs, used - for comparing date and datetime objects without error. + """Convert a date object to a datetime object for comparison. + + This internal function ensures that date and datetime objects can be + compared without errors by converting date objects to datetime objects. + + Args: + x: The object to convert, which may be a `date` or `datetime` object. + + Returns + ------- + datetime.datetime: A datetime object if the input was a date object; + otherwise, the input is returned unchanged. """ if isinstance(x, dt.date) and not isinstance(x, dt.datetime): return dt.datetime(*x.timetuple()[:6]) @@ -567,9 +597,19 @@ def _to_datetime(x): @contextmanager def exceptions_summarized(): - """ - Useful utility for writing docs that need to show expected errors. - Shows exception only, concisely, without a traceback. + """Context manager to display exceptions concisely without tracebacks. + + This utility is useful for writing documentation or examples where + only the exception type and message are needed, without the full + traceback. + + Yields + ------ + None: Allows the code inside the context to execute. + + Prints: + A concise summary of any exception raised, including the exception + type and message, to `sys.stderr`. """ try: yield @@ -616,9 +656,22 @@ def __iter__(cls): yield from cls.types() 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. + """Decorate a generator function to support type checking. + + This decorator modifies a generator function that yields different types + so that it can be used with `isinstance` and `issubclass`. + + Args: + gen_func (function): The generator function to decorate. + + Returns + ------- + type: A new type that supports `isinstance` and `issubclass` checks + based on the generator function's yielded types. + + Raises + ------ + TypeError: If the provided function is not a generator function. """ if not inspect.isgeneratorfunction(gen_func): msg = "gen_types decorator can only be applied to generator" diff --git a/param/ipython.py b/param/ipython.py index 13b8b5015..cc156f5ee 100644 --- a/param/ipython.py +++ b/param/ipython.py @@ -197,7 +197,7 @@ def _build_table(self, info, order, max_col_len=40, only_changed=False): def _tabulate(self, info_list, col_widths, changed, order, bounds_dict): """ - Returns the supplied information as a table suitable for + Return the supplied information as a table suitable for printing or paging. info_list: List of the parameters name, type and mode. @@ -320,13 +320,24 @@ def __init__(self, *args, **kwargs): @line_magic def params(self, parameter_s='', namespaces=None): - """ - The %params line magic accepts a single argument which is a - handle on the parameterized object to be inspected. If the - object can be found in the active namespace, information about - the object's parameters is displayed in the IPython pager. + """Display information about a parameterized object in the IPython pager. + + The `%params` line magic takes a single argument, which is a reference to + a parameterized object or class to be inspected. If the object is found in + the active namespace, information about its parameters is displayed in the + IPython pager. + + Usage: + %params + + Args: + parameter_s (str, optional): The name of the parameterized object to inspect. + Defaults to an empty string. + namespaces (optional): Additional namespaces to search for the object. - Usage: %params + Returns + ------- + None: Outputs the parameter information or error messages directly. """ if parameter_s=='': print("Please specify an object to inspect.") diff --git a/param/parameterized.py b/param/parameterized.py index 27439e049..a763c1ceb 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -121,7 +121,7 @@ def get_logger(name=None): def register_reference_transform(transform): """ - Appends a transform to extract potential parameter dependencies + Append a transform to extract potential parameter dependencies from an object. Arguments: @@ -133,7 +133,7 @@ def register_reference_transform(transform): def transform_reference(arg): """ - Applies transforms to turn objects which should be treated like + 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 @@ -147,7 +147,7 @@ def transform_reference(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 @@ -163,7 +163,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)): @@ -187,7 +187,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)] @@ -265,10 +265,20 @@ 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. - 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. + """Manage batching of watcher calls with optional queueing and execution. + + This internal version of `batch_call_watchers` allows control over whether + events are queued and whether accumulated watchers are executed upon exit. + + Args: + parameterized: The object whose watchers are being managed. + enable (bool, optional): If `True`, enable batching of events. Defaults to `True`. + run (bool, optional): If `True`, execute accumulated watchers on exit. + If `False`, they remain queued. Defaults to `True`. + + Yields + ------ + None: This is a context manager that temporarily modifies watcher behavior. """ BATCH_WATCH = parameterized.param._BATCH_WATCH parameterized.param._BATCH_WATCH = enable or parameterized.param._BATCH_WATCH @@ -519,7 +529,7 @@ def _f(self, obj, val): def get_method_owner(method): - """Gets the instance that owns the supplied method.""" + """Get the instance that owns the supplied method.""" if not inspect.ismethod(method): return None if isinstance(method, partial): @@ -530,7 +540,7 @@ def get_method_owner(method): # PARAM3_DEPRECATION def recursive_repr(fillvalue='...'): """ - Decorator to make a repr function return fillvalue for a recursive call. + Decorate to make a repr function return fillvalue for a recursive call. .. deprecated:: 1.12.0 """ @@ -632,7 +642,7 @@ def _output(*args,**kw): def _parse_dependency_spec(spec): """ - Parses param.depends string specifications into three components. + Parse param.depends string specifications into three components. The 3 components are: @@ -653,7 +663,8 @@ def _parse_dependency_spec(spec): def _params_depended_on(minfo, dynamic=True, intermediate=True): """ - Resolves dependencies declared on a Parameterized method. + Resolve dependencies declared on a Parameterized method. + Dynamic dependencies, i.e. dependencies on sub-objects which may or may not yet be available, are only resolved if dynamic=True. By default intermediate dependencies, i.e. dependencies on the @@ -682,7 +693,7 @@ def _params_depended_on(minfo, dynamic=True, intermediate=True): def _resolve_mcs_deps(obj, resolved, dynamic, intermediate=True): """ - Resolves constant and dynamic parameter dependencies previously + Resolve constant and dynamic parameter dependencies previously obtained using the _params_depended_on function. Existing resolved dependencies are updated with a supplied parameter instance while dynamic dependencies are resolved if possible. @@ -708,7 +719,8 @@ def _resolve_mcs_deps(obj, resolved, dynamic, intermediate=True): def _skip_event(*events, **kwargs): """ - Checks whether a subobject event should be skipped. + Check whether a subobject event should be skipped. + Returns True if all the values on the new subobject match the values on the previous subobject. """ @@ -771,7 +783,7 @@ def _sync_caller(*events, what='value', changed=None, callback=None, function=No def _m_caller(self, method_name, what='value', changed=None, callback=None): """ - Wraps a method call adding support for scheduling a callback + Wrap a method call adding support for scheduling a callback before it is executed and skipping events if a subobject has changed but its values have not. """ @@ -883,7 +895,20 @@ class Watcher(_Watcher): """ def __new__(cls_, *args, **kwargs): - """Allows creating Watcher without explicit precedence value.""" + """Create a new instance of the class, setting a default precedence value. + + This method allows creating a `Watcher` instance without explicitly + specifying a `precedence` value. If `precedence` is not provided, it + defaults to `0`. + + Args: + *args: Positional arguments to initialize the instance. + **kwargs: Keyword arguments to initialize the instance. + + Returns + ------- + An instance of the class with the specified or default values. + """ values = dict(zip(cls_._fields, args)) values.update(kwargs) if 'precedence' not in values: @@ -1568,14 +1593,40 @@ def __set__(self, obj, val): obj.param._batch_call_watchers() def _validate_value(self, value, allow_None): - """Implements validation for parameter value.""" + """Validate the parameter value against constraints. + + Args: + value: The value to be validated. + allow_None (bool): Whether `None` is allowed as a valid value. + + Raises + ------ + ValueError: If the value does not meet the parameter's constraints. + """ def _validate(self, val): - """Implements validation for the parameter value and attributes.""" + """Validate the parameter value and its attributes. + + This method ensures that the given value adheres to the parameter's + constraints and attributes. Subclasses can extend this method to + include additional validation logic. + + Args: + val: The value to be validated. + """ self._validate_value(val, self.allow_None) def _post_setter(self, obj, val): - """Called after the parameter value has been validated and set.""" + """Handle actions to be performed after setting a parameter value. + + This method is called after the parameter value has been validated + and assigned. Subclasses can override this method to implement + additional behavior post-assignment. + + Args: + obj: The object on which the parameter is being set. + val: The value that has been assigned to the parameter. + """ def __delete__(self,obj): raise TypeError("Cannot delete '%s': Parameters deletion not allowed." % self.name) @@ -1685,7 +1736,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): def as_uninitialized(fn): """ - Decorator: call fn with the parameterized_instance's + Decorate call fn with the parameterized_instance's initialization flag set to False, then revert the flag. (Used to decorate Parameterized methods that must alter @@ -1873,7 +1924,16 @@ def __setstate__(self, state): setattr(self, k, v) def __getitem__(self_, key): - """Returns the class or instance parameter.""" + """Retrieve the class or instance parameter by key. + + Args: + key: The name of the parameter to retrieve. + + Returns + ------- + The parameter associated with the given key. If accessed on an instance, + returns the instantiated parameter. + """ inst = self_.self if inst is None: return self_._cls_parameters[key] @@ -1881,18 +1941,40 @@ def __getitem__(self_, key): return _instantiated_parameter(inst, p) def __dir__(self_): - """Adds parameters to dir.""" + """Return the list of standard attributes and parameters. + + Returns + ------- + list: A combined list of standard attributes and parameter names. + """ return super().__dir__() + list(self_._cls_parameters) def __iter__(self_): - """Iterates over the parameters on this object.""" + """Iterate over the parameters on this object.""" yield from self_._cls_parameters def __contains__(self_, param): return param in self_._cls_parameters def __getattr__(self_, attr): - """Extends attribute access to parameter objects.""" + """Handle attribute access for parameter objects. + + This method extends standard attribute access to support parameters + defined in the object. If the requested attribute corresponds to a + parameter, it retrieves the parameter value. + + Args: + attr (str): The name of the attribute to access. + + Returns + ------- + The value of the parameter if it exists. + + Raises + ------ + AttributeError: If the class is not initialized or the attribute + does not exist in the parameter objects. + """ cls = self_.__dict__.get('cls') if cls is None: # Class not initialized raise AttributeError @@ -2204,7 +2286,9 @@ def callback(*events): def _watch_group(self_, obj, name, queued, group, attribute=None): """ - Sets up a watcher for a group of dependencies. Ensures that + Set up a watcher for a group of dependencies. + + Ensures that if the dependency was dynamically generated we check whether a subobject change event actually causes a value change and that we update the existing watchers, i.e. clean up watchers @@ -2498,7 +2582,7 @@ def _cls_parameters(self_): def objects(self_, instance=True): """ - Returns the Parameters of this instance or class. + Return the Parameters of this instance or class. If instance=True and called on a Parameterized instance it will create instance parameters for all Parameters defined on @@ -2561,7 +2645,7 @@ def trigger(self_, *param_names): self_._state_watchers += watchers def _update_event_type(self_, watcher, event, triggered): - """Returns an updated Event object with the type field set appropriately.""" + """Return an updated Event object with the type field set appropriately.""" if triggered: event_type = 'triggered' else: @@ -2767,7 +2851,7 @@ def deserialize_value(self_, pname, value, mode='json'): return serializer.deserialize_parameter_value(self_or_cls, pname, value) def schema(self_, safe=False, subset=None, mode='json'): - """Returns a schema for the parameters on this Parameterized object.""" + """Return a schema for the parameters on this Parameterized object.""" 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}') @@ -2938,7 +3022,7 @@ def params_depended_on(self_, *args, **kwargs): def outputs(self_): """ - Returns a mapping between any declared outputs and a tuple + Return a mapping between any declared outputs and a tuple of the declared Parameter type, the output method, and the index into the output if multiple outputs are returned. """ @@ -2957,7 +3041,7 @@ def outputs(self_): def _spec_to_obj(self_, spec, dynamic=True, intermediate=True): """ - Resolves a dependency specification into lists of explicit + Resolve a dependency specification into lists of explicit parameter dependencies and dynamic dependencies. Dynamic dependencies are specifications to be resolved when @@ -3191,7 +3275,7 @@ def defaults(self_): # verbose(), debug(), etc are taking advantage of this. def __db_print(self_,level,msg,*args,**kw): """ - Calls the logger returned by the get_logger() function, + Call the logger returned by the get_logger() function, prepending the result of calling dbprint_prefix() (if any). See python's logging module for details. @@ -3625,18 +3709,19 @@ def _get_param(mcs): param = property(_get_param) def __setattr__(mcs, attribute_name, value): - """ - Implements 'self.attribute_name=value' in a way that also supports Parameters. + """Set an attribute, supporting special behavior for Parameters. + + If the attribute being set corresponds to a Parameter descriptor and the + new value is not a Parameter, the descriptor's `__set__` method is invoked + with the provided value. This ensures proper handling of Parameter values. - If there is already a descriptor named attribute_name, and - that descriptor is a Parameter, and the new value is *not* a - Parameter, then call that Parameter's __set__ method with the - specified value. + In all other cases, the attribute is set normally. If the new value is a + Parameter, the method ensures that the value is inherited correctly from + Parameterized superclasses as described in `__param_inheritance()`. - In all other cases set the attribute normally (i.e. overwrite - the descriptor). If the new value is a Parameter, once it has - been set we make sure that the value is inherited from - Parameterized superclasses as described in __param_inheritance(). + Args: + attribute_name (str): The name of the attribute to set. + value: The value to assign to the attribute. """ # Find out if there's a Parameter called attribute_name as a # class attribute of this class - if not, parameter is None. @@ -4642,9 +4727,21 @@ def __reduce__(self): def _pprint(self, imports=None, prefix="\n ",unknown_value='', qualify=False, separator=""): - """ - Same as self.param.pprint, except that X.classname(Y - is replaced with X.classname.instance(Y. + """Pretty-print the object with adjustments for instance representation. + + This method is similar to `self.param.pprint`, but replaces + `X.classname(Y` with `X.classname.instance(Y`. + + Args: + imports (optional): Additional imports to include in the output. + prefix (str, optional): String prefix for each line of the output. + unknown_value (str, optional): Placeholder for unknown values. Defaults to ''. + qualify (bool, optional): Whether to include full qualification for names. + separator (str, optional): String separator for elements. + + Returns + ------- + str: The formatted string representation of the object. """ r = self.param.pprint(imports,prefix, unknown_value=unknown_value, diff --git a/param/parameters.py b/param/parameters.py index d0791cff5..0216f81bc 100644 --- a/param/parameters.py +++ b/param/parameters.py @@ -703,9 +703,15 @@ def __init__(self, default=Undefined, *, bounds=Undefined, softbounds=Undefined, self._validate(self.default) def __get__(self, obj, objtype): - """ - Same as the superclass's __get__, but if the value was - dynamically generated, check the bounds. + """Retrieve the value of the attribute, checking bounds if dynamically generated. + + Args: + obj: The instance the attribute is accessed on, or `None` for class access. + objtype: The class that owns the attribute. + + Returns + ------- + The value of the attribute, potentially after applying bounds checks. """ result = super().__get__(obj, objtype) @@ -820,7 +826,7 @@ def _validate_step(self, val, step): def _validate(self, val): """ - Checks that the value is numeric and that it is within the hard + Check that the value is numeric and that it is within the hard bounds; if not, an exception is raised. """ self._validate_value(val, self.allow_None) @@ -907,7 +913,7 @@ def __init__(self, default=Undefined, **kwargs): def _validate_value(self, val, allow_None): """ - Checks that the value is numeric and that it is within the hard + Check that the value is numeric and that it is within the hard bounds; if not, an exception is raised. """ if self.allow_None and val is None: @@ -966,7 +972,7 @@ def __init__(self, default=Undefined, **kwargs): def _validate_value(self, val, allow_None): """ - Checks that the value is numeric and that it is within the hard + Check that the value is numeric and that it is within the hard bounds; if not, an exception is raised. """ if self.allow_None and val is None: @@ -2498,7 +2504,7 @@ def __init__(self, default=Undefined, *, class_=Undefined, item_type=Undefined, def _validate(self, val): """ - Checks that the value is numeric and that it is within the hard + Check that the value is numeric and that it is within the hard bounds; if not, an exception is raised. """ self._validate_value(val, self.allow_None) @@ -2506,7 +2512,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.""" + """Check 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 diff --git a/param/reactive.py b/param/reactive.py index 19cccd695..634298129 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -213,20 +213,33 @@ def _as_rx(self): return self._reactive if isinstance(self._reactive, rx) else self() def __call__(self): - """Creates a reactive expression.""" + """Create a reactive expression.""" rxi = self._reactive return rxi if isinstance(rx, rx) else rx(rxi) def and_(self, other): - """Replacement for the ``and`` statement.""" + """Perform a logical AND operation with the given operand. + + Args: + other: The operand to combine with using the AND operation. + + Returns + ------- + The result of applying the AND operation. + """ return self._as_rx()._apply_operator(lambda obj, other: obj and other, other) def bool(self): - """__bool__ cannot be implemented so it is provided as a method.""" + """Evaluate the truthiness of the current object. + + Returns + ------- + The boolean value of the object. + """ return self._as_rx()._apply_operator(bool) def buffer(self, n): - """Collects the last n items that were emitted.""" + """Collect the last n items that were emitted.""" items = [] def collect(new, n): items.append(new) @@ -236,15 +249,39 @@ def collect(new, n): return self._as_rx()._apply_operator(collect, n) def in_(self, other): - """Replacement for the ``in`` statement.""" + """Check if the current object is contained "in" the given operand. + + Args: + other: The operand to check for containment. + + Returns + ------- + The result of the containment check. + """ return self._as_rx()._apply_operator(operator.contains, other, reverse=True) def is_(self, other): - """Replacement for the ``is`` statement.""" + """Perform a logical "is" comparison with the given operand. + + Args: + other: The operand to compare against. + + Returns + ------- + The result of the "is" comparison. + """ return self._as_rx()._apply_operator(operator.is_, other) def is_not(self, other): - """Replacement for the ``is not`` statement.""" + """Perform a logical "is not" comparison with the given operand. + + Args: + other: The operand to compare against. + + Returns + ------- + The result of the "is not" comparison. + """ return self._as_rx()._apply_operator(operator.is_not, other) def len(self): @@ -279,11 +316,24 @@ def apply(vs, *args, **kwargs): return self._as_rx()._apply_operator(apply, *args, **kwargs) def not_(self): - """__bool__ cannot be implemented so not has to be provided as a method.""" + """Perform a logical NOT operation. + + Returns + ------- + The result of applying the NOT operation. + """ return self._as_rx()._apply_operator(operator.not_) def or_(self, other): - """Replacement for the ``or`` statement.""" + """Perform a logical OR operation with the given operand. + + Args: + other: The operand to combine with using the OR operation. + + Returns + ------- + The result of applying the OR operation. + """ return self._as_rx()._apply_operator(lambda obj, other: obj or other, other) def pipe(self, func, /, *args, **kwargs): @@ -304,7 +354,7 @@ def pipe(self, func, /, *args, **kwargs): def resolve(self, nested=True, recursive=False): """ - Resolves references held by the expression. + Resolve references held by the expression. As an example if the expression returns a list of parameters this operation will return a list of the parameter values. @@ -325,7 +375,7 @@ def resolve(self, nested=True, recursive=False): return resolver.param.value.rx() def updating(self): - """Returns a new expression that is True while the expression is updating.""" + """Return a new expression that is True while the expression is updating.""" wrapper = Wrapper(object=False) self._watch(lambda e: wrapper.param.update(object=True), precedence=-999) self._watch(lambda e: wrapper.param.update(object=False), precedence=999) @@ -333,7 +383,7 @@ def updating(self): def when(self, *dependencies, initial=Undefined): """ - Returns a reactive expression that emits the contents of this + Return a reactive expression that emits the contents of this expression only when the dependencies change. If initial value is provided and the dependencies are all param.Event types the expression will not be evaluated until the first event is @@ -361,8 +411,10 @@ def eval(*_, evaluated=[]): def where(self, x, y): """ - Returns either x or y depending on the current state of the - expression, i.e. replaces a ternary if statement. + Return either x or y depending on the current state of the + expression. + + Replaces a ternary if statement. Arguments: --------- @@ -411,7 +463,7 @@ def value(self): @value.setter def value(self, new): - """Allows overriding the original input to the pipeline.""" + """Override the original input to the pipeline.""" if isinstance(self._reactive, Parameter): raise AttributeError( "`Parameter.rx.value = value` is not supported. Cannot override " @@ -440,7 +492,7 @@ def value(self, new): def watch(self, fn=None, onlychanged=True, queued=False, precedence=0): """ - Adds a callable that observes the output of the pipeline. + Add a callable that observes the output of the pipeline. If no callable is provided this simply causes the expression to be eagerly evaluated. """ @@ -644,7 +696,7 @@ def register_accessor( predicate: Optional[Callable[[Any], bool]] = None ): """ - Registers an accessor that extends rx with custom behavior. + Register an accessor that extends rx with custom behavior. Arguments: --------- @@ -661,8 +713,9 @@ def register_accessor( @classmethod def register_display_handler(cls, obj_type, handler, **kwargs): """ - Registers a display handler for a specific type of object, - making it possible to define custom display options for + Register a display handler for a specific type of object. + + Makes it possible to define custom display options for specific objects. Arguments: @@ -681,7 +734,7 @@ def register_display_handler(cls, obj_type, handler, **kwargs): @classmethod def register_method_handler(cls, method, handler): """ - Registers a handler that is called when a specific method on + Register a handler that is called when a specific method on an object is called. """ cls._method_handlers[method] = handler @@ -975,7 +1028,7 @@ def _resolve(self): return current def _transform_output(self, obj): - """Applies custom display handlers before their output.""" + """Apply custom display handlers before their output.""" applies = False for predicate, (handler, opts) in self._display_handlers.items(): display_opts = { diff --git a/param/serializer.py b/param/serializer.py index 664f568be..795964181 100644 --- a/param/serializer.py +++ b/param/serializer.py @@ -112,7 +112,7 @@ def deserialize_parameters(cls, pobj, serialization, subset=None): @classmethod def _get_method(cls, ptype, suffix): - """Returns specialized method if available, otherwise None.""" + """Return specialized method if available, otherwise None.""" method_name = ptype.lower()+'_' + suffix return getattr(cls, method_name, None) diff --git a/param/version.py b/param/version.py index ebaafee2f..b43e4f5d9 100644 --- a/param/version.py +++ b/param/version.py @@ -155,7 +155,7 @@ def dirty(self): def fetch(self): """ - Returns a tuple of the major version together with the + Return a tuple of the major version together with the appropriate SHA and dirty bit (for development version only). """ if self._release is not None: @@ -228,6 +228,8 @@ def git_fetch(self, cmd='git', as_string=False): def _known_stale(self): """ + Return whether the commit is know to be stale or not. + The commit is known to be from a file (and therefore stale) if a SHA is supplied by git archive and doesn't match the parsed commit. """ @@ -361,7 +363,7 @@ def verify(self, string_version=None): def get_setup_version(cls, setup_path, reponame, describe=False, dirty='report', pkgname=None, archive_commit=None): """ - Helper for use in setup.py to get the version from the .version file (if available) + Get the version from the .version file (if available) or more up-to-date information from git describe (if available). Assumes the __init__.py will be found in the directory @@ -459,8 +461,8 @@ def setup_version(cls, setup_path, reponame, archive_commit=None, def get_setup_version(location, reponame, pkgname=None, archive_commit=None): """ - Helper for use in setup.py to get the current version from either - git describe or the .version file (if available). + Get the current version from either git describe or the + .version file (if available). Set pkgname to the package name if it is different from the repository name. @@ -620,7 +622,7 @@ def dirty(self): def fetch(self): """ - Returns a tuple of the major version together with the + Return a tuple of the major version together with the appropriate SHA and dirty bit (for development version only). """ if self._release is not None: diff --git a/pyproject.toml b/pyproject.toml index 60b8ad141..835a31e0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -128,7 +128,6 @@ ignore = [ "D105", # Missing docstring in magic method" "D107", # Missing docstring in `__init__`" "D205", # 1 blank line required between summary line and description - "D401", # First line of docstring should be in imperative mood: "Returns the last n lines captured at the given level" "D415", # First line should end with a period, question mark, or exclamation point "D417", # Missing argument description in the docstring for `param_union`: `*parameterizeds` "E402", # Module level import not at top of file diff --git a/tests/testdeprecations.py b/tests/testdeprecations.py index 6cb643c05..a4e4162a0 100644 --- a/tests/testdeprecations.py +++ b/tests/testdeprecations.py @@ -7,7 +7,7 @@ @pytest.fixture(autouse=True) def specific_filter(): - """Used to make sure warnings are set up with the right stacklevel.""" + """Make sure warnings are set up with the right stacklevel.""" with warnings.catch_warnings(): warnings.simplefilter('ignore') warnings.filterwarnings('error', module=__name__) diff --git a/tests/utils.py b/tests/utils.py index 51424d5e4..0201ff0fc 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -49,7 +49,7 @@ def reset(self): self.release() def tail(self, level, n=1): - """Returns the last n lines captured at the given level.""" + """Return 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 bf9c27e989c17887f8baafef8d9f9af6ee0985f9 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Fri, 27 Dec 2024 07:42:35 +0000 Subject: [PATCH 03/15] add package docstrings --- benchmarks/benchmarks/__init__.py | 1 + param/__init__.py | 64 ++++++++++++++++++++++++++----- pyproject.toml | 2 - tests/__init__.py | 1 + 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/benchmarks/benchmarks/__init__.py b/benchmarks/benchmarks/__init__.py index e69de29bb..48b385e68 100644 --- a/benchmarks/benchmarks/__init__.py +++ b/benchmarks/benchmarks/__init__.py @@ -0,0 +1 @@ +"""Benchmark package.""" diff --git a/param/__init__.py b/param/__init__.py index acbaec83b..120046406 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -1,17 +1,61 @@ + +""" +Param: A declarative framework for managing parameters and reactive programming in Python. + +Param is a lightweight library for defining and managing user-modifiable parameters, +designed to simplify Python programs and enhance their readability, maintainability, +and robustness. In addition Param provides the `rx` framework for reactive programming. + +Examples +-------- +Here is an example of using `param.Parameterized` to define a class with validated parameters: + +>>> import param +>>> class MyClass(param.Parameterized): +... my_number = param.Number(default=1, bounds=(0, 10)) +... my_list = param.List(default=[1, 2, 3], item_type=int) + +>>> obj = MyClass() +>>> obj.my_number = 5 # Valid +>>> obj.my_number = 15 # Raises ValueError: must be in range (0, 10) + +Here is an example of using `param.rx` to define a reactive expression: + +>>> import param +>>> rx_value = param.rx([1,2,3]) +>>> rx_value.rx.len() +3 + +Lets update the reactive value and check its length: + +>>> rx_value.rx.value = [1,2,3,4] +>>> rx_value.rx.len() +4 + +Documentation +------------- +For detailed documentation, see https://param.holoviz.org/. + +Notes +----- +Param is well-suited for use in scientific computing, data analysis tools, +graphical user interfaces (GUIs), and any Python application where well-defined, +validated parameters are needed. +""" import os -from . import version # noqa: api import -from .depends import depends # noqa: api import -from .parameterized import ( # noqa: api import +from . import version +from .depends import depends +from .parameterized import ( Parameterized, Parameter, Skip, String, ParameterizedFunction, ParamOverrides, Undefined, get_logger ) -from .parameterized import (batch_watch, output, script_repr, # noqa: api import +from .parameterized import (batch_watch, output, script_repr, discard_events, edit_constant) -from .parameterized import shared_parameters # noqa: api import -from .parameterized import logging_level # noqa: api import -from .parameterized import DEBUG, VERBOSE, INFO, WARNING, ERROR, CRITICAL # noqa: api import -from .parameters import ( # noqa: api import +from .parameterized import shared_parameters +from .parameterized import logging_level +from .parameterized import DEBUG, VERBOSE, INFO, WARNING, ERROR, CRITICAL +from .parameters import ( guess_param_types, param_union, parameterized_class, @@ -58,8 +102,8 @@ CalendarDateRange, Event, ) -from .reactive import bind, rx # noqa: api import -from ._utils import ( # noqa: api import +from .reactive import bind, rx +from ._utils import ( produce_value, as_unicode, is_ordered_dict, diff --git a/pyproject.toml b/pyproject.toml index 835a31e0d..6aab2a662 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -124,9 +124,7 @@ ignore = [ "D101", # Missing docstring in public class" "D102", # Missing docstring in public method "D103", # Missing docstring in public function - "D104", # Missing docstring in public package" "D105", # Missing docstring in magic method" - "D107", # Missing docstring in `__init__`" "D205", # 1 blank line required between summary line and description "D415", # First line should end with a period, question mark, or exclamation point "D417", # Missing argument description in the docstring for `param_union`: `*parameterizeds` diff --git a/tests/__init__.py b/tests/__init__.py index e69de29bb..38bb211b0 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Test package.""" From fcd87c0c4559f0a5fdd97aeb807206c9a5a3c181 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Sat, 28 Dec 2024 06:44:45 +0000 Subject: [PATCH 04/15] improve package docstring --- param/__init__.py | 18 ++++++++---------- script.py | 1 + 2 files changed, 9 insertions(+), 10 deletions(-) create mode 100644 script.py diff --git a/param/__init__.py b/param/__init__.py index 120046406..f2c481fa7 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -6,6 +6,14 @@ designed to simplify Python programs and enhance their readability, maintainability, and robustness. In addition Param provides the `rx` framework for reactive programming. +Param is well-suited for use in scientific computing, data analysis tools, +graphical user interfaces (GUIs), and any Python application where well-defined, +validated parameters are needed. + +Documentation +------------- +For detailed documentation, see https://param.holoviz.org/. + Examples -------- Here is an example of using `param.Parameterized` to define a class with validated parameters: @@ -31,16 +39,6 @@ >>> rx_value.rx.value = [1,2,3,4] >>> rx_value.rx.len() 4 - -Documentation -------------- -For detailed documentation, see https://param.holoviz.org/. - -Notes ------ -Param is well-suited for use in scientific computing, data analysis tools, -graphical user interfaces (GUIs), and any Python application where well-defined, -validated parameters are needed. """ import os diff --git a/script.py b/script.py new file mode 100644 index 000000000..6c5512925 --- /dev/null +++ b/script.py @@ -0,0 +1 @@ +import param \ No newline at end of file From d1ca89e455ea95af305b9eabb4b7f8035d780d04 Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Sat, 28 Dec 2024 06:45:10 +0000 Subject: [PATCH 05/15] remove script file --- script.py | 1 - 1 file changed, 1 deletion(-) delete mode 100644 script.py diff --git a/script.py b/script.py deleted file mode 100644 index 6c5512925..000000000 --- a/script.py +++ /dev/null @@ -1 +0,0 @@ -import param \ No newline at end of file From dcbe46816f4e2008cc857959ccc777915d4bf51a Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 16:02:05 +0100 Subject: [PATCH 06/15] Switch to NumPy style --- numbergen/__init__.py | 74 ++++++++++++++------------ param/_utils.py | 53 +++++++++++-------- param/ipython.py | 13 +++-- param/parameterized.py | 113 +++++++++++++++++++++++++--------------- param/parameters.py | 11 ++-- param/reactive.py | 114 ++++++++++++++++++++++++++++------------- pyproject.toml | 1 + 7 files changed, 239 insertions(+), 140 deletions(-) diff --git a/numbergen/__init__.py b/numbergen/__init__.py index 881941c5a..b08d3730a 100644 --- a/numbergen/__init__.py +++ b/numbergen/__init__.py @@ -138,25 +138,30 @@ def pprint(x, *args, **kwargs): class BinaryOperator(NumberGenerator): - """Applies any binary operator to NumberGenerators or numbers to yield a NumberGenerator.""" - - def __init__(self,lhs,rhs,operator,reverse=False,**args): - """Initialize a BinaryOperator with operands, an operator, and optional arguments. - - Args: - lhs: The left-hand side operand, which can be a NumberGenerator or a number. - rhs: The right-hand side operand, which can be a NumberGenerator or a number. - operator (Callable): The binary operator to apply to the operands. - reverse (bool, optional): If `True`, swaps the left and right operands. Defaults to `False`. - **args: Optional keyword arguments to pass to the operator when it is called. - - Notes - ----- - It is currently not possible to set parameters in the superclass during - initialization because `**args` is used by this class itself. - """ - super().__init__() + """ + Applies any binary operator to NumberGenerators or numbers to yield a NumberGenerator. + + Parameters + ---------- + lhs: NumberGenerator or Number + The left-hand side operand, which can be a NumberGenerator or a number. + rhs: NumberGenerator or Number + The right-hand side operand, which can be a NumberGenerator or a number. + operator : callable + The binary operator to apply to the operands. + reverse : bool, optional + If `True`, swaps the left and right operands. Defaults to `False`. + **args: + Optional keyword arguments to pass to the operator when it is called. + Notes + ----- + It is currently not possible to set parameters in the superclass during + initialization because `**args` is used by this class itself. + """ + + def __init__(self,lhs, rhs, operator, reverse=False, **args): + super().__init__() if reverse: self.lhs=rhs self.rhs=lhs @@ -177,21 +182,25 @@ def pprint(self, *args, **kwargs): class UnaryOperator(NumberGenerator): - """Applies any unary operator to a NumberGenerator to yield another NumberGenerator.""" + """ + Applies any unary operator to a NumberGenerator to yield another NumberGenerator. - def __init__(self,operand,operator,**args): - """Initialize a UnaryOperator with an operand, operator, and optional arguments. + Parameters + ---------- + operand : NumberGenerator + The NumberGenerator to which the operator is applied. + operator : callable + The unary operator to apply to the operand. + **args: + Optional keyword arguments to pass to the operator when it is called. - Args: - operand (NumberGenerator): The NumberGenerator to which the operator is applied. - operator (Callable): The unary operator to apply to the operand. - **args: Optional keyword arguments to pass to the operator when it is called. + Notes + ----- + It is currently not possible to set parameters in the superclass during + initialization because `**args` is used by this class itself. + """ - Notes - ----- - It is currently not possible to set parameters in the superclass during - initialization because `**args` is used by this class itself. - """ + def __init__(self, operand, operator, **args): super().__init__() self.operand=operand @@ -247,7 +256,6 @@ def _rational(self, val): numer, denom = frac.numerator, frac.denominator return numer % I32, denom % I32 - def __getstate__(self): """Avoid Hashlib.md5 TypeError in deepcopy (hashlib issue).""" d = self.__dict__.copy() @@ -255,7 +263,6 @@ def __getstate__(self): d.pop('_hash_struct') return d - def __setstate__(self, d): self._digest = hashlib.md5() name, input_count = d['name'], d['input_count'] @@ -263,7 +270,6 @@ def __setstate__(self, d): self._hash_struct = struct.Struct( "!" +" ".join(["I"] * (input_count * 2))) self.__dict__.update(d) - def __call__(self, *vals): """ Given integer or rational inputs, generate a cross-platform, @@ -439,7 +445,7 @@ class RandomDistribution(NumberGenerator, TimeAwareRandomState): __abstract = True - def __init__(self,**params): + def __init__(self, **params): """ Initialize a new Random() instance and store the supplied positional and keyword arguments. diff --git a/param/_utils.py b/param/_utils.py index 8af83282c..806b3f429 100644 --- a/param/_utils.py +++ b/param/_utils.py @@ -61,9 +61,11 @@ class ParamFutureWarning(ParamWarning, FutureWarning): Always displayed. """ + class Skip(Exception): """Exception that allows skipping an update when resolving a reference.""" + def _deprecated(extra_msg="", warning_cat=ParamDeprecationWarning): def decorator(func): """Mark a function or method as deprecated. @@ -72,12 +74,15 @@ def decorator(func): or method is called, indicating that it has been deprecated and will be removed in a future version. - Args: - func: The function or method to mark as deprecated. + Parameters + ---------- + func: FunctionType | MethodType + The function or method to mark as deprecated. Returns ------- - Callable: The wrapped function that issues a deprecation warning. + callable: + The wrapped function that issues a deprecation warning. """ @functools.wraps(func) def inner(*args, **kwargs): @@ -99,12 +104,15 @@ def _deprecate_positional_args(func): are passed as positional arguments, in accordance with PEP 3102. It adapts the behavior from scikit-learn. - Args: - func: The function to wrap with positional argument deprecation warnings. + Parameters + ---------- + func: FunctionType | MethodType + The function to wrap with positional argument deprecation warnings. Returns ------- - Callable: The wrapped function that issues warnings for deprecated + callable: + The wrapped function that issues warnings for deprecated positional arguments. """ signature = inspect.signature(func) @@ -219,7 +227,6 @@ def _validate_error_prefix(parameter, attribute=None): pass return ' '.join(out) - def _is_mutable_container(value): """Determine if the value is a mutable container. @@ -227,7 +234,6 @@ def _is_mutable_container(value): """ return isinstance(value, MUTABLE_TYPES) - def full_groupby(l, key=lambda x: x): """Groupby implementation which does not require a prior sort.""" d = defaultdict(list) @@ -235,7 +241,6 @@ def full_groupby(l, key=lambda x: x): d[key(item)].append(item) return d.items() - def iscoroutinefunction(function): """Whether the function is an asynchronous generator or a coroutine.""" # Partial unwrapping not required starting from Python 3.11.0 @@ -582,12 +587,15 @@ def _to_datetime(x): This internal function ensures that date and datetime objects can be compared without errors by converting date objects to datetime objects. - Args: - x: The object to convert, which may be a `date` or `datetime` object. + Parameters + ---------- + x: Any + The object to convert, which may be a `date` or `datetime` object. Returns ------- - datetime.datetime: A datetime object if the input was a date object; + datetime.datetime: + A datetime object if the input was a date object; otherwise, the input is returned unchanged. """ if isinstance(x, dt.date) and not isinstance(x, dt.datetime): @@ -605,11 +613,13 @@ def exceptions_summarized(): Yields ------ - None: Allows the code inside the context to execute. + None: + Allows the code inside the context to execute. - Prints: - A concise summary of any exception raised, including the exception - type and message, to `sys.stderr`. + Prints + ------ + A concise summary of any exception raised, including the exception + type and message, to `sys.stderr`. """ try: yield @@ -661,17 +671,20 @@ def gen_types(gen_func): This decorator modifies a generator function that yields different types so that it can be used with `isinstance` and `issubclass`. - Args: - gen_func (function): The generator function to decorate. + Parameters + ---------- + gen_func : GeneratorType + The generator function to decorate. Returns ------- - type: A new type that supports `isinstance` and `issubclass` checks + type: + A new type that supports `isinstance` and `issubclass` checks based on the generator function's yielded types. Raises ------ - TypeError: If the provided function is not a generator function. + TypeError: If the provided function is not a generator function. """ if not inspect.isgeneratorfunction(gen_func): msg = "gen_types decorator can only be applied to generator" diff --git a/param/ipython.py b/param/ipython.py index cc156f5ee..f7ee03532 100644 --- a/param/ipython.py +++ b/param/ipython.py @@ -330,14 +330,17 @@ def params(self, parameter_s='', namespaces=None): Usage: %params - Args: - parameter_s (str, optional): The name of the parameterized object to inspect. - Defaults to an empty string. - namespaces (optional): Additional namespaces to search for the object. + Argsuments + ---------- + parameter_s : str, optional + The name of the parameterized object to inspect. Defaults to an empty string. + namespaces : dict, optional + Additional namespaces to search for the object. Returns ------- - None: Outputs the parameter information or error messages directly. + None: + Outputs the parameter information or error messages to stdout. """ if parameter_s=='': print("Please specify an object to inspect.") diff --git a/param/parameterized.py b/param/parameterized.py index a763c1ceb..4efbb3e39 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -124,8 +124,8 @@ def register_reference_transform(transform): Append a transform to extract potential parameter dependencies from an object. - Arguments: - --------- + Parameters + ---------- transform: Callable[Any, Any] """ @@ -270,15 +270,20 @@ def _batch_call_watchers(parameterized, enable=True, run=True): This internal version of `batch_call_watchers` allows control over whether events are queued and whether accumulated watchers are executed upon exit. - Args: - parameterized: The object whose watchers are being managed. - enable (bool, optional): If `True`, enable batching of events. Defaults to `True`. - run (bool, optional): If `True`, execute accumulated watchers on exit. - If `False`, they remain queued. Defaults to `True`. + Parameters + ---------- + parameterized : object + The object whose watchers are being managed. + enable : bool, optional + If `True`, enable batching of events. Defaults to `True`. + run : bool, optional + If `True`, execute accumulated watchers on exit. + If `False`, they remain queued. Defaults to `True`. Yields ------ - None: This is a context manager that temporarily modifies watcher behavior. + None: + This is a context manager that temporarily modifies watcher behavior. """ BATCH_WATCH = parameterized.param._BATCH_WATCH parameterized.param._BATCH_WATCH = enable or parameterized.param._BATCH_WATCH @@ -901,13 +906,16 @@ def __new__(cls_, *args, **kwargs): specifying a `precedence` value. If `precedence` is not provided, it defaults to `0`. - Args: - *args: Positional arguments to initialize the instance. - **kwargs: Keyword arguments to initialize the instance. + Parameters + ---------- + *args : Any + Positional arguments to initialize the instance. + **kwargs : Any + Keyword arguments to initialize the instance. Returns ------- - An instance of the class with the specified or default values. + An instance of the Watcher with the specified or default values. """ values = dict(zip(cls_._fields, args)) values.update(kwargs) @@ -922,7 +930,6 @@ def __str__(self): - class ParameterMetaclass(type): """Metaclass allowing control over creation of Parameter classes.""" @@ -1595,13 +1602,17 @@ def __set__(self, obj, val): def _validate_value(self, value, allow_None): """Validate the parameter value against constraints. - Args: - value: The value to be validated. - allow_None (bool): Whether `None` is allowed as a valid value. + Parameters + ---------- + value : Any + The value to be validated. + allow_None : bool + Whether `None` is allowed as a valid value. Raises ------ - ValueError: If the value does not meet the parameter's constraints. + ValueError + If the value does not meet the parameter's constraints. """ def _validate(self, val): @@ -1611,8 +1622,10 @@ def _validate(self, val): constraints and attributes. Subclasses can extend this method to include additional validation logic. - Args: - val: The value to be validated. + Parameters + ---------- + val: Any + The value to be validated. """ self._validate_value(val, self.allow_None) @@ -1623,9 +1636,12 @@ def _post_setter(self, obj, val): and assigned. Subclasses can override this method to implement additional behavior post-assignment. - Args: - obj: The object on which the parameter is being set. - val: The value that has been assigned to the parameter. + Parameters + ---------- + obj : Parameterized + The object on which the parameter is being set. + val : Any + The value that has been assigned to the parameter. """ def __delete__(self,obj): @@ -1926,11 +1942,14 @@ def __setstate__(self, state): def __getitem__(self_, key): """Retrieve the class or instance parameter by key. - Args: - key: The name of the parameter to retrieve. + Parameters + ---------- + key: str + The name of the parameter to retrieve. Returns ------- + Parameter: The parameter associated with the given key. If accessed on an instance, returns the instantiated parameter. """ @@ -1945,7 +1964,8 @@ def __dir__(self_): Returns ------- - list: A combined list of standard attributes and parameter names. + list[str]: + A combined list of standard attributes and parameter names. """ return super().__dir__() + list(self_._cls_parameters) @@ -1963,17 +1983,20 @@ def __getattr__(self_, attr): defined in the object. If the requested attribute corresponds to a parameter, it retrieves the parameter value. - Args: - attr (str): The name of the attribute to access. + Parameters + ---------- + attr : str + The name of the attribute to access. Returns ------- - The value of the parameter if it exists. + The value of the parameter if it exists. Raises ------ - AttributeError: If the class is not initialized or the attribute - does not exist in the parameter objects. + AttributeError + If the class is not initialized or the attribute does not exist in + the parameter objects. """ cls = self_.__dict__.get('cls') if cls is None: # Class not initialized @@ -3719,9 +3742,12 @@ def __setattr__(mcs, attribute_name, value): Parameter, the method ensures that the value is inherited correctly from Parameterized superclasses as described in `__param_inheritance()`. - Args: - attribute_name (str): The name of the attribute to set. - value: The value to assign to the attribute. + Parameters + ---------- + attribute_name : str + The name of the attribute to set. + value: Any + The value to assign to the attribute. """ # Find out if there's a Parameter called attribute_name as a # class attribute of this class - if not, parameter is None. @@ -4732,16 +4758,23 @@ def _pprint(self, imports=None, prefix="\n ",unknown_value='', This method is similar to `self.param.pprint`, but replaces `X.classname(Y` with `X.classname.instance(Y`. - Args: - imports (optional): Additional imports to include in the output. - prefix (str, optional): String prefix for each line of the output. - unknown_value (str, optional): Placeholder for unknown values. Defaults to ''. - qualify (bool, optional): Whether to include full qualification for names. - separator (str, optional): String separator for elements. + Parameters + ---------- + imports : optional + Additional imports to include in the output. + prefix : str, optional + String prefix for each line of the output. + unknown_value : str, optional + Placeholder for unknown values. Defaults to ''. + qualify : bool, optional + Whether to include full qualification for names. + separator : str, optional + String separator for elements. Returns ------- - str: The formatted string representation of the object. + str + The formatted string representation of the object. """ r = self.param.pprint(imports,prefix, unknown_value=unknown_value, diff --git a/param/parameters.py b/param/parameters.py index 0216f81bc..3d6447961 100644 --- a/param/parameters.py +++ b/param/parameters.py @@ -705,13 +705,16 @@ def __init__(self, default=Undefined, *, bounds=Undefined, softbounds=Undefined, def __get__(self, obj, objtype): """Retrieve the value of the attribute, checking bounds if dynamically generated. - Args: - obj: The instance the attribute is accessed on, or `None` for class access. - objtype: The class that owns the attribute. + Arguments + --------- + obj: Parameterized | None + The instance the attribute is accessed on, or `None` for class access. + objtype: type[Parameterized] + The class that owns the attribute. Returns ------- - The value of the attribute, potentially after applying bounds checks. + The value of the attribute, potentially after applying bounds checks. """ result = super().__get__(obj, objtype) diff --git a/param/reactive.py b/param/reactive.py index 634298129..68743ae5d 100644 --- a/param/reactive.py +++ b/param/reactive.py @@ -220,12 +220,14 @@ def __call__(self): def and_(self, other): """Perform a logical AND operation with the given operand. - Args: - other: The operand to combine with using the AND operation. + Parameters + ---------- + other: + The operand to combine with using the AND operation. Returns ------- - The result of applying the AND operation. + An expression with the result of applying the AND operation. """ return self._as_rx()._apply_operator(lambda obj, other: obj and other, other) @@ -234,7 +236,7 @@ def bool(self): Returns ------- - The boolean value of the object. + An expression with the boolean value of the object. """ return self._as_rx()._apply_operator(bool) @@ -251,36 +253,42 @@ def collect(new, n): def in_(self, other): """Check if the current object is contained "in" the given operand. - Args: - other: The operand to check for containment. + Parameters + ---------- + other: + The operand to check for containment. Returns ------- - The result of the containment check. + An expression with the result of the containment check. """ return self._as_rx()._apply_operator(operator.contains, other, reverse=True) def is_(self, other): """Perform a logical "is" comparison with the given operand. - Args: - other: The operand to compare against. + Parameters + ---------- + other: + The operand to compare against. Returns ------- - The result of the "is" comparison. + An expression with the result of the "is" comparison. """ return self._as_rx()._apply_operator(operator.is_, other) def is_not(self, other): """Perform a logical "is not" comparison with the given operand. - Args: - other: The operand to compare against. + Parameters + ---------- + other: + The operand to compare against. Returns ------- - The result of the "is not" comparison. + An expression containing the result of the "is not" comparison. """ return self._as_rx()._apply_operator(operator.is_not, other) @@ -292,8 +300,8 @@ def map(self, func, /, *args, **kwargs): """ Apply a function to each item. - Arguments: - --------- + Parameters + ---------- func: function Function to apply. args: iterable, optional @@ -301,6 +309,9 @@ def map(self, func, /, *args, **kwargs): kwargs: mapping, optional A dictionary of keywords to pass to `func`. + Returns + ------- + An expression containing a list with the result of the mapped values. """ if inspect.isasyncgenfunction(func) or inspect.isgeneratorfunction(func): raise TypeError( @@ -320,19 +331,21 @@ def not_(self): Returns ------- - The result of applying the NOT operation. + An expression with the result of applying the NOT operation. """ return self._as_rx()._apply_operator(operator.not_) def or_(self, other): """Perform a logical OR operation with the given operand. - Args: - other: The operand to combine with using the OR operation. + Parameters + ---------- + other + The operand to combine with using the OR operation. Returns ------- - The result of applying the OR operation. + An expression with the result of applying the OR operation. """ return self._as_rx()._apply_operator(lambda obj, other: obj or other, other) @@ -340,8 +353,8 @@ def pipe(self, func, /, *args, **kwargs): """ Apply chainable functions. - Arguments: - --------- + Parameters + ---------- func: function Function to apply. args: iterable, optional @@ -349,6 +362,9 @@ def pipe(self, func, /, *args, **kwargs): kwargs: mapping, optional A dictionary of keywords to pass to `func`. + Returns + ------- + An expression with the result of the applied function. """ return self._as_rx()._apply_operator(func, *args, **kwargs) @@ -359,8 +375,8 @@ def resolve(self, nested=True, recursive=False): As an example if the expression returns a list of parameters this operation will return a list of the parameter values. - Arguments: - --------- + Parameters + ---------- nested: bool Whether to resolve references contained within nested objects, i.e. tuples, lists, sets and dictionaries. @@ -369,6 +385,9 @@ def resolve(self, nested=True, recursive=False): itself returns a reference we recurse into it until no more references can be resolved. + Returns + ------- + An expression where any references have been resolved. """ resolver_type = NestedResolver if nested else Resolver resolver = resolver_type(object=self._reactive, recursive=recursive) @@ -389,14 +408,18 @@ def when(self, *dependencies, initial=Undefined): expression will not be evaluated until the first event is triggered. - Arguments: - --------- + Parameters + ---------- dependencies: param.Parameter | rx A dependency that will trigger an update in the output. initial: object Object that will stand in for the actual value until the first time a param.Event in the dependencies is triggered. + Returns + ------- + An expression which updates only when the supplied dependencies + change. """ deps = [p for d in dependencies for p in resolve_ref(d)] is_event = all(isinstance(dep, Event) for dep in deps) @@ -416,13 +439,17 @@ def where(self, x, y): Replaces a ternary if statement. - Arguments: - --------- + Parameters + ---------- x: object The value to return if the expression evaluates to True. y: object The value to return if the expression evaluates to False. + Returns + ------- + An expression returning either x or y dependending on + whether the condition is True or False. """ xrefs = resolve_ref(x) yrefs = resolve_ref(y) @@ -493,8 +520,23 @@ def value(self, new): def watch(self, fn=None, onlychanged=True, queued=False, precedence=0): """ Add a callable that observes the output of the pipeline. - If no callable is provided this simply causes the expression - to be eagerly evaluated. + + Parameters + ---------- + fn : callable, optional + A callable to observe the output. If None, the expression is + evaluated eagerly. + onlychanged : bool, optional + If True, the observer will only be notified of changes in output. + queued : bool, optional + If True, changes will be processed in a queued manner. + precedence : int, optional + The priority level of the observer. Higher values have higher precedence. + + Notes + ----- + Using this method without a callable will ensure that the expression + tied to the pipeline is eagerly evaluated. """ if precedence < 0: raise ValueError("User-defined watch callbacks must declare " @@ -524,8 +566,8 @@ def bind(function, *args, watch=False, **kwargs): which allows all of the arguments to be bound, leaving a simple callable object. - Arguments: - --------- + Parameters + ---------- function: callable The function to bind constant or dynamic args and kwargs to. args: object, param.Parameter @@ -540,7 +582,6 @@ def bind(function, *args, watch=False, **kwargs): ------- Returns a new function with the args and kwargs bound to it and annotated with all dependencies. - """ args, kwargs = ( tuple(transform_reference(arg) for arg in args), @@ -679,7 +720,6 @@ class rx: Then update the original value and see the new result: >>> ifloat.value = 1 2 - """ _accessors: dict[str, Callable[[rx], Any]] = {} @@ -698,8 +738,8 @@ def register_accessor( """ Register an accessor that extends rx with custom behavior. - Arguments: - --------- + Parameters + ---------- name: str The name of the accessor will be attribute-accessible under. accessor: Callable[[rx], any] @@ -718,8 +758,8 @@ def register_display_handler(cls, obj_type, handler, **kwargs): Makes it possible to define custom display options for specific objects. - Arguments: - --------- + Parameters + ---------- obj_type: type | callable The type to register a custom display handler on. handler: Viewable | callable diff --git a/pyproject.toml b/pyproject.toml index 6aab2a662..c5bccfee9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -116,6 +116,7 @@ omit = ["param/version.py"] [tool.ruff] fix = true include = ["*.py"] +exclude = ["version.py"] [tool.ruff.lint] select = ["D", "W", "E", "F"] From cdb24b2f6c748d6aa6e44964c6b5cf30163d3c0c Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 16:09:52 +0100 Subject: [PATCH 07/15] Exclude pyarrow version --- param/version.py | 32 +++++++++++++++----------------- pixi.toml | 2 +- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/param/version.py b/param/version.py index b43e4f5d9..2f3042eaa 100644 --- a/param/version.py +++ b/param/version.py @@ -134,28 +134,28 @@ 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 def fetch(self): """ - Return a tuple of the major version together with the + Returns a tuple of the major version together with the appropriate SHA and dirty bit (for development version only). """ if self._release is not None: @@ -228,8 +228,6 @@ def git_fetch(self, cmd='git', as_string=False): def _known_stale(self): """ - Return whether the commit is know to be stale or not. - The commit is known to be from a file (and therefore stale) if a SHA is supplied by git archive and doesn't match the parsed commit. """ @@ -261,7 +259,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']: @@ -363,7 +361,7 @@ def verify(self, string_version=None): def get_setup_version(cls, setup_path, reponame, describe=False, dirty='report', pkgname=None, archive_commit=None): """ - Get the version from the .version file (if available) + Helper for use in setup.py to get the version from the .version file (if available) or more up-to-date information from git describe (if available). Assumes the __init__.py will be found in the directory @@ -461,8 +459,8 @@ def setup_version(cls, setup_path, reponame, archive_commit=None, def get_setup_version(location, reponame, pkgname=None, archive_commit=None): """ - Get the current version from either git describe or the - .version file (if available). + Helper for use in setup.py to get the current version from either + git describe or the .version file (if available). Set pkgname to the package name if it is different from the repository name. @@ -601,28 +599,28 @@ 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 def fetch(self): """ - Return a tuple of the major version together with the + Returns a tuple of the major version together with the appropriate SHA and dirty bit (for development version only). """ if self._release is not None: @@ -669,7 +667,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/pixi.toml b/pixi.toml index d37e5f2ce..d619e9fec 100644 --- a/pixi.toml +++ b/pixi.toml @@ -72,7 +72,7 @@ numpy = "*" odfpy = "*" openpyxl = "*" pandas = "*" -pyarrow = "*" +pyarrow = "!=18.1.0" # Temporary ping to avoid OSX Symbol undefined error pytables = "*" xlrd = "*" From 2ce57ce0c99176b9016043dfdffe7b6d1cb9e3a5 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 16:24:35 +0100 Subject: [PATCH 08/15] Pin libprotobuf instead --- pixi.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pixi.toml b/pixi.toml index d619e9fec..43cea628b 100644 --- a/pixi.toml +++ b/pixi.toml @@ -67,12 +67,13 @@ test-unit = 'pytest tests' cloudpickle = "*" ipython = "*" jsonschema = "*" +libprotobuf = "<5.28" # Temporary ping to avoid OSX Symbol undefined error nest-asyncio = "*" numpy = "*" odfpy = "*" openpyxl = "*" pandas = "*" -pyarrow = "!=18.1.0" # Temporary ping to avoid OSX Symbol undefined error +pyarrow = "*" pytables = "*" xlrd = "*" From 85722e675e28f59387a70bab50a7063d3922ebef Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 16:36:51 +0100 Subject: [PATCH 09/15] Pin libabseil instead --- pixi.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixi.toml b/pixi.toml index 43cea628b..1e5305631 100644 --- a/pixi.toml +++ b/pixi.toml @@ -67,7 +67,7 @@ test-unit = 'pytest tests' cloudpickle = "*" ipython = "*" jsonschema = "*" -libprotobuf = "<5.28" # Temporary ping to avoid OSX Symbol undefined error +libabseil = "!=20240722.0=cxx17_h07bc746_2" # Avoid symbol error with build _2 on OSX nest-asyncio = "*" numpy = "*" odfpy = "*" From cb22242ddf583e1ea3d2b30208a99379bcde9f2b Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 16:40:25 +0100 Subject: [PATCH 10/15] Fix syntax --- pixi.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixi.toml b/pixi.toml index 1e5305631..c1795a9f0 100644 --- a/pixi.toml +++ b/pixi.toml @@ -67,7 +67,7 @@ test-unit = 'pytest tests' cloudpickle = "*" ipython = "*" jsonschema = "*" -libabseil = "!=20240722.0=cxx17_h07bc746_2" # Avoid symbol error with build _2 on OSX +libabseil = { build = "!=cxx17_h07bc746_2" } # Avoid symbol error with build _2 on OSX nest-asyncio = "*" numpy = "*" odfpy = "*" From 90d7ad3df4065bbe84a7c9d1c5e53cd8c71e73f3 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 18:34:11 +0100 Subject: [PATCH 11/15] remove pin after libprotobuff was patched --- pixi.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pixi.toml b/pixi.toml index c1795a9f0..d37e5f2ce 100644 --- a/pixi.toml +++ b/pixi.toml @@ -67,7 +67,6 @@ test-unit = 'pytest tests' cloudpickle = "*" ipython = "*" jsonschema = "*" -libabseil = { build = "!=cxx17_h07bc746_2" } # Avoid symbol error with build _2 on OSX nest-asyncio = "*" numpy = "*" odfpy = "*" From c447c1e32a3694a0ddb373fce151e160433929c3 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 20:28:52 +0100 Subject: [PATCH 12/15] re-add libprotobuff pin --- pixi.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pixi.toml b/pixi.toml index d37e5f2ce..6bca8e66e 100644 --- a/pixi.toml +++ b/pixi.toml @@ -67,6 +67,7 @@ test-unit = 'pytest tests' cloudpickle = "*" ipython = "*" jsonschema = "*" +libprotobuf = ">=5.28.3" # Pin to avoid Mac arm64 Symbol undefined errors nest-asyncio = "*" numpy = "*" odfpy = "*" From 6cb579fb5f731446498b61b3cf4530f650b41fdd Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 20:39:28 +0100 Subject: [PATCH 13/15] More extreme pin until issue is resolved --- pixi.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pixi.toml b/pixi.toml index 6bca8e66e..389f79852 100644 --- a/pixi.toml +++ b/pixi.toml @@ -67,13 +67,12 @@ test-unit = 'pytest tests' cloudpickle = "*" ipython = "*" jsonschema = "*" -libprotobuf = ">=5.28.3" # Pin to avoid Mac arm64 Symbol undefined errors nest-asyncio = "*" numpy = "*" odfpy = "*" openpyxl = "*" pandas = "*" -pyarrow = "*" +pyarrow = "<18" # Temporary pin to avoid issue with libprotobuf and libaseil on Mac arm64 (https://github.com/conda-forge/abseil-cpp-feedstock/issues/87) pytables = "*" xlrd = "*" From c16e911c9ceae77c589ce3f4652abb446544e4df Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 30 Dec 2024 21:48:22 +0100 Subject: [PATCH 14/15] Adjust pin again --- pixi.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixi.toml b/pixi.toml index 389f79852..57a0e6ed7 100644 --- a/pixi.toml +++ b/pixi.toml @@ -72,7 +72,7 @@ numpy = "*" odfpy = "*" openpyxl = "*" pandas = "*" -pyarrow = "<18" # Temporary pin to avoid issue with libprotobuf and libaseil on Mac arm64 (https://github.com/conda-forge/abseil-cpp-feedstock/issues/87) +pyarrow = "<18.1" # Temporary pin to avoid issue with libprotobuf and libaseil on Mac arm64 (https://github.com/conda-forge/abseil-cpp-feedstock/issues/87) pytables = "*" xlrd = "*" From 696a2d0b6e91fe5527d486aa1c97e6fd7d84ec53 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Tue, 31 Dec 2024 14:13:05 +0100 Subject: [PATCH 15/15] Unpin again --- pixi.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixi.toml b/pixi.toml index 57a0e6ed7..d37e5f2ce 100644 --- a/pixi.toml +++ b/pixi.toml @@ -72,7 +72,7 @@ numpy = "*" odfpy = "*" openpyxl = "*" pandas = "*" -pyarrow = "<18.1" # Temporary pin to avoid issue with libprotobuf and libaseil on Mac arm64 (https://github.com/conda-forge/abseil-cpp-feedstock/issues/87) +pyarrow = "*" pytables = "*" xlrd = "*"