question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Defining fields programmatically

See original GitHub issue

I have a list of field names as strings

FIELDS = ('field_1', 'field_2',..., 'field_42')

and I would like to create this schema programmatically:

class MySchema(Schema):

    field_1 = Float()
    field_2 = Float()
    ...
    field_42 = Float()

I managed to do that with a custom metaclass in which one can specify lists of dynamic fields. Each element of the list is a tuple containing both a list of field names and a Field specification (a dict containing field class + optional args and kwargs).

    class DynamicSchemaOpts(SchemaOpts):
    
        def __init__(self, meta):
            super().__init__(meta)
            self.auto_fields = getattr(meta, 'auto_fields', [])
    
    
    class DynamicSchemaMeta(SchemaMeta):
    
        @classmethod
        def get_declared_fields(mcs, klass, cls_fields, inherited_fields, dict_cls):
    
            fields = super().get_declared_fields(klass, cls_fields, inherited_fields, dict_cls)
    
            for auto_field_list in klass.opts.auto_fields:
                field_names, field = auto_field_list
                field_cls = field['cls']
                field_args = field.get('args', [])
                field_kwargs = field.get('kwargs', {})
                for field_name in field_names:
                    fields.update({field_name: field_cls(*field_args, **field_kwargs)})
    
            return fields
    
    
    class MySchema(Schema, metaclass=DynamicSchemaMeta):
    
        OPTIONS_CLASS = DynamicSchemaOpts
    
        class Meta:
            strict = True
            auto_fields = [
                (FIELDS,
                 {'cls': Float}),
            ]

See this SO question for the whole story and an example using a field with args and kwargs.

It seems to work.

I’d appreciate some feedback. Is this the right way to address this issue?

The code would be simpler if I could pass a field instance (especially for fields with args and kwargs)

class Meta:
    strict = True
    auto_fields = [
        (FIELDS, Float()),
    ]

but then all the fields in FIELDS would share the same Nested field instance. Could this be an issue? I peaked into the fields in Marshmallow and didn’t identify any use case that would break, but it doesn’t look like a good idea. A custom field could store some information in its instance that is not meant to be shared. I’d appreciate feedback about this as well.

I thought that would be a Python issue with a generic Python solution, but what I did is specific to Marshmallow. Would it make sense to add this feature to the library?

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:11 (8 by maintainers)

github_iconTop GitHub Comments

6reactions
maximkulkincommented, Feb 15, 2017

What happened to plain old metaprogramming?!

MySchema = type('MySchema', (marshmallow.Schema,), {
    attr: marshmallow.fields.Float()
    for attr in FIELDS
})

You can even have different types of fields there:

fields = {}
fields['foo'] = marshmallow.fields.Float()
fields['bar'] = marshmallow.fields.String()
MySchema = type('MySchema', (marshmallow.Schema,), fields)

or as a base for your customizations:

class MySchema(type('_MySchema', (marshmallow.Schema,), fields)):
    @marshmallow.post_dump
    def update_something(self, data):
        pass
1reaction
maximkulkincommented, Feb 15, 2017

You could also do

MySchema = type(
    'MySchema',
    (marshmallow.Schema,),
    dict({
        field: ma.fields.Nested(MyEmbeddedSchema)
        for field in FIELDS
    }, Meta=type('Meta', tuple(), {'strict': True})
)
Read more comments on GitHub >

github_iconTop Results From Across the Web

Define fields programmatically in Marshmallow Schema
All you need to do is to use type() function to build your class with any attributes you want: MySchema = type('MySchema', (marshmallow....
Read more >
Programmatically get field definition for custom user profile fields
Yes you can get field definition programmatically with field name and entity name, by using EntityFieldManager::getFieldDefinitions .
Read more >
Populating fields programmatically
In Marketing Operations, you can create custom fields that are populated programmatically from the values in other fields.
Read more >
Programmatically define a text field plus a float and set ...
I'm using the following code to define a text field and a float: ... 'instance_myfield' => array( 'field_name' => 'MyField', ...
Read more >
How To Programmatically Add Input Fields to React Forms
When working with forms in React, there are situations when we don't have a pre-defined number of input fields and can't hard-code or...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found