from typing import cast import logging import json import urllib.request import http.client import urllib.parse logger = logging.getLogger(__name__) class Response(http.client.HTTPResponse): @classmethod def tune(cls, resp: http.client.HTTPResponse) -> 'Response': resp.__class__ = cls return cast(Response, resp) def json(self): return json.loads(self.read().decode('utf-8')) class SimpleRequestor: def __init__(self, base_url): self.base_url = base_url def request(self, method, path, params=None, data=None, headers=None) -> Response: headers = headers or {} path = f'{self.base_url}{path}' if params: path = f'{path}?{urllib.parse.urlencode(params)}' req = urllib.request.Request( url=path, method=method.upper(), data=json.dumps(data).encode('utf-8') if data else None, headers=headers, ) if data and not req.get_header('Content-Type'): req.add_header('Content-Type', 'application/json') logger.info(f'{method} {req.full_url} with headers: {req.headers!r} and body: {req.data!r}') return Response.tune(urllib.request.urlopen(req)) if __name__ == '__main__': import logging logging.basicConfig(level=logging.INFO) requestor = SimpleRequestor('https://httpbin.org/') requestor.request('GET', 'anything', params={"limit": 10}) resp = requestor.request('POST', 'anything', params={"a": 1}, data={"a": 2}) print('Response:', resp.json())