Search code examples
pythonpython-typingmetaclasspython-dataclasses

Making classfactory that derive from dataclass objects informed by types in python


When using dataclasses.dataclass the type information informs how parameters are parsed. I would like to take a defined dataclass and produce a class that changes all the attribute type declarations from X to Optional[List[X]].

from dataclasses import dataclass
from dataclasses_json import DataClassJsonMixin
from datetime import datetime

@dataclass
class SrcClass(DataClassJsonMixin):
    number: int
    name: str
    at: datetime

SrcClassLister = make_lister(SrcClass)

I want the function make_lister to produce a class similar to the class defined below.

@dataclass
class SrcClassLister(DataClassJsonMixin):
    numbers: Optional[List[int]]
    names: Optional[List[str]]
    ats: Optional[List[datetime]]

I am unsure how type information is captured for parsing by the dataclass.

My reason for doing this is I have a high variety of dataclass definitions and I would like to automatically make a spec for filtering. This spec would take a list of values that are acceptable for a pass-filter.


Solution

  • I'd imagine something like

    import dataclasses
    import typing
    from dataclasses import dataclass
    from dataclasses_json import DataClassJsonMixin
    from datetime import datetime
    
    
    @dataclass
    class SrcClass(DataClassJsonMixin):
        number: int
        name: str
        at: datetime
        purpose: int = 42
    
    
    def pluralize(name):
        # TODO: improve this if you will
        return name + "s"
    
    
    def make_lister(src_cls):
        fields = [
            (pluralize(field.name), typing.Optional[typing.List[field.type]], dataclasses.field(default=None))
            for field in dataclasses.fields(src_cls)
        ]
        name = f"{src_cls.__name__}Lister"
        return dataclasses.make_dataclass(name, fields, bases=(DataClassJsonMixin,))
    
    
    SrcClassLister = make_lister(SrcClass)
    
    scl = SrcClassLister(numbers=[1, 2])
    print(scl)
    print(scl.to_json())
    

    works for you - this prints out

    SrcClassLister(numbers=[1, 2], names=None, ats=None, purposes=None)
    {"numbers": [1, 2], "names": null, "ats": null, "purposes": null}