From d74635a4beeaaa0ba364393392f8a723ef7de594 Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Tue, 16 Apr 2024 20:31:39 +0000 Subject: [PATCH] MyPy --- .github/workflows/ci.yaml | 17 +- freezegun/__init__.pyi | 2 - freezegun/api.py | 309 ++++++++++++++++++++----------------- freezegun/api.pyi | 62 -------- setup.cfg | 33 ++++ tests/another_module.py | 25 +-- tests/fake_module.py | 19 +-- tests/test_asyncio.py | 25 +-- tests/test_class_import.py | 28 ++-- tests/test_configure.py | 10 +- tests/test_datetimes.py | 203 ++++++++++++------------ tests/test_errors.py | 11 +- tests/test_import_alias.py | 8 +- tests/test_operations.py | 25 +-- tests/test_pickle.py | 8 +- tests/test_sqlite3.py | 4 +- tests/test_ticking.py | 28 ++-- tests/test_utils.py | 4 +- tests/test_uuid.py | 7 +- tests/test_warnings.py | 13 +- tests/utils.py | 16 +- tox.ini | 2 +- 22 files changed, 443 insertions(+), 416 deletions(-) delete mode 100644 freezegun/__init__.pyi delete mode 100644 freezegun/api.pyi diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8be8dca1..269e3867 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,6 +8,15 @@ jobs: mypy: name: mypy runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - '3.7' + - '3.8' + - '3.9' + - '3.10' + - '3.11' + - '3.12' steps: - uses: actions/checkout@master @@ -15,11 +24,11 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 - - name: Install tox - run: pip install tox + - name: Install mypy + run: pip install mypy - - name: Run tests - run: pip install python-dateutil && tox -e mypy + - name: Run MyPy + run: mypy freezegun tests --install-types --non-interactive tests: name: Python ${{ matrix.implementation }}${{ matrix.python-version }} diff --git a/freezegun/__init__.pyi b/freezegun/__init__.pyi deleted file mode 100644 index 17dd86ac..00000000 --- a/freezegun/__init__.pyi +++ /dev/null @@ -1,2 +0,0 @@ -from .api import freeze_time as freeze_time - diff --git a/freezegun/api.py b/freezegun/api.py index 366d2cb5..6acb90a0 100644 --- a/freezegun/api.py +++ b/freezegun/api.py @@ -15,21 +15,33 @@ import types import numbers import inspect +from typing import TYPE_CHECKING, overload +from typing import Any, Awaitable, Callable, Dict, Iterator, List, Optional, Set, TypeVar, Tuple, Union from dateutil import parser from dateutil.tz import tzlocal try: - from maya import MayaDT + from maya import MayaDT # type: ignore except ImportError: MayaDT = None +if TYPE_CHECKING: + from typing_extensions import ParamSpec + + P = ParamSpec("P") + +T = TypeVar("T") + _TIME_NS_PRESENT = hasattr(time, 'time_ns') _MONOTONIC_NS_PRESENT = hasattr(time, 'monotonic_ns') _PERF_COUNTER_NS_PRESENT = hasattr(time, 'perf_counter_ns') _EPOCH = datetime.datetime(1970, 1, 1) _EPOCHTZ = datetime.datetime(1970, 1, 1, tzinfo=dateutil.tz.UTC) +T2 = TypeVar("T2") +_Freezable = str | datetime.datetime | datetime.date | datetime.timedelta | types.FunctionType | Callable[[], str | datetime.datetime | datetime.date | datetime.timedelta] | Iterator[datetime.datetime] + real_time = time.time real_localtime = time.localtime real_gmtime = time.gmtime @@ -57,14 +69,14 @@ # time.clock is deprecated and was removed in Python 3.8 real_clock = getattr(time, 'clock', None) -freeze_factories = [] -tz_offsets = [] -ignore_lists = [] -tick_flags = [] +freeze_factories: List[Union["StepTickTimeFactory", "TickingDateTimeFactory", "FrozenDateTimeFactory"]] = [] +tz_offsets: List[datetime.timedelta] = [] +ignore_lists: List[Tuple[str, ...]] = [] +tick_flags: List[bool] = [] try: # noinspection PyUnresolvedReferences - real_uuid_generate_time = uuid._uuid_generate_time + real_uuid_generate_time = uuid._uuid_generate_time # type: ignore uuid_generate_time_attr = '_uuid_generate_time' except AttributeError: # noinspection PyUnresolvedReferences @@ -72,25 +84,25 @@ # A no-op after Python ~3.9, being removed in 3.13. uuid._load_system_functions() # noinspection PyUnresolvedReferences - real_uuid_generate_time = uuid._generate_time_safe + real_uuid_generate_time = uuid._generate_time_safe # type: ignore uuid_generate_time_attr = '_generate_time_safe' except ImportError: real_uuid_generate_time = None - uuid_generate_time_attr = None + uuid_generate_time_attr = None # type: ignore try: # noinspection PyUnresolvedReferences - real_uuid_create = uuid._UuidCreate + real_uuid_create = uuid._UuidCreate # type: ignore except (AttributeError, ImportError): real_uuid_create = None # keep a cache of module attributes otherwise freezegun will need to analyze too many modules all the time -_GLOBAL_MODULES_CACHE = {} +_GLOBAL_MODULES_CACHE: Dict[str, Tuple[str, List[Tuple[str, Any]]]] = {} -def _get_module_attributes(module): - result = [] +def _get_module_attributes(module: types.ModuleType) -> List[Tuple[str, Any]]: + result: List[Tuple[str, Any]] = [] try: module_attributes = dir(module) except (ImportError, TypeError): @@ -106,7 +118,7 @@ def _get_module_attributes(module): return result -def _setup_module_cache(module): +def _setup_module_cache(module: types.ModuleType) -> None: date_attrs = [] all_module_attributes = _get_module_attributes(module) for attribute_name, attribute_value in all_module_attributes: @@ -115,7 +127,7 @@ def _setup_module_cache(module): _GLOBAL_MODULES_CACHE[module.__name__] = (_get_module_attributes_hash(module), date_attrs) -def _get_module_attributes_hash(module): +def _get_module_attributes_hash(module: types.ModuleType) -> str: try: module_dir = dir(module) except (ImportError, TypeError): @@ -123,7 +135,7 @@ def _get_module_attributes_hash(module): return f'{id(module)}-{hash(frozenset(module_dir))}' -def _get_cached_module_attributes(module): +def _get_cached_module_attributes(module: types.ModuleType) -> List[Tuple[str, Any]]: module_hash, cached_attrs = _GLOBAL_MODULES_CACHE.get(module.__name__, ('0', [])) if _get_module_attributes_hash(module) == module_hash: return cached_attrs @@ -144,7 +156,7 @@ def _get_cached_module_attributes(module): call_stack_inspection_limit = 5 -def _should_use_real_time(): +def _should_use_real_time() -> bool: if not call_stack_inspection_limit: return False @@ -155,38 +167,38 @@ def _should_use_real_time(): if not ignore_lists[-1]: return False - frame = inspect.currentframe().f_back.f_back + frame = inspect.currentframe().f_back.f_back # type: ignore for _ in range(call_stack_inspection_limit): - module_name = frame.f_globals.get('__name__') + module_name = frame.f_globals.get('__name__') # type: ignore if module_name and module_name.startswith(ignore_lists[-1]): return True - frame = frame.f_back + frame = frame.f_back # type: ignore if frame is None: break return False -def get_current_time(): +def get_current_time() -> datetime.datetime: return freeze_factories[-1]() -def fake_time(): +def fake_time() -> float: if _should_use_real_time(): return real_time() current_time = get_current_time() return calendar.timegm(current_time.timetuple()) + current_time.microsecond / 1000000.0 if _TIME_NS_PRESENT: - def fake_time_ns(): + def fake_time_ns() -> int: if _should_use_real_time(): return real_time_ns() return int(int(fake_time()) * 1e9) -def fake_localtime(t=None): +def fake_localtime(t: Optional[float]=None) -> time.struct_time: if t is not None: return real_localtime(t) if _should_use_real_time(): @@ -195,7 +207,7 @@ def fake_localtime(t=None): return shifted_time.timetuple() -def fake_gmtime(t=None): +def fake_gmtime(t: Optional[float]=None) -> time.struct_time: if t is not None: return real_gmtime(t) if _should_use_real_time(): @@ -203,7 +215,7 @@ def fake_gmtime(t=None): return get_current_time().timetuple() -def _get_fake_monotonic(): +def _get_fake_monotonic() -> float: # For monotonic timers like .monotonic(), .perf_counter(), etc current_time = get_current_time() return ( @@ -212,7 +224,7 @@ def _get_fake_monotonic(): ) -def _get_fake_monotonic_ns(): +def _get_fake_monotonic_ns() -> int: # For monotonic timers like .monotonic(), .perf_counter(), etc current_time = get_current_time() return ( @@ -221,14 +233,14 @@ def _get_fake_monotonic_ns(): ) * 1000 -def fake_monotonic(): +def fake_monotonic() -> float: if _should_use_real_time(): return real_monotonic() return _get_fake_monotonic() -def fake_perf_counter(): +def fake_perf_counter() -> float: if _should_use_real_time(): return real_perf_counter() @@ -236,7 +248,7 @@ def fake_perf_counter(): if _MONOTONIC_NS_PRESENT: - def fake_monotonic_ns(): + def fake_monotonic_ns() -> int: if _should_use_real_time(): return real_monotonic_ns() @@ -244,13 +256,13 @@ def fake_monotonic_ns(): if _PERF_COUNTER_NS_PRESENT: - def fake_perf_counter_ns(): + def fake_perf_counter_ns() -> int: if _should_use_real_time(): return real_perf_counter_ns() return _get_fake_monotonic_ns() -def fake_strftime(format, time_to_format=None): +def fake_strftime(format: Any, time_to_format: Any=None) -> str: if time_to_format is None: if not _should_use_real_time(): time_to_format = fake_localtime() @@ -261,12 +273,12 @@ def fake_strftime(format, time_to_format=None): return real_strftime(format, time_to_format) if real_clock is not None: - def fake_clock(): + def fake_clock() -> Any: if _should_use_real_time(): - return real_clock() + return real_clock() # type: ignore if len(freeze_factories) == 1: - return 0.0 if not tick_flags[-1] else real_clock() + return 0.0 if not tick_flags[-1] else real_clock() # type: ignore first_frozen_time = freeze_factories[0]() last_frozen_time = get_current_time() @@ -275,22 +287,22 @@ def fake_clock(): total_seconds = timedelta.total_seconds() if tick_flags[-1]: - total_seconds += real_clock() + total_seconds += real_clock() # type: ignore return total_seconds class FakeDateMeta(type): @classmethod - def __instancecheck__(self, obj): + def __instancecheck__(self, obj: Any) -> bool: return isinstance(obj, real_date) @classmethod - def __subclasscheck__(cls, subclass): + def __subclasscheck__(cls, subclass: Any) -> bool: return issubclass(subclass, real_date) -def datetime_to_fakedatetime(datetime): +def datetime_to_fakedatetime(datetime: datetime.datetime) -> "FakeDatetime": return FakeDatetime(datetime.year, datetime.month, datetime.day, @@ -301,39 +313,39 @@ def datetime_to_fakedatetime(datetime): datetime.tzinfo) -def date_to_fakedate(date): +def date_to_fakedate(date: datetime.date) -> "FakeDate": return FakeDate(date.year, date.month, date.day) class FakeDate(real_date, metaclass=FakeDateMeta): - def __add__(self, other): + def __add__(self, other: Any) -> "FakeDate": result = real_date.__add__(self, other) if result is NotImplemented: return result return date_to_fakedate(result) - def __sub__(self, other): + def __sub__(self, other: Any) -> "FakeDate": # type: ignore result = real_date.__sub__(self, other) if result is NotImplemented: - return result + return result # type: ignore if isinstance(result, real_date): return date_to_fakedate(result) else: - return result + return result # type: ignore @classmethod - def today(cls): + def today(cls: type["FakeDate"]) -> "FakeDate": result = cls._date_to_freeze() + cls._tz_offset() return date_to_fakedate(result) @staticmethod - def _date_to_freeze(): + def _date_to_freeze() -> datetime.datetime: return get_current_time() @classmethod - def _tz_offset(cls): + def _tz_offset(cls) -> datetime.timedelta: return tz_offsets[-1] FakeDate.min = date_to_fakedate(real_date.min) @@ -342,37 +354,37 @@ def _tz_offset(cls): class FakeDatetimeMeta(FakeDateMeta): @classmethod - def __instancecheck__(self, obj): + def __instancecheck__(self, obj: Any) -> bool: return isinstance(obj, real_datetime) @classmethod - def __subclasscheck__(cls, subclass): + def __subclasscheck__(cls, subclass: Any) -> bool: return issubclass(subclass, real_datetime) class FakeDatetime(real_datetime, FakeDate, metaclass=FakeDatetimeMeta): - def __add__(self, other): + def __add__(self, other: Any) -> "FakeDatetime": # type: ignore result = real_datetime.__add__(self, other) if result is NotImplemented: return result return datetime_to_fakedatetime(result) - def __sub__(self, other): + def __sub__(self, other: Any) -> "FakeDatetime": # type: ignore result = real_datetime.__sub__(self, other) if result is NotImplemented: - return result + return result # type: ignore if isinstance(result, real_datetime): return datetime_to_fakedatetime(result) else: - return result + return result # type: ignore - def astimezone(self, tz=None): + def astimezone(self, tz: Optional[datetime.tzinfo]=None) -> "FakeDatetime": if tz is None: tz = tzlocal() return datetime_to_fakedatetime(real_datetime.astimezone(self, tz)) @classmethod - def fromtimestamp(cls, t, tz=None): + def fromtimestamp(cls, t: float, tz: Optional[datetime.tzinfo]=None) -> "FakeDatetime": if tz is None: tz = dateutil.tz.tzoffset("freezegun", cls._tz_offset()) result = real_datetime.fromtimestamp(t, tz=tz).replace(tzinfo=None) @@ -380,13 +392,13 @@ def fromtimestamp(cls, t, tz=None): result = real_datetime.fromtimestamp(t, tz) return datetime_to_fakedatetime(result) - def timestamp(self): + def timestamp(self) -> float: if self.tzinfo is None: - return (self - _EPOCH - self._tz_offset()).total_seconds() - return (self - _EPOCHTZ).total_seconds() + return (self - _EPOCH - self._tz_offset()).total_seconds() # type: ignore + return (self - _EPOCHTZ).total_seconds() # type: ignore @classmethod - def now(cls, tz=None): + def now(cls, tz: Optional[datetime.tzinfo] = None) -> "FakeDatetime": now = cls._time_to_freeze() or real_datetime.now() if tz: result = tz.fromutc(now.replace(tzinfo=tz)) + cls._tz_offset() @@ -394,33 +406,34 @@ def now(cls, tz=None): result = now + cls._tz_offset() return datetime_to_fakedatetime(result) - def date(self): + def date(self) -> "FakeDate": return date_to_fakedate(self) @property - def nanosecond(self): + def nanosecond(self) -> int: try: # noinspection PyUnresolvedReferences - return real_datetime.nanosecond + return real_datetime.nanosecond # type: ignore except AttributeError: return 0 @classmethod - def today(cls): + def today(cls) -> "FakeDatetime": return cls.now(tz=None) @classmethod - def utcnow(cls): + def utcnow(cls) -> "FakeDatetime": result = cls._time_to_freeze() or real_datetime.now(datetime.timezone.utc) return datetime_to_fakedatetime(result) @staticmethod - def _time_to_freeze(): + def _time_to_freeze() -> Optional[datetime.datetime]: if freeze_factories: return get_current_time() + return None @classmethod - def _tz_offset(cls): + def _tz_offset(cls) -> datetime.timedelta: return tz_offsets[-1] @@ -428,17 +441,17 @@ def _tz_offset(cls): FakeDatetime.max = datetime_to_fakedatetime(real_datetime.max) -def convert_to_timezone_naive(time_to_freeze): +def convert_to_timezone_naive(time_to_freeze: datetime.datetime) -> datetime.datetime: """ Converts a potentially timezone-aware datetime to be a naive UTC datetime """ if time_to_freeze.tzinfo: - time_to_freeze -= time_to_freeze.utcoffset() + time_to_freeze -= time_to_freeze.utcoffset() # type: ignore time_to_freeze = time_to_freeze.replace(tzinfo=None) return time_to_freeze -def pickle_fake_date(datetime_): +def pickle_fake_date(datetime_: datetime.date) -> Tuple[type[FakeDate], Tuple[int, int, int]]: # A pickle function for FakeDate return FakeDate, ( datetime_.year, @@ -447,7 +460,7 @@ def pickle_fake_date(datetime_): ) -def pickle_fake_datetime(datetime_): +def pickle_fake_datetime(datetime_: datetime.datetime) -> Tuple[type[FakeDatetime], Tuple[int, int, int, int, int, int, int, Optional[datetime.tzinfo]]]: # A pickle function for FakeDatetime return FakeDatetime, ( datetime_.year, @@ -461,7 +474,7 @@ def pickle_fake_datetime(datetime_): ) -def _parse_time_to_freeze(time_to_freeze_str): +def _parse_time_to_freeze(time_to_freeze_str: Optional[_Freezable]) -> datetime.datetime: """Parses all the possible inputs for freeze_time :returns: a naive ``datetime.datetime`` object """ @@ -475,12 +488,12 @@ def _parse_time_to_freeze(time_to_freeze_str): elif isinstance(time_to_freeze_str, datetime.timedelta): time_to_freeze = datetime.datetime.now(datetime.timezone.utc) + time_to_freeze_str else: - time_to_freeze = parser.parse(time_to_freeze_str) + time_to_freeze = parser.parse(time_to_freeze_str) # type: ignore return convert_to_timezone_naive(time_to_freeze) -def _parse_tz_offset(tz_offset): +def _parse_tz_offset(tz_offset: Union[datetime.timedelta, float]) -> datetime.timedelta: if isinstance(tz_offset, datetime.timedelta): return tz_offset else: @@ -489,21 +502,21 @@ def _parse_tz_offset(tz_offset): class TickingDateTimeFactory: - def __init__(self, time_to_freeze, start): + def __init__(self, time_to_freeze: datetime.datetime, start: datetime.datetime): self.time_to_freeze = time_to_freeze self.start = start - def __call__(self): + def __call__(self) -> datetime.datetime: return self.time_to_freeze + (real_datetime.now() - self.start) - def tick(self, delta=datetime.timedelta(seconds=1)): + def tick(self, delta: Union[datetime.timedelta, int]=datetime.timedelta(seconds=1)) -> None: if isinstance(delta, numbers.Real): # noinspection PyTypeChecker self.move_to(self.time_to_freeze + datetime.timedelta(seconds=delta)) else: - self.move_to(self.time_to_freeze + delta) + self.move_to(self.time_to_freeze + delta) # type: ignore - def move_to(self, target_datetime): + def move_to(self, target_datetime: _Freezable) -> None: """Moves frozen date to the given ``target_datetime``""" self.start = real_datetime.now() self.time_to_freeze = _parse_time_to_freeze(target_datetime) @@ -511,20 +524,20 @@ def move_to(self, target_datetime): class FrozenDateTimeFactory: - def __init__(self, time_to_freeze): + def __init__(self, time_to_freeze: datetime.datetime): self.time_to_freeze = time_to_freeze - def __call__(self): + def __call__(self) -> datetime.datetime: return self.time_to_freeze - def tick(self, delta=datetime.timedelta(seconds=1)): + def tick(self, delta: Union[datetime.timedelta, int]=datetime.timedelta(seconds=1)) -> None: if isinstance(delta, numbers.Real): # noinspection PyTypeChecker self.time_to_freeze += datetime.timedelta(seconds=delta) else: - self.time_to_freeze += delta + self.time_to_freeze += delta # type: ignore - def move_to(self, target_datetime): + def move_to(self, target_datetime: _Freezable) -> None: """Moves frozen date to the given ``target_datetime``""" target_datetime = _parse_time_to_freeze(target_datetime) delta = target_datetime - self.time_to_freeze @@ -533,24 +546,24 @@ def move_to(self, target_datetime): class StepTickTimeFactory: - def __init__(self, time_to_freeze, step_width): + def __init__(self, time_to_freeze: datetime.datetime, step_width: float): self.time_to_freeze = time_to_freeze self.step_width = step_width - def __call__(self): + def __call__(self) -> datetime.datetime: return_time = self.time_to_freeze self.tick() return return_time - def tick(self, delta=None): + def tick(self, delta: Union[datetime.timedelta, int, None]=None) -> None: if not delta: delta = datetime.timedelta(seconds=self.step_width) - self.time_to_freeze += delta + self.time_to_freeze += delta # type: ignore - def update_step_width(self, step_width): + def update_step_width(self, step_width: float) -> None: self.step_width = step_width - def move_to(self, target_datetime): + def move_to(self, target_datetime: _Freezable) -> None: """Moves frozen date to the given ``target_datetime``""" target_datetime = _parse_time_to_freeze(target_datetime) delta = target_datetime - self.time_to_freeze @@ -559,26 +572,48 @@ def move_to(self, target_datetime): class _freeze_time: - def __init__(self, time_to_freeze_str, tz_offset, ignore, tick, as_arg, as_kwarg, auto_tick_seconds, real_asyncio): + def __init__( + self, + time_to_freeze_str: Optional[_Freezable], + tz_offset: Union[int, datetime.timedelta], + ignore: List[str], + tick: bool, + as_arg: bool, + as_kwarg: str, + auto_tick_seconds: float, + real_asyncio: Optional[bool], + ): self.time_to_freeze = _parse_time_to_freeze(time_to_freeze_str) self.tz_offset = _parse_tz_offset(tz_offset) self.ignore = tuple(ignore) self.tick = tick self.auto_tick_seconds = auto_tick_seconds - self.undo_changes = [] - self.modules_at_start = set() + self.undo_changes: List[Tuple[types.ModuleType, str, Any]] = [] + self.modules_at_start: Set[str] = set() self.as_arg = as_arg self.as_kwarg = as_kwarg self.real_asyncio = real_asyncio - def __call__(self, func): + @overload + def __call__(self, func: type[T2]) -> type[T2]: + ... + + @overload + def __call__(self, func: Callable[P, Awaitable[Any]]) -> Callable[P, Awaitable[Any]]: + ... + + @overload + def __call__(self, func: Callable[P, T]) -> Callable[P, T]: + ... + + def __call__(self, func: Union[type[T2], Callable[P, Awaitable[Any]], Callable[P, T]]) -> Union[type[T2], Callable[P, Awaitable[Any]], Callable[P, T]]: # type: ignore if inspect.isclass(func): return self.decorate_class(func) elif inspect.iscoroutinefunction(func): return self.decorate_coroutine(func) - return self.decorate_callable(func) + return self.decorate_callable(func) # type: ignore - def decorate_class(self, klass): + def decorate_class(self, klass: type[T2]) -> type[T2]: if issubclass(klass, unittest.TestCase): # If it's a TestCase, we freeze time around setup and teardown, as well # as for every test case. This requires some care to avoid freezing @@ -589,41 +624,39 @@ def decorate_class(self, klass): orig_tearDownClass = klass.tearDownClass # noinspection PyDecorator - @classmethod - def setUpClass(cls): + @classmethod # type: ignore + def setUpClass(cls: type) -> None: self.start() if orig_setUpClass is not None: orig_setUpClass() self.stop() # noinspection PyDecorator - @classmethod - def tearDownClass(cls): + @classmethod # type: ignore + def tearDownClass(cls: type) -> None: self.start() if orig_tearDownClass is not None: orig_tearDownClass() self.stop() - klass.setUpClass = setUpClass - klass.tearDownClass = tearDownClass + klass.setUpClass = setUpClass # type: ignore + klass.tearDownClass = tearDownClass # type: ignore orig_setUp = klass.setUp orig_tearDown = klass.tearDown - def setUp(*args, **kwargs): + def setUp(*args: Any, **kwargs: Any) -> None: self.start() if orig_setUp is not None: orig_setUp(*args, **kwargs) - def tearDown(*args, **kwargs): + def tearDown(*args: Any, **kwargs: Any) -> None: if orig_tearDown is not None: orig_tearDown(*args, **kwargs) self.stop() - klass.setUp = setUp - klass.tearDown = tearDown - - return klass + klass.setUp = setUp # type: ignore[method-assign] + klass.tearDown = tearDown # type: ignore[method-assign] else: @@ -644,18 +677,18 @@ def tearDown(*args, **kwargs): except (AttributeError, TypeError): # Sometimes we can't set this for built-in types and custom callables continue - return klass + return klass - def __enter__(self): + def __enter__(self) -> Union[StepTickTimeFactory, TickingDateTimeFactory, FrozenDateTimeFactory]: return self.start() - def __exit__(self, *args): + def __exit__(self, *args: Any) -> None: self.stop() - def start(self): + def start(self) -> Union[StepTickTimeFactory, TickingDateTimeFactory, FrozenDateTimeFactory]: if self.auto_tick_seconds: - freeze_factory = StepTickTimeFactory(self.time_to_freeze, self.auto_tick_seconds) + freeze_factory: Union[StepTickTimeFactory, TickingDateTimeFactory, FrozenDateTimeFactory] = StepTickTimeFactory(self.time_to_freeze, self.auto_tick_seconds) elif self.tick: freeze_factory = TickingDateTimeFactory(self.time_to_freeze, real_datetime.now()) else: @@ -671,19 +704,19 @@ def start(self): return freeze_factory # Change the modules - datetime.datetime = FakeDatetime - datetime.date = FakeDate + datetime.datetime = FakeDatetime # type: ignore[misc] + datetime.date = FakeDate # type: ignore[misc] time.time = fake_time time.monotonic = fake_monotonic time.perf_counter = fake_perf_counter - time.localtime = fake_localtime - time.gmtime = fake_gmtime - time.strftime = fake_strftime + time.localtime = fake_localtime # type: ignore + time.gmtime = fake_gmtime # type: ignore + time.strftime = fake_strftime # type: ignore if uuid_generate_time_attr: setattr(uuid, uuid_generate_time_attr, None) - uuid._UuidCreate = None - uuid._last_timestamp = None + uuid._UuidCreate = None # type: ignore[attr-defined] + uuid._last_timestamp = None # type: ignore[attr-defined] copyreg.dispatch_table[real_datetime] = pickle_fake_datetime copyreg.dispatch_table[real_date] = pickle_fake_date @@ -714,10 +747,10 @@ def start(self): if real_clock is not None: # time.clock is deprecated and was removed in Python 3.8 - time.clock = fake_clock + time.clock = fake_clock # type: ignore[attr-defined] to_patch.append(('real_clock', real_clock, fake_clock)) - self.fake_names = tuple(fake.__name__ for real_name, real, fake in to_patch) + self.fake_names = tuple(fake.__name__ for real_name, real, fake in to_patch) # type: ignore self.reals = {id(fake): real for real_name, real, fake in to_patch} fakes = {id(real): fake for real_name, real, fake in to_patch} add_change = self.undo_changes.append @@ -756,20 +789,20 @@ def start(self): event_loop = asyncio.new_event_loop() event_loop.close() EventLoopClass = type(event_loop) - add_change((EventLoopClass, "time", EventLoopClass.time)) - EventLoopClass.time = lambda self: real_monotonic() + add_change((EventLoopClass, "time", EventLoopClass.time)) # type: ignore + EventLoopClass.time = lambda self: real_monotonic() # type: ignore[method-assign] return freeze_factory - def stop(self): + def stop(self) -> None: freeze_factories.pop() ignore_lists.pop() tick_flags.pop() tz_offsets.pop() if not freeze_factories: - datetime.datetime = real_datetime - datetime.date = real_date + datetime.datetime = real_datetime # type: ignore[misc] + datetime.date = real_date # type: ignore[misc] copyreg.dispatch_table.pop(real_datetime) copyreg.dispatch_table.pop(real_date) for module_or_object, attribute, original_value in self.undo_changes: @@ -809,7 +842,7 @@ def stop(self): time.gmtime = real_gmtime time.localtime = real_localtime time.strftime = real_strftime - time.clock = real_clock + time.clock = real_clock # type: ignore[attr-defined] if _TIME_NS_PRESENT: time.time_ns = real_time_ns @@ -822,33 +855,33 @@ def stop(self): if uuid_generate_time_attr: setattr(uuid, uuid_generate_time_attr, real_uuid_generate_time) - uuid._UuidCreate = real_uuid_create - uuid._last_timestamp = None + uuid._UuidCreate = real_uuid_create # type: ignore[attr-defined] + uuid._last_timestamp = None # type: ignore[attr-defined] - def decorate_coroutine(self, coroutine): + def decorate_coroutine(self, coroutine: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]: return wrap_coroutine(self, coroutine) - def decorate_callable(self, func): - def wrapper(*args, **kwargs): + def decorate_callable(self, func: Callable[P, T]) -> Callable[P, T]: + @functools.wraps(func) + def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: with self as time_factory: if self.as_arg and self.as_kwarg: assert False, "You can't specify both as_arg and as_kwarg at the same time. Pick one." elif self.as_arg: - result = func(time_factory, *args, **kwargs) + result = func(time_factory, *args, **kwargs) # type: ignore elif self.as_kwarg: kwargs[self.as_kwarg] = time_factory result = func(*args, **kwargs) else: result = func(*args, **kwargs) return result - functools.update_wrapper(wrapper, func) return wrapper -def freeze_time(time_to_freeze=None, tz_offset=0, ignore=None, tick=False, as_arg=False, as_kwarg='', - auto_tick_seconds=0, real_asyncio=False): - acceptable_times = (type(None), str, datetime.date, datetime.timedelta, +def freeze_time(time_to_freeze: Optional[_Freezable]=None, tz_offset: Union[int, datetime.timedelta]=0, ignore: Optional[List[str]]=None, tick: bool=False, as_arg: bool=False, as_kwarg: str='', + auto_tick_seconds: float=0, real_asyncio: bool=False) -> _freeze_time: + acceptable_times: Any = (type(None), str, datetime.date, datetime.timedelta, types.FunctionType, types.GeneratorType) if MayaDT is not None: @@ -898,10 +931,10 @@ def freeze_time(time_to_freeze=None, tz_offset=0, ignore=None, tick=False, as_ar pass else: # These are copied from Python sqlite3.dbapi2 - def adapt_date(val): + def adapt_date(val: datetime.date) -> str: return val.isoformat() - def adapt_datetime(val): + def adapt_datetime(val: datetime.datetime) -> str: return val.isoformat(" ") sqlite3.register_adapter(FakeDate, adapt_date) diff --git a/freezegun/api.pyi b/freezegun/api.pyi deleted file mode 100644 index 2ff9bdc5..00000000 --- a/freezegun/api.pyi +++ /dev/null @@ -1,62 +0,0 @@ -from collections.abc import Awaitable, Callable, Iterator, Sequence -from datetime import date, datetime, timedelta -from numbers import Real -from typing import Any, TypeVar, overload -from typing_extensions import TypeAlias - -_T = TypeVar("_T") -_Freezable: TypeAlias = str | datetime | date | timedelta - -class TickingDateTimeFactory: - def __init__(self, time_to_freeze: datetime, start: datetime) -> None: ... - def __call__(self) -> datetime: ... - -class FrozenDateTimeFactory: - def __init__(self, time_to_freeze: datetime) -> None: ... - def __call__(self) -> datetime: ... - def tick(self, delta: float | Real | timedelta = ...) -> None: ... - def move_to(self, target_datetime: _Freezable | None) -> None: ... - -class StepTickTimeFactory: - def __init__(self, time_to_freeze: datetime, step_width: float) -> None: ... - def __call__(self) -> datetime: ... - def tick(self, delta: timedelta | None = ...) -> None: ... - def update_step_width(self, step_width: float) -> None: ... - def move_to(self, target_datetime: _Freezable | None) -> None: ... - -class _freeze_time: - def __init__( - self, - time_to_freeze_str: _Freezable | None, - tz_offset: int | timedelta, - ignore: Sequence[str], - tick: bool, - as_arg: bool, - as_kwarg: str, - auto_tick_seconds: float, - real_asyncio: bool, - ) -> None: ... - @overload - def __call__(self, func: type[_T]) -> type[_T]: ... - @overload - def __call__(self, func: Callable[..., Awaitable[_T]]) -> Callable[..., Awaitable[_T]]: ... - @overload - def __call__(self, func: Callable[..., _T]) -> Callable[..., _T]: ... - def __enter__(self) -> FrozenDateTimeFactory | StepTickTimeFactory: ... - def __exit__(self, *args: object) -> None: ... - def start(self) -> Any: ... - def stop(self) -> None: ... - def decorate_class(self, klass: type[_T]) -> _T: ... - def decorate_coroutine(self, coroutine: _T) -> _T: ... - def decorate_callable(self, func: Callable[..., _T]) -> Callable[..., _T]: ... - -def freeze_time( - time_to_freeze: _Freezable | Callable[..., _Freezable] | Iterator[_Freezable] | None = ..., - tz_offset: int | timedelta | None = ..., - ignore: Sequence[str] | None = ..., - tick: bool | None = ..., - as_arg: bool | None = ..., - as_kwarg: str | None = ..., - auto_tick_seconds: float | None = ..., - real_asyncio: bool | None = ... -) -> _freeze_time: ... diff --git a/setup.cfg b/setup.cfg index 39ca7dc7..b7163219 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,3 +30,36 @@ python_requires = >=3.7 install_requires = python-dateutil >= 2.7 include_package_data = true + +[mypy] +files= freezegun, tests +exclude = +show_column_numbers=True +show_error_codes = True +disable_error_code=abstract + +disallow_any_unimported=False +disallow_any_expr=False +disallow_any_decorated=True +disallow_any_explicit=False +disallow_any_generics=True +disallow_subclassing_any=True + +disallow_untyped_calls=True +disallow_untyped_defs=True +disallow_incomplete_defs=True +check_untyped_defs=True +disallow_untyped_decorators=True + +no_implicit_optional=True +strict_optional=True + +warn_redundant_casts=True +warn_unused_ignores=False +warn_no_return=True +warn_return_any=False +warn_unreachable=False + +strict_equality=True +ignore_missing_imports=True +follow_imports=silent \ No newline at end of file diff --git a/tests/another_module.py b/tests/another_module.py index 637c889b..17ec7d95 100644 --- a/tests/another_module.py +++ b/tests/another_module.py @@ -1,5 +1,6 @@ from datetime import date, datetime from time import time, localtime, gmtime, strftime +from typing import Any from freezegun.api import ( FakeDatetime, @@ -13,51 +14,51 @@ # Reals -def get_datetime(): +def get_datetime() -> Any: return datetime -def get_date(): +def get_date() -> Any: return date -def get_time(): +def get_time() -> Any: return time -def get_localtime(): +def get_localtime() -> Any: return localtime -def get_gmtime(): +def get_gmtime() -> Any: return gmtime -def get_strftime(): +def get_strftime() -> Any: return strftime # Fakes -def get_fake_datetime(): +def get_fake_datetime() -> Any: return FakeDatetime -def get_fake_date(): +def get_fake_date() -> Any: return FakeDate -def get_fake_time(): +def get_fake_time() -> Any: return fake_time -def get_fake_localtime(): +def get_fake_localtime() -> Any: return fake_localtime -def get_fake_gmtime(): +def get_fake_gmtime() -> Any: return fake_gmtime -def get_fake_strftime(): +def get_fake_strftime() -> Any: return fake_strftime diff --git a/tests/fake_module.py b/tests/fake_module.py index 8afdaecf..df1a3546 100644 --- a/tests/fake_module.py +++ b/tests/fake_module.py @@ -1,38 +1,39 @@ from datetime import date, datetime -from time import time, localtime, gmtime, strftime +from time import time, localtime, gmtime, strftime, struct_time +from typing import Any -def fake_datetime_function(): +def fake_datetime_function() -> datetime: return datetime.now() -def fake_date_function(): +def fake_date_function() -> date: return date.today() -def fake_time_function(): +def fake_time_function() -> float: return time() -def fake_localtime_function(): +def fake_localtime_function() -> struct_time: return localtime() -def fake_gmtime_function(): +def fake_gmtime_function() -> struct_time: return gmtime() -def fake_strftime_function(): +def fake_strftime_function() -> str: return strftime("%Y") class EqualToAnything: description = 'This is the equal_to_anything object' - def __eq__(self, other): + def __eq__(self, other: Any) -> bool: return True - def __neq__(self, other): + def __neq__(self, other: Any) -> bool: return False diff --git a/tests/test_asyncio.py b/tests/test_asyncio.py index 6afc6e3c..1d4570b1 100644 --- a/tests/test_asyncio.py +++ b/tests/test_asyncio.py @@ -1,21 +1,22 @@ import asyncio import datetime import time +from typing import Any from freezegun import freeze_time -def test_datetime_in_coroutine(): +def test_datetime_in_coroutine() -> None: @freeze_time('1970-01-01') - async def frozen_coroutine(): + async def frozen_coroutine() -> Any: assert datetime.date.today() == datetime.date(1970, 1, 1) - asyncio.run(frozen_coroutine()) + asyncio.run(frozen_coroutine()) # type: ignore -def test_freezing_time_in_coroutine(): +def test_freezing_time_in_coroutine() -> None: """Test calling freeze_time while executing asyncio loop.""" - async def coroutine(): + async def coroutine() -> None: with freeze_time('1970-01-02'): assert time.time() == 86400 with freeze_time('1970-01-03'): @@ -24,15 +25,15 @@ async def coroutine(): asyncio.run(coroutine()) -def test_freezing_time_before_running_coroutine(): +def test_freezing_time_before_running_coroutine() -> None: """Test calling freeze_time before executing asyncio loop.""" - async def coroutine(): + async def coroutine() -> None: assert time.time() == 86400 with freeze_time('1970-01-02'): asyncio.run(coroutine()) -def test_asyncio_sleeping_not_affected_by_freeze_time(): +def test_asyncio_sleeping_not_affected_by_freeze_time() -> None: """Test that asyncio.sleep() is not affected by `freeze_time`. This test ensures that despite freezing time using `freeze_time`, @@ -40,7 +41,7 @@ def test_asyncio_sleeping_not_affected_by_freeze_time(): to make things like `asyncio.sleep()` work. """ - async def coroutine(): + async def coroutine() -> None: # Sleeping with time frozen should sleep the expected duration. before_sleep = time.time() with freeze_time('1970-01-02', real_asyncio=True): @@ -55,15 +56,15 @@ async def coroutine(): asyncio.run(coroutine()) -def test_asyncio_to_call_later_with_frozen_time(): +def test_asyncio_to_call_later_with_frozen_time() -> None: """Test that asyncio `loop.call_later` works with frozen time.""" # `to_call_later` will be called by asyncio event loop and should add # the Unix timestamp of 1970-01-02 00:00 to the `timestamps` list. timestamps = [] - def to_call_later(): + def to_call_later() -> None: timestamps.append(time.time()) - async def coroutine(): + async def coroutine() -> None: # Schedule calling `to_call_later` in 100 ms. asyncio.get_running_loop().call_later(0.1, to_call_later) diff --git a/tests/test_class_import.py b/tests/test_class_import.py index 709dc6e1..87742d60 100644 --- a/tests/test_class_import.py +++ b/tests/test_class_import.py @@ -22,24 +22,24 @@ @freeze_time("2012-01-14") -def test_import_datetime_works(): +def test_import_datetime_works() -> None: assert fake_datetime_function().day == 14 @freeze_time("2012-01-14") -def test_import_date_works(): +def test_import_date_works() -> None: assert fake_date_function().day == 14 @freeze_time("2012-01-14") -def test_import_time(): +def test_import_time() -> None: local_time = datetime.datetime(2012, 1, 14) utc_time = local_time - datetime.timedelta(seconds=time.timezone) expected_timestamp = time.mktime(utc_time.timetuple()) assert fake_time_function() == expected_timestamp -def test_start_and_stop_works(): +def test_start_and_stop_works() -> None: freezer = freeze_time("2012-01-14") result = fake_datetime_function() @@ -57,7 +57,7 @@ def test_start_and_stop_works(): assert result.__class__ != FakeDatetime -def test_isinstance_works(): +def test_isinstance_works() -> None: date = datetime.date.today() now = datetime.datetime.now() @@ -70,7 +70,7 @@ def test_isinstance_works(): freezer.stop() -def test_issubclass_works(): +def test_issubclass_works() -> None: real_date = datetime.date real_datetime = datetime.datetime @@ -81,7 +81,7 @@ def test_issubclass_works(): freezer.stop() -def test_fake_uses_real_when_ignored(): +def test_fake_uses_real_when_ignored() -> None: real_time_before = time.time() with freeze_time('2012-01-14', ignore=['tests.fake_module']): real_time = fake_time_function() @@ -89,7 +89,7 @@ def test_fake_uses_real_when_ignored(): assert real_time_before <= real_time <= real_time_after -def test_can_ignore_email_module(): +def test_can_ignore_email_module() -> None: from email.utils import formatdate with freeze_time('2012-01-14'): faked_date_str = formatdate() @@ -104,12 +104,12 @@ def test_can_ignore_email_module(): @freeze_time('2011-01-01') -def test_avoid_replacing_equal_to_anything(): +def test_avoid_replacing_equal_to_anything() -> None: assert fake_module.equal_to_anything.description == 'This is the equal_to_anything object' @freeze_time("2012-01-14 12:00:00") -def test_import_localtime(): +def test_import_localtime() -> None: struct = fake_localtime_function() assert struct.tm_year == 2012 assert struct.tm_mon == 1 @@ -118,7 +118,7 @@ def test_import_localtime(): @freeze_time("2012-01-14 12:00:00") -def test_fake_gmtime_function(): +def test_fake_gmtime_function() -> None: struct = fake_gmtime_function() assert struct.tm_year == 2012 assert struct.tm_mon == 1 @@ -126,11 +126,11 @@ def test_fake_gmtime_function(): @freeze_time("2012-01-14") -def test_fake_strftime_function(): +def test_fake_strftime_function() -> None: assert fake_strftime_function() == '2012' -def test_import_after_start(): +def test_import_after_start() -> None: with freeze_time('2012-01-14'): assert 'tests.another_module' not in sys.modules.keys() from tests import another_module @@ -180,7 +180,7 @@ def test_import_after_start(): assert another_module.get_fake_strftime() is fake_strftime del sys.modules['tests.another_module'] -def test_none_as_initial(): +def test_none_as_initial() -> None: with freeze_time() as ft: ft.move_to('2012-01-14') assert fake_strftime_function() == '2012' diff --git a/tests/test_configure.py b/tests/test_configure.py index 930e3fe3..2310b81e 100644 --- a/tests/test_configure.py +++ b/tests/test_configure.py @@ -3,15 +3,15 @@ import freezegun.config -def setup_function(): +def setup_function() -> None: freezegun.config.reset_config() -def teardown_function(): +def teardown_function() -> None: freezegun.config.reset_config() -def test_default_ignore_list_is_overridden(): +def test_default_ignore_list_is_overridden() -> None: freezegun.configure(default_ignore_list=['threading', 'tensorflow']) with mock.patch("freezegun.api._freeze_time.__init__", return_value=None) as _freeze_time_init_mock: @@ -34,7 +34,7 @@ def test_default_ignore_list_is_overridden(): real_asyncio=False, ) -def test_extend_default_ignore_list(): +def test_extend_default_ignore_list() -> None: freezegun.configure(extend_ignore_list=['tensorflow']) with mock.patch("freezegun.api._freeze_time.__init__", return_value=None) as _freeze_time_init_mock: @@ -68,7 +68,7 @@ def test_extend_default_ignore_list(): real_asyncio=False, ) -def test_extend_default_ignore_list_duplicate_items(): +def test_extend_default_ignore_list_duplicate_items() -> None: freezegun.configure(extend_ignore_list=['tensorflow', 'pymongo', 'tensorflow','rabbitmq']) freezegun.configure(extend_ignore_list=['tensorflow']) diff --git a/tests/test_datetimes.py b/tests/test_datetimes.py index 0632f9ff..e64c3e67 100644 --- a/tests/test_datetimes.py +++ b/tests/test_datetimes.py @@ -4,6 +4,7 @@ import unittest import locale import sys +from typing import Any, Callable from unittest import SkipTest from dateutil.tz import UTC @@ -14,7 +15,7 @@ from freezegun.api import FakeDatetime, FakeDate try: - import maya + import maya # type: ignore except ImportError: maya = None @@ -27,10 +28,10 @@ class temp_locale: """Temporarily change the locale.""" - def __init__(self, *targets): + def __init__(self, *targets: str): self.targets = targets - def __enter__(self): + def __enter__(self) -> None: self.old = locale.setlocale(locale.LC_ALL) for target in self.targets: try: @@ -41,7 +42,7 @@ def __enter__(self): msg = 'could not set locale to any of: %s' % ', '.join(self.targets) raise SkipTest(msg) - def __exit__(self, *args): + def __exit__(self, *args: Any) -> None: locale.setlocale(locale.LC_ALL, self.old) # Small sample of locales where '%x' expands to a dd/mm/yyyy string, @@ -49,7 +50,7 @@ def __exit__(self, *args): _dd_mm_yyyy_locales = ['da_DK.UTF-8', 'de_DE.UTF-8', 'fr_FR.UTF-8'] -def test_simple_api(): +def test_simple_api() -> None: # time to freeze is always provided in UTC freezer = freeze_time("2012-01-14") # expected timestamp must be a timestamp, corresponding to 2012-01-14 UTC @@ -77,7 +78,7 @@ def test_simple_api(): freezer.stop() -def test_tz_offset(): +def test_tz_offset() -> None: freezer = freeze_time("2012-01-14 03:21:34", tz_offset=-4) # expected timestamp must be a timestamp, # corresponding to 2012-01-14 03:21:34 UTC @@ -93,7 +94,7 @@ def test_tz_offset(): freezer.stop() -def test_timestamp_tz_offset(): +def test_timestamp_tz_offset() -> None: freezer = freeze_time(datetime.datetime.fromtimestamp(1), tz_offset=-1) freezer.start() t = datetime.datetime.now().timestamp() @@ -102,7 +103,7 @@ def test_timestamp_tz_offset(): freezer.stop() -def test_timedelta_tz_offset(): +def test_timedelta_tz_offset() -> None: freezer = freeze_time("2012-01-14 03:21:34", tz_offset=-datetime.timedelta(hours=3, minutes=30)) freezer.start() @@ -111,7 +112,7 @@ def test_timedelta_tz_offset(): freezer.stop() -def test_tz_offset_with_today(): +def test_tz_offset_with_today() -> None: freezer = freeze_time("2012-01-14", tz_offset=-4) freezer.start() assert datetime.date.today() == datetime.date(2012, 1, 13) @@ -119,7 +120,7 @@ def test_tz_offset_with_today(): assert datetime.date.today() != datetime.date(2012, 1, 13) -def test_zero_tz_offset_with_time(): +def test_zero_tz_offset_with_time() -> None: # we expect the system to behave like a system with UTC timezone # at the beginning of the Epoch freezer = freeze_time('1970-01-01') @@ -133,7 +134,7 @@ def test_zero_tz_offset_with_time(): freezer.stop() -def test_tz_offset_with_time(): +def test_tz_offset_with_time() -> None: # we expect the system to behave like a system with UTC-4 timezone # at the beginning of the Epoch (wall clock should be 4 hrs late) freezer = freeze_time('1970-01-01', tz_offset=-4) @@ -147,21 +148,21 @@ def test_tz_offset_with_time(): freezer.stop() -def test_time_with_microseconds(): +def test_time_with_microseconds() -> None: freezer = freeze_time(datetime.datetime(1970, 1, 1, 0, 0, 1, 123456)) freezer.start() assert time.time() == 1.123456 freezer.stop() -def test_time_with_dst(): +def test_time_with_dst() -> None: freezer = freeze_time(datetime.datetime(1970, 6, 1, 0, 0, 1, 123456)) freezer.start() assert time.time() == 13046401.123456 freezer.stop() -def test_manual_increment(): +def test_manual_increment() -> None: initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(initial_datetime) as frozen_datetime: @@ -176,7 +177,7 @@ def test_manual_increment(): assert frozen_datetime() == initial_datetime -def test_manual_increment_seconds(): +def test_manual_increment_seconds() -> None: initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(initial_datetime) as frozen_datetime: @@ -191,7 +192,7 @@ def test_manual_increment_seconds(): assert frozen_datetime() == initial_datetime -def test_move_to(): +def test_move_to() -> None: initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) @@ -207,7 +208,7 @@ def test_move_to(): assert frozen_datetime() == initial_datetime -def test_bad_time_argument(): +def test_bad_time_argument() -> None: try: freeze_time("2012-13-14", tz_offset=-4) except ValueError: @@ -222,7 +223,7 @@ def test_bad_time_argument(): ("perf_counter", True, 1.0), ("perf_counter_ns", HAS_PERF_COUNTER_NS, int(1e9)),) ) -def test_time_monotonic(func_name, has_func, tick_size): +def test_time_monotonic(func_name: str, has_func: bool, tick_size: int) -> None: initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) if not has_func: @@ -244,7 +245,7 @@ def test_time_monotonic(func_name, has_func, tick_size): assert t11 == t1 + 10 * tick_size -def test_time_gmtime(): +def test_time_gmtime() -> None: with freeze_time('2012-01-14 03:21:34'): time_struct = time.gmtime() assert time_struct.tm_year == 2012 @@ -260,31 +261,31 @@ def test_time_gmtime(): @pytest.mark.skipif(not HAS_CLOCK, reason="time.clock was removed in Python 3.8") -def test_time_clock(): +def test_time_clock() -> None: with freeze_time('2012-01-14 03:21:34'): - assert time.clock() == 0 + assert time.clock() == 0 # type: ignore[attr-defined] with freeze_time('2012-01-14 03:21:35'): - assert time.clock() == 1 + assert time.clock() == 1 # type: ignore[attr-defined] with freeze_time('2012-01-14 03:21:36'): - assert time.clock() == 2 + assert time.clock() == 2 # type: ignore[attr-defined] class modify_timezone: - def __init__(self, new_timezone): + def __init__(self, new_timezone: int): self.new_timezone = new_timezone self.original_timezone = time.timezone - def __enter__(self): + def __enter__(self) -> None: time.timezone = self.new_timezone - def __exit__(self, *args): + def __exit__(self, *args: Any) -> None: time.timezone = self.original_timezone -def test_time_localtime(): +def test_time_localtime() -> None: with modify_timezone(-3600): # Set this for UTC-1 with freeze_time('2012-01-14 03:21:34'): time_struct = time.localtime() @@ -300,49 +301,49 @@ def test_time_localtime(): assert time.localtime().tm_year != 2012 -def test_strftime(): +def test_strftime() -> None: with modify_timezone(0): with freeze_time('1970-01-01'): assert time.strftime("%Y") == "1970" -def test_real_strftime_fall_through(): +def test_real_strftime_fall_through() -> None: this_real_year = datetime.datetime.now().year with freeze_time(): assert time.strftime('%Y') == str(this_real_year) assert time.strftime('%Y', (2001, 1, 1, 1, 1, 1, 1, 1, 1)) == '2001' -def test_date_object(): +def test_date_object() -> None: frozen_date = datetime.date(year=2012, month=11, day=10) date_freezer = freeze_time(frozen_date) regular_freezer = freeze_time('2012-11-10') assert date_freezer.time_to_freeze == regular_freezer.time_to_freeze -def test_old_date_object(): +def test_old_date_object() -> None: frozen_date = datetime.date(year=1, month=1, day=1) with freeze_time(frozen_date): assert datetime.date.today() == frozen_date -def test_date_with_locale(): +def test_date_with_locale() -> None: with temp_locale(*_dd_mm_yyyy_locales): frozen_date = datetime.date(year=2012, month=1, day=2) date_freezer = freeze_time(frozen_date) assert date_freezer.time_to_freeze.date() == frozen_date -def test_invalid_type(): +def test_invalid_type() -> None: try: - freeze_time(int(4)) + freeze_time(int(4)) # type: ignore except TypeError: pass else: assert False, "Bad types should raise a TypeError" -def test_datetime_object(): +def test_datetime_object() -> None: frozen_datetime = datetime.datetime(year=2012, month=11, day=10, hour=4, minute=15, second=30) datetime_freezer = freeze_time(frozen_datetime) @@ -350,23 +351,23 @@ def test_datetime_object(): assert datetime_freezer.time_to_freeze == regular_freezer.time_to_freeze -def test_function_object(): +def test_function_object() -> None: frozen_datetime = datetime.datetime(year=2012, month=11, day=10, hour=4, minute=15, second=30) - def function(): return frozen_datetime + def function() -> datetime.datetime: return frozen_datetime with freeze_time(function): assert frozen_datetime == datetime.datetime.now() -def test_lambda_object(): +def test_lambda_object() -> None: frozen_datetime = datetime.datetime(year=2012, month=11, day=10, hour=4, minute=15, second=30) with freeze_time(lambda: frozen_datetime): assert frozen_datetime == datetime.datetime.now() -def test_generator_object(): +def test_generator_object() -> None: frozen_datetimes = (datetime.datetime(year=y, month=1, day=1) for y in range(2010, 2012)) @@ -380,7 +381,7 @@ def test_generator_object(): freeze_time(frozen_datetimes) -def test_maya_datetimes(): +def test_maya_datetimes() -> None: if not maya: raise SkipTest("maya is optional since it's not supported for " "enough python versions") @@ -393,14 +394,14 @@ def test_maya_datetimes(): ) -def test_old_datetime_object(): +def test_old_datetime_object() -> None: frozen_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(frozen_datetime): assert datetime.datetime.now() == frozen_datetime -def test_datetime_with_locale(): +def test_datetime_with_locale() -> None: with temp_locale(*_dd_mm_yyyy_locales): frozen_datetime = datetime.datetime(year=2012, month=1, day=2) date_freezer = freeze_time(frozen_datetime) @@ -408,78 +409,78 @@ def test_datetime_with_locale(): @freeze_time("2012-01-14") -def test_decorator(): +def test_decorator() -> None: assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) -def test_decorator_wrapped_attribute(): - def to_decorate(): +def test_decorator_wrapped_attribute() -> None: + def to_decorate() -> None: pass wrapped = freeze_time("2014-01-14")(to_decorate) - assert wrapped.__wrapped__ is to_decorate + assert wrapped.__wrapped__ is to_decorate # type: ignore -class Callable: +class Callable: # type: ignore - def __call__(self, *args, **kws): + def __call__(self, *args: Any, **kws: Any) -> Any: return (args, kws) @freeze_time("2012-01-14") class Tester: - def test_the_class(self): + def test_the_class(self) -> None: assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) - def test_still_the_same(self): + def test_still_the_same(self) -> None: assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) - def test_class_name_preserved_by_decorator(self): + def test_class_name_preserved_by_decorator(self) -> None: assert self.__class__.__name__ == "Tester" class NotATestClass: - def perform_operation(self): + def perform_operation(self) -> datetime.date: return datetime.date.today() @freeze_time('2001-01-01') - def test_class_decorator_ignores_nested_class(self): + def test_class_decorator_ignores_nested_class(self) -> None: not_a_test = self.NotATestClass() assert not_a_test.perform_operation() == datetime.date(2001, 1, 1) - a_mock = Callable() + a_mock = Callable() # type: ignore - def test_class_decorator_wraps_callable_object_py3(self): + def test_class_decorator_wraps_callable_object_py3(self) -> None: assert self.a_mock.__wrapped__.__class__ == Callable @staticmethod - def helper(): + def helper() -> datetime.date: return datetime.date.today() - def test_class_decorator_respects_staticmethod(self): + def test_class_decorator_respects_staticmethod(self) -> None: assert self.helper() == datetime.date(2012, 1, 14) @freeze_time("Jan 14th, 2012") -def test_nice_datetime(): +def test_nice_datetime() -> None: assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) @freeze_time("2012-01-14") -def test_datetime_date_method(): +def test_datetime_date_method() -> None: now = datetime.datetime.now() assert now.date() == FakeDate(2012, 1, 14) -def test_context_manager(): +def test_context_manager() -> None: with freeze_time("2012-01-14"): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) assert datetime.datetime.now() != datetime.datetime(2012, 1, 14) -def test_nested_context_manager(): +def test_nested_context_manager() -> None: with freeze_time("2012-01-14"): with freeze_time("2012-12-25"): _assert_datetime_date_and_time_are_all_equal(datetime.datetime(2012, 12, 25)) @@ -487,13 +488,13 @@ def test_nested_context_manager(): assert datetime.datetime.now() > datetime.datetime(2013, 1, 1) -def _assert_datetime_date_and_time_are_all_equal(expected_datetime): +def _assert_datetime_date_and_time_are_all_equal(expected_datetime: datetime.datetime) -> None: assert datetime.datetime.now() == expected_datetime assert datetime.date.today() == expected_datetime.date() assert datetime.datetime.fromtimestamp(time.time()) == expected_datetime -def test_nested_context_manager_with_tz_offsets(): +def test_nested_context_manager_with_tz_offsets() -> None: with freeze_time("2012-01-14 23:00:00", tz_offset=2): with freeze_time("2012-12-25 19:00:00", tz_offset=6): assert datetime.datetime.now() == datetime.datetime(2012, 12, 26, 1) @@ -505,7 +506,7 @@ def test_nested_context_manager_with_tz_offsets(): @freeze_time("Jan 14th, 2012") -def test_isinstance_with_active(): +def test_isinstance_with_active() -> None: now = datetime.datetime.now() assert utils.is_fake_datetime(now) assert utils.is_fake_date(now.date()) @@ -514,7 +515,7 @@ def test_isinstance_with_active(): assert utils.is_fake_date(today) -def test_isinstance_without_active(): +def test_isinstance_without_active() -> None: now = datetime.datetime.now() assert isinstance(now, datetime.datetime) assert isinstance(now, datetime.date) @@ -526,21 +527,21 @@ def test_isinstance_without_active(): class TestUnitTestMethodDecorator(unittest.TestCase): @freeze_time('2013-04-09') - def test_method_decorator_works_on_unittest(self): + def test_method_decorator_works_on_unittest(self) -> None: self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) @freeze_time('2013-04-09', as_kwarg='frozen_time') - def test_method_decorator_works_on_unittest_kwarg_frozen_time(self, frozen_time): + def test_method_decorator_works_on_unittest_kwarg_frozen_time(self, frozen_time: Any) -> None: self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) self.assertEqual(datetime.date(2013, 4, 9), frozen_time.time_to_freeze.today()) @freeze_time('2013-04-09', as_kwarg='hello') - def test_method_decorator_works_on_unittest_kwarg_hello(self, **kwargs): + def test_method_decorator_works_on_unittest_kwarg_hello(self, **kwargs: Any) -> None: self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) - self.assertEqual(datetime.date(2013, 4, 9), kwargs.get('hello').time_to_freeze.today()) + self.assertEqual(datetime.date(2013, 4, 9), kwargs.get('hello').time_to_freeze.today()) # type: ignore @freeze_time(lambda: datetime.date(year=2013, month=4, day=9), as_kwarg='frozen_time') - def test_method_decorator_works_on_unittest_kwarg_frozen_time_with_func(self, frozen_time): + def test_method_decorator_works_on_unittest_kwarg_frozen_time_with_func(self, frozen_time: Any) -> None: self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) self.assertEqual(datetime.date(2013, 4, 9), frozen_time.time_to_freeze.today()) @@ -549,60 +550,60 @@ def test_method_decorator_works_on_unittest_kwarg_frozen_time_with_func(self, fr class TestUnitTestClassDecorator(unittest.TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: assert datetime.date(2013, 4, 9) == datetime.date.today() - def setUp(self): + def setUp(self) -> None: self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) - def tearDown(self): + def tearDown(self) -> None: self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: assert datetime.date(2013, 4, 9) == datetime.date.today() - def test_class_decorator_works_on_unittest(self): + def test_class_decorator_works_on_unittest(self) -> None: self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) - def test_class_name_preserved_by_decorator(self): + def test_class_name_preserved_by_decorator(self) -> None: self.assertEqual(self.__class__.__name__, "TestUnitTestClassDecorator") @freeze_time('2013-04-09') class TestUnitTestClassDecoratorWithNoSetUpOrTearDown(unittest.TestCase): - def test_class_decorator_works_on_unittest(self): + def test_class_decorator_works_on_unittest(self) -> None: self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) class TestUnitTestClassDecoratorSubclass(TestUnitTestClassDecorator): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: # the super() call can fail if the class decoration was done wrong super().setUpClass() @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: # the super() call can fail if the class decoration was done wrong super().tearDownClass() - def test_class_name_preserved_by_decorator(self): + def test_class_name_preserved_by_decorator(self) -> None: self.assertEqual(self.__class__.__name__, "TestUnitTestClassDecoratorSubclass") class BaseInheritanceFreezableTests(unittest.TestCase): @classmethod - def setUpClass(cls): + def setUpClass(cls) -> None: pass @classmethod - def tearDownClass(cls): + def tearDownClass(cls) -> None: pass class UnfrozenInheritedTests(BaseInheritanceFreezableTests): - def test_time_is_not_frozen(self): + def test_time_is_not_frozen(self) -> None: # In this class, time should not be frozen - and the below decorated # class shouldn't affect that self.assertNotEqual(datetime.date(2013, 4, 9), datetime.date.today()) @@ -610,24 +611,24 @@ def test_time_is_not_frozen(self): @freeze_time('2013-04-09') class FrozenInheritedTests(BaseInheritanceFreezableTests): - def test_time_is_frozen(self): + def test_time_is_frozen(self) -> None: # In this class, time should be frozen self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) class TestOldStyleClasses: - def test_direct_method(self): + def test_direct_method(self) -> None: # Make sure old style classes (not inheriting from object) is supported @freeze_time('2013-04-09') class OldStyleClass: - def method(self): + def method(self) -> datetime.date: return datetime.date.today() assert OldStyleClass().method() == datetime.date(2013, 4, 9) - def test_inherited_method(self): + def test_inherited_method(self) -> None: class OldStyleBaseClass: - def inherited_method(self): + def inherited_method(self) -> datetime.date: return datetime.date.today() @freeze_time('2013-04-09') @@ -637,7 +638,7 @@ class OldStyleClass(OldStyleBaseClass): assert OldStyleClass().inherited_method() == datetime.date(2013, 4, 9) -def test_min_and_max(): +def test_min_and_max() -> None: freezer = freeze_time("2012-01-14") real_datetime = datetime.datetime real_date = datetime.date @@ -664,7 +665,7 @@ def test_min_and_max(): @freeze_time("2014-07-30T01:00:00Z") -def test_freeze_with_timezone_aware_datetime_in_utc(): +def test_freeze_with_timezone_aware_datetime_in_utc() -> None: """ utcnow() should always return a timezone naive datetime """ @@ -673,7 +674,7 @@ def test_freeze_with_timezone_aware_datetime_in_utc(): @freeze_time("1970-01-01T00:00:00-04:00") -def test_freeze_with_timezone_aware_datetime_in_non_utc(): +def test_freeze_with_timezone_aware_datetime_in_non_utc() -> None: """ we expect the system to behave like a system with UTC-4 timezone at the beginning of the Epoch (wall clock should be 4 hrs late) @@ -684,7 +685,7 @@ def test_freeze_with_timezone_aware_datetime_in_non_utc(): @freeze_time('2015-01-01') -def test_time_with_nested(): +def test_time_with_nested() -> None: from time import time first = 1420070400.0 second = 1420070760.0 @@ -697,9 +698,9 @@ def test_time_with_nested(): @pytest.mark.parametrize("func_name", ("monotonic", "perf_counter") ) -def test_monotonic_with_nested(func_name): +def test_monotonic_with_nested(func_name: str) -> None: __import__("time", fromlist=[func_name]) - invoke_time_func = lambda: getattr(time, func_name)() + invoke_time_func: Callable[[], float] = lambda: getattr(time, func_name)() with freeze_time('2015-01-01') as frozen_datetime_1: initial_t1 = invoke_time_func() @@ -712,7 +713,7 @@ def test_monotonic_with_nested(func_name): assert invoke_time_func() == initial_t1 + 1 -def test_should_use_real_time(): +def test_should_use_real_time() -> None: frozen = datetime.datetime(2015, 3, 5) expected_frozen = 1425513600.0 # TODO: local time seems to leak the local timezone, so this test fails in CI @@ -731,7 +732,7 @@ def test_should_use_real_time(): # assert time.localtime() == expected_frozen_local assert time.gmtime() == expected_frozen_gmt if HAS_CLOCK: - assert time.clock() == expected_clock + assert time.clock() == expected_clock # type: ignore[attr-defined] if HAS_TIME_NS: assert time.time_ns() == expected_frozen * 1e9 @@ -743,7 +744,7 @@ def test_should_use_real_time(): # assert time.localtime() != expected_frozen_local assert time.gmtime() != expected_frozen_gmt if HAS_CLOCK: - assert time.clock() != expected_clock + assert time.clock() != expected_clock # type: ignore[attr-defined] if HAS_TIME_NS: assert time.time_ns() != expected_frozen * 1e9 @@ -753,7 +754,7 @@ def test_should_use_real_time(): @pytest.mark.skipif(not HAS_TIME_NS, reason="time.time_ns is present only on 3.7 and above") -def test_time_ns(): +def test_time_ns() -> None: freezer = freeze_time("2012-01-14") local_time = datetime.datetime(2012, 1, 14) utc_time = local_time - datetime.timedelta(seconds=time.timezone) @@ -767,7 +768,7 @@ def test_time_ns(): assert time.time_ns() != expected_timestamp * 1e9 -def test_compare_datetime_and_time_with_timezone(monkeypatch): +def test_compare_datetime_and_time_with_timezone(monkeypatch: pytest.MonkeyPatch) -> None: """ Compare the result of datetime.datetime.now() and time.time() in a non-UTC timezone. These should be consistent. @@ -786,7 +787,7 @@ def test_compare_datetime_and_time_with_timezone(monkeypatch): time.tzset() # set the timezone back to what is was before -def test_timestamp_with_tzoffset(): +def test_timestamp_with_tzoffset() -> None: with freeze_time("2000-01-01", tz_offset=6): utcnow = datetime.datetime(2000, 1, 1, 0) nowtz = datetime.datetime(2000, 1, 1, 0, tzinfo=UTC) @@ -800,7 +801,7 @@ def test_timestamp_with_tzoffset(): assert utcnow == datetime.datetime.utcnow() @pytest.mark.skip("timezone handling is currently incorrect") -def test_datetime_in_timezone(monkeypatch): +def test_datetime_in_timezone(monkeypatch: pytest.MonkeyPatch) -> None: """ It is assumed that the argument passed to freeze_time is in UTC, unless explicitly indicated otherwise. Therefore datetime.now() should return the frozen time with an offset. diff --git a/tests/test_errors.py b/tests/test_errors.py index 06d5b260..9d1a4eb9 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -1,6 +1,7 @@ import contextlib import datetime import sys +from typing import Any, Iterator import pytest from freezegun import freeze_time @@ -22,11 +23,11 @@ class ModuleWithError: __name__ = 'module_with_error' __dict__ = {} - def __init__(self, error_type): + def __init__(self, error_type: Any): self.error_triggered = False self.error_type = error_type - def __dir__(self): + def __dir__(self) -> Any: try: raise self.error_type() finally: @@ -34,10 +35,10 @@ def __dir__(self): @contextlib.contextmanager -def assert_module_with_raised_error(error_type): +def assert_module_with_raised_error(error_type: Any) -> Iterator[None]: """Install a module into sys.modules that raises an error upon invoking __dir__.""" - module = sys.modules['module_with_error'] = ModuleWithError(error_type) + module = sys.modules['module_with_error'] = ModuleWithError(error_type) # type: ignore try: yield @@ -48,7 +49,7 @@ def assert_module_with_raised_error(error_type): @pytest.mark.parametrize('error_type', [ImportError, TypeError]) -def test_ignore_errors_in_start(error_type): +def test_ignore_errors_in_start(error_type: Any) -> None: with assert_module_with_raised_error(error_type): freezer = freeze_time(datetime.datetime(2019, 1, 11, 9, 34)) diff --git a/tests/test_import_alias.py b/tests/test_import_alias.py index 1dfc388d..b18793f6 100644 --- a/tests/test_import_alias.py +++ b/tests/test_import_alias.py @@ -4,22 +4,22 @@ @freeze_time("1980-01-01") -def test_datetime_alias(): +def test_datetime_alias() -> None: assert datetime_aliased.now() == datetime_aliased(1980, 1, 1) @freeze_time("1970-01-01") -def test_time_alias(): +def test_time_alias() -> None: assert time_aliased() == 0.0 @freeze_time('2013-04-09') class TestCallOtherFuncInTestClassDecoratorWithAlias: - def test_calls_other_method(self): + def test_calls_other_method(self) -> None: assert datetime_aliased(2013, 4, 9) == datetime_aliased.today() self.some_other_func() assert datetime_aliased(2013, 4, 9) == datetime_aliased.today() - def some_other_func(self): + def some_other_func(self) -> None: pass diff --git a/tests/test_operations.py b/tests/test_operations.py index 303a1dc8..d34f3dd2 100644 --- a/tests/test_operations.py +++ b/tests/test_operations.py @@ -3,10 +3,11 @@ from dateutil.relativedelta import relativedelta from datetime import timedelta, tzinfo from tests import utils +from typing import Any @freeze_time("2012-01-14") -def test_addition(): +def test_addition() -> None: now = datetime.datetime.now() later = now + datetime.timedelta(days=1) other_later = now + relativedelta(days=1) @@ -21,7 +22,7 @@ def test_addition(): @freeze_time("2012-01-14") -def test_subtraction(): +def test_subtraction() -> None: now = datetime.datetime.now() before = now - datetime.timedelta(days=1) other_before = now - relativedelta(days=1) @@ -40,52 +41,52 @@ def test_subtraction(): @freeze_time("2012-01-14") -def test_datetime_timezone_none(): +def test_datetime_timezone_none() -> None: now = datetime.datetime.now(tz=None) assert now == datetime.datetime(2012, 1, 14) class GMT5(tzinfo): - def utcoffset(self, dt): + def utcoffset(self, dt: Any) -> timedelta: return timedelta(hours=5) - def tzname(self, dt): + def tzname(self, dt: Any) -> str: return "GMT +5" - def dst(self, dt): + def dst(self, dt: Any) -> timedelta: return timedelta(0) @freeze_time("2012-01-14 2:00:00") -def test_datetime_timezone_real(): +def test_datetime_timezone_real() -> None: now = datetime.datetime.now(tz=GMT5()) assert now == datetime.datetime(2012, 1, 14, 7, tzinfo=GMT5()) assert now.utcoffset() == timedelta(0, 60 * 60 * 5) @freeze_time("2012-01-14 2:00:00", tz_offset=-4) -def test_datetime_timezone_real_with_offset(): +def test_datetime_timezone_real_with_offset() -> None: now = datetime.datetime.now(tz=GMT5()) assert now == datetime.datetime(2012, 1, 14, 3, tzinfo=GMT5()) assert now.utcoffset() == timedelta(0, 60 * 60 * 5) @freeze_time("2012-01-14 00:00:00") -def test_astimezone(): +def test_astimezone() -> None: now = datetime.datetime.now(tz=GMT5()) converted = now.astimezone(GMT5()) assert utils.is_fake_datetime(converted) @freeze_time("2012-01-14 00:00:00") -def test_astimezone_tz_none(): +def test_astimezone_tz_none() -> None: now = datetime.datetime.now(tz=GMT5()) converted = now.astimezone() assert utils.is_fake_datetime(converted) @freeze_time("2012-01-14 00:00:00") -def test_replace(): +def test_replace() -> None: now = datetime.datetime.now() modified_time = now.replace(year=2013) assert utils.is_fake_datetime(modified_time) @@ -96,7 +97,7 @@ def test_replace(): @freeze_time("Jan 14th, 2020", auto_tick_seconds=15) -def test_auto_tick(): +def test_auto_tick() -> None: first_time = datetime.datetime.now() auto_incremented_time = datetime.datetime.now() assert first_time + datetime.timedelta(seconds=15) == auto_incremented_time diff --git a/tests/test_pickle.py b/tests/test_pickle.py index 95bce9b5..6ca35fc4 100644 --- a/tests/test_pickle.py +++ b/tests/test_pickle.py @@ -3,7 +3,7 @@ from freezegun import freeze_time -def assert_pickled_datetimes_equal_original(): +def assert_pickled_datetimes_equal_original() -> None: min_datetime = datetime.datetime.min max_datetime = datetime.datetime.max min_date = datetime.date.min @@ -20,7 +20,7 @@ def assert_pickled_datetimes_equal_original(): assert pickle.loads(pickle.dumps(utc_now)) == utc_now -def test_pickle(): +def test_pickle() -> None: freezer = freeze_time("2012-01-14") freezer.start() @@ -30,7 +30,7 @@ def test_pickle(): assert_pickled_datetimes_equal_original() -def test_pickle_real_datetime(): +def test_pickle_real_datetime() -> None: real_datetime = datetime.datetime(1970, 2, 1) pickle.loads(pickle.dumps(real_datetime)) == real_datetime @@ -45,7 +45,7 @@ def test_pickle_real_datetime(): assert pickle.loads(pickle.dumps(real_datetime)) == real_datetime -def test_pickle_real_date(): +def test_pickle_real_date() -> None: real_date = datetime.date(1970, 2, 1) assert pickle.loads(pickle.dumps(real_date)) == real_date diff --git a/tests/test_sqlite3.py b/tests/test_sqlite3.py index e63ff753..41d30711 100644 --- a/tests/test_sqlite3.py +++ b/tests/test_sqlite3.py @@ -4,12 +4,12 @@ @freeze_time("2013-01-01") -def test_fake_datetime_select(): +def test_fake_datetime_select() -> None: db = sqlite3.connect("/tmp/foo") db.execute("""select ?""", (datetime.datetime.now(),)) @freeze_time("2013-01-01") -def test_fake_date_select(): +def test_fake_date_select() -> None: db = sqlite3.connect("/tmp/foo") db.execute("""select ?""", (datetime.date.today(),)) diff --git a/tests/test_ticking.py b/tests/test_ticking.py index e33b5d23..6385fe28 100644 --- a/tests/test_ticking.py +++ b/tests/test_ticking.py @@ -9,7 +9,7 @@ from tests import utils @utils.cpython_only -def test_ticking_datetime(): +def test_ticking_datetime() -> None: with freeze_time("Jan 14th, 2012", tick=True): time.sleep(0.001) # Deal with potential clock resolution problems assert datetime.datetime.now() > datetime.datetime(2012, 1, 14) @@ -18,23 +18,23 @@ def test_ticking_datetime(): @pytest.mark.skipif(not hasattr(time, "clock"), reason="time.clock was removed in Python 3.8") @utils.cpython_only -def test_ticking_time_clock(): +def test_ticking_time_clock() -> None: with freeze_time('2012-01-14 03:21:34', tick=True): - first = time.clock() + first = time.clock() # type: ignore time.sleep(0.001) # Deal with potential clock resolution problems with freeze_time('2012-01-14 03:21:35', tick=True): - second = time.clock() + second = time.clock() # type: ignore time.sleep(0.001) # Deal with potential clock resolution problems with freeze_time('2012-01-14 03:21:36', tick=True): - third = time.clock() + third = time.clock() # type: ignore time.sleep(0.001) # Rewind time backwards with freeze_time('2012-01-14 03:20:00', tick=True): - fourth = time.clock() + fourth = time.clock() # type: ignore time.sleep(0.001) - fifth = time.clock() + fifth = time.clock() # type: ignore assert first > 0 assert second > first @@ -50,21 +50,21 @@ def test_ticking_time_clock(): @utils.cpython_only -def test_ticking_date(): +def test_ticking_date() -> None: with freeze_time("Jan 14th, 2012, 23:59:59.9999999", tick=True): time.sleep(0.001) # Deal with potential clock resolution problems assert datetime.date.today() == datetime.date(2012, 1, 15) @utils.cpython_only -def test_ticking_time(): +def test_ticking_time() -> None: with freeze_time("Jan 14th, 2012, 23:59:59", tick=True): time.sleep(0.001) # Deal with potential clock resolution problems assert time.time() > 1326585599.0 @utils.cpython_only -def test_ticking_tick(): +def test_ticking_tick() -> None: with freeze_time("Jan 14th, 2012, 23:59:59", tick=True) as ft: ft.tick(61) time.sleep(0.001) # Deal with potential clock resolution problems @@ -80,7 +80,7 @@ def test_ticking_tick(): @utils.cpython_only -def test_ticking_move_to(): +def test_ticking_move_to() -> None: with freeze_time("Jan 14th, 2012, 23:59:59", tick=True) as ft: ft.move_to("Jan 15th, 2012, 00:59:59.999999") time.sleep(0.001) # Deal with potential clock resolution problems @@ -91,7 +91,7 @@ def test_ticking_move_to(): @pytest.mark.parametrize("func_name", ("monotonic", "monotonic_ns", "perf_counter", "perf_counter_ns"), ) -def test_ticking_monotonic(func_name): +def test_ticking_monotonic(func_name: str) -> None: if sys.version_info[0:2] >= (3, 7): # All of these functions should exist in Python 3.7+, so this test helps # avoid inappropriate skipping when we've accidentally typo-ed the name @@ -110,7 +110,7 @@ def test_ticking_monotonic(func_name): @mock.patch('freezegun.api._is_cpython', False) -def test_pypy_compat(): +def test_pypy_compat() -> None: try: freeze_time("Jan 14th, 2012, 23:59:59", tick=True) except SystemError: @@ -120,7 +120,7 @@ def test_pypy_compat(): @mock.patch('freezegun.api._is_cpython', True) -def test_non_pypy_compat(): +def test_non_pypy_compat() -> None: try: freeze_time("Jan 14th, 2012, 23:59:59", tick=True) except Exception: diff --git a/tests/test_utils.py b/tests/test_utils.py index 603c7910..1669ba2d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -6,7 +6,7 @@ @mock.patch('platform.python_implementation', lambda: 'CPython') -def test_should_not_skip_cpython(): +def test_should_not_skip_cpython() -> None: reload(api) reload(utils) function_mock = mock.MagicMock(__name__='function') @@ -18,7 +18,7 @@ def test_should_not_skip_cpython(): @mock.patch('platform.python_implementation', lambda: 'not-CPython') -def test_should_skip_non_cpython(): +def test_should_skip_non_cpython() -> None: reload(api) reload(utils) function_mock = mock.MagicMock(__name__='function', skipped=False) diff --git a/tests/test_uuid.py b/tests/test_uuid.py index 08ae8a14..5bdfcd69 100644 --- a/tests/test_uuid.py +++ b/tests/test_uuid.py @@ -1,10 +1,11 @@ import datetime import uuid +from typing import Any from freezegun import freeze_time -def time_from_uuid(value): +def time_from_uuid(value: Any) -> datetime.datetime: """ Converts an UUID(1) to it's datetime value """ @@ -14,7 +15,7 @@ def time_from_uuid(value): datetime.timedelta(microseconds=uvalue.time // 10)) -def test_uuid1_future(): +def test_uuid1_future() -> None: """ Test that we can go back in time after setting a future date. Normally UUID1 would disallow this, since it keeps track of @@ -29,7 +30,7 @@ def test_uuid1_future(): assert time_from_uuid(uuid.uuid1()) == past_target -def test_uuid1_past(): +def test_uuid1_past() -> None: """ Test that we can go forward in time after setting some time in the past. This is simply the opposite of test_uuid1_future() diff --git a/tests/test_warnings.py b/tests/test_warnings.py index 5ee32ae4..81ad2715 100644 --- a/tests/test_warnings.py +++ b/tests/test_warnings.py @@ -3,6 +3,7 @@ import sys import types import warnings +from typing import Iterator from freezegun import freeze_time @@ -30,7 +31,7 @@ class ModuleWithWarning: counter = 0 @property - def attribute_that_emits_a_warning(self): + def attribute_that_emits_a_warning(self) -> None: # Use unique warning messages to avoid messages being only reported once self.__class__.counter += 1 warnings.warn(f'this is test warning #{self.__class__.counter}') @@ -38,10 +39,10 @@ def attribute_that_emits_a_warning(self): @contextlib.contextmanager -def assert_module_with_emitted_warning(): +def assert_module_with_emitted_warning() -> Iterator[None]: """Install a module that triggers warnings into sys.modules and ensure the warning was triggered in the with-block. """ - module = sys.modules['module_with_warning'] = ModuleWithWarning() + module = sys.modules['module_with_warning'] = ModuleWithWarning() # type: ignore try: yield @@ -52,7 +53,7 @@ def assert_module_with_emitted_warning(): @contextlib.contextmanager -def assert_no_warnings(): +def assert_no_warnings() -> Iterator[None]: """A context manager that makes sure no warnings was emitted.""" with warnings.catch_warnings(record=True) as caught_warnings: warnings.filterwarnings('always') @@ -60,7 +61,7 @@ def assert_no_warnings(): assert not caught_warnings -def test_ignore_warnings_in_start(): +def test_ignore_warnings_in_start() -> None: """Make sure that modules being introspected in start() does not emit warnings.""" with assert_module_with_emitted_warning(): freezer = freeze_time(datetime.datetime(2016, 10, 27, 9, 56)) @@ -73,7 +74,7 @@ def test_ignore_warnings_in_start(): freezer.stop() -def test_ignore_warnings_in_stop(): +def test_ignore_warnings_in_stop() -> None: """Make sure that modules that was loaded after start() does not trigger warnings in stop()""" freezer = freeze_time(datetime.datetime(2016, 10, 27, 9, 56)) diff --git a/tests/utils.py b/tests/utils.py index 6cb8a235..7fb64447 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,16 +1,24 @@ from functools import wraps +from typing import Any, Callable, TYPE_CHECKING, TypeVar from unittest import SkipTest from freezegun.api import FakeDate, FakeDatetime, _is_cpython import pytest +if TYPE_CHECKING: + from typing_extensions import ParamSpec -def is_fake_date(obj): + P = ParamSpec("P") + +T = TypeVar("T") + + +def is_fake_date(obj: Any) -> bool: return obj.__class__ is FakeDate -def is_fake_datetime(obj): +def is_fake_datetime(obj: Any) -> bool: return obj.__class__ is FakeDatetime @@ -19,9 +27,9 @@ def is_fake_datetime(obj): reason="Requires CPython") -def cpython_only(func): +def cpython_only(func: Callable[P, T]) -> Callable[P, T]: @wraps(func) - def wrapper(*args): + def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: if not _is_cpython: raise SkipTest("Requires CPython") return func(*args) diff --git a/tox.ini b/tox.ini index e021ed40..4fd676a6 100644 --- a/tox.ini +++ b/tox.ini @@ -13,4 +13,4 @@ deps = -rrequirements.txt [testenv:mypy] deps = mypy -commands = mypy freezegun +commands = mypy freezegun tests --install-types --non-interactive