I have been an extensive user of attrs
for two years, but I have discovered cattrs
only recently so my question may sound naive.
In my codes, I often use a class method to instantiate an attrs
object from a json file. For example :
from cattrs.preconf.json import make_converter
from attrs import field, define, validators
from enum import StrEnum, auto
from pathlib import Path
class Colors(StrEnum):
BLUE = auto()
RED = auto()
GREEN = auto()
@define
class A:
color: Colors = field(validator=validators.instance_of(Colors))
value: int = field(validator=validators.instance_of(int))
@classmethod
def from_json_file(cls, path: Path):
with open(path, 'r') as f:
data = json.load(f)
return cls(color=Colors(data["color"]), value=data["value"])
I was wondering if I could use the power of ¢attrs
and the json converter in the following way :
@classmethod
def from_json_file(cls, path: Path):
json_converter = make_converter()
return json_converter.loads(path.read_text(), cls)
The code works as expected but does it respect the principle of cattrs
to separate the class logic from the un/structuring rules ?
No. Creating a converter instance within the class method violates cattrs' principle of separation between class logic and un/structuring rules. The conversion configuration should be maintained externally.
converter = make_converter()
converter.register_structure_hook(Colors, lambda v, _: Colors(v))
@define
class A:
color: Colors = field(validator=validators.instance_of(Colors))
value: int = field(validator=validators.instance_of(int))
def load_a_from_json(path: Path) -> A:
return converter.loads(path.read_text(), A)