marshmallow-code / marshmallow-code/marshmallow

Object class and schema definition combined, ORM-style

Open
#2,000 5 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
7.2k
Forks
738
Avg merge
1d 23h
Merged PRs (30d)
7

Description

Hello all,

I would like to ask if there has been consideration about adding a model that allows for data storage and serialization/deserialization in one. This is a pretty common use case, avoiding redundancy between defining schemas and the data they produce. This could be done via an ORM-style model like SQLAlchemy has.

Something like this was discussed before (https://github.com/marshmallow-code/marshmallow/issues/1043) but since the recipe is simple and useful, I can see value adding it to marshmallow.

There are some libraries that accomplish similar goals, but they have some drawbacks:

  • marshmallow-dataclass is available but requires some boilerplate, plus some workarounds (e.g. must use dataclass fields rather than marshmallow fields)
  • marshmallow-objects exists but is currently archived

A possible API could look like the following:

from datetime import datetime

from marshmallow import MarshModel, INCLUDE, fields, ValidationError

class UserModel(MarshModel):
    __meta_args__ = {'unknown': INCLUDE}
    
    name: str = fields.Str()
    email: str = fields.Email()
    created_at: datetime = fields.DateTime()

    @validates('email'):
    def validate_email(self, value: Any) -> None:
        if '@' not in value:
            raise ValidationError('Not an email address!')

class BlogModel(MarshModel):
    title: str = fields.String()
    author: dict = fields.Nested(UserModel)

user_data = {"name": "Ronnie", "email": "ronnie@stones.com"}
user = UserModel.load(user_data)

blog = BlogModel(title="Something Completely Different", author=user)
blog.dump()
pprint(result)
# {'title': 'Something Completely Different',
#  'author': {'name': 'Ronnie',
#             'email': ronnie@stones.org',
#             'created_at': '2021-08-17T14:58:57.600623+00:00'}}

MarshModel would require:

  • Something that creates a schema from the defined class (maybe via an init_subclass hook to store it as cls.__schema or something)
  • Implicit __init__ function in similar way to dataclasses
  • Implicit load() classmethod that returns an instance
  • Typing - something similar to how SQLA handles this https://docs.sqlalchemy.org/en/14/orm/extensions/mypy.html#installation

If there is interest, I may be able to submit a PR

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the linked discussion in issue #1043 and the proposed MarshModel API; no implementation files or tests are identified here. Done would require an agreed scope and design for combined schema/model definitions, implicit initialization and load behavior, nested models, validation, and typing.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.