custom-components / pyscript

Pyscript adds rich Python scripting to HASS
Apache License 2.0
874 stars 46 forks source link

Feature Request: Service Closure #509

Closed rajeee closed 1 year ago

rajeee commented 1 year ago

The ability to use closure for Triggers and being able to define a range of trigger functions in a loop is very handy. Could you also extend this functionality to @service definitions? Looks like its not possible to create multiple services with

all_services = []
for i in range(10):
    @service(f"test.service{i}')
    def func():
        log.debug(f"Service {i}")
    all_services.append(func)

All of the test.servicex will print the last service, service 9.

craigbarratt commented 1 year ago

It should work with @service too, although I don't think I tested that.

The problem with your code is that the variable i inside every func() is bound to the same single variable i, which has the value 9 after the loop. The f-string inside the function is not evaluated until the function is called. So when the service is called, the f-string is evaluated and i has the value 9 for all ten service functions. The @service is evaluated when the function is defined, so its f-string will work as you expect.

Something like this should work, since function argument defaults are evaluated once at definition time (disclaimer: untested):

all_services = []
for i in range(10):
    @service(f"test.service{i}')
    def func(service_num=i):
        log.debug(f"Service {service_num}")
    all_services.append(func)
rajeee commented 1 year ago

Ha! Thanks. I forgot how closure is supposed to work in python! I can confirm that the suggest fix works. Maybe worth adding a note in the documentation that this works with services (and other things?) too.