Notice: This forum has been recovered from an old backup, so some content, links, and dates may be outdated. The forum is currently read-only while we restore sign-in and registration functionality. Details

If you find this forum valuable and would like to help keep it online, donations to help cover hosting and domain costs are greatly appreciated, but never expected. You can support the forum through Buy Me a Coffee or Ko-fi. Thank you for helping preserve the EventGhost community.

Scheduler and Threading issue

If you have a question or need help, this is the place to be.
Post Reply
Foune
Experienced User
Posts: 96
Joined: Sun Jul 03, 2011 7:08 pm

Scheduler and Threading issue

Post by Foune »

Hello, can someone tell me what's wrong when I do this :

Code: Select all

eg.scheduler.AddTask(0.1,eg.TriggerEvent("Action", payload="bla", prefix="Prefix", source=eg),"MyEvent1")
Exception in thread Thread-106:
Traceback (most recent call last):
File "threading.pyc", line 532, in __bootstrap_inner
File "threading.pyc", line 484, in run
TypeError: 'EventGhostEvent' object is not callable

Code: Select all

eg.scheduler.AddTask(0.1, urllib.urlopen("http://127.0.0.1:8080/json.htm?blabla"),"MyEvent2")
Exception in thread Thread-134:
Traceback (most recent call last):
File "threading.pyc", line 532, in __bootstrap_inner
File "threading.pyc", line 484, in run
AttributeError: addinfourl instance has no __call__ method
I'm doing like this as I need to have these actions threaded not to slow down EG. Even with these errors, everything is working, but I must be missing something.
User avatar
kgschlosser
Site Admin
Posts: 5190
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Scheduler and Threading issue

Post by kgschlosser »

OK we are going to go to school

AddTask(self, waitTime, func, *args, **kwargs):

this is the method for eg.scheduler.AddTask


the self you are going to ignore. but the waitTime, func, *args, **kwargs we are not

waitTime is pretty obvious
func is the function you want to run
and *args is the information you want to pass to func but these are positional arguments
and **kwargs is the information you want to pass to func these are keyword arguments


so what is happening is you are actually calling urllib.urlopen and not letting the scheduler do it because you have surrounded your information in ()'s without having a , between urllib.urlopen and the ()'s.
now because you don't want to pass a tuple as a positional argument containing your information you just want to pass the information it's self you will ditch the ()'s and put a , between urllib.urlopen and your information

so as an example

Code: Select all

eg.scheduler.AddTask(0.1, eg.TriggerEvent, 'Some_Suffix', None, 'Some_Prefix')

Code: Select all

eg.scheduler.AddTask(0.1, eg.TriggerEvent, prefix='Some_Prefix', suffix='Some_Suffix')

the 2 above examples do exactly the same thing. but one uses positional arguments and the other uses keyword arguments. the purpose to keyword arguments is if the person that wrote the code has set default values for some of the arguments.
as with Triggerevent it is coded like so.

the use of source is nothing you would have to worry about so i omitted it from this example

Code: Select all

TriggerEvent(self, suffix='', payload=None, prefix='Main')
so we can see that suffix is defaulted to blank. then payload is None and prefix is Main. so if we only wanted to supply a prefix.
instead of doing this

Code: Select all

TriggerEvent('', None, 'Some_Prefix')
we can do this, which is easier to understand. the code will leave the default values in place and only change the default value for prefix to 'Some_Prefix'

Code: Select all

TriggerEvent(prefix='Some_Prefix')

so with the scheduler a mechanism was provided so you can specify a specific argument or you can positionally set them. But you do not want to run the function as you are passing it to the scheduler. you want the scheduler to run it for you.. you error is because there is a returned value from running either one of those functions. in the case of urllib it returns a addinfourl object. so what you are really passing to the scheduler is the addinfourl object and then an argument of "MyEvent2" to be passed to that object so what is actually happening is this

now this is not what you want to have happen..

Code: Select all

addinfourl = urllib.urlopen("http://127.0.0.1:8080/json.htm?blabla")
addinfourl("MyEvent2")

Code: Select all

event = eg.TriggerEvent("Action", payload="bla", prefix="Prefix", source=eg)
event("MyEvent1")

you want the scheduler to run urllib,urlopen or eg.TriggerEvent
"MyEvent2" has no use

Code: Select all

eg.scheduler.AddTask(0.1, urllib.urlopen, "http://127.0.0.1:8080/json.htm?blabla")

Code: Select all

eg.scheduler.AddTask(0.1, eg.TriggerEvent, prefix="MyEvent1", suffix="Action", payload="bla")
or

Code: Select all

eg.scheduler.AddTask(0.1, eg.TriggerEvent, "Action", "bla", "MyEvent1")


Now here comes a little spin on it. position arguments and keywords arguments can be passed at the same time. so long as the positional arguments are passed first and then the keyword arguments. and anything without a default value HAS to be filled in before any keyword arguments are passed.

so this will make the suffix as "Action" and the prefix as "MyEvent1" and it will leave the payload at it's default of None

Code: Select all

eg.scheduler.AddTask(0.1, eg.TriggerEvent, "Action", prefix="MyEvent1")

Now when your head is done throbbing.. and you have taken a grip of migraine pills. come on back and ask away. this is a whole lot of information to grasp. and I tried to do my best to explain it fully and tried to do it in a way that is easiest to understand. don't kill yourself about trying to guess it it. if something is unclear (which i fully understand, took me a hell of a long to to get a handle on this bit of python) tell me what piece you are having an issue with. and how you think it should be working with the explanation i gave. a lot of times this will help me think of a better way to go about explaining something. (gives me a clue as to how your brain translates the information so i can alter it to fit how your bean works)
If you like the work I have been doing then feel free to Image
Foune
Experienced User
Posts: 96
Joined: Sun Jul 03, 2011 7:08 pm

Re: Scheduler and Threading issue

Post by Foune »

I.LOVE.YOU

I corrected all my calls to scheduler.AddTask
I put scheduler.AddTask every time I use urllib.open, or any function that could slow down the evengthost response time.
User avatar
kgschlosser
Site Admin
Posts: 5190
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Scheduler and Threading issue

Post by kgschlosser »

all you're makin me blush.. NOT!


LOL

I am just hoping that you understood that mess. and I hope you gained some more knowledge of python. and I know this will help you in the future because the *args, **kwargs thing is not limited to just the scheduler.

as an example of the **kwargs
here we are going to count from 0 to 3 and watch the output

Code: Select all


def trigger_event(suffix='', prefix='Some_Prefix', payload=None):
    eg.TriggerEvent(prefix=prefix, suffix=suffix, payload=payload)

for count in range(4):
    event = dict()
    if count == 1:
        event['suffix'] = 'Event1'
    elif count == 2:
        event['prefix'] = 'Event'
        event['suffix'] = '2'
    elif count == 3:
        event['prefix'] = 'Event'
        event['suffix'] = '3'
        event['payload'] = 'Some Payload Data'
    else:
        event['prefix'] = 'Event'
        event['suffix'] = 'NOT FOUND'

    trigger_event(**event)

if you notice i don't call trigger event inside of each of the specific if statements. so how kwargs works is it's a dictionary of key, value pairs. so if you use a dictionary and populate it with the keywords and a value for each of the keywords you want to use. it will put the information where it needs to be. The same holds true for args. since args are positional you can use a list or a tuple so long as the values in it are in the same order the function you are calling expects. but when you pass it you will need to place a * before it. there are no keywords needed if you are going to use the args way
If you like the work I have been doing then feel free to Image
Foune
Experienced User
Posts: 96
Joined: Sun Jul 03, 2011 7:08 pm

Re: Scheduler and Threading issue

Post by Foune »

Ok, I understood your explanations. Coming from 9 year programming using DOTNET, I'm not totally new to programming, but I admit that Python has a lot of tricks I'm not familiar with. Because I don't spend much time on programming anymore, I prefer writing long and "explicit" code (verbose old-school coding rather than compact/optimized).

Thank you for your help, I had a basic idea of the kwargs concept as I made a Foscam Plugin some years ago, and I had to deal with this concept. You gave me a good lesson, now I need to practice. Especially your loop for populating the dict, I didn't know it was possible to loop on a "event = dict()" statement. The python syntax is sometimes disturbing, IMO.
User avatar
kgschlosser
Site Admin
Posts: 5190
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Scheduler and Threading issue

Post by kgschlosser »

I come from cpp with microcontrollers. So it is very very different and it also took me a very long time to get past some of the crazy memory optimization thecniques used with the microcontrollers and no do the same with Python.
If you like the work I have been doing then feel free to Image
Post Reply