Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pendulum/testing/traveller.py: 45%
66 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-30 06:11 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-30 06:11 +0000
1from __future__ import annotations
3from typing import TYPE_CHECKING
4from typing import cast
6from pendulum.datetime import DateTime
7from pendulum.utils._compat import PYPY
10if TYPE_CHECKING:
11 from types import TracebackType
13 from typing_extensions import Self
16class BaseTraveller:
17 def __init__(self, datetime_class: type[DateTime] = DateTime) -> None:
18 self._datetime_class: type[DateTime] = datetime_class
20 def freeze(self) -> Self:
21 raise NotImplementedError()
23 def travel_back(self) -> Self:
24 raise NotImplementedError()
26 def travel(
27 self,
28 years: int = 0,
29 months: int = 0,
30 weeks: int = 0,
31 days: int = 0,
32 hours: int = 0,
33 minutes: int = 0,
34 seconds: int = 0,
35 microseconds: int = 0,
36 ) -> Self:
37 raise NotImplementedError()
39 def travel_to(self, dt: DateTime, *, freeze: bool = False) -> Self:
40 raise NotImplementedError()
42 def __enter__(self) -> Self:
43 return self
45 def __exit__(
46 self,
47 exc_type: type[BaseException] | None,
48 exc_val: BaseException | None,
49 exc_tb: TracebackType,
50 ) -> None:
51 ...
54if not PYPY:
55 import time_machine
57 class Traveller(BaseTraveller):
58 def __init__(self, datetime_class: type[DateTime] = DateTime) -> None:
59 super().__init__(datetime_class)
61 self._started: bool = False
62 self._traveller: time_machine.travel | None = None
63 self._coordinates: time_machine.Coordinates | None = None
65 def freeze(self) -> Self:
66 if self._started:
67 cast(time_machine.Coordinates, self._coordinates).move_to(
68 self._datetime_class.now(), tick=False
69 )
70 else:
71 self._start(freeze=True)
73 return self
75 def travel_back(self) -> Self:
76 if not self._started:
77 return self
79 cast(time_machine.travel, self._traveller).stop()
80 self._coordinates = None
81 self._traveller = None
82 self._started = False
84 return self
86 def travel(
87 self,
88 years: int = 0,
89 months: int = 0,
90 weeks: int = 0,
91 days: int = 0,
92 hours: int = 0,
93 minutes: int = 0,
94 seconds: int = 0,
95 microseconds: int = 0,
96 *,
97 freeze: bool = False,
98 ) -> Self:
99 self._start(freeze=freeze)
101 cast(time_machine.Coordinates, self._coordinates).move_to(
102 self._datetime_class.now().add(
103 years=years,
104 months=months,
105 weeks=weeks,
106 days=days,
107 hours=hours,
108 minutes=minutes,
109 seconds=seconds,
110 microseconds=microseconds,
111 )
112 )
114 return self
116 def travel_to(self, dt: DateTime, *, freeze: bool = False) -> Self:
117 self._start(freeze=freeze)
119 cast(time_machine.Coordinates, self._coordinates).move_to(dt)
121 return self
123 def _start(self, freeze: bool = False) -> None:
124 if self._started:
125 return
127 if not self._traveller:
128 self._traveller = time_machine.travel(
129 self._datetime_class.now(), tick=not freeze
130 )
132 self._coordinates = self._traveller.start()
134 self._started = True
136 def __enter__(self) -> Self:
137 self._start()
139 return self
141 def __exit__(
142 self,
143 exc_type: type[BaseException] | None,
144 exc_val: BaseException | None,
145 exc_tb: TracebackType,
146 ) -> None:
147 self.travel_back()
149else:
151 class Traveller(BaseTraveller): # type: ignore[no-redef]
152 ...