From 43d93acd46fcd970ba27247a45f5f0e46a3edb64 Mon Sep 17 00:00:00 2001 From: Brian Price Date: Tue, 21 May 2019 15:35:28 -0500 Subject: [PATCH 1/8] Implementing readOnly and writeOnly validation --- openapi_core/schema/schemas/factories.py | 3 + openapi_core/schema/schemas/models.py | 44 ++++++++----- tests/unit/schema/test_schemas.py | 79 ++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 15 deletions(-) diff --git a/openapi_core/schema/schemas/factories.py b/openapi_core/schema/schemas/factories.py index 136fbd09..92f1a12a 100644 --- a/openapi_core/schema/schemas/factories.py +++ b/openapi_core/schema/schemas/factories.py @@ -43,6 +43,8 @@ def create(self, schema_spec): exclusive_maximum = schema_deref.get('exclusiveMaximum', False) min_properties = schema_deref.get('minProperties', None) max_properties = schema_deref.get('maxProperties', None) + read_only = schema_deref.get('readOnly', False) + write_only = schema_deref.get('writeOnly', False) properties = None if properties_spec: @@ -76,6 +78,7 @@ def create(self, schema_spec): exclusive_maximum=exclusive_maximum, exclusive_minimum=exclusive_minimum, min_properties=min_properties, max_properties=max_properties, + read_only=read_only, write_only=write_only ) @property diff --git a/openapi_core/schema/schemas/models.py b/openapi_core/schema/schemas/models.py index b9784cf2..bb003170 100644 --- a/openapi_core/schema/schemas/models.py +++ b/openapi_core/schema/schemas/models.py @@ -79,7 +79,8 @@ def __init__( min_length=None, max_length=None, pattern=None, unique_items=False, minimum=None, maximum=None, multiple_of=None, exclusive_minimum=False, exclusive_maximum=False, - min_properties=None, max_properties=None): + min_properties=None, max_properties=None, read_only=False, + write_only=False): self.type = SchemaType(schema_type) self.model = model self.properties = properties and dict(properties) or {} @@ -109,6 +110,8 @@ def __init__( if min_properties is not None else None self.max_properties = int(max_properties)\ if max_properties is not None else None + self.read_only = read_only + self.write_only = write_only self._all_required_properties_cache = None self._all_optional_properties_cache = None @@ -391,7 +394,7 @@ def default(x, **kw): return defaultdict(lambda: default, mapping) - def validate(self, value, custom_formatters=None): + def validate(self, value, custom_formatters=None, read=False, write=False): if value is None: if not self.nullable: raise InvalidSchemaValue("Null value for non-nullable schema of type {type}", value, self.type) @@ -407,11 +410,11 @@ def validate(self, value, custom_formatters=None): # structure validation validator_mapping = self.get_validator_mapping() validator_callable = validator_mapping[self.type] - validator_callable(value, custom_formatters=custom_formatters) + validator_callable(value, custom_formatters=custom_formatters, read=read, write=write) return value - def _validate_collection(self, value, custom_formatters=None): + def _validate_collection(self, value, custom_formatters=None, **kwargs): if self.items is None: raise UndefinedItemsSchema(self.type) @@ -439,10 +442,10 @@ def _validate_collection(self, value, custom_formatters=None): raise OpenAPISchemaError("Value may not contain duplicate items") f = functools.partial(self.items.validate, - custom_formatters=custom_formatters) + custom_formatters=custom_formatters, **kwargs) return list(map(f, value)) - def _validate_number(self, value, custom_formatters=None): + def _validate_number(self, value, **kwargs): if self.minimum is not None: if self.exclusive_minimum and value <= self.minimum: raise InvalidSchemaValue( @@ -464,7 +467,7 @@ def _validate_number(self, value, custom_formatters=None): "Value {value} is not a multiple of {type}", value, self.multiple_of) - def _validate_string(self, value, custom_formatters=None): + def _validate_string(self, value, custom_formatters=None, **kwargs): try: schema_format = SchemaFormat(self.format) except ValueError: @@ -513,7 +516,7 @@ def _validate_string(self, value, custom_formatters=None): return True - def _validate_object(self, value, custom_formatters=None): + def _validate_object(self, value, custom_formatters=None, **kwargs): properties = value.__dict__ if self.one_of: @@ -522,7 +525,7 @@ def _validate_object(self, value, custom_formatters=None): try: self._validate_properties( properties, one_of_schema, - custom_formatters=custom_formatters) + custom_formatters=custom_formatters, **kwargs) except OpenAPISchemaError: pass else: @@ -535,7 +538,7 @@ def _validate_object(self, value, custom_formatters=None): else: self._validate_properties(properties, - custom_formatters=custom_formatters) + custom_formatters=custom_formatters, **kwargs) if self.min_properties is not None: if self.min_properties < 0: @@ -565,7 +568,7 @@ def _validate_object(self, value, custom_formatters=None): return True def _validate_properties(self, value, one_of_schema=None, - custom_formatters=None): + custom_formatters=None, read=False, write=False): all_props = self.get_all_properties() all_props_names = self.get_all_properties_names() all_req_props_names = self.get_all_required_properties_names() @@ -588,19 +591,30 @@ def _validate_properties(self, value, one_of_schema=None, for prop_name in extra_props: prop_value = value[prop_name] self.additional_properties.validate( - prop_value, custom_formatters=custom_formatters) + prop_value, custom_formatters=custom_formatters, + read=read, write=write) for prop_name, prop in iteritems(all_props): + should_skip = (read and not prop.read_only) or (write and prop.write_only) try: prop_value = value[prop_name] + if read and prop.write_only: + message = "WriteOnly property {prop} defined on read.".format(prop=prop_name) + raise UndefinedSchemaProperty(message) + + if write and prop.read_only: + message = "ReadOnly property {prop} defined on write.".format(prop=prop_name) + raise UndefinedSchemaProperty(message) + except KeyError: - if prop_name in all_req_props_names: + if prop_name in all_req_props_names and not should_skip: raise MissingSchemaProperty(prop_name) - if not prop.nullable and not prop.default: + if (not prop.nullable and not prop.default) or should_skip: continue prop_value = prop.default try: - prop.validate(prop_value, custom_formatters=custom_formatters) + prop.validate(prop_value, custom_formatters=custom_formatters, + read=read, write=write) except OpenAPISchemaError as exc: raise InvalidSchemaProperty(prop_name, original_exception=exc) diff --git a/tests/unit/schema/test_schemas.py b/tests/unit/schema/test_schemas.py index 8efd96be..af94e255 100644 --- a/tests/unit/schema/test_schemas.py +++ b/tests/unit/schema/test_schemas.py @@ -1008,3 +1008,82 @@ def test_object_with_invalid_properties(self, value): with pytest.raises(Exception): schema.validate(value) + + @pytest.mark.parametrize('value', [ + Model({ + 'someint': 123, + }), + ]) + def test_object_write_only_pass(self, value): + schema = Schema( + 'object', + properties={ + 'somestr': Schema('string', + read_only=True), + 'someint': Schema('integer', + write_only=True), + }, + ) + + result = schema.validate(value, write=True) + + assert result == value + + @pytest.mark.parametrize('value', [ + Model({ + 'somestr': "asdf", + }), + ]) + def test_object_write_only_failed(self, value): + schema = Schema( + 'object', + properties={ + 'somestr': Schema('string', + read_only=True), + 'someint': Schema('integer', + write_only=True), + }, + ) + + with pytest.raises(UndefinedSchemaProperty): + schema.validate(value, write=True) + + @pytest.mark.parametrize('value', [ + Model({ + 'somestr': "asdf" + }), + ]) + def test_object_read_only_pass(self, value): + schema = Schema( + 'object', + properties={ + 'somestr': Schema('string', + read_only=True), + 'someint': Schema('integer', + write_only=True), + }, + ) + + result = schema.validate(value, read=True) + + assert result == value + + @pytest.mark.parametrize('value', [ + Model({ + 'somestr': "asdf", + 'someint': 123 + }), + ]) + def test_object_read_only_failed(self, value): + schema = Schema( + 'object', + properties={ + 'somestr': Schema('string', + read_only=True), + 'someint': Schema('integer', + write_only=True), + }, + ) + + with pytest.raises(UndefinedSchemaProperty): + schema.validate(value, read=True) From ae2479ce95d0f97d9405f39b26ba728597cc8cd6 Mon Sep 17 00:00:00 2001 From: Brian Price Date: Tue, 21 May 2019 16:51:20 -0500 Subject: [PATCH 2/8] Adding readOnly and writeOnly support to validator. --- openapi_core/schema/media_types/models.py | 4 +- openapi_core/schema/parameters/models.py | 2 +- openapi_core/validation/request/validators.py | 4 +- .../validation/response/validators.py | 2 +- tests/integration/data/v3.0/get_and_post.yaml | 52 +++++++++++++ tests/integration/test_get_and_post.py | 75 +++++++++++++++++++ 6 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 tests/integration/data/v3.0/get_and_post.yaml create mode 100644 tests/integration/test_get_and_post.py diff --git a/openapi_core/schema/media_types/models.py b/openapi_core/schema/media_types/models.py index 5104095a..795ab4c1 100644 --- a/openapi_core/schema/media_types/models.py +++ b/openapi_core/schema/media_types/models.py @@ -32,7 +32,7 @@ def deserialize(self, value): deserializer = self.get_dererializer() return deserializer(value) - def unmarshal(self, value, custom_formatters=None): + def unmarshal(self, value, custom_formatters=None, read=False, write=False): if not self.schema: return value @@ -47,6 +47,6 @@ def unmarshal(self, value, custom_formatters=None): raise InvalidMediaTypeValue(exc) try: - return self.schema.validate(unmarshalled, custom_formatters=custom_formatters) + return self.schema.validate(unmarshalled, custom_formatters=custom_formatters, read=read, write=write) except OpenAPISchemaError as exc: raise InvalidMediaTypeValue(exc) diff --git a/openapi_core/schema/parameters/models.py b/openapi_core/schema/parameters/models.py index 090bf0a4..5202d5d0 100644 --- a/openapi_core/schema/parameters/models.py +++ b/openapi_core/schema/parameters/models.py @@ -89,7 +89,7 @@ def get_value(self, request): return location[self.name] - def unmarshal(self, value, custom_formatters=None): + def unmarshal(self, value, custom_formatters=None, **kwags): if self.deprecated: warnings.warn( "{0} parameter is deprecated".format(self.name), diff --git a/openapi_core/validation/request/validators.py b/openapi_core/validation/request/validators.py index 08593f63..b323ddf5 100644 --- a/openapi_core/validation/request/validators.py +++ b/openapi_core/validation/request/validators.py @@ -53,7 +53,7 @@ def _get_parameters(self, request, operation): continue try: - value = param.unmarshal(raw_value, self.custom_formatters) + value = param.unmarshal(raw_value, self.custom_formatters, read=True) except OpenAPIMappingError as exc: errors.append(exc) else: @@ -79,7 +79,7 @@ def _get_body(self, request, operation): errors.append(exc) else: try: - body = media_type.unmarshal(raw_body, self.custom_formatters) + body = media_type.unmarshal(raw_body, self.custom_formatters, write=True) except OpenAPIMappingError as exc: errors.append(exc) diff --git a/openapi_core/validation/response/validators.py b/openapi_core/validation/response/validators.py index 4f9696bf..a221438b 100644 --- a/openapi_core/validation/response/validators.py +++ b/openapi_core/validation/response/validators.py @@ -61,7 +61,7 @@ def _get_data(self, response, operation_response): errors.append(exc) else: try: - data = media_type.unmarshal(raw_data, self.custom_formatters) + data = media_type.unmarshal(raw_data, self.custom_formatters, read=True) except OpenAPIMappingError as exc: errors.append(exc) diff --git a/tests/integration/data/v3.0/get_and_post.yaml b/tests/integration/data/v3.0/get_and_post.yaml new file mode 100644 index 00000000..cba2e2ef --- /dev/null +++ b/tests/integration/data/v3.0/get_and_post.yaml @@ -0,0 +1,52 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Test Post and Get + license: + name: MIT +paths: + /object: + post: + summary: Post an Object + operationId: postObject + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ObjectDesc' + responses: + '201': + description: Null response + /object/{objectId}: + get: + summary: Get an Object + operationId: getObject + parameters: + - name: objectId + in: path + required: true + description: The id of the object + schema: + type: string + responses: + '200': + description: Object description + content: + application/json: + schema: + $ref: "#/components/schemas/ObjectDesc" +components: + schemas: + ObjectDesc: + type: object + additionalProperties: False + properties: + object_id: + type: string + readOnly: true + message: + type: string + password: + type: string + writeOnly: true diff --git a/tests/integration/test_get_and_post.py b/tests/integration/test_get_and_post.py new file mode 100644 index 00000000..28d12576 --- /dev/null +++ b/tests/integration/test_get_and_post.py @@ -0,0 +1,75 @@ +import pytest +import json + +from openapi_core.shortcuts import create_spec +from openapi_core.validation.request.validators import RequestValidator +from openapi_core.validation.response.validators import ResponseValidator +from openapi_core.wrappers.mock import MockRequest, MockResponse + + +class TestGetAndPost(object): + + get_object = [{ + "object_id": "random_id", + "message": "test message" + }] + + post_object = [{ + "message": "second message", + "password": "fakepassword" + }] + spec_paths = [ + "data/v3.0/get_and_post.yaml", + ] + + @pytest.mark.parametrize("response", post_object) + @pytest.mark.parametrize("spec_path", spec_paths) + def test_post_object_success(self, factory, response, spec_path): + spec_dict = factory.spec_from_file(spec_path) + spec = create_spec(spec_dict) + validator = RequestValidator(spec) + request = MockRequest("http://www.example.com", "post", + "/object", data=json.dumps(response)) + + result = validator.validate(request) + assert not result.errors + + @pytest.mark.parametrize("response", get_object) + @pytest.mark.parametrize("spec_path", spec_paths) + def test_post_object_failure(self, factory, response, spec_path): + spec_dict = factory.spec_from_file(spec_path) + spec = create_spec(spec_dict) + validator = RequestValidator(spec) + request = MockRequest("http://www.example.com", "post", + "/object", data=json.dumps(response)) + + result = validator.validate(request) + assert result.errors + + @pytest.mark.parametrize("response", get_object) + @pytest.mark.parametrize("spec_path", spec_paths) + def test_get_object_success(self, factory, response, spec_path): + spec_dict = factory.spec_from_file(spec_path) + spec = create_spec(spec_dict) + request = MockRequest("http://www.example.com", "get", + "/object/{objectId}") + validator = ResponseValidator(spec) + response = MockResponse(data=json.dumps(response)) + + result = validator.validate(request, response) + print(result.errors) + assert not result.errors + + @pytest.mark.parametrize("response", post_object) + @pytest.mark.parametrize("spec_path", spec_paths) + def test_get_object_failure(self, factory, response, spec_path): + spec_dict = factory.spec_from_file(spec_path) + spec = create_spec(spec_dict) + request = MockRequest("http://www.example.com", "get", + "/object/{objectId}") + + validator = ResponseValidator(spec) + response = MockResponse(data=json.dumps(response)) + + result = validator.validate(request, response) + assert result.errors From faf1f498e99f7543a8474b7defb29d14e168dc1a Mon Sep 17 00:00:00 2001 From: Brian Price Date: Tue, 21 May 2019 16:52:12 -0500 Subject: [PATCH 3/8] Ignoring reports directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 89a475dc..ac25106a 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ nosetests.xml coverage.xml *.cover .hypothesis/ +reports/ # Translations *.mo From 709ce8c604ddc19af1b7e873b2c07a1e44235ecf Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Tue, 21 May 2019 17:49:16 -0500 Subject: [PATCH 4/8] Fixing string issue for Python 2.7 --- openapi_core/schema/schemas/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openapi_core/schema/schemas/models.py b/openapi_core/schema/schemas/models.py index bb003170..cc66c316 100644 --- a/openapi_core/schema/schemas/models.py +++ b/openapi_core/schema/schemas/models.py @@ -9,7 +9,7 @@ import re import warnings -from six import iteritems, integer_types, binary_type, text_type +from six import iteritems, integer_types, binary_type, text_type, string_types from openapi_core.extensions.models.factories import ModelFactory from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType @@ -42,14 +42,14 @@ class Schema(object): } STRING_FORMAT_CALLABLE_GETTER = { - SchemaFormat.NONE: Format(text_type, TypeValidator(text_type)), - SchemaFormat.PASSWORD: Format(text_type, TypeValidator(text_type)), + SchemaFormat.NONE: Format(text_type, TypeValidator(string_types)), + SchemaFormat.PASSWORD: Format(text_type, TypeValidator(string_types)), SchemaFormat.DATE: Format( format_date, TypeValidator(date, exclude=datetime)), SchemaFormat.DATETIME: Format(format_datetime, TypeValidator(datetime)), SchemaFormat.BINARY: Format(binary_type, TypeValidator(binary_type)), SchemaFormat.UUID: Format(format_uuid, TypeValidator(UUID)), - SchemaFormat.BYTE: Format(format_byte, TypeValidator(text_type)), + SchemaFormat.BYTE: Format(format_byte, TypeValidator(string_types)), } NUMBER_FORMAT_CALLABLE_GETTER = { From 147d9f75809a574dea76c610593f3d34f6b79dac Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Tue, 21 May 2019 17:58:49 -0500 Subject: [PATCH 5/8] Python 2 uses str as "bytes" which is still a string. --- tests/unit/schema/test_schemas.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/unit/schema/test_schemas.py b/tests/unit/schema/test_schemas.py index af94e255..a496566f 100644 --- a/tests/unit/schema/test_schemas.py +++ b/tests/unit/schema/test_schemas.py @@ -1,5 +1,6 @@ import datetime import uuid +import six import mock import pytest @@ -520,7 +521,16 @@ def test_string(self, value): assert result == value @pytest.mark.parametrize('value', [b('test'), False, 1, 3.14, [1, 3]]) - def test_string_invalid(self, value): + @pytest.mark.skip(six.PY2) + def test_string_invalid_py3(self, value): + schema = Schema('string') + + with pytest.raises(InvalidSchemaValue): + schema.validate(value) + + @pytest.mark.parametrize('value', [False, 1, 3.14, [1, 3]]) + @pytest.mark.skip(six.PY3) + def test_string_invalid_py2(self, value): schema = Schema('string') with pytest.raises(InvalidSchemaValue): @@ -610,6 +620,7 @@ def test_string_format_binary(self, value): @pytest.mark.parametrize('value', [ b('tsssst'), b('dGVzdA=='), ]) + @pytest.mark.skip(six.PY2) def test_string_format_byte_invalid(self, value): schema = Schema('string', schema_format='byte') From 1f8b2bc6736b2de3c5bb9fa42449db7801031021 Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Wed, 22 May 2019 10:31:45 -0500 Subject: [PATCH 6/8] Fixing a bug with the logic when requried was specified. Including test coverage. --- openapi_core/schema/parameters/models.py | 2 +- openapi_core/schema/schemas/models.py | 2 +- tests/unit/schema/test_schemas.py | 51 ++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/openapi_core/schema/parameters/models.py b/openapi_core/schema/parameters/models.py index 5202d5d0..b9ed5684 100644 --- a/openapi_core/schema/parameters/models.py +++ b/openapi_core/schema/parameters/models.py @@ -89,7 +89,7 @@ def get_value(self, request): return location[self.name] - def unmarshal(self, value, custom_formatters=None, **kwags): + def unmarshal(self, value, custom_formatters=None, **kwargs): if self.deprecated: warnings.warn( "{0} parameter is deprecated".format(self.name), diff --git a/openapi_core/schema/schemas/models.py b/openapi_core/schema/schemas/models.py index cc66c316..b7a1864b 100644 --- a/openapi_core/schema/schemas/models.py +++ b/openapi_core/schema/schemas/models.py @@ -595,7 +595,7 @@ def _validate_properties(self, value, one_of_schema=None, read=read, write=write) for prop_name, prop in iteritems(all_props): - should_skip = (read and not prop.read_only) or (write and prop.write_only) + should_skip = (write and prop.read_only) or (read and prop.write_only) try: prop_value = value[prop_name] if read and prop.write_only: diff --git a/tests/unit/schema/test_schemas.py b/tests/unit/schema/test_schemas.py index a496566f..bfb673a2 100644 --- a/tests/unit/schema/test_schemas.py +++ b/tests/unit/schema/test_schemas.py @@ -9,7 +9,7 @@ from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType from openapi_core.schema.schemas.exceptions import ( InvalidSchemaValue, MultipleOneOfSchema, NoOneOfSchema, OpenAPISchemaError, - UndefinedSchemaProperty + UndefinedSchemaProperty, MissingSchemaProperty ) from openapi_core.schema.schemas.models import Schema @@ -1056,9 +1056,11 @@ def test_object_write_only_failed(self, value): }, ) - with pytest.raises(UndefinedSchemaProperty): + with pytest.raises(UndefinedSchemaProperty) as e: schema.validate(value, write=True) + assert 'ReadOnly property somestr defined on write.' in str(e) + @pytest.mark.parametrize('value', [ Model({ 'somestr': "asdf" @@ -1096,5 +1098,48 @@ def test_object_read_only_failed(self, value): }, ) - with pytest.raises(UndefinedSchemaProperty): + with pytest.raises(UndefinedSchemaProperty) as e: schema.validate(value, read=True) + assert 'WriteOnly property someint defined on read.' in str(e) + + @pytest.mark.parametrize('value', [ + Model({ + }), + ]) + def test_object_read_only_required_failed(self, value): + schema = Schema( + 'object', + properties={ + 'somestr': Schema('string', + read_only=True), + 'someint': Schema('integer', + write_only=True), + }, + required=['somestr', 'someint'] + ) + + with pytest.raises(MissingSchemaProperty) as e: + schema.validate(value, read=True) + assert 'Missing schema property: somestr' in str(e) + assert 'Missing schema property: someint' not in str(e) + + @pytest.mark.parametrize('value', [ + Model({ + }), + ]) + def test_object_write_only_required_failed(self, value): + schema = Schema( + 'object', + properties={ + 'somestr': Schema('string', + read_only=True), + 'someint': Schema('integer', + write_only=True), + }, + required=['somestr', 'someint'] + ) + + with pytest.raises(MissingSchemaProperty) as e: + schema.validate(value, write=True) + assert 'Missing schema property: someint' in str(e) + assert 'Missing schema property: somestr' not in str(e) From 66d2ace5727ac8fda9071c1a55608253a7ae2a27 Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Wed, 22 May 2019 10:45:21 -0500 Subject: [PATCH 7/8] Attempting to fix string issues between 2 and 3. --- tests/unit/schema/test_schemas.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/unit/schema/test_schemas.py b/tests/unit/schema/test_schemas.py index bfb673a2..2457003a 100644 --- a/tests/unit/schema/test_schemas.py +++ b/tests/unit/schema/test_schemas.py @@ -1059,7 +1059,8 @@ def test_object_write_only_failed(self, value): with pytest.raises(UndefinedSchemaProperty) as e: schema.validate(value, write=True) - assert 'ReadOnly property somestr defined on write.' in str(e) + assert 'ReadOnly property somestr defined on write.' \ + in six.text_type(e) @pytest.mark.parametrize('value', [ Model({ @@ -1100,7 +1101,8 @@ def test_object_read_only_failed(self, value): with pytest.raises(UndefinedSchemaProperty) as e: schema.validate(value, read=True) - assert 'WriteOnly property someint defined on read.' in str(e) + assert 'WriteOnly property someint defined on read.' \ + in six.text_type(e) @pytest.mark.parametrize('value', [ Model({ @@ -1120,8 +1122,8 @@ def test_object_read_only_required_failed(self, value): with pytest.raises(MissingSchemaProperty) as e: schema.validate(value, read=True) - assert 'Missing schema property: somestr' in str(e) - assert 'Missing schema property: someint' not in str(e) + assert 'Missing schema property: somestr' in six.text_type(e) + assert 'Missing schema property: someint' not in six.text_type(e) @pytest.mark.parametrize('value', [ Model({ @@ -1141,5 +1143,5 @@ def test_object_write_only_required_failed(self, value): with pytest.raises(MissingSchemaProperty) as e: schema.validate(value, write=True) - assert 'Missing schema property: someint' in str(e) - assert 'Missing schema property: somestr' not in str(e) + assert 'Missing schema property: someint' in six.text_type(e) + assert 'Missing schema property: somestr' not in six.text_type(e) From d369076bd135146c131cf0c92dab77f60d2571a5 Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Wed, 22 May 2019 11:02:08 -0500 Subject: [PATCH 8/8] Attempting to fix string issues between 2 and 3...again --- tests/unit/schema/test_schemas.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit/schema/test_schemas.py b/tests/unit/schema/test_schemas.py index 2457003a..2da1a304 100644 --- a/tests/unit/schema/test_schemas.py +++ b/tests/unit/schema/test_schemas.py @@ -1060,7 +1060,7 @@ def test_object_write_only_failed(self, value): schema.validate(value, write=True) assert 'ReadOnly property somestr defined on write.' \ - in six.text_type(e) + in six.text_type(e.value) @pytest.mark.parametrize('value', [ Model({ @@ -1102,7 +1102,7 @@ def test_object_read_only_failed(self, value): with pytest.raises(UndefinedSchemaProperty) as e: schema.validate(value, read=True) assert 'WriteOnly property someint defined on read.' \ - in six.text_type(e) + in six.text_type(e.value) @pytest.mark.parametrize('value', [ Model({ @@ -1122,8 +1122,8 @@ def test_object_read_only_required_failed(self, value): with pytest.raises(MissingSchemaProperty) as e: schema.validate(value, read=True) - assert 'Missing schema property: somestr' in six.text_type(e) - assert 'Missing schema property: someint' not in six.text_type(e) + assert 'Missing schema property: somestr' in six.text_type(e.value) + assert 'Missing schema property: someint' not in six.text_type(e.value) @pytest.mark.parametrize('value', [ Model({ @@ -1143,5 +1143,5 @@ def test_object_write_only_required_failed(self, value): with pytest.raises(MissingSchemaProperty) as e: schema.validate(value, write=True) - assert 'Missing schema property: someint' in six.text_type(e) - assert 'Missing schema property: somestr' not in six.text_type(e) + assert 'Missing schema property: someint' in six.text_type(e.value) + assert 'Missing schema property: somestr' not in six.text_type(e.value)