diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c59820..154af5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ Current Version + - Update flake8 quote linting - Add official support for Python 3.7 - Drop official support for Python 2.6, 3.2, 3.3 diff --git a/pybutton/client.py b/pybutton/client.py index 476df32..5406cc8 100644 --- a/pybutton/client.py +++ b/pybutton/client.py @@ -12,7 +12,7 @@ class Client(object): - '''Top-level interface for making requests to the Button API. + """Top-level interface for making requests to the Button API. All resources implemented in this client will be exposed as attributes of a pybutton.Client instance. @@ -37,7 +37,7 @@ class Client(object): Raises: pybutton.ButtonClientError - ''' + """ def __init__(self, api_key, config=None): diff --git a/pybutton/error.py b/pybutton/error.py index 45076f5..053ec68 100644 --- a/pybutton/error.py +++ b/pybutton/error.py @@ -5,19 +5,19 @@ class ButtonClientError(Exception): - '''An Exception class for all pybutton understood errors. - ''' + """An Exception class for all pybutton understood errors. + """ class HTTPResponseError(ButtonClientError): - '''A non-success HTTP response was returned from the remote API. + """A non-success HTTP response was returned from the remote API. The HTTP response status code can be retrieved from the `.status_code` property. The original error object can be retrieved from the `.cause` property. - ''' + """ def __init__(self, message, status_code, cause): super(HTTPResponseError, self).__init__(message) self.status_code = status_code diff --git a/pybutton/request.py b/pybutton/request.py index 230aaa7..3bf8a73 100644 --- a/pybutton/request.py +++ b/pybutton/request.py @@ -26,7 +26,7 @@ from urllib.parse import parse_qs def request(url, method, headers, data=None, timeout=None): - ''' Make an HTTP request in Python 3.x + """ Make an HTTP request in Python 3.x This method will abstract the underlying organization and invocation of the Python 3 HTTP standard lib implementation. @@ -45,7 +45,7 @@ def request(url, method, headers, data=None, timeout=None): Returns: (dict): The response from the server interpreted as JSON. - ''' + """ encoded_data = json.dumps(data).encode('utf8') if data else None request = Request(url, data=encoded_data, headers=headers) @@ -71,7 +71,7 @@ def request(url, method, headers, data=None, timeout=None): from urlparse import parse_qs def request(url, method, headers, data=None, timeout=None): - ''' Make an HTTP request in Python 2.x + """ Make an HTTP request in Python 2.x This method will abstract the underlying organization and invocation of the Python 2 HTTP standard lib implementation. @@ -90,7 +90,7 @@ def request(url, method, headers, data=None, timeout=None): Returns: (dict): The response from the server interpreted as JSON. - ''' + """ request = Request(url) request.get_method = lambda: method @@ -111,7 +111,7 @@ def request(url, method, headers, data=None, timeout=None): def request_url(secure, hostname, port, path, query=None): - ''' + """ Combines url components into a url passable into the request function. Args: @@ -123,7 +123,7 @@ def request_url(secure, hostname, port, path, query=None): Returns: (str) A complete url made up of the arguments. - ''' + """ encoded_query = urlencode(query) if query else '' scheme = 'https' if secure else 'http' netloc = '{0}:{1}'.format(hostname, port) @@ -132,7 +132,7 @@ def request_url(secure, hostname, port, path, query=None): def query_dict(url): - ''' + """ Given a url, returns a dictionary of its query parameters. Args: @@ -145,7 +145,7 @@ def query_dict(url): ... } - ''' + """ url_components = urlparse(url) if (url_components): diff --git a/pybutton/resources/accounts.py b/pybutton/resources/accounts.py index 7078393..435d3a0 100644 --- a/pybutton/resources/accounts.py +++ b/pybutton/resources/accounts.py @@ -7,14 +7,14 @@ class Accounts(Resource): - '''Manages interacting with Button Accounts via the Button API + """Manages interacting with Button Accounts via the Button API See Resource for class docstring. - ''' + """ def all(self): - '''Get a list of available accounts + """Get a list of available accounts Raises: pybutton.ButtonClientError @@ -22,13 +22,13 @@ def all(self): Returns: (pybutton.Response) The API response - ''' + """ return self.api_get('/v1/affiliation/accounts') def transactions(self, account_id, cursor=None, start=None, end=None, time_field=None): - '''Get a list of transactions. + """Get a list of transactions. To paginate transactions, pass the result of response.next_cursor() as the cursor argument. @@ -50,7 +50,7 @@ def transactions(self, account_id, cursor=None, start=None, end=None, Returns: (pybutton.Response) The API response - ''' + """ query = {} diff --git a/pybutton/resources/customers.py b/pybutton/resources/customers.py index a59ca98..6bbd2ef 100644 --- a/pybutton/resources/customers.py +++ b/pybutton/resources/customers.py @@ -7,14 +7,14 @@ class Customers(Resource): - '''Manages interacting with Button Customers via the Button API + """Manages interacting with Button Customers via the Button API See Resource for class docstring. - ''' + """ def _path(self, customer_id=None): - '''Format a url path + """Format a url path Args: customer_id (str) optional: A Button customer id ('customer-XXX') @@ -22,7 +22,7 @@ def _path(self, customer_id=None): Returns: (str): The formatted path - ''' + """ if customer_id: return '/v1/customers/{0}'.format(customer_id) @@ -30,7 +30,7 @@ def _path(self, customer_id=None): return '/v1/customers' def get(self, customer_id): - '''Get a customer + """Get a customer Args: customer_id (str) : A Button customer id ('customer-XXX') @@ -41,12 +41,12 @@ def get(self, customer_id): Returns: (pybutton.Response) The API response - ''' + """ return self.api_get(self._path(customer_id)) def create(self, customer): - '''Create an customer + """Create an customer Args: customer (dict): A dict representing the attributes of an customer @@ -57,6 +57,6 @@ def create(self, customer): Returns: (pybutton.Response) The API response - ''' + """ return self.api_post(self._path(), customer) diff --git a/pybutton/resources/links.py b/pybutton/resources/links.py index 205addb..cd9d102 100644 --- a/pybutton/resources/links.py +++ b/pybutton/resources/links.py @@ -7,14 +7,14 @@ class Links(Resource): - '''Manages interacting with Button Links via the Button API + """Manages interacting with Button Links via the Button API See Resource for class docstring. - ''' + """ def _path(self): - '''Format a url path + """Format a url path Args: link (dict): A dict representing the attributes of a link @@ -22,12 +22,12 @@ def _path(self): Returns: (str): The formatted path - ''' + """ return '/v1/links' def create(self, link): - '''Create a link + """Create a link Args: link (dict): A dict representing the attributes of a link @@ -38,12 +38,12 @@ def create(self, link): Returns: (pybutton.Response) The API response - ''' + """ return self.api_post(self._path(), link) def get_info(self, link): - '''Get info on a link + """Get info on a link Args: link (dict): A dict representing the attributes of a link for info @@ -54,6 +54,6 @@ def get_info(self, link): Returns: (pybutton.Response) The API response - ''' + """ return self.api_post(self._path() + '/info', link) diff --git a/pybutton/resources/merchants.py b/pybutton/resources/merchants.py index 18e5250..1eceec8 100644 --- a/pybutton/resources/merchants.py +++ b/pybutton/resources/merchants.py @@ -7,14 +7,14 @@ class Merchants(Resource): - '''Manages interacting with Button Merchants via the Button API + """Manages interacting with Button Merchants via the Button API See Resource for class docstring. - ''' + """ def all(self, status=None, currency=None): - '''Get a list of merchants and their configured rates + """Get a list of merchants and their configured rates Args: status (str) optional: A status to filter by. One of ('approved', @@ -28,7 +28,7 @@ def all(self, status=None, currency=None): Returns: (pybutton.Response) The API response - ''' + """ query = {} diff --git a/pybutton/resources/orders.py b/pybutton/resources/orders.py index 65f6b24..32a379b 100644 --- a/pybutton/resources/orders.py +++ b/pybutton/resources/orders.py @@ -7,14 +7,14 @@ class Orders(Resource): - '''Manages interacting with Button Orders via the Button API + """Manages interacting with Button Orders via the Button API See Resource for class docstring. - ''' + """ def _path(self, order_id=None): - '''Format a url path + """Format a url path Args: order_id (str) optional: A Button order id ('btnorder-XXX') @@ -22,7 +22,7 @@ def _path(self, order_id=None): Returns: (str): The formatted path - ''' + """ if order_id: return '/v1/order/{0}'.format(order_id) @@ -30,7 +30,7 @@ def _path(self, order_id=None): return '/v1/order' def get(self, order_id): - '''Get an order + """Get an order Args: order_id (str) : A Button order id ('btnorder-XXX') @@ -41,12 +41,12 @@ def get(self, order_id): Returns: (pybutton.Response) The API response - ''' + """ return self.api_get(self._path(order_id)) def create(self, order): - '''Create an order + """Create an order Args: order (dict): A dict representing the attributes of an order @@ -57,12 +57,12 @@ def create(self, order): Returns: (pybutton.Response) The API response - ''' + """ return self.api_post(self._path(), order) def update(self, order_id, order): - '''Update an order + """Update an order Args: order_id (str) : A Button order id ('btnorder-XXX') @@ -74,12 +74,12 @@ def update(self, order_id, order): Returns: (pybutton.Response) The API response - ''' + """ return self.api_post(self._path(order_id), order) def delete(self, order_id): - '''Delete an order + """Delete an order Args: order_id (str) : A Button order id ('btnorder-XXX') @@ -90,6 +90,6 @@ def delete(self, order_id): Returns: (pybutton.Response) The API response - ''' + """ return self.api_delete(self._path(order_id)) diff --git a/pybutton/resources/resource.py b/pybutton/resources/resource.py index b8acc28..68b8af7 100644 --- a/pybutton/resources/resource.py +++ b/pybutton/resources/resource.py @@ -18,7 +18,7 @@ class Resource(object): - '''Abstract Base Class for managing a remote resource in our API. + """Abstract Base Class for managing a remote resource in our API. Includes handy methods for making HTTP calls against our API and returning payloads in a standardized format (namely, pybutton.Response objects). @@ -40,14 +40,14 @@ class Resource(object): pybutton.ButtonClientError pybutton.HTTPResponseError - ''' + """ def __init__(self, api_key, config): self.api_key = api_key self.config = config def api_get(self, path, query=None): - '''Make an HTTP GET request + """Make an HTTP GET request Args: path (str): The path of the resource @@ -55,11 +55,11 @@ def api_get(self, path, query=None): Returns: (pybutton.Response): The API response - ''' + """ return self._api_request(path, 'GET', query=query) def api_post(self, path, data): - '''Make an HTTP POST request + """Make an HTTP POST request Args: path (str): The path of the resource @@ -68,11 +68,11 @@ def api_post(self, path, data): Returns: (pybutton.Response): The API response - ''' + """ return self._api_request(path, 'POST', data) def api_delete(self, path): - '''Make an HTTP DELETE request + """Make an HTTP DELETE request Args: path (str): The path of the resource @@ -80,12 +80,12 @@ def api_delete(self, path): Returns: (pybutton.Response): The API response - ''' + """ return self._api_request(path, 'DELETE') def _headers(self): - '''Generate the HTTP headers used for a request - ''' + """Generate the HTTP headers used for a request + """ api_key_bytes = '{0}:'.format(self.api_key).encode() authorization = b64encode(api_key_bytes).decode() @@ -101,7 +101,7 @@ def _headers(self): return headers def _api_request(self, path, method, data=None, query=None): - '''Make an HTTP request + """Make an HTTP request Any data provided will be JSON encoded an included as part of the request body. Additionally, an Authorization header will be set based @@ -116,7 +116,7 @@ def _api_request(self, path, method, data=None, query=None): Returns: (pybutton.Response): The API response - ''' + """ url = request_url( self.config['secure'], diff --git a/pybutton/response.py b/pybutton/response.py index a21c0b6..432de33 100644 --- a/pybutton/response.py +++ b/pybutton/response.py @@ -7,7 +7,7 @@ class Response(object): - '''The Response class wraps the returned values from an API call. + """The Response class wraps the returned values from an API call. It exposes the response data via the `data` method and cursors for pagination via the `next_cursor`/`prev_cursor` methods. @@ -16,7 +16,7 @@ class Response(object): meta (dict): The metadata from an API call response_data (dict or array): The response elements from an API call - ''' + """ classPrefix = 'class pybutton.Response' @@ -25,26 +25,26 @@ def __init__(self, meta, response_data): self.response_data = response_data def data(self): - ''' + """ Return the raw response element(s) received from the server. May be a single dict or an array of dicts. - ''' + """ return self.response_data def next_cursor(self): - ''' + """ For paginated responses, returns the url used to fetch the next elements. - ''' + """ return self._format_cursor(self.meta.get('next')) def prev_cursor(self): - ''' + """ For paginated responses, returns the url used to fetch the previous elements. - ''' + """ return self._format_cursor(self.meta.get('prev')) diff --git a/pybutton/test/request_test.py b/pybutton/test/request_test.py index f67fd4b..1b0357e 100644 --- a/pybutton/test/request_test.py +++ b/pybutton/test/request_test.py @@ -36,7 +36,7 @@ def test_get_request(self, MockRequest, mock_url_open): MockRequest.assert_called_with(url) self.assertEqual(instance.get_method(), method) instance.add_header.assert_called_with('b', 2) - self.assertEqual(response, {"a": 1}) + self.assertEqual(response, {'a': 1}) @patch('pybutton.request.urlopen') @patch('pybutton.request.Request') @@ -56,7 +56,7 @@ def test_post_request(self, MockRequest, mock_url_open): MockRequest.assert_called_with(url) self.assertEqual(instance.get_method(), method) - self.assertEqual(response, {"a": 1}) + self.assertEqual(response, {'a': 1}) @patch('pybutton.request.urlopen') @patch('pybutton.request.Request') @@ -85,7 +85,7 @@ def test_post_request_with_data(self, MockRequest, mock_url_open): 'application/json' ) - self.assertEqual(response, {"a": 1}) + self.assertEqual(response, {'a': 1}) @patch('pybutton.request.urlopen') @patch('pybutton.request.Request') @@ -129,7 +129,7 @@ def test_get_request(self, MockRequest, mock_url_open): MockRequest.assert_called_with(url, data=None, headers=headers) self.assertEqual(instance.get_method(), method) - self.assertEqual(response, {"a": 1}) + self.assertEqual(response, {'a': 1}) @patch('pybutton.request.urlopen') @patch('pybutton.request.Request') @@ -149,7 +149,7 @@ def test_post_request(self, MockRequest, mock_url_open): MockRequest.assert_called_with(url, data=None, headers=headers) self.assertEqual(instance.get_method(), method) - self.assertEqual(response, {"a": 1}) + self.assertEqual(response, {'a': 1}) @patch('pybutton.request.urlopen') @patch('pybutton.request.Request') @@ -181,7 +181,7 @@ def test_post_request_with_data(self, MockRequest, mock_url_open): 'application/json' ) - self.assertEqual(response, {"a": 1}) + self.assertEqual(response, {'a': 1}) @patch('pybutton.request.urlopen') @patch('pybutton.request.Request') diff --git a/pybutton/test/resources/resource_test.py b/pybutton/test/resources/resource_test.py index 82970e4..c18bef4 100644 --- a/pybutton/test/resources/resource_test.py +++ b/pybutton/test/resources/resource_test.py @@ -127,9 +127,9 @@ def test_api_request_with_byte_response(self, request): data = {'c': 3} fp = Mock() - fp.read.return_value = ''' + fp.read.return_value = """ { "error": { "message": "bloop failed" } } - '''.encode() + """.encode() def side_effect(*args): raise HTTPError('url', 404, 'bloop', {}, fp) diff --git a/pybutton/utils.py b/pybutton/utils.py index 77cf42f..ff5eaeb 100644 --- a/pybutton/utils.py +++ b/pybutton/utils.py @@ -9,7 +9,7 @@ def is_webhook_authentic(webhook_secret, request_body, sent_signature): - '''Used to verify that requests sent to a webhook endpoint are from Button + """Used to verify that requests sent to a webhook endpoint are from Button and that their payload can be trusted. Returns True if a webhook request body matches the sent signature and False otherwise. @@ -24,7 +24,7 @@ def is_webhook_authentic(webhook_secret, request_body, sent_signature): Returns: (bool) Whether or not the request is authentic - ''' + """ computed_signature = hmac.new( as_bytes(webhook_secret), @@ -42,7 +42,7 @@ def is_webhook_authentic(webhook_secret, request_body, sent_signature): def as_bytes(v, only_py_2=False): - '''Converts v to a UTF-8 byte string if unicode, else returns identity. + """Converts v to a UTF-8 byte string if unicode, else returns identity. Args: v (str|unicode): the string to convert @@ -52,7 +52,7 @@ def as_bytes(v, only_py_2=False): Returns: (byte string): A byte string copy, UTF-8 enccoded - ''' + """ python_version = sys.version_info[0] diff --git a/setup.py b/setup.py index 7662c89..3acc97e 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ include_package_data=False, license='MIT', test_suite='nose.collector', - tests_require=['nose', 'mock'], + tests_require=['nose', 'mock', "flake8-quotes==2.1.0"], zip_safe=True, classifiers=[ "Intended Audience :: Developers",