lidatong / dataclasses-json

Easily serialize Data Classes to and from JSON
MIT License
1.34k stars 150 forks source link

[FEATURE] Flag for skipping private fields in export #526

Open D-Sokol opened 2 months ago

D-Sokol commented 2 months ago

Description

I'm using dataclasses-json to load search configuration with a regular expression pattern from JSON. To speed up my application I compile regexp in __post_init__ and store it in a separate private field. The problem is that I cannot use .to_json() after that because of compiled pattern, despite I don't need it in the output JSON.

My code:

import re
from dataclasses_json import dataclass_json
from dataclasses import dataclass, field

@dataclass_json
@dataclass
class Search:
    pattern: str = r"\d+"
    _pattern: re.Pattern = field(init=False, repr=False)

    def __post_init__(self):
        self._pattern = re.compile(self.pattern)

a = Search()
print(a.to_json())

Desired output: {"pattern": "\\d+"} Actual output: TypeError: Object of type Pattern is not JSON serializable

Possible solution

Possible solution is a flag that causes dataclasses_json to skip private fields:

@dataclass_json(ignore_private=True)
@dataclass
class Search:
    ...

or a config parameter that removes field from output:

...
_pattern: re.Pattern = field(init=False, repr=False, metadata=config(ignore=True))
...

Alternatives

Marking field as ClassVar/InitVar or omitting an annotation produces desired result, but I'd like to avoid misleading annotations.

Some tricks that excludes certain fields from dataclasses control (e.g. base class that is not a dataclass) should work, but I think they should be part of a dataclass and ignored only for serialization purposes, also it separates part of class definition into somewhere else.

Context

versions:

Python 3.9.2
dataclasses-json==0.6.4
OS: 5.10.0-28-amd64 #1 SMP Debian 5.10.209-2 (2024-01-31) x86_64 GNU/Linux
D-Sokol commented 2 months ago

Found a :paramref:dataclasses_json.cfg.config.exclude, which solves exactly this problem. It is not clear why it was not mentioned in the documentation and readme file.