Dinosaur
Dinosaur

Reputation: 25

How to get all the subclasses of an abstract class in different files

I'm trying to apply design pattern to make it extendable and easy to maintain.

Here is my file structure:

/evaluation
│── metrics/
│──│── metric.py  # abstract class 
│──│── QWK.py
│──│── PCC.py
│── evaluators/ 
│──│── __init__.py
│──│── evaluator.py # abstract class
│──│── score_evaluator.py
│──│── feedback_evaluator.py
│── evaluator_factory.py

evaluator.py

class Evaluator(ABC):
    def __init__(self, evaluation_config, framework_config, **kwargs):

        self.evaluation_config = evaluation_config
        self.framework_config = framework_config

        self.logger = WandbLogger()

    @abstractmethod
    def load_evaluation_data(self, data_path):
        pass

    @abstractmethod
    def __call__(self, *args, **kwargs):
        pass

score_evaluator.py

class ScoreEvaluator(Evaluator):
    def __init__(self, evaluation_config, framework_config, **kwargs):
        super().__init__(evaluation_config, framework_config, **kwargs)

        self.score_generator = ScoreGenerator(llm=LLMClient(),
                                              vlm=VLMClient(),
                                              config=self.framework_config)


    def load_evaluation_data(self, data_path):
        ...
        return evaluation_data


    async def __call__(self, *args, **kwargs):
        ... 

        return evaluation_results

evaluator_factory.py

from evaluation.evaluators.evaluator import Evaluator

class EvaluatorFactory:
    def __init__(self, framework_config, evaluation_config, **kwargs):
        self.framework_config = framework_config
        self.evaluation_config = evaluation_config
        self.kwargs = kwargs

        self.evaluators = self._create_evaluators()

    def _create_evaluators(self):
        evaluators = []
        evaluator_classes = Evaluator.__subclasses__()
        print(evaluator_classes) # bug here, get empty list 
        evaluator_module = importlib.import_module("evaluation.evaluators.evaluator")
        print(evaluator_module) # second attempt using importlib, and inspect still get empty dict. 
        evaluators = {
            name: cls()
            for name, cls in inspect.getmembers(evaluator_module, inspect.isclass)
            if issubclass(cls, evaluator_module.Evaluator) and cls is not evaluator_module.Evaluator
        }

        print(evaluators)
        for cls in evaluator_classes:
            evaluators.append(cls(self.framework_config, self.evaluation_config, **self.kwargs))

        return evaluators

    async def evaluate(self):
        evaluation_results = {}
        print(len(self.evaluators))
        for evaluator in self.evaluators:
            results = await evaluator()
            evaluation_results[evaluator.__name__] = results

        return evaluation_results

Dear design pattern specialists:), help me.

I also want to design something with the metrics:

Thank youuuuuu so much~


Edit 1

I figured out that __subclasses__ only works when the subclasses already loaded in memory, to do so I need to register it in the __init__ file:

evaluators/__init__.py

from evaluation.evaluators.score_evaluator import ScoreEvaluator
from evaluation.evaluators.feedback_evaluator import FeedbackEvaluator

__all__ = ["ScoreEvaluator", "FeedbackEvaluator"]

Still waiting for any other approaches and my second concern 😊

Upvotes: 0

Views: 43

Answers (0)

Related Questions