125 lines
4.3 KiB
Python
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)
|