Repository: ovh/python-ovh

Issue:
API raises BadParameterError for boolean arguments
Hello,

When an API call requires a boolean argument, we send it as `True` or `False` (valid Python booleans) but the API raises `BadParametersError` because it waits for a string (`'true'` or `'false'`) :

```python
In [1]: import ovh

In [2]: client = ovh.Client()

In [3]: client.get('/hosting/web/ncrocfer.ovh/ovhConfig', historical=False)
---------------------------------------------------------------------------
BadParametersError                        Traceback (most recent call last)
<ipython-input-3-b9140291291d> in <module>()
----> 1 client.get('/hosting/web/ncrocfer.ovh/ovhConfig', historical=False)

/home/ncrocfer/.virtualenvs/ovh/lib/python3.4/site-packages/ovh/client.py in get(self, _target, _need_auth, **kwargs)
    317                 _target = '%s?%s' % (_target, query_string)
    318 
--> 319         return self.call('GET', _target, None, _need_auth)
    320 
    321     def put(self, _target, _need_auth=True, **kwargs):

/home/ncrocfer/.virtualenvs/ovh/lib/python3.4/site-packages/ovh/client.py in call(self, method, path, data, need_auth)
    446             raise ResourceNotFoundError(json_result.get('message'))
    447         elif status == 400:
--> 448             raise BadParametersError(json_result.get('message'))
    449         elif status == 409:
    450             raise ResourceConflictError(json_result.get('message'))

BadParametersError: [historical] Given data (False) is not valid for type boolean

In [4]: client.get('/hosting/web/ncrocfer.ovh/ovhConfig', historical='false')
Out[4]: [1779827]
```

Is it possible to translate automatically the boolean argument to be API compatible ?
Thanks.

Discussion:
ncrocfer: Yep, it's ok for me :

```python
In [1]: import ovh

In [2]: ovh.Client().get('/hosting/web/ncrocfer.ovh/ovhConfig', historical=False)
Out[2]: [1779827]
```
Thanks  :+1:


Patch:
diff --git a/ovh/client.py b/ovh/client.py
index fe989cf..82db162 100644
--- a/ovh/client.py
+++ b/ovh/client.py
@@ -289,14 +289,24 @@ class Client(object):
         can be prefixed with an underscore. For example, ``from`` argument of
         ``POST /email/domain/{domain}/redirection`` may be replaced by ``_from``
 
+        This function also handles Python booleans which should be serialized
+        using solely lowercase to be recognized by the API.
+
         :param dict kwargs: input kwargs
         :return dict: filtered kawrgs
         """
         arguments = {}
 
         for k, v in kwargs.items():
+            # Handle Python keywork collision
             if k[0] == '_' and k[1:] in keyword.kwlist:
                 k = k[1:]
+
+            # Handle Booleans
+            if isinstance(v, bool):
+                v = str(v).lower()
+
+            # Commit
             arguments[k] = v
 
         return arguments


Test patch:
diff --git a/tests/test_client.py b/tests/test_client.py
index ddea110..66b300a 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -185,6 +185,12 @@ class testClient(unittest.TestCase):
         self.assertEqual(m_call.return_value, api.get(FAKE_URL+'?query=string', param="test"))
         m_call.assert_called_once_with('GET', FAKE_URL+'?query=string&param=test', None, True)
 
+        # boolean arguments
+        m_call.reset_mock()
+        api = Client(ENDPOINT, APPLICATION_KEY, APPLICATION_SECRET, CONSUMER_KEY)
+        self.assertEqual(m_call.return_value, api.get(FAKE_URL+'?query=string', checkbox=True))
+        m_call.assert_called_once_with('GET', FAKE_URL+'?query=string&checkbox=true', None, True)
+
         # keyword calling convention
         m_call.reset_mock()
         api = Client(ENDPOINT, APPLICATION_KEY, APPLICATION_SECRET, CONSUMER_KEY)