There was some code, it looked a bit like this:
Django recommends that you use, for example, django.utils.timezone.now
to ensure you always get “the right now” (i.e. timezone-aware).
So you might, as with the code example above,
extrapolate that timezone.datetime(2015, 1, 1)
will give you a timezone-aware “1st of January 2015” datetime
object.
This is not what happens.
You get a naïve datetime
object.
Why?
Hint: django.utils.timezone
doesn’t provide datetime
as part of its API.
So how does that code work, I hear you ask?
Line 9 of django/utils/timezone.py
:
That’s it.
django.utils.timezone.datetime
is effectively just another binding for the vanilla datetime.datetime
:
This is useful behaviour if you’re looking to move your code around while providing compatibility support for old imports.
This is not so useful behaviour when you suddenly find that, surprise, that thing you thought was a library feature turns out to be the stdlib in disguise.
Does this fall foul of “explicit is better than implicit”? It certainly gets me on the Principle of Least Astonishment; I understand why it happens, but it’s still surprising from a user’s perspective!
Incidentally, we found this when
we added warnings.simplefilter("error")
to our tests so that any generated warnings would cause test failure.
You probably want to do that too.