Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove assertion to ensure FiniteDateRange difference #167

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 113 additions & 1 deletion tests/test_ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ def test_respects_other_range_boundaries(self, other):

def test_doesnt_extend_union(self):
"""
A union of ranges should be longer than the sum of it's parts.
A union of ranges should not be longer than the sum of it's parts.
"""
# This is a weird test to include, it is added because this feels like an
# obvious risk with the implementation I have used.
Expand All @@ -886,6 +886,118 @@ def test_finite_range(self):

assert 3 in subject

class TestDifference:
def test_paco(self):
r1 = ranges.FiniteDateRange(
start=datetime.date(2024, 10, 1),
end=datetime.date(2024, 10, 30),
)
r2 = ranges.FiniteDateRange(
start=datetime.date(2024, 10, 5),
end=datetime.date(2024, 10, 15),
)
r3 = ranges.FiniteDateRange(
start=datetime.date(2024, 12, 1),
end=datetime.date(2024, 12, 30),
)
f1 = ranges.FiniteRangeSet([r1])
f2 = ranges.FiniteRangeSet([r2])
f3 = ranges.FiniteRangeSet([r3])
r1.difference(r2)
r1.difference(r3)

f1-f2



def test_range_sets_overlap(self):
range_set = ranges.FiniteRangeSet(
[
ranges.FiniteDateRange(
start=datetime.date(2024, 10, 1),
end=datetime.date(2024, 10, 31),
)
]
)
other = ranges.FiniteRangeSet(
[
ranges.FiniteDateRange(
start=datetime.date(2024, 10, 1),
end=datetime.date(2024, 10, 15),
)
]
)
difference = range_set.difference(other)

assert difference == ranges.FiniteRangeSet(
[
ranges.FiniteDateRange(
start=datetime.date(2024, 10, 15),
end=datetime.date(2024, 10, 31),
)
]
)

def test_range_sets_overlap_multiple_ranges(self):
range_set = ranges.FiniteRangeSet(
[
ranges.FiniteDateRange(
start=datetime.date(2024, 1, 1),
end=datetime.date(2024, 2, 28),
),
ranges.FiniteDateRange(
start=datetime.date(2024, 5, 1),
end=datetime.date(2024, 6, 30),
),
]
)
other = ranges.FiniteRangeSet(
[
ranges.FiniteDateRange(
start=datetime.date(2024, 1, 1),
end=datetime.date(2024, 2, 15),
),
ranges.FiniteDateRange(
start=datetime.date(2024, 5, 15),
end=datetime.date(2024, 6, 30),
)
]
)
difference = range_set.difference(other)

assert difference == ranges.FiniteRangeSet(
[
ranges.FiniteDateRange(
start=datetime.date(2024, 2, 15),
end=datetime.date(2024, 2, 28),
),
ranges.FiniteDateRange(
start=datetime.date(2024, 5,1),
end=datetime.date(2024, 5, 15),
),
]
)

def test_difference_does_not_overlap(self):
range_set = ranges.FiniteRangeSet(
[
ranges.FiniteDateRange(
start=datetime.date(2024, 1, 1),
end=datetime.date(2024, 1, 31),
)
]
)
other = ranges.FiniteRangeSet(
[
ranges.FiniteDateRange(
start=datetime.date(2024, 3, 1),
end=datetime.date(2024, 3, 31),
)
]
)
difference = range_set.difference(other)
assert difference == range_set


class TestAsFiniteDatetimePeriods:
def test_converts(self):
Expand Down
42 changes: 41 additions & 1 deletion xocto/ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -876,9 +876,49 @@ def intersection(self, other: Range[datetime.date]) -> Optional["FiniteDateRange
if base_intersection is None:
return None

assert base_intersection.boundaries == RangeBoundaries.INCLUSIVE_INCLUSIVE
return FiniteDateRange(base_intersection.start, base_intersection.end)

def difference(self, other: Range[datetime.date]) -> Optional["FiniteDateRange"]:
"""
Difference between two FiniteDateRanges should produce a FiniteDateRange.
"""
if self.is_disjoint(other):
return self

boundaries = RangeBoundaries.INCLUSIVE_INCLUSIVE

if (self.start is None and other.start is not None) or (
self.start is not None
and other.start is not None
and not other._is_inside_left_bound(self.start)
and self._is_inside_left_bound(other.start)
):
lower_part: Optional["Range[T]"] = Range(
self.start, other.start, boundaries=boundaries
)
else:
lower_part = None

if (self.end is None and other.end is not None) or (
self.end is not None
and other.end is not None
and not other._is_inside_right_bound(self.end)
and self._is_inside_right_bound(other.end)
):
upper_part: Optional["Range[T]"] = Range(
other.end, self.end, boundaries=boundaries
)
else:
upper_part = None

if lower_part is None and upper_part is None:
return None
elif lower_part is not None and upper_part is not None:
return RangeSet([lower_part, upper_part])
else:
return lower_part or upper_part


def union(self, other: Range[datetime.date]) -> Optional["FiniteDateRange"]:
"""
Unions between two FiniteDateRanges should produce a FiniteDateRange.
Expand Down