I'm trying to create classes that can be saved to a JSON file. The idea is to convert my object to a dataclass that stores only the important attributes. I'll then use something from json or dataclass_wizard to save the dataclass to a file/reconstruct the object later.
Here's the problem: I want to have an alternate constructor to create the object from the dataclass. I can't overload __init__(), so I'm using a @classmethod. Because the from_briefcase() method is overridden in BiggerBusinessMan, I get a mypy error that this violates the LSP. I can see why I get this error, but is there a way to tell Python that from_briefcase() is meant to be an alternate constructor and not part of the interface? As far as I understand, changing the arguments of __init__() would not violate the LSP, so I want from_briefcase() to be treated similarly.
from dataclasses import dataclass
from typing import Self
@dataclass
class Briefcase:
item1: str
item2: str
@dataclass
class BiggerBriefcase(Briefcase):
item3: str
# also has `item1` and `item2`
class BusinessMan:
def __init__(self):
self.item1 = ""
self.item2 = ""
@classmethod
def from_briefcase(cls, briefcase: Briefcase) -> Self:
businessman = cls()
businessman.item1 = briefcase.item1
businessman.item2 = briefcase.item2
return businessman
class BiggerBusinessMan(BusinessMan):
def __init__(self):
super().__init__()
self.item3 = ""
@classmethod
def from_briefcase(cls, briefcase: BiggerBriefcase) -> Self: # mypy error on this line
# I want to be able to use the base class constructor
businessman = super().from_briefcase(briefcase)
businessman.item3 = briefcase.item3
return businessman
# these two lines would really be run by some sort of JSON loader to create the dataclasses
basic_briefcase = Briefcase("notes", "cards")
bigger_briefcase = BiggerBriefcase("pens", "pencils", "letters")
# I'm not trying to use `from_briefcase()` polymorphically, it's supposed to be like a constructor
basic_businessman = BusinessMan.from_briefcase(basic_briefcase)
bigger_businessman = BiggerBusinessMan.from_briefcase(bigger_briefcase)
Also, I know I could use a dict instead of a dataclass to solve this issue, but I want stronger typing and to not have to keep track of the correct dictionary keys.
Worst case I can throw a # type: ignore on there but that seems silly. I could also use __init__(self, briefcase), but I would like to be able to create the object without needing a Briefcase instance.