python-attrs / cattrs

Composable custom class converters for attrs, dataclasses and friends.
https://catt.rs
MIT License
791 stars 110 forks source link

Type validation on unstructure #433

Open danielnelson opened 10 months ago

danielnelson commented 10 months ago

Description

I want users of my library to fill out an attrs class, then later I will unstructure it and send it out to a remote API. When the user creates the attrs instance, they can optionally use mypy to make sure they set the attributes to the correct types, but of course this is optional. Before I send out the data on the network I would like to be sure it matches the correct schema.

I know I could use attrs validators to enforce types in the attrs class, but I've found that its hard to do correctly for more advanced types. Before I send out the data on the network I would like to be sure it matches the correct schema.

However, it appears that cattrs doesn't check types in unstructure the same way structure does. Is there a way to make cattrs unstructure strictly, or perhaps the recommendation is to add separate validation after unstructuring?

What I Did

import attrs
import cattrs

@attrs.define
class Foo:
    x: int = 42

f = Foo("wrong type")
print(cattrs.unstructure(f))

Actual output:

{'x': 'wrong type'}

Expected output: Exception

Tinche commented 10 months ago

Howdy,

I don't have any immediate plans for this, but you can try something like the following:

import attrs

import cattrs

c = cattrs.Converter()

def validate_int(i):
    if not isinstance(i, int):
        raise TypeError()
    return i

c.register_unstructure_hook(int, validate_int)

@attrs.define
class Foo:
    x: int = 42

f = Foo("wrong type")
print(c.unstructure(f))

And put in some additional hooks for strings and other primitives. A comprehensive solution would probably involve writing a strategy, which I'd be glad to mentor someone to do.