Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GenConverter.register_unstructure_hook fails with recursive unstructure_attrs_asdict #118

Closed
spookylukey opened this issue Jan 26, 2021 · 2 comments

Comments

@spookylukey
Copy link

  • cattrs version: 1.1.2, master
  • Python version: 3.9
  • Operating System: Linux

Description

I was trying to use register_unstructure_hook to add a handle that does normal asdict style unstructuring, plus adds an extra field (a type tag). I found that it worked the first time, but subsequent execution fails.

Test case:

import attr
import cattr

converter = cattr.GenConverter()


@attr.s
class C:
    a: int = attr.ib(default=1)


def handler(obj):
    return {
        'type_tag': obj.__class__.__name__,
        **converter.unstructure_attrs_asdict(obj)
    }


converter.register_unstructure_hook(C, handler)

inst = C()

expected = {'type_tag': 'C', 'a': 1}

unstructured1 = converter.unstructure(inst)
unstructured2 = converter.unstructure(inst)

assert unstructured1 == expected, repr(unstructured1)
assert unstructured2 == unstructured1, repr(unstructured2)

You see it fails on the final assertion, not the first i.e. the second call behaves differently from the first, which was very surprising.

I found that I'm possibly "doing it wrong" - if I use cattr.global_converter.unstructure_attrs_asdict instead of converter.unstructure_attrs_asdict I get the intended behaviour. It's not clear to me if this is a bug or something that needs to be added to the documentation.

@Tinche
Copy link
Member

Tinche commented Jan 26, 2021

Ah, I see the issue. The GenConverter is wired to generate and register an automatic hook in unstructure_attrs_asdict. Usually if a manual hook is registered that function will never get called, but you're calling it yourself here. That's why the first call works fine, and the other doesn't (since your manual hook gets overwritten with the generated hook).

I think this is a bug and this use case should be supported. I will look into it.

@Tinche Tinche closed this as completed in ad6be86 Jan 28, 2021
@Tinche
Copy link
Member

Tinche commented Jan 28, 2021

I pushed a fix for this to master, adding a test alongside. Thanks!

petergaultney pushed a commit to petergaultney/cattrs that referenced this issue Jan 28, 2021
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

No branches or pull requests

2 participants