clock-pattern 0.3.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clock_pattern-0.5.0/PKG-INFO +193 -0
- clock_pattern-0.5.0/README.md +169 -0
- clock_pattern-0.5.0/clock_pattern/__init__.py +10 -0
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/clock_pattern/clocks/system_clock.py +5 -5
- clock_pattern-0.5.0/clock_pattern/clocks/testing/__init__.py +7 -0
- clock_pattern-0.5.0/clock_pattern/clocks/testing/mock_clock.py +289 -0
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/clock_pattern/clocks/utc_clock.py +2 -2
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/clock_pattern/models/clock.py +3 -3
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/pyproject.toml +1 -1
- clock_pattern-0.3.0/PKG-INFO +0 -95
- clock_pattern-0.3.0/README.md +0 -71
- clock_pattern-0.3.0/clock_pattern/__init__.py +0 -1
- clock_pattern-0.3.0/clock_pattern/clocks/testing/__init__.py +0 -3
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/.gitignore +0 -0
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/LICENSE.md +0 -0
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/clock_pattern/clocks/__init__.py +0 -0
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/clock_pattern/clocks/testing/fixed_clock.py +0 -0
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/clock_pattern/models/__init__.py +0 -0
- {clock_pattern-0.3.0 → clock_pattern-0.5.0}/clock_pattern/py.typed +0 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clock-pattern
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: The Clock Pattern is a Python package that turns time into an injectable dependency.
|
|
5
|
+
Project-URL: Homepage, https://github.com/adriamontoto/clock-pattern
|
|
6
|
+
Project-URL: Repository, https://github.com/adriamontoto/clock-pattern
|
|
7
|
+
Project-URL: Issues, https://github.com/adriamontoto/clock-pattern/issues
|
|
8
|
+
Author: Adria Montoto
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE.md
|
|
11
|
+
Keywords: clock,dependency-injection,development,domain-driven-design,pattern,python,utilities
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: value-object-pattern>=0.6.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
<a name="readme-top"></a>
|
|
26
|
+
|
|
27
|
+
# 🕰️ Clock Pattern
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<a href="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml?event=push&branch=master" target="_blank">
|
|
31
|
+
<img src="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml/badge.svg?event=push&branch=master" alt="CI Pipeline">
|
|
32
|
+
</a>
|
|
33
|
+
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/adriamontoto/clock-pattern" target="_blank">
|
|
34
|
+
<img src="https://coverage-badge.samuelcolvin.workers.dev/adriamontoto/clock-pattern.svg" alt="Coverage Pipeline">
|
|
35
|
+
</a>
|
|
36
|
+
<a href="https://pypi.org/project/clock-pattern" target="_blank">
|
|
37
|
+
<img src="https://img.shields.io/pypi/v/clock-pattern?color=%2334D058&label=pypi%20package" alt="Package Version">
|
|
38
|
+
</a>
|
|
39
|
+
<a href="https://pypi.org/project/clock-pattern/" target="_blank">
|
|
40
|
+
<img src="https://img.shields.io/pypi/pyversions/clock-pattern.svg?color=%2334D058" alt="Supported Python Versions">
|
|
41
|
+
</a>
|
|
42
|
+
<a href="https://pepy.tech/projects/clock-pattern" target="_blank">
|
|
43
|
+
<img src="https://static.pepy.tech/badge/clock-pattern/month" alt="Package Downloads">
|
|
44
|
+
</a>
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
The **Clock Pattern** is a Python 🐍 package that turns time into an injectable dependency 🧩. By replacing ad-hoc datetime.now() calls with a swappable Clock interface 🕰️ you unlock deterministic tests 🧪, decouple business logic from the OS clock, and gain the freedom to swap in high-precision or logical clocks without touching domain code.
|
|
48
|
+
<br><br>
|
|
49
|
+
|
|
50
|
+
## Table of Contents
|
|
51
|
+
|
|
52
|
+
- [📥 Installation](#installation)
|
|
53
|
+
- [💻 Utilization](#utilization)
|
|
54
|
+
- [📚 Available Clocks](#available-clocks)
|
|
55
|
+
- [🎄 Real-Life Case: Christmas Detector Service](#real-life-case-christmas-detector-service)
|
|
56
|
+
- [🤝 Contributing](#contributing)
|
|
57
|
+
- [🔑 License](#license)
|
|
58
|
+
|
|
59
|
+
<p align="right">
|
|
60
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
61
|
+
</p><br><br>
|
|
62
|
+
|
|
63
|
+
<a name="installation"></a>
|
|
64
|
+
|
|
65
|
+
## 📥 Installation
|
|
66
|
+
|
|
67
|
+
You can install **Clock Pattern** using `pip`:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install clock-pattern
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
<p align="right">
|
|
74
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
75
|
+
</p><br><br>
|
|
76
|
+
|
|
77
|
+
<a name="utilization"></a>
|
|
78
|
+
|
|
79
|
+
## 💻 Utilization
|
|
80
|
+
|
|
81
|
+
The **Clock Pattern** library is designed to be straightforward. Simply import the desired clock and use its `now()` or `today()` methods to get the current datetime/date. This approach allows for easy dependency injection and testing.
|
|
82
|
+
|
|
83
|
+
Here is a basic example of how to use the [`SystemClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/system_clock.py) clock:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from datetime import timezone
|
|
87
|
+
|
|
88
|
+
from clock_pattern import SystemClock
|
|
89
|
+
|
|
90
|
+
clock = SystemClock(timezone=timezone.utc)
|
|
91
|
+
print(clock.now())
|
|
92
|
+
# >>> 2025-06-16 13:57:26.210964+00:00
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
<p align="right">
|
|
96
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
97
|
+
</p><br><br>
|
|
98
|
+
|
|
99
|
+
<a name="available-clocks"></a>
|
|
100
|
+
|
|
101
|
+
## 📚 Available Clocks
|
|
102
|
+
|
|
103
|
+
The package offers several clock implementations to suit different needs:
|
|
104
|
+
|
|
105
|
+
- [`clock_pattern.SystemClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/system_clock.py): The standard clock implementation that returns the system's current datetime/date with the provided timezone.
|
|
106
|
+
- [`clock_pattern.UtcClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/utc_clock.py): A clock implementation that returns the system's current datetime/date in UTC. Ideal for production environments.
|
|
107
|
+
- [`clock_pattern.clocks.testing.FixedClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/fixed_clock.py): A clock that always returns a fixed, preset datetime/date. It is perfect for basic testing as it allows you to control the datetime/date within your test environment, ensuring deterministic results.
|
|
108
|
+
- [`clock_pattern.clocks.testing.MockClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/mock_clock.py): A clock that allows you to mock the system clock. It is perfect for more complex testing as it allows you to control the datetime/date within your test environment and if or not the methods are called or not.
|
|
109
|
+
<p align="right">
|
|
110
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
111
|
+
</p><br><br>
|
|
112
|
+
|
|
113
|
+
<a name="real-life-case-christmas-detector-service"></a>
|
|
114
|
+
|
|
115
|
+
## 🎄 Real-Life Case: Christmas Detector Service
|
|
116
|
+
|
|
117
|
+
Below is an example of a real-life scenario where Clock Pattern can create clean and testable code. We have a `ChristmasDetectorService` that checks if the curren date falls within a specific Christmas holiday range. Using the Clock Pattern, in this case [`UtcClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/utc_clock.py) and [`MockClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/mock_clock.py), we can decouple the service from the python `datetime.now()` and `datetime.today()` functions, making it easy to test for different dates without changing the system's time.
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from datetime import date
|
|
121
|
+
|
|
122
|
+
from clock_pattern import Clock, UtcClock
|
|
123
|
+
from clock_pattern.clocks.testing import MockClock
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class ChristmasDetectorService:
|
|
127
|
+
def __init__(self, clock: Clock) -> None:
|
|
128
|
+
self.clock = clock
|
|
129
|
+
self.christmas_start = date(year=2024, month=12, day=24)
|
|
130
|
+
self.christmas_end = date(year=2025, month=1, day=6)
|
|
131
|
+
|
|
132
|
+
def is_christmas(self) -> bool:
|
|
133
|
+
return self.christmas_start <= self.clock.today() <= self.christmas_end
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
clock = UtcClock()
|
|
137
|
+
christmas_detector_service = ChristmasDetectorService(clock=clock)
|
|
138
|
+
|
|
139
|
+
print(christmas_detector_service.is_christmas())
|
|
140
|
+
# >>> False
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_christmas_detector_is_christmas() -> None:
|
|
144
|
+
clock = MockClock()
|
|
145
|
+
christmas_detector_service = ChristmasDetectorService(clock=clock)
|
|
146
|
+
|
|
147
|
+
today = date(year=2024, month=12, day=25)
|
|
148
|
+
clock.prepare_today_method_return_value(today=today)
|
|
149
|
+
|
|
150
|
+
assert christmas_detector_service.is_christmas() is True
|
|
151
|
+
clock.assert_today_method_was_called_once()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_christmas_detector_is_not_christmas() -> None:
|
|
155
|
+
clock = MockClock()
|
|
156
|
+
christmas_detector_service = ChristmasDetectorService(clock=clock)
|
|
157
|
+
|
|
158
|
+
today = date(year=2025, month=1, day=7)
|
|
159
|
+
clock.prepare_today_method_return_value(today=today)
|
|
160
|
+
|
|
161
|
+
assert christmas_detector_service.is_christmas() is False
|
|
162
|
+
clock.assert_today_method_was_called_once()
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
<p align="right">
|
|
166
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
167
|
+
</p><br><br>
|
|
168
|
+
|
|
169
|
+
<a name="contributing"></a>
|
|
170
|
+
|
|
171
|
+
## 🤝 Contributing
|
|
172
|
+
|
|
173
|
+
We love community help! Before you open an issue or pull request, please read:
|
|
174
|
+
|
|
175
|
+
- [`🤝 How to Contribute`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CONTRIBUTING.md)
|
|
176
|
+
- [`🧭 Code of Conduct`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CODE_OF_CONDUCT.md)
|
|
177
|
+
- [`🔐 Security Policy`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/SECURITY.md)
|
|
178
|
+
|
|
179
|
+
_Thank you for helping make **🕰️ Clock Pattern** package awesome! 🌟_
|
|
180
|
+
|
|
181
|
+
<p align="right">
|
|
182
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
183
|
+
</p><br><br>
|
|
184
|
+
|
|
185
|
+
<a name="license"></a>
|
|
186
|
+
|
|
187
|
+
## 🔑 License
|
|
188
|
+
|
|
189
|
+
This project is licensed under the terms of the [`MIT license`](https://github.com/adriamontoto/clock-pattern/blob/master/LICENSE.md).
|
|
190
|
+
|
|
191
|
+
<p align="right">
|
|
192
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
193
|
+
</p>
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<a name="readme-top"></a>
|
|
2
|
+
|
|
3
|
+
# 🕰️ Clock Pattern
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml?event=push&branch=master" target="_blank">
|
|
7
|
+
<img src="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml/badge.svg?event=push&branch=master" alt="CI Pipeline">
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/adriamontoto/clock-pattern" target="_blank">
|
|
10
|
+
<img src="https://coverage-badge.samuelcolvin.workers.dev/adriamontoto/clock-pattern.svg" alt="Coverage Pipeline">
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://pypi.org/project/clock-pattern" target="_blank">
|
|
13
|
+
<img src="https://img.shields.io/pypi/v/clock-pattern?color=%2334D058&label=pypi%20package" alt="Package Version">
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://pypi.org/project/clock-pattern/" target="_blank">
|
|
16
|
+
<img src="https://img.shields.io/pypi/pyversions/clock-pattern.svg?color=%2334D058" alt="Supported Python Versions">
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://pepy.tech/projects/clock-pattern" target="_blank">
|
|
19
|
+
<img src="https://static.pepy.tech/badge/clock-pattern/month" alt="Package Downloads">
|
|
20
|
+
</a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
The **Clock Pattern** is a Python 🐍 package that turns time into an injectable dependency 🧩. By replacing ad-hoc datetime.now() calls with a swappable Clock interface 🕰️ you unlock deterministic tests 🧪, decouple business logic from the OS clock, and gain the freedom to swap in high-precision or logical clocks without touching domain code.
|
|
24
|
+
<br><br>
|
|
25
|
+
|
|
26
|
+
## Table of Contents
|
|
27
|
+
|
|
28
|
+
- [📥 Installation](#installation)
|
|
29
|
+
- [💻 Utilization](#utilization)
|
|
30
|
+
- [📚 Available Clocks](#available-clocks)
|
|
31
|
+
- [🎄 Real-Life Case: Christmas Detector Service](#real-life-case-christmas-detector-service)
|
|
32
|
+
- [🤝 Contributing](#contributing)
|
|
33
|
+
- [🔑 License](#license)
|
|
34
|
+
|
|
35
|
+
<p align="right">
|
|
36
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
37
|
+
</p><br><br>
|
|
38
|
+
|
|
39
|
+
<a name="installation"></a>
|
|
40
|
+
|
|
41
|
+
## 📥 Installation
|
|
42
|
+
|
|
43
|
+
You can install **Clock Pattern** using `pip`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install clock-pattern
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
<p align="right">
|
|
50
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
51
|
+
</p><br><br>
|
|
52
|
+
|
|
53
|
+
<a name="utilization"></a>
|
|
54
|
+
|
|
55
|
+
## 💻 Utilization
|
|
56
|
+
|
|
57
|
+
The **Clock Pattern** library is designed to be straightforward. Simply import the desired clock and use its `now()` or `today()` methods to get the current datetime/date. This approach allows for easy dependency injection and testing.
|
|
58
|
+
|
|
59
|
+
Here is a basic example of how to use the [`SystemClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/system_clock.py) clock:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from datetime import timezone
|
|
63
|
+
|
|
64
|
+
from clock_pattern import SystemClock
|
|
65
|
+
|
|
66
|
+
clock = SystemClock(timezone=timezone.utc)
|
|
67
|
+
print(clock.now())
|
|
68
|
+
# >>> 2025-06-16 13:57:26.210964+00:00
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
<p align="right">
|
|
72
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
73
|
+
</p><br><br>
|
|
74
|
+
|
|
75
|
+
<a name="available-clocks"></a>
|
|
76
|
+
|
|
77
|
+
## 📚 Available Clocks
|
|
78
|
+
|
|
79
|
+
The package offers several clock implementations to suit different needs:
|
|
80
|
+
|
|
81
|
+
- [`clock_pattern.SystemClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/system_clock.py): The standard clock implementation that returns the system's current datetime/date with the provided timezone.
|
|
82
|
+
- [`clock_pattern.UtcClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/utc_clock.py): A clock implementation that returns the system's current datetime/date in UTC. Ideal for production environments.
|
|
83
|
+
- [`clock_pattern.clocks.testing.FixedClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/fixed_clock.py): A clock that always returns a fixed, preset datetime/date. It is perfect for basic testing as it allows you to control the datetime/date within your test environment, ensuring deterministic results.
|
|
84
|
+
- [`clock_pattern.clocks.testing.MockClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/mock_clock.py): A clock that allows you to mock the system clock. It is perfect for more complex testing as it allows you to control the datetime/date within your test environment and if or not the methods are called or not.
|
|
85
|
+
<p align="right">
|
|
86
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
87
|
+
</p><br><br>
|
|
88
|
+
|
|
89
|
+
<a name="real-life-case-christmas-detector-service"></a>
|
|
90
|
+
|
|
91
|
+
## 🎄 Real-Life Case: Christmas Detector Service
|
|
92
|
+
|
|
93
|
+
Below is an example of a real-life scenario where Clock Pattern can create clean and testable code. We have a `ChristmasDetectorService` that checks if the curren date falls within a specific Christmas holiday range. Using the Clock Pattern, in this case [`UtcClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/utc_clock.py) and [`MockClock`](https://github.com/adriamontoto/clock-pattern/blob/master/clock_pattern/clocks/testing/mock_clock.py), we can decouple the service from the python `datetime.now()` and `datetime.today()` functions, making it easy to test for different dates without changing the system's time.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from datetime import date
|
|
97
|
+
|
|
98
|
+
from clock_pattern import Clock, UtcClock
|
|
99
|
+
from clock_pattern.clocks.testing import MockClock
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class ChristmasDetectorService:
|
|
103
|
+
def __init__(self, clock: Clock) -> None:
|
|
104
|
+
self.clock = clock
|
|
105
|
+
self.christmas_start = date(year=2024, month=12, day=24)
|
|
106
|
+
self.christmas_end = date(year=2025, month=1, day=6)
|
|
107
|
+
|
|
108
|
+
def is_christmas(self) -> bool:
|
|
109
|
+
return self.christmas_start <= self.clock.today() <= self.christmas_end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
clock = UtcClock()
|
|
113
|
+
christmas_detector_service = ChristmasDetectorService(clock=clock)
|
|
114
|
+
|
|
115
|
+
print(christmas_detector_service.is_christmas())
|
|
116
|
+
# >>> False
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_christmas_detector_is_christmas() -> None:
|
|
120
|
+
clock = MockClock()
|
|
121
|
+
christmas_detector_service = ChristmasDetectorService(clock=clock)
|
|
122
|
+
|
|
123
|
+
today = date(year=2024, month=12, day=25)
|
|
124
|
+
clock.prepare_today_method_return_value(today=today)
|
|
125
|
+
|
|
126
|
+
assert christmas_detector_service.is_christmas() is True
|
|
127
|
+
clock.assert_today_method_was_called_once()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_christmas_detector_is_not_christmas() -> None:
|
|
131
|
+
clock = MockClock()
|
|
132
|
+
christmas_detector_service = ChristmasDetectorService(clock=clock)
|
|
133
|
+
|
|
134
|
+
today = date(year=2025, month=1, day=7)
|
|
135
|
+
clock.prepare_today_method_return_value(today=today)
|
|
136
|
+
|
|
137
|
+
assert christmas_detector_service.is_christmas() is False
|
|
138
|
+
clock.assert_today_method_was_called_once()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
<p align="right">
|
|
142
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
143
|
+
</p><br><br>
|
|
144
|
+
|
|
145
|
+
<a name="contributing"></a>
|
|
146
|
+
|
|
147
|
+
## 🤝 Contributing
|
|
148
|
+
|
|
149
|
+
We love community help! Before you open an issue or pull request, please read:
|
|
150
|
+
|
|
151
|
+
- [`🤝 How to Contribute`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CONTRIBUTING.md)
|
|
152
|
+
- [`🧭 Code of Conduct`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CODE_OF_CONDUCT.md)
|
|
153
|
+
- [`🔐 Security Policy`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/SECURITY.md)
|
|
154
|
+
|
|
155
|
+
_Thank you for helping make **🕰️ Clock Pattern** package awesome! 🌟_
|
|
156
|
+
|
|
157
|
+
<p align="right">
|
|
158
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
159
|
+
</p><br><br>
|
|
160
|
+
|
|
161
|
+
<a name="license"></a>
|
|
162
|
+
|
|
163
|
+
## 🔑 License
|
|
164
|
+
|
|
165
|
+
This project is licensed under the terms of the [`MIT license`](https://github.com/adriamontoto/clock-pattern/blob/master/LICENSE.md).
|
|
166
|
+
|
|
167
|
+
<p align="right">
|
|
168
|
+
<a href="#readme-top">🔼 Back to top</a>
|
|
169
|
+
</p>
|
|
@@ -23,7 +23,7 @@ class SystemClock(Clock):
|
|
|
23
23
|
|
|
24
24
|
Example:
|
|
25
25
|
```python
|
|
26
|
-
from clock_pattern
|
|
26
|
+
from clock_pattern import SystemClock
|
|
27
27
|
|
|
28
28
|
clock = SystemClock()
|
|
29
29
|
print(clock.now())
|
|
@@ -48,7 +48,7 @@ class SystemClock(Clock):
|
|
|
48
48
|
|
|
49
49
|
Example:
|
|
50
50
|
```python
|
|
51
|
-
from clock_pattern
|
|
51
|
+
from clock_pattern import SystemClock
|
|
52
52
|
|
|
53
53
|
clock = SystemClock()
|
|
54
54
|
print(clock.now())
|
|
@@ -72,7 +72,7 @@ class SystemClock(Clock):
|
|
|
72
72
|
|
|
73
73
|
Example:
|
|
74
74
|
```python
|
|
75
|
-
from clock_pattern
|
|
75
|
+
from clock_pattern import SystemClock
|
|
76
76
|
|
|
77
77
|
clock = SystemClock()
|
|
78
78
|
print(clock.now())
|
|
@@ -91,7 +91,7 @@ class SystemClock(Clock):
|
|
|
91
91
|
|
|
92
92
|
Example:
|
|
93
93
|
```python
|
|
94
|
-
from clock_pattern
|
|
94
|
+
from clock_pattern import SystemClock
|
|
95
95
|
|
|
96
96
|
clock = SystemClock()
|
|
97
97
|
print(clock.now())
|
|
@@ -110,7 +110,7 @@ class SystemClock(Clock):
|
|
|
110
110
|
|
|
111
111
|
Example:
|
|
112
112
|
```python
|
|
113
|
-
from clock_pattern
|
|
113
|
+
from clock_pattern import SystemClock
|
|
114
114
|
|
|
115
115
|
clock = SystemClock()
|
|
116
116
|
print(clock.timezone)
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MockClock module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from sys import version_info
|
|
6
|
+
|
|
7
|
+
if version_info >= (3, 12):
|
|
8
|
+
from typing import override # pragma: no cover
|
|
9
|
+
else:
|
|
10
|
+
from typing_extensions import override # pragma: no cover
|
|
11
|
+
|
|
12
|
+
from datetime import UTC, date, datetime
|
|
13
|
+
from unittest.mock import Mock
|
|
14
|
+
|
|
15
|
+
from value_object_pattern.usables import NotNoneValueObject
|
|
16
|
+
from value_object_pattern.usables.dates import DateValueObject, DatetimeValueObject
|
|
17
|
+
|
|
18
|
+
from clock_pattern.models.clock import Clock
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MockClock(Clock):
|
|
22
|
+
"""
|
|
23
|
+
MockModel is responsible of mocking Clock class implementation for testing purposes.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
```python
|
|
27
|
+
from datetime import datetime
|
|
28
|
+
|
|
29
|
+
from clock_pattern.clocks.testing import MockClock
|
|
30
|
+
|
|
31
|
+
return_datetime = datetime(year=1999, month=1, day=1)
|
|
32
|
+
clock = MockClock()
|
|
33
|
+
|
|
34
|
+
clock.prepare_now_method_return_value(now=return_datetime)
|
|
35
|
+
print(clock.now())
|
|
36
|
+
# >>> 1999-01-01 00:00:00+00:00
|
|
37
|
+
|
|
38
|
+
clock.assert_now_method_was_called_once()
|
|
39
|
+
```
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
_now_mock: Mock
|
|
43
|
+
_today_mock: Mock
|
|
44
|
+
_now_datetime: datetime | None
|
|
45
|
+
_today_date: date | None
|
|
46
|
+
|
|
47
|
+
def __init__(self) -> None:
|
|
48
|
+
"""
|
|
49
|
+
MockClock constructor.
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
```python
|
|
53
|
+
from datetime import datetime
|
|
54
|
+
|
|
55
|
+
from clock_pattern.clocks.testing import MockClock
|
|
56
|
+
|
|
57
|
+
return_datetime = datetime(year=1999, month=1, day=1)
|
|
58
|
+
clock = MockClock()
|
|
59
|
+
|
|
60
|
+
clock.prepare_now_method_return_value(now=return_datetime)
|
|
61
|
+
print(clock.now())
|
|
62
|
+
# >>> 1999-01-01 00:00:00+00:00
|
|
63
|
+
|
|
64
|
+
clock.assert_now_method_was_called_once()
|
|
65
|
+
```
|
|
66
|
+
"""
|
|
67
|
+
self._now_mock = Mock()
|
|
68
|
+
self._today_mock = Mock()
|
|
69
|
+
self._now_datetime = None
|
|
70
|
+
self._today_date = None
|
|
71
|
+
|
|
72
|
+
@override
|
|
73
|
+
def now(self) -> datetime:
|
|
74
|
+
"""
|
|
75
|
+
Retrieve the current datetime (now). Use `MockClock.prepare_now_method_return_value` to prepare the return value
|
|
76
|
+
for this method.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
TypeError: If `now` method return value is not configured.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
datetime: The current datetime.
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
```python
|
|
86
|
+
from datetime import datetime
|
|
87
|
+
|
|
88
|
+
from clock_pattern.clocks.testing import MockClock
|
|
89
|
+
|
|
90
|
+
return_datetime = datetime(year=1999, month=1, day=1)
|
|
91
|
+
clock = MockClock()
|
|
92
|
+
|
|
93
|
+
clock.prepare_now_method_return_value(now=return_datetime)
|
|
94
|
+
print(clock.now())
|
|
95
|
+
# >>> 1999-01-01 00:00:00+00:00
|
|
96
|
+
|
|
97
|
+
clock.assert_now_method_was_called_once()
|
|
98
|
+
```
|
|
99
|
+
"""
|
|
100
|
+
NotNoneValueObject(value=self._now_datetime, title='MockClock', parameter='now')
|
|
101
|
+
|
|
102
|
+
self._now_mock()
|
|
103
|
+
|
|
104
|
+
return self._now_datetime # type: ignore[return-value]
|
|
105
|
+
|
|
106
|
+
def prepare_now_method_return_value(self, *, now: datetime) -> None:
|
|
107
|
+
"""
|
|
108
|
+
Prepare now method to return the provided datetime `now`. If the provided datetime `now` has not timezone UTC
|
|
109
|
+
will be set.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
now (datetime): Datetime to return.
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
TypeError: If `now` is not of type datetime.
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
```python
|
|
119
|
+
from datetime import datetime
|
|
120
|
+
|
|
121
|
+
from clock_pattern.clocks.testing import MockClock
|
|
122
|
+
|
|
123
|
+
return_datetime = datetime(year=1999, month=1, day=1)
|
|
124
|
+
clock = MockClock()
|
|
125
|
+
|
|
126
|
+
clock.prepare_now_method_return_value(now=return_datetime)
|
|
127
|
+
print(clock.now())
|
|
128
|
+
# >>> 1999-01-01 00:00:00+00:00
|
|
129
|
+
|
|
130
|
+
clock.assert_now_method_was_called_once()
|
|
131
|
+
```
|
|
132
|
+
"""
|
|
133
|
+
DatetimeValueObject(value=now, title='MockClock', parameter='now')
|
|
134
|
+
|
|
135
|
+
if now.tzinfo is None:
|
|
136
|
+
now = now.replace(tzinfo=UTC)
|
|
137
|
+
|
|
138
|
+
self._now_datetime = now
|
|
139
|
+
|
|
140
|
+
def assert_now_method_was_called_once(self) -> None:
|
|
141
|
+
"""
|
|
142
|
+
Assert that the now method was called once.
|
|
143
|
+
|
|
144
|
+
Example:
|
|
145
|
+
```python
|
|
146
|
+
from datetime import datetime
|
|
147
|
+
|
|
148
|
+
from clock_pattern.clocks.testing import MockClock
|
|
149
|
+
|
|
150
|
+
return_datetime = datetime(year=1999, month=1, day=1)
|
|
151
|
+
clock = MockClock()
|
|
152
|
+
|
|
153
|
+
clock.prepare_now_method_return_value(now=return_datetime)
|
|
154
|
+
print(clock.now())
|
|
155
|
+
# >>> 1999-01-01 00:00:00+00:00
|
|
156
|
+
|
|
157
|
+
clock.assert_now_method_was_called_once()
|
|
158
|
+
```
|
|
159
|
+
"""
|
|
160
|
+
self._now_mock.assert_called_once_with()
|
|
161
|
+
|
|
162
|
+
def assert_now_method_was_not_called(self) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Assert that the now method was not called.
|
|
165
|
+
|
|
166
|
+
Example:
|
|
167
|
+
```python
|
|
168
|
+
from datetime import date
|
|
169
|
+
|
|
170
|
+
from clock_pattern.clocks.testing import MockClock
|
|
171
|
+
|
|
172
|
+
return_date = date(year=1999, month=1, day=1)
|
|
173
|
+
clock = MockClock()
|
|
174
|
+
|
|
175
|
+
clock.prepare_today_method_return_value(today=return_date)
|
|
176
|
+
print(clock.today())
|
|
177
|
+
# >>> 2025-06-16
|
|
178
|
+
|
|
179
|
+
clock.assert_now_method_was_not_called()
|
|
180
|
+
```
|
|
181
|
+
"""
|
|
182
|
+
self._now_mock.assert_not_called()
|
|
183
|
+
|
|
184
|
+
@override
|
|
185
|
+
def today(self) -> date:
|
|
186
|
+
"""
|
|
187
|
+
Retrieve the current date (today). Use `MockClock.prepare_today_method_return_value` to prepare the return value
|
|
188
|
+
for this method.
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
ValueError: If `today` method return value is not configured.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
date: The current date.
|
|
195
|
+
|
|
196
|
+
Example:
|
|
197
|
+
```python
|
|
198
|
+
from datetime import date
|
|
199
|
+
|
|
200
|
+
from clock_pattern.clocks.testing import MockClock
|
|
201
|
+
|
|
202
|
+
return_date = date(year=1999, month=1, day=1)
|
|
203
|
+
clock = MockClock()
|
|
204
|
+
|
|
205
|
+
clock.prepare_today_method_return_value(today=return_date)
|
|
206
|
+
print(clock.today())
|
|
207
|
+
# >>> 2025-06-16
|
|
208
|
+
|
|
209
|
+
clock.assert_today_method_was_called_once()
|
|
210
|
+
```
|
|
211
|
+
"""
|
|
212
|
+
NotNoneValueObject(value=self._today_date, title='MockClock', parameter='today')
|
|
213
|
+
|
|
214
|
+
self._today_mock()
|
|
215
|
+
|
|
216
|
+
return self._today_date # type: ignore[return-value]
|
|
217
|
+
|
|
218
|
+
def prepare_today_method_return_value(self, *, today: date) -> None:
|
|
219
|
+
"""
|
|
220
|
+
Prepare today method to return the provided date `today`.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
today (date): Date to return.
|
|
224
|
+
|
|
225
|
+
Raises:
|
|
226
|
+
TypeError: If `today` is not of type date.
|
|
227
|
+
|
|
228
|
+
Example:
|
|
229
|
+
```python
|
|
230
|
+
from datetime import date
|
|
231
|
+
|
|
232
|
+
from clock_pattern.clocks.testing import MockClock
|
|
233
|
+
|
|
234
|
+
return_date = date(year=1999, month=1, day=1)
|
|
235
|
+
clock = MockClock()
|
|
236
|
+
|
|
237
|
+
clock.prepare_today_method_return_value(today=return_date)
|
|
238
|
+
print(clock.today())
|
|
239
|
+
# >>> 2025-06-16
|
|
240
|
+
|
|
241
|
+
clock.assert_today_method_was_called_once()
|
|
242
|
+
```
|
|
243
|
+
"""
|
|
244
|
+
DateValueObject(value=today, title='MockClock', parameter='today')
|
|
245
|
+
self._today_date = today
|
|
246
|
+
|
|
247
|
+
def assert_today_method_was_called_once(self) -> None:
|
|
248
|
+
"""
|
|
249
|
+
Assert that the today method was called once.
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
```python
|
|
253
|
+
from datetime import date
|
|
254
|
+
|
|
255
|
+
from clock_pattern.clocks.testing import MockClock
|
|
256
|
+
|
|
257
|
+
return_date = date(year=1999, month=1, day=1)
|
|
258
|
+
clock = MockClock()
|
|
259
|
+
|
|
260
|
+
clock.prepare_today_method_return_value(today=return_date)
|
|
261
|
+
print(clock.today())
|
|
262
|
+
# >>> 2025-06-16
|
|
263
|
+
|
|
264
|
+
clock.assert_today_method_was_called_once()
|
|
265
|
+
```
|
|
266
|
+
"""
|
|
267
|
+
self._today_mock.assert_called_once_with()
|
|
268
|
+
|
|
269
|
+
def assert_today_method_was_not_called(self) -> None:
|
|
270
|
+
"""
|
|
271
|
+
Assert that the today method was not called.
|
|
272
|
+
|
|
273
|
+
Example:
|
|
274
|
+
```python
|
|
275
|
+
from datetime import datetime
|
|
276
|
+
|
|
277
|
+
from clock_pattern.clocks.testing import MockClock
|
|
278
|
+
|
|
279
|
+
return_datetime = datetime(year=1999, month=1, day=1)
|
|
280
|
+
clock = MockClock()
|
|
281
|
+
|
|
282
|
+
clock.prepare_now_method_return_value(now=return_datetime)
|
|
283
|
+
print(clock.now())
|
|
284
|
+
# >>> 1999-01-01 00:00:00+00:00
|
|
285
|
+
|
|
286
|
+
clock.assert_today_method_was_not_called()
|
|
287
|
+
```
|
|
288
|
+
"""
|
|
289
|
+
self._today_mock.assert_not_called()
|
|
@@ -13,7 +13,7 @@ class UtcClock(SystemClock):
|
|
|
13
13
|
|
|
14
14
|
Example:
|
|
15
15
|
```python
|
|
16
|
-
from clock_pattern
|
|
16
|
+
from clock_pattern import UtcClock
|
|
17
17
|
|
|
18
18
|
clock = UtcClock()
|
|
19
19
|
print(clock.now())
|
|
@@ -27,7 +27,7 @@ class UtcClock(SystemClock):
|
|
|
27
27
|
|
|
28
28
|
Example:
|
|
29
29
|
```python
|
|
30
|
-
from clock_pattern
|
|
30
|
+
from clock_pattern import UtcClock
|
|
31
31
|
|
|
32
32
|
clock = UtcClock()
|
|
33
33
|
print(clock.now())
|
|
@@ -14,7 +14,7 @@ class Clock(ABC):
|
|
|
14
14
|
|
|
15
15
|
Example:
|
|
16
16
|
```python
|
|
17
|
-
from clock_pattern
|
|
17
|
+
from clock_pattern import SystemClock
|
|
18
18
|
|
|
19
19
|
clock = SystemClock()
|
|
20
20
|
print(clock.now())
|
|
@@ -32,7 +32,7 @@ class Clock(ABC):
|
|
|
32
32
|
|
|
33
33
|
Example:
|
|
34
34
|
```python
|
|
35
|
-
from clock_pattern
|
|
35
|
+
from clock_pattern import SystemClock
|
|
36
36
|
|
|
37
37
|
clock = SystemClock()
|
|
38
38
|
print(clock.now())
|
|
@@ -50,7 +50,7 @@ class Clock(ABC):
|
|
|
50
50
|
|
|
51
51
|
Example:
|
|
52
52
|
```python
|
|
53
|
-
from clock_pattern
|
|
53
|
+
from clock_pattern import SystemClock
|
|
54
54
|
|
|
55
55
|
clock = SystemClock()
|
|
56
56
|
print(clock.today())
|
clock_pattern-0.3.0/PKG-INFO
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: clock-pattern
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: The Clock Pattern is a Python package that turns time into an injectable dependency.
|
|
5
|
-
Project-URL: Homepage, https://github.com/adriamontoto/clock-pattern
|
|
6
|
-
Project-URL: Repository, https://github.com/adriamontoto/clock-pattern
|
|
7
|
-
Project-URL: Issues, https://github.com/adriamontoto/clock-pattern/issues
|
|
8
|
-
Author: Adria Montoto
|
|
9
|
-
License-Expression: MIT
|
|
10
|
-
License-File: LICENSE.md
|
|
11
|
-
Keywords: clock,dependency-injection,development,domain-driven-design,pattern,python,utilities
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
-
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python
|
|
16
|
-
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
-
Classifier: Typing :: Typed
|
|
21
|
-
Requires-Python: >=3.11
|
|
22
|
-
Requires-Dist: value-object-pattern>=0.5.0
|
|
23
|
-
Description-Content-Type: text/markdown
|
|
24
|
-
|
|
25
|
-
<a name="readme-top"></a>
|
|
26
|
-
|
|
27
|
-
# 🕰️ Clock Pattern
|
|
28
|
-
|
|
29
|
-
<p align="center">
|
|
30
|
-
<a href="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml?event=push&branch=master" target="_blank">
|
|
31
|
-
<img src="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml/badge.svg?event=push&branch=master" alt="CI Pipeline">
|
|
32
|
-
</a>
|
|
33
|
-
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/adriamontoto/clock-pattern" target="_blank">
|
|
34
|
-
<img src="https://coverage-badge.samuelcolvin.workers.dev/adriamontoto/clock-pattern.svg" alt="Coverage Pipeline">
|
|
35
|
-
</a>
|
|
36
|
-
<a href="https://pypi.org/project/clock-pattern" target="_blank">
|
|
37
|
-
<img src="https://img.shields.io/pypi/v/clock-pattern?color=%2334D058&label=pypi%20package" alt="Package Version">
|
|
38
|
-
</a>
|
|
39
|
-
<a href="https://pypi.org/project/clock-pattern/" target="_blank">
|
|
40
|
-
<img src="https://img.shields.io/pypi/pyversions/clock-pattern.svg?color=%2334D058" alt="Supported Python Versions">
|
|
41
|
-
</a>
|
|
42
|
-
</p>
|
|
43
|
-
|
|
44
|
-
The **Clock Pattern** is a Python 🐍 package that turns time into an injectable dependency 🧩. By replacing ad-hoc datetime.now() calls with a swappable Clock interface 🕰️ you unlock deterministic tests 🧪, decouple business logic from the OS clock, and gain the freedom to swap in high-precision or logical clocks without touching domain code.
|
|
45
|
-
<br><br>
|
|
46
|
-
|
|
47
|
-
## Table of Contents
|
|
48
|
-
|
|
49
|
-
- [📥 Installation](#installation)
|
|
50
|
-
- [🤝 Contributing](#contributing)
|
|
51
|
-
- [🔑 License](#license)
|
|
52
|
-
|
|
53
|
-
<p align="right">
|
|
54
|
-
<a href="#readme-top">🔼 Back to top</a>
|
|
55
|
-
</p><br><br>
|
|
56
|
-
|
|
57
|
-
<a name="installation"></a>
|
|
58
|
-
|
|
59
|
-
## 📥 Installation
|
|
60
|
-
|
|
61
|
-
You can install **Clock Pattern** using `pip`:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
pip install clock-pattern
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
<p align="right">
|
|
68
|
-
<a href="#readme-top">🔼 Back to top</a>
|
|
69
|
-
</p><br><br>
|
|
70
|
-
|
|
71
|
-
<a name="contributing"></a>
|
|
72
|
-
|
|
73
|
-
## 🤝 Contributing
|
|
74
|
-
|
|
75
|
-
We love community help! Before you open an issue or pull request, please read:
|
|
76
|
-
|
|
77
|
-
- [`🤝 How to Contribute`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CONTRIBUTING.md)
|
|
78
|
-
- [`🧭 Code of Conduct`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CODE_OF_CONDUCT.md)
|
|
79
|
-
- [`🔐 Security Policy`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/SECURITY.md)
|
|
80
|
-
|
|
81
|
-
_Thank you for helping make **🕰️ Clock Pattern** package awesome! 🌟_
|
|
82
|
-
|
|
83
|
-
<p align="right">
|
|
84
|
-
<a href="#readme-top">🔼 Back to top</a>
|
|
85
|
-
</p><br><br>
|
|
86
|
-
|
|
87
|
-
<a name="license"></a>
|
|
88
|
-
|
|
89
|
-
## 🔑 License
|
|
90
|
-
|
|
91
|
-
This project is licensed under the terms of the [`MIT license`](https://github.com/adriamontoto/clock-pattern/blob/master/LICENSE.md).
|
|
92
|
-
|
|
93
|
-
<p align="right">
|
|
94
|
-
<a href="#readme-top">🔼 Back to top</a>
|
|
95
|
-
</p>
|
clock_pattern-0.3.0/README.md
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
<a name="readme-top"></a>
|
|
2
|
-
|
|
3
|
-
# 🕰️ Clock Pattern
|
|
4
|
-
|
|
5
|
-
<p align="center">
|
|
6
|
-
<a href="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml?event=push&branch=master" target="_blank">
|
|
7
|
-
<img src="https://github.com/adriamontoto/clock-pattern/actions/workflows/ci.yaml/badge.svg?event=push&branch=master" alt="CI Pipeline">
|
|
8
|
-
</a>
|
|
9
|
-
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/adriamontoto/clock-pattern" target="_blank">
|
|
10
|
-
<img src="https://coverage-badge.samuelcolvin.workers.dev/adriamontoto/clock-pattern.svg" alt="Coverage Pipeline">
|
|
11
|
-
</a>
|
|
12
|
-
<a href="https://pypi.org/project/clock-pattern" target="_blank">
|
|
13
|
-
<img src="https://img.shields.io/pypi/v/clock-pattern?color=%2334D058&label=pypi%20package" alt="Package Version">
|
|
14
|
-
</a>
|
|
15
|
-
<a href="https://pypi.org/project/clock-pattern/" target="_blank">
|
|
16
|
-
<img src="https://img.shields.io/pypi/pyversions/clock-pattern.svg?color=%2334D058" alt="Supported Python Versions">
|
|
17
|
-
</a>
|
|
18
|
-
</p>
|
|
19
|
-
|
|
20
|
-
The **Clock Pattern** is a Python 🐍 package that turns time into an injectable dependency 🧩. By replacing ad-hoc datetime.now() calls with a swappable Clock interface 🕰️ you unlock deterministic tests 🧪, decouple business logic from the OS clock, and gain the freedom to swap in high-precision or logical clocks without touching domain code.
|
|
21
|
-
<br><br>
|
|
22
|
-
|
|
23
|
-
## Table of Contents
|
|
24
|
-
|
|
25
|
-
- [📥 Installation](#installation)
|
|
26
|
-
- [🤝 Contributing](#contributing)
|
|
27
|
-
- [🔑 License](#license)
|
|
28
|
-
|
|
29
|
-
<p align="right">
|
|
30
|
-
<a href="#readme-top">🔼 Back to top</a>
|
|
31
|
-
</p><br><br>
|
|
32
|
-
|
|
33
|
-
<a name="installation"></a>
|
|
34
|
-
|
|
35
|
-
## 📥 Installation
|
|
36
|
-
|
|
37
|
-
You can install **Clock Pattern** using `pip`:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
pip install clock-pattern
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
<p align="right">
|
|
44
|
-
<a href="#readme-top">🔼 Back to top</a>
|
|
45
|
-
</p><br><br>
|
|
46
|
-
|
|
47
|
-
<a name="contributing"></a>
|
|
48
|
-
|
|
49
|
-
## 🤝 Contributing
|
|
50
|
-
|
|
51
|
-
We love community help! Before you open an issue or pull request, please read:
|
|
52
|
-
|
|
53
|
-
- [`🤝 How to Contribute`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CONTRIBUTING.md)
|
|
54
|
-
- [`🧭 Code of Conduct`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/CODE_OF_CONDUCT.md)
|
|
55
|
-
- [`🔐 Security Policy`](https://github.com/adriamontoto/clock-pattern/blob/master/.github/SECURITY.md)
|
|
56
|
-
|
|
57
|
-
_Thank you for helping make **🕰️ Clock Pattern** package awesome! 🌟_
|
|
58
|
-
|
|
59
|
-
<p align="right">
|
|
60
|
-
<a href="#readme-top">🔼 Back to top</a>
|
|
61
|
-
</p><br><br>
|
|
62
|
-
|
|
63
|
-
<a name="license"></a>
|
|
64
|
-
|
|
65
|
-
## 🔑 License
|
|
66
|
-
|
|
67
|
-
This project is licensed under the terms of the [`MIT license`](https://github.com/adriamontoto/clock-pattern/blob/master/LICENSE.md).
|
|
68
|
-
|
|
69
|
-
<p align="right">
|
|
70
|
-
<a href="#readme-top">🔼 Back to top</a>
|
|
71
|
-
</p>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.3.0'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|