Skip to content

Commit

Permalink
linting pep8, tested & fixed invoices
Browse files Browse the repository at this point in the history
  • Loading branch information
pkopac committed Feb 7, 2017
1 parent b7b9cd1 commit 6cb9d45
Show file tree
Hide file tree
Showing 26 changed files with 616 additions and 256 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ To work on the library:

For a testing project we recommend setting up a [virtualenv](http://docs.python-guide.org/en/latest/dev/virtualenvs/)
with [development mode](https://packaging.python.org/installing/#installing-from-a-local-src-tree) installation
and [Jupyter](http://jupyter.org/).
and [Jupyter](http://jupyter.org/). [virtualenvwrapper](http://chrisstrelioff.ws/sandbox/2014/09/04/virtualenv_and_virtualenvwrapper_on_ubuntu_14_04.html) is another handy tool.

Built using [Requests](https://github.com/kennethreitz/requests).

Expand Down
2 changes: 1 addition & 1 deletion chartmogul/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"""

__title__ = 'chartmogul'
__version__ = '0.0.1'
__version__ = '1.0.0'
__build__ = 0x000000
__author__ = 'ChartMogul Ltd'
__license__ = 'MIT'
Expand Down
1 change: 1 addition & 0 deletions chartmogul/api/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ..resource import Resource
from collections import namedtuple


class Activity(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#list-customer-subscriptions
Expand Down
8 changes: 7 additions & 1 deletion chartmogul/api/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class _Schema(Schema):
def make(self, data):
return Stripe(**data)


class Name(DataObject):
class _Schema(Schema):
fullName = fields.String()
Expand All @@ -19,6 +20,7 @@ class _Schema(Schema):
def make(self, data):
return Name(**data)


class Employment(DataObject):
class _Schema(Schema):
name = fields.String()
Expand All @@ -27,6 +29,7 @@ class _Schema(Schema):
def make(self, data):
return Employment(**data)


class Person(DataObject):
class _Schema(Schema):
name = fields.Nested(Name._Schema)
Expand All @@ -36,6 +39,7 @@ class _Schema(Schema):
def make(self, data):
return Person(**data)


class Company(DataObject):
class _Schema(Schema):
name = fields.String()
Expand All @@ -49,15 +53,17 @@ class _Schema(Schema):
def make(self, data):
return Company(**data)


class Clearbit(DataObject):
class _Schema(Schema):
company= fields.Nested(Company._Schema)
company = fields.Nested(Company._Schema)
person = fields.Nested(Person._Schema)

@post_load
def make(self, data):
return Clearbit(**data)


class Attributes(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#customer-attributes
Expand Down
1 change: 1 addition & 0 deletions chartmogul/api/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
VERSION = "v1"
API_BASE = "https://api.chartmogul.com"


class Config:
uri = API_BASE + "/" + VERSION

Expand Down
24 changes: 11 additions & 13 deletions chartmogul/api/customer.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
from marshmallow import Schema, fields, post_load
from ..resource import Resource, DataObject, _add_method
from collections import namedtuple
from .attributes import Stripe, Name, Employment, Person, Company, Clearbit, Attributes

"""
Beside the Customer class this module uses also subdocument classes.
These are used only on deserializing the server response, so the client has
proper types (eg. parsed dates instead of strings). Creating customer only
requires Customer class and simple dict/array data.
Validation is done on server.
"""
from marshmallow import Schema, fields, post_load
from ..resource import Resource, DataObject, _add_method
from collections import namedtuple
from .attributes import Stripe, Name, Employment, Person, Company, Clearbit, Attributes


class Address(DataObject):

class _Schema(Schema):
address_zip = fields.String()
city = fields.String()
Expand All @@ -22,13 +23,15 @@ class _Schema(Schema):
def make(self, data):
return Address(**data)


class Customer(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#plans
"""
_path = "/customers{/uuid}"
_root_key = 'entries'
_many = namedtuple('Customers', [_root_key, "has_more", "per_page", "page", "current_page", "total_pages"])
_many = namedtuple('Customers',
[_root_key, "has_more", "per_page", "page", "current_page", "total_pages"])

class _Schema(Schema):
# All operations
Expand Down Expand Up @@ -69,11 +72,6 @@ def make(self, data):

_schema = _Schema(strict=True)

@classmethod
def search(cls, config, email=None):
return super(Customer, cls)._request(config, 'all', 'get', '/customers/search', email=email)


@classmethod
def merge(cls, config, data=None):
return super(Customer, cls)._request(config, 'merge', 'post', '/customers/merge', data=data)
Customer.search = Customer._method('all', 'get', '/customers/search')
Customer.merge = Customer._method('merge', 'post', '/customers/merges')
1 change: 1 addition & 0 deletions chartmogul/api/data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ..resource import Resource
from collections import namedtuple


class DataSource(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#data-sources
Expand Down
2 changes: 2 additions & 0 deletions chartmogul/api/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ..resource import Resource, DataObject, _add_method
from collections import namedtuple


class Summary(DataObject):
"""
Optional information about a series of metrics.
Expand All @@ -17,6 +18,7 @@ def make(self, data):

_schema = _Schema(strict=True)


class Metrics(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#introduction-metrics-api
Expand Down
2 changes: 2 additions & 0 deletions chartmogul/api/ping.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ..resource import Resource, _add_method
from collections import namedtuple


class Ping(Resource):
"""
https://dev.chartmogul.com/docs/authentication
Expand All @@ -17,4 +18,5 @@ def make(self, data):

_schema = _Schema(strict=True)


_add_method(Ping, "ping", "get")
1 change: 1 addition & 0 deletions chartmogul/api/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ..resource import Resource
from collections import namedtuple


class Plan(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#plans
Expand Down
1 change: 1 addition & 0 deletions chartmogul/api/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ..resource import Resource
from collections import namedtuple


class Subscription(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#list-customer-subscriptions
Expand Down
12 changes: 8 additions & 4 deletions chartmogul/imp/invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
from .transaction import Transaction
from collections import namedtuple


class LineItem(DataObject):

class _Schema(Schema):
uuid = fields.String()
external_id = fields.String()
external_id = fields.String(allow_none=True)
type = fields.String()
subscription_uuid = fields.String()
plan_uuid = fields.String()
Expand All @@ -15,26 +17,28 @@ class _Schema(Schema):
service_period_end = fields.DateTime()
amount_in_cents = fields.Int()
quantity = fields.Int()
discount_code = fields.String()
discount_code = fields.String(allow_none=True)
discount_amount_in_cents = fields.Int()
tax_amount_in_cents = fields.Int()
account_code = fields.String()
account_code = fields.String(allow_none=True)

@post_load
def make(self, data):
return LineItem(**data)


class Invoice(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#invoices
"""
_path = "/import/customers{/uuid}/invoices"
_root_key = 'invoices'
_many = namedtuple('Invoices', [_root_key, "current_page", "total_pages"])
_many.__new__.__defaults__ = (None,) * len(_many._fields)

class _Schema(Schema):
uuid = fields.String()
external_id = fields.String()
external_id = fields.String(allow_none=True)
date = fields.DateTime()
due_date = fields.DateTime()
currency = fields.String()
Expand Down
2 changes: 1 addition & 1 deletion chartmogul/imp/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class Subscription(Resource):
_root_key = 'subscriptions'
_many = namedtuple('Subscriptions', [_root_key, "current_page", "total_pages", "customer_uuid"])


class _Schema(Schema):
uuid = fields.String()
external_id = fields.String()
Expand All @@ -26,5 +25,6 @@ def make(self, data):

_schema = _Schema(strict=True)


Subscription.cancel = Subscription._method('cancel', 'patch', "/import/subscriptions{/uuid}")
Subscription.modify = Subscription._method('modify', 'patch', "/import/subscriptions{/uuid}")
3 changes: 2 additions & 1 deletion chartmogul/imp/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ..resource import Resource
from collections import namedtuple


class Transaction(Resource):
"""
https://dev.chartmogul.com/v1.0/reference#transactions
Expand All @@ -10,7 +11,7 @@ class Transaction(Resource):

class _Schema(Schema):
uuid = fields.String()
external_id = fields.String()
external_id = fields.String(allow_none=True)
type = fields.String()
date = fields.DateTime()
result = fields.String()
Expand Down
46 changes: 27 additions & 19 deletions chartmogul/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
'update': 'put'
}

PAGING = ['current_page', 'total_pages', 'has_more', 'per_page', 'page', 'summary']
PAGING = ['current_page', 'total_pages',
'has_more', 'per_page', 'page', 'summary']
ESCAPED_QUERY_KEYS = {
'start_date': 'start-date',
'end_date': 'end-date'
}


class DataObject:

def __init__(self, **kwargs):
"""
Any arguments are translated into class attributes.
Expand All @@ -47,13 +50,15 @@ def _set_attrs(self, **kwargs):

def __repr__(self):
"""
Pretty-prints any object as <ClassName{property='string',number=4,date=datetime.datetime(2003, 8, 4, 21, 41, 43)}>
Pretty-prints any object as
<ClassName{property='string',number=4,date=datetime.datetime(2003, 8, 4, 21, 41, 43)}>
"""
return "<" + self.__class__.__name__ + "{" + \
", ".join([attr + "=" + repr(getattr(self, attr)) for attr in sorted(dir(self))
if not attr.startswith('_') and not callable(getattr(self, attr))]) + \
", ".join([attr + "=" + repr(getattr(self, attr)) for attr in sorted(dir(self))
if not attr.startswith('_') and not callable(getattr(self, attr))]) + \
"}>"


def json_serial(obj):
"""
JSON serializer for objects not serializable by default json code
Expand Down Expand Up @@ -81,7 +86,7 @@ def _load(cls, response):
return None
try:
jsonObj = response.json()
except ValueError: # Couldn't parse JSON, probably just text message.
except ValueError: # Couldn't parse JSON, probably just text message.
return response.content

try:
Expand All @@ -91,7 +96,8 @@ def _load(cls, response):
**{key: jsonObj[key] for key in PAGING if key in jsonObj})
else:
return cls._schema.load(jsonObj).data
except ValueError: # Model parsing/validation failed, return the json at least.
# Model parsing/validation failed, return the json at least.
except ValueError:
return jsonObj

@classmethod
Expand All @@ -110,16 +116,14 @@ def _request(cls, config, method, http_verb, path, data=None, **kwargs):
else:
params = None
if data is not None:
data=dumps(data, default=json_serial)
data = dumps(data, default=json_serial)

return Promise(lambda resolve, _:
resolve(getattr(requests, http_verb)(config.uri + path,
data=data,
params=params,
auth=config.auth)
)
).then(cls._load
).catch(annotateHTTPError)
resolve(getattr(requests, http_verb)(config.uri + path,
data=data,
params=params,
auth=config.auth)
)).then(cls._load).catch(annotateHTTPError)

@classmethod
def _expandPath(cls, path, kwargs):
Expand All @@ -131,16 +135,18 @@ def _method(cls, method, http_verb, path=None):
@classmethod
def fc(cls, config, **kwargs):
if config is None or not isinstance(config, Config):
raise ConfigurationError("First argument should be instance of chartmogul.Config class!")
raise ConfigurationError("First argument should be"
" instance of chartmogul.Config class!")

pathTemp = path # due to Python closure
pathTemp = path # due to Python closure
if pathTemp is None:
pathTemp = cls._path

# This enforces user to pass argument, otherwise we could call wrong URL.
if method in ['destroy','cancel', 'retrieve', 'update'] and 'uuid' not in kwargs:
# This enforces user to pass argument, otherwise we could call
# wrong URL.
if method in ['destroy', 'cancel', 'retrieve', 'update'] and 'uuid' not in kwargs:
raise ArgumentMissingError("Please pass 'uuid' parameter")
if method in ['create','modify'] and 'data' not in kwargs:
if method in ['create', 'modify'] and 'data' not in kwargs:
raise ArgumentMissingError("Please pass 'data' parameter")

pathTemp = Resource._expandPath(pathTemp, kwargs)
Expand All @@ -151,11 +157,13 @@ def fc(cls, config, **kwargs):
return cls._request(config, method, http_verb, pathTemp, **kwargs)
return fc


def _add_method(cls, method, http_verb, path=None):
"""
Dynamically define all possible actions.
"""
fc = Resource._method(method, http_verb, path)
# Not supported by 2.7, but probably not needed.
# fc.__doc__ = "Sends %s request to ChartMogul." % http_verb
# fc.__name__ = method
setattr(cls, method, fc)
Expand Down
Loading

0 comments on commit 6cb9d45

Please sign in to comment.