Added combined filter
This commit is contained in:
parent
ae8a1ddf34
commit
4d7a9be45f
|
@ -1,19 +1,18 @@
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
from configparser import SectionProxy
|
||||||
from typing import ClassVar, Dict, Type
|
from typing import ClassVar, Dict, Type
|
||||||
from mastoposter.types import Status
|
from mastoposter.types import Status
|
||||||
from re import Pattern, compile as regexp
|
from re import Pattern, compile as regexp
|
||||||
|
|
||||||
|
UNUSED = lambda *_: None # NOQA
|
||||||
|
|
||||||
|
|
||||||
class BaseFilter(ABC):
|
class BaseFilter(ABC):
|
||||||
FILTER_REGISTRY: ClassVar[Dict[str, Type["BaseFilter"]]] = {}
|
FILTER_REGISTRY: ClassVar[Dict[str, Type["BaseFilter"]]] = {}
|
||||||
FILTER_NAME_REGEX: Pattern = regexp(r"^([a-z_]+)$")
|
FILTER_NAME_REGEX: Pattern = regexp(r"^([a-z_]+)$")
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, section: SectionProxy):
|
||||||
pass
|
UNUSED(section)
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __call__(self, status: Status) -> bool:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def __init_subclass__(cls, filter_name: str, **kwargs):
|
def __init_subclass__(cls, filter_name: str, **kwargs):
|
||||||
super().__init_subclass__(**kwargs)
|
super().__init_subclass__(**kwargs)
|
||||||
|
@ -22,3 +21,10 @@ class BaseFilter(ABC):
|
||||||
if filter_name in cls.FILTER_REGISTRY:
|
if filter_name in cls.FILTER_REGISTRY:
|
||||||
raise KeyError(f"{filter_name=!r} is already registered")
|
raise KeyError(f"{filter_name=!r} is already registered")
|
||||||
cls.FILTER_REGISTRY[filter_name] = cls
|
cls.FILTER_REGISTRY[filter_name] = cls
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def __call__(self, status: Status) -> bool:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def post_init(self, filters: Dict[str, "BaseFilter"]):
|
||||||
|
UNUSED(filters)
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
from configparser import SectionProxy
|
||||||
|
from typing import Callable, ClassVar, Dict, List, NamedTuple
|
||||||
|
from functools import reduce
|
||||||
|
from mastoposter.filters.base import BaseFilter
|
||||||
|
from mastoposter.types import Status
|
||||||
|
|
||||||
|
|
||||||
|
class FilterType(NamedTuple):
|
||||||
|
inverse: bool
|
||||||
|
filter: BaseFilter
|
||||||
|
|
||||||
|
|
||||||
|
class CombinedFilter(BaseFilter, filter_name="combined"):
|
||||||
|
OPERATORS: ClassVar[Dict[str, Callable]] = {
|
||||||
|
"and": lambda a, b: a and b,
|
||||||
|
"or": lambda a, b: a or b,
|
||||||
|
"xor": lambda a, b: a ^ b,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, section: SectionProxy):
|
||||||
|
self.filter_names = section.get("filters", "").split()
|
||||||
|
self.operator = self.OPERATORS[section.get("operator", "and")]
|
||||||
|
self.filters: List[FilterType] = []
|
||||||
|
|
||||||
|
def post_init(self, filters: Dict[str, "BaseFilter"]):
|
||||||
|
super().post_init(filters)
|
||||||
|
for filter_name in self.filter_names:
|
||||||
|
self.filters.append(
|
||||||
|
FilterType(
|
||||||
|
filter_name[:1] in "~!", # inverse
|
||||||
|
filters[filter_name.rstrip("!~")],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __call__(self, status: Status) -> bool:
|
||||||
|
results = [fil.filter(status) ^ fil.inverse for fil in self.filters]
|
||||||
|
return reduce(self.operator, results)
|
Loading…
Reference in New Issue