Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REF: Add more pytest idiom to test_holiday.py #25204

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
77 changes: 77 additions & 0 deletions pandas/tests/tseries/holiday/test_calendar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from datetime import datetime

import pytest

from pandas import DatetimeIndex
import pandas.util.testing as tm

from pandas.tseries.holiday import (
AbstractHolidayCalendar, Holiday, Timestamp, USFederalHolidayCalendar,
USThanksgivingDay, get_calendar)


@pytest.mark.parametrize("transform", [
lambda x: x,
lambda x: x.strftime("%Y-%m-%d"),
lambda x: Timestamp(x)
])
def test_calendar(transform):
start_date = datetime(2012, 1, 1)
end_date = datetime(2012, 12, 31)

calendar = USFederalHolidayCalendar()
holidays = calendar.holidays(transform(start_date), transform(end_date))

expected = [
datetime(2012, 1, 2),
datetime(2012, 1, 16),
datetime(2012, 2, 20),
datetime(2012, 5, 28),
datetime(2012, 7, 4),
datetime(2012, 9, 3),
datetime(2012, 10, 8),
datetime(2012, 11, 12),
datetime(2012, 11, 22),
datetime(2012, 12, 25)
]

assert list(holidays.to_pydatetime()) == expected


def test_calendar_caching():
# see gh-9552.

class TestCalendar(AbstractHolidayCalendar):
def __init__(self, name=None, rules=None):
super(TestCalendar, self).__init__(name=name, rules=rules)

jan1 = TestCalendar(rules=[Holiday("jan1", year=2015, month=1, day=1)])
jan2 = TestCalendar(rules=[Holiday("jan2", year=2015, month=1, day=2)])

# Getting holidays for Jan 1 should not alter results for Jan 2.
tm.assert_index_equal(jan1.holidays(), DatetimeIndex(["01-Jan-2015"]))
tm.assert_index_equal(jan2.holidays(), DatetimeIndex(["02-Jan-2015"]))


def test_calendar_observance_dates():
# see gh-11477
us_fed_cal = get_calendar("USFederalHolidayCalendar")
holidays0 = us_fed_cal.holidays(datetime(2015, 7, 3), datetime(
2015, 7, 3)) # <-- same start and end dates
holidays1 = us_fed_cal.holidays(datetime(2015, 7, 3), datetime(
2015, 7, 6)) # <-- different start and end dates
holidays2 = us_fed_cal.holidays(datetime(2015, 7, 3), datetime(
2015, 7, 3)) # <-- same start and end dates

# These should all produce the same result.
#
# In addition, calling with different start and end
# dates should not alter the output if we call the
# function again with the same start and end date.
tm.assert_index_equal(holidays0, holidays1)
tm.assert_index_equal(holidays0, holidays2)


def test_rule_from_name():
us_fed_cal = get_calendar("USFederalHolidayCalendar")
assert us_fed_cal.rule_from_name("Thanksgiving") == USThanksgivingDay
36 changes: 36 additions & 0 deletions pandas/tests/tseries/holiday/test_federal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from datetime import datetime

from pandas.tseries.holiday import (
AbstractHolidayCalendar, USMartinLutherKingJr, USMemorialDay)


def test_no_mlk_before_1986():
# see gh-10278
class MLKCalendar(AbstractHolidayCalendar):
rules = [USMartinLutherKingJr]

holidays = MLKCalendar().holidays(start="1984",
end="1988").to_pydatetime().tolist()

# Testing to make sure holiday is not incorrectly observed before 1986.
assert holidays == [datetime(1986, 1, 20, 0, 0),
datetime(1987, 1, 19, 0, 0)]


def test_memorial_day():
class MemorialDay(AbstractHolidayCalendar):
rules = [USMemorialDay]

holidays = MemorialDay().holidays(start="1971",
end="1980").to_pydatetime().tolist()

# Fixes 5/31 error and checked manually against Wikipedia.
assert holidays == [datetime(1971, 5, 31, 0, 0),
datetime(1972, 5, 29, 0, 0),
datetime(1973, 5, 28, 0, 0),
datetime(1974, 5, 27, 0, 0),
datetime(1975, 5, 26, 0, 0),
datetime(1976, 5, 31, 0, 0),
datetime(1977, 5, 30, 0, 0),
datetime(1978, 5, 29, 0, 0),
datetime(1979, 5, 28, 0, 0)]
193 changes: 193 additions & 0 deletions pandas/tests/tseries/holiday/test_holiday.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
from datetime import datetime

import pytest
from pytz import utc

import pandas.util.testing as tm

from pandas.tseries.holiday import (
MO, SA, AbstractHolidayCalendar, DateOffset, EasterMonday, GoodFriday,
Holiday, HolidayCalendarFactory, Timestamp, USColumbusDay, USLaborDay,
USMartinLutherKingJr, USMemorialDay, USPresidentsDay, USThanksgivingDay,
get_calendar, next_monday)


def _check_holiday_results(holiday, start, end, expected):
"""
Check that the dates for a given holiday match in date and timezone.

Parameters
----------
holiday : Holiday
The holiday to check.
start : datetime-like
The start date of range in which to collect dates for a given holiday.
end : datetime-like
The end date of range in which to collect dates for a given holiday.
expected : list
The list of dates we expect to get.
"""
assert list(holiday.dates(start, end)) == expected

# Verify that timezone info is preserved.
assert (list(holiday.dates(utc.localize(Timestamp(start)),
utc.localize(Timestamp(end)))) ==
[utc.localize(dt) for dt in expected])


@pytest.mark.parametrize("holiday,start_date,end_date,expected", [
(USMemorialDay, datetime(2011, 1, 1), datetime(2020, 12, 31),
[datetime(2011, 5, 30), datetime(2012, 5, 28), datetime(2013, 5, 27),
datetime(2014, 5, 26), datetime(2015, 5, 25), datetime(2016, 5, 30),
datetime(2017, 5, 29), datetime(2018, 5, 28), datetime(2019, 5, 27),
datetime(2020, 5, 25)]),

(Holiday("July 4th Eve", month=7, day=3), "2001-01-01", "2003-03-03",
[Timestamp("2001-07-03 00:00:00"), Timestamp("2002-07-03 00:00:00")]),
(Holiday("July 4th Eve", month=7, day=3, days_of_week=(0, 1, 2, 3)),
"2001-01-01", "2008-03-03", [
Timestamp("2001-07-03 00:00:00"), Timestamp("2002-07-03 00:00:00"),
Timestamp("2003-07-03 00:00:00"), Timestamp("2006-07-03 00:00:00"),
Timestamp("2007-07-03 00:00:00")]),

(EasterMonday, datetime(2011, 1, 1), datetime(2020, 12, 31),
[Timestamp("2011-04-25 00:00:00"), Timestamp("2012-04-09 00:00:00"),
Timestamp("2013-04-01 00:00:00"), Timestamp("2014-04-21 00:00:00"),
Timestamp("2015-04-06 00:00:00"), Timestamp("2016-03-28 00:00:00"),
Timestamp("2017-04-17 00:00:00"), Timestamp("2018-04-02 00:00:00"),
Timestamp("2019-04-22 00:00:00"), Timestamp("2020-04-13 00:00:00")]),
(GoodFriday, datetime(2011, 1, 1), datetime(2020, 12, 31),
[Timestamp("2011-04-22 00:00:00"), Timestamp("2012-04-06 00:00:00"),
Timestamp("2013-03-29 00:00:00"), Timestamp("2014-04-18 00:00:00"),
Timestamp("2015-04-03 00:00:00"), Timestamp("2016-03-25 00:00:00"),
Timestamp("2017-04-14 00:00:00"), Timestamp("2018-03-30 00:00:00"),
Timestamp("2019-04-19 00:00:00"), Timestamp("2020-04-10 00:00:00")]),

(USThanksgivingDay, datetime(2011, 1, 1), datetime(2020, 12, 31),
[datetime(2011, 11, 24), datetime(2012, 11, 22), datetime(2013, 11, 28),
datetime(2014, 11, 27), datetime(2015, 11, 26), datetime(2016, 11, 24),
datetime(2017, 11, 23), datetime(2018, 11, 22), datetime(2019, 11, 28),
datetime(2020, 11, 26)])
])
def test_holiday_dates(holiday, start_date, end_date, expected):
_check_holiday_results(holiday, start_date, end_date, expected)


@pytest.mark.parametrize("holiday,start,expected", [
(USMemorialDay, datetime(2015, 7, 1), []),
(USMemorialDay, "2015-05-25", "2015-05-25"),

(USLaborDay, datetime(2015, 7, 1), []),
(USLaborDay, "2015-09-07", "2015-09-07"),

(USColumbusDay, datetime(2015, 7, 1), []),
(USColumbusDay, "2015-10-12", "2015-10-12"),

(USThanksgivingDay, datetime(2015, 7, 1), []),
(USThanksgivingDay, "2015-11-26", "2015-11-26"),

(USMartinLutherKingJr, datetime(2015, 7, 1), []),
(USMartinLutherKingJr, "2015-01-19", "2015-01-19"),

(USPresidentsDay, datetime(2015, 7, 1), []),
(USPresidentsDay, "2015-02-16", "2015-02-16"),

(GoodFriday, datetime(2015, 7, 1), []),
(GoodFriday, "2015-04-03", "2015-04-03"),

(EasterMonday, "2015-04-06", "2015-04-06"),
(EasterMonday, datetime(2015, 7, 1), []),
(EasterMonday, "2015-04-05", []),

("New Years Day", "2015-01-01", "2015-01-01"),
("New Years Day", "2010-12-31", "2010-12-31"),
("New Years Day", datetime(2015, 7, 1), []),
("New Years Day", "2011-01-01", []),

("July 4th", "2015-07-03", "2015-07-03"),
("July 4th", datetime(2015, 7, 1), []),
("July 4th", "2015-07-04", []),

("Veterans Day", "2012-11-12", "2012-11-12"),
("Veterans Day", datetime(2015, 7, 1), []),
("Veterans Day", "2012-11-11", []),

("Christmas", "2011-12-26", "2011-12-26"),
("Christmas", datetime(2015, 7, 1), []),
("Christmas", "2011-12-25", []),
])
def test_holidays_within_dates(holiday, start, expected):
# see gh-11477
#
# Fix holiday behavior where holiday.dates returned dates outside
# start/end date, or observed rules could not be applied because the
# holiday was not in the original date range (e.g., 7/4/2015 -> 7/3/2015).
if isinstance(holiday, str):
calendar = get_calendar("USFederalHolidayCalendar")
holiday = calendar.rule_from_name(holiday)

if isinstance(expected, str):
expected = [Timestamp(expected)]

_check_holiday_results(holiday, start, start, expected)


@pytest.mark.parametrize("transform", [
lambda x: x.strftime("%Y-%m-%d"),
lambda x: Timestamp(x)
])
def test_argument_types(transform):
start_date = datetime(2011, 1, 1)
end_date = datetime(2020, 12, 31)

holidays = USThanksgivingDay.dates(start_date, end_date)
holidays2 = USThanksgivingDay.dates(
transform(start_date), transform(end_date))
tm.assert_index_equal(holidays, holidays2)


@pytest.mark.parametrize("name,kwargs", [
("One-Time", dict(year=2012, month=5, day=28)),
("Range", dict(month=5, day=28, start_date=datetime(2012, 1, 1),
end_date=datetime(2012, 12, 31),
offset=DateOffset(weekday=MO(1))))
])
def test_special_holidays(name, kwargs):
base_date = [datetime(2012, 5, 28)]
holiday = Holiday(name, **kwargs)

start_date = datetime(2011, 1, 1)
end_date = datetime(2020, 12, 31)

assert base_date == holiday.dates(start_date, end_date)


def test_get_calendar():
class TestCalendar(AbstractHolidayCalendar):
rules = []

calendar = get_calendar("TestCalendar")
assert TestCalendar == calendar.__class__


def test_factory():
class_1 = HolidayCalendarFactory("MemorialDay",
AbstractHolidayCalendar,
USMemorialDay)
class_2 = HolidayCalendarFactory("Thanksgiving",
AbstractHolidayCalendar,
USThanksgivingDay)
class_3 = HolidayCalendarFactory("Combined", class_1, class_2)

assert len(class_1.rules) == 1
assert len(class_2.rules) == 1
assert len(class_3.rules) == 2


def test_both_offset_observance_raises():
# see gh-10217
msg = "Cannot use both offset and observance"
with pytest.raises(NotImplementedError, match=msg):
Holiday("Cyber Monday", month=11, day=1,
offset=[DateOffset(weekday=SA(4))],
observance=next_monday)
Loading