Skip to content

fix[next]: properly ignore ndarray embedded caches#2536

Merged
egparedes merged 15 commits intoGridTools:mainfrom
egparedes:fix-embedded-connectivity-caching
Mar 19, 2026
Merged

fix[next]: properly ignore ndarray embedded caches#2536
egparedes merged 15 commits intoGridTools:mainfrom
egparedes:fix-embedded-connectivity-caching

Conversation

@egparedes
Copy link
Contributor

@egparedes egparedes commented Mar 17, 2026

Add a general mechanism to deal with serialization of dataclass-like instances using a new mixin class: utils.MetadataBasedPickling. By default this mechanism ignores run-time only data added to the instance (e.g. caches) and allows skipping some specific fields from pickle using field metadata.

Additionally, this fixes a bug in the embedded NdArrayField (and subclasses), where because of cache data not being skipped properly during fingerprinting, the gt4py caches are not used properly. This bug was the actual trigger of this implementation.

Copilot AI review requested due to automatic review settings March 17, 2026 14:22
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a bug in the embedded NdArrayConnectivityField implementation so its runtime inverse-image cache is excluded from object state serialization (and thus won’t leak into serialized artifacts).

Changes:

  • Added __getstate__/__setstate__ to NdArrayConnectivityField to omit the _cache cached-property from serialized state.
  • Added unit tests verifying _cache is excluded from __getstate__ and not reintroduced by __setstate__.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/gt4py/next/embedded/nd_array_field.py Implements state (de)serialization hooks to drop the _cache runtime cache from serialization.
tests/next_tests/unit_tests/embedded_tests/test_nd_array_field.py Adds tests covering __getstate__/__setstate__ behavior around _cache.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@egparedes egparedes requested a review from Copilot March 17, 2026 14:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes serialization/fingerprinting behavior for embedded NdArrayField/NdArrayConnectivityField by ensuring runtime-only caches aren’t included in saved state.

Changes:

  • Added __getstate__ / __setstate__ to serialize only dataclass-defined state (excluding cached/runtime attributes).
  • Moved/reintroduced an embedded runtime cache (_cache) for connectivity inverse-image/restrict acceleration while keeping it out of serialization.
  • Added unit tests asserting cached properties and runtime caches are excluded from state/restoration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
tests/next_tests/unit_tests/embedded_tests/test_nd_array_field.py Adds tests for __getstate__ / __setstate__ behavior and cache exclusion for ndarray + connectivity fields
src/gt4py/next/embedded/nd_array_field.py Implements __getstate__ / __setstate__ and clarifies _cache as a runtime-only cached property

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@egparedes egparedes requested a review from Copilot March 17, 2026 15:38
@egparedes egparedes changed the title fix[next]: fix connectivity ndarray embedded cache fix[next]: ignore ndarray embedded caches Mar 17, 2026
@egparedes egparedes changed the title fix[next]: ignore ndarray embedded caches fix[next]: properly ignore ndarray embedded caches Mar 17, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a serialization/fingerprinting bug in the embedded NdArrayField (and NdArrayConnectivityField) by ensuring runtime-only caches (e.g., cached properties) are excluded from pickling state.

Changes:

  • Add NdArrayField.__getstate__ / __setstate__ to serialize only dataclass instance fields (excluding cached attributes).
  • Rework the embedded connectivity runtime cache (_cache) to remain a non-serialized cached property.
  • Add unit tests covering __getstate__, __setstate__, and a pickle roundtrip for both ndarray fields and connectivity fields; add a utility helper for dataclass field name lookup.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
tests/next_tests/unit_tests/embedded_tests/test_nd_array_field.py Adds tests asserting cached attributes are excluded from state and that pickle roundtrips restore data correctly.
src/gt4py/next/embedded/nd_array_field.py Implements __getstate__/__setstate__ to drop runtime caches from serialization and keeps connectivity _cache non-serialized.
src/gt4py/eve/utils.py Adds a cached helper to retrieve dataclass field names for use by serialization logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes serialization/fingerprinting of embedded NdArrayField (and subclasses) by ensuring runtime-only cached attributes are excluded from pickled state, improving determinism of content_hash-based fingerprints.

Changes:

  • Add NdArrayField.__getstate__/__setstate__ to serialize only dataclass instance fields (excluding cached properties stored in __dict__).
  • Reintroduce NdArrayConnectivityField._cache as an explicit runtime-only cache and add tests ensuring it is excluded from serialization.
  • Add unit tests covering __getstate__/__setstate__ behavior and pickle roundtrips.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/gt4py/next/embedded/nd_array_field.py Implements custom pickling state handling to exclude runtime caches and introduces helper logic for selecting serializable dataclass fields.
tests/next_tests/unit_tests/embedded_tests/test_nd_array_field.py Adds regression tests for excluding cached properties/runtime caches from serialization and for pickle roundtrips.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a metadata-driven pickling mechanism for dataclass-like objects in gt4py.next, and applies it to embedded NdArrayField serialization so runtime caches don’t affect fingerprinting (restoring proper cache reuse).

Changes:

  • Add utils.MetadataBasedPickling + utils.gt4py_metadata(...) to control which dataclass/datamodel fields participate in pickling.
  • Update embedded NdArrayField (and NdArrayConnectivityField) to use metadata-based pickling and to exclude runtime-only derived/cached data.
  • Add unit tests validating __getstate__ output and pickle roundtrips for dataclasses/datamodels and embedded ndarray fields.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/gt4py/next/utils.py Adds the metadata namespace helper and the MetadataBasedPickling mixin that generates __getstate__ based on field metadata.
src/gt4py/next/embedded/nd_array_field.py Adopts the mixin on NdArrayField and marks _kind as non-pickled to avoid fingerprint instability from derived state.
tests/next_tests/unit_tests/test_utils.py Adds tests for the mixin/state generator and pickle roundtrips for dataclass/datamodel variants.
tests/next_tests/unit_tests/embedded_tests/test_nd_array_field.py Adds regression tests ensuring embedded field runtime caches aren’t serialized and pickle roundtrips work.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link
Contributor

@havogt havogt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, just a few optional comments

# - for class instances with __dict__ and no __slots__ -> state = self.__dict__.
# - for class instances with __slots__ and no __dict__ -> state = (None, {slot.name: slot.value for all slots}).
# - for class instances with __dict__ and __slots__ -> state = (self.__dict__, {slot.name: slot.value for all slots}).
if not has_slots:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this if else change surprisingly hard to read. I think I'd prefer (although slightly more checks and feel free to ignore):

if has_slots and has_dict:
    ...
else:
    if has_slots:
        ...
    else: # has_dict
        ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now inlined the comments with the cases so it should be easier to read.

return (
{name: getattr(self, name) for name in dict_names},
{name: getattr(self, name) for name in slot_names},
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we could add a test for empty datamodels and dataclasses. I don't see why it should break though...

_codomain: common.DimT
_skip_value: Optional[core_defs.IntegralScalar]
_kind: Optional[common.ConnectivityKind] = None
_kind: Optional[common.ConnectivityKind] = dataclasses.field(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it skipped, because it is also a property? I think for caches it is clear, but for other cases a docstring would be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kind has been converted to a cached_property so this is not longer necessary.

Copy link
Contributor

@havogt havogt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@egparedes egparedes merged commit 72a63fd into GridTools:main Mar 19, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants