Skip to content
This repository has been archived by the owner on May 31, 2019. It is now read-only.

Commit

Permalink
Replace header object with wsgiref.headers (#42)
Browse files Browse the repository at this point in the history
* Replace header handling with wsgiref.headers

* Fix type hintings

* Fix tests
  • Loading branch information
c-bata committed May 25, 2016
1 parent 3b50635 commit f3201ea
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 21 deletions.
27 changes: 12 additions & 15 deletions kobin/environs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from typing import Dict, List, Tuple, Any
import http.client as http_client
from urllib.parse import SplitResult
from http.cookies import SimpleCookie # type: ignore
from http.cookies import SimpleCookie
from wsgiref.headers import Headers # type: ignore


def _local_property():
Expand Down Expand Up @@ -152,17 +153,17 @@ class Response:

def __init__(self, body: str='', status: int=None, headers: Dict=None,
**more_headers) -> None:
self._headers = {} # type: Dict[str, List[str]]
self.headers = Headers()
self.body = body
self._status_code = status or self.default_status
self._cookies = SimpleCookie() # type: SimpleCookie

if headers:
for name, value in headers.items():
self.add_header(name, value)
self.headers.add_header(name, value)
if more_headers:
for name, value in more_headers.items():
self.add_header(name, value)
self.headers.add_header(name, value)

@property
def status_code(self):
Expand All @@ -187,12 +188,11 @@ def status(self, status_code: int):
def headerlist(self) -> List[Tuple[str, str]]:
""" WSGI conform list of (header, value) tuples. """
out = [] # type: List[Tuple[str, str]]
headers = list(self._headers.items())
if 'Content-Type' not in self._headers:
headers.append(('Content-Type', [self.default_content_type]))
out += [(name, val)
for (name, vals) in headers
for val in vals]
if 'Content-Type' not in self.headers:
self.headers.add_header('Content-Type', self.default_content_type)
out += [(key, value)
for key in self.headers.keys()
for value in self.headers.get_all(key)]
if self._cookies:
for c in self._cookies.values():
out.append(('Set-Cookie', c.OutputString()))
Expand Down Expand Up @@ -224,13 +224,10 @@ def delete_cookie(self, key, **kwargs) -> None:
kwargs['expires'] = 0
self.set_cookie(key, '', **kwargs)

def add_header(self, key: str, value: str) -> None:
self._headers.setdefault(key, []).append(value)

def apply(self, other):
self.status = other._status_code
self._headers = other._headers
self._cookies = other._cookies
self.headers = other.headers
self.body = other.body


Expand All @@ -240,7 +237,7 @@ class LocalResponse(Response):
"""
bind = Response.__init__
_status_code = _local_property()
_headers = _local_property()
headers = _local_property()
_cookies = _local_property()
body = _local_property()

Expand Down
2 changes: 1 addition & 1 deletion kobin/static_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ def static_file(filename: str,
headers["Accept-Ranges"] = "bytes"

for k, v in headers.items():
response.add_header(k, v)
response.headers.add_header(k, v)

return body
4 changes: 2 additions & 2 deletions tests/test_environs.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,15 @@ def test_delete_cookie(self):

def test_constructor_headerlist_has_already_content_type(self):
response = Response()
response.add_header('Content-Type', 'application/json')
response.headers.add_header('Content-Type', 'application/json')
expected_content_type = ('Content-Type', 'application/json')
self.assertIn(expected_content_type, response.headerlist)
expected_content_type = ('Content-Type', 'text/html; charset=UTF-8')
self.assertNotIn(expected_content_type, response.headerlist)

def test_add_header(self):
response = Response()
response.add_header('key', 'value')
response.headers.add_header('key', 'value')
self.assertIn(('key', 'value'), response.headerlist)

def test_constructor_headerlist_with_add_header(self):
Expand Down
10 changes: 7 additions & 3 deletions tests/test_static_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def setUp(self):
'STATIC_ROOT': '/static/',
'STATICFILES_DIRS': [os.path.join(os.path.dirname(os.path.abspath(__name__)), 'static')]
})
response.bind({})

def test_routing_to_static_file(self):
test_env = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/static/static.css'}
Expand All @@ -33,6 +34,9 @@ class StaticFilesTests(TestCase):
'STATICFILES_DIRS': [os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')]
}

def setUp(self):
response.bind({})

@patch('kobin.app.current_config')
def test_return_static_file(self, mock_current_config):
mock_current_config.return_value = self.dummy_current_config
Expand All @@ -49,20 +53,20 @@ def test_static_file_404_not_found(self, mock_current_config):
def test_exist_last_modified_in_headers(self, mock_current_config):
mock_current_config.return_value = self.dummy_current_config
static_file('static.css')
self.assertIn('Last-Modified', response._headers)
self.assertIn('Last-Modified', response.headers)

@patch('kobin.app.current_config')
def test_content_length(self, mock_current_config):
mock_current_config.return_value = self.dummy_current_config
expected_content_length = str(23)
static_file('static.css')
actual_content_length = response._headers['Content-Length']
actual_content_length = response.headers['Content-Length']
self.assertIn(expected_content_length, actual_content_length)

@patch('kobin.app.current_config')
def test_content_type(self, mock_current_config):
mock_current_config.return_value = self.dummy_current_config
expected_content_type = 'text/css; charset=UTF-8'
static_file('static.css')
actual_content_type = response._headers['Content-Type']
actual_content_type = response.headers['Content-Type']
self.assertIn(expected_content_type, actual_content_type)

0 comments on commit f3201ea

Please sign in to comment.