added parsers and parser composer for clean handling of storage blobs in the context of interpreting downloaded blobs
This commit is contained in:
parent
ea2d3223fb
commit
6e5af4092e
0
pyinfra/parser/__init__.py
Normal file
0
pyinfra/parser/__init__.py
Normal file
14
pyinfra/parser/blob_parser.py
Normal file
14
pyinfra/parser/blob_parser.py
Normal file
@ -0,0 +1,14 @@
|
||||
import abc
|
||||
|
||||
|
||||
class ParsingError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BlobParser(abc.ABC):
|
||||
@abc.abstractmethod
|
||||
def parse(self, blob: bytes):
|
||||
pass
|
||||
|
||||
def __call__(self, blob: bytes):
|
||||
return self.parse(blob)
|
||||
52
pyinfra/parser/parser_composer.py
Normal file
52
pyinfra/parser/parser_composer.py
Normal file
@ -0,0 +1,52 @@
|
||||
from funcy import rcompose
|
||||
|
||||
from pyinfra.parser.blob_parser import ParsingError
|
||||
|
||||
|
||||
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 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.parse(item)
|
||||
|
||||
|
||||
class EitherParserComposer:
|
||||
def __init__(self, *parsers):
|
||||
self.parser = rcompose(*map(EitherParserWrapper, parsers))
|
||||
|
||||
def parse(self, item):
|
||||
return self.parser(item).item
|
||||
|
||||
def __call__(self, item):
|
||||
return self.parse(item)
|
||||
0
pyinfra/parser/parsers/__init__.py
Normal file
0
pyinfra/parser/parsers/__init__.py
Normal file
7
pyinfra/parser/parsers/identity.py
Normal file
7
pyinfra/parser/parsers/identity.py
Normal file
@ -0,0 +1,7 @@
|
||||
from pyinfra.parser.blob_parser import BlobParser
|
||||
|
||||
|
||||
class IdentityBlobParser(BlobParser):
|
||||
|
||||
def parse(self, data: bytes):
|
||||
return data
|
||||
19
pyinfra/parser/parsers/json.py
Normal file
19
pyinfra/parser/parsers/json.py
Normal file
@ -0,0 +1,19 @@
|
||||
import json
|
||||
|
||||
from pyinfra.parser.blob_parser import BlobParser, ParsingError
|
||||
from pyinfra.server.packing import string_to_bytes
|
||||
|
||||
|
||||
class JsonBlobParser(BlobParser):
|
||||
|
||||
def parse(self, data: bytes):
|
||||
try:
|
||||
data = data.decode()
|
||||
data = json.loads(data)
|
||||
except (UnicodeDecodeError, json.JSONDecodeError, AttributeError) as err:
|
||||
raise ParsingError from err
|
||||
|
||||
if "data" in data:
|
||||
data["data"] = string_to_bytes(data["data"])
|
||||
|
||||
return data
|
||||
9
pyinfra/parser/parsers/string.py
Normal file
9
pyinfra/parser/parsers/string.py
Normal file
@ -0,0 +1,9 @@
|
||||
from pyinfra.parser.blob_parser import BlobParser, ParsingError
|
||||
|
||||
|
||||
class StringBlobParser(BlobParser):
|
||||
def parse(self, data: bytes):
|
||||
try:
|
||||
return data.decode()
|
||||
except Exception as err:
|
||||
raise ParsingError from err
|
||||
0
test/parser/__init__.py
Normal file
0
test/parser/__init__.py
Normal file
34
test/parser/parser_test.py
Normal file
34
test/parser/parser_test.py
Normal file
@ -0,0 +1,34 @@
|
||||
import json
|
||||
|
||||
from pyinfra.parser.parser_composer import EitherParserComposer
|
||||
from pyinfra.parser.parsers.identity import IdentityBlobParser
|
||||
from pyinfra.parser.parsers.json import JsonBlobParser
|
||||
from pyinfra.parser.parsers.string import StringBlobParser
|
||||
|
||||
|
||||
def test_json_parser():
|
||||
d = {"a": 1}
|
||||
assert JsonBlobParser()(json.dumps(d).encode()) == d
|
||||
|
||||
|
||||
def test_string_parser():
|
||||
a = "a"
|
||||
assert StringBlobParser()(a.encode()) == a
|
||||
|
||||
|
||||
def test_identity_parser():
|
||||
a = "a"
|
||||
assert IdentityBlobParser()(a.encode()) == a.encode()
|
||||
|
||||
|
||||
def test_either_parser_composer():
|
||||
parser = EitherParserComposer(JsonBlobParser(), StringBlobParser(), IdentityBlobParser())
|
||||
|
||||
d = {"a": 1}
|
||||
assert parser(json.dumps(d).encode()) == d
|
||||
|
||||
a = "a"
|
||||
assert parser(a.encode()) == a
|
||||
|
||||
a = 1
|
||||
assert parser(a) == a
|
||||
Loading…
x
Reference in New Issue
Block a user