Python library that leverages the __eq__ method to make unit tests more declarative and readable through flexible comparison classes.
—
Date and time comparison classes with support for approximate matching, range validation, timezone handling, and format parsing. These types enable flexible validation of temporal data including relative time comparisons and format-aware parsing.
Comprehensive datetime comparison with multiple constraint options including approximate matching, range bounds, timezone enforcement, and format parsing from strings or Unix timestamps.
class IsDatetime(DirtyEquals):
"""
Datetime comparison with configurable conditions.
Supports range checking, approximate matching, timezone validation,
and parsing from various string and numeric formats.
"""
def __init__(
self,
*,
approx: Optional[datetime] = None,
delta: Optional[Union[int, float, timedelta]] = None,
gt: Optional[datetime] = None,
lt: Optional[datetime] = None,
ge: Optional[datetime] = None,
le: Optional[datetime] = None,
unix_number: bool = False,
iso_string: bool = False,
format_string: Optional[str] = None,
enforce_tz: bool = False
):
"""
Initialize datetime comparison with constraints.
Args:
approx: Expected datetime for approximate comparison
delta: Tolerance for approximate comparison (seconds or timedelta)
gt: Value must be greater than this datetime
lt: Value must be less than this datetime
ge: Value must be greater than or equal to this datetime
le: Value must be less than or equal to this datetime
unix_number: If True, parse numeric values as Unix timestamps
iso_string: If True, parse strings as ISO format datetimes
format_string: Custom strptime format for parsing strings
enforce_tz: If True, require timezone information
"""
allowed_types: ClassVar[type] = datetime
def prepare(self) -> None:
"""Prepare constraints for comparison validation."""
def approx_equals(self, other: datetime, delta: timedelta) -> bool:
"""
Check if datetime is within delta of expected value.
Args:
other: Datetime to compare
delta: Maximum allowed difference
Returns:
bool: True if within tolerance
"""
def equals(self, other: Any) -> bool:
"""
Check if value matches datetime constraints.
Args:
other: Value to validate (datetime, string, or number)
Returns:
bool: True if value satisfies all conditions
"""from dirty_equals import IsDatetime
from datetime import datetime, timedelta
# Basic datetime matching
now = datetime.now()
assert now == IsDatetime
# Approximate matching - within 5 seconds
target_time = datetime(2023, 1, 1, 12, 0, 0)
close_time = datetime(2023, 1, 1, 12, 0, 3)
assert close_time == IsDatetime(approx=target_time, delta=5)
# Range constraints
past_date = datetime(2022, 1, 1)
future_date = datetime(2024, 1, 1)
test_date = datetime(2023, 6, 15)
assert test_date == IsDatetime(gt=past_date, lt=future_date)
assert test_date == IsDatetime(ge=past_date, le=future_date)
# Parse from Unix timestamp
import time
timestamp = time.time()
assert timestamp == IsDatetime(unix_number=True)
# Parse from ISO string
iso_string = "2023-01-01T12:00:00"
assert iso_string == IsDatetime(iso_string=True)
# Parse with custom format
date_string = "2023/01/01 12:00:00"
assert date_string == IsDatetime(format_string="%Y/%m/%d %H:%M:%S")
# Timezone enforcement
from datetime import timezone
utc_time = datetime.now(timezone.utc)
naive_time = datetime.now()
assert utc_time == IsDatetime(enforce_tz=True)
# assert naive_time == IsDatetime(enforce_tz=True) # Would fail
# Complex validation in data structures
api_response = {
'created_at': '2023-01-01T12:00:00Z',
'updated_at': datetime.now(),
'expires_at': time.time() + 3600 # 1 hour from now
}
assert api_response == {
'created_at': IsDatetime(iso_string=True),
'updated_at': IsDatetime(approx=datetime.now(), delta=30),
'expires_at': IsDatetime(unix_number=True, gt=datetime.now())
}Checks if a datetime is close to the current time with configurable tolerance. Useful for validating timestamps that should represent "now" within a reasonable margin.
class IsNow(DirtyEquals):
"""
Checks if datetime is close to current time.
Validates that a datetime value is within a specified tolerance
of the current moment, with support for parsing and timezone handling.
"""
def __init__(
self,
*,
delta: Union[int, float, timedelta] = 2,
unix_number: bool = False,
iso_string: bool = False,
format_string: Optional[str] = None,
enforce_tz: bool = False,
tz: Optional[timezone] = None
):
"""
Initialize "now" comparison.
Args:
delta: Maximum allowed difference from current time (default 2 seconds)
unix_number: If True, parse numeric values as Unix timestamps
iso_string: If True, parse strings as ISO format datetimes
format_string: Custom strptime format for parsing strings
enforce_tz: If True, require timezone information
tz: Specific timezone to use for "now" calculation
"""
def _get_now(self) -> datetime:
"""
Get current datetime for comparison.
Returns:
datetime: Current time in appropriate timezone
"""
def equals(self, other: Any) -> bool:
"""
Check if value is close to current time.
Args:
other: Value to check (datetime, string, or number)
Returns:
bool: True if within delta of current time
"""from dirty_equals import IsNow
from datetime import datetime, timedelta
import time
# Basic "now" checking with default 2-second tolerance
current_time = datetime.now()
assert current_time == IsNow
# Custom tolerance - within 10 seconds
slightly_past = datetime.now() - timedelta(seconds=5)
assert slightly_past == IsNow(delta=10)
# Parse timestamp as "now"
current_timestamp = time.time()
assert current_timestamp == IsNow(unix_number=True)
# Parse ISO string as "now"
import json
now_iso = datetime.now().isoformat()
assert now_iso == IsNow(iso_string=True)
# With timezone
from datetime import timezone
utc_now = datetime.now(timezone.utc)
assert utc_now == IsNow(tz=timezone.utc, delta=5)
# In API testing
user_registration = {
'username': 'john_doe',
'email': 'john@example.com',
'created_at': datetime.now(),
'last_login': time.time()
}
assert user_registration == {
'username': 'john_doe',
'email': 'john@example.com',
'created_at': IsNow(delta=30), # Created within last 30 seconds
'last_login': IsNow(unix_number=True, delta=60) # Logged in within last minute
}
# Database record validation
db_record = {
'id': 123,
'updated_timestamp': '2023-01-01T12:00:00.123Z',
'sync_time': datetime.now()
}
# Validate recent updates
assert db_record == {
'id': 123,
'updated_timestamp': IsNow(iso_string=True, delta=300), # Within 5 minutes
'sync_time': IsNow(delta=10) # Synced within 10 seconds
}Date comparison with support for range constraints, approximate matching, and parsing from string formats. Works specifically with date objects and date components of datetime objects.
class IsDate(DirtyEquals):
"""
Date comparison with configurable conditions.
Supports range checking, approximate matching, and parsing from
various string formats for date validation.
"""
def __init__(
self,
*,
approx: Optional[date] = None,
delta: Optional[Union[int, timedelta]] = None,
gt: Optional[date] = None,
lt: Optional[date] = None,
ge: Optional[date] = None,
le: Optional[date] = None,
iso_string: bool = False,
format_string: Optional[str] = None
):
"""
Initialize date comparison with constraints.
Args:
approx: Expected date for approximate comparison
delta: Tolerance for approximate comparison (days or timedelta)
gt: Value must be greater than this date
lt: Value must be less than this date
ge: Value must be greater than or equal to this date
le: Value must be less than or equal to this date
iso_string: If True, parse strings as ISO format dates
format_string: Custom strptime format for parsing strings
"""
allowed_types: ClassVar[type] = date
def prepare(self) -> None:
"""Prepare constraints for comparison validation."""
def equals(self, other: Any) -> bool:
"""
Check if value matches date constraints.
Args:
other: Value to validate (date, datetime, or string)
Returns:
bool: True if value satisfies all conditions
"""from dirty_equals import IsDate
from datetime import date, timedelta
# Basic date matching
today = date.today()
assert today == IsDate
# Approximate matching - within 2 days
target_date = date(2023, 1, 15)
close_date = date(2023, 1, 16)
assert close_date == IsDate(approx=target_date, delta=2)
# Range constraints
start_date = date(2023, 1, 1)
end_date = date(2023, 12, 31)
test_date = date(2023, 6, 15)
assert test_date == IsDate(gt=start_date, lt=end_date)
assert test_date == IsDate(ge=start_date, le=end_date)
# Parse from ISO string
date_string = "2023-01-15"
assert date_string == IsDate(iso_string=True)
# Parse with custom format
date_string = "01/15/2023"
assert date_string == IsDate(format_string="%m/%d/%Y")
# Extract date from datetime
from datetime import datetime
dt = datetime(2023, 1, 15, 14, 30, 0)
assert dt == IsDate(approx=date(2023, 1, 15))
# In data validation
event_data = {
'title': 'Conference',
'start_date': '2023-06-15',
'end_date': date(2023, 6, 17),
'registration_deadline': datetime(2023, 6, 1, 23, 59, 59)
}
assert event_data == {
'title': 'Conference',
'start_date': IsDate(iso_string=True, ge=date.today()),
'end_date': IsDate(gt=date(2023, 6, 15)), # After start date
'registration_deadline': IsDate(lt=date(2023, 6, 15)) # Before start
}Checks if a date represents today's date, with support for parsing from string formats. Useful for validating that dates represent the current day.
class IsToday(DirtyEquals):
"""
Checks if date is today.
Validates that a date value represents the current date,
with support for string parsing.
"""
def __init__(
self,
*,
iso_string: bool = False,
format_string: Optional[str] = None
):
"""
Initialize today comparison.
Args:
iso_string: If True, parse strings as ISO format dates
format_string: Custom strptime format for parsing strings
"""
def equals(self, other: Any) -> bool:
"""
Check if value represents today's date.
Args:
other: Value to check (date, datetime, or string)
Returns:
bool: True if value represents today
"""from dirty_equals import IsToday
from datetime import date, datetime
# Basic today checking
today = date.today()
assert today == IsToday
# Works with datetime objects (uses date part)
now = datetime.now()
assert now == IsToday
# Parse from ISO string
today_string = date.today().isoformat()
assert today_string == IsToday(iso_string=True)
# Parse with custom format
today_formatted = date.today().strftime("%m/%d/%Y")
assert today_formatted == IsToday(format_string="%m/%d/%Y")
# In logging/audit validation
log_entry = {
'user_id': 123,
'action': 'login',
'timestamp': datetime.now(),
'date': date.today().isoformat()
}
assert log_entry == {
'user_id': 123,
'action': 'login',
'timestamp': IsToday, # Timestamp should be today
'date': IsToday(iso_string=True) # Date field should be today
}
# Daily report validation
daily_stats = {
'report_date': '2023-01-15',
'generated_at': datetime.now(),
'stats': {'users': 100, 'orders': 25}
}
# Validate this is today's report
assert daily_stats == {
'report_date': IsToday(iso_string=True),
'generated_at': IsToday,
'stats': {'users': 100, 'orders': 25}
}from typing import Any, ClassVar, Optional, Union
from datetime import datetime, date, timedelta, timezone
# All datetime types inherit from DirtyEquals
# and work with Python's standard datetime/date typesInstall with Tessl CLI
npx tessl i tessl/pypi-dirty-equals