Skip to content

Commit 2bbdbc7

Browse files
authored
Merge pull request #94 from bbc/philipn-fix-contains-and-float
Fix TimeRange `__contains__` and add Timestamp `__float__`
2 parents 35b3695 + e57642e commit 2bbdbc7

3 files changed

Lines changed: 45 additions & 11 deletions

File tree

mediatimestamp/immutable/timerange.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -371,16 +371,13 @@ def finite(self) -> bool:
371371
return (self.start is not None and self.end is not None)
372372

373373
def __contains__(self, ts: object) -> bool:
374-
"""Returns true if the timestamp is within this range."""
375-
return ((isinstance(ts, SupportsMediaTimestamp)) and
376-
(self.start is None or mediatimestamp(ts) >= self.start) and
377-
(self.end is None or mediatimestamp(ts) <= self.end) and
378-
(not ((self.start is not None) and
379-
(mediatimestamp(ts) == self.start) and
380-
(self.inclusivity & TimeRange.INCLUDE_START == 0))) and
381-
(not ((self.end is not None) and
382-
(mediatimestamp(ts) == self.end) and
383-
(self.inclusivity & TimeRange.INCLUDE_END == 0))))
374+
"""Returns true if the timestamp or timerange is wholly within this range."""
375+
return ((
376+
isinstance(ts, (Timestamp, SupportsMediaTimestamp, int, float)) and
377+
self.contains_subrange(mediatimestamp(ts))
378+
) or (
379+
isinstance(ts, (TimeRange, SupportsMediaTimeRange)) and
380+
self.contains_subrange(ts)))
384381

385382
def __eq__(self, other: object) -> bool:
386383
if not isinstance(other, SupportsMediaTimeRange):

mediatimestamp/immutable/timestamp.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ def to_tai_sec_frac(self, fixed_size: bool = False) -> str:
429429
def to_float(self) -> float:
430430
""" Convert to a floating point number of seconds
431431
"""
432-
return self._value / Timestamp.MAX_NANOSEC
432+
return self.__float__()
433433

434434
def to_datetime(self) -> datetime:
435435
sec, nsec, sign, leap = self.to_unix()
@@ -665,6 +665,9 @@ def __floordiv__(self, anint: int) -> "Timestamp":
665665
ns = self._value // anint
666666
return Timestamp(ns=ns)
667667

668+
def __float__(self):
669+
return self._value / Timestamp.MAX_NANOSEC
670+
668671
def _get_fractional_seconds(self, fixed_size: bool = False) -> str:
669672
div = self.MAX_NANOSEC // 10
670673
rem = self.ns

tests/test_timerange.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,35 @@ def test_subrange__negative(self):
353353

354354
self._check_subrange(a, b, c, d)
355355

356+
def test_subrange__eternity_never(self):
357+
self.assertTrue(TimeRange.eternity().contains_subrange(TimeRange.eternity()))
358+
self.assertTrue(TimeRange.eternity().contains_subrange(TimeRange.from_str("[0:0]")))
359+
self.assertTrue(TimeRange.eternity().contains_subrange(TimeRange.from_str("[0:0_1:0)")))
360+
361+
self.assertTrue(TimeRange.eternity().contains_subrange(TimeRange.never()))
362+
363+
self.assertFalse(TimeRange.never().contains_subrange(TimeRange.eternity()))
364+
self.assertFalse(TimeRange.never().contains_subrange(TimeRange.never()))
365+
self.assertFalse(TimeRange.never().contains_subrange(TimeRange.from_str("[0:0]")))
366+
self.assertFalse(TimeRange.never().contains_subrange(TimeRange.from_str("[0:0_1:0)")))
367+
368+
def test_contains(self):
369+
self.assertNotIn(None, TimeRange.from_str("[0:0]"))
370+
self.assertNotIn(None, TimeRange.never())
371+
self.assertNotIn(None, TimeRange.eternity())
372+
373+
self.assertNotIn(1.0, TimeRange.from_str("[0:0]"))
374+
self.assertIn(1.0, TimeRange.from_str("[1:0]"))
375+
self.assertIn(1.0, TimeRange.from_str("[0:0_10:0)"))
376+
377+
self.assertNotIn(Timestamp.from_str("0:0"), TimeRange.from_str("[1:0_10:0)"))
378+
self.assertIn(Timestamp.from_str("1:0"), TimeRange.from_str("[1:0_10:0)"))
379+
380+
self.assertNotIn(TimeRange.from_str("[0:0_10:0)"), TimeRange.from_str("[0:0_5:0)"))
381+
self.assertIn(TimeRange.from_str("0:0_5:0"), TimeRange.from_str("[0:0_10:0)"))
382+
383+
# The subrange tests will cover the rest
384+
356385
def _check_intersection(self, a, b, c, d):
357386
self.assertEqual(TimeRange(a, c, TimeRange.INCLUDE_START).intersect_with(b), mediatimerange(b))
358387

@@ -460,6 +489,11 @@ def test_length_negative(self):
460489

461490
self._check_length(a, b, c)
462491

492+
def test_length_float(self):
493+
self.assertEqual(TimeRange.eternity().length, float("inf"))
494+
self.assertEqual(float(TimeRange.eternity().length), float("inf"))
495+
self.assertEqual(float(TimeRange.from_str("[0:0_1:0)").length), 1.0)
496+
463497
def test_repr(self):
464498
"""This tests that the repr function turns time ranges into `eval`-able strings."""
465499
test_trs = [

0 commit comments

Comments
 (0)