From 6fef3db6dd726af5475d7b781bb59e421115e794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Mon, 1 Dec 2025 11:37:26 +0100 Subject: [PATCH 1/4] DOC: prepare changelog for release --- doc/source/changes/version_0_35.rst.inc | 39 ++++--------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/doc/source/changes/version_0_35.rst.inc b/doc/source/changes/version_0_35.rst.inc index bc85a1c46..d35e0d374 100644 --- a/doc/source/changes/version_0_35.rst.inc +++ b/doc/source/changes/version_0_35.rst.inc @@ -4,8 +4,6 @@ Syntax changes ^^^^^^^^^^^^^^ -* renamed ``Array.old_method_name()`` to :py:obj:`Array.new_method_name()` (closes :issue:`1`). - * renamed ``stacked`` argument of :py:obj:`Array.plot()` to ``stack``. This also impacts all the relevant kind-specific sub-methods (:py:obj:`Array.plot.area()`, :py:obj:`Array.plot.bar()`, @@ -25,8 +23,10 @@ Backward incompatible changes Shown plots will open a window and pause the running script until the window is closed by the user. To revert to the previous behavior, use show=False. -* Using :py:obj:`CheckedSession`, :py:obj:`CheckedParameters` or :py:obj:`CheckedArray` - now requires to install pydantic >= 2.12 (closes :issue:`1075`). +* Using :py:obj:`CheckedSession`, :py:obj:`CheckedParameters` or + :py:obj:`CheckedArray` now requires installing pydantic >= 2.12 + (closes :issue:`1075`). + New features ^^^^^^^^^^^^ @@ -49,40 +49,13 @@ New features directly, without having to use the matplotlib API. This is the new default behavior, unless a ``filepath`` is given. -* implemented a new kind of plot: `heatmap`. It can be used like this: +* implemented a new kind of plot: ``heatmap``. It can be used like this: >>> arr.plot.heatmap() * implemented :py:obj:`Session.align()` to align all the arrays in several sessions at once. Closes :issue:`501`. -* added a feature (see the :ref:`miscellaneous section ` for details). It works on :ref:`api-axis` and - :ref:`api-group` objects. - - Here is an example of the new feature: - - >>> arr = ndtest((2, 3)) - >>> arr - a\b b0 b1 b2 - a0 0 1 2 - a1 3 4 5 - - And it can also be used like this: - - >>> arr = ndtest("a=a0..a2") - >>> arr - a a0 a1 a2 - 0 1 2 - -* added another feature in the editor (closes :editor_issue:`1`). - - .. note:: - - - It works for foo bar ! - - It does not work for foo baz ! - - -.. _misc: Miscellaneous improvements ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,4 +117,4 @@ Fixes * fixed evaluating operations involving X.axis and an array when that operation is only valid in the context of a larger array by delaying - the evaluation until the larger array is known (closes :issue:`1129`). \ No newline at end of file + the evaluation until the larger array is known (closes :issue:`1129`). From af485e3340f5c6237414498c7951dad8fbcb481c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Fri, 5 Dec 2025 17:32:35 +0100 Subject: [PATCH 2/4] FIX: fixed calling methods on CheckedSession subclasses (thanks to Alix for finding the solution to this) --- larray/core/checked.py | 11 ++++++++--- larray/tests/test_checked_session.py | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/larray/core/checked.py b/larray/core/checked.py index 21fac5fde..6d8a95a79 100644 --- a/larray/core/checked.py +++ b/larray/core/checked.py @@ -116,9 +116,14 @@ def __new__(mcs, cls_name: str, bases: tuple[type[Any], ...], namespace: dict[st raw_annotations = namespace.get('__annotations__', {}) # tries to infer types for variables without type hints - keys_to_infer_type = [key for key in namespace.keys() if key not in raw_annotations] - keys_to_infer_type = [key for key in keys_to_infer_type if is_valid_field_name(key)] - keys_to_infer_type = [key for key in keys_to_infer_type if key not in {'model_config', 'dict'}] + keys_to_infer_type = [key for key in namespace.keys() + if key not in raw_annotations] + keys_to_infer_type = [key for key in keys_to_infer_type + if is_valid_field_name(key)] + keys_to_infer_type = [key for key in keys_to_infer_type + if key not in {'model_config', 'dict', 'build'}] + keys_to_infer_type = [key for key in keys_to_infer_type + if not callable(namespace[key])] for key in keys_to_infer_type: value = namespace[key] raw_annotations[key] = type(value) diff --git a/larray/tests/test_checked_session.py b/larray/tests/test_checked_session.py index befcaa6f3..e4bee387a 100644 --- a/larray/tests/test_checked_session.py +++ b/larray/tests/test_checked_session.py @@ -715,5 +715,24 @@ def test_neg_cs(checkedsession): assert_array_nan_equal(neg_cs.h, -h) +def test_checked_class_with_methods(): + a = Axis('a=a0,a1') + + class CheckedSessionWithMethods(CheckedSession): + arr: CheckedArray(a) + + # Define a method which already exists in Session/CheckedSession + def save(self, path=None, **kwargs): + super().save(path, **kwargs) + + def new_method(self): + return True + + array = ndtest(a) + + cs = CheckedSessionWithMethods(arr=array) + assert cs.new_method() + + if __name__ == "__main__": pytest.main() From 608dfcdbba2f5a871ad890bfcf0c43084f961d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Mon, 8 Dec 2025 11:20:59 +0100 Subject: [PATCH 3/4] CLN: style improvements --- larray/core/checked.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/larray/core/checked.py b/larray/core/checked.py index 6d8a95a79..7fac55818 100644 --- a/larray/core/checked.py +++ b/larray/core/checked.py @@ -19,9 +19,10 @@ class NotLoaded: except ImportError: pydantic = None -# moved the not implemented versions of Checked* classes in the beginning of the module -# otherwise PyCharm do not provide auto-completion for methods of CheckedSession -# (imported from Session) + +# the not implemented versions of Checked* classes must be in the beginning of +# the module otherwise PyCharm do not provide auto-completion for methods of +# CheckedSession (imported from Session) if not pydantic: def CheckedArray(axes: AxisCollection, dtype: np.dtype = float) -> Type[Array]: raise NotImplementedError("CheckedArray cannot be used because pydantic is not installed") @@ -97,12 +98,13 @@ def validate_array(value: Any, info: ValidationInfo) -> Array: return Annotated[Array, BeforeValidator(validate_array)] + class AbstractCheckedSession: pass + # Simplified version of the ModelMetaclass class from pydantic: # https://github.com/pydantic/pydantic/blob/v2.12.0/pydantic/_internal/_model_construction.py - class ModelMetaclass(ABCMeta): @no_type_check # noqa C901 def __new__(mcs, cls_name: str, bases: tuple[type[Any], ...], namespace: dict[str, Any], **kwargs: Any): @@ -204,6 +206,7 @@ def __dir__(self) -> list[str]: attributes.remove('__fields__') return attributes + class CheckedSession(Session, AbstractCheckedSession, metaclass=ModelMetaclass): """ Class intended to be inherited by user defined classes in which the variables of a model are declared. From acb33ec4fed7dcf105b031f673f2e6ddc5b7d6de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20de=20Menten?= Date: Mon, 8 Dec 2025 12:19:16 +0100 Subject: [PATCH 4/4] ENH: added deprecation warning for now-unused method This should have been a private method but since it was public, I added the deprecation warning to avoid breaking users code. I also removed the Optional for the exclude argument since the code does not actually work with exclude=None --- larray/core/checked.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/larray/core/checked.py b/larray/core/checked.py index 7fac55818..3695dbcac 100644 --- a/larray/core/checked.py +++ b/larray/core/checked.py @@ -3,7 +3,7 @@ import numpy as np -from typing import Type, Any, Dict, Set, no_type_check, Optional, Annotated +from typing import Type, Any, Dict, Set, no_type_check, Annotated from larray.core.axis import AxisCollection from larray.core.array import Array, full @@ -467,9 +467,18 @@ def __getstate__(self) -> Dict[str, Any]: def __setstate__(self, state: Dict[str, Any]) -> None: object.__setattr__(self, '__dict__', state['__dict__']) - def dict(self, exclude: Optional[Set[str]] = None) -> Dict[str, Any]: + def dict(self, exclude: Set[str]) -> Dict[str, Any]: + warnings.warn( + "checked_session.dict(exclude) is deprecated. Use a dict " + "comprehension instead: " + "{k: v for k, v in checked_session.items() if k not in exclude}" + "\nIf you use this method a lot, please complain and we may " + "add it back in a better form.", + FutureWarning, stacklevel=2) + return {k: v for k, v in self.items() if k not in exclude} + class CheckedParameters(CheckedSession): """ Same as py:class:`CheckedSession` but declared variables cannot be modified after initialization.