Can I use abstract methods with Appdaemon using ABC?

I have started to write a series of apps with Appdaemon to control my electrical consumption smarter. I now have created 5 apps which today includes copy of the same code in the apps. I had an idea to create class that inherits from hass.Hass where I put all the common functionality. Then each app inherits from that. I came to a situation where I wanted to define abstract methods which my apps needed to implement. All with the purpose to make the apps similar and simple to develop.
After some googling I found https://www.geeksforgeeks.org/abstract-classes-in-python/ which described the class ABC which introduces abstract methods.
Before I even try to create the abstract methods I run into problem with the setup.

I defined the class like this:

import appdaemon.plugins.hass.hassapi as hass
from datetime import datetime, timedelta, date
from abc import ABC, abstractmethod

class NLEnergyBase(hass.Hass, ABC):
...

The I have a app that used the class like this:

from datetime import datetime, timedelta
from NLEnergyBase import NLEnergyBase

class CarChargerV3(NLEnergyBase):
...

When I run this app this is what is written into the error log:

2023-01-15 21:25:35.630008 WARNING BilladdareV3: ------------------------------------------------------------
2023-01-15 21:25:35.630543 WARNING BilladdareV3: Unexpected error initializing app: BilladdareV3:
2023-01-15 21:25:35.630917 WARNING BilladdareV3: ------------------------------------------------------------
2023-01-15 21:25:35.632048 WARNING BilladdareV3: Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/appdaemon/app_management.py", line 1026, in check_app_updates
    await self.init_object(app)
  File "/usr/lib/python3.10/site-packages/appdaemon/app_management.py", line 321, in init_object
    modname = await utils.run_in_executor(self, __import__, app_args["module"])
  File "/usr/lib/python3.10/site-packages/appdaemon/utils.py", line 337, in run_in_executor
    response = future.result()
  File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/appdaemon/apps/energy/CarChargerV3.py", line 16, in <module>
    class CarChargerV3(NLEnergyBase):
  File "/usr/lib/python3.10/abc.py", line 106, in __new__
    cls = super().__new__(mcls, name, bases, namespace, **kwargs)
TypeError: NLEnergyBase.__init_subclass__() missing 1 required positional argument: 'a'

2023-01-15 21:25:35.632564 WARNING BilladdareV3: ------------------------------------------------------------

I have not defined a __init__ method for my class.

Is it impossible to use abstract methods using the class ABC in Appdaemon?
Is it obvious what I’m doing wrong?

Yes, it is possible but IMO, unless you really know what you’re doing, it isn’t ideal to use such a design pattern in AD. Instead you can create one (or multiple) apps that registers one (or multiple) services and can be called, and passed various parameters from other apps. You’ll want to use persistent namespace for registering your own services in AD.

1 Like

Thanks for feedback!
I might lower my ambition and simplify the solution instead.