Skip to content

Make customizing Schema behavior with subclasses easier #1812

@sirosen

Description

@sirosen

This was mentioned in #1751:

I think this is an indication that Schema needs to be easier to customize, not that we need to bake more custom functionality into the base schema.

OneOfSchema is just one motivating use-case. More generally, what kind of structures are problematic today for customizing Schema?


Some examples of things which could possibly be improved:

  1. Customizing _serialize and _deserialize?

#1726 is all about making Schema._serialize and Schema._deserialize open to subclasses as a better place to customize behavior. Whether or not extra={...} is a good idea (#1726), is making these steps friendly to overload a good approach?

  1. Hook execution (order matters)

Often, users want a schema base class which has some fixed "pre_load" or "post_load" behavior. But if a base schema adds a @pre_load method, it will get mixed with the potential hooks on subclasses and the user's desired ordering is lost.

One approach would be to let users overload hook processing and rely on super() to call the "real" hooks. The signatures for _invoke_schema_validators, _invoke_load_processors, and _invoke_dump_processors are all slightly different. Can they be unified into a method like Schema.run_hook(...)? Or, alternatively, replace these with methods like Schema.run_pre_load_hooks(...)?

  1. Customizing handling of unknown fields

INCLUDE, EXCLUDE, and RAISE are good out-of-the-box behaviors. Looking at issues like #853 , could this potentially be solved by making the handling of unknown fields settable as a hook?

Mainly, the logic is here:

if unknown != EXCLUDE:
fields = {
field_obj.data_key if field_obj.data_key is not None else field_name
for field_name, field_obj in self.load_fields.items()
}
for key in set(data) - fields:
value = data[key]
if unknown == INCLUDE:
ret_d[key] = value
elif unknown == RAISE:
error_store.store_error(
[self.error_messages["unknown"]],
key,
(index if index_errors else None),
)

What about Schema.handle_unknown_fields(...) or some method like that? So the Schema class implements today's behavior, and users can subclass and override with their own behaviors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions