From 06cf0638dd6c04c04bc0f00b6b7d9265fe1d76de Mon Sep 17 00:00:00 2001 From: Chris Targett Date: Thu, 12 Dec 2013 16:09:32 +0000 Subject: [PATCH 1/3] Added the ability to pass in your own API object and ignore the global default. --- .gitignore | 2 ++ paypalrestsdk/api.py | 1 + paypalrestsdk/resource.py | 35 +++++++++++++--------- test/resource_test.py | 63 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index c144b75d..ba469326 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ build/ dist/ MANIFEST + +.*.sw* diff --git a/paypalrestsdk/api.py b/paypalrestsdk/api.py index 41f7d5d8..38fba638 100644 --- a/paypalrestsdk/api.py +++ b/paypalrestsdk/api.py @@ -205,3 +205,4 @@ def set_config(options={}, **config): return __api__ configure = set_config + diff --git a/paypalrestsdk/resource.py b/paypalrestsdk/resource.py index aecab79c..1c51614e 100644 --- a/paypalrestsdk/resource.py +++ b/paypalrestsdk/resource.py @@ -1,7 +1,7 @@ import uuid import paypalrestsdk.util as util -import paypalrestsdk.api as api +from paypalrestsdk.api import default as default_api # Base class for all REST service @@ -9,7 +9,9 @@ class Resource(object): convert_resources = {} - def __init__(self, attributes={}): + def __init__(self, attributes={}, api=None): + self.__dict__['api'] = api or default_api() + super(Resource, self).__setattr__('__data__', {}) super(Resource, self).__setattr__('error', None) super(Resource, self).__setattr__('headers', {}) @@ -53,14 +55,14 @@ def success(self): # Merge new attributes def merge(self, new_attributes): - for k in new_attributes: - self.__setattr__(k, new_attributes[k]) + for k,v in new_attributes.iteritems(): + setattr(self, k, v) # Convert the attribute values to configured class. def convert(self, name, value): if isinstance(value, dict): cls = self.convert_resources.get(name, Resource) - return cls(value) + return cls(value, api=self.api) elif isinstance(value, list): new_list = [] for obj in value: @@ -99,9 +101,11 @@ def parse_object(value): class Find(Resource): @classmethod - def find(cls, resource_id): + def find(cls, resource_id, api=None): + api = api or default_api() + url = util.join_url(cls.path, str(resource_id)) - return cls(api.default().get(url)) + return cls(api.get(url), api=api) # == Example @@ -110,12 +114,14 @@ class List(Resource): list_class = Resource @classmethod - def all(cls, params=None): + def all(cls, params=None, api=None): + api = api or default_api() + if params is None: url = cls.path else: url = util.join_url_params(cls.path, params) - return cls.list_class(api.default().get(url)) + return cls.list_class(api.get(url), api=api) # == Example @@ -124,7 +130,7 @@ def all(cls, params=None): class Create(Resource): def create(self): - new_attributes = api.default().post(self.path, self.to_dict(), self.http_headers()) + new_attributes = self.api.post(self.path, self.to_dict(), self.http_headers()) self.error = None self.merge(new_attributes) return self.success() @@ -136,7 +142,7 @@ class Delete(Resource): def delete(self): url = util.join_url(self.path, str(self['id'])) - new_attributes = api.default().delete(url) + new_attributes = self.api.delete(url) self.error = None self.merge(new_attributes) return self.success() @@ -150,11 +156,12 @@ class Post(Resource): def post(self, name, attributes={}, cls=Resource): url = util.join_url(self.path, str(self['id']), name) if not isinstance(attributes, Resource): - attributes = Resource(attributes) - new_attributes = api.default().post(url, attributes.to_dict(), attributes.http_headers()) + attributes = Resource(attributes, api=self.api) + new_attributes = self.api.post(url, attributes.to_dict(), attributes.http_headers()) if isinstance(cls, Resource): cls.error = None cls.merge(new_attributes) return self.success() else: - return cls(new_attributes) + return cls(new_attributes, api=self.api) + diff --git a/test/resource_test.py b/test/resource_test.py index 1da86a57..fa475bbe 100644 --- a/test/resource_test.py +++ b/test/resource_test.py @@ -1,5 +1,5 @@ from test_helper import unittest -from paypalrestsdk.resource import Resource +from paypalrestsdk.resource import Resource, Find, List, Post class TestResource(unittest.TestCase): def test_getter(self): @@ -70,12 +70,69 @@ def test_request_id(self): def test_http_headers(self): data = { - 'name': 'testing', - 'header': { 'My-Header': 'testing' } } + 'name': 'testing', + 'header': { 'My-Header': 'testing' } } resource = Resource(data) self.assertEqual(resource.header, {'My-Header': 'testing'}) self.assertEqual(resource.http_headers(), {'PayPal-Request-Id': resource.request_id, 'My-Header': 'testing'}) + def test_passing_api(self): + """ + Check that api objects are passed on to new resources when given + """ + class DummyAPI(object): + post = lambda s,*a,**k: {} + get = lambda s,*a,**k: {} + + api = DummyAPI() + + # Conversion + resource = Resource({ + 'name': 'testing', + }, api=api) + self.assertEqual(resource.api, api) + convert_ret = resource.convert('test', {}) + self.assertEqual(convert_ret.api, api) + + class TestResource(Find, List, Post): + path = '/' + + # Find + find = TestResource.find('resourceid', api=api) + self.assertEqual(find.api, api) + + # List + list_ = TestResource.all(api=api) + self.assertEqual(list_.api, api) + + # Post + post = TestResource({'id':'id'}, api=api) + post_ret = post.post('test') + self.assertEqual(post_ret.api, api) + + def test_default_resource(self): + from paypalrestsdk import api + original = api.__api__ + + class DummyAPI(object): + post = lambda s,*a,**k: {} + get = lambda s,*a,**k: {} + + # Make default api object a dummy api object + default = api.__api__ = DummyAPI() + + resource = Resource({}) + self.assertEqual(resource.api, default) + + class TestResource(Find, List, Post): + path = '/' + # Find + find = TestResource.find('resourceid') + self.assertEqual(find.api, default) + # List + list_ = TestResource.all() + self.assertEqual(list_.api, default) + api.__api__ = original # Restore original api object From bfc720435389b83d6440a527585db652c8b42944 Mon Sep 17 00:00:00 2001 From: Chris Targett Date: Thu, 12 Dec 2013 16:43:05 +0000 Subject: [PATCH 2/3] Added some docs --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index fff20aca..02ee1900 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,18 @@ export PAYPAL_CLIENT_ID=EBWKjlELKMYqRNQ6sYvFo64FtaRLRR5BdHEESmha49TM export PAYPAL_CLIENT_SECRET=EO422dn3gQLgDbuwqTjzrFgFtaRLRR5BdHEESmha49TM ``` +Configure through a non-global Api object +```python +import paypalrestsdk +my_api = paypalrestsdk.Api({ + 'mode': 'sandbox', + 'client_id': '...', + 'client_secret': '...'}) + +payment = paypalrestsdk.Payment({...}, api=my_api) + +``` + ### Create Payment ```python From 2e68ea7daa51ceec4d84370d00b326007f1ec4f7 Mon Sep 17 00:00:00 2001 From: Avi Das Date: Tue, 7 Jan 2014 13:01:27 -0600 Subject: [PATCH 3/3] Iteritems not supported in Python 3, replace with items --- paypalrestsdk/resource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paypalrestsdk/resource.py b/paypalrestsdk/resource.py index 3534b266..fe886f0d 100644 --- a/paypalrestsdk/resource.py +++ b/paypalrestsdk/resource.py @@ -56,7 +56,7 @@ def success(self): # Merge new attributes def merge(self, new_attributes): - for k,v in new_attributes.iteritems(): + for k,v in new_attributes.items(): setattr(self, k, v) # Convert the attribute values to configured class.