Documentation does not explain unstruct_collection_overrides' input

Open Beginner friendly
#513 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
64/100
Issue type
Documentation
Clarity
Clearly specified
Activity status
Stale
Tech stack
python
Domain
documentation

Research direction

Start with the “Customizing collection unstructuring” section in the unstructuring documentation and the Converter docstring. Document what input functions in unstruct_collection_overrides receive, including the unstructured collection contents, and make the explanation consistent in both locations.

Written by the indexing model from the issue text.

Description

  • cattrs version: 23.2.3
  • Python version: 3.11.4
  • Operating System: MacOS
Description

I am trying to unstructure sets into something that JSON can cope with and that is canonical (equal for any two equal sets; set iteration order can differ for equal sets). I tried unstruct_collection_overrides={Set: sorted} and obtained a very confusing error ("< not supported between dict and dict"). It turns out that the problem is that the functions in unstruct_collection_overrides receive a generator that emits the unstructured contents of the collection (at least for Set; I'm not sure for dicts). Since the objects in my set are frozen attrs objects, they themselves work fine in a Set (and being sorted), but once unstructured they become dictionaries, which can't be sorted.

[Edited to add: my conclusion is that this isn't really possible; that's not the bug, that's just an unfortunate limitation.]

The problem: the documentation at https://catt.rs/en/stable/unstructuring.html#customizing-collection-unstructuring never specifies what the unstructuring functions receive as input. Neither does the docstring for Converter (https://catt.rs/en/stable/cattrs.html#cattrs.Converter). A little explanation would have helped tremendously in tracking down the mysterious error.

What I Did
@frozen
class A:
    x: int = 0
    y: int = 0


def convert_set(s):
    list_s = list(s)
    print(f"{list_s=}")
    return sorted(list_s)


converter = Converter(unstruct_collection_overrides={Set: convert_set})

converter.unstructure({A(x=1), A(x=2), A(x=3)})

gives

list_s=[{'x': 3, 'y': 0}, {'x': 1, 'y': 0}, {'x': 2, 'y': 0}]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[12], [line 15](vscode-notebook-cell:?execution_count=12&line=15)
     [10](vscode-notebook-cell:?execution_count=12&line=10)     return sorted(list_s)
     [13](vscode-notebook-cell:?execution_count=12&line=13) converter = Converter(unstruct_collection_overrides={Set: convert_set})
---> [15](vscode-notebook-cell:?execution_count=12&line=15) converter.unstructure({A(x=1), A(x=2), A(x=3)})

File [~/Library/Caches/pypoetry/virtualenvs/da-dropper-wire-data-l5CQQYIb-py3.11/lib/python3.11/site-packages/cattrs/converters.py:238](https://file+.vscode-resource.vscode-cdn.net/Users/annearchibald/projects/da-dropper-wire-data/analysis/~/Library/Caches/pypoetry/virtualenvs/da-dropper-wire-data-l5CQQYIb-py3.11/lib/python3.11/site-packages/cattrs/converters.py:238), in BaseConverter.unstructure(self, obj, unstructure_as)
    [237](https://file+.vscode-resource.vscode-cdn.net/Users/annearchibald/projects/da-dropper-wire-data/analysis/~/Library/Caches/pypoetry/virtualenvs/da-dropper-wire-data-l5CQQYIb-py3.11/lib/python3.11/site-packages/cattrs/converters.py:237) def unstructure(self, obj: Any, unstructure_as: Any = None) -> Any:
--> [238](https://file+.vscode-resource.vscode-cdn.net/Users/annearchibald/projects/da-dropper-wire-data/analysis/~/Library/Caches/pypoetry/virtualenvs/da-dropper-wire-data-l5CQQYIb-py3.11/lib/python3.11/site-packages/cattrs/converters.py:238)     return self._unstructure_func.dispatch(
    [239](https://file+.vscode-resource.vscode-cdn.net/Users/annearchibald/projects/da-dropper-wire-data/analysis/~/Library/Caches/pypoetry/virtualenvs/da-dropper-wire-data-l5CQQYIb-py3.11/lib/python3.11/site-packages/cattrs/converters.py:239)         obj.__class__ if unstructure_as is None else unstructure_as
    [240](https://file+.vscode-resource.vscode-cdn.net/Users/annearchibald/projects/da-dropper-wire-data/analysis/~/Library/Caches/pypoetry/virtualenvs/da-dropper-wire-data-l5CQQYIb-py3.11/lib/python3.11/site-packages/cattrs/converters.py:240)     )(obj)

File :2, in unstructure_iterable(iterable)

Cell In[12], [line 10](vscode-notebook-cell:?execution_count=12&line=10)
      [8](vscode-notebook-cell:?execution_count=12&line=8) list_s = list(s)
      [9](vscode-notebook-cell:?execution_count=12&line=9) print(f"{list_s=}")
---> [10](vscode-notebook-cell:?execution_count=12&line=10) return sorted(list_s)

TypeError: '<' not supported between instances of 'dict' and 'dict'

as opposed to some kind of canonically sorted list.

Dominant language
Python
Stars
1.1k
Forks
159
Avg merge
12h 21m
Merged PRs (30d)
6

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from python-attrs/cattrs

All issues in python-attrs/cattrs

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.