4 Request = collections.namedtuple(
11 _Response = collections.namedtuple(
21 class Response(_Response):
22 def __new__(cls, content, **kwargs):
23 status = kwargs.pop('status', 200)
24 assert isinstance(status, int)
26 content_type = kwargs.pop('content_type')
27 assert isinstance(content_type, str)
29 extra_headers = kwargs.pop('extra_headers', ())
30 assert isinstance(extra_headers, tuple)
32 assert len(kwargs) == 0
34 return super().__new__(
37 content_type=content_type,
38 extra_headers=extra_headers,
45 ('Content-Type', self.content_type),
48 class HTMLResponse(Response):
49 def __new__(cls, content, **kwargs):
50 assert 'content_type' not in kwargs
52 return super().__new__(
55 content_type='text/html',
59 class JSONResponse(Response):
60 def __new__(cls, content_json, **kwargs):
61 assert 'content_type' not in kwargs
62 assert 'content' not in kwargs
64 self = super().__new__(
66 content=json.dumps(content_json),
67 content_type='application/json',
70 self.content_json = content_json
73 class TextResponse(Response):
74 def __new__(cls, content, **kwargs):
75 assert 'content_type' not in kwargs
77 return super().__new__(
80 content_type='text/plain',
84 def _get_status(response):
89 def _get_headers(response):
90 return list(response.headers)
92 def _get_content(response):
93 content = response.content
95 if isinstance(content, bytes):
98 if isinstance(content, str):
99 return (content.encode('utf-8'),)
104 def app(environ, start_fn):
105 response = handler(Request(environ))
107 start_fn(_get_status(response), _get_headers(response))
108 return _get_content(response)