class KWArgsHandler[_VT]:
	type __allowedKeywordsType = str |\
		tuple[str, type | tuple[type, ...]] |\
		tuple[str, type | tuple[type, ...], object]

	def __init__(
			self,
			kwargs: dict[str, _VT],
			*allowedKeywords: __allowedKeywordsType
	) -> None:
		r"""
		Handles Keyword Arguments for a function
		:param kwargs:
		:param allowedKeywords:
		:raises ValueError: Invalid format for 'allowedKeywords' or disallowed keyword in 'kwargs'
		:raises TypeError: Invalid value type for keyword in 'kwargs'
		"""
		allowedKeywords_: dict[str, tuple[type | tuple[type, ...], object]] = {}
		self.kwargs = {}
		for kw in allowedKeywords:
			if isinstance(kw, tuple) and len(kw) in (2, 3):
				keyword, argType = kw[:2]
				defValue = kw[2] if len(kw) == 3 else None
				allowedKeywords_[keyword] = (argType, defValue)
			elif isinstance(kw, str):
				allowedKeywords_[kw] = (object, None)
			else:
				raise ValueError('Invalid format for allowedKeywords. \n'
				                 'Use either ("keyword", type, defaultValue) ("keyword", type) or "keyword".')
		for keyword, value in kwargs.items():
			if keyword not in allowedKeywords_:
				raise ValueError(f"Invalid keyword '{keyword}' provided.")
			if not isinstance(value, expVT := allowedKeywords_[keyword][0]):
				raise TypeError(
					f"Invalid type for keyword '{keyword}'. Expected {
						expVT.__name__ 
						if not isinstance(expVT, tuple) 
						else f"({" | ".join([vt.__name__ for vt in expVT])})"
					}, got {type(value).__name__}"
				)

		for keyword, (valueType, defValue) in allowedKeywords_.items():
			value = kwargs.get(keyword, defValue)
			if keyword not in allowedKeywords_:
				raise ValueError(f"Invalid keyword '{keyword}' provided.")
			if valueType is not None and not isinstance(value, valueType):
				raise TypeError(
					f"Invalid type for keyword '{keyword}'. Expected {
						valueType.__name__ if not isinstance(valueType, tuple) else (vt.__name__ for vt in valueType)
					}, got {type(value).__name__}.")
			self.kwargs[keyword] = value

	def __getattr__(self, attr) -> _VT:
		if attr in self.kwargs:
			return self.kwargs[attr]
		raise AttributeError(f"'KWArgsHandler' object has no attribute '{attr}'.")

	def __getitem__(self, item):
		if isinstance(item, int):
			raise IndexError("KWArgsHandler does not support indexing!")
		elif not isinstance(item, str):
			raise KeyError("KWArgsHandler only supports keys of type 'str'!")
		if item in self.kwargs:
			return self.kwargs[item]
		raise KeyError(f"KWArgsHandler object has no attribute '{item}'")

	def __repr__(self) -> str:
		return f"KWArgsHandler: {self.kwargs}"