pyinfra/pyinfra/parser/parser_composer.py

68 lines
1.5 KiB
Python

import logging
from funcy import rcompose
from pyinfra.parser.blob_parser import ParsingError
logger = logging.getLogger(__name__)
class Either:
def __init__(self, item):
self.item = item
def bind(self):
return self.item
class Left(Either):
pass
class Right(Either):
pass
class EitherParserWrapper:
def __init__(self, parser):
self.parser = parser
def __log(self, result):
if isinstance(result, Right):
logger.debug(f"{self.parser.__class__.__name__} succeeded or forwarded on {result.bind()}")
else:
logger.debug(f"{self.parser.__class__.__name__} failed on {result.bind()}")
return result
def parse(self, item: Either):
if isinstance(item, Left):
try:
return Right(self.parser(item.bind()))
except ParsingError:
return item
elif isinstance(item, Right):
return item
else:
return self.parse(Left(item))
def __call__(self, item):
return self.__log(self.parse(item))
class EitherParserComposer:
def __init__(self, *parsers):
self.parser = rcompose(*map(EitherParserWrapper, parsers))
def parse(self, item):
result = self.parser(item)
if isinstance(result, Right):
return result.bind()
else:
raise ParsingError("All parsers failed.")
def __call__(self, item):
return self.parse(item)