Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 6 additions & 33 deletions doc/source/changes/version_0_35.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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()`,
Expand All @@ -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
^^^^^^^^^^^^
Expand All @@ -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 <misc>` 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
^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -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`).
the evaluation until the larger array is known (closes :issue:`1129`).
35 changes: 26 additions & 9 deletions larray/core/checked.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
Expand Down Expand Up @@ -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):
Expand All @@ -116,9 +118,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)
Expand Down Expand Up @@ -199,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.
Expand Down Expand Up @@ -459,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.
Expand Down
19 changes: 19 additions & 0 deletions larray/tests/test_checked_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Loading