diff --git a/freezegun/api.py b/freezegun/api.py index 0f11e0c..d235292 100644 --- a/freezegun/api.py +++ b/freezegun/api.py @@ -509,10 +509,11 @@ def __init__(self, time_to_freeze: datetime.datetime, start: datetime.datetime): def __call__(self) -> datetime.datetime: return self.time_to_freeze + (real_datetime.now() - self.start) - def tick(self, delta: Union[datetime.timedelta, int]=datetime.timedelta(seconds=1)) -> datetime.datetime: - if isinstance(delta, numbers.Real): - # noinspection PyTypeChecker - self.move_to(self.time_to_freeze + datetime.timedelta(seconds=delta)) + def tick(self, delta: Union[datetime.timedelta, float]=datetime.timedelta(seconds=1)) -> datetime.datetime: + if isinstance(delta, numbers.Integral): + self.move_to(self.time_to_freeze + datetime.timedelta(seconds=int(delta))) + elif isinstance(delta, numbers.Real): + self.move_to(self.time_to_freeze + datetime.timedelta(seconds=float(delta))) else: self.move_to(self.time_to_freeze + delta) # type: ignore return self.time_to_freeze @@ -531,10 +532,11 @@ def __init__(self, time_to_freeze: datetime.datetime): def __call__(self) -> datetime.datetime: return self.time_to_freeze - def tick(self, delta: Union[datetime.timedelta, int]=datetime.timedelta(seconds=1)) -> datetime.datetime: - if isinstance(delta, numbers.Real): - # noinspection PyTypeChecker - self.time_to_freeze += datetime.timedelta(seconds=delta) + def tick(self, delta: Union[datetime.timedelta, float]=datetime.timedelta(seconds=1)) -> datetime.datetime: + if isinstance(delta, numbers.Integral): + self.move_to(self.time_to_freeze + datetime.timedelta(seconds=int(delta))) + elif isinstance(delta, numbers.Real): + self.move_to(self.time_to_freeze + datetime.timedelta(seconds=float(delta))) else: self.time_to_freeze += delta # type: ignore return self.time_to_freeze @@ -557,9 +559,13 @@ def __call__(self) -> datetime.datetime: self.tick() return return_time - def tick(self, delta: Union[datetime.timedelta, int, None]=None) -> datetime.datetime: + def tick(self, delta: Union[datetime.timedelta, float, None]=None) -> datetime.datetime: if not delta: delta = datetime.timedelta(seconds=self.step_width) + elif isinstance(delta, numbers.Integral): + delta = datetime.timedelta(seconds=int(delta)) + elif isinstance(delta, numbers.Real): + delta = datetime.timedelta(seconds=float(delta)) self.time_to_freeze += delta # type: ignore return self.time_to_freeze diff --git a/tests/test_datetimes.py b/tests/test_datetimes.py index 12e5949..a6f1989 100644 --- a/tests/test_datetimes.py +++ b/tests/test_datetimes.py @@ -1,6 +1,7 @@ import time import calendar import datetime +import fractions import unittest import locale import sys @@ -180,6 +181,17 @@ def test_manual_increment() -> None: assert frozen_datetime.tick(delta=datetime.timedelta(seconds=10)) == expected assert frozen_datetime() == expected + expected = initial_datetime + datetime.timedelta(seconds=22.5) + ticked_time = frozen_datetime.tick( + delta=fractions.Fraction(3, 2) # type: ignore + # type hints follow the recommendation of + # https://peps.python.org/pep-0484/#the-numeric-tower + # which means for instance `Fraction`s work at runtime, but not + # during static type analysis + ) + assert ticked_time == expected + assert frozen_datetime() == expected + def test_move_to() -> None: initial_datetime = datetime.datetime(year=1, month=7, day=12, diff --git a/tests/test_operations.py b/tests/test_operations.py index d34f3dd..49b703d 100644 --- a/tests/test_operations.py +++ b/tests/test_operations.py @@ -1,9 +1,11 @@ import datetime +import fractions +import pytest from freezegun import freeze_time from dateutil.relativedelta import relativedelta from datetime import timedelta, tzinfo from tests import utils -from typing import Any +from typing import Any, Union @freeze_time("2012-01-14") @@ -102,3 +104,38 @@ def test_auto_tick() -> None: auto_incremented_time = datetime.datetime.now() assert first_time + datetime.timedelta(seconds=15) == auto_incremented_time + +@pytest.mark.parametrize( + "tick,expected_diff", + ( + (datetime.timedelta(milliseconds=1500), 1.5), + (1, 1), + (1.5, 1.5), + (fractions.Fraction(3, 2), 1.5), + ) +) +def test_auto_and_manual_tick( + tick: Union[ + datetime.timedelta, + int, + float, + # fractions.Fraction, + # Fraction works at runtime, but not at type-checking time + # cf. https://peps.python.org/pep-0484/#the-numeric-tower + ], + expected_diff: float +) -> None: + first_time = datetime.datetime(2020, 1, 14, 0, 0, 0, 1) + + with freeze_time(first_time, auto_tick_seconds=2) as frozen_time: + frozen_time.tick(tick) + incremented_time = datetime.datetime.now() + expected_time = first_time + datetime.timedelta(seconds=expected_diff) + assert incremented_time == expected_time + + expected_time += datetime.timedelta(seconds=2) # auto_tick_seconds + + frozen_time.tick(tick) + incremented_time = datetime.datetime.now() + expected_time += datetime.timedelta(seconds=expected_diff) + assert incremented_time == expected_time