custom-components / pyscript

Pyscript adds rich Python scripting to HASS
Apache License 2.0
894 stars 47 forks source link

How to use class inheritance correctly #628

Closed cjlapao closed 2 months ago

cjlapao commented 2 months ago

I am trying to create some modules that contains code that is reusable and I am trying to use class inheritance to do so.

for example

class Device:
    def __init__(self, device_id, **args):
      self._device_id = device_id
      self._name = args.get("name", device_id)
      self._domain = device_id.split(".")[0]
      self._friendly_name = args.get("friendly_name", self._name)
      self._brightness = args.get("brightness", 0)
      self._color_temp = args.get("color_temp", 0)
      self._group = args.get("group", None)

    def info(self):
        return f"Name: {self.name()}\nID: {self.device_id()}\nArgs: {self._args}"

class TestLight(Device):
    def __init__(self, device_id, **args):
        # super().__init__(device_id, **args)
        log.info(f"Creating TestLight with {args}")
        self._automation_device_id = None

    def turn_on(self, **kwargs):
        if self._domain == "light" or self._domain == "switch":
            self.call_service("turn_on", **kwargs)
            return True
        return False

    def turn_off(self, **kwargs):
        if self._domain == "light" or self._domain == "switch":
            self.call_service("turn_off", **kwargs)
            return True
        return False

    def call_service(self, action, **kwargs):
        # Placeholder for service call logic
        print(f"Calling service {action} with {kwargs}")

this then creates an error as the super seems to not work properly

Is there any way I can bypass this?

ALERTua commented 2 months ago

My workaround: https://github.com/ALERTua/ha_pyscript_modules/blob/main/entities/switch.py#L5 its super: https://github.com/ALERTua/ha_pyscript_modules/blob/main/entities/entity.py#L74

cjlapao commented 2 months ago

@ALERTua Yes I did something similar yesterday,

class TestLight(Device):
    def __init__(self, device_id: str, **args):
        Device.init(self, device_id, **args)
        if self.is_debug_enabled():
            log.debug(f"Creating light {device_id} with {args}")
        clean_args = self.clean_args(**args)
        self.set_args(**clean_args)
        self._attributes = LightAttributes(device_id)
        self._tiggers = []
        self.init(**args)

This is my approach, very similar

thanks

craigbarratt commented 2 months ago

As you discovered, certain class features don't work properly in pyscript. One specific challenge is that all functions in pyscript are async, including class methods you create. That means that things like creating magic methods (eg, operator overloading) won't work, since python will expect those methods to be regular functions. One workaround is to create the class using regular python with @pyscript_compile.

ALERTua commented 2 months ago

I would pin this issue for future generations and close it. Glad I helped.

cjlapao commented 2 months ago

I agree, I am satisfied with the solution I found and all works really well for me