marshmallow-annotations
marshmallow-annotations copied to clipboard
Handle generating field for schema that isn't defined yet
Closes #5
Adding a new parameter to AbstractConverter is probably a breaking change :/ -- but can use the upgrade to Marshmallow 3 as an excuse to also bump major version. :eyes:
Anyways, idea here is that when we are generating a schema if we encounter a field that we don't know about yet, we can just create a kind of thunk field (appropriately named ThunkedField) that delays creating the actual field until it's requested, and then caches that field.
The ThunkedField will proxy all operations to the underlying field, creating it if necessary. This is potentially dangerous if there's a marshmallow plugin that'll poke at the created field BEFORE the other schema is created.
This first pass implementation actually improperly handles lists, optionals, etc by just generating thunks for them all since it happens pretty early in _get_field_from_typehint, but as a first pass works pretty well. Fixing this might require additionally updating TypeRegistry.get to accept an additional argument or adding a get_or_thunk method (which is probably better) in which case the ThunkedField can carry less information, just what the FieldFactory delegate declares
Risks (setting aside the new parameter thing):
The following would now generate a schema but fail at first serialization attempt -- rather than eagerly fail:
class Foo:
bar: List["bar"] # WHOOPS!
class Bar:
pass
Possible solution: Push a __THUNKED__: bool into the field settings and make the end user explicitly declare that a field is to be thunked:
class FooSchema(AnnotationSchema):
class Meta:
target = Foo
class Fields:
# explicitly opt into thunkiness rather than as the default for everything
bar = {"__THUNKED__": True}
I like the explicit opt-in better, even if it's slightly cumbersome, since it prevents unexpected surprises down the line (leaving only expected surprises). And means that only convert needs to change since convert_all would receive the opt-in via the field configurations.