Skip to content

Commit

Permalink
Cleanup and PyPi packaging. Here's a full list:
Browse files Browse the repository at this point in the history
* Converted README.md to ReST, since that's what PyPi uses for their
  detail pages.
* Created a top-level wepay module, containing api and exceptions.
  This is to facilitate the packaging process.
* ReSTified all docstrings so Sphinx docs can be generated.
* Added a setup.py file.
* Added a VERSION const to wepay.__init__.py. PyPi wants this.
  Feel free to change the value.
* Moved WePayError into its own module.
* Eliminated a few unsafe default kwarg values in WePay class.
  Dicts can be accidentally manipulated if left as default.
  • Loading branch information
Greg Taylor committed Nov 7, 2011
1 parent be71f4e commit b631097
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 117 deletions.
8 changes: 8 additions & 0 deletions .gitignore
@@ -0,0 +1,8 @@
*.pyc
*.swp
*.tmp
*~
build
dist
MANIFEST
.idea
2 changes: 2 additions & 0 deletions MANIFEST.in
@@ -0,0 +1,2 @@
include README.md
include wepay-example.py
54 changes: 0 additions & 54 deletions README.md

This file was deleted.

97 changes: 97 additions & 0 deletions README.rst
@@ -0,0 +1,97 @@
WePay Python SDK
================

WePay's API allows you to easily add payments into your application.

For full documentation, see `WePay's developer documentation`_

.. _WePay's developer documentation: https://www.wepay.com/developer

Usage
-----
These examples use the simple web.py application framework.

Setup
^^^^^

Import the module::

from wepay import WePay

Instantiate
^^^^^^^^^^^

Create a new ``WePay`` instance. With no arguments, it will use the production
version of WePay (www.wepay.com). If called with ``production=False`` then
it will use the staging version (stage.wepay.com) for testing.::

wepay = WePay()

If your user has already authorized your application and you still have the
access token, you can instantiate the SDK with the optional ``access_token``
parameter. Afterwards, ``wepay.call()`` will use the given token for the
authorization header.::

wepay = WePay(access_token=USERS_ACCESS_TOKEN)

Get authorized
^^^^^^^^^^^^^^

Create an authorization url and redirect the user to it. The first parameter
is where the user will be redirected back to after they finish authorization.
The second is your ``CLIENT_ID`` which is provided by WePay.::

auth_url = wepay.get_authorization_url(web.ctx.homedomain + '/callback', CLIENT_ID)
web.redirect(auth_url)

Handle the callback
^^^^^^^^^^^^^^^^^^^

In your method for handling the redirect back to your site (in this case,
``/callback``), you will need to load the GET param ``code`` and then call
``get_token`` with it. ``CLIENT_SECRET`` is provided by WePay. The first
parameter of ``get_token`` should be the exact same string that was used
in ``get_authorization_url``.::

code = web.input(code='')['code']
# make sure the first arg is exactly the same as the first arg
# of get_authorization_url
wepay.get_token(web.ctx.homedomain + '/callback', CLIENT_ID, CLIENT_SECRET, code)

The ``get_token`` method will automatically load the access token into the
``WePay`` instance so that all future API calls will use that token for
authorization. It also returns the entire response from the
``/v2/oauth2/token`` call if you need any additional data like the WePay ID.

Make some calls
^^^^^^^^^^^^^^^

You are now ready to do anything on behalf of your user. Let's start by making
a new account.::

create_response = wepay.call('/account/create', {
'name': 'kitty expenses fund',
'description': 'all the money for my kitty'
})

Now let's set a picture!::

wepay.call('/account/modify', {
'account_id': create_response['account_id'],
'image_uri': 'http://www.placekitten.com/500/500'
})

Redirect them to their account page to see it.::

web.redirect(create_response['account_uri'])

Try it!
^^^^^^^

These examples are put together into a working web app in
``wepay-example.py``. If you already have web.py installed, you can run it
by simply doing ``python wepay-example.py``. If you open the app in your
browser you should be redirected to WePay to authorize the app. After you
authorize, you should get redirected around a bit and end up on your new
account page with a kitty picture.
31 changes: 31 additions & 0 deletions setup.py
@@ -0,0 +1,31 @@
from distutils.core import setup
import wepay

long_description = open('README.rst').read()

version_str = '%s.%s.%s' % (
wepay.VERSION[0],
wepay.VERSION[1],
wepay.VERSION[2]
)

setup(
name='wepay',
version=version_str,
packages=['wepay'],
description='A Python SDK for our WePay API.',
long_description=long_description,
author='Bryce Culhane',
author_email='bryce.culhane@gmail.com',
license='BSD License',
url='https://github.com/wepay/Python-SDK',
platforms=["any"],
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
],
)
63 changes: 0 additions & 63 deletions wepay.py

This file was deleted.

4 changes: 4 additions & 0 deletions wepay/__init__.py
@@ -0,0 +1,4 @@
from api import WePay

# Major, minor, revision
VERSION = (0, 1, 1)
100 changes: 100 additions & 0 deletions wepay/api.py
@@ -0,0 +1,100 @@
import urllib,urllib2,json
from wepay.exceptions import WePayError

class WePay(object):
"""
A client for the WePay API.
"""

def __init__(self, production=True, access_token=None):
"""
:param bool production: When ``False``, the ``stage.wepay.com`` API
server will be used instead of the default production.
:param str access_token: The access token associated with your
application.
"""
self.access_token = access_token
if production:
self.wepay_url = "https://www.wepay.com/v2"
else:
self.wepay_url = "https://stage.wepay.com/v2"

def call(self, uri, params=None, token=None):
"""
Calls wepay.com/v2/``uri`` with ``params`` and returns the JSON
response as a python dict. The optional token parameter will override
the instance's access_token if it is set.
:param str uri: The URI on the API endpoint to call.
:param dict params: The parameters to pass to the URI.
:param str token: Optional override for this ``WePay`` object's access
token.
"""
if not params:
params = {}

headers = {'Content-Type' : 'application/json'}
url = self.wepay_url + uri

if self.access_token or token:
headers['Authorization'] = 'Bearer ' + (token if token else self.access_token)

params = json.dumps(params)

request = urllib2.Request(url, params, headers)
try:
response = urllib2.urlopen(request).read()
return json.loads(response)
except urllib2.HTTPError as e:
response = json.loads(e.read())
raise WePayError(response['error'], response['error_description'])

def get_authorization_url(self, redirect_uri, client_id, options=None,
scope=None):
"""
Returns a URL to send the user to in order to get authorization.
After getting authorization the user will return to redirect_uri.
Optionally, scope can be set to limit permissions, and the options
dict can be loaded with any combination of state, user_name
or user_email.
:param str redirect_uri: The URI to redirect to after a authorization.
:param str client_id: The client ID issued by WePay to your app.
:keyword dict options: Allows for passing additional values to the
authorize call, aside from scope, redirect_uri, and etc.
:keyword str scope: A comma-separated string of permissions.
"""
if not options:
options = {}
if not scope:
scope = "manage_accounts,collect_payments,view_balance,view_user,refund_payments"

options['scope'] = scope
options['redirect_uri'] = redirect_uri
options['client_id'] = client_id

return self.wepay_url + '/oauth2/authorize?' + urllib.urlencode(options)

def get_token(self, redirect_uri, client_id, client_secret, code):
"""
Calls wepay.com/v2/oauth2/token to get an access token. Sets the
access_token for the WePay instance and returns the entire response
as a dict. Should only be called after the user returns from being
sent to get_authorization_url.
:param str redirect_uri: The same URI specified in the
:py:meth:`get_authorization_url` call that preceeded this.
:param str client_id: The client ID issued by WePay to your app.
:param str client_secret: The client secret issued by WePay
to your app.
:param str code: The code returned by :py:meth:`get_authorization_url`.
"""
params = {
'redirect_uri': redirect_uri,
'client_id': client_id,
'client_secret': client_secret,
'code': code,
}
response = self.call('/oauth2/token', params)
self.access_token = response['access_token']
return response
7 changes: 7 additions & 0 deletions wepay/exceptions.py
@@ -0,0 +1,7 @@
class WePayError(Exception):
"""
Raised when an error comes back in the API response from WePay.
"""
def __init__(self, error_type, message):
Exception.__init__(self, message)
self.type = error_type

0 comments on commit b631097

Please sign in to comment.