freeze_time not working for default param
Asked Answered
V

1

5

I am having a function with the a default value of a param as datetime.now(). method is something like below,

def as_standard_format(p_date=datetime.now(), fmt=sdk_constants.DEFAULT_DATE_TIME_FORMAT):
    return p_date.strftime(fmt)

And I am having a test method something like below,

@freeze_time(datetime(year=2018, month=9, day=25, hour=15, minute=46, second=36))
def testNowWithDefaultFormat(self):

    # The below method gives the frozen time
    print(datetime.now())

    # But the below test fails
    assert utils.format_date(
        datetime.now()) == "20180925T154636Z", "Default call not giving current time in " \
                                               "standard format \"%Y%m%dT%H%M%SZ\""

Why is the freeze_time not working with default param value?

Venturesome answered 26/9, 2018 at 6:37 Comment(0)
S
4

You're being victim of a common gotcha in Python related to mutable default value parameters and not specific only to freeze_time.

For the explanation, consider the following code:

import time from datetime import datetime

def what_time_is_it(p_date=datetime.now()):
    return p_date.strftime('"%Y-%m-%d %X"')

if __name__ == '__main__':
    print(what_time_is_it())
    time.sleep(10)
    print(what_time_is_it())

What you might have expected to happen

"2019-02-28 13:47:24"
"2019-02-28 13:47:34" # This line showing a datetime 10 seconds after the first one

A new datetime.now() is called on every call to what_time_is_it()

What does happen

"2019-02-28 13:47:24"
"2019-02-28 13:47:24" # EXACTLY the same time in both lines!

A new datetime.now() is created once when the function is defined, and the same value is used in each successive call.

What you should do instead?

Create a new object each time the function is called, by using a default arg to signal that no argument was provided (None is often a good choice):

def as_standard_format(p_date=None, fmt=sdk_constants.DEFAULT_DATE_TIME_FORMAT):
    if p_date is None:
        return datetime.now().strftime(fmt)
    else:
        return p_date.strftime(fmt)
Stumer answered 28/2, 2019 at 17:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.