pytest icon indicating copy to clipboard operation
pytest copied to clipboard

datetime and timedelta suport for approx

Open RonnyPfannschmidt opened this issue 4 years ago • 10 comments

this is to follow up after a initial proposal by @brianmaissy in #4760 and #4736

key issues to decide on/highlight

  • [ ] new internal helper classes for date times and time deltas
  • [ ] meaning of relative for time-deltas
  • [ ] decision on whether timestamps can have a meaningful rel at all ( i currently lean on no)
  • [ ] documentation of the explicit requirements for declaring approximate date-times in nested structures (no implication as we don't have sane defaults for abs/rel)

RonnyPfannschmidt avatar Mar 04 '21 09:03 RonnyPfannschmidt

FWIW, this is what I'm currently using:

class approx_datetime(ApproxBase):
    """
    Perform approximate comparisons where the expected value is a datetime or timedelta.
    """

    def __init__(self, expected, abs: timedelta = timedelta(seconds=10)):
        if abs < timedelta(0):
            raise ValueError(f"absolute tolerance can't be negative: {abs}")
        super().__init__(expected, abs=abs)

    def __repr__(self):
        return f"approx_datetime({self.expected!r} \u00b1 {self.abs!r})"

    def __eq__(self, actual):
        return abs(self.expected - actual) <= self.abs

brianmaissy avatar Mar 04 '21 11:03 brianmaissy

Thanks for the reference, thats a good start point

RonnyPfannschmidt avatar Mar 04 '21 11:03 RonnyPfannschmidt

Would love to see this feature added!

selting avatar Mar 26 '21 16:03 selting

Is there any way to get the time that the current test was started from pytest? Most of the time when I'm doing these approx date comparisons, it's when the result of a test might be out by the length of time that something in the test took to run. If you could say assert abs(expected - actual) <= time_this_test_has_been_running that would catch most of my use cases without having to concoct a sensible default tolerance... :woman_shrugging:

Came to me as I was bumbling around the task myself, so thought I would capture here as part of the discussion. Great library :raised_hands:

bentilley avatar May 11 '21 12:05 bentilley

@bentilley one way to do that would be to create a function-scoped fixture which returns the current time. The fixture will be initialized with the current time immediately before each test runs:

@pytest.fixture
def test_start_time():
    return datetime.now()


def test_my_stuff(test_start_time):
    ....

brianmaissy avatar May 11 '21 13:05 brianmaissy

@brianmaissy That is a great shout 🙏 thank you

bentilley avatar May 11 '21 13:05 bentilley

Supporting approx for datetime and timedelta sounds very interesting. Any idea why it is not already merged? Is there technical issues?

Oups, i though it was a PR, not an issue.

vallsv avatar Jun 21 '21 11:06 vallsv

BTW, i don't know if it is useful, but this can be reduced as float comparison:

epsilon = datetime.timedelta(seconds=2)
now = datetime.datetime.now()
assert mydate.timestamp() == pytest.approx(now.timestamp(), abs=epsilon.total_seconds())

vallsv avatar Jun 21 '21 11:06 vallsv

Just FYI, a related helper I've been using:

import time, pytest

def approx_now(abs=10):
    """Pytest based checker for whether a unix epoch/timestamp is approximately 'now' (within some tolerance)."""
    return pytest.approx(time.time(), abs=abs)

def test_something():
    # ....
    assert metadata == {"status": "running", "timestamp": approx_now()}

soxofaan avatar Jan 19 '22 15:01 soxofaan

This is still a very much needed feature, is there any news on this ?

Seluj78 avatar Dec 29 '23 21:12 Seluj78