Skip to content

fix: array attrs not being validated at creation and being of inconsistent type#3996

Merged
ikrommyd merged 3 commits into
scikit-hep:mainfrom
ikrommyd:ikrommyd/fix-attrs-type
May 9, 2026
Merged

fix: array attrs not being validated at creation and being of inconsistent type#3996
ikrommyd merged 3 commits into
scikit-hep:mainfrom
ikrommyd:ikrommyd/fix-attrs-type

Conversation

@ikrommyd

@ikrommyd ikrommyd commented May 5, 2026

Copy link
Copy Markdown
Member

We have been allowing this this whole time:

In [1]: import awkward as ak

In [2]: attrs = {1: 2}

In [3]: ak.Array([1,2,3], attrs=attrs)
Out[3]: <Array [1, 2, 3] type='3 * int64'>

In [4]: x = ak.Array([1,2,3], attrs=attrs)

In [5]: x.attrs
Out[5]: {1: 2}

In [6]: x._attrs
Out[6]: {1: 2}

which is not correct because A) attrs should normally be of type Attrs and not dict and B) attrs should have only string keys if you look at the Attrs class:

class Attrs(Mapping):
def __init__(self, data: Mapping[str, Any]):
self._data = {_enforce_str_key(k): v for k, v in data.items()}
def __getitem__(self, key: str):
return self._data[key]
def __setitem__(self, key: str, value: Any):
self._data[_enforce_str_key(key)] = value
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
def __repr__(self):
return f"Attrs({self._data!r})"
def to_dict(self):
return dict(self._data)

Also setting attrs to itself would raise an error

In [7]: x.attrs = attrs
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[7], line 1
----> 1 x.attrs = attrs

File ~/Dropbox/work/pyhep_dev/awkward/src/awkward/highlevel.py:1327, in Array.__setattr__(self, name, value)
   1303 """
   1304 Args:
   1305     where (str): Attribute name to set
   (...)   1324 to add or modify a field.
   1325 """
   1326 if name.startswith("_") or hasattr(type(self), name):
-> 1327     super().__setattr__(name, value)
   1328 elif name in self._layout.fields:
   1329     raise AttributeError(
   1330         "fields cannot be set as attributes. use #__setitem__ or #ak.with_field"
   1331     )

File ~/Dropbox/work/pyhep_dev/awkward/src/awkward/highlevel.py:403, in Array.attrs(self, value)
    400 @attrs.setter
    401 def attrs(self, value: Mapping[str, Any]):
    402     if isinstance(value, Mapping):
--> 403         self._attrs = Attrs(value)
    404     else:
    405         raise TypeError("attrs must be a 'Attrs' mapping")

File ~/Dropbox/work/pyhep_dev/awkward/src/awkward/_attrs.py:49, in Attrs.__init__(self, data)
     48 def __init__(self, data: Mapping[str, Any]):
---> 49     self._data = {_enforce_str_key(k): v for k, v in data.items()}

File ~/Dropbox/work/pyhep_dev/awkward/src/awkward/_attrs.py:72, in _enforce_str_key(key)
     70 def _enforce_str_key(key: Any) -> str:
     71     if not isinstance(key, str):
---> 72         raise TypeError(f"'attrs' keys must be strings, got: {key!r}")
     73     return key

TypeError: 'attrs' keys must be strings, got: 1

We make attrs get validated on array/record/builder creation as they should and also make them appear of consistent type Attrs to the user. Not sometimes dict and sometimes Attrs.

This was found through coffea while noticing that when you open up a file in coffea, attrs are a dict in virtual/eager mode but of type Attrs in dask mode.

@ikrommyd ikrommyd changed the title fix: array attrs not being validate at creation and being of inconsistent type fix: array attrs not being validated at creation and being of inconsistent type May 5, 2026
@ikrommyd
ikrommyd requested a review from pfackeldey May 5, 2026 20:41
@codecov

codecov Bot commented May 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.29%. Comparing base (390cbb8) to head (9b975a0).

Additional details and impacted files
Files with missing lines Coverage Δ
src/awkward/highlevel.py 80.94% <100.00%> (+0.79%) ⬆️

@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown

The documentation preview is ready to be viewed at http://preview.awkward-array.org.s3-website.us-east-1.amazonaws.com/PR3996

@pfackeldey pfackeldey left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks, good catch!

Could you add your example as a test so we're sure to not alter this behavior in the future?

@ianna

ianna commented May 6, 2026

Copy link
Copy Markdown
Member

We have been allowing this this whole time:

In [1]: import awkward as ak

In [2]: attrs = {1: 2}

In [3]: ak.Array([1,2,3], attrs=attrs)
Out[3]: <Array [1, 2, 3] type='3 * int64'>

In [4]: x = ak.Array([1,2,3], attrs=attrs)

In [5]: x.attrs
Out[5]: {1: 2}

In [6]: x._attrs
Out[6]: {1: 2}

also:

>>> attrs[1]
2
>>> attrs[1]=3
>>> array.attrs
{1: 3}

@ikrommyd

ikrommyd commented May 6, 2026

Copy link
Copy Markdown
Member Author

Yeah, the Attrs class blocks non-string keys on __setitem__ so that's fixed too.

@ikrommyd

ikrommyd commented May 6, 2026

Copy link
Copy Markdown
Member Author

Thanks, good catch!

Could you add your example as a test so we're sure to not alter this behavior in the future?

Tests added.

@ianna ianna added pr-next-release Required for the next release labels May 7, 2026
@ianna

ianna commented May 8, 2026

Copy link
Copy Markdown
Member

@pfackeldey -- could you please add some description to your review for the benefit of other admins? Thanks.

@pfackeldey pfackeldey left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In my initial review (#3996 (review)) I was happy with this change, except for missing tests. Now that you've (@ikrommyd) added them, I'm happy to approve.

@ianna

ianna commented May 8, 2026

Copy link
Copy Markdown
Member

In my initial review (#3996 (review)) I was happy with this change, except for missing tests. Now that you've (@ikrommyd) added them, I'm happy to approve.

To summarize: It was a "good catch" and now it has some test :-) . Thanks.

@ikrommyd
ikrommyd merged commit 3f84414 into scikit-hep:main May 9, 2026
38 checks passed
@ikrommyd
ikrommyd deleted the ikrommyd/fix-attrs-type branch May 9, 2026 23:52
ianna pushed a commit that referenced this pull request May 10, 2026
…stent type (#3996)

* convert dict attrs to Attrs type

* add test
ianna added a commit that referenced this pull request May 16, 2026
* next step in kernel migration from parents to offsets

* linter fix

* add jax bincount

* add cpp kernel to convert parents to offsets

* fix typo

* fix typo in an auto-generated test

* almost there

* nearly there

* cleanup

* fix remaining kernels

* final cleanup

* format json data

* format

* initialize maxnextparents  = -1 (a sentinel meaning "no bin was touched")

* update the kernels to work on offsets!

* format

* migrate cupy rawkernels from parents to offsets

* migrate jax reducers

* fix for platfroms where the int64 counts can't be safely cast

* add bincount for cupy backend

* compact loc

* fix windows build and add optional OpenMP support

* update cuda kernels

* feat: add `missing_repeat` kernel implementation using cuda.compute (#3922)

* feat: add missing_repeat implementation using cuda.compute

* keep the same name as in cpu kernel

* add tests for repetitions>1 and regularsize>1

* style: pre-commit fixes

* add keywords

* style fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat: add `index_rpad_and_clip` kernels implementations using cuda.compute (#3923)

* feat: add `index_rpad_and_clip` kernels implementation using cuda.compute

* style fix

* add a test for `index_rpad_and_clip_axis0` that would have target>length

* add keyword names

* style

* Apply suggestions from Ianna

Co-authored-by: Ianna Osborne <ianna.osborne@cern.ch>

* style: pre-commit fixes

---------

Co-authored-by: Ianna Osborne <ianna.osborne@cern.ch>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix: array attrs not being validated at creation and being of inconsistent type (#3996)

* convert dict attrs to Attrs type

* add test

* fix: ensure jax backend uses arrays on cpu only (#3990)

* ensure jax uses cpu by default

* remove now redundant jax_platform_name setting

* change error messages

* better errors

* remove DeviceArray mentions as that does not exist while we're at it too

* almost there

* cleanup

* cleanup

* remove old data file

* update cupy kernels

* remove exlicit test for depricated kernel

* add complex kernels and port them to use offsets

* fix complex reducers

* add remaining kernels

* add kernels for complex and bool sum

* move to segmented_reduce

* fix typo

* promote type

* fix complex bool reducer

* try another algo

* missed one

* use type inference

* make numba happy

* remove reducer overloads

* use sum op func for complex types

* remove test of depricated code

* avoid using == to compare floating-point products

* fix boundary tests

* cleanup

* cleanup

* remove dead code

* revert lexsort to argmin/max

* handrolled lexsort

* remove dead code

* remove bincount

* import numba cuda for jit

* fix tests

---------

Co-authored-by: maxymnaumchyk <maxymnaumchyk@gmail.com>
Co-authored-by: maxymnaumchyk <70752300+maxymnaumchyk@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Iason Krommydas <iason.krom@gmail.com>
ianna added a commit that referenced this pull request Jun 30, 2026
* feat: complete CPU kernel migration from `parents` to `offsets` (#3988)

* next step in kernel migration from parents to offsets

* linter fix

* add jax bincount

* add cpp kernel to convert parents to offsets

* fix typo

* fix typo in an auto-generated test

* almost there

* nearly there

* cleanup

* fix remaining kernels

* final cleanup

* format json data

* format

* initialize maxnextparents  = -1 (a sentinel meaning "no bin was touched")

* update the kernels to work on offsets!

* format

* migrate cupy rawkernels from parents to offsets

* migrate jax reducers

* fix for platfroms where the int64 counts can't be safely cast

* add bincount for cupy backend

* compact loc

* fix windows build and add optional OpenMP support

* update cuda kernels

* feat: add `missing_repeat` kernel implementation using cuda.compute (#3922)

* feat: add missing_repeat implementation using cuda.compute

* keep the same name as in cpu kernel

* add tests for repetitions>1 and regularsize>1

* style: pre-commit fixes

* add keywords

* style fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat: add `index_rpad_and_clip` kernels implementations using cuda.compute (#3923)

* feat: add `index_rpad_and_clip` kernels implementation using cuda.compute

* style fix

* add a test for `index_rpad_and_clip_axis0` that would have target>length

* add keyword names

* style

* Apply suggestions from Ianna

Co-authored-by: Ianna Osborne <ianna.osborne@cern.ch>

* style: pre-commit fixes

---------

Co-authored-by: Ianna Osborne <ianna.osborne@cern.ch>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix: array attrs not being validated at creation and being of inconsistent type (#3996)

* convert dict attrs to Attrs type

* add test

* fix: ensure jax backend uses arrays on cpu only (#3990)

* ensure jax uses cpu by default

* remove now redundant jax_platform_name setting

* change error messages

* better errors

* remove DeviceArray mentions as that does not exist while we're at it too

* almost there

* cleanup

* cleanup

* remove old data file

* update cupy kernels

* remove exlicit test for depricated kernel

* add complex kernels and port them to use offsets

* fix complex reducers

* add remaining kernels

* add kernels for complex and bool sum

* move to segmented_reduce

* fix typo

* promote type

* fix complex bool reducer

* try another algo

* missed one

* use type inference

* make numba happy

* remove reducer overloads

* use sum op func for complex types

* remove test of depricated code

* avoid using == to compare floating-point products

* fix boundary tests

* cleanup

* cleanup

* remove dead code

* revert lexsort to argmin/max

* handrolled lexsort

* remove dead code

* remove bincount

* import numba cuda for jit

* fix tests

---------

Co-authored-by: maxymnaumchyk <maxymnaumchyk@gmail.com>
Co-authored-by: maxymnaumchyk <70752300+maxymnaumchyk@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Iason Krommydas <iason.krom@gmail.com>

* chore: profile: add benchmark script (#4073)

add benchmark script

* feat: add some of the kernels using cuda.compute (#3981)

* feat: add `awkward_IndexedArray_overlay_mask` kernel using cuda.compute

* feat: add `awkward_IndexedArray_reduce_next_64` kernel using cuda.compute

* feat: add `IndexedArray_reduce_next_nonlocal_nextshifts_64` kernel using cuda.compute

* feat: add `ByteMaskedArray_getitem_nextcarry` kernel using cuda.compute

* feat: add `awkward_ByteMaskedArray_numnull` kernel using cuda.compute

* feat: add `awkward_RegularArray_getitem_jagged_expand` kernel using cuda.compute

* add an upper bound

* style: pre-commit fixes

* feat: add `awkward_RegularArray_getitem_jagged_expand` kernel using cuda.compute

* feat: add `awkward_UnionArray_simplify_one` kernel using cuda.compute

* feat: add `awkward_ListArray_broadcast_tooffsets` kernel using cuda.compute

* feat: add `awkward_ListArray_localindex` kernel using cuda.compute

* fix the impl

* feat: add `awkward_ListArray_compact_offsets` kernel using cuda.compute

* feat: add `awkward_ListArray_combinations_length` kernel using cuda.compute

* feat: add `awkward_ListArray_combinations` kernel using cuda.compute

* feat: add `awkward_UnionArray_nestedfill_tags_index` kernel using cuda.compute

* fix the tests for kernels that are deliberately raising errors

* compare `starts` and `stops` separately

* ignore `memptr` argument for pylint

* style: pre-commit fixes

* Add functions for indexing and repeating arrays

* style: pre-commit fixes

* return unary_transform call for segment_ids

* style: pre-commit fixes

* update the `awkward_IndexedArray_reduce_next_64` to work with offsets

* style: pre-commit fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ianna Osborne <ianna.osborne@cern.ch>

* feat: migrate some more kernels to cuda.compute (#4019)

* feat: add reimplementation of the `awkward_RegularArray` kernels using cuda.compute

* reimplement more kernels using cuda.compute

* reimplement more kernels using cuda.compute

* style: pre-commit fixes

* style fix

* use the named functions instead of lambdas

* add new kernels

* add new kernels

* fix a type mismatch

* style: pre-commit fixes

* add new kernels

* fix the overflow error

* new batch of kernels (draft)

* add comments and cleanup

* fix the tests messages

* add new `BitMaskedArray` kernels

* modify the `test_1381_check_errors.py` test

* resolve the conflicts

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* Fable fixes based on the report

* sort kernel issues addressed

* add tests

* add benchmarks

* add benchmarks

* fix memory leak

* add benchmarks/cuda_compute_cache_leak_reproducer.py

* fix ruff checks

* synchronization

* fix it

* fix memory leak

* more fixes

* more tests

* reduce temporaries

* more tests

* relax conditions

* fix bench

* bigfix

* fix bug

* relax condition

* add kernel fusion with parrot

* the same for more reducers

* cleanup

* apply __restrict__ uniformly

* rename macro-generated ABI symbols to match the kernel name

* add tests

* add O2 build

* fix

* add max_segment_size

* add benchmarks and cccl profiler

* pin cccl and clean up

* cleanup

* add test

* fix overflow int64

---------

Co-authored-by: maxymnaumchyk <maxymnaumchyk@gmail.com>
Co-authored-by: maxymnaumchyk <70752300+maxymnaumchyk@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Iason Krommydas <iason.krom@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-next-release Required for the next release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants