🕰️ Clock Pattern
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.
Table of Contents
🔼 Back to top
📥 Installation
You can install Clock Pattern using pip
:
pip install clock-pattern
🔼 Back to top
💻 Utilization
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.
Here is a basic example of how to use the SystemClock
clock:
from datetime import timezone
from clock_pattern import SystemClock
clock = SystemClock(timezone=timezone.utc)
print(clock.now())
🔼 Back to top
📚 Available Clocks
The package offers several clock implementations to suit different needs:
clock_pattern.SystemClock
: The standard clock implementation that returns the system's current datetime/date with the provided timezone.
clock_pattern.UtcClock
: A clock implementation that returns the system's current datetime/date in UTC. Ideal for production environments.
clock_pattern.clocks.testing.FixedClock
: 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.
clock_pattern.clocks.testing.MockClock
: 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.
🔼 Back to top
🎄 Real-Life Case: Christmas Detector Service
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
and MockClock
, 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.
from datetime import date
from clock_pattern import Clock, UtcClock
from clock_pattern.clocks.testing import MockClock
class ChristmasDetectorService:
def __init__(self, clock: Clock) -> None:
self.clock = clock
self.christmas_start = date(year=2024, month=12, day=24)
self.christmas_end = date(year=2025, month=1, day=6)
def is_christmas(self) -> bool:
return self.christmas_start <= self.clock.today() <= self.christmas_end
clock = UtcClock()
christmas_detector_service = ChristmasDetectorService(clock=clock)
print(christmas_detector_service.is_christmas())
def test_christmas_detector_is_christmas() -> None:
clock = MockClock()
christmas_detector_service = ChristmasDetectorService(clock=clock)
today = date(year=2024, month=12, day=25)
clock.prepare_today_method_return_value(today=today)
assert christmas_detector_service.is_christmas() is True
clock.assert_today_method_was_called_once()
def test_christmas_detector_is_not_christmas() -> None:
clock = MockClock()
christmas_detector_service = ChristmasDetectorService(clock=clock)
today = date(year=2025, month=1, day=7)
clock.prepare_today_method_return_value(today=today)
assert christmas_detector_service.is_christmas() is False
clock.assert_today_method_was_called_once()
🔼 Back to top
🤝 Contributing
We love community help! Before you open an issue or pull request, please read:
Thank you for helping make 🕰️ Clock Pattern package awesome! 🌟
🔼 Back to top
🔑 License
This project is licensed under the terms of the MIT license
.
🔼 Back to top