mirror of
https://github.com/ovh/python-ovh.git
synced 2026-01-16 23:00:21 +00:00
Support '_' prefixed alias for Python reserved keywords in API calls
Signed-off-by: Jean-Tiare LE BIGOT <jean-tiare.le-bigot@ovh.net>
This commit is contained in:
parent
afa35f7354
commit
3643dd40da
5 changed files with 151 additions and 5 deletions
|
|
@ -1,7 +1,12 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
## 0.3.0 (2014-09-23)
|
||||
## 0.3.1 (2014-12-22)
|
||||
|
||||
- [enhancement] support '_' prefixed keyword argument alias when colliding with Python reserved keywords
|
||||
- [enhancement] add API documentation
|
||||
|
||||
## 0.3.0 (2014-11-23)
|
||||
- [enhancement] add kimsufi API Europe/North-America
|
||||
- [enhancement] add soyoustart API Europe/North-America
|
||||
- [Q/A] add minimal integration test
|
||||
|
|
|
|||
34
README.rst
34
README.rst
|
|
@ -157,6 +157,40 @@ end-user on each use.
|
|||
{'method': 'DELETE', 'path': '/*'}
|
||||
]
|
||||
|
||||
Install a new mail redirection
|
||||
------------------------------
|
||||
|
||||
e-mail redirections may be freely configured on domains and DNS zones hosted by
|
||||
OVH to an arbitrary destination e-mail using API call
|
||||
``POST /email/domain/{domain}/redirection``.
|
||||
|
||||
For this call, the api specifies that the source adress shall be given under the
|
||||
``from`` keyword. Which is a problem as this is also a reserved Python keyword.
|
||||
In this case, simply prefix it with a '_', the wrapper will automatically detect
|
||||
it as being a prefixed reserved keyword and will subsitute it. Such aliasing
|
||||
is only supported with reserved keywords.
|
||||
|
||||
.. code:: python
|
||||
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import ovh
|
||||
|
||||
DOMAIN = "example.com"
|
||||
SOURCE = "sales@example.com"
|
||||
DESTINATION = "contact@example.com"
|
||||
|
||||
# create a client
|
||||
client = ovh.Client()
|
||||
|
||||
# Create a new alias
|
||||
client.post('/email/domain/%s/redirection' % DOMAIN,
|
||||
_from=SOURCE,
|
||||
to=DESTINATION
|
||||
localCopy=False
|
||||
)
|
||||
print "Installed new mail redirection from %s to %s" % (SOURCE, DESTINATION)
|
||||
|
||||
Grab bill list
|
||||
--------------
|
||||
|
||||
|
|
|
|||
|
|
@ -149,6 +149,40 @@ end-user on each use.
|
|||
{'method': 'DELETE', 'path': '/*'}
|
||||
]
|
||||
|
||||
Install a new mail redirection
|
||||
------------------------------
|
||||
|
||||
e-mail redirections may be freely configured on domains and DNS zones hosted by
|
||||
OVH to an arbitrary destination e-mail using API call
|
||||
``POST /email/domain/{domain}/redirection``.
|
||||
|
||||
For this call, the api specifies that the source adress shall be given under the
|
||||
``from`` keyword. Which is a problem as this is also a reserved Python keyword.
|
||||
In this case, simply prefix it with a '_', the wrapper will automatically detect
|
||||
it as being a prefixed reserved keyword and will subsitute it. Such aliasing
|
||||
is only supported with reserved keywords.
|
||||
|
||||
.. code:: python
|
||||
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import ovh
|
||||
|
||||
DOMAIN = "example.com"
|
||||
SOURCE = "sales@example.com"
|
||||
DESTINATION = "contact@example.com"
|
||||
|
||||
# create a client
|
||||
client = ovh.Client()
|
||||
|
||||
# Create a new alias
|
||||
client.post('/email/domain/%s/redirection' % DOMAIN,
|
||||
_from=SOURCE,
|
||||
to=DESTINATION
|
||||
localCopy=False
|
||||
)
|
||||
print "Installed new mail redirection from %s to %s" % (SOURCE, DESTINATION)
|
||||
|
||||
Grab bill list
|
||||
--------------
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ It handles requesting credential, signing queries...
|
|||
|
||||
import hashlib
|
||||
import urllib
|
||||
import keyword
|
||||
import time
|
||||
import json
|
||||
|
||||
|
|
@ -233,9 +234,38 @@ class Client(object):
|
|||
|
||||
## API shortcuts
|
||||
|
||||
def _canonicalize_kwargs(self, kwargs):
|
||||
"""
|
||||
If an API needs an argument colliding with a Python reserved keyword, it
|
||||
can be prefixed with an underscore. For example, ``from`` argument of
|
||||
``POST /email/domain/{domain}/redirection`` may be replaced by ``_from``
|
||||
|
||||
:param dict kwargs: input kwargs
|
||||
:return dict: filtered kawrgs
|
||||
"""
|
||||
arguments = {}
|
||||
|
||||
for k, v in kwargs.iteritems():
|
||||
if k[0] == '_' and k[1:] in keyword.kwlist:
|
||||
k = k[1:]
|
||||
arguments[k] = v
|
||||
|
||||
return arguments
|
||||
|
||||
def get(self, _target, _need_auth=True, **kwargs):
|
||||
"""'GET' :py:func:`Client.call` wrapper"""
|
||||
"""
|
||||
'GET' :py:func:`Client.call` wrapper.
|
||||
|
||||
Query string parameters can be set either directly in ``_target`` or as
|
||||
keywork arguments. If an argument collides with a Python reserved
|
||||
keyword, prefix it with a '_'. For instance, ``from`` becomes ``_from``.
|
||||
|
||||
:param string _target: API method to call
|
||||
:param string _need_auth: If True, send authentication headers. This is
|
||||
the default
|
||||
"""
|
||||
if kwargs:
|
||||
kwargs = self._canonicalize_kwargs(kwargs)
|
||||
query_string = urlencode(kwargs)
|
||||
if '?' in _target:
|
||||
_target = '%s&%s' % (_target, query_string)
|
||||
|
|
@ -245,15 +275,43 @@ class Client(object):
|
|||
return self.call('GET', _target, None, _need_auth)
|
||||
|
||||
def put(self, _target, _need_auth=True, **kwargs):
|
||||
"""'PUT' :py:func:`Client.call` wrapper"""
|
||||
"""
|
||||
'PUT' :py:func:`Client.call` wrapper
|
||||
|
||||
Body parameters can be set either directly in ``_target`` or as keywork
|
||||
arguments. If an argument collides with a Python reserved keyword,
|
||||
prefix it with a '_'. For instance, ``from`` becomes ``_from``.
|
||||
|
||||
:param string _target: API method to call
|
||||
:param string _need_auth: If True, send authentication headers. This is
|
||||
the default
|
||||
"""
|
||||
kwargs = self._canonicalize_kwargs(kwargs)
|
||||
return self.call('PUT', _target, kwargs, _need_auth)
|
||||
|
||||
def post(self, _target, _need_auth=True, **kwargs):
|
||||
"""'POST' :py:func:`Client.call` wrapper"""
|
||||
"""
|
||||
'POST' :py:func:`Client.call` wrapper
|
||||
|
||||
Body parameters can be set either directly in ``_target`` or as keywork
|
||||
arguments. If an argument collides with a Python reserved keyword,
|
||||
prefix it with a '_'. For instance, ``from`` becomes ``_from``.
|
||||
|
||||
:param string _target: API method to call
|
||||
:param string _need_auth: If True, send authentication headers. This is
|
||||
the default
|
||||
"""
|
||||
kwargs = self._canonicalize_kwargs(kwargs)
|
||||
return self.call('POST', _target, kwargs, _need_auth)
|
||||
|
||||
def delete(self, _target, _need_auth=True):
|
||||
"""'DELETE' :py:func:`Client.call` wrapper"""
|
||||
"""
|
||||
'DELETE' :py:func:`Client.call` wrapper
|
||||
|
||||
:param string _target: API method to call
|
||||
:param string _need_auth: If True, send authentication headers. This is
|
||||
the default
|
||||
"""
|
||||
return self.call('DELETE', _target, None, _need_auth)
|
||||
|
||||
## low level helpers
|
||||
|
|
|
|||
|
|
@ -131,6 +131,14 @@ class testClient(unittest.TestCase):
|
|||
|
||||
## test wrappers
|
||||
|
||||
def test__canonicalize_kwargs(self):
|
||||
api = Client(ENDPOINT, APPLICATION_KEY, APPLICATION_SECRET, CONSUMER_KEY)
|
||||
|
||||
self.assertEqual({}, api._canonicalize_kwargs({}))
|
||||
self.assertEqual({'from': 'value'}, api._canonicalize_kwargs({'from': 'value'}))
|
||||
self.assertEqual({'_to': 'value'}, api._canonicalize_kwargs({'_to': 'value'}))
|
||||
self.assertEqual({'from': 'value'}, api._canonicalize_kwargs({'_from': 'value'}))
|
||||
|
||||
@mock.patch.object(Client, 'call')
|
||||
def test_get(self, m_call):
|
||||
# basic test
|
||||
|
|
@ -150,6 +158,13 @@ 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¶m=test', None, True)
|
||||
|
||||
# keyword calling convention
|
||||
m_call.reset_mock()
|
||||
api = Client(ENDPOINT, APPLICATION_KEY, APPLICATION_SECRET, CONSUMER_KEY)
|
||||
self.assertEqual(m_call.return_value, api.get(FAKE_URL, _from="start", to="end"))
|
||||
m_call.assert_called_once_with('GET', FAKE_URL+'?to=end&from=start', None, True)
|
||||
|
||||
|
||||
@mock.patch.object(Client, 'call')
|
||||
def test_delete(self, m_call):
|
||||
api = Client(ENDPOINT, APPLICATION_KEY, APPLICATION_SECRET, CONSUMER_KEY)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue