From a707d38e258e40105f6f884fceefad374dc52204 Mon Sep 17 00:00:00 2001 From: Kyle Hornberg Date: Tue, 6 Feb 2018 07:10:41 -0600 Subject: [PATCH] Enhancement: Validate request body parameters and use defaults --- src/octokit/__init__.py | 21 +++++++++++--------- tests/test_methods.py | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/octokit/__init__.py b/src/octokit/__init__.py index 439bf6c..7c0479f 100644 --- a/src/octokit/__init__.py +++ b/src/octokit/__init__.py @@ -10,7 +10,7 @@ __version__ = '0.1.0' class Base(object): - headers = {} + headers = {} # TODO default headers base_url = 'https://api.github.com' def _get_headers(self, definition): @@ -21,8 +21,10 @@ class Base(object): for p in required_params: assert p in kwargs # has all required for kwarg, value in kwargs.items(): - param = params.get(kwarg) - assert param # is a valid param but not necessarily required + param_value = params.get(kwarg) + assert param_value # is a valid param but not necessarily required + if param_value.get('enum'): + assert value in param_value.get('enum') # is a valid option of the enum if kwarg in required_params: assert value # required param has a value @@ -31,12 +33,16 @@ class Base(object): for name, value in values.items(): _url, subs = re.subn(f':{name}', str(value), _url) if subs != 0: - # TODO - # it seems like params not in the url are in the body data data_values.pop(name) url = f'{self.base_url}{_url}' return url, data_values + def _get_data(self, kwargs, params): + for param, value in params.items(): + if value.get('default') and not kwargs.get(param): + kwargs[param] = value.get('default') + return json.dumps(kwargs) if kwargs else None + class Octokit(Base): @@ -65,10 +71,7 @@ class Octokit(Base): def _api_call(*args, **kwargs): self._validate(kwargs, definition.get('params')) url, data_kwargs = self._form_url(kwargs, definition['url']) - # TODO for post, put, patch data - # use defaults for params - # data = json.dumps(o_kwargs) if o_kwargs else None - data = None + data = self._get_data(data_kwargs, definition.get('params')) return getattr(requests, definition['method'].lower())( url, headers=self._get_headers(definition), data=data ) diff --git a/tests/test_methods.py b/tests/test_methods.py index fc816b4..6396ac1 100644 --- a/tests/test_methods.py +++ b/tests/test_methods.py @@ -1,6 +1,7 @@ from octokit import Octokit import requests import pytest +import json class TestClientMethods(object): @@ -35,3 +36,45 @@ class TestClientMethods(object): mocker.patch('requests.get') Octokit().authorization.get(id=100) requests.get.assert_called_once_with('https://api.github.com/authorizations/100', data=None, headers={}) + + def test_request_has_body_parameters(self, mocker): + mocker.patch('requests.post') + data = { + 'scopes': [ + 'public_repo' + ], + 'note': 'admin script' + } + Octokit().authorization.create(**data) + requests.post.assert_called_once_with( + 'https://api.github.com/authorizations', data=json.dumps(data), headers={} + ) + + def test_must_include_required_body_parameters(self): + data = { + 'gist_id': 'abc123', + } + with pytest.raises(AssertionError): + Octokit().authorization.create(**data) + + def test_use_default_parameter_values(self, mocker): + mocker.patch('requests.patch') + headers = {'accept': 'application/vnd.github.squirrel-girl-preview'} + data = {'state': 'open'} + Octokit().issues.edit(owner='testUser', repo='testRepo', number=1) + requests.patch.assert_called_once_with( + 'https://api.github.com/repos/testUser/testRepo/issues/1', data=json.dumps(data), headers=headers + ) + + def test_use_passed_value_instead_of_default_parameter_values(self, mocker): + mocker.patch('requests.patch') + headers = {'accept': 'application/vnd.github.squirrel-girl-preview'} + data = {'state': 'closed'} + Octokit().issues.edit(owner='testUser', repo='testRepo', number=1, **data) + requests.patch.assert_called_once_with( + 'https://api.github.com/repos/testUser/testRepo/issues/1', data=json.dumps(data), headers=headers + ) + + def test_validate_enum_values(self): + with pytest.raises(AssertionError): + Octokit().issues.edit(owner='testUser', repo='testRepo', number=1, state='closeddddd')