'Problems with ABC/Interfaces using pydantic + Mixins pattern

Im trying to implement Mixin patter while Im using Pydantics BaseClass to facilitate the instantiation and validation of data from my class. The problem is that my Mixins cannot inhirit from my base classes (actually, the dependency is the opposite ). Also, im using mypy so my implementation needs to be rightly typed.

Lets see an simplified example:

class BaseCart(BaseModel):
    id: int
    items: List[Item]
    adress: str


class CartInterface(ABC):
    @abstractproperty
    def id(self):
        ...

    @abstractproperty
    def items(self):
        ...

    @abstractproperty
    def adress(self):
        ...

    @abstractmethod
    def get_shipping_value(self):
        ...

    @abstractmethod
    def get_items_availability(self):
        ...


class ShippingMixin(ABC, CartInterface):
    def get_shipping_value(self) -> int:
        # some business logic using self.address to calculate

class NormalItemsMixin(ABC, CartInterface):
    def get_items_availability(self) -> bool:
       # iterate over self.items and check stock availability

class AwesomeItemsMixin(ABC, CartInterface):
    def get_items_availability(self) -> bool:
       # iterate over self.items and check stock availability
       # this implementation is different from the normal one

class NormalCart(BaseCart, ShippingMixin, NormalItemsMixin):
    ...

class AwesomeCart(BaseCart, ShippingMixin, AwesomeItemsMixin):
    ...

The problem is that after implementing this, I can't instantiate AwesomeCart, I get the following error: TypeError: Can't instantiate abstract class ResellerCart with abstract methods business_unit, cart_type, channel, id, items, reseller, status, updated_at

What am I missing ?

TLDR: Why this


class Data(BaseModel):
    a: int

class IData(ABC):
    @abstractproperty
    def a(self):
        ...

class XData(Data, IData):
    ...

raises TypeError: Can't instantiate abstract class XData with abstract method a when I instanciates XData likes x = XData(a=1)?



Solution 1:[1]

In IData a is only "masquarading" as a property when in fact it is a method of the class. You have to do something like

class Data(BaseModel):
    _a: int

    @property
    def a(self):
        return self._a


class IData(ABC):
    @abstractproperty
    def a(self):
        pass


class XData(Data, IData):
    pass

Now a in Data is also a method and the code works as expected.


@abstractproperty is deprecated since python 3.3, use 'property' with 'abstractmethod' instead.

class IData(ABC):
    @property
    @abstractmethod
    def a(self):
        pass

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nicu Tofan