'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 |