From 09d80fb7e06cbfbeb2e403dc5e18a6fa46faf13d Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 11:04:37 +0200 Subject: [PATCH 01/20] Supporting big files --- coreapi/codecs/base.py | 9 +++++++-- coreapi/codecs/download.py | 8 ++++++-- coreapi/transports/http.py | 5 +++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/coreapi/codecs/base.py b/coreapi/codecs/base.py index 6f20044..512b730 100644 --- a/coreapi/codecs/base.py +++ b/coreapi/codecs/base.py @@ -19,9 +19,14 @@ def dump(self, *args, **kwargs): # Fallback for v1.x interface return self.encode(*args, **kwargs) - def load(self, *args, **kwargs): + def support_streaming(self): + return False + + def load(self, chunks, *args, **kwargs): # Fallback for v1.x interface - return self.decode(*args, **kwargs) + if not(self.support_streaming): + chunks = bytes().join(chunks) or bytes() + return self.decode(chunks, *args, **kwargs) @property def supports(self): diff --git a/coreapi/codecs/download.py b/coreapi/codecs/download.py index 0995690..5023814 100644 --- a/coreapi/codecs/download.py +++ b/coreapi/codecs/download.py @@ -109,11 +109,14 @@ def __init__(self, download_dir=None): self._delete_on_close = download_dir is None self._download_dir = download_dir + def support_streaming(self): + return True + @property def download_dir(self): return self._download_dir - def decode(self, bytestring, **options): + def decode(self, chunks, **options): base_url = options.get('base_url') content_type = options.get('content_type') content_disposition = options.get('content_disposition') @@ -121,7 +124,8 @@ def decode(self, bytestring, **options): # Write the download to a temporary .download file. fd, temp_path = tempfile.mkstemp(suffix='.download') file_handle = os.fdopen(fd, 'wb') - file_handle.write(bytestring) + for chunk in chunks: + file_handle.write(chunk) file_handle.close() # Determine the output filename. diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index a548024..f4c2d5f 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -275,7 +275,8 @@ def _decode_result(response, decoders, force_codec=False): """ Given an HTTP response, return the decoded Core API document. """ - if response.content: + chunks = response.iter_content(1024) + if chunks: # Content returned in response. We should decode it. if force_codec: codec = decoders[0] @@ -291,7 +292,7 @@ def _decode_result(response, decoders, force_codec=False): if 'content-disposition' in response.headers: options['content_disposition'] = response.headers['content-disposition'] - result = codec.load(response.content, **options) + result = codec.load(chunks, **options) else: # No content returned in response. result = None From ce0b6be08a49b86f2ba1b2026af44aa51c6a9f72 Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 11:13:22 +0200 Subject: [PATCH 02/20] fix a bug --- coreapi/codecs/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/codecs/base.py b/coreapi/codecs/base.py index 512b730..80f6af2 100644 --- a/coreapi/codecs/base.py +++ b/coreapi/codecs/base.py @@ -24,7 +24,7 @@ def support_streaming(self): def load(self, chunks, *args, **kwargs): # Fallback for v1.x interface - if not(self.support_streaming): + if not(self.support_streaming()): chunks = bytes().join(chunks) or bytes() return self.decode(chunks, *args, **kwargs) From 4147bd999361b9a10a369fc272d34ba3fbc33082 Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 11:48:33 +0200 Subject: [PATCH 03/20] allowing streaming on action --- coreapi/client.py | 4 ++-- coreapi/transports/http.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/client.py b/coreapi/client.py index d02a59c..c021484 100644 --- a/coreapi/client.py +++ b/coreapi/client.py @@ -140,7 +140,7 @@ def reload(self, document, format=None, force_codec=False): return self.get(document.url, format=format, force_codec=force_codec) def action(self, document, keys, params=None, validate=True, overrides=None, - action=None, encoding=None, transform=None): + action=None, encoding=None, transform=None, stream=False): if (action is not None) or (encoding is not None) or (transform is not None): # Fallback for v1.x overrides. # Will be removed at some point, most likely in a 2.1 release. @@ -175,4 +175,4 @@ def action(self, document, keys, params=None, validate=True, overrides=None, # Perform the action, and return a new document. transport = determine_transport(self.transports, link.url) - return transport.transition(link, self.decoders, params=params, link_ancestors=link_ancestors) + return transport.transition(link, self.decoders, params=params, link_ancestors=link_ancestors, stream=stream) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index f4c2d5f..0026862 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -367,7 +367,7 @@ def __init__(self, credentials=None, headers=None, auth=None, session=None, requ def headers(self): return self._headers - def transition(self, link, decoders, params=None, link_ancestors=None, force_codec=False): + def transition(self, link, decoders, params=None, link_ancestors=None, force_codec=False, stream=False): session = self._session method = _get_method(link.action) encoding = _get_encoding(link.encoding) @@ -377,8 +377,8 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod headers.update(self.headers) request = _build_http_request(session, url, method, headers, encoding, params) - response = session.send(request) - result = _decode_result(response, decoders, force_codec) + with session.send(request, stream=stream) as response: + result = _decode_result(response, decoders, force_codec) if isinstance(result, Document) and link_ancestors: result = _handle_inplace_replacements(result, link, link_ancestors) From 552bce22c226ae94a57e5ced440512643bc4c39a Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 11:56:10 +0200 Subject: [PATCH 04/20] setting the stream part of the request --- coreapi/transports/http.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index 0026862..6644020 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -200,7 +200,7 @@ def _get_upload_headers(file_obj): } -def _build_http_request(session, url, method, headers=None, encoding=None, params=empty_params): +def _build_http_request(session, url, method, headers=None, encoding=None, params=empty_params, stream=False): """ Make an HTTP request and return an HTTP response. """ @@ -210,6 +210,7 @@ def _build_http_request(session, url, method, headers=None, encoding=None, param if params.query: opts['params'] = params.query + opts['stream'] = stream if params.data or params.files: if encoding == 'application/json': @@ -376,8 +377,8 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod headers = _get_headers(url, decoders) headers.update(self.headers) - request = _build_http_request(session, url, method, headers, encoding, params) - with session.send(request, stream=stream) as response: + request = _build_http_request(session, url, method, headers, encoding, params, stream=stream) + with session.send(request) as response: result = _decode_result(response, decoders, force_codec) if isinstance(result, Document) and link_ancestors: From a0efe9c7a8176c0a0b242818ce6d41af7ebd1371 Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 12:05:54 +0200 Subject: [PATCH 05/20] the stream should be part of the session --- coreapi/transports/http.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index 6644020..ce3e79b 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -200,7 +200,7 @@ def _get_upload_headers(file_obj): } -def _build_http_request(session, url, method, headers=None, encoding=None, params=empty_params, stream=False): +def _build_http_request(session, url, method, headers=None, encoding=None, params=empty_params): """ Make an HTTP request and return an HTTP response. """ @@ -210,7 +210,6 @@ def _build_http_request(session, url, method, headers=None, encoding=None, param if params.query: opts['params'] = params.query - opts['stream'] = stream if params.data or params.files: if encoding == 'application/json': @@ -227,7 +226,6 @@ def _build_http_request(session, url, method, headers=None, encoding=None, param opts['data'] = params.data upload_headers = _get_upload_headers(params.data) opts['headers'].update(upload_headers) - request = requests.Request(method, url, **opts) return session.prepare_request(request) @@ -377,8 +375,8 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod headers = _get_headers(url, decoders) headers.update(self.headers) - request = _build_http_request(session, url, method, headers, encoding, params, stream=stream) - with session.send(request) as response: + request = _build_http_request(session, url, method, headers, encoding, params) + with session.send(request, stream=True) as response: result = _decode_result(response, decoders, force_codec) if isinstance(result, Document) and link_ancestors: From 5b05715fa6b8c552589e663d81143dcaef32a7de Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 12:12:07 +0200 Subject: [PATCH 06/20] when mocking send we should get **kwargs since that is the signature of send --- coreapi/transports/http.py | 2 +- tests/test_transport.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index ce3e79b..fa9ba1d 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -376,7 +376,7 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod headers.update(self.headers) request = _build_http_request(session, url, method, headers, encoding, params) - with session.send(request, stream=True) as response: + with session.send(request, stream=stream) as response: result = _decode_result(response, decoders, force_codec) if isinstance(result, Document) and link_ancestors: diff --git a/tests/test_transport.py b/tests/test_transport.py index 09cb849..8187fd9 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -47,7 +47,7 @@ def test_missing_hostname(): # Test basic transition types. def test_get(monkeypatch, http): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') monkeypatch.setattr(requests.Session, 'send', mockreturn) @@ -58,7 +58,7 @@ def mockreturn(self, request): def test_get_with_parameters(monkeypatch, http): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): insert = request.path_url.encode('utf-8') return MockResponse( b'{"_type": "document", "url": "' + insert + b'"}' @@ -72,7 +72,7 @@ def mockreturn(self, request): def test_get_with_path_parameter(monkeypatch, http): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): insert = request.url.encode('utf-8') return MockResponse( b'{"_type": "document", "example": "' + insert + b'"}' @@ -90,7 +90,7 @@ def mockreturn(self, request): def test_post(monkeypatch, http): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): codec = CoreJSONCodec() body = force_text(request.body) content = codec.encode(Document(content={'data': json.loads(body)})) @@ -104,7 +104,7 @@ def mockreturn(self, request): def test_delete(monkeypatch, http): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): return MockResponse(b'') monkeypatch.setattr(requests.Session, 'send', mockreturn) From b5977389ec8be05ed2380e479097c090cf4f791e Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 12:29:19 +0200 Subject: [PATCH 07/20] fixing test to support streaming --- coreapi/transports/http.py | 5 +++-- tests/test_integration.py | 14 ++++++++++---- tests/test_transitions.py | 2 +- tests/test_transport.py | 5 +++++ 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index fa9ba1d..ea7d999 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -376,8 +376,9 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod headers.update(self.headers) request = _build_http_request(session, url, method, headers, encoding, params) - with session.send(request, stream=stream) as response: - result = _decode_result(response, decoders, force_codec) + response = session.send(request, stream=stream) + result = _decode_result(response, decoders, force_codec) + response.close() if isinstance(result, Document) and link_ancestors: result = _handle_inplace_replacements(result, link, link_ancestors) diff --git a/tests/test_integration.py b/tests/test_integration.py index b38de9a..04d889a 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -23,6 +23,12 @@ def __init__(self, content): self.url = 'http://example.org' self.status_code = 200 + def iter_content(self, *args, **kwargs): + return self.content + + def close(self): + return + # Basic integration tests. @@ -41,7 +47,7 @@ def test_dump(document): def test_get(monkeypatch): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') monkeypatch.setattr(requests.Session, 'send', mockreturn) @@ -52,7 +58,7 @@ def mockreturn(self, request): def test_follow(monkeypatch, document): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') monkeypatch.setattr(requests.Session, 'send', mockreturn) @@ -63,7 +69,7 @@ def mockreturn(self, request): def test_reload(monkeypatch): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') monkeypatch.setattr(requests.Session, 'send', mockreturn) @@ -75,7 +81,7 @@ def mockreturn(self, request): def test_error(monkeypatch, document): - def mockreturn(self, request): + def mockreturn(self, request, **kwargs): return MockResponse(b'{"_type": "error", "message": ["failed"]}') monkeypatch.setattr(requests.Session, 'send', mockreturn) diff --git a/tests/test_transitions.py b/tests/test_transitions.py index a31ba13..e2b6a57 100644 --- a/tests/test_transitions.py +++ b/tests/test_transitions.py @@ -8,7 +8,7 @@ class MockTransport(HTTPTransport): schemes = ['mock'] - def transition(self, link, decoders, params=None, link_ancestors=None): + def transition(self, link, decoders, params=None, link_ancestors=None, stream=True): if link.action == 'get': document = Document(title='new', content={'new': 123}) elif link.action in ('put', 'post'): diff --git a/tests/test_transport.py b/tests/test_transport.py index 8187fd9..d45ed21 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -26,9 +26,14 @@ def __init__(self, content): self.url = 'http://example.org' self.status_code = 200 + def iter_content(self, *args, **kwargs): + return self.content + def close(self): + return # Test transport errors. + def test_unknown_scheme(): with pytest.raises(NetworkError): determine_transport(transports, 'ftp://example.org') From 7b4d4e1548b28e0a633ee26680abdabb74b66ba9 Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 12:39:46 +0200 Subject: [PATCH 08/20] fixing test to python3 --- tests/test_integration.py | 4 +++- tests/test_transport.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index 04d889a..4c6c910 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -24,7 +24,9 @@ def __init__(self, content): self.status_code = 200 def iter_content(self, *args, **kwargs): - return self.content + n = 2 + list_of_chunks = list(self.content[i:i + n] for i in range(0, len(self.content), n)) + return list_of_chunks def close(self): return diff --git a/tests/test_transport.py b/tests/test_transport.py index d45ed21..268ebfd 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -27,7 +27,9 @@ def __init__(self, content): self.status_code = 200 def iter_content(self, *args, **kwargs): - return self.content + n = 2 + list_of_chunks = list(self.content[i:i + n] for i in range(0, len(self.content), n)) + return list_of_chunks def close(self): return From 03a1317bcf49d98f98680a024771cb21c40f71b8 Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 14:35:07 +0200 Subject: [PATCH 09/20] dealing with the case the decoder returned a file --- coreapi/transports/http.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index ea7d999..e247796 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -267,6 +267,9 @@ def _coerce_to_error(obj, default_title): return Error(title=default_title, content={'messages': obj}) elif obj is None: return Error(title=default_title) + elif hasattr(obj, 'read'): + # dealing with the case the decoder returned a file + return Error(title=default_title, content={'messages': obj.read().decode("utf-8")}) return Error(title=default_title, content={'message': obj}) From fb1ca07bc102ba78280bcbf2f227a3cbcd64186d Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 14:46:42 +0200 Subject: [PATCH 10/20] Supporting the case where there is error and DownloadCoded is enabled --- coreapi/transports/http.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index a548024..ec34cea 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -268,6 +268,8 @@ def _coerce_to_error(obj, default_title): return Error(title=default_title, content={'messages': obj}) elif obj is None: return Error(title=default_title) + elif hasattr(obj, "read"): + return Error(title=default_title, content={'messages': obj.read().decode("utf-8")}) return Error(title=default_title, content={'message': obj}) From 343891717a75d70bef28758ef182af5cecacc90c Mon Sep 17 00:00:00 2001 From: Guy D Date: Tue, 12 Dec 2017 14:28:09 +0200 Subject: [PATCH 11/20] when uploading file making sure it uses multipart/form --- coreapi/__init__.py | 2 +- coreapi/transports/http.py | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/coreapi/__init__.py b/coreapi/__init__.py index 92ac890..7d900db 100644 --- a/coreapi/__init__.py +++ b/coreapi/__init__.py @@ -4,7 +4,7 @@ from coreapi.document import Array, Document, Link, Object, Error, Field -__version__ = '2.3.3' +__version__ = '2.3.4' __all__ = [ 'Array', 'Document', 'Link', 'Object', 'Error', 'Field', 'Client', diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index e247796..b126a2b 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -12,6 +12,7 @@ import mimetypes import uritemplate import warnings +import io Params = collections.namedtuple('Params', ['path', 'query', 'data', 'files']) @@ -86,7 +87,14 @@ def _get_method(action): return action.upper() -def _get_encoding(encoding): +def _get_encoding(encoding, params): + has_file = False + if params is not None: + for value in params.values(): + if hasattr(value, 'read'): + has_file = True + if has_file: + return 'multipart/form-data' if not encoding: return 'application/json' return encoding @@ -372,7 +380,7 @@ def headers(self): def transition(self, link, decoders, params=None, link_ancestors=None, force_codec=False, stream=False): session = self._session method = _get_method(link.action) - encoding = _get_encoding(link.encoding) + encoding = _get_encoding(link.encoding, params) params = _get_params(method, encoding, link.fields, params) url = _get_url(link.url, params.path) headers = _get_headers(url, decoders) @@ -380,7 +388,9 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod request = _build_http_request(session, url, method, headers, encoding, params) response = session.send(request, stream=stream) - result = _decode_result(response, decoders, force_codec) + result = None + if response.status_code != 204: # no content + result = _decode_result(response, decoders, force_codec) response.close() if isinstance(result, Document) and link_ancestors: From fcc52c0ba2d498d6239cbe6c2833cf7b3fbde7a7 Mon Sep 17 00:00:00 2001 From: Guy D Date: Wed, 15 Aug 2018 09:43:09 +0300 Subject: [PATCH 12/20] adding progress_bar to download --- coreapi/codecs/download.py | 10 +++++++--- coreapi/transports/http.py | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/coreapi/codecs/download.py b/coreapi/codecs/download.py index 5023814..9c03fc9 100644 --- a/coreapi/codecs/download.py +++ b/coreapi/codecs/download.py @@ -6,7 +6,7 @@ import os import posixpath import tempfile - +from tqdm import tqdm def _unique_output_path(path): """ @@ -102,12 +102,13 @@ class DownloadCodec(BaseCodec): media_type = '*/*' format = 'download' - def __init__(self, download_dir=None): + def __init__(self, download_dir=None, progress_bar=False): """ `download_dir` - The path to use for file downloads. """ self._delete_on_close = download_dir is None self._download_dir = download_dir + self._progress_bar = progress_bar def support_streaming(self): return True @@ -122,8 +123,11 @@ def decode(self, chunks, **options): content_disposition = options.get('content_disposition') # Write the download to a temporary .download file. - fd, temp_path = tempfile.mkstemp(suffix='.download') + fd, temp_path = tempfile.mkstemp(suffix='.download', dir=self._download_dir) file_handle = os.fdopen(fd, 'wb') + content_length = options.get("content-length", None) + if content_length and self._progress_bar: + chunks = tqdm(chunks, total=content_length, unit="mb") for chunk in chunks: file_handle.write(chunk) file_handle.close() diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index b126a2b..cb330e9 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -13,6 +13,7 @@ import uritemplate import warnings import io +import math Params = collections.namedtuple('Params', ['path', 'query', 'data', 'files']) @@ -285,7 +286,8 @@ def _decode_result(response, decoders, force_codec=False): """ Given an HTTP response, return the decoded Core API document. """ - chunks = response.iter_content(1024) + chunk_size = 1024*1024 + chunks = response.iter_content(chunk_size) if chunks: # Content returned in response. We should decode it. if force_codec: @@ -301,7 +303,9 @@ def _decode_result(response, decoders, force_codec=False): options['content_type'] = response.headers['content-type'] if 'content-disposition' in response.headers: options['content_disposition'] = response.headers['content-disposition'] - + if 'content-length' in response.headers: + options["content-length"] = int(response.headers["content-length"])/chunk_size + result = codec.load(chunks, **options) else: # No content returned in response. From 7a93524c247fc7b33f37370db4cac649388193be Mon Sep 17 00:00:00 2001 From: Guy D Date: Wed, 15 Aug 2018 09:43:52 +0300 Subject: [PATCH 13/20] adding tqdm dep --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7dabead..39f0aa3 100755 --- a/setup.py +++ b/setup.py @@ -66,7 +66,8 @@ def get_package_data(package): 'coreschema', 'requests', 'itypes', - 'uritemplate' + 'uritemplate', + 'tqdm' ], entry_points={ 'coreapi.codecs': [ From a535c65f16ae88c48f1537906781ab5dd17d202a Mon Sep 17 00:00:00 2001 From: Guy Doulberg Date: Wed, 15 Aug 2018 14:24:56 +0300 Subject: [PATCH 14/20] remore extra lines --- tests/test_integration.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index 0dcb2b0..a8761aa 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -49,7 +49,6 @@ def test_dump(document): def test_get(monkeypatch): - def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') @@ -61,7 +60,6 @@ def mockreturn(self, request, *args, **kwargs): def test_follow(monkeypatch, document): - def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') @@ -73,7 +71,6 @@ def mockreturn(self, request, *args, **kwargs): def test_reload(monkeypatch): - def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') @@ -86,7 +83,6 @@ def mockreturn(self, request, *args, **kwargs): def test_error(monkeypatch, document): - def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "error", "message": ["failed"]}') From 9edaf400caa79a44a33b1c645ccf17751d8ac5f6 Mon Sep 17 00:00:00 2001 From: Guy Doulberg Date: Wed, 15 Aug 2018 14:25:55 +0300 Subject: [PATCH 15/20] Update test_transport.py --- tests/test_transport.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_transport.py b/tests/test_transport.py index 3e41dd5..698c94f 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -81,7 +81,6 @@ def mockreturn(self, request, *args, **kwargs): def test_get_with_path_parameter(monkeypatch, http): - def mockreturn(self, request, *args, **kwargs): insert = request.url.encode('utf-8') return MockResponse( @@ -100,9 +99,7 @@ def mockreturn(self, request, *args, **kwargs): def test_post(monkeypatch, http): - def mockreturn(self, request, *args, **kwargs): - codec = CoreJSONCodec() body = force_text(request.body) content = codec.encode(Document(content={'data': json.loads(body)})) @@ -116,7 +113,6 @@ def mockreturn(self, request, *args, **kwargs): def test_delete(monkeypatch, http): - def mockreturn(self, request, *args, **kwargs): return MockResponse(b'') From bf6191ec1dcf1053a3f0ee650abbca858a1052b3 Mon Sep 17 00:00:00 2001 From: Guy Doulberg Date: Wed, 15 Aug 2018 14:26:47 +0300 Subject: [PATCH 16/20] Update test_transport.py --- tests/test_transport.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_transport.py b/tests/test_transport.py index 698c94f..ec93bb3 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -54,7 +54,6 @@ def test_missing_hostname(): # Test basic transition types. def test_get(monkeypatch, http): - def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') @@ -66,7 +65,6 @@ def mockreturn(self, request, *args, **kwargs): def test_get_with_parameters(monkeypatch, http): - def mockreturn(self, request, *args, **kwargs): insert = request.path_url.encode('utf-8') return MockResponse( From 43a719b33da25fbda99c99e828195a07bb7580c3 Mon Sep 17 00:00:00 2001 From: Guy Doulberg Date: Wed, 15 Aug 2018 14:28:38 +0300 Subject: [PATCH 17/20] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 71ddd11..77e66d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ coreschema itypes requests uritemplate +tqdm # Testing requirements coverage From 3f50c5c4483416cbbcb2451fcddce0e924013958 Mon Sep 17 00:00:00 2001 From: Guy D Date: Wed, 15 Aug 2018 14:33:23 +0300 Subject: [PATCH 18/20] coding style --- coreapi/transports/http.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index cb330e9..0e52d91 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -12,8 +12,6 @@ import mimetypes import uritemplate import warnings -import io -import math Params = collections.namedtuple('Params', ['path', 'query', 'data', 'files']) @@ -286,7 +284,7 @@ def _decode_result(response, decoders, force_codec=False): """ Given an HTTP response, return the decoded Core API document. """ - chunk_size = 1024*1024 + chunk_size = 1024 * 1024 chunks = response.iter_content(chunk_size) if chunks: # Content returned in response. We should decode it. @@ -304,8 +302,7 @@ def _decode_result(response, decoders, force_codec=False): if 'content-disposition' in response.headers: options['content_disposition'] = response.headers['content-disposition'] if 'content-length' in response.headers: - options["content-length"] = int(response.headers["content-length"])/chunk_size - + options["content-length"] = int(response.headers["content-length"]) / chunk_size result = codec.load(chunks, **options) else: # No content returned in response. From 0668871f42b42718e3251281ca701170cef69f18 Mon Sep 17 00:00:00 2001 From: Guy D Date: Wed, 15 Aug 2018 14:39:33 +0300 Subject: [PATCH 19/20] code style --- coreapi/codecs/download.py | 1 + coreapi/transports/http.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/codecs/download.py b/coreapi/codecs/download.py index 9c03fc9..48cda49 100644 --- a/coreapi/codecs/download.py +++ b/coreapi/codecs/download.py @@ -8,6 +8,7 @@ import tempfile from tqdm import tqdm + def _unique_output_path(path): """ Given a path like '/a/b/c.txt' diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index 53bb7e2..ecd5bb0 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -390,7 +390,8 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod request = _build_http_request(session, url, method, headers, encoding, params) settings = session.merge_environment_settings(request.url, None, None, None, None) - response = session.send(request, stream=stream) + settings["stream"] = stream + response = session.send(request, **settings) result = None if response.status_code != 204: # no content result = _decode_result(response, decoders, force_codec) From 8fb5573861e5c9c6f739783b48db5871f9d61735 Mon Sep 17 00:00:00 2001 From: Guy D Date: Sun, 10 Dec 2017 14:46:42 +0200 Subject: [PATCH 20/20] Supporting the case where there is error and DownloadCoded is enabled --- coreapi/transports/http.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index 7338e61..ca07c71 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -268,6 +268,8 @@ def _coerce_to_error(obj, default_title): return Error(title=default_title, content={'messages': obj}) elif obj is None: return Error(title=default_title) + elif hasattr(obj, "read"): + return Error(title=default_title, content={'messages': obj.read().decode("utf-8")}) return Error(title=default_title, content={'message': obj})