Opa_omroep-automatiseren/venv/lib/python3.8/site-packages/holidays/holiday_base.py

231 lines
7.8 KiB
Python
Raw Normal View History

2020-12-27 20:00:11 +00:00
# -*- coding: utf-8 -*-
# python-holidays
# ---------------
# A fast, efficient Python library for generating country, province and state
# specific sets of holidays on the fly. It aims to make determining whether a
# specific date is a holiday as fast and flexible as possible.
#
# Author: ryanss <ryanssdev@icloud.com> (c) 2014-2017
# dr-prodigy <maurizio.montel@gmail.com> (c) 2017-2020
# Website: https://github.com/dr-prodigy/python-holidays
# License: MIT (see LICENSE file)
from datetime import timedelta, datetime, date
import six
from dateutil.parser import parse
class HolidayBase(dict):
PROVINCES = []
def __init__(self, years=[], expand=True, observed=True,
prov=None, state=None):
self.observed = observed
self.expand = expand
if isinstance(years, int):
years = [years, ]
self.years = set(years)
if not getattr(self, 'prov', False):
self.prov = prov
self.state = state
for year in list(self.years):
self._populate(year)
def __setattr__(self, key, value):
if key == 'observed' and len(self) > 0:
dict.__setattr__(self, key, value)
if value is True:
# Add (Observed) dates
years = list(self.years)
self.years = set()
self.clear()
for year in years:
self._populate(year)
else:
# Remove (Observed) dates
for k, v in list(self.items()):
if v.find("Observed") >= 0:
del self[k]
else:
return dict.__setattr__(self, key, value)
def __keytransform__(self, key):
if isinstance(key, datetime):
key = key.date()
elif isinstance(key, date):
key = key
elif isinstance(key, int) or isinstance(key, float):
key = datetime.utcfromtimestamp(key).date()
elif isinstance(key, six.string_types):
try:
key = parse(key).date()
except (ValueError, OverflowError):
raise ValueError("Cannot parse date from string '%s'" % key)
else:
raise TypeError("Cannot convert type '%s' to date." % type(key))
if self.expand and key.year not in self.years:
self.years.add(key.year)
self._populate(key.year)
return key
def __contains__(self, key):
return dict.__contains__(self, self.__keytransform__(key))
def __getitem__(self, key):
if isinstance(key, slice):
if not key.start or not key.stop:
raise ValueError("Both start and stop must be given.")
start = self.__keytransform__(key.start)
stop = self.__keytransform__(key.stop)
if key.step is None:
step = 1
elif isinstance(key.step, timedelta):
step = key.step.days
elif isinstance(key.step, int):
step = key.step
else:
raise TypeError(
"Cannot convert type '%s' to int." % type(key.step)
)
if step == 0:
raise ValueError('Step value must not be zero.')
date_diff = stop - start
if date_diff.days < 0 <= step or date_diff.days >= 0 > step:
step *= -1
days_in_range = []
for delta_days in range(0, date_diff.days, step):
day = start + timedelta(days=delta_days)
try:
dict.__getitem__(
self,
day
)
days_in_range.append(day)
except KeyError:
pass
return days_in_range
return dict.__getitem__(self, self.__keytransform__(key))
def __setitem__(self, key, value):
if key in self:
if self.get(key).find(value) < 0 \
and value.find(self.get(key)) < 0:
value = "%s, %s" % (value, self.get(key))
else:
value = self.get(key)
return dict.__setitem__(self, self.__keytransform__(key), value)
def update(self, *args):
args = list(args)
for arg in args:
if isinstance(arg, dict):
for key, value in list(arg.items()):
self[key] = value
elif isinstance(arg, list):
for item in arg:
self[item] = "Holiday"
else:
self[arg] = "Holiday"
def append(self, *args):
return self.update(*args)
def get(self, key, default=None):
return dict.get(self, self.__keytransform__(key), default)
def get_list(self, key):
return [h for h in self.get(key, "").split(", ") if h]
def get_named(self, name):
# find all dates matching provided name (accepting partial
# strings too, case insensitive), returning them in a list
matches = [key for key in self if name.lower() in self[key].lower()]
return matches
def pop(self, key, default=None):
if default is None:
return dict.pop(self, self.__keytransform__(key))
return dict.pop(self, self.__keytransform__(key), default)
def pop_named(self, name):
to_pop = self.get_named(name)
if not to_pop:
raise KeyError(name)
for key in to_pop:
self.pop(key)
return to_pop
def __eq__(self, other):
return dict.__eq__(self, other) and self.__dict__ == other.__dict__
def __ne__(self, other):
return dict.__ne__(self, other) or self.__dict__ != other.__dict__
def __add__(self, other):
if isinstance(other, int) and other == 0:
# Required to sum() list of holidays
# sum([h1, h2]) is equivalent to (0 + h1 + h2)
return self
elif not isinstance(other, HolidayBase):
raise TypeError()
HolidaySum = createHolidaySum(self, other)
country = (getattr(self, 'country', None) or
getattr(other, 'country', None))
if self.country and other.country and self.country != other.country:
c1 = self.country
if not isinstance(c1, list):
c1 = [c1]
c2 = other.country
if not isinstance(c2, list):
c2 = [c2]
country = c1 + c2
prov = getattr(self, 'prov', None) or getattr(other, 'prov', None)
if self.prov and other.prov and self.prov != other.prov:
p1 = self.prov if isinstance(self.prov, list) else [self.prov]
p2 = other.prov if isinstance(other.prov, list) else [other.prov]
prov = p1 + p2
return HolidaySum(years=(self.years | other.years),
expand=(self.expand or other.expand),
observed=(self.observed or other.observed),
country=country, prov=prov)
def __radd__(self, other):
return self.__add__(other)
def _populate(self, year):
pass
def createHolidaySum(h1, h2):
class HolidaySum(HolidayBase):
def __init__(self, country, **kwargs):
self.country = country
self.holidays = []
if getattr(h1, 'holidays', False):
for h in h1.holidays:
self.holidays.append(h)
else:
self.holidays.append(h1)
if getattr(h2, 'holidays', False):
for h in h2.holidays:
self.holidays.append(h)
else:
self.holidays.append(h2)
HolidayBase.__init__(self, **kwargs)
def _populate(self, year):
for h in self.holidays[::-1]:
h._populate(year)
self.update(h)
return HolidaySum