marshmallow
                                
                                 marshmallow copied to clipboard
                                
                                    marshmallow copied to clipboard
                            
                            
                            
                        Meta Decorator
Motivation
I often have lots of small schemas containing unique Meta classes with only a few attributes. The Meta class sometimes requires more lines than the schema definition and makes a file containing multiple schemas harder to read. This is especially true when using marshmallow-jsonapi due to type_.
Proposal
Provide a meta decorator that will inject its kwargs into a Meta class for the class it is wrapping.
Example
Before:
class TestSchema(Schema):
    foo = fields.String()
    bar = fields.String()
    class Meta:
        type_ = 'tests'
        ordered = True
After:
@meta(type_='tests', ordered=True)
class TestSchema(Schema):
    foo = fields.String()
    bar = fields.String()
Would it replace or update an existing (inherited) Meta class?
Updating would allow stacking, although I don't really see the use case for stacking.
Inheritance is another good use case where Meta is likely to only need a few attributes. I was initially imagining spreading the parent meta manually like @meta(..., **vars(ParentSchema.Meta)), but that doesn't actually work. Implicitly inheriting into a new class would be convenient.
A use case for stacking might be if you have enough attributes to justify a meta class, but still preferred the decorator syntax. It would avoid opening and indenting the meta arguments into a block (which a linter might do automatically).
@meta(
    type_='tests',
    include=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'j', 'k', ...],
)
class TestSchema(Schema):
    foo = fields.String()
    bar = fields.String()
@meta(type_='tests')
@meta(include=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'j', 'k', ...])
class TestSchema(Schema):
    foo = fields.String()
    bar = fields.String()
I ended up having to subclass the schema to get SchemaMeta.__new__ to rebuild opts from Meta. I am going to test drive this utility for a little while.
def meta(**kwargs):
    def wrapper(schema):
        class _Meta(schema.Meta):
            pass
        for key in kwargs:
            setattr(_Meta, key, kwargs[key])
        class _Schema(schema):
            Meta = _Meta
        _Meta.__name__ = schema.Meta.__name__
        _Schema.__name__ = schema.__name__
        return _Schema
    return wrapper
I quite like the ergonomics of this proposal. I've no strong objections to adding this
How will this interact with Meta.ordered = True?
When the specific class has set ordered=True, the _declared_fields is set to an OrderedDict() instance with inherited fields listed first, followed by the fields declared on the class directly, in declaration order, followed by any Meta.include pairs.
The issue I can see is that if the current class is inheriting from another Schema with Meta.ordered=False, then by the time the class decorator comes to the scene the _declared_fields dictionary will be a regular dictionary and the directly-declared fields are no longer easily distinguished from the inherited fields or Meta.include fields, especially if the latter overrides some of the class or inherited fields.
I ended up having to subclass the schema to get
SchemaMeta.__new__to rebuildoptsfromMeta.
This also rebuilds _declared_fields with the new meta options.
I published a module for this functionality. I think this should just be a community library for now. Once I cover it with tests I will add it to the wiki and close this issue.
https://github.com/deckar01/marshmallow-meta