Skip to content

Conversation

@reversefold
Copy link

@reversefold reversefold commented Dec 2, 2025

Fixes #699. The values of an Enum are unstructured and structured. Structuring is only done when the Enum class has a type defined for the _value_ attribute as per the Python typing standard.

I've added two very simple tests which show that this works. I'm attempting to add tests which use hypothesis like the rest but the magic chains of incantations in tests/typed.py are throwing me a bit and it's taking a while to understand what they're doing and how to use it to generate random dynamic Enum classes. Any pointers there would be appreciated.

@Tinche
Copy link
Member

Tinche commented Dec 2, 2025

Thanks for working on this, I will review within a couple days when I get some time. Don't worry about Hypothesis, I'm kind of moving away from it, since it bloats the test times and can turn out to be very complex to use properly, so the cost/benefit ratio is usually in favor of just normal unit tests. :)

@Tinche Tinche self-requested a review December 6, 2025 23:01
Copy link
Member

@Tinche Tinche left a comment

Choose a reason for hiding this comment

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

Sorry for the delay, I'm a little under the weather.

Looks like good work, left some comments.

([#698](https://github.com/python-attrs/cattrs/pull/698))
- Apply the attrs converter to the default value before checking if it is equal to the attribute's value, when `omit_if_default` is true and an attrs converter is specified.
([#696](https://github.com/python-attrs/cattrs/pull/696))
- Unstructure enum values and structure enum values if they have a type hinted `_value_` attribute.
Copy link
Member

Choose a reason for hiding this comment

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

I would rephrase this a little bit, maybe something like:

Take account of the optional value type hint when handling enums, if present.

Uses type hints for the "_value_" attribute if they exist to structure
the enum values before returning the result."""
hints = get_type_hints(cl)
Copy link
Member

Choose a reason for hiding this comment

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

get_type_hints is probably going to be expensive. Let's try doing a simple check first. Maybe something like:

if "_value_" in cl.__dict__:
    val = self.structure(val, get_type_hints(cl)["_value_"])

I want to avoid doing too much extra work in the majority of cases.

"""Convert an enum to its value."""
return obj.value
"""Convert an enum to its unstructured value."""
return self._unstructure_func.dispatch(obj.value.__class__)(obj.value)
Copy link
Member

Choose a reason for hiding this comment

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

Hm, I'm a little concerned about performance and backwards comp. Can we do a deep unstructure only if the enum has a _value_ attribute, like when structuring?

'siamese'
```

Enum structuring and unstructuring even works for complex values, like tuples, but if you have anything but simple literal types in those tuples (`str`, `bool`, `int`, `float`) you should consider defining the Enum value's type via the `_value_` attribute's type hint so that cattrs can properly structure it.
Copy link
Member

Choose a reason for hiding this comment

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

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.

The value of enums should be unstructured and structured too

2 participants