Marshmallow: Generate a TypedDict or dataclass from Schema

Created on 17 Sep 2019  路  6Comments  路  Source: marshmallow-code/marshmallow

It would be nice to be able to use Schemata with mypy or similar, e.g.

class User(Schema):
    name = fields.String()
    age = fields.Integer()


def have_a_birthday(user: User.type) -> User.type:
    user['age'] += '1'  # will fail type check
    return user  # typechecks OK

I started an inline implementation with Schema._declared_fields, but since there's nothing like a Field.deser_type it was going to be quite a hacky map by cases - isinstance(cls, fields.String) etc. - and then I realised I had nested fields to contend with and jumped out of the rabbit hole before I got too deep.

I do think this would be very nice to have though, or perhaps even go further and have a @deser_to_dataclass decorator (that's the route I was going) that re-writes the Schema so that the type is User (or whatever) itself, and User.name is annotated automatically as : str.

enhancement feedback welcome

Most helpful comment

I've been considering something like this. It's a neat idea.

A few half-baked thoughts:

  • You would need to generate types from schema instances rather than classes. Conceptually, a schema _instance_ represents a set of known inputs/outputs, whereas a schema class is more like a blueprint or factory.
  • There need to be different TypedDicts generated for load vs dump. So you could have an API like
def user_detail(user: LoadType(UserSchema())) -> DumpType(UserSchema()):
    # ...
  • This is pretty tricky given that post_load and post_dump methods can return any type.

I probably won't pursue this myself for a while, and I don't think we should put this into marshmallow core at least until PEP 589 lands. If you end up experimenting with this in a 3rd-party repo, though, please let us know.

I do think this would be very nice to have though, or perhaps even go further and have a @deser_to_dataclass

You might want to look into https://github.com/lovasoa/marshmallow_dataclass . It generates a schema from dataclass that also deserializes to the same dataclass.

All 6 comments

I've been considering something like this. It's a neat idea.

A few half-baked thoughts:

  • You would need to generate types from schema instances rather than classes. Conceptually, a schema _instance_ represents a set of known inputs/outputs, whereas a schema class is more like a blueprint or factory.
  • There need to be different TypedDicts generated for load vs dump. So you could have an API like
def user_detail(user: LoadType(UserSchema())) -> DumpType(UserSchema()):
    # ...
  • This is pretty tricky given that post_load and post_dump methods can return any type.

I probably won't pursue this myself for a while, and I don't think we should put this into marshmallow core at least until PEP 589 lands. If you end up experimenting with this in a 3rd-party repo, though, please let us know.

I do think this would be very nice to have though, or perhaps even go further and have a @deser_to_dataclass

You might want to look into https://github.com/lovasoa/marshmallow_dataclass . It generates a schema from dataclass that also deserializes to the same dataclass.

+1 for marshmallow_dataclass. It would be cool to eventually see this kind of functionality included in Marshmallow by default now that it's Python 3-only!

Well, we'll be supporting Python 3.5 and 3.6 for a while, so probably won't be added to marshmallow core any time soon. That said, it seems to be actively maintained, and I might even help out with it.

Maybe marshmallow 4 could go PY3.7+ and include marshmallow-dataclass?

Maybe marshmallow 4 could go PY3.7+ and include marshmallow-dataclass?

@lafrech I'm open to that. We could even do it in marshmallow 3 if we keep it in an isolated module.

How about building a schema based on an existing TypedDict class? There's a plenty of information that can be inferred from the type definition, similar to marshmallow-dataclass.

Was this page helpful?
0 / 5 - 0 ratings