-
Notifications
You must be signed in to change notification settings - Fork 1
Add Accounts resource #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
aa8e608
d43dedf
d2fda7a
7f0052f
1a98942
794015e
4da26be
0b3a183
6c3cbe5
daec3a4
0ef6f39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -91,7 +91,7 @@ The supported options are as follows: | |
| Resources | ||
| --------- | ||
|
|
||
| We currently expose only one resource to manage, ``Orders``. | ||
| We currently expose two resources to manage, ``Orders`` and ``Accounts``. | ||
|
|
||
| Orders | ||
| ~~~~~~ | ||
|
|
@@ -163,6 +163,121 @@ Delete | |
| print(response) | ||
| # <class pybutton.Response > | ||
|
|
||
| Accounts | ||
| ~~~~~~~~ | ||
|
|
||
| All | ||
| ''' | ||
|
|
||
| .. code:: python | ||
|
|
||
| from pybutton import Client | ||
|
|
||
| client = Client('sk-XXX') | ||
|
|
||
| response = client.accounts.all() | ||
|
|
||
| print(response) | ||
| # <class pybutton.Response [2 elements]> | ||
|
|
||
| Transactions | ||
| '''''''''''' | ||
|
|
||
| Along with the required account ID, you may also | ||
| pass the following optional arguments: | ||
|
|
||
| * ``cursor`` (string): An API cursor to fetch a specific set of results. | ||
| * ``start`` (ISO-8601 datetime string): Fetch transactions after this time. | ||
| * ``end`` (ISO-8601 datetime string): Fetch transactions before this time. | ||
|
|
||
| .. code:: python | ||
|
|
||
| from pybutton import Client | ||
|
|
||
| client = Client('sk-XXX') | ||
|
|
||
| response = client.accounts.transactions( | ||
| 'acc-123', | ||
| start='2016-07-15T00:00:00.000Z', | ||
| end='2016-09-30T00:00:00.000Z' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: trailing commas |
||
| ) | ||
|
|
||
| print(response) | ||
| # <class pybutton.Response [100 elements]> | ||
|
|
||
| Response | ||
| -------- | ||
|
|
||
| Methods | ||
| ~~~~~~~ | ||
|
|
||
| data | ||
| '''' | ||
|
|
||
| .. code:: python | ||
|
|
||
| from pybutton import Client | ||
|
|
||
| client = Client('sk-XXX') | ||
|
|
||
| response = client.orders.get('btnorder-XXX') | ||
|
|
||
| print(response.data()) | ||
| # {'total': 50, 'currency': 'USD', 'status': 'open' ... } | ||
|
|
||
| response = client.accounts.all() | ||
|
|
||
| print(response.data()) | ||
| # [{'id': 'acc-123', ... }, {'id': 'acc-234', ... }] | ||
|
|
||
| next_cursor | ||
| '''''''''' | ||
|
|
||
| For any paged resource, ``next_cursor()`` will return a cursor to | ||
| supply for the next page of results. If ``next_cursor()`` returns ``None``, | ||
| there are no more results. | ||
|
|
||
| .. code:: python | ||
|
|
||
| from pybutton import Client | ||
|
|
||
| client = Client('sk-XXX') | ||
|
|
||
| response = client.accounts.transactions('acc-123') | ||
| cursor = response.next_cursor() | ||
|
|
||
| # loop through and print all transactions | ||
| while cursor: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a cool method we can add later to the |
||
| response = client.accounts.transactions('acc-123', cursor=cursor) | ||
| print(response.data()) | ||
| cursor = response.next_cursor() | ||
|
|
||
| prev_cursor | ||
| '''''''''' | ||
|
|
||
| For any paged resource, ``prev_cursor()`` will return a cursor to | ||
| supply for the next page of results. If ``prev_cursor()`` returns | ||
| ``None``, there are no more previous results. | ||
|
|
||
| .. code:: python | ||
|
|
||
| from pybutton import Client | ||
|
|
||
| client = Client('sk-XXX') | ||
|
|
||
| response = client.accounts.transactions('acc-123', cursor='xyz') | ||
|
|
||
| print(response) | ||
| # <class pybutton.Response [25 elements]> | ||
|
|
||
| cursor = response.prev_cursor() | ||
|
|
||
| response = client.accounts.transactions('acc-123', cursor=cursor) | ||
|
|
||
| print(response) | ||
| # <class pybutton.Response [100 elements]> | ||
|
|
||
|
|
||
| Contributing | ||
| ------------ | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,10 @@ | |
| from urllib.request import Request | ||
| from urllib.request import urlopen | ||
| from urllib.error import HTTPError | ||
| from urllib.parse import urlencode | ||
| from urllib.parse import urlunsplit | ||
| from urllib.parse import urlparse | ||
| from urllib.parse import parse_qs | ||
|
|
||
| def request(url, method, headers, data=None, timeout=None): | ||
| ''' Make an HTTP request in Python 3.x | ||
|
|
@@ -62,7 +65,10 @@ def request(url, method, headers, data=None, timeout=None): | |
| from urllib2 import Request | ||
| from urllib2 import urlopen | ||
| from urllib2 import HTTPError | ||
| from urllib import urlencode | ||
| from urlparse import urlunsplit | ||
| from urlparse import urlparse | ||
| from urlparse import parse_qs | ||
|
|
||
| def request(url, method, headers, data=None, timeout=None): | ||
| ''' Make an HTTP request in Python 2.x | ||
|
|
@@ -104,7 +110,7 @@ def request(url, method, headers, data=None, timeout=None): | |
| raise ButtonClientError('Invalid response: {0}'.format(response)) | ||
|
|
||
|
|
||
| def request_url(secure, hostname, port, path): | ||
| def request_url(secure, hostname, port, path, query=None): | ||
| ''' | ||
| Combines url components into a url passable into the request function. | ||
|
|
||
|
|
@@ -113,13 +119,44 @@ def request_url(secure, hostname, port, path): | |
| hostname (str): The host name for the url. | ||
| port (int): The port number, as an integer. | ||
| path (str): The hierarchical path. | ||
| query (dict): A dict of query parameters. | ||
|
|
||
| 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) | ||
|
|
||
| return urlunsplit((scheme, netloc, path, '', '')) | ||
| return urlunsplit((scheme, netloc, path, encoded_query, '')) | ||
|
|
||
| __all__ = [Request, urlopen, HTTPError, request, request_url] | ||
|
|
||
| def query_dict(url): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: docstring
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: docstring |
||
| ''' | ||
| Given a url, returns a dictionary of its query parameters. | ||
|
|
||
| Args: | ||
| url (string): The url to extract query parameters from. | ||
|
|
||
| Returns: | ||
| (dict) A dictionary of query parameters, formatted as follows: | ||
| { | ||
| query_name: [ list of values ], | ||
| ... | ||
| } | ||
|
|
||
| ''' | ||
| url_components = urlparse(url) | ||
|
|
||
| if (url_components): | ||
| query_string = url_components.query | ||
| return parse_qs(query_string) | ||
|
|
||
| __all__ = [ | ||
| Request, | ||
| urlopen, | ||
| HTTPError, | ||
| request, | ||
| request_url, | ||
| query_dict, | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| from __future__ import absolute_import | ||
| from __future__ import division | ||
| from __future__ import print_function | ||
| from __future__ import unicode_literals | ||
|
|
||
| from .resource import Resource | ||
|
|
||
|
|
||
| class Accounts(Resource): | ||
| '''Manages interacting with Button Accounts with the Button API | ||
|
|
||
| Args: | ||
| api_key (string): Your organization's API key. Do find yours at | ||
| https://app.usebutton.com/settings/organization. | ||
| config (dict): Configurati 9E71 on options for the client. Options include: | ||
| hostname: Defaults to api.usebutton.com. | ||
| port: Defaults to 443 if config.secure, else defaults to 80. | ||
| secure: Whether or not to use HTTPS. Defaults to True. | ||
| timeout: The time in seconds for network requests to abort. | ||
| Defaults to None. | ||
| (N.B: Button's API is only exposed through HTTPS. This option is | ||
| provided purely as a convenience for testing and development.) | ||
|
|
||
| Raises: | ||
| pybutton.ButtonClientError | ||
|
|
||
| ''' | ||
|
|
||
| def all(self): | ||
| '''Get a list of available accounts | ||
|
|
||
| Raises: | ||
| pybutton.ButtonClientError | ||
|
|
||
| Returns: | ||
| (pybutton.Response) The API response | ||
|
|
||
| ''' | ||
|
|
||
| return self.api_get('/v1/affiliation/accounts') | ||
|
|
||
| def transactions(self, account_id, cursor=None, start=None, end=None): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May be worth spelling out in the docs what arguments are required and what are optional. |
||
| '''Get a list of transactions. | ||
| To paginate transactions, pass the result of response.next_cursor() as | ||
| the cursor argument. | ||
|
|
||
|
|
||
| Args: | ||
| account_id (str) optional: A Button account id ('acc-XXX') | ||
| cursor (str) optional: An opaque string that lets you view a | ||
| consistent list of transactions. | ||
| start (ISO-8601 datetime str) optional: Filter out transactions | ||
| created at or after this time. | ||
| end (ISO-8601 datetime str) optional: Filter out transactions | ||
| created before this time. | ||
|
|
||
| Raises: | ||
| pybutton.ButtonClientError | ||
|
|
||
| Returns: | ||
| (pybutton.Response) The API response | ||
|
|
||
| ''' | ||
|
|
||
| query = {} | ||
|
|
||
| if cursor: | ||
| query['cursor'] = cursor | ||
| if start: | ||
| query['start'] = start | ||
| if end: | ||
| query['end'] = end | ||
|
|
||
| path = '/v1/affiliation/accounts/{0}/transactions'.format( | ||
| account_id | ||
| ) | ||
|
|
||
| return self.api_get(path, query=query) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A section in the readme talking about the nature of our
pybutton.Responseclass is worthwhile at this point, I think!