vacanza/holidays

TypeError: ObservedHolidayBase._add_observed() got an unexpected keyword argument 'before'

Closed this issue · 6 comments

this test code was working fine under 0.27.1 (where the method was still named _add_with_observed()) but now with the latest 0.37 it complains about 'unexpected argument' as in the title.
what is the new way of adding custom holidays so they can only be pushed forward?

from holidays.countries import US
from holidays.constants import JAN, JUL

class MyCivilHolidays(US):
    def _populate(self, year):
        super()._populate(year)
        self.pop_named('New Year')
        self.pop_named('Independence')

        self._add_observed(date(year, JAN, 1), "New Year's Day", before=False) # strictly no backtracks to friday
        self._add_observed(date(year, JUL, 4), 'Independence Day', before=False) # if these fall on saturday then they must be pushed to monday

my_holidays = MyCivilHolidays()

date(2024, 1, 1) in my_holidays```

Yes, code for observed holidays handling has been significantly changed and unified.

If you want to exactly implement the behavior of before=False parameter, you need code like:

from holidays.countries import US
from holidays.observed_holiday_base import ObservedHolidayBase, SUN_TO_NEXT_MON

class MyCivilHolidays(US):
    def _populate(self, year):
        super()._populate(year)
        self.pop_named("New Year")
        self.pop_named("Independence")

        self._add_observed(self._add_new_years_day("New Year's Day"), rule=SUN_TO_NEXT_MON)
        self._add_observed(self._add_holiday_jul_4("Independence Day"), rule=SUN_TO_NEXT_MON)

But when holiday falls on a Saturday, there will be no observed at all.

If it should be exactly as comment says, "if these fall on saturday then they must be pushed to monday", then code should be like:

from holidays.countries import US
from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_MON

class MyCivilHolidays(US):
    def _populate(self, year):
        super()._populate(year)
        self.pop_named("New Year")
        self.pop_named("Independence")

        self._add_observed(self._add_new_years_day("New Year's Day"), rule=SAT_SUN_TO_NEXT_MON)
        self._add_observed(self._add_holiday_jul_4("Independence Day"), rule=SAT_SUN_TO_NEXT_MON)

this works, thanks.

btw, what are those methods _add_new_years_day() and _add_holiday_jul_4()?
if i wanted to add ninja turtle day is there a special method for that? or can i just name these things whatever on the fly?

No, those are predefined methods. However, their nature differs a bit. While _add_new_years_day() is part of international holidays group the _add_holiday_jul_4() is a syntactic sugar method handled by HolidayBase::__getattr__() logic -- you can use _add_holiday_<3_letter_month_name>_<day_number>() for adding custom holidays.

but self._add_holiday_jul_13("Ninja Turtle Day") and self[date(year, 7, 13)] = "Ninja Turtle Day" still do the same thing, yes? or is the latter expected to be deprecated in the future?

Right, both examples result in the same holidays object state as HolidayBase is a dict based object. I don't think the __setitem__ functionality is going to be deprecated so you can continue using it directly (self[date(year, 7, 13)] = "Ninja Turtle Day").

ok, thank you very much for this useful library