Problem rs.sleep computing python

Hello everyone,

I’m trying to use the rs.sleep() function in order to create a time interval between operation for batch rendering purpose.

But when I try to use the rs.sleep() function in a loop, it only works at the end of the whole loop.
For instance I tried the simple script but everything is printed in the same time instead of one line each 2000ms

print “This”
rs.Sleep(2000)
print “is”
rs.Sleep(2000)
print “a”
rs.Sleep(2000)
print “slow”
rs.Sleep(2000)
print “message!”*

Thanks guys!

Welcome @haehnsen,

The problem is that the GHPython component doesn’t recompute at each loop iteration! Instead it runs your script once internally, keeping track of your desired pauses, and then returns the result(s) at the script end. It only updates itself, if it gets externally triggered, by you or an input parameter changing.

What you are trying to do isn’t possible, unless you explicitly control the way the component gets updated:

example

from scriptcontext import sticky
import Grasshopper as gh
import time

def update_component():
    """Updates this component, similar to using a Grasshopper timer."""
    # written by Anders Deleuran (andersholdendeleuran.com)
    def call_back(e):
        """Defines a callback action"""
        ghenv.Component.ExpireSolution(False)
    # Get the Grasshopper document
    ghDoc = ghenv.Component.OnPingDocument() 
    # Schedule this component to expire
    ghDoc.ScheduleSolution(1, \
        gh.Kernel.GH_Document.GH_ScheduleDelegate(call_back))


message_parts = "This is a slow message!".split(" ")

if Reset and "Count" in sticky.keys():
    sticky.pop("Count", None)
    ghenv.Component.Message = "Reset"

if Run:
    if not "Count" in sticky.keys():
        count = 0
        sticky["Count"] = count
        update_component()
    else:
        count = sticky["Count"]
        if count < len(message_parts)-1:
            count += 1
            sticky["Count"] = count
            ghenv.Component.Message = "Running"
            update_component()
        else:
            ghenv.Component.Message = "Finished"
    
    print "{}: {}".format(count, message_parts[count])
    time.sleep(0.5)
4 Likes

Thanks P1r4t3b0y!!

It was exactly what I was looking for,

Cheers!

Great solution, thanks P1r4t3b0y!

Just wondering. Is it possible to make it wait for a external (from another component) condition to be met in order to proceed to the next loop, instead of the timer? (sleep).

By the way, here follows a small amendment where the boolean toggle is not necessary:

import scriptcontext as sc
import Grasshopper as gh
import time

def update_component():
    """Updates this component, similar to using a Grasshopper timer."""
    # written by Anders Deleuran (andersholdendeleuran.com)
    def call_back(e):
        """Defines a callback action"""
        ghenv.Component.ExpireSolution(False)
    # Get the Grasshopper document
    ghDoc = ghenv.Component.OnPingDocument() 
    # Schedule this component to expire
    ghDoc.ScheduleSolution(1, \
        gh.Kernel.GH_Document.GH_ScheduleDelegate(call_back))

#Resets the sticky dictionary
if Reset and "list_index" in sc.sticky.keys():
    sc.sticky.pop("list_index", None)
    ghenv.Component.Message = "Reset"
    sc.sticky["run_timed_loop"] = True

if sc.sticky.Contains("run_timed_loop"):
    if sc.sticky["run_timed_loop"]:
        #after reseting, if the sticky dictionary is empty, start counting and putting
        if not "list_index" in sc.sticky.keys():
            count = 0
            sc.sticky["list_index"] = count
            update_component()
        #filter when starts counting (index > 0)
        else:
            count = sc.sticky["list_index"]
            #loop over all list but the last item
            if count < len(list)-1:
                count += 1
                sc.sticky["list_index"] = count
                ghenv.Component.Message = "Running"
                update_component()
            # list last item
            else:
                ghenv.Component.Message = "Finished"
                sc.sticky["run_timed_loop"] = False
        item = list[count]
        time.sleep(time_to_delay)

Python sleep() will pause for an hour, day or whatever if given the proper value. It does not allow other processes take place (in same script) however. A better way is to use an event which will create an event on timeout.

Have a look at threading.Timer. It runs your function in a new thread without using sleep().

from threading import Timer

def hello():
    print "hello, world"

t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed

The second method to delay would be using the implicit wait method:

driver.implicitly_wait(5)

The third method is more useful when you have to wait until a particular action is completed or until an element is found:

self.wait.until(EC.presence_of_element_located((By.ID, 'UserName'))