Base class with abstract method _conn()
from cached_property import cached_property
class Base:
def __init__(self, conn_id):
"""Store secrets details"""
self.conn_id = conn_id
@cached_property
def _conn(self):
"""Fetch secrets and generate authenticated client"""
raise NotImplemented
def get_conn(self):
"""Return authenticated client"""
return self._conn
Parent classes
from cached_property import cached_property
class Parent(Base):
@cached_property
def _conn(self):
"""Generate authenticated client specific for Parent"""
client = ...
return client
Child classes
from typing import List, Optional
from pydantic.dataclasses import dataclass
@dataclass
class Toy:
name: str
type: str
def get_color(self) -> str:
color = self.get_conn().get_toy_color(...)
return color
@dataclass
class Child:
first_name: str
last_name: str
...
def list_all_toys(self) -> List[Toy]:
all_toys = self.get_conn().fetch_all_toys(...)
return [Toy(name=x.toy_name, type=x.toy_type) for x in all_toys]
def get_favorite_toy(self) -> Optional[Toy]:
favorite_toy = self.get_conn().fetch_favorite_toy(...)
if not favorite_toy:
return None
return Toy(name=favorite_toy.toy_name, type=favorite_toy.toy_type)
(Ideal) Usage
parent = Parent(conn_id='my-secret-connection-details')
child_1 = parent.Child(first_name='John', last_name='Doe')
for each_toy in child_1.list_all_toys():
print(f"{child_1.first_name}'s toy {each_toy.name} is a {each_toy.get_color()} {each_toy.type}.")
# John's toy Teddy is a white stuffed bear.
Important notes
- The parent class can be an ordinary Python class, but the children classes should be Python/Pydantic dataclasses.
- The goal of using the same
get_conn()
method is to reduce the number attempts to fetch credentials and to authenticate.
I've thought about solving this using a @classmethod
of the children classes that returns an authenticated instance. Seemed promising until I realized that dataclasses don't allow you to modify their __init__
method. For example:
from typing import Callable, Optional
from pydantic.dataclasses import dataclass
@dataclass
class Toy:
...
@classmethod
def generate_with_connection(cls, connection: Callable, *args, **kwargs):
return cls(*args, **kwargs, connection=connection) # Requires logic in __init__ to handle `connection`.
@dataclass
class Child:
...
def get_favorite_toy(self) -> Optional[Toy]:
favorite_toy = self.get_conn().fetch_favorite_toy(...)
if not favorite_toy:
return None
return Toy.generate_with_connection(
connection=self.get_conn,
name=favorite_toy.toy_name,
type=favorite_toy.toy_type
)
Questions
- How do you link the parent class and multiple children classes to ensure that each child class can access the same
get_conn()
method of the parent class? My first guess would be inheritance but I don't think it solves the next question. Are there other ways using the inspect/traceback modules? - How do we ensure that the methods of each children class can return instances of other children classes that also have access to the same
get_conn()
method of the parent class? For example:Child.get_favorite_toy()
should return an instance ofToy
which can successfully runToy.get_color()
using the sameget_conn()
method.