Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

pyeviscape for gae

  • Loading branch information...
commit 5028c8476cc04c3988296d051a47d7f905545e33 0 parents
@iapain authored
13 README
@@ -0,0 +1,13 @@
+pyeviscape - Python Wrapper to Eviscape API
+pyeviscape-gae enables it to run on Google App Engine (gae)
+
+Examples:
+from pyeviscape.eviscape import Members, Nodes, Evis
+
+for member in Members.search('deepak'):
+ print member
+
+print Nodes(id=17).get()
+
+for evis in Evis.latest()[:5]:
+ print evis
1  pyeviscape/__init__.py
@@ -0,0 +1 @@
+__VERSION__ = (0,1,1)
4 pyeviscape/config.py
@@ -0,0 +1,4 @@
+#Get it from http://www.eviscape.com/apps/new
+API_KEY = ''
+API_SECRET = ''
+FORMATTER = 'json'
804 pyeviscape/eviscape.py
@@ -0,0 +1,804 @@
+"""
+Eviscape API wrapper
+Author: Deepak Thukral<deepak@musicpictures.com>
+PyEviscape provides functions for interacting with the Eviscape API.
+
+The MIT License
+
+Copyright (c) 2009 MMIX Musicpictures Ltd, Berlin
+"""
+
+#Preferably requires python2.5+ if you are using older python make sure you've
+#hashlib packages
+
+import hashlib
+import pickle
+import random
+import StringIO
+import time
+import urllib
+from utils import request_get, request_protected_get, request_protected_post, SERVER, smart_str, parseDateTime
+from config import FORMATTER
+
+
+class Files(object):
+ """ Represents files on Eviscape """
+ def __init__(self, id, fle_title=None, fle_permalink=None):
+ self.id = id
+ self.fle_title = fle_title
+ self.fle_permalink = fle_permalink
+
+ def __str__(self):
+ return smart_str("File Object: %s (%s)" % (self.id, self.fle_permalink))
+
+
+class Comments(object):
+ """ Represent comments on Eviscape """
+ def __init__(self, id, node=None, ecm_comment=None, mem_pen_name=None, ecm_insert_date=None):
+ self.id = id
+ self.node = node
+ self.ecm_comment = ecm_comment
+ self.mem_pen_name = mem_pen_name
+ self.ecm_insert_date = ecm_insert_date
+
+ @classmethod
+ def get(self, node, evis, access_token=None, per_page=10, page=1):
+ """
+ Gets comments for an evis (optionally required access_token)
+ Usage: Comments.get(Nodes(id=17), Evis(id=6259, Nodes(id=17))
+ Returns: List of Comments object
+ Eviscape API Method: comments.get
+ """
+ method = "comments.get"
+ if access_token is None:
+ data = request_get(method, nod_id=node.id, evi_id=evis.id,\
+ per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, nod_id=node.id,\
+ evi_id=evis.id, per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_comment_json(data)
+ else:
+ return _handle_comment_xml(data)
+
+ @classmethod
+ def post(self, node, member, evis, comment_body, access_token, per_page=10, page=1):
+ """
+ Posts a comments for an evis (optionally required access_token)
+ Usage: Comments.post(Nodes(id=17), Members(id=13), Evis(id=6259, Nodes(id=17), "Hello World")
+ Returns: Comments object
+ Eviscape API Method: comment.post
+ """
+ method="comment.post"
+ data = request_protected_post(method, access_token, nod_id=node.id,\
+ evi_id=evis.id, mem_id=member.id, comment=comment_body,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_comment_json(data)[0]
+ else:
+ return _handle_comment_xml(data)[0]
+
+ def __str__(self):
+ return smart_str("Comment Object: %s" % self.id)
+
+class Members(object):
+ """ Represent User/Member on Eviscape """
+ def __init__(self, id, mem_name=None, mem_full_name=None,\
+ mem_pen_name=None, primary_node=None):
+ self.id = id
+ self.mem_name = mem_name
+ self.mem_full_name = mem_full_name
+ self.mem_pen_name = mem_pen_name
+ self.primary_node = primary_node
+
+ @classmethod
+ def get_by_token(self, access_token, per_page=10, page=1):
+ """
+ Get member via access_token
+ Usage: Member.get_by_token(access_token)
+ Returns: Member Object
+ Eviscape API Method: member.token
+ """
+ method = "member.token"
+ data = request_protected_get(method, access_token, per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_member_json(data)[0]
+ else:
+ return _handle_member_xml(data)[0]
+
+
+ @classmethod
+ def search(self, q, per_page=10, page=1):
+ """
+ Search members on eviscape
+ Usage: Members.search("deepak")
+ Returns: List of Members object
+ Eviscape API Method: members.search
+ """
+ method = "members.search"
+ data = request_get(method, q=q, per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_member_json(data)
+ else:
+ return _handle_member_xml(data)
+
+
+ def __str__(self):
+ return smart_str("Member Object: %s (%s)" % (self.id, str(self.mem_name)))
+
+class Nodes(object):
+ """ Represent Node/Profile/Evisite on Eviscape """
+ def __init__(self, id, nod_name=None, member=None, nod_permalink=None, nod_strict=None,\
+ nod_logo_image=None, nod_desc=None, nod_listener_count=None):
+ self.id = id
+ self.member = member
+ self.nod_name = nod_name
+ self.nod_desc = nod_desc
+ self.nod_listener_count = nod_listener_count
+ if nod_permalink is not None and not nod_permalink.startswith('http'):
+ if nod_permalink == '':
+ self.nod_permalink = None
+ else:
+ self.nod_permalink = "http://"+ SERVER + nod_permalink
+ else:
+ self.nod_permalink = nod_permalink
+ if nod_logo_image is not None and not nod_logo_image == "":
+ self.nod_logo_image = "http://%s/static/%s" % (SERVER, nod_logo_image)
+ else:
+ self.nod_logo_image = None
+ self.nod_strict = nod_strict
+
+ def get(self, access_token=None, per_page=10, page=1):
+ """
+ Get details of a Node/Profile/Evisite
+ Usage: Nodes(id=17).get()
+ Returns: Nodes object
+ Eviscape API Method: node.get
+ """
+ method="node.get"
+ if access_token is None:
+ data = request_get(method, nod_id=self.id, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, nod_id=self.id,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_node_json(data)[0]
+ else:
+ return _handle_node_xml(data)[0]
+
+
+ def listeners(self, access_token=None, per_page=10, page=1):
+ """
+ Get Listeners/Followers of a Node/Profile/Evisite
+ Usage: Nodes(id=17).listeners()
+ Returns: List of Nodes object
+ Eviscape API Method: nodes.listeners
+ """
+ method = "nodes.listeners"
+ if access_token is None:
+ data = request_get(method, nod_id=self.id, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, nod_id=self.id,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_node_json(data)
+ else:
+ return _handle_node_xml(data)
+
+
+ def speakers(self, access_token=None, per_page=10, page=1):
+ """
+ Get Nodes/Profile/Evisite which base node is Followering
+ Usage: Nodes(id=17).speakers()
+ Returns: List of Nodes object
+ Eviscape API Method: nodes.speakers
+ """
+ method = "nodes.speakers"
+ if access_token is None:
+ data = request_get(method, nod_id=self.id, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, nod_id=self.id,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_node_json(data)
+ else:
+ return _handle_node_xml(data)
+
+ @classmethod
+ def get_for_member(self, member_name, perms='write', access_token=None, per_page=10, page=1):
+ """
+ Get Node/Profile/Evisite of a User/Member
+ Usage: Nodes.get_for_memnber("iapain")
+ Returns: List of Nodes object
+ Eviscape API Method: nodes.get
+ """
+ method = "nodes.member"
+ if access_token is None:
+ data = request_get(method, mem_name=member_name, perms=perms, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, mem_name=member_name,\
+ perms=perms, per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_node_json(data)
+ else:
+ return _handle_node_xml(data)
+
+ @classmethod
+ def created_by_member(self, member_name, access_token=None, per_page=10, page=1):
+ """
+ Get Node/Profile/Evisite which was created by User/Member
+ Usage: Nodes.created_by_member("iapain")
+ Returns: List of Nodes object
+ Eviscape API Method: nodes.get
+ """
+ method = "nodes.get"
+ if access_token is None:
+ data = request_get(method, mem_name=member_name, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, mem_name=member_name,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_node_json(data)
+ else:
+ return _handle_node_xml(data)
+
+ @classmethod
+ def search(self, q, per_page=10, page=1):
+ """
+ Searches Nodes/Evisite/Profile on eviscape (public only)
+ Usage: Nodes.search('iapain')
+ Returns: List of Nodes object
+ Eviscape API Method: nodes.search
+ """
+ method = "nodes.search"
+ data = request_get(method, q=q, per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_node_json(data)
+ else:
+ return _handle_node_xml(data)
+
+ def __str__(self):
+ return smart_str("Node Object: %s (%s)" % (self.id, self.nod_name))
+
+class Evis(object):
+ """ Represents Evis on Eviscape """
+ def __init__(self, id, node, member=None, evi_subject=None, evi_body=None,\
+ evi_type=None, evi_comment_count=None, evi_insert_date=None,\
+ evi_permalink=None, files=[], reverse_type_id=True):
+ self.id = id
+ self.node = node
+ self.member = member
+ self.evi_subject = evi_subject
+ self.evi_body = evi_body
+ self.evi_insert_date = evi_insert_date
+ self.evi_type = evi_type
+ self.evi_permalink = evi_permalink
+ self.evi_comment_count = evi_comment_count
+ self.files = files
+
+
+ def get(self, access_token=None, per_page=10, page=1):
+ """
+ Get an Evis/Post/Article
+ Usage: Evis(id=6369).get()
+ Returns: An Evis Object
+ Eviscape API Method: evis.get
+ """
+ method = "evis.get"
+ if access_token is None:
+ data = request_get(method, evi_id=self.id, nod_id=self.node.id,\
+ per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, evi_id=self.id,\
+ nod_id=self.node.id, per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_evis_json(data)[0]
+ else:
+ return _handle_evis_xml(data)[0]
+
+ def get_files(self, access_token=None, per_page=10, page=1):
+ """
+ Get Files belongs to an Evis/Post/Article
+ Usage: Evis(id=6369).get_files()
+ Returns: A list of Files Object
+ Eviscape API Method: evis.get_files
+ """
+ method = "evis.get_files"
+ if access_token is None:
+ data = request_get(method, evi_id=self.id, nod_id=self.node.id,\
+ per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, evi_id=self.id,\
+ nod_id=self.node.id, per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ self.files = _handle_file_json(data)
+ else:
+ self.files = _handle_file_xml(data)
+ return self.files
+
+
+ @classmethod
+ def post(self, evi_subject, evi_body, evi_type, member, node, evis_tags,\
+ access_token, evis_is_draft=False, per_page=10, page=1):
+ """
+ Posts an Evis/Post/Article
+ Usage: Evis.post('Cool', 'I am feeling cool', 'text', Members(id=13), Nodes(id=17), 'cool test')
+ Returns: An Evis Object
+ Eviscape API Method: evis.post
+ """
+ method = "evis.post"
+ data = request_protected_post(method, access_token, evi_subject=evi_subject,\
+ evi_body=evi_body, evi_type=evi_type,\
+ mem_id=member.id, nod_id=node.id,\
+ evi_tags=evis_tags, evis_is_draft=evis_is_draft,\
+ per_page=per_page, page=page)
+
+ if FORMATTER == 'json':
+ return _handle_evis_json(data)[0]
+ else:
+ return _handle_evis_xml(data)[0]
+
+ @classmethod
+ def timeline(self, member, node, access_token, per_page=10, page=1):
+ """
+ Get timeline for a member
+ Usage: Evis.timeline(memberobj, nodeobj, 'token')
+ Returns: List of evis
+ Eviscape API method: evis.timeline
+ """
+ method = "evis.timeline"
+ data = request_protected_get(method, access_token, mem_id=member.id,\
+ nod_id=node.id, per_page=per_page, page=page)
+
+ if FORMATTER == 'json':
+ return _handle_evis_json(data)
+ else:
+ return _handle_evis_xml(data)
+
+
+ @classmethod
+ def xsearch(self, query, access_token=None, per_page=10, page=1):
+ """
+ Search an Evis/Post/Article
+ Usage: Evis.search('bon jovi OR metallica')
+ Returns: generator object containing evis
+ Eviscape API Method: evis.search
+ """
+ method = "evis.search"
+ if access_token is None:
+ data = request_get(method, q=query, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, q=query,\
+ per_page=per_page, page=page)
+
+ if FORMATTER == 'json':
+ if isinstance(data.get('objects', None), list):
+ for evi in data['objects']:
+ yield _parse_compact_evis(evi)
+ else:
+ if data.rsp.objects.__dict__.has_key('evis'):
+ if isinstance(data.rsp.objects.evis, list):
+ for evi in data.rsp.objects.evis:
+ yield _parse_compact_evis(evi)
+ else:
+ yield _parse_compact_evis(data.rsp.objects.evis)
+
+ @classmethod
+ def xsent(self, node, access_token=None, per_page=10, page=1):
+ """
+ Get all posted Evis/Post/Article of a Node/Profile/Evisite
+ Usage: Evis.xsent(Nodes(id=17))
+ Returns: A Generator with Evis Object
+ Eviscape API Method: evis.sent
+ """
+ method = "evis.sent"
+ if access_token is None:
+ data = request_get(method, nod_id=node.id, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, nod_id=node.id,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ if isinstance(data.get('objects', None), list):
+ for evi in data['objects']:
+ yield _parse_evis(evi)
+ else:
+ if data.rsp.objects.__dict__.has_key('evis'):
+ if isinstance(data.rsp.objects.evis, list):
+ for evi in data.rsp.objects.evis:
+ yield _parse_evis(evi)
+ else:
+ yield _parse_evis(data.rsp.objects.evis)
+
+ @classmethod
+ def xreceived(self, member, node, access_token=None, per_page=10, page=1):
+ """
+ Get all received Evis/Post/Article of a Node/Profile/Evisite
+ Usage: Evis.xreceived(Member(id=13), Nodes(id=17))
+ Returns: A Generator with Evis Object
+ Eviscape API Method: evis.received
+ """
+ method = "evis.received"
+ if access_token is None:
+ data = request_get(method, mem_id=member.id, nod_id=node.id, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, mem_id=member.id, nod_id=node.id,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ if isinstance(data.get('objects', None), list):
+ for evi in data['objects']:
+ yield _parse_compact_evis(evi)
+ else:
+ if data.rsp.objects.__dict__.has_key('evis'):
+ if isinstance(data.rsp.objects.evis, list):
+ for evi in data.rsp.objects.evis:
+ yield _parse_compact_evis(evi)
+ else:
+ yield _parse_compact_evis(data.rsp.objects.evis)
+
+ @classmethod
+ def xlatest(self, access_token=None, per_page=10, page=1):
+ """
+ Get all latest evis
+ Usage: Evis.xlatest()
+ Returns: A Generator with Evis Object
+ Eviscape API Method: evis.latest
+ """
+ method = "evis.latest"
+ if access_token is None:
+ data = request_get(method, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ if isinstance(data.get('objects', None), list):
+ for evi in data['objects']:
+ yield _parse_compact_evis(evi)
+ else:
+ if data.rsp.objects.__dict__.has_key('evis'):
+ if isinstance(data.rsp.objects.evis, list):
+ for evi in data.rsp.objects.evis:
+ yield _parse_compact_evis(evi)
+ else:
+ yield _parse_compact_evis(data.rsp.objects.evis)
+
+ @classmethod
+ def search(self, query, access_token=None, per_page=10, page=1):
+ """
+ Search an Evis/Post/Article
+ Usage: Evis.search('bon jovi OR metallica')
+ Returns: List of evis
+ Eviscape API Method: evis.search
+ """
+ method = "evis.search"
+ if access_token is None:
+ data = request_get(method, q=query, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, q=query,\
+ per_page=per_page, page=page)
+
+ if FORMATTER == 'json':
+ return _handle_evis_json(data, compact=True)
+ else:
+ return _handle_evis_xml(data, compact=True)
+
+ @classmethod
+ def sent(self, node, access_token=None, per_page=100, page=1):
+ """
+ Get all posted Evis/Post/Article of a Node/Profile/Evisite
+ Usage: Evis.sent(Nodes(id=17))
+ Returns: A list of Evis Object
+ Eviscape API Method: evis.sent
+ """
+ method = "evis.sent"
+ if access_token is None:
+ data = request_get(method, nod_id=node.id, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, nod_id=node.id,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_evis_json(data)
+ else:
+ return _handle_evis_xml(data)
+
+ @classmethod
+ def received(self, member, node, access_token=None, per_page=10, page=1):
+ """
+ Get all received Evis/Post/Article of a Node/Profile/Evisite
+ Usage: Evis.received(Member(id=13), Nodes(id=17))
+ Returns: A list with Evis Object
+ Eviscape API Method: evis.received
+ """
+ method = "evis.received"
+ if access_token is None:
+ data = request_get(method, mem_id=member.id, nod_id=node.id, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token, mem_id=member.id, nod_id=node.id,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_evis_json(data, compact=True)
+ else:
+ return _handle_evis_xml(data, compact=True)
+
+ @classmethod
+ def latest(self, access_token=None, per_page=10, page=1):
+ """
+ Get all latest Evis/Post/Article
+ Usage: Evis.latest()
+ Returns: A list with Evis Object
+ Eviscape API Method: evis.latest
+ """
+ method = "evis.latest"
+ if access_token is None:
+ data = request_get(method, per_page=per_page, page=page)
+ else:
+ data = request_protected_get(method, access_token,\
+ per_page=per_page, page=page)
+ if FORMATTER == 'json':
+ return _handle_evis_json(data, compact=True)
+ else:
+ return _handle_evis_xml(data, compact=True)
+
+ def __str__(self):
+ return smart_str("Evis Object: %s (%s)" % (self.id, self.evi_permalink))
+
+
+def _handle_member_xml(data):
+ "Handles xml data object for member"
+ members = []
+ if data.rsp.objects.__dict__.has_key('members'):
+ if isinstance(data.rsp.objects.members, list):
+ for m in data.rsp.objects.members:
+ members.append(_parse_member(m))
+ else:
+ members = [_parse_member(data.rsp.objects.members)]
+ return members
+
+def _handle_node_xml(data):
+ "Handles xml data for nodes"
+ nodes = []
+ if data.rsp.objects.__dict__.has_key('node'):
+ if isinstance(data.rsp.objects.node, list):
+ for n in data.rsp.objects.node:
+ nodes.append(_parse_node(n))
+ else:
+ nodes = [_parse_node(data.rsp.objects.node)]
+ return nodes
+
+def _handle_evis_xml(data, compact=False):
+ "Handles xml data for evis"
+ evis = []
+ if data.rsp.objects.__dict__.has_key('evis'):
+ if isinstance(data.rsp.objects.evis, list):
+ for evi in data.rsp.objects.evis:
+ if compact:
+ evis.append(_parse_compact_evis(evi))
+ else:
+ evis.append(_parse_evis(evi))
+ else:
+ if compact:
+ evis = [_parse_compact_evis(data.rsp.objects.evis)]
+ else:
+ evis = [_parse_evis(data.rsp.objects.evis)]
+ return evis
+ return None
+
+def _handle_comment_xml(data):
+ comments = []
+ if data.rsp.objects.__dict__.has_key('comment'):
+ if isinstance(data.rsp.objects.comment, list):
+ for c in data.rsp.objects.comment:
+ comments.append(_parse_comment(c))
+ else:
+ comments = [_parse_comment(data.rsp.objects.comment)]
+ return comments
+
+def _handle_comment_json(data):
+ comment = []
+ if isinstance(data.get('objects', None), list):
+ for c in data['objects']:
+ comment.append(_parse_comment_json(c))
+ return comment
+
+def _handle_evis_json(data, compact=False):
+ "Handles json data for evis"
+ evis = []
+ if isinstance(data.get('objects', None), list):
+ for evi in data['objects']:
+ if compact:
+ evis.append(_parse_compact_evis_json(evi))
+ else:
+ evis.append(_parse_evis_json(evi))
+ return evis
+
+def _handle_file_xml(data):
+ files=[]
+ if data.rsp.objects.__dict__.has_key('files'):
+ if isinstance(data.rsp.objects.files, list):
+ for fle in data.rsp.objects.files:
+ files.append(_parse_file(fle))
+ else:
+ files = [_parse_file(data.rsp.objects.files)]
+ return files
+
+def _handle_file_json(data):
+ "Handles json data for file"
+ files = []
+ if isinstance(data.get('objects', None), list):
+ for f in data['objects']:
+ files.append(_parse_file_json(f))
+ return files
+
+def _handle_node_json(data):
+ "Handles json data for nodes"
+ nodes = []
+ if isinstance(data.get('objects', None), list):
+ for n in data['objects']:
+ nodes.append(_parse_node_json(n))
+ return nodes
+
+def _handle_member_json(data):
+ "Handle simplejson data object for member"
+ member = []
+ if isinstance(data.get('objects', None), list):
+ for m in data['objects']:
+ member.append(_parse_member_json(m))
+ return member
+
+
+def _parse_evis_json(e):
+ evi = e.get('evis', {})
+ m = Members(int(evi.get('mem_id', None)), evi.get('mem_name', None))
+ n = Nodes(int(evi.get('nod_id', None)), evi.get('nod_name', None), m)
+ return Evis(e.get('id', None),\
+ n,\
+ m,\
+ evi.get('evi_subject', None),\
+ evi.get('evi_body', None),\
+ evi.get('typ_value', None),\
+ evi.get('evi_comment_count', None),\
+ parseDateTime(evi.get('evi_insert_date', None)),\
+ e.get('ref', None)
+ )
+
+def _parse_compact_evis_json(e):
+ evi = e.get('evis', {})
+ m = Members(int(evi.get('mem_id', None)), evi.get('mem_name', None))
+ n = Nodes(int(evi.get('nod_id', None)), evi.get('nod_name', None), m)
+ return Evis(id=e.get('id', None),\
+ node=n,\
+ member=m,\
+ evi_subject=evi.get('evi_subject', None),\
+ evi_comment_count=evi.get('evi_comment_count', None),\
+ evi_permalink=e.get('ref', None),\
+ evi_insert_date=parseDateTime(evi.get('evi_insert_date', None)))
+
+def _parse_member_json(m):
+ mem = m.get('member', {})
+ if mem.has_key('nod_id_primary'):
+ n = Nodes(int(mem['nod_id_primary']))
+ else:
+ n = None
+ return Members(m.get('id', None),\
+ mem.get('mem_name', None),\
+ mem.get('mem_full_name', None),\
+ mem.get('mem_pen_name', None),
+ n)
+
+
+def _parse_node_json(n):
+ nod = n.get('node', {})
+ if nod.has_key('mem_id'):
+ m = Members(int(nod['mem_id']))
+ else:
+ m = None
+ return Nodes(n.get('id', None),\
+ nod.get('nod_name', None),\
+ m,\
+ n.get('ref', None),\
+ nod.get('nod_strict', None),\
+ nod.get('nod_logo_image', None),\
+ nod.get('nod_desc', None),\
+ nod.get('nod_listener_count', None)\
+ )
+
+def _parse_file_json(f):
+ "Parse file response simplejson"
+ file = f.get('nodes', {})
+ if not f.get('ref', '').startswith('http'):
+ ref = "http://www.eviscape.com%s" % f.get('ref', '')
+ else:
+ ref = f.get('ref', None)
+ return Files(f.get('id', None),\
+ file.get('fle_title', None),\
+ ref)
+
+def _parse_comment_json(c):
+ "Parse comment response"
+ comment= c.get('comment', {})
+ n = Nodes(int(comment.get('nod_id', None)))
+ return Comments(c.get('id', None),\
+ n,\
+ comment.get('ecm_comment', None),\
+ comment.get('mem_pen_name', None),\
+ comment.get('ecm_insert_date', None))
+
+def _parse_member(member):
+ "Parse member response"
+ if hasattr(member, 'mem_pen_name') and hasattr(member.mem_pen_name, 'text'):
+ mem_pen_name = member.mem_pen_name.text
+ else:
+ mem_pen_name = None
+ if hasattr(member, 'nod_id_primary'):
+ n = Nodes(int(member.nod_id_primary.text))
+ else:
+ n = None
+ m = Members(member.id,\
+ member.mem_name.text,\
+ member.mem_full_name.text,\
+ mem_pen_name,\
+ n)
+ return m
+
+def _parse_node(node):
+ "Parse Node response"
+ if hasattr(node, 'nod_logo_image'):
+ logo = node.nod_logo_image.text
+ else:
+ logo = None
+ if hasattr(node, 'nod_desc'):
+ desc = node.nod_desc.text
+ else:
+ desc = None
+
+ if hasattr(node, 'nod_listener_count'):
+ count = node.nod_listener_count
+ else:
+ count = None
+ if hasattr(node, 'mem_id'):
+ m = Members(int(node.mem_id.text))
+ else:
+ m = None
+ n = Nodes(node.id, node.nod_name.text, m, node.ref, node.nod_strict.text,\
+ logo, desc, count)
+ return n
+
+def _parse_evis(evis, reverse_type_id=True):
+ "Parse Evis response"
+ m = Members(int(evis.mem_id.text))
+ n = Nodes(int(evis.nod_id.text))
+ evi = Evis(evis.id, n, m, evis.evi_subject.text, evis.evi_body.text,\
+ evis.type.text, evis.evi_comment_count.text, parseDateTime(evis.evi_insert_date.text), evis.ref,\
+ reverse_type_id=reverse_type_id)
+ return evi
+
+def _parse_compact_evis(evis, reverse_type_id=True):
+ "Parse less informative evis response"
+ m = Members(int(evis.mem_id.text))
+ n = Nodes(int(evis.nod_id.text))
+ evis = Evis(id=evis.id, node=n, member=m, evi_subject=evis.evi_subject.text,\
+ evi_comment_count=evis.evi_comment_count.text,\
+ evi_permalink=evis.ref, evi_insert_date=parseDateTime(evis.evi_insert_date.text), reverse_type_id=reverse_type_id)
+ return evis
+
+def _parse_file(file):
+ "Parse file response"
+ if not file.ref.startswith('http'):
+ ref = "http://www.eviscape.com%s" % file.ref
+ else:
+ ref = file.ref
+ fle = Files(file.id, file.fle_title.text, ref)
+ return fle
+
+def _parse_comment(comment):
+ "Parse comment response"
+ n = Nodes(int(comment.nod_id.text))
+ if not hasattr(comment, 'ecm_insert_date'):
+ ecm_insert_date = ""
+ else:
+ ecm_insert_date = comment.ecm_insert_date.text
+ if hasattr(comment, 'mem_pen_name') and hasattr(comment.mem_pen_name, 'text'):
+ comm = Comments(comment.id, n, comment.ecm_comment.text, comment.mem_pen_name.text,\
+ ecm_insert_date)
+ else:
+ comm = Comments(comment.id, n, comment.ecm_comment.text, None,ecm_insert_date)
+ return comm
536 pyeviscape/oauth.py
@@ -0,0 +1,536 @@
+"""
+The MIT License
+Copyright (c) 2007 Leah Culver
+"""
+
+import cgi
+import urllib
+import time
+import random
+import urlparse
+import hmac
+import binascii
+
+VERSION = '1.0' # Hi Blaine!
+HTTP_METHOD = 'GET'
+SIGNATURE_METHOD = 'PLAINTEXT'
+
+# Generic exception class
+class OAuthError(RuntimeError):
+ def __init__(self, message='OAuth error occured.'):
+ self.message = message
+
+# optional WWW-Authenticate header (401 error)
+def build_authenticate_header(realm=''):
+ return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
+
+# url escape
+def escape(s):
+ # escape '/' too
+ return urllib.quote(s, safe='~')
+
+# util function: current timestamp
+# seconds since epoch (UTC)
+def generate_timestamp():
+ return int(time.time())
+
+# util function: nonce
+# pseudorandom number
+def generate_nonce(length=8):
+ return ''.join([str(random.randint(0, 9)) for i in range(length)])
+
+# OAuthConsumer is a data type that represents the identity of the Consumer
+# via its shared secret with the Service Provider.
+class OAuthConsumer(object):
+ key = None
+ secret = None
+
+ def __init__(self, key, secret):
+ self.key = key
+ self.secret = secret
+
+# OAuthToken is a data type that represents an End User via either an access
+# or request token.
+class OAuthToken(object):
+ # access tokens and request tokens
+ key = None
+ secret = None
+
+ '''
+ key = the token
+ secret = the token secret
+ '''
+ def __init__(self, key, secret):
+ self.key = key
+ self.secret = secret
+
+ def to_string(self):
+ return urllib.urlencode({'oauth_token': self.key, 'oauth_token_secret': self.secret})
+
+ # return a token from something like:
+ # oauth_token_secret=digg&oauth_token=digg
+ def from_string(s):
+ params = cgi.parse_qs(s, keep_blank_values=False)
+ key = params['oauth_token'][0]
+ secret = params['oauth_token_secret'][0]
+ return OAuthToken(key, secret)
+ from_string = staticmethod(from_string)
+
+ def __str__(self):
+ return self.to_string()
+
+# OAuthRequest represents the request and can be serialized
+class OAuthRequest(object):
+ '''
+ OAuth parameters:
+ - oauth_consumer_key
+ - oauth_token
+ - oauth_signature_method
+ - oauth_signature
+ - oauth_timestamp
+ - oauth_nonce
+ - oauth_version
+ ... any additional parameters, as defined by the Service Provider.
+ '''
+ parameters = None # oauth parameters
+ http_method = HTTP_METHOD
+ http_url = None
+ version = VERSION
+
+ def __init__(self, http_method=HTTP_METHOD, http_url=None, parameters=None):
+ self.http_method = http_method
+ self.http_url = http_url
+ self.parameters = parameters or {}
+
+ def set_parameter(self, parameter, value):
+ self.parameters[parameter] = value
+
+ def get_parameter(self, parameter):
+ try:
+ return self.parameters[parameter]
+ except:
+ raise OAuthError('Parameter not found: %s' % parameter)
+
+ def _get_timestamp_nonce(self):
+ return self.get_parameter('oauth_timestamp'), self.get_parameter('oauth_nonce')
+
+ # get any non-oauth parameters
+ def get_nonoauth_parameters(self):
+ parameters = {}
+ for k, v in self.parameters.iteritems():
+ # ignore oauth parameters
+ if k.find('oauth_') < 0:
+ parameters[k] = v
+ return parameters
+
+ # serialize as a header for an HTTPAuth request
+ def to_header(self, realm=''):
+ auth_header = 'OAuth realm="%s"' % realm
+ # add the oauth parameters
+ if self.parameters:
+ for k, v in self.parameters.iteritems():
+ if k[:6] == 'oauth_':
+ auth_header += ', %s="%s"' % (k, escape(str(v)))
+ return {'Authorization': auth_header}
+
+ # serialize as post data for a POST request
+ def to_postdata(self):
+ return '&'.join(['%s=%s' % (escape(str(k)), escape(str(v))) for k, v in self.parameters.iteritems()])
+ # serialize as a url for a GET request
+ def to_url(self):
+ return '%s?%s' % (self.get_normalized_http_url(), self.to_postdata())
+
+ # return a string that consists of all the parameters that need to be signed
+ def get_normalized_parameters(self):
+ params = self.parameters
+ try:
+ # exclude the signature if it exists
+ del params['oauth_signature']
+ except:
+ pass
+ key_values = params.items()
+ # sort lexicographically, first after key, then after value
+ key_values.sort()
+ # combine key value pairs in string and escape
+ return '&'.join(['%s=%s' % (escape(str(k)), escape(str(v))) for k, v in key_values])
+
+ # just uppercases the http method
+ def get_normalized_http_method(self):
+ return self.http_method.upper()
+
+ # parses the url and rebuilds it to be scheme://host/path
+ def get_normalized_http_url(self):
+ parts = urlparse.urlparse(self.http_url)
+ url_string = '%s://%s%s' % (parts[0], parts[1], parts[2]) # scheme, netloc, path
+ return url_string
+
+ # set the signature parameter to the result of build_signature
+ def sign_request(self, signature_method, consumer, token):
+ # set the signature method
+ self.set_parameter('oauth_signature_method', signature_method.get_name())
+ # set the signature
+ self.set_parameter('oauth_signature', self.build_signature(signature_method, consumer, token))
+
+ def build_signature(self, signature_method, consumer, token):
+ # call the build signature method within the signature method
+ return signature_method.build_signature(self, consumer, token)
+
+ def from_request(http_method, http_url, headers=None, parameters=None, query_string=None):
+ # combine multiple parameter sources
+ if parameters is None:
+ parameters = {}
+
+ # headers
+ if headers and 'Authorization' in headers:
+ auth_header = headers['Authorization']
+ # check that the authorization header is OAuth
+ if auth_header.index('OAuth') > -1:
+ try:
+ # get the parameters from the header
+ header_params = OAuthRequest._split_header(auth_header)
+ parameters.update(header_params)
+ except:
+ raise OAuthError('Unable to parse OAuth parameters from Authorization header.')
+
+ # GET or POST query string
+ if query_string:
+ query_params = OAuthRequest._split_url_string(query_string)
+ parameters.update(query_params)
+
+ # URL parameters
+ param_str = urlparse.urlparse(http_url)[4] # query
+ url_params = OAuthRequest._split_url_string(param_str)
+ parameters.update(url_params)
+
+ if parameters:
+ return OAuthRequest(http_method, http_url, parameters)
+
+ return None
+ from_request = staticmethod(from_request)
+
+ def from_consumer_and_token(oauth_consumer, perms=None, token=None, oauth_callback=None, oauth_verifier=None, http_method=HTTP_METHOD, http_url=None, parameters=None):
+ if not parameters:
+ parameters = {}
+
+ defaults = {
+ 'oauth_consumer_key': oauth_consumer.key,
+ 'oauth_timestamp': generate_timestamp(),
+ 'oauth_nonce': generate_nonce(),
+ 'oauth_version': OAuthRequest.version,
+ }
+
+ defaults.update(parameters)
+ parameters = defaults
+
+ if token:
+ parameters['oauth_token'] = token.key
+
+ if oauth_callback:
+ parameters['oauth_callback'] = oauth_callback
+
+ if oauth_verifier:
+ parameters['oauth_verifier'] = oauth_verifier
+
+ if perms:
+ parameters['perms'] = perms
+
+ return OAuthRequest(http_method, http_url, parameters)
+ from_consumer_and_token = staticmethod(from_consumer_and_token)
+
+ def from_token_and_callback(token, callback=None, http_method=HTTP_METHOD, http_url=None, parameters=None):
+ if not parameters:
+ parameters = {}
+
+ parameters['oauth_token'] = token.key
+
+ if callback:
+ parameters['oauth_callback'] = callback
+
+ return OAuthRequest(http_method, http_url, parameters)
+ from_token_and_callback = staticmethod(from_token_and_callback)
+
+ # util function: turn Authorization: header into parameters, has to do some unescaping
+ def _split_header(header):
+ params = {}
+ parts = header.split(',')
+ for param in parts:
+ # ignore realm parameter
+ if param.find('OAuth realm') > -1:
+ continue
+ # remove whitespace
+ param = param.strip()
+ # split key-value
+ param_parts = param.split('=', 1)
+ # remove quotes and unescape the value
+ params[param_parts[0]] = urllib.unquote(param_parts[1].strip('\"'))
+ return params
+ _split_header = staticmethod(_split_header)
+
+ # util function: turn url string into parameters, has to do some unescaping
+ def _split_url_string(param_str):
+ parameters = cgi.parse_qs(param_str, keep_blank_values=False)
+ for k, v in parameters.iteritems():
+ parameters[k] = urllib.unquote(v[0])
+ return parameters
+ _split_url_string = staticmethod(_split_url_string)
+
+# OAuthServer is a worker to check a requests validity against a data store
+class OAuthServer(object):
+ timestamp_threshold = 300 # in seconds, five minutes
+ version = VERSION
+ signature_methods = None
+ data_store = None
+
+ def __init__(self, data_store=None, signature_methods=None):
+ self.data_store = data_store
+ self.signature_methods = signature_methods or {}
+
+ def set_data_store(self, oauth_data_store):
+ self.data_store = data_store
+
+ def get_data_store(self):
+ return self.data_store
+
+ def add_signature_method(self, signature_method):
+ self.signature_methods[signature_method.get_name()] = signature_method
+ return self.signature_methods
+
+ # process a request_token request
+ # returns the request token on success
+ def fetch_request_token(self, oauth_request):
+ try:
+ # get the request token for authorization
+ token = self._get_token(oauth_request, 'request')
+ except OAuthError:
+ # no token required for the initial token request
+ version = self._get_version(oauth_request)
+ consumer = self._get_consumer(oauth_request)
+ self._check_signature(oauth_request, consumer, None)
+ # fetch a new token
+ token = self.data_store.fetch_request_token(consumer)
+ return token
+
+ # process an access_token request
+ # returns the access token on success
+ def fetch_access_token(self, oauth_request):
+ version = self._get_version(oauth_request)
+ consumer = self._get_consumer(oauth_request)
+ # get the request token
+ token = self._get_token(oauth_request, 'request')
+ self._check_signature(oauth_request, consumer, token)
+ new_token = self.data_store.fetch_access_token(consumer, token)
+ return new_token
+
+ # verify an api call, checks all the parameters
+ def verify_request(self, oauth_request):
+ # -> consumer and token
+ version = self._get_version(oauth_request)
+ consumer = self._get_consumer(oauth_request)
+ # get the access token
+ token = self._get_token(oauth_request, 'access')
+ self._check_signature(oauth_request, consumer, token)
+ parameters = oauth_request.get_nonoauth_parameters()
+ return consumer, token, parameters
+
+ # authorize a request token
+ def authorize_token(self, token, user):
+ return self.data_store.authorize_request_token(token, user)
+
+ # get the callback url
+ def get_callback(self, oauth_request):
+ return oauth_request.get_parameter('oauth_callback')
+
+ # optional support for the authenticate header
+ def build_authenticate_header(self, realm=''):
+ return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
+
+ # verify the correct version request for this server
+ def _get_version(self, oauth_request):
+ try:
+ version = oauth_request.get_parameter('oauth_version')
+ except:
+ version = VERSION
+ if version and version != self.version:
+ raise OAuthError('OAuth version %s not supported.' % str(version))
+ return version
+
+ # figure out the signature with some defaults
+ def _get_signature_method(self, oauth_request):
+ try:
+ signature_method = oauth_request.get_parameter('oauth_signature_method')
+ except:
+ signature_method = SIGNATURE_METHOD
+ try:
+ # get the signature method object
+ signature_method = self.signature_methods[signature_method]
+ except:
+ signature_method_names = ', '.join(self.signature_methods.keys())
+ raise OAuthError('Signature method %s not supported try one of the following: %s' % (signature_method, signature_method_names))
+
+ return signature_method
+
+ def _get_consumer(self, oauth_request):
+ consumer_key = oauth_request.get_parameter('oauth_consumer_key')
+ if not consumer_key:
+ raise OAuthError('Invalid consumer key.')
+ consumer = self.data_store.lookup_consumer(consumer_key)
+ if not consumer:
+ raise OAuthError('Invalid consumer.')
+ return consumer
+
+ # try to find the token for the provided request token key
+ def _get_token(self, oauth_request, token_type='access'):
+ token_field = oauth_request.get_parameter('oauth_token')
+ token = self.data_store.lookup_token(token_type, token_field)
+ if not token:
+ raise OAuthError('Invalid %s token: %s' % (token_type, token_field))
+ return token
+
+ def _check_signature(self, oauth_request, consumer, token):
+ timestamp, nonce = oauth_request._get_timestamp_nonce()
+ self._check_timestamp(timestamp)
+ self._check_nonce(consumer, token, nonce)
+ signature_method = self._get_signature_method(oauth_request)
+ try:
+ signature = oauth_request.get_parameter('oauth_signature')
+ except:
+ raise OAuthError('Missing signature.')
+ # validate the signature
+ valid_sig = signature_method.check_signature(oauth_request, consumer, token, signature)
+ if not valid_sig:
+ key, base = signature_method.build_signature_base_string(oauth_request, consumer, token)
+ raise OAuthError('Invalid signature. Expected signature base string: %s' % base)
+ built = signature_method.build_signature(oauth_request, consumer, token)
+
+ def _check_timestamp(self, timestamp):
+ # verify that timestamp is recentish
+ timestamp = int(timestamp)
+ now = int(time.time())
+ lapsed = now - timestamp
+ if lapsed > self.timestamp_threshold:
+ raise OAuthError('Expired timestamp: given %d and now %s has a greater difference than threshold %d' % (timestamp, now, self.timestamp_threshold))
+
+ def _check_nonce(self, consumer, token, nonce):
+ # verify that the nonce is uniqueish
+ nonce = self.data_store.lookup_nonce(consumer, token, nonce)
+ if nonce:
+ raise OAuthError('Nonce already used: %s' % str(nonce))
+
+# OAuthClient is a worker to attempt to execute a request
+class OAuthClient(object):
+ consumer = None
+ token = None
+
+ def __init__(self, oauth_consumer, oauth_token):
+ self.consumer = oauth_consumer
+ self.token = oauth_token
+
+ def get_consumer(self):
+ return self.consumer
+
+ def get_token(self):
+ return self.token
+
+ def fetch_request_token(self, oauth_request):
+ # -> OAuthToken
+ raise NotImplementedError
+
+ def fetch_access_token(self, oauth_request):
+ # -> OAuthToken
+ raise NotImplementedError
+
+ def access_resource(self, oauth_request):
+ # -> some protected resource
+ raise NotImplementedError
+
+# OAuthDataStore is a database abstraction used to lookup consumers and tokens
+class OAuthDataStore(object):
+
+ def lookup_consumer(self, key):
+ # -> OAuthConsumer
+ raise NotImplementedError
+
+ def lookup_token(self, oauth_consumer, token_type, token_token):
+ # -> OAuthToken
+ raise NotImplementedError
+
+ def lookup_nonce(self, oauth_consumer, oauth_token, nonce, timestamp):
+ # -> OAuthToken
+ raise NotImplementedError
+
+ def fetch_request_token(self, oauth_consumer):
+ # -> OAuthToken
+ raise NotImplementedError
+
+ def fetch_access_token(self, oauth_consumer, oauth_token):
+ # -> OAuthToken
+ raise NotImplementedError
+
+ def authorize_request_token(self, oauth_token, user):
+ # -> OAuthToken
+ raise NotImplementedError
+
+# OAuthSignatureMethod is a strategy class that implements a signature method
+class OAuthSignatureMethod(object):
+ def get_name(self):
+ # -> str
+ raise NotImplementedError
+
+ def build_signature_base_string(self, oauth_request, oauth_consumer, oauth_token):
+ # -> str key, str raw
+ raise NotImplementedError
+
+ def build_signature(self, oauth_request, oauth_consumer, oauth_token):
+ # -> str
+ raise NotImplementedError
+
+ def check_signature(self, oauth_request, consumer, token, signature):
+ built = self.build_signature(oauth_request, consumer, token)
+ return built == signature
+
+class OAuthSignatureMethod_HMAC_SHA1(OAuthSignatureMethod):
+
+ def get_name(self):
+ return 'HMAC-SHA1'
+
+ def build_signature_base_string(self, oauth_request, consumer, token):
+ sig = (
+ escape(oauth_request.get_normalized_http_method()),
+ escape(oauth_request.get_normalized_http_url()),
+ escape(oauth_request.get_normalized_parameters()),
+ )
+ key = '%s&' % escape(consumer.secret)
+ if token:
+ key += escape(token.secret)
+ raw = '&'.join(sig)
+ return key, raw
+
+ def build_signature(self, oauth_request, consumer, token):
+ # build the base signature string
+ key, raw = self.build_signature_base_string(oauth_request, consumer, token)
+
+ # hmac object
+ try:
+ import hashlib # 2.5
+ hashed = hmac.new(key, raw, hashlib.sha1)
+ except:
+ import sha # deprecated
+ hashed = hmac.new(key, raw, sha)
+
+ # calculate the digest base 64
+ return binascii.b2a_base64(hashed.digest())[:-1]
+
+class OAuthSignatureMethod_PLAINTEXT(OAuthSignatureMethod):
+
+ def get_name(self):
+ return 'PLAINTEXT'
+
+ def build_signature_base_string(self, oauth_request, consumer, token):
+ # concatenate the consumer key and secret
+ sig = escape(consumer.secret) + '&'
+ if token:
+ sig = sig + escape(token.secret)
+ return sig
+
+ def build_signature(self, oauth_request, consumer, token):
+ return self.build_signature_base_string(oauth_request, consumer, token)
306 pyeviscape/utils.py
@@ -0,0 +1,306 @@
+"""
+Eviscape API wrapper
+Author: Deepak Thukral<deepak@musicpictures.com>
+PyEviscape provides functions for interacting with the Eviscape API.
+
+The MIT License
+
+Copyright (c) 2009 MMIX Musicpictures Ltd, Berlin
+"""
+
+import oauth
+import urlparse
+import re
+from datetime import datetime
+from config import API_KEY, API_SECRET, FORMATTER
+from xml.dom import minidom
+from urllib import urlencode
+from google.appengine.api import urlfetch
+
+if FORMATTER == 'json':
+ from django.utils import simplejson
+
+API_VERSION = '1.0'
+API_PROTOCOL = u'rest'
+SERVER = 'www.eviscape.com'
+API_URL = u'http://%s/api/%s/%s/' % (SERVER, API_VERSION, API_PROTOCOL)
+API_DOCS = u'http://%s/api/%s/docs/' % (SERVER, API_VERSION)
+API_RESPONSE_FORMAT = 'json' #this toolkit only support xml and json
+
+signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
+
+REQUEST_TOKEN_URL = 'http://%s/oauth/request_token' % SERVER
+ACCESS_TOKEN_URL = 'http://%s/oauth/access_token' % SERVER
+AUTHORIZATION_URL = 'http://%s/oauth/authorize' % SERVER
+
+CONSUMER_KEY = API_KEY
+CONSUMER_SECRET = API_SECRET
+
+CONSUMER = oauth.OAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET)
+
+
+
+class EviscapeError(Exception):
+ pass
+
+def request_oauth_resource(consumer, url, access_token, parameters=None, signature_method=signature_method, http_method='GET'):
+ """
+ usage: request_oauth_resource( consumer, '/url/', your_access_token, parameters=dict() )
+ Returns a OAuthRequest object
+ """
+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(
+ consumer, token=access_token, http_url=url, parameters=parameters, http_method=http_method
+ )
+ oauth_request.sign_request(signature_method, consumer, access_token)
+ return oauth_request
+
+
+def fetch_response(oauth_request):
+ url = oauth_request.to_url()
+ result = urlfetch.fetch(url)
+ if result.status_code != 200:
+ raise EviscapeError
+ return result.content
+
+def fetch_urllib(oauth_request, params={}):
+ url = oauth_request.to_url()
+ if oauth_request.http_method.lower() == 'post':
+ result = urlfetch.fetch(url=url,
+ payload=urlencode(params),
+ method=urlfetch.POST,
+ headers={'Content-Type': 'application/x-www-form-urlencoded'})
+ else:
+ result = urlfetch.fetch(url)
+
+ if result.status_code != 200:
+ raise EviscapeError, result.content
+ return result.content
+
+def get_unauthorised_request_token(callback=None, consumer=CONSUMER, signature_method=signature_method):
+ "Ask Eviscape OAuth server for a request_token"
+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(
+ consumer, oauth_callback=callback, http_url=REQUEST_TOKEN_URL
+ )
+ oauth_request.sign_request(signature_method, consumer, None)
+ resp = fetch_response(oauth_request)
+ token = oauth.OAuthToken.from_string(resp)
+ return token
+
+
+def get_authorisation_url(token, perms='write', consumer=CONSUMER, signature_method=signature_method):
+ "Ask Eviscape OAuth server for a authroization URL"
+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(
+ consumer, perms=perms, token=token, http_url=AUTHORIZATION_URL
+ )
+ oauth_request.sign_request(signature_method, consumer, token)
+ return oauth_request.to_url()
+
+def exchange_request_token_for_access_token(request_token, verifier, consumer=CONSUMER, signature_method=signature_method):
+ "Exchange request token with access_token after authorization"
+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(
+ consumer, token=request_token, oauth_callback=verifier, http_url=ACCESS_TOKEN_URL
+ )
+ oauth_request.sign_request(signature_method, consumer, request_token)
+ resp = fetch_urllib(oauth_request)
+ return oauth.OAuthToken.from_string(resp)
+
+def is_authenticated(access_token):
+ "Checks if current access_token is good or not"
+ oauth_request = request_oauth_resource(CONSUMER, API_URL,\
+ access_token,\
+ parameters={'method':'test.echo',\
+ 'format':'json'})
+ json = urlfetch.fetch(oauth_request.to_url()).content
+ if 'auth_checked' in json:
+ return True
+ return False
+
+class Bag(object):
+ pass
+
+#unmarshal taken and modified from pyamazon.py
+#makes the xml easy to work with
+def unmarshal(element):
+ rc = Bag()
+ if isinstance(element, minidom.Element):
+ for key in element.attributes.keys():
+ setattr(rc, key, element.attributes[key].value)
+
+ childElements = [e for e in element.childNodes \
+ if isinstance(e, minidom.Element)]
+ if childElements:
+ for child in childElements:
+ key = child.tagName
+ if hasattr(rc, key):
+ if type(getattr(rc, key)) <> type([]):
+ setattr(rc, key, [getattr(rc, key)])
+ setattr(rc, key, getattr(rc, key) + [unmarshal(child)])
+ elif isinstance(child, minidom.Element) and \
+ (child.tagName == 'Details'):
+ # make the first Details element a key
+ setattr(rc,key,[unmarshal(child)])
+ #dbg: because otherwise 'hasattr' only tests
+ #dbg: on the second occurence: if there's a
+ #dbg: single return to a query, it's not a
+ #dbg: list. This module should always
+ #dbg: return a list of Details objects.
+ else:
+ setattr(rc, key, unmarshal(child))
+ else:
+ #jec: we'll have the main part of the element stored in .text
+ #jec: will break if tag <text> is also present
+ text = "".join([e.data for e in element.childNodes \
+ if isinstance(e, minidom.Text)])
+ setattr(rc, 'text', text)
+ return rc
+
+#unique items from a list from the cookbook
+def uniq(alist): # Fastest without order preserving
+ set = {}
+ map(set.__setitem__, alist, [])
+ return set.keys()
+
+def prepare_params(params):
+ """Convert lists to strings with ',' between items."""
+ for (key, value) in params.items():
+ if isinstance(value, list):
+ params[key] = ','.join([item for item in value])
+ return params
+
+def get_data_xml(xml):
+ """Given a bunch of XML back from Flickr, we turn it into a data structure
+ we can deal with (after checking for errors)."""
+ data = unmarshal(xml)
+ if not data.rsp.stat == 'ok':
+ msg = "ERROR [%s]: %s" % (data.rsp.err.code, data.rsp.err.msg)
+ raise EviscapeError, msg
+ return data
+
+def get_data_json(json):
+ if json['stat'] != 'ok':
+ msg = "ERROR [%s]: %s" % (json['code'], json['msg'])
+ raise EviscapeError, msg
+ return json
+
+def request_get(method, **params):
+ params = prepare_params(params)
+ url = '%s?method=%s&format=%s&nojsoncallback&%s' % (API_URL, method, FORMATTER, urlencode(params))
+ if FORMATTER == 'json':
+ return get_data_json(simplejson.loads(urlfetch.fetch(url).content))
+ return get_data_xml(minidom.parseString(urlfetch.fetch(url).content))
+
+def request_protected_get(method, access_token, **params):
+ p = params
+ p['method'] = method
+ p['format'] = FORMATTER
+ p['nojsoncallback'] = '1'
+ params = prepare_params(params)
+ url = '%s?method=%s&format=%s&nojsoncallback&%s' % (API_URL, method, FORMATTER, urlencode(params))
+ oauth_request = request_oauth_resource(CONSUMER, url, access_token, parameters=p)
+ a = oauth_request.to_url()
+ if FORMATTER == 'json':
+ return get_data_json(simplejson.loads(fetch_response(oauth_request)))
+ return get_data_xml(minidom.parseString(fetch_response(oauth_request)))
+
+def request_protected_post(method, access_token, **params):
+ p = params
+ p['method'] = method
+ p['format'] = FORMATTER
+ p['nojsoncallback'] = '1'
+ params = prepare_params(params)
+ url = '%s?method=%s&format=%s&nojsoncallback&%s' % (API_URL, method, FORMATTER, urlencode(params))
+ oauth_request = request_oauth_resource(CONSUMER, url, access_token, parameters=p, http_method='POST')
+ if FORMATTER == 'json':
+ return get_data_json(simplejson.loads(fetch_urllib(oauth_request, params)))
+ return get_data_xml(minidom.parseString(fetch_urllib(oauth_request, params)))
+
+
+class Promise(object):
+ pass
+
+def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'):
+ """
+ Returns a bytestring version of 's', encoded as specified in 'encoding'.
+
+ If strings_only is True, don't convert (some) non-string-like objects.
+ """
+ if strings_only and isinstance(s, (types.NoneType, int)):
+ return s
+ if isinstance(s, Promise):
+ return unicode(s).encode(encoding, errors)
+ elif not isinstance(s, basestring):
+ try:
+ return str(s)
+ except UnicodeEncodeError:
+ if isinstance(s, Exception):
+ # An Exception subclass containing non-ASCII data that doesn't
+ # know how to print itself properly. We shouldn't raise a
+ # further exception.
+ return ' '.join([smart_str(arg, encoding, strings_only,
+ errors) for arg in s])
+ return unicode(s).encode(encoding, errors)
+ elif isinstance(s, unicode):
+ return s.encode(encoding, errors)
+ elif s and encoding != 'utf-8':
+ return s.decode('utf-8', errors).encode(encoding, errors)
+ else:
+ return s
+
+
+
+
+def parseDateTime(s):
+ """Create datetime object representing date/time
+ expressed in a string
+
+ Takes a string in the format produced by calling str()
+ on a python datetime object and returns a datetime
+ instance that would produce that string.
+
+ Acceptable formats are: "YYYY-MM-DD HH:MM:SS.ssssss+HH:MM",
+ "YYYY-MM-DD HH:MM:SS.ssssss",
+ "YYYY-MM-DD HH:MM:SS+HH:MM",
+ "YYYY-MM-DD HH:MM:SS"
+ Where ssssss represents fractional seconds. The timezone
+ is optional and may be either positive or negative
+ hours/minutes east of UTC.
+ """
+ if s is None:
+ return None
+ # Split string in the form 2007-06-18 19:39:25.3300-07:00
+ # into its constituent date/time, microseconds, and
+ # timezone fields where microseconds and timezone are
+ # optional.
+ m = re.match(r'(.*?)(?:\.(\d+))?(([-+]\d{1,2}):(\d{2}))?$',
+ str(s))
+ datestr, fractional, tzname, tzhour, tzmin = m.groups()
+
+ # Create tzinfo object representing the timezone
+ # expressed in the input string. The names we give
+ # for the timezones are lame: they are just the offset
+ # from UTC (as it appeared in the input string). We
+ # handle UTC specially since it is a very common case
+ # and we know its name.
+ if tzname is None:
+ tz = None
+ else:
+ tzhour, tzmin = int(tzhour), int(tzmin)
+ if tzhour == tzmin == 0:
+ tzname = 'UTC'
+ tz = FixedOffset(timedelta(hours=tzhour,
+ minutes=tzmin), tzname)
+
+ # Convert the date/time field into a python datetime
+ # object.
+ x = datetime.strptime(datestr, "%Y-%m-%d %H:%M:%S")
+
+ # Convert the fractional second portion into a count
+ # of microseconds.
+ if fractional is None:
+ fractional = '0'
+ fracpower = 6 - len(fractional)
+ fractional = float(fractional) * (10 ** fracpower)
+
+ # Return updated datetime object with microseconds and
+ # timezone information.
+ return x.replace(microsecond=int(fractional), tzinfo=tz)
Please sign in to comment.
Something went wrong with that request. Please try again.