Skip to content
This repository has been archived by the owner on May 12, 2020. It is now read-only.

Commit

Permalink
Merge pull request #33 from avidas/docstring_comments
Browse files Browse the repository at this point in the history
Docstring comments
  • Loading branch information
avidas committed Feb 5, 2014
2 parents 95e6929 + d35d44c commit 76867c4
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 118 deletions.
89 changes: 56 additions & 33 deletions paypalrestsdk/api.py
Expand Up @@ -15,16 +15,18 @@

class Api:

# User-Agent for HTTP request
# User-Agent for HTTP request
library_details = "httplib2 %s; python %s" % (httplib2.__version__, platform.python_version())
user_agent = "PayPalSDK/rest-sdk-python %s (%s)" % (__version__, library_details)

# Create API object
# == Example
# import paypalrestsdk
# api = paypalrestsdk.Api( mode="sandbox",
# client_id='CLIENT_ID', client_secret='CLIENT_SECRET', ssl_options={} )

def __init__(self, options=None, **args):
"""Create API object
Usage::
>>> import paypalrestsdk
>>> api = paypalrestsdk.Api(mode="sandbox", client_id='CLIENT_ID', client_secret='CLIENT_SECRET', ssl_options={})
"""
args = util.merge_dict(options or {}, args)

self.mode = args.get("mode", "sandbox")
Expand All @@ -42,20 +44,22 @@ def __init__(self, options=None, **args):

self.options = args

# Default endpoint
def default_endpoint(self):
if self.mode == "live":
return "https://api.paypal.com"
else:
return "https://api.sandbox.paypal.com"

# Find basic auth
def basic_auth(self):
"""Find basic auth, and returns base64 encoded
"""
credentials = "%s:%s" % (self.client_id, self.client_secret)
return base64.b64encode(credentials.encode('utf-8')).decode('utf-8').replace("\n", "")

# Generate token_hash
def get_token_hash(self):
"""Generate new token by making a POST request with client credentials if
validate_token_hash finds token to be invalid
"""
self.validate_token_hash()
if self.token_hash is None:
self.token_request_at = datetime.datetime.now()
Expand All @@ -69,27 +73,33 @@ def get_token_hash(self):

return self.token_hash

# Validate expires_in
def validate_token_hash(self):
"""Checks if token duration has expired and if so resets token
"""
if self.token_request_at and self.token_hash and self.token_hash.get("expires_in") is not None:
delta = datetime.datetime.now() - self.token_request_at
duration = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6
if duration > self.token_hash.get("expires_in"):
self.token_hash = None

# Get access token
def get_token(self):
return self.get_token_hash()["access_token"]

# Get token type
# Get token
def get_token_type(self):
"""Get token type e.g. Bearer
"""
return self.get_token_hash()["token_type"]

# Make HTTP call and Format Response
# == Example
# api.request("https://api.sandbox.paypal.com/v1/payments/payment?count=10", "GET", {})
# api.request("https://api.sandbox.paypal.com/v1/payments/payment", "POST", "{}", {} )
def request(self, url, method, body=None, headers=None):
"""Make HTTP call, formats response and does error handling. Uses http_call method in API class.
Usage::
>>> api.request("https://api.sandbox.paypal.com/v1/payments/payment?count=10", "GET", {})
>>> api.request("https://api.sandbox.paypal.com/v1/payments/payment", "POST", "{}", {} )
"""
http_headers = util.merge_dict(self.headers(), headers or {})

if http_headers.get('PayPal-Request-Id'):
Expand All @@ -110,8 +120,10 @@ def request(self, url, method, body=None, headers=None):
else:
raise error

# Make http Call
def http_call(self, url, method, **args):
"""
Makes a http call. Logs response information.
"""
logging.info('Request[%s]: %s' % (method, url))
http = httplib2.Http(**self.ssl_options)
start_time = datetime.datetime.now()
Expand All @@ -120,8 +132,9 @@ def http_call(self, url, method, **args):
logging.info('Response[%d]: %s, Duration: %s.%ss' % (response.status, response.reason, duration.seconds, duration.microseconds))
return self.handle_response(response, content.decode('utf-8'))

# Validate HTTP response
def handle_response(self, response, content):
"""Validate HTTP response
"""
status = response.status
if status in (301, 302, 303, 307):
raise Redirection(response, content)
Expand Down Expand Up @@ -150,38 +163,48 @@ def handle_response(self, response, content):
else:
raise ConnectionError(response, content, "Unknown response code: #{response.code}")

# Default HTTP headers
def headers(self):
"""Default HTTP headers
"""
return {
"Authorization": ("%s %s" % (self.get_token_type(), self.get_token())),
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": self.user_agent
}

# Make GET request
# == Example
# api.get("v1/payments/payment?count=1")
# api.get("v1/payments/payment/PAY-1234")
def get(self, action, headers=None):
"""Make GET request
Usage::
>>> api.get("v1/payments/payment?count=1")
>>> api.get("v1/payments/payment/PAY-1234")
"""
return self.request(util.join_url(self.endpoint, action), 'GET', headers=headers or {})

# Make POST request
# == Example
# api.post("v1/payments/payment", { 'indent': 'sale' })
# api.post("v1/payments/payment/PAY-1234/execute", { 'payer_id': '1234' })
def post(self, action, params=None, headers=None):
"""Make POST request
Usage::
>>> api.post("v1/payments/payment", { 'indent': 'sale' })
>>> api.post("v1/payments/payment/PAY-1234/execute", { 'payer_id': '1234' })
"""
return self.request(util.join_url(self.endpoint, action), 'POST', body=json.dumps(params or {}), headers=headers or {})

# Make DELETE request
def delete(self, action, headers=None):
"""Make DELETE request
"""
return self.request(util.join_url(self.endpoint, action), 'DELETE', headers=headers or {})


__api__ = None

# Get default api
def default():
"""Returns default api object and if not present creates a new one
By default points to developer sandbox
"""
global __api__
if __api__ is None:
try:
Expand All @@ -194,11 +217,11 @@ def default():
return __api__


# Create new default api object with given configuration
def set_config(options=None, **config):
"""Create new default api object with given configuration
"""
global __api__
__api__ = Api(options or {}, **config)
return __api__

configure = set_config

56 changes: 29 additions & 27 deletions paypalrestsdk/exceptions.py
@@ -1,5 +1,4 @@


class ConnectionError(Exception):
def __init__(self, response, content=None, message=None):
self.response = response
Expand All @@ -15,86 +14,89 @@ def __str__(self):
return message


# Raised when a Timeout::Error occurs.
class TimeoutError(ConnectionError):
"""Raised when a Timeout::Error occurs.
"""
def __init__(self, message):
self.message = message

def __str__(self):
return self.message


# Raised when a OpenSSL::SSL::SSLError occurs.
class SSLError(ConnectionError):
"""Raised when a OpenSSL::SSL::SSLError occurs
"""
def __init__(self, message):
self.message = message

def __str__(self):
return self.message


# 3xx Redirection
class Redirection(ConnectionError):
"""3xx Redirection
"""
def __str__(self):
message = super(Redirection, self).__str__()
if self.response.get('Location'):
message = "%s => %s" % (message, self.response.get('Location'))
return message


class MissingParam(TypeError):
pass


class MissingConfig(Exception):
pass


# 4xx Client Error
class ClientError(ConnectionError):
"""4xx Client Error
"""
pass


# 400 Bad Request
class BadRequest(ClientError):
"""400 Bad Request
"""
pass


# 401 Unauthorized

class UnauthorizedAccess(ClientError):
"""401 Unauthorized
"""
pass


# 403 Forbidden
class ForbiddenAccess(ClientError):
"""403 Forbidden
"""
pass


# 404 Not Found
class ResourceNotFound(ClientError):
"""404 Not Found
"""
pass


# 409 Conflict

class ResourceConflict(ClientError):
"""409 Conflict
"""
pass


# 410 Gone
class ResourceGone(ClientError):
"""410 Gone
"""
pass

#422 Invalid
class ResourceInvalid(ClientError):
"""422 Invalid
"""
pass

# 5xx Server Error
class ServerError(ConnectionError):
"""5xx Server Error
"""
pass


# 405 Method Not Allowed

class MethodNotAllowed(ClientError):
"""405 Method Not Allowed
"""

def allowed_methods(self):
return self.response['Allow']

0 comments on commit 76867c4

Please sign in to comment.