Skip to content

Commit

Permalink
Allow Pythonic, underscore-separated parameters to be passed in and t…
Browse files Browse the repository at this point in the history
…ransformed into MyGeotab's camel-case standard for parameters
  • Loading branch information
aaront committed Dec 17, 2015
1 parent 72f451b commit 8316470
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 12 deletions.
41 changes: 30 additions & 11 deletions mygeotab/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
from urlparse import urlparse

import json
import re

import requests

import mygeotab.serializers

requests.packages.urllib3.disable_warnings()
try:
requests.packages.urllib3.disable_warnings()
except:
pass


class API(object):
Expand Down Expand Up @@ -80,6 +84,23 @@ def _process(data):
return data
return None

def _process_param_names(self, parameters):
"""
Allows the use of Pythonic-style parameters with underscores instead of camel-case
:param parameters: The parameters object dict
:return: The processed parameters
"""
for param_name in parameters:
value = parameters[param_name]
server_param_name = re.sub(r'_(\w)', lambda m: m.group(1).upper(), param_name)
if isinstance(value, dict):
value = self._process_param_names(value)
parameters[server_param_name] = value
if server_param_name != param_name:
del parameters[param_name]
return parameters

def _query(self, method, parameters):
"""
Formats and performs the query against the API
Expand All @@ -98,12 +119,11 @@ def _query(self, method, parameters):
headers=headers, allow_redirects=True, verify=is_live)
return self._process(r.json(object_hook=mygeotab.serializers.object_deserializer))

def call(self, method, type_name=None, **parameters):
def call(self, method, **parameters):
"""
Makes a call to the API.
:param method: The method name.
:param type_name: The type of entity for generic methods (for example, 'Get')
:param parameters: Additional parameters to send (for example, search=dict(id='b123') )
:return: The JSON result (decoded into a dict) from the server
:raise MyGeotabException: Raises when an exception occurs on the MyGeotab server
Expand All @@ -112,8 +132,7 @@ def call(self, method, type_name=None, **parameters):
raise Exception("Must specify a method name")
if parameters is None:
parameters = {}
if type_name:
parameters['typeName'] = type_name
parameters = self._process_param_names(parameters)
if self.credentials is None:
self.authenticate()
if 'credentials' not in parameters and self.credentials.session_id:
Expand All @@ -128,7 +147,7 @@ def call(self, method, type_name=None, **parameters):
if exception.name == 'InvalidUserException' and self._reauthorize_count == 0:
self._reauthorize_count += 1
self.authenticate()
return self.call(method, parameters)
return self.call(method, **parameters)
raise
return None

Expand All @@ -152,7 +171,7 @@ def get(self, type_name, **parameters):
:return: The JSON result (decoded into a dict) from the server
:raise MyGeotabException: Raises when an exception occurs on the MyGeotab server
"""
return self.call('Get', type_name, **parameters)
return self.call('Get', type_name=type_name, **parameters)

def search(self, type_name, **parameters):
"""
Expand All @@ -168,7 +187,7 @@ def search(self, type_name, **parameters):
if results_limit is not None:
del parameters['resultsLimit']
parameters = dict(search=parameters)
return self.call('Get', type_name, resultsLimit=results_limit, **parameters)
return self.call('Get', type_name=type_name, resultsLimit=results_limit, **parameters)
return self.get(type_name)

def add(self, type_name, entity):
Expand All @@ -180,7 +199,7 @@ def add(self, type_name, entity):
:return: The id of the object added
:raise MyGeotabException: Raises when an exception occurs on the MyGeotab server
"""
return self.call('Add', type_name, entity=entity)
return self.call('Add', type_name=type_name, entity=entity)

def set(self, type_name, entity):
"""
Expand All @@ -190,7 +209,7 @@ def set(self, type_name, entity):
:param entity: The entity to set
:raise MyGeotabException: Raises when an exception occurs on the MyGeotab server
"""
return self.call('Set', type_name, entity=entity)
return self.call('Set', type_name=type_name, entity=entity)

def remove(self, type_name, entity):
"""
Expand All @@ -200,7 +219,7 @@ def remove(self, type_name, entity):
:param entity: The entity to remove
:raise MyGeotabException: Raises when an exception occurs on the MyGeotab server
"""
return self.call('Remove', type_name, entity=entity)
return self.call('Remove', type_name=type_name, entity=entity)

def authenticate(self):
"""
Expand Down
7 changes: 6 additions & 1 deletion tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def setUp(self):
if self.username and password:
self.api = api.API(self.username, password=password, database=self.database)
self.api.authenticate()
password = None
del password
else:
self.skipTest(
'Can\'t make calls to the API without the MYGEOTAB_USERNAME and MYGEOTAB_PASSWORD environment '
Expand All @@ -81,6 +81,11 @@ def test_get_user(self):
user = user[0]
self.assertEqual(user['name'], self.username)

def test_pythonic_parameters(self):
users = self.api.get('User')
count_users = self.api.call('GetCountOf', type_name='User')
self.assertGreaterEqual(count_users, 1)
self.assertEqual(count_users, len(users))

if __name__ == '__main__':
unittest.main()

0 comments on commit 8316470

Please sign in to comment.