python-attrs / cattrs

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

Extra keys #580

Open kellerza opened 2 weeks ago

kellerza commented 2 weeks ago

Description

Is it possible to get the keys that were not used during a call to structure(input_dict, SomeClass)?

One way would be to use forbid_extra_keys to get the names of these extra keys, but then you would have to run structure a second time if you still want to use the structured data

kellerza commented 1 week ago

For now I'm using this.

It's based on the fallback_field example in the docs. It support an attrs alias but not the overrides

def pre_process(
    converter_arg: Converter,
    *,
    unknown_field: str = "",
) -> typing.Any:
    """Decorator to move unknown fields to a specific field."""

    def decorator(cls: typing.Any) -> typing.Any:
        struct = make_dict_structure_fn(cls, converter_arg)

        def structure(d: dict[str, typing.Any], cl: typing.Any) -> typing.Any:
            fields = adapted_fields(get_origin(cls) or cls)  # type: ignore
            all_fields = {a.alias or a.name for a in fields}
            unknown_f = set(d.keys()) - all_fields
            d[unknown_field] = {k: d.pop(k) for k in unknown_f}

            return struct(d, cl)

        converter_arg.register_structure_hook(cls, structure)

        return cls

    return decorator
Tinche commented 1 week ago

Hello,

I'm on paternity leave currently so my availability is dependent on how well our baby sleeps 😥

I was going to ask what do you want to do with the extra keys, but I see the idea is to stick them into an attribute?

Your approach is pretty solid. I think you can pull out the first two lines out of structure into preprocess to optimize a little.

If you want to support overrides, I think you can use converter.get_structure_hook instead of make_dict_structure_func and look at hook.overrides - the generated hooks will have their overrides stored there. If present, this attribute can be examined and used to adapt your logic.