Skip to content

Commit

Permalink
fix: enforce string-only keys in .attrs (#3350)
Browse files Browse the repository at this point in the history
* enforce string keys in .attrs

* add test; minor wording improvements

* style: pre-commit fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
pfackeldey and pre-commit-ci[bot] authored Dec 18, 2024
1 parent 55f1909 commit bc14d22
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 deletions.
16 changes: 11 additions & 5 deletions src/awkward/_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ def attrs_of(*arrays, attrs: Mapping | None = None) -> Mapping:


def without_transient_attrs(attrs: dict[str, Any]) -> JSONMapping:
return {
k: v for k, v in attrs.items() if not (isinstance(k, str) and k.startswith("@"))
}
return {k: v for k, v in attrs.items() if not k.startswith("@")}


class Attrs(Mapping):
def __init__(self, ref, data: Mapping[str, Any]):
self._ref = weakref.ref(ref)
self._data = _freeze_attrs(data)
self._data = _freeze_attrs(
{_enforce_str_key(k): v for k, v in _unfreeze_attrs(data).items()}
)

def __getitem__(self, key: str):
return self._data[key]
Expand All @@ -61,7 +61,7 @@ def __setitem__(self, key: str, value: Any):
if ref is None:
msg = "The reference array has been deleted. If you still need to set attributes, convert this 'Attrs' instance to a dict with '.to_dict()'."
raise ValueError(msg)
ref._attrs = _unfreeze_attrs(self._data) | {key: value}
ref._attrs = _unfreeze_attrs(self._data) | {_enforce_str_key(key): value}

def __iter__(self):
return iter(self._data)
Expand All @@ -76,6 +76,12 @@ def to_dict(self):
return _unfreeze_attrs(self._data)


def _enforce_str_key(key: Any) -> str:
if not isinstance(key, str):
raise TypeError(f"'attrs' keys must be strings, got: {key!r}")
return key


def _freeze_attrs(attrs: Mapping[str, Any]) -> Mapping[str, Any]:
return MappingProxyType(attrs)

Expand Down
18 changes: 18 additions & 0 deletions tests/test_3350_enforce_attrs_string_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# BSD 3-Clause License; see https://github.com/scikit-hep/awkward/blob/main/LICENSE
# ruff: noqa: E402

from __future__ import annotations

import pytest

import awkward as ak


def test():
arr = ak.Array([1])

with pytest.raises(
TypeError,
match="'attrs' keys must be strings, got: 1",
):
arr.attrs[1] = "foo"

0 comments on commit bc14d22

Please sign in to comment.