Repository: podhmo/swagger-marshmallow-codegen

Issue:
some tests are broken

Discussion:

Patch:
diff --git a/examples/02default/definition.py b/examples/02default/definition.py
index 6b59f5c..97f70a4 100644
--- a/examples/02default/definition.py
+++ b/examples/02default/definition.py
@@ -43,12 +43,12 @@ class Length_validation(Schema):
 
 
 class Maximum_validation(Schema):
-    n0 = fields.Number(validate=[Range(min=None, max=100, exclusive_min=False, exclusive_max=False)])
-    n1 = fields.Number(validate=[Range(min=None, max=100, exclusive_min=False, exclusive_max=True)])
-    n2 = fields.Number(validate=[Range(min=None, max=100, exclusive_min=False, exclusive_max=False)])
-    m0 = fields.Number(validate=[Range(min=100, max=None, exclusive_min=False, exclusive_max=False)])
-    m1 = fields.Number(validate=[Range(min=100, max=None, exclusive_min=True, exclusive_max=False)])
-    m2 = fields.Number(validate=[Range(min=100, max=None, exclusive_min=False, exclusive_max=False)])
+    n0 = fields.Number(validate=[Range(min=None, max=100, min_inclusive=True, max_inclusive=True)])
+    n1 = fields.Number(validate=[Range(min=None, max=100, min_inclusive=True, max_inclusive=False)])
+    n2 = fields.Number(validate=[Range(min=None, max=100, min_inclusive=True, max_inclusive=True)])
+    m0 = fields.Number(validate=[Range(min=100, max=None, min_inclusive=True, max_inclusive=True)])
+    m1 = fields.Number(validate=[Range(min=100, max=None, min_inclusive=False, max_inclusive=True)])
+    m2 = fields.Number(validate=[Range(min=100, max=None, min_inclusive=True, max_inclusive=True)])
 
 
 class Regex_validation(Schema):
@@ -57,7 +57,7 @@ class Regex_validation(Schema):
 
 
 class Array_validation(Schema):
-    nums = fields.List(fields.Integer(), validate=[ItemsRange(min=1, max=10), Unique()])
+    nums = fields.List(fields.Integer(), validate=[ItemsRange(min=1, max=10, min_inclusive=True, max_inclusive=True), Unique()])
 
 
 class Enum_validation(Schema):
diff --git a/examples/05uber/main.py b/examples/05uber/main.py
index c611131..f4ce4db 100644
--- a/examples/05uber/main.py
+++ b/examples/05uber/main.py
@@ -6,12 +6,12 @@ if __name__ == "__main__":
     try:
         d = {
             "products": [
-                dict(product_id="x1", description="first", display_name="1st", capacity="4 people"),
+                dict(product_id="x1", description="first", display_name="1st", capacity="4"),
                 dict(
                     product_id="x2",
                     description="second",
                     display_name="2nd",
-                    capacity="5 people",
+                    capacity="5",
                     image="http://example.jp/img/notfound.jpg"
                 ),
             ]
diff --git a/examples/05uber/uberschema.py b/examples/05uber/uberschema.py
index 124f594..05b06c9 100644
--- a/examples/05uber/uberschema.py
+++ b/examples/05uber/uberschema.py
@@ -15,7 +15,7 @@ class Product(Schema):
 
 
 class ProductList(Schema):
-    products = fields.List(fields.Field('Product'), description='Contains the list of products')
+    products = fields.List(fields.Nested('Product'), description='Contains the list of products')
 
 
 class PriceEstimate(Schema):
@@ -44,7 +44,7 @@ class Activities(Schema):
     offset = fields.Integer(description='Position in pagination.')
     limit = fields.Integer(description='Number of items to retrieve (100 max).')
     count = fields.Integer(description='Total number of items available.')
-    history = fields.List(fields.Field('Activity'))
+    history = fields.List(fields.Nested('Activity'))
 
 
 class Error(Schema):
diff --git a/examples/07custom/myschema.py b/examples/07custom/myschema.py
index 5ee30ad..76de5a9 100644
--- a/examples/07custom/myschema.py
+++ b/examples/07custom/myschema.py
@@ -24,10 +24,10 @@ class ObjectId(fields.String):
         except (ValueError, AttributeError):
             self.fail('invalid_object_id')
 
-    def _deserialize(self, value, attr, data):
+    def _deserialize(self, value, attr, data, **kwargs):
         return self._validated(value)
 
-    def _serialize(self, value, attr, data):
+    def _serialize(self, value, attr, data, **kwargs):
         if not value:
             return value
         return str(value)
diff --git a/swagger_marshmallow_codegen/resolver.py b/swagger_marshmallow_codegen/resolver.py
index 8c54a97..5606561 100644
--- a/swagger_marshmallow_codegen/resolver.py
+++ b/swagger_marshmallow_codegen/resolver.py
@@ -130,9 +130,9 @@ class Resolver:
         if "minimum" in field or "maximum" in field:
             range_opts = {
                 "min": field.get("minimum"),
-                "exclusive_min": field.get("exclusiveMinimum", False),
+                "min_inclusive": not field.get("exclusiveMinimum", False),
                 "max": field.get("maximum"),
-                "exclusive_max": field.get("exclusiveMaximum", False),
+                "max_inclusive": not field.get("exclusiveMaximum", False),
             }
             add(validate.Range(**range_opts))
         if "minLength" in field or "maxLength" in field:
diff --git a/swagger_marshmallow_codegen/schema/extra.py b/swagger_marshmallow_codegen/schema/extra.py
index 2b91d56..88939dc 100644
--- a/swagger_marshmallow_codegen/schema/extra.py
+++ b/swagger_marshmallow_codegen/schema/extra.py
@@ -68,19 +68,20 @@ def make_additional_properties_schema_class(Schema):
         OPTIONS_CLASS = AdditionalPropertiesOpts
 
         @pre_load
-        @pre_dump
-        def wrap_dynamic_additionals(self, data):
-            diff = set(data.keys()).difference(self.fields.keys())
+        def wrap_load_dynamic_additionals(self, data, *, many=False, partial=False):
+            diff = set(data.keys()).difference(self.load_fields.keys())
             for name in diff:
                 f = self.opts.additional_field
-                self.fields[name] = f() if callable(f) else f
+                self.load_fields[name] = f() if callable(f) else f
             return data
 
-        def dumps(self, obj, many=None, *args, **kwargs):
-            return super().dumps(obj, many=many, *args, **kwargs)
-
-        def dump(self, obj, many=None, *args, **kwargs):
-            return super().dump(obj, many=many, *args, **kwargs)
+        @pre_dump
+        def wrap_dump_dynamic_additionals(self, data, *, many=False, partial=False):
+            diff = set(data.keys()).difference(self.dump_fields.keys())
+            for name in diff:
+                f = self.opts.additional_field
+                self.dump_fields[name] = f() if callable(f) else f
+            return data
 
     return AdditionalPropertiesSchema
 
diff --git a/swagger_marshmallow_codegen/validate.py b/swagger_marshmallow_codegen/validate.py
index 533e277..82f7d6a 100644
--- a/swagger_marshmallow_codegen/validate.py
+++ b/swagger_marshmallow_codegen/validate.py
@@ -1,51 +1,19 @@
 from marshmallow import validate as v
-from marshmallow.validate import (  # NOQA
-    Length,
-    Regexp,
-    OneOf,
-)
+from marshmallow.validate import Length, Regexp, OneOf  # NOQA
 
 
-class Range(v.Range):
-    def __init__(self, min=None, max=None, error=None, exclusive_max=False, exclusive_min=False):
-        super().__init__(min=min, max=max, error=error)
-        self.exclusive_max = exclusive_max
-        self.exclusive_min = exclusive_min
-
-    def _repr_args(self):
-        return 'min={0!r}, max={1!r}, exclusive_min={2!r}, exclusive_max={3!r}'.format(self.min, self.max, self.exclusive_min, self.exclusive_max)
-
-    def __call__(self, value):
-        if self.min is not None:
-            if self.exclusive_min:
-                over = value <= self.min
-            else:
-                over = value < self.min
-            if over:
-                message = self.message_min if self.max is None else self.message_all
-                raise v.ValidationError(self._format_error(value, message))
-
-        if self.max is not None:
-            if self.exclusive_max:
-                over = value >= self.max
-            else:
-                over = value > self.max
-            if over:
-                message = self.message_max if self.min is None else self.message_all
-                raise v.ValidationError(self._format_error(value, message))
-
-        return value
+Range = v.Range
 
 
 class MultipleOf(v.Validator):
-    message = '{input} is Not divisible by {n}'
+    message = "{input} is Not divisible by {n}"
 
     def __init__(self, n=1, error=None):
         self.n = n
         self.error = error
 
     def _repr_args(self):
-        return 'n={0!r}'.format(self.n)
+        return "n={0!r}".format(self.n)
 
     def _format_error(self, value):
         return self.message.format(input=value, n=self.n)
@@ -59,32 +27,24 @@ class MultipleOf(v.Validator):
 class ItemsRange(v.Range):
     """for maxItems and minItems"""
 
-    message_min = 'Must be at least {min} items.'
-    message_max = 'Must be at most {max} items.'
-    message_all = 'Must be between {min} and {max} items.'
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
+    message_min = "Must be {min_op} {{min}} items."
+    message_max = "Must be {max_op} {{max}} items."
+    message_all = "Must be {min_op} {{min}} and {max_op} {{max}} items."
 
-    def __call__(self, value):
-        if self.min is not None and len(value) < self.min:
-            message = self.message_min if self.max is None else self.message_all
-            raise v.ValidationError(self._format_error(value, message))
-
-        if self.max is not None and len(value) > self.max:
-            message = self.message_max if self.min is None else self.message_all
-            raise v.ValidationError(self._format_error(value, message))
-        return value
+    message_gte = "greater than or equal to"
+    message_gt = "greater than"
+    message_lte = "less than or equal to"
+    message_lt = "less than"
 
 
 class Unique(v.Validator):
-    message = '{input} is Not unique'
+    message = "{input} is Not unique"
 
     def __init__(self, error=None):
         self.error = error
 
     def _repr_args(self):
-        return ''
+        return ""
 
     def _format_error(self, value):
         return self.message.format(input=value)


Test patch:
diff --git a/swagger_marshmallow_codegen/tests/dst/00allOf.py b/swagger_marshmallow_codegen/tests/dst/00allOf.py
index b641802..7d0bdf8 100644
--- a/swagger_marshmallow_codegen/tests/dst/00allOf.py
+++ b/swagger_marshmallow_codegen/tests/dst/00allOf.py
@@ -18,4 +18,4 @@ class Cat(Pet):
 
 class Dog(Pet):
     """A representation of a dog"""
-    packSize = fields.Integer(required=True, description='the size of the pack the dog is from', validate=[Range(min=0, max=None, exclusive_min=False, exclusive_max=False)])
+    packSize = fields.Integer(required=True, description='the size of the pack the dog is from', validate=[Range(min=0, max=None, min_inclusive=True, max_inclusive=True)])
diff --git a/swagger_marshmallow_codegen/tests/dst/00items.py b/swagger_marshmallow_codegen/tests/dst/00items.py
index 9a8696d..3aa7e6a 100644
--- a/swagger_marshmallow_codegen/tests/dst/00items.py
+++ b/swagger_marshmallow_codegen/tests/dst/00items.py
@@ -9,4 +9,4 @@ from swagger_marshmallow_codegen.validate import (
 
 
 class A(Schema):
-    nums = fields.List(fields.Integer(), validate=[ItemsRange(min=1, max=10), Unique()])
+    nums = fields.List(fields.Integer(), validate=[ItemsRange(min=1, max=10, min_inclusive=True, max_inclusive=True), Unique()])
diff --git a/swagger_marshmallow_codegen/tests/dst/00maximum.py b/swagger_marshmallow_codegen/tests/dst/00maximum.py
index 08c690d..37ed6ff 100644
--- a/swagger_marshmallow_codegen/tests/dst/00maximum.py
+++ b/swagger_marshmallow_codegen/tests/dst/00maximum.py
@@ -8,9 +8,9 @@ from swagger_marshmallow_codegen.validate import (
 
 
 class X(Schema):
-    n0 = fields.Number(validate=[Range(min=None, max=100, exclusive_min=False, exclusive_max=False)])
-    n1 = fields.Number(validate=[Range(min=None, max=100, exclusive_min=False, exclusive_max=True)])
-    n2 = fields.Number(validate=[Range(min=None, max=100, exclusive_min=False, exclusive_max=False)])
-    m0 = fields.Number(validate=[Range(min=100, max=None, exclusive_min=False, exclusive_max=False)])
-    m1 = fields.Number(validate=[Range(min=100, max=None, exclusive_min=True, exclusive_max=False)])
-    m2 = fields.Number(validate=[Range(min=100, max=None, exclusive_min=False, exclusive_max=False)])
+    n0 = fields.Number(validate=[Range(min=None, max=100, min_inclusive=True, max_inclusive=True)])
+    n1 = fields.Number(validate=[Range(min=None, max=100, min_inclusive=True, max_inclusive=False)])
+    n2 = fields.Number(validate=[Range(min=None, max=100, min_inclusive=True, max_inclusive=True)])
+    m0 = fields.Number(validate=[Range(min=100, max=None, min_inclusive=True, max_inclusive=True)])
+    m1 = fields.Number(validate=[Range(min=100, max=None, min_inclusive=False, max_inclusive=True)])
+    m2 = fields.Number(validate=[Range(min=100, max=None, min_inclusive=True, max_inclusive=True)])
diff --git a/swagger_marshmallow_codegen/tests/dst/00paths.py b/swagger_marshmallow_codegen/tests/dst/00paths.py
index 7177bac..203028d 100644
--- a/swagger_marshmallow_codegen/tests/dst/00paths.py
+++ b/swagger_marshmallow_codegen/tests/dst/00paths.py
@@ -26,7 +26,7 @@ class PetsInput:
 
         class Query(Schema):
             animal_type = fields.String(validate=[Regexp(regex=re.compile('^[a-zA-Z0-9]*$'))])
-            limit = fields.Integer(missing=lambda: 100, validate=[Range(min=0, max=None, exclusive_min=False, exclusive_max=False)])
+            limit = fields.Integer(missing=lambda: 100, validate=[Range(min=0, max=None, min_inclusive=True, max_inclusive=True)])
 
 
 
diff --git a/swagger_marshmallow_codegen/tests/test_schema.py b/swagger_marshmallow_codegen/tests/test_schema.py
index ba9d8a5..4c47724 100644
--- a/swagger_marshmallow_codegen/tests/test_schema.py
+++ b/swagger_marshmallow_codegen/tests/test_schema.py
@@ -6,17 +6,27 @@ from marshmallow import fields, Schema
 class PrimitiveValueSchemaTests(unittest.TestCase):
     def _getTargetClass(self):
         from swagger_marshmallow_codegen.schema import PrimitiveValueSchema
+
         return PrimitiveValueSchema
 
-    def assert_value(self, fut, c):
+    def assert_load_value(self, fut, c):
         if c.ok:
             actual = fut()
             self.assertEqual(actual, c.expected)
         else:
             from marshmallow import ValidationError
+
             with self.assertRaises(ValidationError):
                 fut()
 
+    def assert_dump_value(self, fut, c):
+        if c.ok:
+            actual = fut()
+            self.assertEqual(actual, c.expected)
+        else:
+            with self.assertRaises(ValueError):
+                fut()
+
     def test_load_atom(self):
         class S(self._getTargetClass()):
             class schema_class(Schema):
@@ -29,7 +39,7 @@ class PrimitiveValueSchemaTests(unittest.TestCase):
         ]
         for c in candidates:
             with self.subTest(value=c.value, ok=c.ok):
-                self.assert_value(lambda: S().load(c.value), c)
+                self.assert_load_value(lambda: S().load(c.value), c)
 
     def test_load_list(self):
         class S(self._getTargetClass()):
@@ -44,7 +54,7 @@ class PrimitiveValueSchemaTests(unittest.TestCase):
         ]
         for c in candidates:
             with self.subTest(value=c.value, ok=c.ok):
-                self.assert_value(lambda: S().load(c.value), c)
+                self.assert_load_value(lambda: S().load(c.value), c)
 
     def test_dump_atom(self):
         class S(self._getTargetClass()):
@@ -59,7 +69,7 @@ class PrimitiveValueSchemaTests(unittest.TestCase):
         ]
         for c in candidates:
             with self.subTest(value=c.value, ok=c.ok):
-                self.assert_value(lambda: S().dump(c.value), c)
+                self.assert_dump_value(lambda: S().dump(c.value), c)
 
     def test_dump_list(self):
         class S(self._getTargetClass()):
@@ -74,12 +84,13 @@ class PrimitiveValueSchemaTests(unittest.TestCase):
         ]
         for c in candidates:
             with self.subTest(value=c.value, ok=c.ok):
-                self.assert_value(lambda: S().dump(c.value), c)
+                self.assert_dump_value(lambda: S().dump(c.value), c)
 
 
-class AddtioinalSchemaTests(unittest.TestCase):
+class AdditioinalSchemaTests(unittest.TestCase):
     def _getTargetClass(self):
         from swagger_marshmallow_codegen.schema import AdditionalPropertiesSchema
+
         return AdditionalPropertiesSchema
 
     def assert_value(self, fut, c):
@@ -88,6 +99,7 @@ class AddtioinalSchemaTests(unittest.TestCase):
             self.assertEqual(actual, c.expected)
         else:
             from marshmallow import ValidationError
+
             with self.assertRaises(ValidationError):
                 fut()
 
@@ -98,12 +110,10 @@ class AddtioinalSchemaTests(unittest.TestCase):
         C = namedtuple("C", "value, expected, ok")
         candidates = [
             C(
-                value={"name": "foo",
-                       "value": "100"},
-                expected={"name": "foo",
-                          "value": "100"},
-                ok=True
-            ),
+                value={"name": "foo", "value": "100"},
+                expected={"name": "foo", "value": "100"},
+                ok=True,
+            )
         ]
         for c in candidates:
             with self.subTest(value=c.value, ok=c.ok):
@@ -119,18 +129,14 @@ class AddtioinalSchemaTests(unittest.TestCase):
         C = namedtuple("C", "value, expected, ok")
         candidates = [
             C(
-                value={"name": "foo",
-                       "value": "100"},
-                expected={"name": "foo",
-                          "value": 100},
-                ok=True
+                value={"name": "foo", "value": "100"},
+                expected={"name": "foo", "value": 100},
+                ok=True,
             ),
             C(
-                value={"name": "foo",
-                       "value": "100"},
-                expected={"name": "foo",
-                          "value": 100},
-                ok=True
+                value={"name": "foo", "value": "100"},
+                expected={"name": "foo", "value": 100},
+                ok=True,
             ),
         ]
         for c in candidates:
@@ -144,12 +150,10 @@ class AddtioinalSchemaTests(unittest.TestCase):
         C = namedtuple("C", "value, expected, ok")
         candidates = [
             C(
-                value={"name": "foo",
-                       "value": "100"},
-                expected={"name": "foo",
-                          "value": "100"},
-                ok=True
-            ),
+                value={"name": "foo", "value": "100"},
+                expected={"name": "foo", "value": "100"},
+                ok=True,
+            )
         ]
         for c in candidates:
             with self.subTest(value=c.value, ok=c.ok):
@@ -165,18 +169,14 @@ class AddtioinalSchemaTests(unittest.TestCase):
         C = namedtuple("C", "value, expected, ok")
         candidates = [
             C(
-                value={"name": "foo",
-                       "value": "100"},
-                expected={"name": "foo",
-                          "value": 100},
-                ok=True
+                value={"name": "foo", "value": "100"},
+                expected={"name": "foo", "value": 100},
+                ok=True,
             ),
             C(
-                value={"name": "foo",
-                       "value": "100"},
-                expected={"name": "foo",
-                          "value": 100},
-                ok=True
+                value={"name": "foo", "value": "100"},
+                expected={"name": "foo", "value": 100},
+                ok=True,
             ),
         ]
         for c in candidates:
diff --git a/swagger_marshmallow_codegen/tests/test_validate.py b/swagger_marshmallow_codegen/tests/test_validate.py
index 4e8f0b5..e1aade5 100644
--- a/swagger_marshmallow_codegen/tests/test_validate.py
+++ b/swagger_marshmallow_codegen/tests/test_validate.py
@@ -5,6 +5,7 @@ from collections import namedtuple
 class RangeTests(unittest.TestCase):
     def _makeOne(self, *args, **kwargs):
         from swagger_marshmallow_codegen.validate import Range
+
         return Range(*args, **kwargs)
 
     def test_maximum(self):
@@ -23,7 +24,9 @@ class RangeTests(unittest.TestCase):
             with self.subTest(
                 maximum=c.maximum, exclusive_maximum=c.exclusive_maximum, value=c.value
             ):
-                target = self._makeOne(max=c.maximum, exclusive_max=c.exclusive_maximum)
+                target = self._makeOne(
+                    max=c.maximum, max_inclusive=not c.exclusive_maximum
+                )
                 try:
                     target(c.value)
                     self.assertTrue(c.ok)
@@ -46,7 +49,9 @@ class RangeTests(unittest.TestCase):
             with self.subTest(
                 minimum=c.minimum, exclusive_minimum=c.exclusive_minimum, value=c.value
             ):
-                target = self._makeOne(min=c.minimum, exclusive_min=c.exclusive_minimum)
+                target = self._makeOne(
+                    min=c.minimum, min_inclusive=not c.exclusive_minimum
+                )
                 try:
                     target(c.value)
                     self.assertTrue(c.ok)
@@ -57,6 +62,7 @@ class RangeTests(unittest.TestCase):
 class MultipleOfTests(unittest.TestCase):
     def _makeOne(self, *args, **kwargs):
         from swagger_marshmallow_codegen.validate import MultipleOf
+
         return MultipleOf(*args, **kwargs)
 
     def test_it(self):