dbader / schedule

Python job scheduling for humans.
https://schedule.readthedocs.io/
MIT License
11.73k stars 959 forks source link

Doesn't work as expected when combined with pytest-freezegun. #629

Closed kimata closed 4 weeks ago

kimata commented 1 month ago

To test the code that uses schedule, I ran the following test code in combination with freezegun, but the test failed.

def test_time(freezer):                                                                                                                                  
    import schedule                                                                                                                                       
    import pytz                                                                                                                                           
    import time                                                                                                                                           

    TIMEZONE = datetime.timezone(datetime.timedelta(hours=9), "JST")                                                                                      

    logging.debug("time.localtime()               = %s", time.asctime(time.localtime(time.time())))                                                       
    logging.debug("datetime.now()                 = %s", datetime.datetime.now())                                                                         
    logging.debug("datetime.now(JST)              = %s", datetime.datetime.now(TIMEZONE))                                                                 

    freeze_time = datetime.datetime.now(tz=datetime.timezone(datetime.timedelta(hours=9))).replace(                                                       
        hour=0, minute=0, second=0                                                                                                                        
    )                                                                                                                                                     

    logging.debug("Freeze time at %s", freeze_time)                                                                                                       
    freezer.move_to(freeze_time)                                                                                                                          

    logging.debug("time.localtime()               = %s", time.asctime(time.localtime(time.time())))                                                       
    logging.debug("datetime.now()                 = %s", datetime.datetime.now())                                                                         
    logging.debug("datetime.now(JST)              = %s", datetime.datetime.now(TIMEZONE))                                                                 

    schedule.clear()                                                                                                                                      

    schedule_time = datetime.datetime.now(tz=datetime.timezone(datetime.timedelta(hours=9))).replace(                                                     
        hour=0, minute=1, second=0                                                                                                                        
    )                                                                                                                                                     
    schedule_time_str = schedule_time.strftime("%H:%M")                                                                                                   
    logging.debug("set schedule at %s", schedule_time_str)                                                                                                

    job_add = schedule.every().day.at(schedule_time_str, pytz.timezone("Asia/Tokyo")).do(lambda: True)                                                    

    idle_sec = schedule.idle_seconds()                                                                                                                    
    logging.info("Time to next jobs is %.1f sec", idle_sec)                                                                                               
    logging.debug("Next run is %s", job_add.next_run)                                                                                                     

    assert abs(idle_sec - 60) < 5

The output when running the test is as follows.

>       assert abs(idle_sec - 60) < 5
E       assert 32399.93986 < 5
E        +  where 32399.93986 = abs((32459.93986 - 60))

tests/test_basic.py:320: AssertionError
------------------------------------------------------------------- Captured log call --------------------------------------------------------------------
08:59:21 DEBUG [test_basic.py:291 test_time] time.localtime()               = Mon Jul 29 08:59:21 2024
08:59:21 DEBUG [test_basic.py:292 test_time] datetime.now()                 = 2024-07-28 23:59:21.060140
08:59:21 DEBUG [test_basic.py:293 test_time] datetime.now(JST)              = 2024-07-29 08:59:21.060140+09:00
08:59:21 DEBUG [test_basic.py:299 test_time] Freeze time at 2024-07-29 00:00:00.060140+09:00
00:00:00 DEBUG [test_basic.py:302 test_time] time.localtime()               = Mon Jul 29 00:00:00 2024
00:00:00 DEBUG [test_basic.py:303 test_time] datetime.now()                 = 2024-07-28 15:00:00.060140
00:00:00 DEBUG [test_basic.py:304 test_time] datetime.now(JST)              = 2024-07-29 00:00:00.060140+09:00
00:00:00 DEBUG [__init__.py:144 clear] Deleting *all* jobs
00:00:00 DEBUG [test_basic.py:312 test_time] set schedule at 00:01
00:00:00 INFO [test_basic.py:317 test_time] Time to next jobs is 32459.9 sec
00:00:00 DEBUG [test_basic.py:318 test_time] Next run is 2024-07-29 00:01:00

pytest-freezegun appears to be freezing the time as intended. What could be the issue?

kimata commented 1 month ago

Note that up until version 1.2.1, I could force the test to pass by modifying freeze_time as shown below. However, since version 1.2.2, it takes time zones into consideration, so it is no longer possible to pass the test.

    freeze_time = datetime.datetime.now(tz=datetime.timezone(datetime.timedelta(hours=9))).replace(                                                            
        hour=0, minute=0, second=0                                                                                                                             
    ) + datetime.timedelta(hours=+9)  
kimata commented 4 weeks ago

It may be problem of schedule. So, I close this issue.

see https://github.com/spulec/freezegun/issues/348