diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml new file mode 100644 index 000000000..0613b9b03 --- /dev/null +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -0,0 +1,24 @@ +name: Pre-commit hooks autoupdate + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +jobs: + auto-update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4.7.0 + - uses: browniebroke/pre-commit-autoupdate-action@v1.0.0 + - uses: peter-evans/create-pull-request@v5.0.2 + with: + base: beta + branch: update/pre-commit-hooks + title: Update pre-commit hooks + author: github-actions[bot] + commit-message: "Chore: Update pre-commit hooks" + committer: github-actions[bot] + body: Update versions of pre-commit hooks to latest version. + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 614c5aeb6..4b8f6f03a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,7 @@ repos: exclude: ^(docs) - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.5.0 + rev: v1.5.1 hooks: - id: mypy additional_dependencies: [types-all] diff --git a/CHANGES b/CHANGES index 940f6d0f5..05df9b91a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,16 @@ +Version 0.32 +============ + +Released September 4, 2023 + +- Add subdivision category holidays support (#1446 by @KJhellico) +- Fix months imports (#1442 by @KJhellico) +- Improve code owners transparency (#1440 by @arkid15r) +- Update HolidayBase tests (#1447 by @arkid15r) +- Update documentation: correct inheritance example (#1438 by @arkid15r) +- Add CODEOWNERS (#1436 by @arkid15r) +- Add pre-commit hooks autoupdate workflow (#1441 by @KJhellico) + Version 0.31 ============ diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..11e1119bc --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,6 @@ +# People marked here will be automatically requested for a review. +# +# For more information on CODEOWNERS, see: +# https://help.github.com/en/articles/about-code-owners + +* @arkid15r @KJhellico diff --git a/docs/source/examples.rst b/docs/source/examples.rst index cf4829fde..44284c6ca 100644 --- a/docs/source/examples.rst +++ b/docs/source/examples.rst @@ -182,27 +182,29 @@ Creating custom holidays (or augmenting existing ones with private ones) Sometimes we may not be able to use the official federal statutory holiday list in our code. Let's pretend we work for a company that -does not include Columbus Day as a statutory holiday but does include +does not include New Year's Day as a statutory holiday but does include "Ninja Turtle Day" on July 13th. We can create a new class that inherits -the US and the only method we need to override is :py:meth:`_populate`: +the US (please note the base class import path) and the only method we need +to override is :py:meth:`_populate`: .. code-block:: python - >>> class CorporateHolidays(holidays.US): + >>> from holidays.countries import US + >>> class CorporateHolidays(US): >>> def _populate(self, year): - >>> # Populate the holiday list with the default US holidays - >>> holidays.US._populate(self, year) - >>> # Remove Columbus Day - >>> self.pop_named("Columbus Day") - >>> # Add Ninja Turtle Day - >>> self[date(year, 7, 13)] = "Ninja Turtle Day" - >>> date(2014, 10, 14) in holidays.country_holidays(country="US") + >>> # Populate the holiday list with the default US holidays. + >>> super()._populate(year) + >>> # Remove New Year's Day. + >>> self.pop_named("New Year's Day") + >>> # Add Ninja Turtle Day. + >>> self._add_holiday_jul_13("Ninja Turtle Day") + >>> date(2014, 1, 1) in holidays.country_holidays(country="US") True - >>> date(2014, 10, 14) in CorporateHolidays() + >>> date(2014, 1, 1) in CorporateHolidays() False >>> date(2014, 7, 13) in holidays.country_holidays(country="US") False - >>> date(2014 ,7, 13) in CorporateHolidays() + >>> date(2014, 7, 13) in CorporateHolidays() True We can also inherit from the HolidayBase class which has an empty diff --git a/holidays/__init__.py b/holidays/__init__.py index 27a435e44..f00e4eb95 100644 --- a/holidays/__init__.py +++ b/holidays/__init__.py @@ -16,7 +16,7 @@ from holidays.registry import EntityLoader from holidays.utils import * -__version__ = "0.31" +__version__ = "0.32" EntityLoader.load("countries", globals()) diff --git a/holidays/countries/bosnia_and_herzegovina.py b/holidays/countries/bosnia_and_herzegovina.py index a646945ee..1ce97690f 100644 --- a/holidays/countries/bosnia_and_herzegovina.py +++ b/holidays/countries/bosnia_and_herzegovina.py @@ -15,9 +15,22 @@ from gettext import gettext as tr from holidays.calendars import _CustomIslamicCalendar -from holidays.calendars.gregorian import GREGORIAN_CALENDAR +from holidays.calendars.gregorian import ( + GREGORIAN_CALENDAR, + JAN, + FEB, + MAR, + APR, + MAY, + JUN, + JUL, + AUG, + SEP, + OCT, + NOV, + DEC, +) from holidays.calendars.julian import JULIAN_CALENDAR -from holidays.constants import JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC from holidays.groups import ChristianHolidays, IslamicHolidays, InternationalHolidays from holidays.holiday_base import HolidayBase diff --git a/holidays/countries/latvia.py b/holidays/countries/latvia.py index 80622ab71..c59b757c2 100644 --- a/holidays/countries/latvia.py +++ b/holidays/countries/latvia.py @@ -13,7 +13,7 @@ from datetime import timedelta as td from gettext import gettext as tr -from holidays.constants import MAY, JUL, SEP +from holidays.calendars.gregorian import MAY, JUL, SEP from holidays.groups import ChristianHolidays, InternationalHolidays from holidays.holiday_base import HolidayBase diff --git a/holidays/holiday_base.py b/holidays/holiday_base.py index b6e58a169..0ea3e2e24 100644 --- a/holidays/holiday_base.py +++ b/holidays/holiday_base.py @@ -577,13 +577,14 @@ def __repr__(self) -> str: parts = [] if hasattr(self, "market"): parts.append(f"holidays.financial_holidays({self.market!r}") + parts.append(")") elif hasattr(self, "country"): if parts: parts.append(" + ") parts.append(f"holidays.country_holidays({self.country!r}") if self.subdiv: parts.append(f", subdiv={self.subdiv!r}") - parts.append(")") + parts.append(")") return "".join(parts) @@ -648,14 +649,19 @@ def _add_holiday(self, name: str, *args) -> Optional[date]: self[dt] = self.tr(name) return dt - def _add_subdiv_holidays(self): - """Populate subdivision holidays.""" + def _add_subdiv_category_holidays(self, category: str = None): + """Populate subdivision holidays by category.""" if self.subdiv is not None: subdiv = self.subdiv.replace("-", "_").replace(" ", "_").lower() - add_subdiv_holidays = getattr(self, f"_add_subdiv_{subdiv}_holidays", None) + method_name = f"_add_subdiv_{subdiv}{f'_{category}' if category else ''}_holidays" + add_subdiv_holidays = getattr(self, method_name, None) if add_subdiv_holidays and callable(add_subdiv_holidays): add_subdiv_holidays() + def _add_subdiv_holidays(self): + """Populate subdivision holidays.""" + self._add_subdiv_category_holidays() + def _add_substituted_holidays(self): """Populate substituted holidays.""" if len(self.substituted_holidays) == 0: @@ -758,6 +764,9 @@ def _populate_categories(self): if populate_category_holidays and callable(populate_category_holidays): populate_category_holidays() + # Populate subdivision holidays for all categories. + self._add_subdiv_category_holidays(category) + def append(self, *args: Union[Dict[DateLike, str], List[DateLike], DateLike]) -> None: """Alias for :meth:`update` to mimic list type.""" return self.update(*args) diff --git a/scripts/generate_release_notes.py b/scripts/generate_release_notes.py index 4f7269ea9..45a0fd53c 100755 --- a/scripts/generate_release_notes.py +++ b/scripts/generate_release_notes.py @@ -31,7 +31,7 @@ Released {month} {day}, {year} """ -IGNORED_CONTRIBUTORS = {"dependabot[bot]"} +IGNORED_CONTRIBUTORS = {"dependabot[bot]", "github-actions[bot]"} REPOSITORY_NAME = "vacanza/python-holidays" diff --git a/tests/test_holiday_base.py b/tests/test_holiday_base.py index 4982b0dd7..bd9efcef4 100644 --- a/tests/test_holiday_base.py +++ b/tests/test_holiday_base.py @@ -9,851 +9,946 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) -import os import pickle import unittest -import warnings from datetime import date, datetime from datetime import timedelta as td -import holidays -from holidays.calendars.gregorian import JAN, FEB, JUL, DEC, MON, TUE, SAT, SUN -from holidays.constants import HOLIDAY_NAME_DELIMITER +from holidays.calendars.gregorian import JAN, FEB, OCT, DEC, MON, TUE, SAT, SUN +from holidays.constants import HOLIDAY_NAME_DELIMITER, PUBLIC +from holidays.holiday_base import HolidayBase -class TestBasics(unittest.TestCase): - def setUp(self): - self.holidays = holidays.US() +class EntityStub(HolidayBase): + special_holidays = { + 1111: (JAN, 1, "Test holiday"), + 2222: (FEB, 2, "Test holiday"), + 3333: ((FEB, 2, "Test holiday")), + 4444: (), + } - def test_contains(self): - self.assertIn(date(2014, 1, 1), self.holidays) - self.assertNotIn(date(2014, 1, 2), self.holidays) + substituted_holidays = { + 1991: ( + (JAN, 12, JAN, 7), + (1991, JAN, 13, JAN, 8), + ), + } + substituted_date_format = "%d/%m/%Y" + substituted_label = "From %s" + supported_categories = {PUBLIC} - def test_getattr(self): - us = holidays.US() - us._populate(2023) + def _add_observed(self, dt: date, before: bool = True, after: bool = True) -> None: + if not self.observed: + return None - name = "Test" - self.assertEqual(us._add_holiday_3rd_mon_of_jun(name), date(2023, 6, 19)) - self.assertEqual(us._add_holiday_4th_fri_of_aug(name), date(2023, 8, 25)) - self.assertEqual(us._add_holiday_1st_wed_of_aug(name), date(2023, 8, 2)) - self.assertRaises(ValueError, lambda: us._add_holiday_5th_fri_of_aug(name)) - self.assertRaises(AttributeError, lambda: us._add_holiday_4th_nam_of_aug(name)) - self.assertRaises(AttributeError, lambda: us._add_holiday_nam_12(name)) + if self._is_saturday(dt) and before: + self._add_holiday("%s (Observed)" % self[dt], dt + td(days=-1)) + elif self._is_sunday(dt) and after: + self._add_holiday("%s (Observed)" % self[dt], dt + td(days=+1)) - self.assertEqual(us._add_holiday_1st_mon_before_may_24(name), date(2023, 5, 22)) - self.assertEqual(us._add_holiday_1st_sun_from_aug_31(name), date(2023, 9, 3)) + def _populate(self, year: int) -> None: + super()._populate(year) - self.assertRaises(AttributeError, lambda: us._add_holiday_1st_fri_before_nam_29(name)) - self.assertRaises(AttributeError, lambda: us._add_holiday_1st_fri_random_jan_29(name)) + name = "New Year's Day" + self._add_observed(self._add_holiday_jan_1(name), before=False) + if self.observed and self._is_friday(DEC, 31): + self._add_holiday_dec_31("%s (Observed)" % name) - def test_getitem(self): - self.assertEqual(self.holidays[date(2014, 1, 1)], "New Year's Day") - self.assertEqual(self.holidays.get(date(2014, 1, 1)), "New Year's Day") - self.assertRaises(KeyError, lambda: self.holidays[date(2014, 1, 2)]) - self.assertIsNone(self.holidays.get(date(2014, 1, 2))) + self._add_observed(self._add_holiday_jun_19("Juneteenth National Independence Day")) + self._add_observed(self._add_holiday_jul_4("Independence Day")) + self._add_holiday_4th_thu_of_nov("Thanksgiving") + self._add_observed(self._add_holiday_dec_25("Christmas Day")) - self.assertListEqual( - self.holidays[date(2013, 12, 31) : date(2014, 1, 2)], [date(2014, 1, 1)] + +class CountryStub1(EntityStub): + country = "CS1" + subdivisions = ("Subdiv1", "Subdiv2") + + def _add_subdiv_subdiv1_holidays(self): + self._add_holiday_aug_10("Subdiv1 Custom Holiday") + + def _add_subdiv_subdiv2_holidays(self): + self._add_holiday_aug_10("Subdiv2 Custom Holiday") + + +class CountryStub2(EntityStub): + country = "CS2" + subdivisions = ("Subdiv3", "Subdiv4") + + def _populate(self, year: int) -> None: + super()._populate(year) + self._add_holiday_mar_1("Custom March 1st Holiday") + + +class CountryStub3(HolidayBase): + country = "CS3" + + def _populate(self, year: int) -> None: + super()._populate(year) + self._add_holiday_may_1("Custom May 1st Holiday") + self._add_holiday_may_2("Custom May 2nd Holiday") + + +class MarketStub1(EntityStub): + market = "MS1" + + +class MarketStub2(EntityStub): + market = "MS2" + + +class TestArgs(unittest.TestCase): + def test_categories(self): + self.assertRaises(NotImplementedError, lambda: CountryStub1(categories=("HOME",))) + + def test_country(self): + self.assertEqual(CountryStub1().country, "CS1") + + def test_expand(self): + hb = CountryStub1(years=(2013, 2015), expand=False) + self.assertFalse(hb.expand) + self.assertSetEqual(hb.years, {2013, 2015}) + + self.assertNotIn("2014-01-01", hb) + self.assertSetEqual(hb.years, {2013, 2015}) + + def test_observed(self): + hb = CountryStub1(observed=False) + self.assertFalse(hb.observed) + self.assertIn("2000-01-01", hb) + self.assertNotIn("1999-12-31", hb) + self.assertIn("2012-01-01", hb) + self.assertNotIn("2012-01-02", hb) + + hb.observed = True + self.assertIn("2000-01-01", hb) + self.assertIn("1999-12-31", hb) + self.assertIn("2012-01-01", hb) + self.assertIn("2012-01-02", hb) + + hb.observed = False + self.assertIn("2000-01-01", hb) + self.assertNotIn("1999-12-31", hb) + self.assertIn("2012-01-01", hb) + self.assertNotIn("2012-01-02", hb) + + def test_subdiv(self): + self.assertEqual(CountryStub1(subdiv="Subdiv1").subdiv, "Subdiv1") + + def test_years(self): + hb = HolidayBase() + self.assertSetEqual(hb.years, set()) + + self.assertNotIn("2014-01-02", hb) + self.assertSetEqual(hb.years, {2014}) + + self.assertNotIn("2013-01-02", hb) + self.assertNotIn("2014-01-02", hb) + self.assertNotIn("2015-01-02", hb) + self.assertSetEqual(hb.years, {2013, 2014, 2015}) + + self.assertSetEqual( + HolidayBase(years=range(2010, 2016)).years, {2010, 2011, 2012, 2013, 2014, 2015} ) + self.assertSetEqual(HolidayBase(years=(2013, 2015, 2015)).years, {2013, 2015}) + self.assertSetEqual(HolidayBase(years=2015).years, {2015}) + + +class TestDeprecationWarnings(unittest.TestCase): + def test_prov_deprecation(self): + with self.assertWarns(Warning): + CountryStub1(prov="Subdiv1") + + def test_state_deprecation(self): + with self.assertWarns(Warning): + CountryStub1(state="Subdiv1") + + +class TestEqualityInequality(unittest.TestCase): + def test_eq(self): + hb_1 = CountryStub1() + hb_2 = CountryStub2() + hb_3 = CountryStub1(subdiv="Subdiv1") + + self.assertEqual(hb_1, hb_1) + self.assertEqual(hb_2, hb_2) + self.assertEqual(hb_3, hb_3) + + hb_4 = CountryStub1(years=2014) + hb_5 = CountryStub1(years=2014) + self.assertEqual(hb_4, hb_5) + self.assertEqual(hb_5, hb_4) + + hb_6 = CountryStub2(years=(2014, 2015)) + hb_7 = CountryStub2(years=(2014, 2015)) + self.assertEqual(hb_6, hb_7) + self.assertEqual(hb_7, hb_6) + + hb_8 = CountryStub3(language="fr") + hb_9 = CountryStub3(language="fr") + self.assertEqual(hb_8, hb_9) + self.assertEqual(hb_9, hb_8) + + # Use assertFalse instead of assertNotEqual as we want to check "==" explicitly. + self.assertFalse(hb_1 == {}) + self.assertFalse(hb_2 == {}) + self.assertFalse(hb_3 == {}) + self.assertFalse(hb_1 == hb_2) + self.assertFalse(hb_2 == hb_1) + self.assertFalse(hb_1 == hb_3) + self.assertFalse(hb_3 == hb_1) + self.assertFalse(hb_2 == hb_3) + self.assertFalse(hb_3 == hb_2) + + def test_ne(self): + hb_1 = CountryStub1() + hb_2 = CountryStub2() + hb_3 = CountryStub1(subdiv="Subdiv1") + + self.assertNotEqual(hb_1, {}) + self.assertNotEqual(hb_2, {}) + self.assertNotEqual(hb_3, {}) + self.assertNotEqual(hb_1, hb_2) + self.assertNotEqual(hb_2, hb_1) + self.assertNotEqual(hb_1, hb_3) + self.assertNotEqual(hb_3, hb_1) + self.assertNotEqual(hb_2, hb_3) + self.assertNotEqual(hb_3, hb_2) + + hb_4 = CountryStub1(years=2014) + hb_5 = CountryStub2(years=2015) + self.assertNotEqual(hb_1, hb_4) + self.assertNotEqual(hb_4, hb_1) + self.assertNotEqual(hb_2, hb_5) + self.assertNotEqual(hb_5, hb_2) + self.assertNotEqual(hb_4, hb_5) + self.assertNotEqual(hb_5, hb_4) + + hb_6 = CountryStub1(years=2014, subdiv="Subdiv1") + hb_7 = CountryStub1(years=2014, subdiv="Subdiv2") + self.assertNotEqual(hb_6, hb_7) + self.assertNotEqual(hb_7, hb_6) + + hb_8 = CountryStub1(years=2014) + hb_9 = CountryStub1(years=2014, language="fr") + self.assertNotEqual(hb_8, hb_9) + self.assertNotEqual(hb_9, hb_8) + + # Use assertFalse instead of assertEqual in order to check "!=" explicitly. + self.assertFalse(hb_1 != hb_1) + self.assertFalse(hb_2 != hb_2) + self.assertFalse(hb_3 != hb_3) + + +class TestGetList(unittest.TestCase): + def test_get_list_multiple_countries(self): + hb_country_1 = CountryStub1(years=2021) + hb_country_2 = CountryStub1(years=2021) + hb_country_1._add_holiday_dec_20("Custom Holiday 1") + hb_country_2._add_holiday_dec_20("Custom Holiday 2") + + self.assertEqual(hb_country_1["2021-12-20"], "Custom Holiday 1") + self.assertEqual(hb_country_2["2021-12-20"], "Custom Holiday 2") + self.assertListEqual(hb_country_1.get_list("2021-12-20"), ["Custom Holiday 1"]) + self.assertListEqual(hb_country_2.get_list("2021-12-20"), ["Custom Holiday 2"]) + + hb_combined = hb_country_1 + hb_country_2 + self.assertEqual(hb_combined["2021-12-20"], "Custom Holiday 1; Custom Holiday 2") self.assertListEqual( - self.holidays[date(2013, 12, 24) : date(2014, 1, 2)], - [date(2013, 12, 25), date(2014, 1, 1)], + hb_combined.get_list("2021-12-20"), ["Custom Holiday 1", "Custom Holiday 2"] ) - self.assertListEqual( - self.holidays[date(2013, 12, 25) : date(2014, 1, 2) : 3], [date(2013, 12, 25)] + + def test_get_list_multiple_subdivisions(self): + hb_subdiv_1 = CountryStub1(subdiv="Subdiv1", years=2021) + hb_subdiv_2 = CountryStub1(subdiv="Subdiv2", years=2021) + self.assertEqual(hb_subdiv_1["2021-08-10"], "Subdiv1 Custom Holiday") + self.assertEqual(hb_subdiv_2["2021-08-10"], "Subdiv2 Custom Holiday") + self.assertListEqual(hb_subdiv_1.get_list("2021-08-10"), ["Subdiv1 Custom Holiday"]) + self.assertListEqual(hb_subdiv_2.get_list("2021-08-10"), ["Subdiv2 Custom Holiday"]) + + hb_combined = hb_subdiv_1 + hb_subdiv_2 + self.assertEqual( + hb_combined["2021-08-10"], "Subdiv1 Custom Holiday; Subdiv2 Custom Holiday" ) self.assertListEqual( - self.holidays[date(2013, 12, 25) : date(2014, 1, 2) : 7], - [date(2013, 12, 25), date(2014, 1, 1)], + hb_combined.get_list("2021-08-10"), + ["Subdiv1 Custom Holiday", "Subdiv2 Custom Holiday"], ) + + +class TestGetNamed(unittest.TestCase): + def test_contains(self): + hb = CountryStub1(years=2022) + for name in ("New", "Year"): + self.assertListEqual(hb.get_named(name, lookup="contains"), [date(2022, 1, 1)]) self.assertListEqual( - self.holidays[date(2014, 1, 2) : date(2013, 12, 30)], [date(2014, 1, 1)] + hb.get_named("Independence Day", lookup="contains"), + [date(2022, 6, 19), date(2022, 6, 20), date(2022, 7, 4)], ) + self.assertListEqual(hb.get_named("independence day", lookup="contains"), []) + self.assertListEqual(hb.get_named("Thanksgiving", lookup="contains"), [date(2022, 11, 24)]) + self.assertListEqual(hb.get_named("Thanksgivi", lookup="contains"), [date(2022, 11, 24)]) + self.assertListEqual(hb.get_named("thanks", lookup="contains"), []) + self.assertSetEqual(hb.years, {2022}) + + hb = CountryStub1(observed=False, years=2022) self.assertListEqual( - self.holidays[date(2014, 1, 2) : date(2013, 12, 25)], [date(2014, 1, 1)] + hb.get_named("Independence Day", lookup="contains"), + [date(2022, 6, 19), date(2022, 7, 4)], ) + self.assertListEqual(hb.get_named("independence day", lookup="contains"), []) + self.assertSetEqual(hb.years, {2022}) + + def test_exact(self): + hb = CountryStub1(years=2022) + for name in ("New", "Day"): + self.assertListEqual(hb.get_named(name, lookup="exact"), []) + self.assertListEqual(hb.get_named("Independence Day", lookup="exact"), [date(2022, 7, 4)]) + self.assertListEqual(hb.get_named("Thanksgiving", lookup="exact"), [date(2022, 11, 24)]) + self.assertListEqual(hb.get_named("thanksgiving", lookup="exact"), []) + self.assertSetEqual(hb.years, {2022}) + + hb = CountryStub1(observed=False, years=2022) + self.assertListEqual(hb.get_named("Independence Day", lookup="exact"), [date(2022, 7, 4)]) + self.assertSetEqual(hb.years, {2022}) + + def test_icontains(self): + hb = CountryStub1(years=2022) + for name in ("Thanksgiving", "thanksgiving", "Thanksgivi"): + self.assertListEqual(hb.get_named(name, lookup="icontains"), [date(2022, 11, 24)]) self.assertListEqual( - self.holidays[date(2014, 1, 2) : date(2013, 12, 24)], - [date(2014, 1, 1), date(2013, 12, 25)], + hb.get_named("Independence Day", lookup="icontains"), + [date(2022, 6, 19), date(2022, 6, 20), date(2022, 7, 4)], ) + self.assertSetEqual(hb.years, {2022}) + + hb = CountryStub1(observed=False, years=2022) self.assertListEqual( - self.holidays[date(2014, 1, 1) : date(2013, 12, 24) : 3], [date(2014, 1, 1)] + hb.get_named("Independence Day", lookup="icontains"), + [date(2022, 6, 19), date(2022, 7, 4)], ) + self.assertSetEqual(hb.years, {2022}) + + def test_iexact(self): + hb = CountryStub1(years=2022) + for name in ("new year's day", "New Year's Day"): + self.assertListEqual(hb.get_named(name, lookup="iexact"), [date(2022, 1, 1)]) + for name in ("New Year Day", "New Year", "year", "NEW Year"): + self.assertListEqual(hb.get_named(name, lookup="iexact"), []) + self.assertListEqual(hb.get_named("independence day", lookup="iexact"), [date(2022, 7, 4)]) + self.assertListEqual(hb.get_named("thanksgiving", lookup="iexact"), [date(2022, 11, 24)]) + self.assertListEqual(hb.get_named("Thanksgivin", lookup="iexact"), []) + self.assertSetEqual(hb.years, {2022}) + + hb = CountryStub1(observed=False, years=2022) + self.assertListEqual(hb.get_named("independence day", lookup="iexact"), [date(2022, 7, 4)]) + self.assertSetEqual(hb.years, {2022}) + + def test_invalid(self): + hb = CountryStub1(years=2022) + self.assertRaises( + AttributeError, lambda: hb.get_named("Independence Day", lookup="invalid") + ) + + def test_istartswith(self): + hb = CountryStub1(years=2022) + for name in ("new year's", "New Year's", "New Year's day"): + self.assertListEqual(hb.get_named(name, lookup="istartswith"), [date(2022, 1, 1)]) + for name in ("New Year Day", "New Year holiday", "New Year's Day Holiday", "year"): + self.assertListEqual(hb.get_named(name, lookup="istartswith"), []) self.assertListEqual( - self.holidays[date(2014, 1, 1) : date(2013, 12, 24) : 7], - [date(2014, 1, 1), date(2013, 12, 25)], + hb.get_named("independence day", lookup="istartswith"), [date(2022, 7, 4)] ) - self.assertListEqual(self.holidays[date(2013, 12, 31) : date(2014, 1, 2) : -3], []) + self.assertSetEqual(hb.years, {2022}) + + hb = CountryStub1(observed=False, years=2022) self.assertListEqual( - self.holidays[date(2014, 1, 1) : date(2013, 12, 24) : td(days=3)], [date(2014, 1, 1)] + hb.get_named("independence day", lookup="istartswith"), [date(2022, 7, 4)] ) + self.assertSetEqual(hb.years, {2022}) + + def test_startswith(self): + hb = CountryStub1(years=2022) + for name in ("New Year's", "New Year"): + self.assertListEqual(hb.get_named(name, lookup="startswith"), [date(2022, 1, 1)]) + for name in ("New Year Day", "New Year Holiday", "New Year's Day Holiday", "year"): + self.assertListEqual(hb.get_named(name, lookup="startswith"), []) self.assertListEqual( - self.holidays[date(2014, 1, 1) : date(2013, 12, 24) : td(days=7)], - [date(2014, 1, 1), date(2013, 12, 25)], + hb.get_named("Independence Day", lookup="startswith"), [date(2022, 7, 4)] ) - self.assertListEqual(self.holidays[date(2013, 12, 31) : date(2014, 1, 2) : td(days=3)], []) - self.assertRaises(ValueError, lambda: self.holidays[date(2014, 1, 1) :]) - self.assertRaises(ValueError, lambda: self.holidays[: date(2014, 1, 1)]) - self.assertRaises( - TypeError, lambda: self.holidays[date(2014, 1, 1) : date(2014, 1, 2) : ""] + self.assertListEqual( + hb.get_named("Christmas", lookup="startswith"), + [date(2022, 12, 25), date(2022, 12, 26)], ) - self.assertRaises( - ValueError, lambda: self.holidays[date(2014, 1, 1) : date(2014, 1, 2) : 0] + self.assertSetEqual(hb.years, {2022}) + + hb = CountryStub1(observed=False, years=2022) + self.assertListEqual( + hb.get_named("Independence Day", lookup="startswith"), [date(2022, 7, 4)] ) + self.assertListEqual(hb.get_named("Christmas", lookup="startswith"), [date(2022, 12, 25)]) + self.assertSetEqual(hb.years, {2022}) - def test_get(self): - self.assertEqual(self.holidays.get("2014-01-01"), "New Year's Day") - self.assertIsNone(self.holidays.get("2014-01-02")) - self.assertFalse(self.holidays.get("2014-01-02", False)) - self.assertTrue(self.holidays.get("2014-01-02", True)) - - def test_pop(self): - self.assertRaises(KeyError, lambda: self.holidays.pop("2014-01-02")) - self.assertFalse(self.holidays.pop("2014-01-02", False)) - self.assertTrue(self.holidays.pop("2014-01-02", True)) - self.assertIn(date(2014, 1, 1), self.holidays) - self.assertEqual(self.holidays.pop("2014-01-01"), "New Year's Day") - self.assertNotIn(date(2014, 1, 1), self.holidays) - self.assertIn(date(2014, 7, 4), self.holidays) - - def test_pop_named_single(self): - self.assertIn(date(2014, 1, 1), self.holidays) - dts = self.holidays.pop_named("New Year's Day") - for dt in dts: - self.assertNotIn(dt, self.holidays) - def test_pop_named_multiple(self): - dt = date(2022, 2, 22) - holiday_name_1 = "Holiday Name 1" - holiday_name_2 = "Holiday Name 2" - holiday_name_3 = "Holiday Name 3" - combined_name = HOLIDAY_NAME_DELIMITER.join( - (holiday_name_1, holiday_name_2, holiday_name_3) - ) - self.holidays[dt] = holiday_name_1 - self.holidays[dt] = holiday_name_2 - self.holidays[dt] = holiday_name_3 - self.assertEqual(self.holidays[dt], combined_name) +class TestHelperMethods(unittest.TestCase): + def setUp(self): + self.hb = CountryStub1() - # Pop the entire date by multiple holidays exact name. - self.holidays.pop_named(combined_name) - self.assertNotIn(dt, self.holidays) + def test_add_holiday(self): + self.hb._populate(2023) + self.hb._add_holiday("Test 1", date(2023, JAN, 5)) + self.hb._add_holiday("Test 2", (JAN, 6)) + self.hb._add_holiday_jan_7("Test 3") - # Pop only one holiday by a single name. - self.holidays[dt] = holiday_name_1 - self.holidays[dt] = holiday_name_2 - self.holidays[dt] = holiday_name_3 - self.assertEqual(self.holidays[dt], combined_name) + self.assertIn("2023-01-05", self.hb) + self.assertIn("2023-01-06", self.hb) + self.assertIn("2023-01-07", self.hb) - self.holidays.pop_named(holiday_name_1) - self.assertEqual( - self.holidays[dt], HOLIDAY_NAME_DELIMITER.join((holiday_name_2, holiday_name_3)) - ) + for args in ( + (date(2020, JAN, 5),), + (JAN, 5, "Test 1", True), + ("Test", "Test"), + ): + self.assertRaises(TypeError, lambda: self.hb._add_holiday(*args)) - self.holidays.pop_named(holiday_name_3) - self.assertEqual(self.holidays[dt], holiday_name_2) + def test_is_leap_year(self): + self.hb._populate(1999) + self.assertFalse(self.hb._is_leap_year()) - self.holidays.pop_named(holiday_name_2) - self.assertNotIn(dt, self.holidays) + self.hb._populate(2000) + self.assertTrue(self.hb._is_leap_year()) - def test_pop_named_partial(self): - self.assertIn(date(2014, 1, 1), self.holidays) - dts = self.holidays.pop_named("N") - for dt in dts: - self.assertNotIn(dt, self.holidays) - self.assertRaises(KeyError, lambda: self.holidays.pop_named("New Year")) + self.hb._populate(2004) + self.assertTrue(self.hb._is_leap_year()) - def test_pop_named_exception(self): - self.assertRaises(KeyError, lambda: self.holidays.pop_named("New Year's Dayz")) + self.hb._populate(2200) + self.assertFalse(self.hb._is_leap_year()) - self.assertIn(date(2022, 1, 1), self.holidays) - self.holidays.pop_named("New Year's Day") - self.assertRaises(KeyError, lambda: self.holidays.pop_named("New Year's Day")) + def test_is_weekend(self): + self.hb._populate(2022) + dts = (date(2022, 10, 3), date(2022, 10, 4), (OCT, 3), (OCT, 4)) - def test_setitem(self): - self.holidays = holidays.US(years=[2014]) - self.assertEqual(len(self.holidays), 10) - self.holidays[date(2014, 1, 3)] = "Fake Holiday" - self.assertEqual(len(self.holidays), 11) - self.assertIn(date(2014, 1, 3), self.holidays) - self.assertEqual(self.holidays.get(date(2014, 1, 3)), "Fake Holiday") - - def test_repr_country(self): - self.assertEqual(repr(holidays.US()), "holidays.country_holidays('US')") - self.assertEqual( - repr(holidays.US(subdiv="CA")), "holidays.country_holidays('US', subdiv='CA')" - ) + self.hb.weekend = {MON, TUE} + for dt in dts: + self.assertTrue(self.hb._is_weekend(dt)) - def test_repr_market(self): - self.assertEqual(repr(holidays.NYSE()), "holidays.financial_holidays('NYSE')") + self.hb.weekend = {} + for dt in dts: + self.assertFalse(self.hb._is_weekend(dt)) - def test_str_country(self): - self.assertEqual( - str(holidays.US()), - "{'country': US, 'expand': True, 'language': None, " - "'market': None, 'observed': True, 'subdiv': None, " - "'years': set()}", - ) - self.assertEqual( - str(holidays.US(years=1900)), - '{datetime.date(1900, 2, 22): "Washington\'s Birthday", ' - 'datetime.date(1900, 1, 1): "New Year\'s Day", ' - "datetime.date(1900, 5, 30): 'Memorial Day', " - "datetime.date(1900, 7, 4): 'Independence Day', " - "datetime.date(1900, 9, 3): 'Labor Day', " - "datetime.date(1900, 11, 22): 'Thanksgiving', " - "datetime.date(1900, 12, 25): 'Christmas Day'}", - ) + self.hb.weekend = {SAT, SUN} + for dt in (date(2022, 10, 1), date(2022, 10, 2)): + self.assertTrue(self.hb._is_weekend(dt)) + for dt in ((OCT, 1), (OCT, 2)): + self.assertTrue(self.hb._is_weekend(dt)) + self.assertTrue(self.hb._is_weekend(*dt)) - def test_str_market(self): - self.assertEqual( - str(holidays.NYSE()), - "{'country': None, 'expand': True, 'language': None, " - "'market': NYSE, 'observed': True, 'subdiv': None, " - "'years': set()}", + for dt in (date(2022, 10, 3), date(2022, 10, 4)): + self.assertFalse(self.hb._is_weekend(dt)) + for dt in ((OCT, 3), (OCT, 4)): + self.assertFalse(self.hb._is_weekend(dt)) + self.assertFalse(self.hb._is_weekend(*dt)) + + +class TestHolidaySum(unittest.TestCase): + def setUp(self) -> None: + self.hb_1 = CountryStub1(years=2014) + self.hb_2 = CountryStub2(years=2015) + self.hb_3 = CountryStub3() + self.hb_combined = self.hb_1 + self.hb_2 + self.hb_3 + + def assertAdded(self): + self.assertNotIn("2014-03-01", self.hb_1) + self.assertNotIn("2014-05-01", self.hb_1) + self.assertNotIn("2014-05-02", self.hb_1) + self.assertIn("2014-03-01", self.hb_2) + self.assertIn("2014-05-01", self.hb_3) + self.assertIn("2014-05-02", self.hb_3) + + self.assertIn("2014-07-04", self.hb_1) + self.assertIn("2014-07-04", self.hb_1 + self.hb_2) + self.assertIn("2014-07-04", self.hb_2 + self.hb_1) + self.assertIn("2015-07-04", self.hb_1 + self.hb_2) + self.assertIn("2015-07-04", self.hb_2 + self.hb_1) + + self.assertIn("2000-03-01", self.hb_combined) + self.assertIn("2000-05-01", self.hb_combined) + self.assertIn("2000-05-02", self.hb_combined) + self.assertIn("2000-07-04", self.hb_combined) + self.assertIn("2000-07-04", self.hb_combined) + + def test_add_country(self): + self.assertAdded() + + self.hb_combined = CountryStub1(years=2014) + self.hb_combined += CountryStub2(years=2015) + self.hb_combined += CountryStub3() + self.assertAdded() + + self.hb_combined = ( + self.hb_1 + + (self.hb_2 + self.hb_3) + + self.hb_1 + + (self.hb_3 + self.hb_2 + CountryStub2(subdiv="Subdiv4")) ) + self.assertAdded() + + self.hb_combined = CountryStub1(years=2014, subdiv="Subdiv1") + self.hb_combined += CountryStub1(years=2014, subdiv="Subdiv2") self.assertEqual( - str(holidays.NYSE(years=1900)), - "{datetime.date(1900, 12, 24): 'Christmas Eve', " - 'datetime.date(1900, 1, 1): "New Year\'s Day", ' - 'datetime.date(1900, 2, 12): "Lincoln\'s Birthday", ' - 'datetime.date(1900, 2, 22): "Washington\'s Birthday", ' - "datetime.date(1900, 4, 13): 'Good Friday', " - "datetime.date(1900, 5, 30): 'Memorial Day', " - "datetime.date(1900, 7, 4): 'Independence Day', " - "datetime.date(1900, 9, 3): 'Labor Day', " - "datetime.date(1900, 11, 6): 'Election Day', " - "datetime.date(1900, 11, 22): 'Thanksgiving Day', " - "datetime.date(1900, 12, 25): 'Christmas Day'}", + self.hb_combined["2014-08-10"], "Subdiv1 Custom Holiday; Subdiv2 Custom Holiday" ) - def test_update(self): - h = holidays.HolidayBase() - h.update( - { - date(2015, 1, 1): "New Year's Day", - "2015-12-25": "Christmas Day", - } - ) - self.assertIn("2015-01-01", h) - self.assertIn(date(2015, 12, 25), h) + self.assertRaises(TypeError, lambda: self.hb_1 + {}) - def test_is_leap_year(self): - instance = holidays.HolidayBase() - instance._populate(2000) - self.assertTrue(instance._is_leap_year()) + def test_add_financial(self): + hb_1 = MarketStub1(years=2013) + hb_2 = MarketStub2(years=(2014, 2015)) + hb_combined = hb_1 + hb_2 + + self.assertIn("2013-01-01", hb_1) + self.assertIn("2014-01-01", hb_2) + self.assertIn("2015-01-01", hb_2) + self.assertIn("2013-01-01", hb_combined) + self.assertIn("2014-01-01", hb_combined) + self.assertIn("2015-01-01", hb_combined) + self.assertListEqual(hb_combined.market, ["MS1", "MS2"]) + + def test_args(self): + self.hb_1 = CountryStub1(years=2014, subdiv="Subdiv1") + self.hb_2 = CountryStub2(years=2015, subdiv="Subdiv3") + self.assertListEqual(self.hb_combined.country, ["CS1", "CS2", "CS3"]) + self.assertListEqual((self.hb_1 + self.hb_2).subdiv, ["Subdiv1", "Subdiv3"]) + self.assertListEqual((self.hb_2 + self.hb_1).subdiv, ["Subdiv3", "Subdiv1"]) + self.assertEqual((self.hb_1 + self.hb_3).subdiv, "Subdiv1") + + self.assertTrue((self.hb_2 + self.hb_3).expand) + self.assertSetEqual((self.hb_2 + self.hb_3).years, {2014, 2015}) + self.assertSetEqual((self.hb_3 + self.hb_2).years, {2014, 2015}) + + self.hb_combined = sum(CountryStub1(subdiv=subdiv) for subdiv in CountryStub1.subdivisions) + self.assertEqual(self.hb_combined.country, CountryStub1.country) + self.assertEqual(self.hb_combined.subdiv, list(CountryStub1.subdivisions)) + + +class TestInheritance(unittest.TestCase): + def setUp(self): + self.hb = CountryStub1() - instance._populate(2100) - self.assertFalse(instance._is_leap_year()) + def test_custom_holidays(self): + class CustomHolidays(CountryStub1): + def _populate(self, year): + super()._populate(year) + self._add_holiday_jul_13("Ninja Turtle's Day") + self._add_holiday_dec_31("New Year's Eve") + del self[date(year, JAN, 1)] - def test_is_weekend(self): - h = holidays.HolidayBase() - h._populate(2022) + hb = CustomHolidays(years=(2014, 2020)) + self.assertIn("2014-01-01", self.hb) + self.assertNotIn("2014-01-01", hb) + self.assertIn("2014-12-31", hb) + self.assertNotIn("2014-12-31", self.hb) - h.weekend = {MON, TUE} - for dt in (date(2022, 10, 3), date(2022, 10, 4)): - self.assertTrue(h._is_weekend(dt)) + self.assertIn("2020-01-01", self.hb) + self.assertNotIn("2020-01-01", hb) + self.assertIn("2020-12-31", hb) + self.assertNotIn("2020-12-31", self.hb) - h.weekend = {} - for dt in (date(2022, 10, 3), date(2022, 10, 4)): - self.assertFalse(h._is_weekend(dt)) + self.assertNotIn("2014-07-13", self.hb) + self.assertIn("2014-07-13", hb) + self.assertNotIn("2020-07-13", self.hb) + self.assertIn("2020-07-13", hb) - h.weekend = {SAT, SUN} - for dt in (date(2022, 10, 1), date(2022, 10, 2)): - self.assertTrue(h._is_weekend(dt)) - for dt in ((10, 1), (10, 2)): - self.assertTrue(h._is_weekend(dt)) - self.assertTrue(h._is_weekend(*dt)) - for dt in (date(2022, 10, 3), date(2022, 10, 4)): - self.assertFalse(h._is_weekend(dt)) - for dt in ((10, 3), (10, 4)): - self.assertFalse(h._is_weekend(dt)) - self.assertFalse(h._is_weekend(*dt)) +class TestKeyTransforms(unittest.TestCase): + def setUp(self): + self.hb = CountryStub1() - def test_append(self): - h = holidays.HolidayBase() - h.update( - { - date(2015, 1, 1): "New Year's Day", - "2015-12-25": "Christmas Day", - } - ) - h.append([date(2015, 4, 1), "2015-04-03"]) - h.append(date(2015, 4, 6)) - h.append("2015-04-07") - self.assertIn("2015-01-01", h) - self.assertIn(date(2015, 12, 25), h) - self.assertIn("2015-04-01", h) - self.assertNotIn("2015-04-02", h) - self.assertIn("2015-04-03", h) - self.assertNotIn("2015-04-04", h) - self.assertNotIn("2015-04-05", h) - self.assertIn("2015-04-06", h) - self.assertIn("2015-04-07", h) + def test_date(self): + dt = date(2014, 1, 1) + self.assertIn(dt, self.hb) + self.assertEqual(self.hb[dt], "New Year's Day") + + dt = date(2014, 1, 3) + self.hb[dt] = "Fake Holiday" + self.assertIn(dt, self.hb) + self.assertEqual(self.hb.pop(dt), "Fake Holiday") + self.assertNotIn(dt, self.hb) + + def test_date_subclass(self): + class CustomDateType(date): + pass - def test_eq(self): - canada = holidays.Canada() - united_states = holidays.UnitedStates() - self.assertEqual(united_states, holidays.US()) - self.assertEqual(holidays.UnitedStates(years=2014), holidays.US(years=2014)) - self.assertEqual(canada, holidays.CA()) - self.assertEqual(holidays.Canada(years=[2014]), holidays.CA(years=[2014])) - self.assertEqual(holidays.Canada(language="fr"), holidays.CA(language="fr")) - self.assertFalse(united_states == {}) - self.assertFalse(united_states == holidays.UnitedStates(subdiv="WA")) + self.assertTrue(issubclass(CustomDateType, date)) + self.assertIn(CustomDateType(2014, 1, 1), self.hb) + self.assertNotIn(CustomDateType(2014, 1, 3), self.hb) - def test_ne(self): - canada = holidays.Canada() - united_states = holidays.UnitedStates() - self.assertNotEqual(united_states, holidays.UnitedStates(years=2014)) - self.assertNotEqual(united_states, canada) - self.assertNotEqual(holidays.UnitedStates(years=2014), holidays.Canada(years=2014)) - self.assertNotEqual(united_states, holidays.UnitedStates(years=[2014])) - self.assertNotEqual(canada, holidays.Canada(language="fr")) + def test_datetime(self): + self.assertIn(datetime(2014, 1, 1, 13, 45), self.hb) + self.assertEqual(self.hb[datetime(2014, 1, 1, 13, 45)], "New Year's Day") - self.assertNotEqual(united_states, {}) - self.assertTrue(united_states != {}) - self.assertTrue(united_states != holidays.UnitedStates(subdiv="WA")) + self.hb[datetime(2014, 1, 3, 1, 1)] = "Fake Holiday" + self.assertIn(datetime(2014, 1, 3, 2, 2), self.hb) + self.assertEqual(self.hb.pop(datetime(2014, 1, 3, 4, 4)), "Fake Holiday") + self.assertNotIn(datetime(2014, 1, 3, 2, 2), self.hb) - united_states.append("2023-01-01") - self.assertNotEqual(united_states, holidays.UnitedStates(years=2023)) + def test_exception(self): + self.assertRaises((TypeError, ValueError), lambda: "abc" in self.hb) + self.assertRaises((TypeError, ValueError), lambda: self.hb.get("abc123")) + self.assertRaises(TypeError, lambda: self.hb.get({"123"})) + self.assertRaises((TypeError, ValueError), self.hb.__setitem__, "abc", "Test") + self.assertRaises((TypeError, ValueError), lambda: {} in self.hb) - def test_copy(self): - us = holidays.UnitedStates() - self.assertEqual(us, us.copy()) - self.assertTrue(us == us.copy()) - - ca = holidays.Canada() - ca_fr = holidays.Canada(language="fr") - ca_xx = holidays.Canada(language="xx") - self.assertNotEqual(ca, ca_fr) - self.assertNotEqual(ca.copy(), ca_fr.copy()) - - self.assertNotEqual(ca, ca_xx) - self.assertNotEqual(ca.copy(), ca_xx.copy()) - - def test_add_countries(self): - ca = holidays.CA() - us = holidays.US() - mx = holidays.MX() - na = ca + (us + mx) - self.assertNotIn("2014-07-01", us) - self.assertIn("2014-07-01", ca) - self.assertNotIn("2014-07-04", ca) - self.assertIn("2014-07-04", us) - self.assertIn("2014-07-04", ca + us) - self.assertIn("2014-07-04", us + ca) - self.assertIn("2015-07-04", ca + us) - self.assertIn("2015-07-04", us + ca) - self.assertIn("2015-07-01", ca + us) - self.assertIn("2015-07-01", us + ca) - self.assertIn("2014-07-04", na) - self.assertIn("2015-07-04", na) - self.assertIn("2015-07-01", na) - self.assertIn("2000-02-05", na) - self.assertEqual((ca + us).subdiv, "ON") - self.assertEqual((us + ca).subdiv, "ON") - ca = holidays.CA(years=[2014], expand=False) - us = holidays.US(years=[2014, 2015], expand=True) - self.assertTrue((ca + us).expand) - self.assertEqual((ca + us).years, {2014, 2015}) - self.assertEqual((us + ca).years, {2014, 2015}) - na = holidays.CA() - na += holidays.US() - na += holidays.MX() - self.assertEqual(na.country, ["CA", "US", "MX"]) - self.assertIn("2014-07-04", na) - self.assertIn("2014-07-04", na) - self.assertIn("2015-07-04", na) - self.assertIn("2015-07-04", na) - self.assertIn("2015-07-01", na) - self.assertIn("2015-07-01", na) - self.assertIn("2000-02-05", na) - self.assertEqual(na.subdiv, "ON") - na = holidays.CA() + holidays.US() - na += holidays.MX() - self.assertIn("2014-07-04", na) - self.assertIn("2014-07-04", na) - self.assertIn("2015-07-04", na) - self.assertIn("2015-07-04", na) - self.assertIn("2015-07-01", na) - self.assertIn("2015-07-01", na) - self.assertIn("2000-02-05", na) - self.assertEqual(na.subdiv, "ON") - self.assertRaises(TypeError, lambda: holidays.US() + {}) - na = ca + (us + mx) + ca + (mx + us + holidays.CA(subdiv="BC")) - self.assertIn("2000-02-05", na) - self.assertIn("2014-02-10", na) - self.assertIn("2014-02-17", na) - self.assertIn("2014-07-04", na) - provs = holidays.CA(subdiv="ON", years=[2014]) + holidays.CA(subdiv="BC", years=[2015]) - self.assertIn("2015-02-09", provs) - self.assertIn("2015-02-16", provs) - self.assertEqual(provs.subdiv, ["ON", "BC"]) - a = sum(holidays.CA(subdiv=x) for x in holidays.CA.subdivisions) - self.assertEqual(a.country, "CA") - self.assertListEqual(a.subdiv, list(holidays.CA.subdivisions)) - self.assertIn("2015-02-09", a) - self.assertIn("2015-02-16", a) - na = holidays.CA() + holidays.US() + holidays.MX(language="es") - self.assertIn(date(1969, 12, 25), na) - self.assertEqual(na.get(date(1969, 7, 1)), "Dominion Day") - self.assertEqual(na.get(date(1983, 7, 1)), "Canada Day") - self.assertEqual(na.get(date(1969, 12, 25)), "Christmas Day; Navidad") - na = holidays.MX(language="es") + holidays.CA() + holidays.US() - self.assertEqual(na.get(date(1969, 12, 25)), "Christmas Day; Navidad") - self.assertEqual(na, na.copy()) + def test_string(self): + self.assertIn("2014-01-01", self.hb) + self.assertEqual(self.hb["2014-01-01"], "New Year's Day") + self.assertIn("01/01/2014", self.hb) + self.assertEqual(self.hb["01/01/2014"], "New Year's Day") + + self.hb["01/03/2014"] = "Fake Holiday" + self.assertIn("01/03/2014", self.hb) + self.assertNotIn("03/01/2014", self.hb) + self.assertIn("2014-01-03", self.hb) + self.assertNotIn("2014-03-01", self.hb) + self.assertEqual(self.hb.pop("01/03/2014"), "Fake Holiday") - def test_add_financial(self): - ecb = holidays.ECB() - nyse = holidays.NYSE() - ecb_nyse = ecb + nyse - self.assertEqual(len(ecb) + len(nyse), len(ecb_nyse)) - self.assertEqual(ecb_nyse.market, ["ECB", "NYSE"]) - self.assertEqual(ecb_nyse, ecb_nyse.copy()) - self.assertNotEqual(ecb_nyse, {}) + def test_timestamp(self): + self.assertIn(1388552400, self.hb) + self.assertEqual(self.hb[1388552400], "New Year's Day") + self.assertIn(1388552400.01, self.hb) + self.assertEqual(self.hb[1388552400.01], "New Year's Day") - def test_add_holiday(self): - us = holidays.UnitedStates() - us._populate(2023) - us._add_holiday("Test 1", date(2023, JAN, 5)) - us._add_holiday("Test 2", (JAN, 6)) - us._add_holiday_jan_7("Test 3") + self.hb[1388725200] = "Fake Holiday" + self.assertIn(1388725201, self.hb) + self.assertEqual(self.hb.pop(1388725202), "Fake Holiday") + self.assertNotIn(1388725201, self.hb) - self.assertIn("2023-01-05", us) - self.assertIn("2023-01-06", us) - self.assertIn("2023-01-07", us) - for args in ( - (date(2020, JAN, 5),), - (JAN, 5, "Test 1", True), - ("Test", "Test"), - ): - self.assertRaises(TypeError, lambda: us._add_holiday(*args)) +class TestPop(unittest.TestCase): + def setUp(self): + self.hb = CountryStub1() - def test_get_list(self): - warnings.simplefilter("ignore", category=DeprecationWarning) + def test_exception(self): + self.assertRaises(KeyError, lambda: self.hb.pop("2014-01-02")) - westland = holidays.NZ(subdiv="WTL") - chathams = holidays.NZ(subdiv="CIT") - wild = westland + chathams - self.assertEqual( - wild[date(1969, 12, 1)], - ("Chatham Islands Anniversary Day; West Coast Anniversary Day"), - ) + self.hb.pop("2014-01-01") + self.assertRaises(KeyError, lambda: self.hb.pop("2014-01-01")) - self.assertEqual( - wild.get_list(date(1969, 12, 1)), - ["Chatham Islands Anniversary Day", "West Coast Anniversary Day"], - ) - self.assertEqual(wild.get_list(date(1969, 1, 1)), ["New Year's Day"]) - self.assertEqual(westland.get_list(date(1969, 12, 1)), ["West Coast Anniversary Day"]) - self.assertEqual(westland.get_list(date(1969, 1, 1)), ["New Year's Day"]) - self.assertEqual(chathams.get_list(date(1969, 12, 1)), ["Chatham Islands Anniversary Day"]) - self.assertEqual(chathams.get_list(date(1969, 1, 1)), ["New Year's Day"]) - ca = holidays.CA() - us = holidays.US() - mx = holidays.MX(language="es") - na = ca + us + mx - self.assertIn(date(1969, 12, 25), na) - self.assertEqual(na.get_list(date(1969, 12, 25)), ["Christmas Day", "Navidad"]) - self.assertEqual(na.get_list(date(1969, 7, 1)), ["Dominion Day"]) - self.assertEqual(na.get_list(date(1969, 1, 3)), []) + def test_success(self): + self.assertFalse(self.hb.pop("2014-01-02", False)) + self.assertTrue(self.hb.pop("2014-01-02", True)) + self.assertIn("2014-01-01", self.hb) + self.assertEqual(self.hb.pop("2014-01-01"), "New Year's Day") + self.assertNotIn("2014-01-01", self.hb) - def test_radd(self): - self.assertRaises(TypeError, lambda: 1 + holidays.US()) - def test_inheritance(self): - class CustomNewYearHolidays(holidays.countries.US): - def _populate(self, year): - super()._populate(year) - self._add_holiday_dec_31("New Year's Eve") - self.pop(date(year, JAN, 1)) +class TestPopNamed(unittest.TestCase): + def setUp(self): + self.hb = CountryStub1() - instance = CustomNewYearHolidays() - self.assertIn(date(2014, JAN, 1), self.holidays) - self.assertNotIn(date(2014, JAN, 1), instance) - self.assertIn(date(2014, DEC, 31), instance) - self.assertNotIn(date(2014, DEC, 31), self.holidays) + def test_exception(self): + self.assertRaises(KeyError, lambda: self.hb.pop_named("New Year's Dayz")) - self.assertIn(date(2020, JAN, 1), self.holidays) - self.assertNotIn(date(2020, JAN, 1), instance) - self.assertIn(date(2020, DEC, 31), instance) - self.assertNotIn(date(2020, DEC, 31), self.holidays) + self.assertIn("2014-01-01", self.hb) + self.hb.pop_named("New Year's Day") + self.assertRaises(KeyError, lambda: self.hb.pop_named("New Year's Day")) - class NinjaTurtlesHolidays(holidays.countries.US): - def _populate(self, year): - super()._populate(year) - self._add_holiday_jul_13("Ninja Turtle's Day") + def test_single(self): + self.assertIn("2014-01-01", self.hb) + for dt in self.hb.pop_named("New Year's Day"): + self.assertNotIn(dt, self.hb) - instance = NinjaTurtlesHolidays() - self.assertNotIn(date(2014, JUL, 13), self.holidays) - self.assertIn(date(2014, JUL, 13), instance) + def test_multiple(self): + dt = date(2022, 2, 22) + holiday_name_1 = "Holiday Name 1" + holiday_name_2 = "Holiday Name 2" + holiday_name_3 = "Holiday Name 3" + combined_name = HOLIDAY_NAME_DELIMITER.join( + (holiday_name_1, holiday_name_2, holiday_name_3) + ) + self.hb[dt] = holiday_name_1 + self.hb[dt] = holiday_name_2 + self.hb[dt] = holiday_name_3 + self.assertEqual(self.hb[dt], combined_name) - self.assertNotIn(date(2020, JUL, 13), self.holidays) - self.assertIn(date(2020, JUL, 13), instance) + # Pop the entire date by multiple holidays exact name. + self.hb.pop_named(combined_name) + self.assertNotIn(dt, self.hb) - class NewCountry(holidays.HolidayBase): - def _populate(self, year): - super()._populate(year) - self._add_holiday_jan_2("New New Year's") + # Pop only one holiday by a single name. + self.hb[dt] = holiday_name_1 + self.hb[dt] = holiday_name_2 + self.hb[dt] = holiday_name_3 - instance = NewCountry() - self.assertNotIn(date(2014, JAN, 1), instance) - self.assertIn(date(2014, JAN, 2), instance) + # 3 holidays names. + self.assertEqual(self.hb[dt], combined_name) - def test_get_named_contains(self): - us = holidays.UnitedStates(years=2020) + self.hb.pop_named(holiday_name_1) + # 2 holiday names. + self.assertEqual( + self.hb[dt], HOLIDAY_NAME_DELIMITER.join((holiday_name_2, holiday_name_3)) + ) - holidays_count = len(us.keys()) - for name in ("New", "Year"): - self.assertIn(date(2020, 1, 1), us.get_named(name)) - for name in ("new", "year", "NEW Year"): - self.assertNotIn(date(2020, 1, 1), us.get_named(name, lookup="contains")) - self.assertEqual(holidays_count, len(us.keys())) - - us = holidays.UnitedStates(years=2022) - self.assertEqual(1, len(us.get_named("Thanksgiving", lookup="contains"))) - self.assertEqual(1, len(us.get_named("Thanksgivi", lookup="contains"))) - self.assertEqual(0, len(us.get_named("thanks", lookup="contains"))) - self.assertEqual([2022], list(us.years)) - - us = holidays.UnitedStates(observed=False, years=2022) - self.assertEqual(2, len(us.get_named("Independence Day", lookup="contains"))) - self.assertEqual(0, len(us.get_named("independence day", lookup="contains"))) - - def test_get_named_exact(self): - us = holidays.UnitedStates(years=2020) - holidays_count = len(us.keys()) - for name in ("New Year's Day", "Christmas Day"): - self.assertEqual(1, len(us.get_named(name))) - for name in ("New", "Day"): - self.assertEqual(0, len(us.get_named(name, lookup="exact"))) - self.assertEqual(holidays_count, len(us.keys())) + self.hb.pop_named(holiday_name_3) + # 1 holiday name. + self.assertEqual(self.hb[dt], holiday_name_2) - us = holidays.UnitedStates(years=2022) - self.assertEqual(1, len(us.get_named("Thanksgiving", lookup="exact"))) - self.assertEqual(0, len(us.get_named("thanksgiving", lookup="exact"))) - self.assertEqual([2022], list(us.years)) + self.hb.pop_named(holiday_name_2) + # 0 holiday names. + self.assertNotIn(dt, self.hb) - us = holidays.UnitedStates(observed=False, years=2022) - self.assertEqual(1, len(us.get_named("Independence Day", lookup="exact"))) + def test_partial(self): + self.assertIn("2014-01-01", self.hb) + for dt in self.hb.pop_named("N"): + self.assertNotIn(dt, self.hb) + self.assertRaises(KeyError, lambda: self.hb.pop_named("New Year")) - def test_get_named_icontains(self): - us = holidays.UnitedStates(years=2020) - holidays_count = len(us.keys()) - self.assertEqual(holidays_count, len(us.keys())) - for name in ("New", "Year", "new", "year", "NEW Year"): - self.assertIn(date(2020, 1, 1), us.get_named(name)) - us = holidays.UnitedStates(years=2022) - for name in ("Thanksgiving", "thanksgiving", "Thanksgivi"): - self.assertEqual(1, len(us.get_named(name, lookup="icontains"))) - self.assertEqual([2022], list(us.years)) +class TestRepr(unittest.TestCase): + def test_country(self): + hb = CountryStub1() + self.assertEqual(repr(hb), "holidays.country_holidays('CS1')") - us = holidays.UnitedStates(observed=False, years=2022) - self.assertEqual(2, len(us.get_named("Independence Day", lookup="icontains"))) + hb = CountryStub1(subdiv="Subdiv1") + self.assertEqual(repr(hb), "holidays.country_holidays('CS1', subdiv='Subdiv1')") - def test_get_named_iexact(self): - us = holidays.UnitedStates(years=2020) - holidays_count = len(us.keys()) - self.assertEqual(holidays_count, len(us.keys())) + def test_market(self): + self.assertEqual(repr(MarketStub1()), "holidays.financial_holidays('MS1')") - for name in ("new year's day", "New Year's Day"): - self.assertIn(date(2020, 1, 1), us.get_named(name, lookup="iexact")) - for name in ("New Year Day", "New Year", "year", "NEW Year"): - self.assertNotIn(date(2020, 1, 1), us.get_named(name, lookup="iexact")) - us = holidays.UnitedStates(years=2022) - self.assertEqual(1, len(us.get_named("thanksgiving", lookup="iexact"))) - self.assertEqual(0, len(us.get_named("Thanksgivin", lookup="iexact"))) - self.assertEqual([2022], list(us.years)) +class TestSerialization(unittest.TestCase): + def setUp(self): + self.hb = CountryStub1() - us = holidays.UnitedStates(years=2022) - self.assertEqual(1, len(us.get_named("independence day", lookup="iexact"))) + def test_pickle(self): + dt = "2020-01-01" + self.assertIn(dt, self.hb) - def test_get_named_istartswith(self): - us = holidays.UnitedStates(years=2020) - holidays_count = len(us.keys()) - self.assertEqual(holidays_count, len(us.keys())) + loaded_holidays = pickle.loads(pickle.dumps(self.hb)) + self.assertEqual(loaded_holidays, self.hb) + self.assertIn(dt, self.hb) - for name in ("new year's", "New Year's", "New Year's day"): - self.assertIn(date(2020, 1, 1), us.get_named(name, lookup="istartswith")) - for name in ("New Year Day", "New Year holiday", "New Year's Day Holiday", "year"): - self.assertNotIn(date(2020, 1, 1), us.get_named(name, lookup="istartswith")) - us = holidays.UnitedStates(years=2022) - self.assertEqual(1, len(us.get_named("independence day", lookup="istartswith"))) +class TestSpecialHolidays(unittest.TestCase): + def setUp(self): + self.hb = CountryStub1() - def test_get_named_startswith(self): - us = holidays.UnitedStates(years=2020) - holidays_count = len(us.keys()) - self.assertEqual(holidays_count, len(us.keys())) + def test_populate_special_holidays(self): + self.assertSetEqual(self.hb.years, set()) - for name in ("New Year's", "New Year"): - self.assertIn(date(2020, 1, 1), us.get_named(name, lookup="startswith")) - for name in ("New Year Day", "New Year Holiday", "New Year's Day Holiday", "year"): - self.assertNotIn(date(2020, 1, 1), us.get_named(name, lookup="startswith")) + self.hb._populate(1111) + self.assertSetEqual(self.hb.years, {1111}) + self.assertIn("1111-01-01", self.hb) + self.assertIn("2222-02-02", self.hb) + self.assertIn("3333-02-02", self.hb) + self.assertSetEqual(self.hb.years, {1111, 2222, 3333}) - us = holidays.UnitedStates(years=2022) - self.assertEqual(2, len(us.get_named("Christmas", lookup="startswith"))) - self.assertEqual(1, len(us.get_named("Independence Day", lookup="startswith"))) - def test_get_named_lookup_invalid(self): - us = holidays.UnitedStates(years=2020) - self.assertRaises(AttributeError, lambda: us.get_named("Holiday name", lookup="invalid")) +class TestStandardMethods(unittest.TestCase): + def setUp(self): + self.hb = CountryStub1() + def test_append(self): + self.hb.append([date(2015, 4, 1), "2015-04-03"]) + self.hb.append(date(2015, 4, 6)) + self.hb.append("2015-04-07") + + for dt in ( + "2015-01-01", + "2015-04-01", + "2015-04-03", + "2015-04-06", + "2015-04-07", + "2015-12-25", + ): + self.assertIn(dt, self.hb) -class TestArgs(unittest.TestCase): - def setUp(self): - self.holidays = holidays.US() + for dt in ( + "2015-04-04", + "2015-04-05", + "2015-04-02", + ): + self.assertNotIn(dt, self.hb) - def test_country(self): - self.assertEqual(self.holidays.country, "US") - self.assertIn(date(2014, 7, 4), self.holidays) - self.assertNotIn(date(2014, 7, 1), self.holidays) - self.holidays = holidays.UnitedStates() - self.assertEqual(self.holidays.country, "US") - self.assertIn(date(2014, 7, 4), self.holidays) - self.assertNotIn(date(2014, 7, 1), self.holidays) - self.assertEqual(self.holidays.country, "US") - self.holidays = holidays.CA() - self.assertEqual(self.holidays.country, "CA") - self.assertEqual(self.holidays.subdiv, "ON") - self.assertIn(date(2014, 7, 1), self.holidays) - self.assertNotIn(date(2014, 7, 4), self.holidays) - self.holidays = holidays.CA(subdiv="BC") - self.assertEqual(self.holidays.country, "CA") - self.assertEqual(self.holidays.subdiv, "BC") - self.assertIn(date(2014, 7, 1), self.holidays) - self.assertNotIn(date(2014, 7, 4), self.holidays) + def test_bool(self): + self.assertFalse(self.hb) + self.assertEqual(bool(self.hb), False) + self.assertEqual(len(self.hb), 0) - def test_years(self): - self.assertEqual(len(self.holidays.years), 0) - self.assertNotIn(date(2014, 1, 2), self.holidays) - self.assertEqual(len(self.holidays.years), 1) - self.assertIn(2014, self.holidays.years) - self.assertNotIn(date(2013, 1, 2), self.holidays) - self.assertNotIn(date(2014, 1, 2), self.holidays) - self.assertNotIn(date(2015, 1, 2), self.holidays) - self.assertEqual(len(self.holidays.years), 3) - self.assertIn(2013, self.holidays.years) - self.assertIn(2015, self.holidays.years) - self.holidays = holidays.US(years=range(2010, 2015 + 1)) - self.assertEqual(len(self.holidays.years), 6) - self.assertNotIn(2009, self.holidays.years) - self.assertIn(2010, self.holidays.years) - self.assertIn(2015, self.holidays.years) - self.assertNotIn(2016, self.holidays.years) - self.holidays = holidays.US(years=(2013, 2015, 2015)) - self.assertEqual(len(self.holidays.years), 2) - self.assertIn(2013, self.holidays.years) - self.assertNotIn(2014, self.holidays.years) - self.assertIn(2015, self.holidays.years) - self.assertIn(date(2021, 12, 31), holidays.US(years=[2021]).keys()) - self.holidays = holidays.US(years=2015) - self.assertNotIn(2014, self.holidays.years) - self.assertIn(2015, self.holidays.years) + self.assertIn("2014-01-01", self.hb) + self.assertTrue(self.hb) + self.assertEqual(bool(self.hb), True) + self.assertNotEqual(len(self.hb), 0) - def test_expand(self): - self.holidays = holidays.US(years=(2013, 2015), expand=False) - self.assertEqual(len(self.holidays.years), 2) - self.assertIn(2013, self.holidays.years) - self.assertNotIn(2014, self.holidays.years) - self.assertIn(2015, self.holidays.years) - self.assertNotIn(date(2014, 1, 1), self.holidays) - self.assertEqual(len(self.holidays.years), 2) - self.assertNotIn(2014, self.holidays.years) + def test_contains(self): + self.assertIn("2014-01-01", self.hb) + self.assertNotIn("2014-01-03", self.hb) - def test_observed(self): - self.holidays = holidays.US(observed=False) - self.assertIn(date(2000, 1, 1), self.holidays) - self.assertNotIn(date(1999, 12, 31), self.holidays) - self.assertIn(date(2012, 1, 1), self.holidays) - self.assertNotIn(date(2012, 1, 2), self.holidays) - self.holidays.observed = True - self.assertIn(date(2000, 1, 1), self.holidays) - self.assertIn(date(1999, 12, 31), self.holidays) - self.assertIn(date(2012, 1, 1), self.holidays) - self.assertIn(date(2012, 1, 2), self.holidays) - self.holidays.observed = False - self.assertIn(date(2000, 1, 1), self.holidays) - self.assertNotIn(date(1999, 12, 31), self.holidays) - self.assertIn(date(2012, 1, 1), self.holidays) - self.assertNotIn(date(2012, 1, 2), self.holidays) - self.holidays = holidays.US(years=[2022], observed=False) - self.assertNotIn(date(2021, 12, 31), self.holidays.keys()) - - self.holidays = holidays.CA(observed=False) - self.assertNotIn(date(1878, 7, 3), self.holidays) - self.holidays.observed = True - self.assertIn(date(2018, 7, 2), self.holidays) - - def test_serialization(self): - dt = datetime(2020, 1, 1) - self.assertIn(dt, self.holidays) - - loaded_holidays = pickle.loads(pickle.dumps(self.holidays)) - self.assertEqual(loaded_holidays, self.holidays) - self.assertIn(dt, self.holidays) - - def test_deprecation_warnings(self): - with self.assertWarns(Warning): - holidays.US(prov="AL") + def test_copy(self): + hb = CountryStub1() + self.assertEqual(hb, hb.copy()) - with self.assertWarns(Warning): - holidays.US(state="WY") + hb_fr = CountryStub1(language="fr") + hb_xx = CountryStub1(language="xx") + self.assertNotEqual(hb, hb_fr) + self.assertNotEqual(hb.copy(), hb_fr.copy()) - def test_categories(self): - self.assertRaises( - NotImplementedError, lambda: holidays.country_holidays("AT", categories={"HOME"}) - ) + self.assertNotEqual(hb, hb_xx) + self.assertNotEqual(hb.copy(), hb_xx.copy()) + def test_get(self): + self.assertEqual(self.hb.get("2014-01-01"), "New Year's Day") + self.assertIsNone(self.hb.get("2014-01-03")) + self.assertFalse(self.hb.get("2014-01-03", False)) + self.assertTrue(self.hb.get("2014-01-03", True)) -class TestKeyTransforms(unittest.TestCase): - def setUp(self): - self.holidays = holidays.US() + def test_getattr(self): + self.hb._populate(2023) - def test_date(self): - self.assertIn(date(2014, 1, 1), self.holidays) - self.assertEqual(self.holidays[date(2014, 1, 1)], "New Year's Day") - self.holidays[date(2014, 1, 3)] = "Fake Holiday" - self.assertIn(date(2014, 1, 3), self.holidays) - self.assertEqual(self.holidays.pop(date(2014, 1, 3)), "Fake Holiday") - self.assertNotIn(date(2014, 1, 3), self.holidays) - - def test_date_derived(self): - class CustomDate(date): - pass + name = "Test" + self.assertEqual(self.hb._add_holiday_3rd_mon_of_jun(name), date(2023, 6, 19)) + self.assertEqual(self.hb._add_holiday_4th_fri_of_aug(name), date(2023, 8, 25)) + self.assertEqual(self.hb._add_holiday_1st_wed_of_aug(name), date(2023, 8, 2)) + self.assertEqual(self.hb._add_holiday_1st_mon_before_may_24(name), date(2023, 5, 22)) + self.assertEqual(self.hb._add_holiday_1st_sun_from_aug_31(name), date(2023, 9, 3)) + + self.assertRaises(ValueError, lambda: self.hb._add_holiday_5th_fri_of_aug(name)) + self.assertRaises(AttributeError, lambda: self.hb._add_holiday_4th_nam_of_aug(name)) + self.assertRaises(AttributeError, lambda: self.hb._add_holiday_nam_12(name)) + self.assertRaises(AttributeError, lambda: self.hb._add_holiday_1st_fri_before_nam_29(name)) + self.assertRaises(AttributeError, lambda: self.hb._add_holiday_1st_fri_random_jan_29(name)) - self.assertIn(CustomDate(2014, 1, 1), self.holidays) - self.assertNotIn(CustomDate(2014, 1, 3), self.holidays) + def test_getitem(self): + self.assertEqual(self.hb["2014-01-01"], "New Year's Day") + self.assertEqual(self.hb.get("2014-01-01"), "New Year's Day") + self.assertIsNone(self.hb.get("2014-01-03")) + self.assertRaises(KeyError, lambda: self.hb["2014-01-03"]) - def test_datetime(self): - self.assertIn(datetime(2014, 1, 1, 13, 45), self.holidays) - self.assertEqual( - self.holidays[datetime(2014, 1, 1, 13, 45)], - "New Year's Day", + self.assertListEqual(self.hb["2013-12-31":"2014-01-02"], [date(2014, 1, 1)]) + self.assertListEqual( + self.hb["2013-12-24":"2014-01-02"], [date(2013, 12, 25), date(2014, 1, 1)] ) - self.holidays[datetime(2014, 1, 3, 1, 1)] = "Fake Holiday" - self.assertIn(datetime(2014, 1, 3, 2, 2), self.holidays) - self.assertEqual( - self.holidays.pop(datetime(2014, 1, 3, 4, 4)), - "Fake Holiday", + self.assertListEqual(self.hb["2013-12-25":"2014-01-02":3], [date(2013, 12, 25)]) + self.assertListEqual( + self.hb["2013-12-25":"2014-01-02":7], [date(2013, 12, 25), date(2014, 1, 1)] ) - self.assertNotIn(datetime(2014, 1, 3, 2, 2), self.holidays) - - def test_timestamp(self): - self.assertIn(1388552400, self.holidays) - self.assertEqual(self.holidays[1388552400], "New Year's Day") - self.assertIn(1388552400.01, self.holidays) - self.assertEqual(self.holidays[1388552400.01], "New Year's Day") - self.holidays[1388725200] = "Fake Holiday" - self.assertIn(1388725201, self.holidays) - self.assertEqual(self.holidays.pop(1388725202), "Fake Holiday") - self.assertNotIn(1388725201, self.holidays) - - def test_string(self): - self.assertIn("2014-01-01", self.holidays) - self.assertEqual(self.holidays["2014-01-01"], "New Year's Day") - self.assertIn("01/01/2014", self.holidays) - self.assertEqual(self.holidays["01/01/2014"], "New Year's Day") - self.holidays["01/03/2014"] = "Fake Holiday" - self.assertIn("01/03/2014", self.holidays) - self.assertEqual(self.holidays.pop("01/03/2014"), "Fake Holiday") - self.assertNotIn("01/03/2014", self.holidays) - - def test_exception(self): - self.assertRaises((TypeError, ValueError), lambda: "abc" in self.holidays) - self.assertRaises( - (TypeError, ValueError), - lambda: self.holidays.get("abc123"), + self.assertListEqual(self.hb["2014-01-02":"2013-12-30"], [date(2014, 1, 1)]) + self.assertListEqual(self.hb["2014-01-02":"2013-12-25"], [date(2014, 1, 1)]) + self.assertListEqual( + self.hb["2014-01-02":"2013-12-24"], [date(2014, 1, 1), date(2013, 12, 25)] ) - self.assertRaises(TypeError, lambda: self.holidays.get({"123"})) - self.assertRaises( - (TypeError, ValueError), - self.holidays.__setitem__, - "abc", - "Test", + self.assertListEqual(self.hb["2014-01-01":"2013-12-24":3], [date(2014, 1, 1)]) + self.assertListEqual( + self.hb["2014-01-01":"2013-12-24":7], + [date(2014, 1, 1), date(2013, 12, 25)], ) - self.assertRaises((TypeError, ValueError), lambda: {} in self.holidays) + self.assertListEqual(self.hb["2013-12-31":"2014-01-02":-3], []) + self.assertListEqual(self.hb["2014-01-01" : "2013-12-24" : td(days=3)], [date(2014, 1, 1)]) + self.assertListEqual( + self.hb["2014-01-01" : "2013-12-24" : td(days=7)], + [date(2014, 1, 1), date(2013, 12, 25)], + ) + self.assertListEqual(self.hb["2013-12-31" : "2014-01-02" : td(days=3)], []) + self.assertRaises(ValueError, lambda: self.hb["2014-01-01":]) + self.assertRaises(ValueError, lambda: self.hb[:"2014-01-01"]) + self.assertRaises(TypeError, lambda: self.hb["2014-01-01":"2014-01-02":""]) + self.assertRaises(ValueError, lambda: self.hb["2014-01-01":"2014-01-02":0]) -class TestCountryHolidayDeprecation(unittest.TestCase): - def test_deprecation(self): - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - h = holidays.CountryHoliday("IT") - self.assertIsInstance(h, holidays.HolidayBase) - self.assertEqual(1, len(w)) - self.assertTrue(issubclass(w[-1].category, DeprecationWarning)) + def test_radd(self): + self.assertRaises(TypeError, lambda: 1 + CountryStub1()) + def test_setitem(self): + self.assertEqual(len(self.hb), 0) + self.hb["2014-01-03"] = "Custom Holiday" + self.assertGreater(len(self.hb), 0) + self.assertIn("2014-01-03", self.hb) + self.assertEqual(self.hb["2014-01-03"], "Custom Holiday") -class TestCountrySpecialHolidays(unittest.TestCase): - def setUp(self): - self.us_holidays = holidays.country_holidays("US") + def test_update(self): + self.hb.update( + { + "2015-01-10": "Custom Holiday", + "2015-01-11": "Custom Holiday", + } + ) + self.assertIn("2015-01-10", self.hb) + self.assertIn("2015-01-11", self.hb) + self.assertEqual(self.hb["2015-01-10"], "Custom Holiday") + self.assertEqual(self.hb["2015-01-11"], "Custom Holiday") - def test_populate_special_holidays(self): - self.us_holidays._populate(1111) # special_holidays is empty. - self.assertEqual(0, len(self.us_holidays)) - - self.us_holidays.special_holidays = { - 1111: (JAN, 1, "Test holiday"), - 2222: (FEB, 2, "Test holiday"), - 3333: ((FEB, 2, "Test holiday")), - 4444: (), - } + self.hb.update( + { + date(2015, 1, 10): "New Holiday", + date(2015, 1, 11): "New Holiday", + } + ) + self.assertIn(date(2015, 1, 10), self.hb) + self.assertIn(date(2015, 1, 11), self.hb) + self.assertEqual(self.hb["2015-01-10"], "Custom Holiday; New Holiday") + self.assertEqual(self.hb["2015-01-11"], "Custom Holiday; New Holiday") - self.assertNotIn(3333, self.us_holidays.years) - self.assertIn("1111-01-01", self.us_holidays) - self.assertIn("2222-02-02", self.us_holidays) - self.assertIn("3333-02-02", self.us_holidays) - self.assertEqual(26, len(self.us_holidays)) +class TestStr(unittest.TestCase): + def test_country(self): + hb = CountryStub1() - self.us_holidays._populate(1111) - self.us_holidays._populate(2222) - self.us_holidays._populate(3333) - self.assertIn("1111-01-01", self.us_holidays) - self.assertIn("2222-02-02", self.us_holidays) - self.assertIn("3333-02-02", self.us_holidays) - self.assertEqual(26, len(self.us_holidays)) + self.assertEqual( + str(hb), + "{'country': CS1, 'expand': True, 'language': None, " + "'market': None, 'observed': True, 'subdiv': None, " + "'years': set()}", + ) + hb._populate(2013) + self.assertEqual( + str(hb), + '{datetime.date(2013, 1, 1): "New Year\'s Day", ' + "datetime.date(2013, 6, 19): 'Juneteenth National Independence Day', " + "datetime.date(2013, 7, 4): 'Independence Day', " + "datetime.date(2013, 11, 28): 'Thanksgiving', " + "datetime.date(2013, 12, 25): 'Christmas Day'}", + ) -class TestCountrySubstitutedHolidays(unittest.TestCase): - def setUp(self): - self.at_holidays = holidays.country_holidays("AT") - self.ua_holidays = holidays.country_holidays("UA", language="en_US") + def test_market(self): + self.assertEqual( + str(MarketStub1()), + "{'country': None, 'expand': True, 'language': None, " + "'market': MS1, 'observed': True, 'subdiv': None, " + "'years': set()}", + ) - def test_populate_substituted_holidays(self): - self.ua_holidays.substituted_holidays = { + +class TestSubstitutedHolidays(unittest.TestCase): + class SubstitutedHolidays(HolidayBase): + country = "HB" + substituted_holidays = { 1991: ( (JAN, 12, JAN, 7), (1991, JAN, 13, JAN, 8), ), } - self.ua_holidays._populate(1991) - self.assertIn("1991-01-07", self.ua_holidays) - self.assertIn("1991-01-08", self.ua_holidays) - self.assertIn("01/12/1991", self.ua_holidays["1991-01-07"]) - self.assertIn("01/13/1991", self.ua_holidays["1991-01-08"]) - - self.at_holidays.substituted_holidays = { - 1991: (JAN, 12, JAN, 7), - } - self.assertRaises(ValueError, lambda: self.at_holidays._populate(1991)) - self.at_holidays.substituted_label = "From %s" - self.assertRaises(ValueError, lambda: self.at_holidays._populate(1991)) - -class TestHolidaysTranslation(unittest.TestCase): - def test_language_unavailable(self): - os.environ["LANGUAGE"] = "en_US" - us_xx = holidays.country_holidays("CA", language="xx") - self.assertEqual(us_xx["2022-01-01"], "New Year's Day") - - os.environ["LANGUAGE"] = "pl" - pl_xx = holidays.country_holidays("PL", language="xx") - self.assertEqual(pl_xx["2022-01-01"], "Nowy Rok") + def test_populate_substituted_holidays(self): + hb = CountryStub1(years=1991) + self.assertIn("1991-01-07", hb) + self.assertIn("1991-01-08", hb) + self.assertIn("12/01/1991", hb["1991-01-07"]) + self.assertIn("13/01/1991", hb["1991-01-08"]) + + def test_no_substituted_date_format(self): + hb = self.SubstitutedHolidays() + hb.substituted_date_format = "%d/%m/%Y" + self.assertRaises(ValueError, lambda: hb._populate(1991)) + + def test_no_substituted_holidays(self): + hb = CountryStub1() + hb.substituted_holidays = {} + hb._populate(1991) + self.assertNotIn("1991-01-07", hb) + self.assertNotIn("1991-01-08", hb) + + def test_no_substituted_label(self): + hb = self.SubstitutedHolidays() + hb.substituted_label = "From %s" + self.assertRaises(ValueError, lambda: hb._populate(1991)) diff --git a/tests/test_l10n.py b/tests/test_l10n.py index 8c053f0f6..414044713 100644 --- a/tests/test_l10n.py +++ b/tests/test_l10n.py @@ -9,9 +9,11 @@ # Website: https://github.com/dr-prodigy/python-holidays # License: MIT (see LICENSE file) +import os import re import unittest from pathlib import Path +from unittest import mock from polib import pofile as create_po_file @@ -19,6 +21,18 @@ class TestLocalization(unittest.TestCase): + @mock.patch.dict(os.environ, {"LANGUAGE": "en_US"}) + def test_language_unavailable_en_us(self): + self.assertEqual(os.environ["LANGUAGE"], "en_US") + ca_xx = holidays.country_holidays("CA", language="xx") + self.assertEqual(ca_xx["2022-01-01"], "New Year's Day") + + @mock.patch.dict(os.environ, {"LANGUAGE": "pl"}) + def test_language_unavailable_pl(self): + self.assertEqual(os.environ["LANGUAGE"], "pl") + pl_xx = holidays.country_holidays("PL", language="xx") + self.assertEqual(pl_xx["2022-01-01"], "Nowy Rok") + def test_localization(self): tests_dir = Path(__file__).parent locale_dir = tests_dir.parent / "holidays" / "locale" diff --git a/tests/test_utils.py b/tests/test_utils.py index 109649163..d8e2c655d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -20,6 +20,7 @@ import holidays from holidays.utils import ( + CountryHoliday, country_holidays, financial_holidays, list_localized_countries, @@ -58,6 +59,14 @@ def test_exceptions(self): self.assertRaises(NotImplementedError, lambda: country_holidays("US", subdiv="XXXX")) self.assertRaises(NotImplementedError, lambda: country_holidays("US", subdiv="XXXX")) + def test_country_holiday_class_deprecation(self): + with warnings.catch_warnings(record=True) as ctx: + warnings.simplefilter("always") + CountryHoliday("IT") + warning = ctx[0] + self.assertTrue(issubclass(warning.category, DeprecationWarning)) + self.assertIn("CountryHoliday is deprecated", str(warning.message)) + class TestFinancialHolidays(unittest.TestCase): def setUp(self):