Making a script that runs once per second

I’m trying to understand how to make a Python script that would run once a second. Was trying to do it with a modal operator, but for some reason it’s not giving the expected result:


import bpy
import time

class ModalOperator(bpy.types.Operator):
    bl_idname = "object.modal_operator"
    bl_label = "Simple Modal Operator"
    
    lastTime = time.time()
    numCountdown = 0
    
    def execute(self, context):
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}
    
    def modal(self, context, event):
        if ((time.time()) >= (self.lastTime + 1.0)) : 
            self.numCountdown += 1
            self.lastTime += 1.0
            print(self.numCountdown)
        if (self.numCountdown >= 5) : return {'FINISHED'}
        
        return {'RUNNING_MODAL'}

bpy.utils.register_class(ModalOperator)
bpy.ops.object.modal_operator('EXEC_DEFAULT')

Instead of printing a number once a second, it prints several numbers at a time. What am I doing wrong?

Time was in milliseconds, no? They say time.clock() is seconds.

time.time() returns seconds.milliseconds same as time.clock() , just they have different start times
( time.time starts from 00:00:00 UTC, while time.clock starts from when it was first run ).

EDIT: Ok, it looks like Blender doesn’t output the printed value unless the mouse is constantly moving over top the Blender window while it’s running. How odd…I think this might be due to some sort of underlying performance optimization, but I’m not sure if it’s just waiting to show the results, or actually running the operation multiple times in a row to catch up when the mouse moves…

(this is on a Windows system btw).

As far as I understand it (and I could be totally wrong) modal (“def modal(self, context, event):”) is only executed if an event happened. That can be a mouse move, click, key stroke, … This also means that if nothing happens, your script will keep “RUNNING_MODAL” and wait for the next event to happen before modal is executed again. This may explain what is happening.

I think that an event_timer might be what you are looking for. Blender comes with an example for that (operator_modal_timer.py). You can find it in the Text Editor’s ‘Templates’ menu.