Skip to content

Commit

Permalink
add support for cursor based pagination (#84)
Browse files Browse the repository at this point in the history
* add support for cursor based pagination
* lint project with black to match pep8

---------

Signed-off-by: Bruno Vieira <bruno@chartmogul.com>
  • Loading branch information
Bruno Vieira authored Oct 4, 2023
1 parent 8514ba4 commit d50d33a
Show file tree
Hide file tree
Showing 53 changed files with 1,727 additions and 1,424 deletions.
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[flake8]
ignore = E501,W503
exclude = __init__.py
max-line-length = 100
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog],
and this project adheres to [Semantic Versioning].

[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
[Semantic Versioning]: https://semver.org/spec/v2.0.0.html

## [3.1.3] - 2023-09-27

### Added
- Support for cursor based pagination to `.all()` endpoints.
- Changelog.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ chartmogul.DataSource.destroy(config, uuid='ds_5915ee5a-babd-406b-b8ce-d207133fb

```python
chartmogul.Customer.create(config, data={})
chartmogul.Customer.all(config, page=2, per_page=20)
chartmogul.Customer.all(config, cursor='cursor==', per_page=20)
chartmogul.Customer.retrieve(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb')
chartmogul.Customer.search(config, email='email@email.com')
chartmogul.Customer.merge(config, data={
Expand Down Expand Up @@ -217,7 +217,7 @@ chartmogul.Plan.retrieve(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb'
chartmogul.Plan.modify(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={
'name': 'new name'
})
chartmogul.Plan.all(config, page=2, external_id='')
chartmogul.Plan.all(config, cursor='cursor==', external_id='')
chartmogul.Plan.destroy(config, uuid='')
```

Expand All @@ -227,7 +227,7 @@ chartmogul.Plan.destroy(config, uuid='')
chartmogul.PlanGroup.create(config, data={})
chartmogul.PlanGroup.retrieve(config, uuid='plg_5915ee5a-babd-406b-b8ce-d207133fb4cb')
chartmogul.PlanGroup.modify(config, uuid='plg_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={})
chartmogul.PlanGroup.all(config, page=2)
chartmogul.PlanGroup.all(config, cursor='cursor==')
chartmogul.PlanGroup.all(config, uuid='plg_5915ee5a-babd-406b-b8ce-d207133fb4cb')
chartmogul.PlanGroup.destroy(config, uuid='')
```
Expand All @@ -238,7 +238,7 @@ chartmogul.PlanGroup.destroy(config, uuid='')
import chartmogul

chartmogul.Invoice.create(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', data={})
chartmogul.Invoice.all(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', page=2, per_page=10)
chartmogul.Invoice.all(config, uuid='cus_5915ee5a-babd-406b-b8ce-d207133fb4cb', cursor='cursor==', per_page=10)
chartmogul.Invoice.all(config, customer_uuid='cus_f466e33d-ff2b-4a11-8f85-417eb02157a7', external_id='INV0001')
chartmogul.Invoice.retrieve(config, uuid='inv_22910fc6-c931-48e7-ac12-90d2cb5f0059')
```
Expand Down
8 changes: 4 additions & 4 deletions chartmogul/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
:license: MIT, see LICENSE for more details.
"""

__title__ = 'chartmogul'
__title__ = "chartmogul"
__build__ = 0x000000
__author__ = 'ChartMogul Ltd'
__license__ = 'MIT'
__copyright__ = 'Copyright 2023 ChartMogul Ltd'
__author__ = "ChartMogul Ltd"
__license__ = "MIT"
__copyright__ = "Copyright 2023 ChartMogul Ltd"
1 change: 0 additions & 1 deletion chartmogul/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@

# api module is imported directly into chartmogul namespace for users' convenience.
1 change: 1 addition & 0 deletions chartmogul/api/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Account(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#account
"""

_path = "/account"

class _Schema(Schema):
Expand Down
16 changes: 9 additions & 7 deletions chartmogul/api/activities_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@


class ExportParams(DataObject):

class _Schema(Schema):
kind = fields.String()
params = fields.Dict(allow_none=True)
Expand All @@ -19,8 +18,9 @@ class ActivitiesExport(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#
"""

_path = "/activities_export"
_many = namedtuple('ActivitiesExport', ["id", "status", "file_url", "expires_at", "created_at"])
_many = namedtuple("ActivitiesExport", ["id", "status", "file_url", "expires_at", "created_at"])

class _Schema(Schema):
# Create
Expand All @@ -45,11 +45,13 @@ def make(self, data, **kwargs):
@classmethod
def _validate_arguments(cls, method, kwargs):
# This enforces user to pass correct argument
if method in ['retrieve'] and 'id' not in kwargs:
raise ArgumentMissingError("Please pass 'id' parameter to retrieve your export request status")
if method in ['create'] and 'data' not in kwargs:
if method in ["retrieve"] and "id" not in kwargs:
raise ArgumentMissingError(
"Please pass 'id' parameter to retrieve your export request status"
)
if method in ["create"] and "data" not in kwargs:
raise ArgumentMissingError("Please pass 'data' parameter")


ActivitiesExport.create = ActivitiesExport._method('create', 'post', '/activities_export')
ActivitiesExport.retrieve = ActivitiesExport._method('retrieve', 'get', '/activities_export/{id}')
ActivitiesExport.create = ActivitiesExport._method("create", "post", "/activities_export")
ActivitiesExport.retrieve = ActivitiesExport._method("retrieve", "get", "/activities_export/{id}")
29 changes: 16 additions & 13 deletions chartmogul/api/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,30 @@

class Activity(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#list-customer-subscriptions
https://dev.chartmogul.com/reference/list-activities
"""

_path = "/activities"
_root_key = 'entries'
_many = namedtuple('Activities', [_root_key, "has_more", "per_page"])
_root_key = "entries"
_many = namedtuple(
"Activities", [_root_key, "has_more", "per_page", "cursor"], defaults=[None, None, None]
)

class _Schema(Schema):
activity_arr = fields.Number(data_key='activity-arr')
activity_mrr = fields.Number(data_key='activity-mrr')
activity_mrr_movement = fields.Number(data_key='activity-mrr-movement')
activity_arr = fields.Number(data_key="activity-arr")
activity_mrr = fields.Number(data_key="activity-mrr")
activity_mrr_movement = fields.Number(data_key="activity-mrr-movement")
currency = fields.String()
date = fields.DateTime()
description = fields.String()
type = fields.String()
subscription_external_id = fields.String(data_key='subscription-external-id')
plan_external_id = fields.String(data_key='plan-external-id')
customer_name = fields.String(data_key='customer-name')
customer_uuid = fields.String(data_key='customer-uuid')
customer_external_id = fields.String(data_key='customer-external-id')
billing_connector_uuid = fields.String(data_key='billing-connector-uuid')
uuid = fields.String(data_key='uuid')
subscription_external_id = fields.String(data_key="subscription-external-id")
plan_external_id = fields.String(data_key="plan-external-id")
customer_name = fields.String(data_key="customer-name")
customer_uuid = fields.String(data_key="customer-uuid")
customer_external_id = fields.String(data_key="customer-external-id")
billing_connector_uuid = fields.String(data_key="billing-connector-uuid")
uuid = fields.String(data_key="uuid")

@post_load
def make(self, data, **kwargs):
Expand Down
1 change: 1 addition & 0 deletions chartmogul/api/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Attributes(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#customer-attributes
"""

_path = "/customers{/uuid}/attributes"

class _Schema(Schema):
Expand Down
2 changes: 1 addition & 1 deletion chartmogul/api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Config:
uri = API_BASE + "/" + VERSION

def __init__(self, api_key, request_timeout=None, max_retries=20, backoff_factor=2):
self.auth = (api_key, '')
self.auth = (api_key, "")
self.request_timeout = request_timeout
self.max_retries = max_retries
self.backoff_factor = backoff_factor
4 changes: 2 additions & 2 deletions chartmogul/api/contact.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ class Contact(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#contacts
"""

_path = "/contacts{/uuid}"
_root_key = "entries"
_many = namedtuple("Contacts",
[_root_key, "has_more", "cursor"])
_many = namedtuple("Contacts", [_root_key, "has_more", "cursor"])

class _Schema(Schema):
uuid = fields.String()
Expand Down
7 changes: 4 additions & 3 deletions chartmogul/api/custom_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class CustomAttributes(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#custom-attributes
"""

_path = "/customers{/uuid}/attributes/custom"

class _Schema(Schema):
Expand All @@ -17,7 +18,7 @@ class _Schema(Schema):
def make(self, data, **kwargs):
return CustomAttributes(**data)

_customers = namedtuple('Customers', ['entries'])
_customers = namedtuple("Customers", ["entries"])
_schema = _Schema(unknown=EXCLUDE)

@classmethod
Expand All @@ -30,8 +31,8 @@ def _load(cls, response):
if response.status_code == 204:
return None
jsonObj = response.json()
if 'entries' in jsonObj:
customers = Customer._schema.load(jsonObj['entries'], many=True)
if "entries" in jsonObj:
customers = Customer._schema.load(jsonObj["entries"], many=True)
return cls._customers(customers)
else:
return cls._schema.load(jsonObj)
25 changes: 16 additions & 9 deletions chartmogul/api/customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@


class Address(DataObject):

class _Schema(Schema):
address_zip = fields.String(allow_none=True)
city = fields.String(allow_none=True)
Expand All @@ -29,10 +28,14 @@ class Customer(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#customers
"""

_path = "/customers{/uuid}"
_root_key = 'entries'
_many = namedtuple('Customers',
[_root_key, "has_more", "per_page", "page", "current_page", "total_pages"])
_root_key = "entries"
_many = namedtuple(
"Customers",
[_root_key, "has_more", "per_page", "page", "current_page", "total_pages", "cursor"],
defaults=[None, None, None, None, None, None],
)

class _Schema(Schema):
# All operations
Expand Down Expand Up @@ -74,8 +77,12 @@ def make(self, data, **kwargs):
_schema = _Schema(unknown=EXCLUDE)


Customer.search = Customer._method('all', 'get', '/customers/search')
Customer.merge = Customer._method('merge', 'post', '/customers/merges')
Customer.connectSubscriptions = Customer._method('create', 'post', '/customers/{uuid}/connect_subscriptions')
Customer.contacts = Contact._method('all', 'get', '/customers/{uuid}/contacts', useCallerClass=True)
Customer.createContact = Contact._method('create', 'post', '/customers/{uuid}/contacts', useCallerClass=True)
Customer.search = Customer._method("all", "get", "/customers/search")
Customer.merge = Customer._method("merge", "post", "/customers/merges")
Customer.connectSubscriptions = Customer._method(
"create", "post", "/customers/{uuid}/connect_subscriptions"
)
Customer.contacts = Contact._method("all", "get", "/customers/{uuid}/contacts", useCallerClass=True)
Customer.createContact = Contact._method(
"create", "post", "/customers/{uuid}/contacts", useCallerClass=True
)
2 changes: 1 addition & 1 deletion chartmogul/api/customers/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# Allow users to access the submodules of customers
# Allow users to access the submodules of customers
19 changes: 12 additions & 7 deletions chartmogul/api/customers/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,26 @@ class CustomerActivity(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#list-customer-subscriptions
"""

_path = "/customers{/uuid}/activities"
_root_key = 'entries'
_many = namedtuple('Activities', [_root_key, "has_more", "per_page", "page"])
_root_key = "entries"
_many = namedtuple(
"Activities",
[_root_key, "has_more", "per_page", "page", "cursor"],
defaults=[None, None, None, None],
)

class _Schema(Schema):
id = fields.Int()
activity_arr = fields.Number(data_key='activity-arr')
activity_mrr = fields.Number(data_key='activity-mrr')
activity_mrr_movement = fields.Number(data_key='activity-mrr-movement')
activity_arr = fields.Number(data_key="activity-arr")
activity_mrr = fields.Number(data_key="activity-mrr")
activity_mrr_movement = fields.Number(data_key="activity-mrr-movement")
currency = fields.String()
currency_sign = fields.String(data_key='currency-sign')
currency_sign = fields.String(data_key="currency-sign")
date = fields.DateTime()
description = fields.String()
type = fields.String()
subscription_external_id = fields.String(data_key='subscription-external-id')
subscription_external_id = fields.String(data_key="subscription-external-id")

@post_load
def make(self, data, **kwargs):
Expand Down
55 changes: 40 additions & 15 deletions chartmogul/api/customers/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ class CustomerSubscription(Resource):
https://dev.chartmogul.com/v1.0/reference#list-customer-subscriptions
https://dev.chartmogul.com/v1.0/reference#list-a-customers-subscriptions
"""

_path = "/customers{/uuid}/subscriptions"
_root_key = 'entries'
_many = namedtuple('Subscriptions', [_root_key, "has_more", "per_page", "page"])
_root_key = "entries"
_many = namedtuple(
"Subscriptions",
[_root_key, "has_more", "per_page", "page", "cursor"],
defaults=[None, None, None, None],
)

class _Schema(Schema):
id = fields.Int(allow_none=True)
Expand All @@ -19,12 +24,12 @@ class _Schema(Schema):
mrr = fields.Number(allow_none=True)
arr = fields.Number(allow_none=True)
status = fields.String(allow_none=True)
billing_cycle = fields.String(data_key='billing-cycle', allow_none=True)
billing_cycle_count = fields.Number(data_key='billing-cycle-count', allow_none=True)
start_date = fields.DateTime(data_key='start-date', allow_none=True)
end_date = fields.DateTime(data_key='end-date', allow_none=True)
billing_cycle = fields.String(data_key="billing-cycle", allow_none=True)
billing_cycle_count = fields.Number(data_key="billing-cycle-count", allow_none=True)
start_date = fields.DateTime(data_key="start-date", allow_none=True)
end_date = fields.DateTime(data_key="end-date", allow_none=True)
currency = fields.String(allow_none=True)
currency_sign = fields.String(data_key='currency-sign', allow_none=True)
currency_sign = fields.String(data_key="currency-sign", allow_none=True)

# /import namespace
uuid = fields.String(allow_none=True)
Expand All @@ -45,16 +50,36 @@ def make(self, data, **kwargs):
@classmethod
def _loadJSON(cls, jsonObj):
if "subscriptions" in jsonObj:
_many = namedtuple('Subscriptions', ["subscriptions", "current_page", "total_pages", "customer_uuid"])
return _many(cls._schema.load(jsonObj["subscriptions"], many=True),
jsonObj["current_page"],
jsonObj["total_pages"],
jsonObj["customer_uuid"])
_many = namedtuple(
"Subscriptions",
[
"subscriptions",
"current_page",
"total_pages",
"customer_uuid",
"has_more",
"cursor",
],
)
return _many(
cls._schema.load(jsonObj["subscriptions"], many=True),
current_page=jsonObj.get("current_page", None),
total_pages=jsonObj.get("total_pages", None),
customer_uuid=jsonObj.get("customer_uuid", None),
has_more=jsonObj.get("has_more", None),
cursor=jsonObj.get("cursor", None),
)
else:
return super(CustomerSubscription, cls)._loadJSON(jsonObj)


# /import namespace
CustomerSubscription.list_imported = CustomerSubscription._method('list_imported', 'get', "/import/customers{/uuid}/subscriptions")
CustomerSubscription.cancel = CustomerSubscription._method('cancel', 'patch', "/import/subscriptions{/uuid}")
CustomerSubscription.modify = CustomerSubscription._method('modify', 'patch', "/import/subscriptions{/uuid}")
CustomerSubscription.list_imported = CustomerSubscription._method(
"list_imported", "get", "/import/customers{/uuid}/subscriptions"
)
CustomerSubscription.cancel = CustomerSubscription._method(
"cancel", "patch", "/import/subscriptions{/uuid}"
)
CustomerSubscription.modify = CustomerSubscription._method(
"modify", "patch", "/import/subscriptions{/uuid}"
)
7 changes: 4 additions & 3 deletions chartmogul/api/data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ class DataSource(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#data-sources
"""
_path = '/data_sources{/uuid}'
_root_key = 'data_sources'
_many = namedtuple('DataSources', [_root_key])

_path = "/data_sources{/uuid}"
_root_key = "data_sources"
_many = namedtuple("DataSources", [_root_key])

class _Schema(Schema):
uuid = fields.String()
Expand Down
Loading

0 comments on commit d50d33a

Please sign in to comment.