diff --git a/.travis.yml b/.travis.yml index af709cd..f132d06 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ python: - "2.7" - "3.3" - "3.4" + - "3.5" + - "3.6" install: - pip install -r requirements.txt diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..e92b342 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,29 @@ +# License + +Copyright © 2017-present, Tom Christie. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/coreapi/__init__.py b/coreapi/__init__.py index 5f069ba..92ac890 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.0' +__version__ = '2.3.3' __all__ = [ 'Array', 'Document', 'Link', 'Object', 'Error', 'Field', 'Client', diff --git a/coreapi/client.py b/coreapi/client.py index d02a59c..00b0057 100644 --- a/coreapi/client.py +++ b/coreapi/client.py @@ -105,7 +105,7 @@ def __init__(self, decoders=None, transports=None, auth=None, session=None): if decoders is None: decoders = get_default_decoders() if transports is None: - transports = get_default_transports(auth=auth) + transports = get_default_transports(auth=auth, session=session) self._decoders = itypes.List(decoders) self._transports = itypes.List(transports) diff --git a/coreapi/codecs/corejson.py b/coreapi/codecs/corejson.py index 091e7a3..f025533 100644 --- a/coreapi/codecs/corejson.py +++ b/coreapi/codecs/corejson.py @@ -32,20 +32,31 @@ def encode_schema_to_corejson(schema): - type_id = SCHEMA_CLASS_TO_TYPE_ID.get(schema.__class__, 'anything') - return { + if hasattr(schema, 'typename'): + type_id = schema.typename + else: + type_id = SCHEMA_CLASS_TO_TYPE_ID.get(schema.__class__, 'anything') + retval = { '_type': type_id, 'title': schema.title, 'description': schema.description } + if hasattr(schema, 'enum'): + retval['enum'] = schema.enum + return retval def decode_schema_from_corejson(data): type_id = _get_string(data, '_type') title = _get_string(data, 'title') description = _get_string(data, 'description') + + kwargs = {} + if type_id == 'enum': + kwargs['enum'] = _get_list(data, 'enum') + schema_cls = TYPE_ID_TO_SCHEMA_CLASS.get(type_id, coreschema.Anything) - return schema_cls(title=title, description=description) + return schema_cls(title=title, description=description, **kwargs) # Robust dictionary lookups, that always return an item of the correct diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index a548024..7338e61 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -376,7 +376,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) + settings = session.merge_environment_settings(request.url, None, None, None, None) + response = session.send(request, **settings) result = _decode_result(response, decoders, force_codec) if isinstance(result, Document) and link_ancestors: diff --git a/setup.py b/setup.py index ef91e7f..7dabead 100755 --- a/setup.py +++ b/setup.py @@ -86,6 +86,13 @@ def get_package_data(package): 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: Internet :: WWW/HTTP', ] ) diff --git a/tests/test_codecs.py b/tests/test_codecs.py index 8ebbd63..32458cd 100644 --- a/tests/test_codecs.py +++ b/tests/test_codecs.py @@ -4,6 +4,7 @@ from coreapi.document import Document, Link, Error, Field from coreapi.exceptions import ParseError, NoCodecAvailable from coreapi.utils import negotiate_decoder, negotiate_encoder +from coreschema import Enum, String import pytest @@ -21,7 +22,13 @@ def doc(): 'integer': 123, 'dict': {'key': 'value'}, 'list': [1, 2, 3], - 'link': Link(url='http://example.org/', fields=[Field(name='example')]), + 'link': Link( + url='http://example.org/', + fields=[ + Field(name='noschema'), + Field(name='string_example', schema=String()), + Field(name='enum_example', schema=Enum(['a', 'b', 'c'])), + ]), 'nested': {'child': Link(url='http://example.org/123')}, '_type': 'needs escaping' }) @@ -40,7 +47,26 @@ def test_document_to_primitive(doc): 'integer': 123, 'dict': {'key': 'value'}, 'list': [1, 2, 3], - 'link': {'_type': 'link', 'fields': [{'name': 'example'}]}, + 'link': {'_type': 'link', 'fields': [ + {'name': 'noschema'}, + { + 'name': 'string_example', + 'schema': { + '_type': 'string', + 'title': '', + 'description': '', + }, + }, + { + 'name': 'enum_example', + 'schema': { + '_type': 'enum', + 'title': '', + 'description': '', + 'enum': ['a', 'b', 'c'], + }, + }, + ]}, 'nested': {'child': {'_type': 'link', 'url': '/123'}}, '__type': 'needs escaping' } @@ -56,7 +82,30 @@ def test_primitive_to_document(doc): 'integer': 123, 'dict': {'key': 'value'}, 'list': [1, 2, 3], - 'link': {'_type': 'link', 'url': 'http://example.org/', 'fields': [{'name': 'example'}]}, + 'link': { + '_type': 'link', + 'url': 'http://example.org/', + 'fields': [ + {'name': 'noschema'}, + { + 'name': 'string_example', + 'schema': { + '_type': 'string', + 'title': '', + 'description': '', + }, + }, + { + 'name': 'enum_example', + 'schema': { + '_type': 'enum', + 'title': '', + 'description': '', + 'enum': ['a', 'b', 'c'], + }, + }, + ], + }, 'nested': {'child': {'_type': 'link', 'url': 'http://example.org/123'}}, '__type': 'needs escaping' } diff --git a/tests/test_integration.py b/tests/test_integration.py index b38de9a..0a2e602 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -41,7 +41,7 @@ def test_dump(document): def test_get(monkeypatch): - def mockreturn(self, request): + def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') monkeypatch.setattr(requests.Session, 'send', mockreturn) @@ -52,7 +52,7 @@ def mockreturn(self, request): def test_follow(monkeypatch, document): - def mockreturn(self, request): + def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') monkeypatch.setattr(requests.Session, 'send', mockreturn) @@ -63,7 +63,7 @@ def mockreturn(self, request): def test_reload(monkeypatch): - def mockreturn(self, request): + def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "document", "example": 123}') monkeypatch.setattr(requests.Session, 'send', mockreturn) @@ -75,7 +75,7 @@ def mockreturn(self, request): def test_error(monkeypatch, document): - def mockreturn(self, request): + def mockreturn(self, request, *args, **kwargs): return MockResponse(b'{"_type": "error", "message": ["failed"]}') monkeypatch.setattr(requests.Session, 'send', mockreturn) diff --git a/tests/test_transport.py b/tests/test_transport.py index 09cb849..eeeb17a 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, *args, **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, *args, **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, *args, **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, *args, **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, *args, **kwargs): return MockResponse(b'') monkeypatch.setattr(requests.Session, 'send', mockreturn)