Skip to content

fix(types): mapping protocol on Structs (dict + **obj + iter) — v0.4.4#10

Merged
vitalii-dynamiq merged 1 commit into
mainfrom
fix/struct-mapping-protocol
May 6, 2026
Merged

fix(types): mapping protocol on Structs (dict + **obj + iter) — v0.4.4#10
vitalii-dynamiq merged 1 commit into
mainfrom
fix/struct-mapping-protocol

Conversation

@vitalii-dynamiq

@vitalii-dynamiq vitalii-dynamiq commented May 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Patch release. dynamiq's embedder code emits `meta = {"model": response.model, "usage": dict(response.usage)}`, which fails on a bare `msgspec.Struct` because Python falls back to integer indexing when neither the mapping protocol nor an iterable-of-pairs is recognised. arcllm 0.4.3 had `getitem/setitem` but not the full mapping protocol.

Extends `_DictLike` with:

Method Purpose
`keys()` Returns Struct `struct_fields` — required by `dict()`
`iter` Yields field names (matches `dict.iter`)
`len` Field count
`values()`, `items()` Derived from keys
`getitem(non-str)` Now `KeyError` instead of confusing `TypeError`

Now `dict(usage)`, `{**usage}`, `for k in usage` all behave like litellm's Pydantic Usage record.

Validation

  • `dict(Usage(...))` returns a populated dict
  • `for k in Struct` yields field names
  • arcllm 776 → 780 unit tests (4 new `TestDictLikeAccess` regressions)
  • mypy --strict + ruff clean

Bumps to 0.4.4.


Note

Low Risk
Low risk patch: adds mapping-protocol methods to _DictLike to improve compatibility with dict(obj)/**obj and adjusts error behavior for non-string keys. Changes are localized to type ergonomics and covered by new unit tests.

Overview
Improves LiteLLM-compat dict-style behavior for msgspec.Struct response types by extending _DictLike to implement the mapping protocol (keys, __iter__, __len__, plus items/values), enabling dict(usage), **usage, and for k in usage.

Tightens __getitem__ to raise KeyError for non-string keys (avoids confusing dict() integer-index fallbacks), adds regression tests for the new behaviors, and bumps the package version to 0.4.4.

Reviewed by Cursor Bugbot for commit 76e1fc6. Bugbot is set up for automated code reviews on this repo. Configure here.

Continuing the litellm-fixture-compat work. dynamiq's embedder code
emits ``meta = {"model": response.model, "usage": dict(response.usage)}``,
which fails on a bare ``msgspec.Struct`` because Python falls back to
integer indexing when neither the mapping protocol (``keys() +
__getitem__``) nor an iterable-of-pairs is recognised.

Extends ``_DictLike`` with the mapping protocol:

- ``keys()`` returns the Struct's declared ``__struct_fields__``
- ``__iter__`` yields field names (matches ``dict.__iter__``)
- ``__len__`` returns the field count
- ``values()`` and ``items()`` derive from keys
- ``__getitem__`` rejects non-str keys with ``KeyError`` instead of
  the confusing ``TypeError: attribute name must be string``

Now ``dict(usage)``, ``{**usage}``, and ``for k in usage`` all work
identically to litellm's Pydantic Usage record.

Bumps to 0.4.4.
@vitalii-dynamiq vitalii-dynamiq merged commit 836bd5a into main May 6, 2026
14 of 15 checks passed
@vitalii-dynamiq vitalii-dynamiq deleted the fix/struct-mapping-protocol branch May 6, 2026 17:15
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.

1 participant