-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathservices.py
85 lines (63 loc) · 2.5 KB
/
services.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
from abc import ABC, abstractmethod
from functools import lru_cache
from json.decoder import JSONDecodeError
from typing import Iterable
from aiohttp import ClientSession, ClientResponse
class Service(ABC):
def __init__(self, endpoint: str):
self.endpoint = endpoint
@abstractmethod
async def request(self, session: ClientSession) -> str:
""" make request to service and parse response """
def __repr__(self, **kwargs):
extra = " ".join(f"{k}={v}" for k, v in kwargs.items())
return f'<{self.__class__.__name__} ' \
f'endpoint={self.endpoint}' \
f'{" " + extra if extra else ""}>'
class TextService(Service):
async def request(self, session: ClientSession) -> str:
response: ClientResponse = await session.get(self.endpoint)
return (await response.text()).strip()
class JSONService(Service):
def __init__(self, endpoint: str, path: str):
super().__init__(endpoint)
self.path = tuple(path.split())
async def request(self, session: ClientSession) -> str:
headers = {'Accept': 'application/json'}
response: ClientResponse = await session.get(self.endpoint,
headers=headers)
try:
payload = await response.json()
except JSONDecodeError as ex:
text = await response.text()
raise Exception(f'Unable to parse {text}') from ex
for p in self.path:
payload = payload[p]
return payload
def __repr__(self):
return super().__repr__(path=self.path)
_service_type_registry = {
'text': TextService,
'json': JSONService,
}
def parse_service(line: str) -> Service:
"""
>>> parse_service('text.com')
<TextService endpoint=text.com>
>>> parse_service('json.com json addr')
<JSONService endpoint=json.com path=('addr',)>
>>> parse_service('xml.com xml')
Traceback (most recent call last):
...
Exception: Error parsing service definition: xml.com xml
"""
endpoint, *extra = line.split(maxsplit=2)
content_type = extra.pop(0) if extra else 'text'
args = [extra.pop(0)] if extra else []
if content_type in _service_type_registry:
return _service_type_registry[content_type](endpoint, *args)
raise Exception(f'Error parsing service definition: {line}')
@lru_cache()
def services() -> Iterable[Service]:
with open('services.txt', 'r') as f:
return tuple(parse_service(line) for line in f)