homeassistant-config/custom_components/ics_calendar/filter.py

125 lines
4.3 KiB
Python

"""Provide Filter class."""
import re
from ast import literal_eval
from typing import List, Optional, Pattern
from homeassistant.components.calendar import CalendarEvent
class Filter:
"""Filter class.
The Filter class is used to filter events according to the exclude and
include rules.
"""
def __init__(self, exclude: str, include: str):
"""Construct Filter class.
:param exclude: The exclude rules
:type exclude: str
:param include: The include rules
:type include: str
"""
self._exclude = Filter.set_rules(exclude)
self._include = Filter.set_rules(include)
@staticmethod
def set_rules(rules: str) -> List[Pattern]:
"""Set the given rules into an array which is returned.
:param rules: The rules to set
:type rules: str
:return: An array of regular expressions
:rtype: List[Pattern]
"""
arr = []
if rules != "":
for rule in literal_eval(rules):
if rule.startswith("/"):
re_flags = re.NOFLAG
[expr, flags] = rule[1:].split("/")
for flag in flags:
match flag:
case "i":
re_flags |= re.IGNORECASE
case "m":
re_flags |= re.MULTILINE
case "s":
re_flags |= re.DOTALL
arr.append(re.compile(expr, re_flags))
else:
arr.append(re.compile(rule, re.IGNORECASE))
return arr
def _is_match(
self, summary: str, description: Optional[str], regexes: List[Pattern]
) -> bool:
"""Indicate if the event matches the given list of regular expressions.
:param summary: The event summary to examine
:type summary: str
:param description: The event description summary to examine
:type description: Optional[str]
:param regexes: The regular expressions to match against
:type regexes: List[]
:return: True if the event matches the exclude filter
:rtype: bool
"""
for regex in regexes:
if regex.search(summary) or (
description and regex.search(description)
):
return True
return False
def _is_excluded(self, summary: str, description: Optional[str]) -> bool:
"""Indicate if the event should be excluded.
:param summary: The event summary to examine
:type summary: str
:param description: The event description summary to examine
:type description: Optional[str]
:return: True if the event matches the exclude filter
:rtype: bool
"""
return self._is_match(summary, description, self._exclude)
def _is_included(self, summary: str, description: Optional[str]) -> bool:
"""Indicate if the event should be included.
:param summary: The event summary to examine
:type summary: str
:param description: The event description summary to examine
:type description: Optional[str]
:return: True if the event matches the include filter
:rtype: bool
"""
return self._is_match(summary, description, self._include)
def filter(self, summary: str, description: Optional[str]) -> bool:
"""Check if the event should be included or not.
:param summary: The event summary to examine
:type summary: str
:param description: The event description summary to examine
:type description: Optional[str]
:return: true if the event should be included, otherwise false
:rtype: bool
"""
add_event = not self._is_excluded(summary, description)
if not add_event:
add_event = self._is_included(summary, description)
return add_event
def filter_event(self, event: CalendarEvent) -> bool:
"""Check if the event should be included or not.
:param event: The event to examine
:type event: CalendarEvent
:return: true if the event should be included, otherwise false
:rtype: bool
"""
return self.filter(event.summary, event.description)