Due to how the holidays
package is structured, you will indeed have to iterate through all the supported regions. The function holidays.list_supported_countries
can help you with this. The good news is that you can do direct lookup in a country object without having to manually search through the dict items:
list_of_holidays = []
target = date.today()
for country in holidays.list_supported_countries():
country = getattr(holidays, country)()
holiday = country.get(target)
if holiday is not None:
list_of_holidays.append((holiday, country.country))
You can write this as a comprehension in versions of python that support the walrus operator:
list_of_holidays = [(c[target], c.country) for country in holidays.list_supported_countries()
if target in (c := getattr(holidays, country)())]
The problem is that there will be a lot of duplicates here, because almost every supported country has multiple ways to reference it. This is also an issue because you do not want to generate the same list over and over on the fly.
On inspecting the library, I find that the most reliable way to check if the country class is "real" is to check if it introduces any new holidays via the _populate
method. You can add the condition for that with:
list_of_holidays = []
target = date.today()
for country in holidays.list_supported_countries():
country_obj = getattr(holidays, country)
country = country_obj()
holiday = country.get(target)
if holiday is not None and '_populate' in country_obj.__dict__:
list_of_holidays.append((holiday, country.country))
Or as a comprehension:
list_of_holidays = [(c[target], c.country) for country in holidays.list_supported_countries()
if target in (c := getattr(holidays, country)()) and '_populate' in c.__class__.__dict__]
Finally, the country code is always given as the name when you use the country
attribute. If you want something more legible, I find it's better to use the name of the class that implements the _populate
method. For the second loop, replace (holiday, country.country)
with
(holiday, country_obj.__name__)
For the second list comprehension, replace (c[target], c.country)
with
(c[target], c.__class__.__name__)