How to inherit __iter__ from a ABC subclass through a router class?

43 Views Asked by At

I am trying to make a MVC framework with routing. The model itself is iterable. If I don't use a router class then it will give all the first keys from the model.

But when using the router class, I get the following error: TypeError: 'ABCMeta' object is not iterable

I have a simplified version of the source code:

Model

from abc import ABC, abstractmethod

class Model(ABC):
    @abstractmethod
    def __iter__(self):
        ...

    @abstractmethod
    def get(self, item):
        ...

    @property
    @abstractmethod
    def item_type(self, name):
        ...


class TestModel(Model):
    test_items = {
        "one": { "name": "1" },
        "two": { "name": "2" },
    }

    item_type = "test"

    def __iter__(self):
        yield from self.test_items
        

    def get(self, item):
        try:
            return self.test_items[item]
        except KeyError as key_err:
            print("Key cannot be found", key_err)

Controller

from abc import ABC, abstractmethod

class Controller(ABC):
    @abstractmethod
    def __iter__(self):
        ...

    @abstractmethod
    def show_items(self):
        ...

    @abstractmethod
    def show_item_information(self, item_name):
        ...

class TestController:
    def __init__(self, model, view):
        self.view = view
        self.model = model

    def show_items(self):
        items = list(self.model)
        item_type = self.model.item_type
        self.view.show_item_list(item_type, items)

    def show_item_information(self, item_name):
        try:
            item_info = self.model.get(item_name)
        except Exception:
            item_type = self.model.item_type
            self.view.item_not_found(item_type, item_name)
        else:
            item_type = self.model.item_type
            self.view.show_item_information(item_type, item_name, item_info)
 

Router

class Router:
    def __init__(self):
        self.routes = {}

    def register_controller(self, path, controller, model, view):
        self.routes[path] = controller(model, view)

    def resolve(self, path):
        callback = self.routes.get(path)
        if callback:
            return callback
        return self.default_controller

    def default_controller(self, *args, **kwargs):
        status = 'Controller not found'
        return status

Main

#!/usr/bin/env python3

from sys import argv

from lib.router import Router
from lib.model import TestModel
from lib.view import TestView
from lib.controller import TestController

def main():
    router = Router()
    router.register_controller('test', TestController, TestModel, TestView)

    path = argv[1]

    controller = router.resolve(path)
    controller.show_items()


if __name__ == '__main__':
    main()

What I expect is that with the routering that the model stays iterable.

I have tried to build in a check if the class is Iterable. But this isn't really a solution.

0

There are 0 best solutions below