So, Django released version 4 awhile back and I finally noticed and set about updating apps, sites, CI pipelines, etc. One app relies heavily on testing modification times and I was using pytest.approx() to test that the times were close. Turns out what I thought was the right way to use pytest.approx() was indeed the wrong way and it wasn't until the updates started that I realized I was doing it completely wrong and it's all the internet's fault.

One of the pytest maintainers realized that the commonly available documentation on the web (i.e. that surfaced by the search engines and not the official pytest documentation) was advertising an incorrect usage of pytest.approx(). This is all explained in a pytest issue and in the 7.0.0rc1 changelog. The wrong usage (what I was using) was

# Don't do this!  This is wrong!
# Shame on you, internet!
assert pytest.approx(timezone.now(), post.published_at)

as explained in the issue, this evaluated to True, regardless of input. Oops. The correct usage, as explained in the documentation is

# An altogether more wholesome way of asserting, don't you think?
assert timezone.now() == pytest.approx(post.published_at)

which fails because those are datetimes and not floats, are not equal, and because this issue is still unresolved.

Now the test is implemented correctly and fails as opposed to passing silently and incorrectly. To get the test to pass correctly, with a correct implementation, I need to convert my datetimes into numbers, since as mentioned, pytest has not decided on how or if to implement approximate datetimes. Most modern datetime representations have some method of returning the seconds or milliseconds since the epoch either as a float or an integer. Since mine are python datetimes, I'll just use the timestamp() method which returns a float, which satisfies pytest.approx():

# Passes correctly for test and implementation.  Yay!
assert timezone.now().timestamp() == pytest.approx(post.published_at.timestamp())

If you are using some other datetime object, use the correct method to convert it to a number and then pytest.approx() should work for you too.

Let this be a lesson to us all, again, of the dangers of secondhand documentation on the internet. Take the time to go on to the project's documentation, and hopefully you won't have to write the initial documentation PR. Worst case scenario, just read the source since the buck stops there anyway. This just underscores the documentation problem we can have with projects. While pytest has good and complete documentation, many projects don't, and secondhand documentation emerges everywhere (except Medium), and then persists.

Keep those projects documented and go straight to the source. And don't be that person using the D3 version 3 example from n years ago that no longer works on version 7.