-
-
Save bukzor/cf5c774729280a22b5e016cd65d6f057 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
from __future__ import absolute_import | |
from __future__ import unicode_literals | |
from datetime import datetime | |
from datetime import timedelta | |
import pytz | |
import tzlocal | |
from hypothesis import assume | |
from hypothesis import given | |
from hypothesis import note | |
from hypothesis import strategies as st | |
MAX_DATETIME = pytz.utc.localize(datetime.max) | |
MIN_DATETIME = pytz.utc.localize(datetime.min) | |
MAX_TIMEDELTA = datetime.max - datetime.min | |
ZERO_TIMEDELTA = datetime.min - datetime.min | |
@st.composite | |
def timezones(draw): | |
draw = draw(st.data()).draw | |
# hypothesis attempts to give examples using the first thing in the list | |
# so we put the examples we want first | |
local_timezone = tzlocal.get_localzone().zone | |
common_timezones = list(pytz.common_timezones) | |
common_timezones.remove(local_timezone) | |
common_timezones.remove('UTC') | |
common_timezones = tuple(['UTC', local_timezone] + common_timezones) | |
# ValueError: offset must be a timedelta strictly between | |
# -timedelta(hours=24) and timedelta(hours=24). | |
# also, the units for pytz.FixedOffset is minutes, apparently | |
max_delta = 24 * 60 - 1 | |
tz = draw(st.one_of( | |
# in order of simplest first | |
st.builds( | |
pytz.timezone, | |
st.sampled_from(common_timezones), | |
), | |
st.builds( | |
pytz.FixedOffset, | |
st.one_of( | |
st.integers(min_value=0, max_value=max_delta), | |
st.integers(min_value=-max_delta, max_value=-0), | |
), | |
), | |
)) | |
print(tz) | |
return tz | |
@given(timezones()) | |
def test_timezones(tz): | |
naivenow = datetime(2000, 4, 2, 9, 30) | |
utcnow = pytz.utc.localize(naivenow) | |
assert utcnow == naivenow.replace(tzinfo=pytz.utc) | |
note(utcnow) | |
note(tz.utcoffset(naivenow)) | |
t1 = utcnow.astimezone(tz) | |
note(t1) | |
assert t1.isoformat() | |
t2 = tz.normalize(utcnow) | |
assert t2.isoformat() | |
assert t1 == t2 | |
@st.composite | |
def timedeltas( | |
draw, | |
min_delta=ZERO_TIMEDELTA, | |
max_delta=MAX_TIMEDELTA, | |
): | |
assert min_delta <= max_delta, (min_delta, max_delta) | |
draw = draw(st.data()).draw | |
microseconds_max = ( | |
(max_delta.days - min_delta.days) * 24 * 60 * 60 * 1000**2 + | |
(max_delta.seconds - min_delta.seconds) * 1000**2 + | |
(max_delta.microseconds - min_delta.microseconds) | |
) | |
microseconds = draw(st.integers(0, microseconds_max)) | |
days, microseconds = divmod(microseconds, 24 * 60 * 60 * 1000**2) | |
seconds, microseconds = divmod(microseconds, 10**9) | |
delta = timedelta(days, seconds, microseconds) | |
return min_delta + delta | |
@given(timedeltas()) | |
def test_timedelta(t): | |
assert datetime.min + t | |
assert datetime.max - t | |
@st.composite | |
def naive_timestamps(draw, after=datetime.min, min_delta=ZERO_TIMEDELTA, max_delta=MAX_TIMEDELTA): | |
assert min_delta <= max_delta, (min_delta, max_delta) | |
draw = draw(st.data()).draw | |
max_delta = min(max_delta, datetime.max - after) | |
return after + draw(timedeltas(min_delta, max_delta)) | |
def assert_timestamp(data, strategy, after, max): | |
t1 = data.draw(strategy(after=after, max_delta=timedelta(500))) | |
min_delta = data.draw(timedeltas(ZERO_TIMEDELTA, max - t1)) | |
max_delta = data.draw(timedeltas(min_delta)) | |
assert min_delta <= max_delta | |
t2 = data.draw(strategy(t1, min_delta, max_delta)) | |
delta = t2 - t1 | |
assert ZERO_TIMEDELTA <= min_delta | |
assert min_delta <= delta | |
assert delta <= max_delta | |
assert max_delta <= MAX_TIMEDELTA | |
return t2 | |
@given(st.data()) | |
def test_naive_timestamps(data): | |
t2 = assert_timestamp(data, naive_timestamps, datetime(2000, 1, 1), datetime.max) | |
assert t2.tzinfo is None | |
@st.composite | |
def timestamps(draw, after=MIN_DATETIME, min_delta=ZERO_TIMEDELTA, max_delta=MAX_TIMEDELTA, tz=timezones()): | |
after = after.astimezone(pytz.utc).replace(tzinfo=None) | |
result = draw(naive_timestamps(after, min_delta, max_delta)) | |
result = pytz.utc.localize(result) | |
try: | |
result = result.astimezone(draw(tz)) | |
except OverflowError: | |
# in rare cases, our chosen time can't be represented in the timezone | |
assume(False) | |
return result | |
@given(st.data()) | |
def test_timestamps(data): | |
t2 = assert_timestamp(data, timestamps, datetime(2000, 1, 1, tzinfo=pytz.utc), MAX_DATETIME) | |
assert t2.tzinfo.normalize(t2) == t2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment