Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

'EvalFunc' object is not callable when working with class #261

Answered by dlashua
vlycop asked this question in Q&A
Discussion options

Hello :)
I am just starting and encountering issue when working on jupyter with the hass pyscript kernel.

I am wondering if this is a limit off hass python, pyscript, or me being a newbe.

With this simplifed exemple:

class BaseMessage:
 @classmethod
 def print_value(cls, value):
 print(value)
toto=BaseMessage()
toto.print_value("titi")

On my python, i get at the output

titi

but using hass pyscript kernel i get the following error

Exception in <jupyter_3> line 8:
 toto.print_value("titi")
 ^
TypeError: 'EvalFunc' object is not callable

Did i miss a limitation ? I am running the latest stable HASS from there docker repo in a development environment.

Thank you !

EDIT:
Just to be sure i tried the same command in the hass docker python, it does work.
So it's something else and i have no idea how that kernel thing work

You must be logged in to vote

In this particular case, I believe it's subclassing that isn't working.

As a whole, I'm really not sure. Subclassing, passing methods or classes created in pyscript to native python modules, and the use of non-pyscript decorators are issues I've run in to myself. But I don't know if a full list has been made.

In short, the solution is, keep your pyscript code to very simple classes and methods. For everything else, use native python modules of @pyscript_compile. It just means you have to separate the logic between what talks to HASS and what doesn't, since anything in @pyscript_compile won't be able to use pyscript functionality.

Replies: 2 comments 2 replies

Comment options

pyscript is Python, but there are some language limitations; features that are not available. In short, almost everything in pyscript (classes, functions, class methods, etc) are turned into classes internally. This makes, for one, using non-pyscript decorators difficult.

The easiest way around this is to use the @pyscript_compile decorator.

I have not tested this, but I believe this will work in your case:

@pyscript_compile
def makeBaseMessage(): 
 class BaseMessage:
 @classmethod
 def print_value(cls, value):
 print(value)
 return BaseMessage
BaseMessage = makeBaseMessage()
toto=BaseMessage()
toto.print_value("titi")
You must be logged in to vote
1 reply
Comment options

Thank you for the feedback :)
Sadly it look like your solution is breaking other thing, for example pyscript function don't seam to work in the class (a log.debug return that log is undef). So no way to run hass task or trigger latter.

I am also having other issue, like subclass not registering themself (i tried to remove all decorators)

Here is what I've started to work on. Could you clarify what will not work (as a hole and not just in this example) for me ? That way i can restart from 0, but with a good idea of what to avoid.

app_config = pyscript.config['apps']['my_app1']
class Device:
 
 device_classes = {}
 
 def __init_subclass__(cls, **kwargs):
 super().__init_subclass__(**kwargs)
 cls.device_classes[cls._DEVICE_TYPE] = cls
 
 def __get_device_config(self, device_name):
 try:
 device_config = app_config["device"][device_name]
 log.debug(f"retrived config for device {device_name}: {device_config}")
 return(device_config)
 except(KeyError):
 log.error(f"{device_name} is not present in the config file")
 return(False)
 
 def set_type(self):
 if self.config["type"] not in self.device_classes:
 raise ValueError('Bad device type {}'.format(self.config["type"]))
 return self.device_classes[self.config["type"]](self.device_name)
 
 def __init__(self, device_name):
 self.device_name=device_name
 print(f"creating {device_name}")
 self.config = self.__get_device_config(self.device_name)
 def is_available(self):
 raise NotImplementedError
 def turn_on(self):
 raise NotImplementedError
 
 def notify(self):
 raise NotImplementedError
class Android_app_device(Device):
 _DEVICE_TYPE = 'android_app'
 
 def turn_on(self):
 log.debug("android device can't be turned on")
 return(True)
 def is_available(self):
 log.debug("android device availability can't be checked")
 return(True)
 def notify(self, message, title=None, data={}, tag=None, color=None, sticky=None, channel=None, importance=None, persistent=None, timeout=None):
 if tag:
 data["tag"] = tag
 if color:
 data["color"] = color
 data["ledColor"] = color
 if sticky:
 data["sticky"] = bool(sticky)
 if persistent:
 data["persistent"] = bool(persistent)
 if timeout:
 data["timeout"] = timeout
 if channel:
 data["channel"] = channel
 if importance:
 data["importance"] = importance
 log.debug({"title": title, "message": message, "data": data})
 def clear_notify(self, tag):
 log.debug(f"clearing notification taged {tag}")
 self.notify(message="clear_notification", tag=tag)
 def remove_channel(self, channel):
 log.debug(f"removing channel named {channel}")
 self.notify(message="remove_channel", channel=channel)
 def tts_notify(self, message):
 log.debug(f"sending \"{message}\" in TTS")
 self.notify(message="TTS", title=message, channel="alarm_stream_max")
x=Device('galaxys4')
print(x.device_classes)
> creating galaxys4
> retrived config for device galaxys4: {'notify_service': 'notify.mobile_app_gt_i9505', 'type': 'android_app', 'status_check': None, 'turn_on': None}
> {}
x=x.set_type()
> ValueError: Bad device type android_app

But with raw python

x=Device('galaxys4')
print(x.device_classes)
x=x.set_type()
x.turn_on()
> creating galaxys4
> debug: retrived config for device galaxys4: {'notify_service': 'notify.mobile_app_gt_i9505', 'type': 'android_app', 'status_check': None, 'turn_on': None}
> {'android_app': <class '__main__.Android_app_device'>}
> creating galaxys4
> debug: retrived config for device galaxys4: {'notify_service': 'notify.mobile_app_gt_i9505', 'type': 'android_app', > 'status_check': None, 'turn_on': None}
> debug: android device can't be turned on
> True
Comment options

In this particular case, I believe it's subclassing that isn't working.

As a whole, I'm really not sure. Subclassing, passing methods or classes created in pyscript to native python modules, and the use of non-pyscript decorators are issues I've run in to myself. But I don't know if a full list has been made.

In short, the solution is, keep your pyscript code to very simple classes and methods. For everything else, use native python modules of @pyscript_compile. It just means you have to separate the logic between what talks to HASS and what doesn't, since anything in @pyscript_compile won't be able to use pyscript functionality.

You must be logged in to vote
1 reply
Comment options

i tend to overcomplicate thing i don't master, so that will keep me in check :D
Thank you for sharing some of your knowledge on this, i will work around those limit and make my centralized notification another way ;D

Cheers !

Answer selected by vlycop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet
2 participants

AltStyle によって変換されたページ (->オリジナル) /