Hello community,

here is the log from the commit of package python-openapi-core for 
openSUSE:Factory checked in at 2019-09-13 14:57:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-openapi-core (Old)
 and      /work/SRC/openSUSE:Factory/.python-openapi-core.new.7948 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-openapi-core"

Fri Sep 13 14:57:54 2019 rev:4 rq:730065 version:0.11.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-openapi-core/python-openapi-core.changes  
2019-07-23 22:41:01.306899418 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-openapi-core.new.7948/python-openapi-core.changes
        2019-09-13 14:57:58.689276371 +0200
@@ -1,0 +2,7 @@
+Wed Sep 11 08:40:59 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 0.11.1:
+  * Path item parameter override (#145)
+  * Separate cast and unmarshal (#156)
+
+-------------------------------------------------------------------

Old:
----
  0.11.0.tar.gz

New:
----
  0.11.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-openapi-core.spec ++++++
--- /var/tmp/diff_new_pack.TZEABK/_old  2019-09-13 14:58:00.061276429 +0200
+++ /var/tmp/diff_new_pack.TZEABK/_new  2019-09-13 14:58:00.061276429 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-openapi-core
-Version:        0.11.0
+Version:        0.11.1
 Release:        0
 Summary:        Adds client-side and server-side support for the oas3
 License:        BSD-3-Clause

++++++ 0.11.0.tar.gz -> 0.11.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openapi-core-0.11.0/openapi_core/__init__.py 
new/openapi-core-0.11.1/openapi_core/__init__.py
--- old/openapi-core-0.11.0/openapi_core/__init__.py    2019-06-18 
23:42:44.000000000 +0200
+++ new/openapi-core-0.11.1/openapi_core/__init__.py    2019-09-07 
14:03:58.000000000 +0200
@@ -6,7 +6,7 @@
 
 __author__ = 'Artur Maciag'
 __email__ = '[email protected]'
-__version__ = '0.11.0'
+__version__ = '0.11.1'
 __url__ = 'https://github.com/p1c2u/openapi-core'
 __license__ = 'BSD 3-Clause License'
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openapi-core-0.11.0/openapi_core/schema/parameters/models.py 
new/openapi-core-0.11.1/openapi_core/schema/parameters/models.py
--- old/openapi-core-0.11.0/openapi_core/schema/parameters/models.py    
2019-06-18 23:42:44.000000000 +0200
+++ new/openapi-core-0.11.1/openapi_core/schema/parameters/models.py    
2019-09-07 14:03:58.000000000 +0200
@@ -109,10 +109,15 @@
             raise InvalidParameterValue(self.name, exc)
 
         try:
+            casted = self.schema.cast(deserialized)
+        except OpenAPISchemaError as exc:
+            raise InvalidParameterValue(self.name, exc)
+
+        try:
             unmarshalled = self.schema.unmarshal(
-                deserialized,
+                casted,
                 custom_formatters=custom_formatters,
-                strict=False,
+                strict=True,
             )
         except OpenAPISchemaError as exc:
             raise InvalidParameterValue(self.name, exc)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openapi-core-0.11.0/openapi_core/schema/schemas/models.py 
new/openapi-core-0.11.1/openapi_core/schema/schemas/models.py
--- old/openapi-core-0.11.0/openapi_core/schema/schemas/models.py       
2019-06-18 23:42:44.000000000 +0200
+++ new/openapi-core-0.11.1/openapi_core/schema/schemas/models.py       
2019-09-07 14:03:58.000000000 +0200
@@ -38,7 +38,13 @@
 class Schema(object):
     """Represents an OpenAPI Schema."""
 
-    DEFAULT_CAST_CALLABLE_GETTER = {
+    TYPE_CAST_CALLABLE_GETTER = {
+        SchemaType.INTEGER: int,
+        SchemaType.NUMBER: float,
+        SchemaType.BOOLEAN: forcebool,
+    }
+
+    DEFAULT_UNMARSHAL_CALLABLE_GETTER = {
     }
 
     STRING_FORMAT_CALLABLE_GETTER = {
@@ -155,7 +161,39 @@
 
         return set(required)
 
-    def get_cast_mapping(self, custom_formatters=None, strict=True):
+    def are_additional_properties_allowed(self, one_of_schema=None):
+        return (
+            (self.additional_properties is not False) and
+            (one_of_schema is None or
+                one_of_schema.additional_properties is not False)
+        )
+
+    def get_cast_mapping(self):
+        mapping = self.TYPE_CAST_CALLABLE_GETTER.copy()
+        mapping.update({
+            SchemaType.ARRAY: self._cast_collection,
+        })
+
+        return defaultdict(lambda: lambda x: x, mapping)
+
+    def cast(self, value):
+        """Cast value from string to schema type"""
+        if value is None:
+            return value
+
+        cast_mapping = self.get_cast_mapping()
+
+        cast_callable = cast_mapping[self.type]
+        try:
+            return cast_callable(value)
+        except ValueError:
+            raise InvalidSchemaValue(
+                "Failed to cast value {value} to type {type}", value, 
self.type)
+
+    def _cast_collection(self, value):
+        return list(map(self.items.cast, value))
+
+    def get_unmarshal_mapping(self, custom_formatters=None, strict=True):
         primitive_unmarshallers = self.get_primitive_unmarshallers(
             custom_formatters=custom_formatters)
 
@@ -166,7 +204,7 @@
 
         pass_defaults = lambda f: functools.partial(
           f, custom_formatters=custom_formatters, strict=strict)
-        mapping = self.DEFAULT_CAST_CALLABLE_GETTER.copy()
+        mapping = self.DEFAULT_UNMARSHAL_CALLABLE_GETTER.copy()
         mapping.update(primitive_unmarshallers_partial)
         mapping.update({
             SchemaType.ANY: pass_defaults(self._unmarshal_any),
@@ -176,15 +214,10 @@
 
         return defaultdict(lambda: lambda x: x, mapping)
 
-    def are_additional_properties_allowed(self, one_of_schema=None):
-        return (
-            (self.additional_properties is not False) and
-            (one_of_schema is None or
-                one_of_schema.additional_properties is not False)
-        )
-
-    def cast(self, value, custom_formatters=None, strict=True):
-        """Cast value to schema type"""
+    def unmarshal(self, value, custom_formatters=None, strict=True):
+        """Unmarshal parameter from the value."""
+        if self.deprecated:
+            warnings.warn("The schema is deprecated", DeprecationWarning)
         if value is None:
             if not self.nullable:
                 raise InvalidSchemaValue("Null value for non-nullable schema", 
value, self.type)
@@ -194,15 +227,15 @@
             raise InvalidSchemaValue(
                 "Value {value} not in enum choices: {type}", value, self.enum)
 
-        cast_mapping = self.get_cast_mapping(
+        unmarshal_mapping = self.get_unmarshal_mapping(
             custom_formatters=custom_formatters, strict=strict)
 
         if self.type is not SchemaType.STRING and value == '':
             return None
 
-        cast_callable = cast_mapping[self.type]
+        unmarshal_callable = unmarshal_mapping[self.type]
         try:
-            return cast_callable(value)
+            unmarshalled = unmarshal_callable(value)
         except UnmarshallerStrictTypeError:
             raise InvalidSchemaValue(
                 "Value {value} is not of type {type}", value, self.type)
@@ -210,17 +243,10 @@
             raise InvalidSchemaValue(
                 "Failed to cast value {value} to type {type}", value, 
self.type)
 
-    def unmarshal(self, value, custom_formatters=None, strict=True):
-        """Unmarshal parameter from the value."""
-        if self.deprecated:
-            warnings.warn("The schema is deprecated", DeprecationWarning)
-
-        casted = self.cast(value, custom_formatters=custom_formatters, 
strict=strict)
-
-        if casted is None and not self.required:
+        if unmarshalled is None and not self.required:
             return None
 
-        return casted
+        return unmarshalled
 
     def get_primitive_unmarshallers(self, **options):
         from openapi_core.schema.schemas.unmarshallers import (
@@ -247,18 +273,18 @@
             SchemaType.OBJECT, SchemaType.ARRAY, SchemaType.BOOLEAN,
             SchemaType.INTEGER, SchemaType.NUMBER, SchemaType.STRING,
         ]
-        cast_mapping = self.get_cast_mapping()
+        unmarshal_mapping = self.get_unmarshal_mapping()
         if self.one_of:
             result = None
             for subschema in self.one_of:
                 try:
-                    casted = subschema.cast(value, custom_formatters)
+                    unmarshalled = subschema.unmarshal(value, 
custom_formatters)
                 except (OpenAPISchemaError, TypeError, ValueError):
                     continue
                 else:
                     if result is not None:
                         raise MultipleOneOfSchema(self.type)
-                    result = casted
+                    result = unmarshalled
 
             if result is None:
                 raise NoOneOfSchema(self.type)
@@ -266,9 +292,9 @@
             return result
         else:
             for schema_type in types_resolve_order:
-                cast_callable = cast_mapping[schema_type]
+                unmarshal_callable = unmarshal_mapping[schema_type]
                 try:
-                    return cast_callable(value)
+                    return unmarshal_callable(value)
                 except UnmarshallerStrictTypeError:
                     continue
                 # @todo: remove ValueError when validation separated
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openapi-core-0.11.0/openapi_core/validation/request/validators.py 
new/openapi-core-0.11.1/openapi_core/validation/request/validators.py
--- old/openapi-core-0.11.0/openapi_core/validation/request/validators.py       
2019-06-18 23:42:44.000000000 +0200
+++ new/openapi-core-0.11.1/openapi_core/validation/request/validators.py       
2019-09-07 14:03:58.000000000 +0200
@@ -1,4 +1,5 @@
 """OpenAPI core validation request validators module"""
+from itertools import chain
 from six import iteritems
 
 from openapi_core.schema.exceptions import OpenAPIMappingError
@@ -28,30 +29,34 @@
 
         try:
             path = self.spec[operation_pattern]
-        # don't process if operation errors
-        except OpenAPIMappingError as exc:
-            return RequestValidationResult([exc, ], None, None)
-
-        path_params, path_params_errors = self._get_parameters(request, path)
-
-        try:
             operation = self.spec.get_operation(
                 operation_pattern, request.method)
         # don't process if operation errors
         except OpenAPIMappingError as exc:
             return RequestValidationResult([exc, ], None, None)
 
-        op_params, op_params_errors = self._get_parameters(request, operation)
+        params, params_errors = self._get_parameters(
+            request, chain(
+                iteritems(operation.parameters),
+                iteritems(path.parameters)
+            )
+        )
+
         body, body_errors = self._get_body(request, operation)
 
-        errors = path_params_errors + op_params_errors + body_errors
-        return RequestValidationResult(errors, body, path_params + op_params)
+        errors = params_errors + body_errors
+        return RequestValidationResult(errors, body, params)
 
-    def _get_parameters(self, request, operation):
+    def _get_parameters(self, request, params):
         errors = []
-
+        seen = set()
         parameters = RequestParameters()
-        for param_name, param in iteritems(operation.parameters):
+        for param_name, param in params:
+            if (param_name, param.location.value) in seen:
+                # skip parameter already seen
+                # e.g. overriden path item paremeter on operation
+                continue
+            seen.add((param_name, param.location.value))
             try:
                 raw_value = param.get_value(request)
             except MissingParameter:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openapi-core-0.11.0/tests/integration/test_validators.py 
new/openapi-core-0.11.1/tests/integration/test_validators.py
--- old/openapi-core-0.11.0/tests/integration/test_validators.py        
2019-06-18 23:42:44.000000000 +0200
+++ new/openapi-core-0.11.1/tests/integration/test_validators.py        
2019-09-07 14:03:58.000000000 +0200
@@ -235,7 +235,7 @@
 class TestPathItemParamsValidator(object):
 
     @pytest.fixture
-    def spec_dict(self, factory):
+    def spec_dict(self):
         return {
             "openapi": "3.0.0",
             "info": {
@@ -305,6 +305,50 @@
         assert result.body is None
         assert result.parameters == {'query': {'resId': 10}}
 
+    def test_request_override_param(self, spec_dict):
+        # override path parameter on operation
+        spec_dict["paths"]["/resource"]["get"]["parameters"] = [
+            {
+                # full valid parameter object required
+                "name": "resId",
+                "in": "query",
+                "required": False,
+                "schema": {
+                    "type": "integer",
+                },
+            }
+        ]
+        validator = RequestValidator(create_spec(spec_dict))
+        request = MockRequest('http://example.com', 'get', '/resource')
+        result = validator.validate(request)
+
+        assert len(result.errors) == 0
+        assert result.body is None
+        assert result.parameters == {}
+
+    def test_request_override_param_uniqueness(self, spec_dict):
+        # add parameter on operation with same name as on path but
+        # different location
+        spec_dict["paths"]["/resource"]["get"]["parameters"] = [
+            {
+                # full valid parameter object required
+                "name": "resId",
+                "in": "header",
+                "required": False,
+                "schema": {
+                    "type": "integer",
+                },
+            }
+        ]
+        validator = RequestValidator(create_spec(spec_dict))
+        request = MockRequest('http://example.com', 'get', '/resource')
+        result = validator.validate(request)
+
+        assert len(result.errors) == 1
+        assert type(result.errors[0]) == MissingRequiredParameter
+        assert result.body is None
+        assert result.parameters == {}
+
 
 class TestResponseValidator(object):
 


Reply via email to