Repository: Azure/msrest-for-python

Issue:
Validation failed if string is valid integer, but minimum/maximum is used.
Example from @derekbekoe 
```python
>>> ExpressRouteCircuitPeering(peer_asn='10002').validate()
[ValidationError("Parameter 'ExpressRouteCircuitPeering.peer_asn' failed to meet validation requirement.",)]
```

I see no reason to refuse that, and should take a look

Discussion:
codecov-io: # [Codecov](https://codecov.io/gh/Azure/msrest-for-python/pull/189?src=pr&el=h1) Report
> Merging [#189](https://codecov.io/gh/Azure/msrest-for-python/pull/189?src=pr&el=desc) into [master](https://codecov.io/gh/Azure/msrest-for-python/commit/c2249d459e8af8912c5da4cd728c8201066b9304?src=pr&el=desc) will **increase** coverage by `0.02%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/Azure/msrest-for-python/pull/189/graphs/tree.svg?width=650&token=Lny6ZO1MUF&height=150&src=pr)](https://codecov.io/gh/Azure/msrest-for-python/pull/189?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #189      +/-   ##
==========================================
+ Coverage   87.95%   87.97%   +0.02%     
==========================================
  Files          25       25              
  Lines        2598     2603       +5     
==========================================
+ Hits         2285     2290       +5     
  Misses        313      313
```


| [Impacted Files](https://codecov.io/gh/Azure/msrest-for-python/pull/189?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [msrest/serialization.py](https://codecov.io/gh/Azure/msrest-for-python/pull/189/diff?src=pr&el=tree#diff-bXNyZXN0L3NlcmlhbGl6YXRpb24ucHk=) | `91.27% <100%> (+0.04%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Azure/msrest-for-python/pull/189?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Azure/msrest-for-python/pull/189?src=pr&el=footer). Last update [c2249d4...45f2597](https://codecov.io/gh/Azure/msrest-for-python/pull/189?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/msrest/serialization.py b/msrest/serialization.py
index 1da64ae..7abaf70 100644
--- a/msrest/serialization.py
+++ b/msrest/serialization.py
@@ -217,6 +217,9 @@ class Model(object):
 
             try:
                 debug_name = "{}.{}".format(self.__class__.__name__, attr_name)
+                # https://github.com/Azure/msrest-for-python/issues/85
+                if value is not None and attr_type in Serializer.basic_types.values():
+                    value = Serializer.serialize_basic(value, attr_type)
                 Serializer.validate(value, debug_name, **self._validation.get(attr_name, {}))
             except ValidationError as validation_error:
                 validation_result.append(validation_error)
@@ -578,6 +581,14 @@ class Serializer(object):
                 raise errors[0]
         return self._serialize(data, data_type, **kwargs)
 
+    def _http_component_validation(self, data, data_type, name, **kwargs):
+        if self.client_side_validation:
+            # https://github.com/Azure/msrest-for-python/issues/85
+            if data is not None and data_type in self.basic_types.values():
+                data = self.serialize_basic(data, data_type, **kwargs)
+            data = self.validate(data, name, required=True, **kwargs)
+        return data
+
     def url(self, name, data, data_type, **kwargs):
         """Serialize data intended for a URL path.
 
@@ -587,8 +598,7 @@ class Serializer(object):
         :raises: TypeError if serialization fails.
         :raises: ValueError if data is None
         """
-        if self.client_side_validation:
-            data = self.validate(data, name, required=True, **kwargs)
+        data = self._http_component_validation(data, data_type, name, **kwargs)
         try:
             output = self.serialize_data(data, data_type, **kwargs)
             if data_type == 'bool':
@@ -612,8 +622,7 @@ class Serializer(object):
         :raises: TypeError if serialization fails.
         :raises: ValueError if data is None
         """
-        if self.client_side_validation:
-            data = self.validate(data, name, required=True, **kwargs)
+        data = self._http_component_validation(data, data_type, name, **kwargs)
         try:
             if data_type in ['[str]']:
                 data = ["" if d is None else d for d in data]
@@ -639,8 +648,7 @@ class Serializer(object):
         :raises: TypeError if serialization fails.
         :raises: ValueError if data is None
         """
-        if self.client_side_validation:
-            data = self.validate(data, name, required=True, **kwargs)
+        data = self._http_component_validation(data, data_type, name, **kwargs)
         try:
             if data_type in ['[str]']:
                 data = ["" if d is None else d for d in data]
@@ -713,14 +721,16 @@ class Serializer(object):
         else:
             return self._serialize(data, **kwargs)
 
-    def _get_custom_serializers(self, data_type, **kwargs):
+    @classmethod
+    def _get_custom_serializers(cls, data_type, **kwargs):
         custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type)
         if custom_serializer:
             return custom_serializer
         if kwargs.get("is_xml", False):
-            return self._xml_basic_types_serializers.get(data_type)
+            return cls._xml_basic_types_serializers.get(data_type)
 
-    def serialize_basic(self, data, data_type, **kwargs):
+    @classmethod
+    def serialize_basic(cls, data, data_type, **kwargs):
         """Serialize basic builting data type.
         Serializes objects to str, int, float or bool.
 
@@ -731,14 +741,15 @@ class Serializer(object):
         :param data: Object to be serialized.
         :param str data_type: Type of object in the iterable.
         """
-        custom_serializer = self._get_custom_serializers(data_type, **kwargs)
+        custom_serializer = cls._get_custom_serializers(data_type, **kwargs)
         if custom_serializer:
             return custom_serializer(data)
         if data_type == 'str':
-            return self.serialize_unicode(data)
+            return cls.serialize_unicode(data)
         return eval(data_type)(data)
 
-    def serialize_unicode(self, data):
+    @classmethod
+    def serialize_unicode(cls, data):
         """Special handling for serializing unicode strings in Py2.
         Encode to UTF-8 if unicode, otherwise handle as a str.
 


Test patch:
diff --git a/tests/test_serialization.py b/tests/test_serialization.py
index 00d253c..46df7f9 100644
--- a/tests/test_serialization.py
+++ b/tests/test_serialization.py
@@ -245,6 +245,32 @@ class TestRuntimeSerialized(unittest.TestCase):
         self.s = Serializer({'TestObj': self.TestObj})
         return super(TestRuntimeSerialized, self).setUp()
 
+    def test_validation_type(self):
+        # https://github.com/Azure/msrest-for-python/issues/85
+        s = Serializer()
+
+        s.query("filter", 186, "int", maximum=666)
+        s.query("filter", "186", "int", maximum=666)
+
+        class TestValidationObj(Model):
+
+            _attribute_map = {
+                'attr_a': {'key':'id', 'type':'int'},
+            }
+            _validation = {
+                'attr_a': {'maximum': 4294967295, 'minimum': 1},
+            }
+
+
+        test_obj = TestValidationObj()
+        test_obj.attr_a = 186
+        errors_found = test_obj.validate()
+        assert not errors_found
+
+        test_obj.attr_a = '186'
+        errors_found = test_obj.validate()
+        assert not errors_found
+
     def test_validation_flag(self):
         s = Serializer()
         s.client_side_validation = True