Commit 4323b999 by Raphael Lullis

Finally getting rid of all the senseless code on __init__, and creating the code…

Finally getting rid of all the senseless code on __init__, and creating the code (for exceptions) and connection (for access keys management and the ParseBase class) modules.
parent 1098b32a
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import urllib
import urllib2
import base64
import json
import datetime
API_ROOT = 'https://api.parse.com/1'
class ParseError(Exception):
'''Base exceptions from requests made to Parse'''
pass
class ResourceRequestBadRequest(ParseError):
'''Request returns a 400'''
pass
class ResourceRequestLoginRequired(ParseError):
'''Request returns a 401'''
pass
class ResourceRequestForbidden(ParseError):
'''Request returns a 403'''
pass
class ResourceRequestNotFound(ParseError):
'''Request returns a 404'''
pass
def master_key_required(func):
'''decorator describing methods that require the master key'''
def ret(obj, *args, **kw):
conn = ParseBase.CONNECTION
if not (conn and conn.get('master_key')):
message = '%s requires the master key' % func.__name__
raise ParseError(message)
func(obj, *args, **kw)
return ret
class ParseBase(object):
ENDPOINT_ROOT = API_ROOT
@classmethod
def register(cls, app_id, rest_key, **kw):
ParseBase.CONNECTION = {
'app_id': app_id,
'rest_key': rest_key
}
ParseBase.CONNECTION.update(**kw)
@classmethod
def execute(cls, uri, http_verb, extra_headers=None, **kw):
if not ParseBase.CONNECTION:
raise ParseError('Missing connection credentials')
app_id = ParseBase.CONNECTION.get('app_id')
rest_key = ParseBase.CONNECTION.get('rest_key')
master_key = ParseBase.CONNECTION.get('master_key')
headers = extra_headers or {}
url = uri if uri.startswith(API_ROOT) else cls.ENDPOINT_ROOT + uri
data = kw and json.dumps(kw) or "{}"
if http_verb == 'GET' and data:
url += '?%s' % urllib.urlencode(kw)
data = None
request = urllib2.Request(url, data, headers)
request.add_header('Content-type', 'application/json')
request.add_header('X-Parse-Application-Id', app_id)
request.add_header('X-Parse-REST-API-Key', rest_key)
if master_key: request.add_header('X-Parse-Master-Key', master_key)
request.get_method = lambda: http_verb
try:
response = urllib2.urlopen(request)
except urllib2.HTTPError, e:
exc = {
400: ResourceRequestBadRequest,
401: ResourceRequestLoginRequired,
403: ResourceRequestForbidden,
404: ResourceRequestNotFound
}.get(e.code, ParseError)
raise exc(e.read())
return json.loads(response.read())
@classmethod
def GET(cls, uri, **kw):
return cls.execute(uri, 'GET', **kw)
@classmethod
def POST(cls, uri, **kw):
return cls.execute(uri, 'POST', **kw)
@classmethod
def PUT(cls, uri, **kw):
return cls.execute(uri, 'PUT', **kw)
@classmethod
def DELETE(cls, uri, **kw):
return cls.execute(uri, 'DELETE', **kw)
__all__ = [
'ParseBase', 'ResourceRequestBadRequest', 'ResourceLoginRequired',
'ResourceRequestForbidden', 'ResourceRequestNotFound'
]
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import urllib2
import urllib
import json
import core
API_ROOT = 'https://api.parse.com/1'
ACCESS_KEYS = {}
def register(app_id, rest_key, **kw):
global ACCESS_KEYS
ACCESS_KEYS = {
'app_id': app_id,
'rest_key': rest_key
}
ACCESS_KEYS.update(**kw)
def master_key_required(func):
'''decorator describing methods that require the master key'''
def ret(obj, *args, **kw):
conn = ACCESS_KEYS
if not (conn and conn.get('master_key')):
message = '%s requires the master key' % func.__name__
raise core.ParseError(message)
func(obj, *args, **kw)
return ret
class ParseBase(object):
ENDPOINT_ROOT = API_ROOT
@classmethod
def execute(cls, uri, http_verb, extra_headers=None, **kw):
if not ('app_id' in ACCESS_KEYS and 'rest_key' in ACCESS_KEYS):
raise core.ParseError('Missing connection credentials')
app_id = ACCESS_KEYS.get('app_id')
rest_key = ACCESS_KEYS.get('rest_key')
master_key = ACCESS_KEYS.get('master_key')
headers = extra_headers or {}
url = uri if uri.startswith(API_ROOT) else cls.ENDPOINT_ROOT + uri
data = kw and json.dumps(kw) or "{}"
if http_verb == 'GET' and data:
url += '?%s' % urllib.urlencode(kw)
data = None
request = urllib2.Request(url, data, headers)
request.add_header('Content-type', 'application/json')
request.add_header('X-Parse-Application-Id', app_id)
request.add_header('X-Parse-REST-API-Key', rest_key)
if master_key: request.add_header('X-Parse-Master-Key', master_key)
request.get_method = lambda: http_verb
try:
response = urllib2.urlopen(request)
except urllib2.HTTPError, e:
exc = {
400: core.ResourceRequestBadRequest,
401: core.ResourceRequestLoginRequired,
403: core.ResourceRequestForbidden,
404: core.ResourceRequestNotFound
}.get(e.code, core.ParseError)
raise exc(e.read())
return json.loads(response.read())
@classmethod
def GET(cls, uri, **kw):
return cls.execute(uri, 'GET', **kw)
@classmethod
def POST(cls, uri, **kw):
return cls.execute(uri, 'POST', **kw)
@classmethod
def PUT(cls, uri, **kw):
return cls.execute(uri, 'PUT', **kw)
@classmethod
def DELETE(cls, uri, **kw):
return cls.execute(uri, 'DELETE', **kw)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class ParseError(Exception):
'''Base exceptions from requests made to Parse'''
pass
class ResourceRequestBadRequest(ParseError):
'''Request returns a 400'''
pass
class ResourceRequestLoginRequired(ParseError):
'''Request returns a 401'''
pass
class ResourceRequestForbidden(ParseError):
'''Request returns a 403'''
pass
class ResourceRequestNotFound(ParseError):
'''Request returns a 404'''
pass
...@@ -13,11 +13,11 @@ ...@@ -13,11 +13,11 @@
import base64 import base64
import datetime import datetime
import urllib2
from __init__ import ParseBase, API_ROOT from connection import API_ROOT, ParseBase
from query import QueryManager from query import QueryManager
class ParseType(object): class ParseType(object):
@staticmethod @staticmethod
...@@ -176,6 +176,7 @@ class File(ParseType): ...@@ -176,6 +176,7 @@ class File(ParseType):
_absolute_url = property(lambda self: self._api_url) _absolute_url = property(lambda self: self._api_url)
class ParseResource(ParseBase, Pointer): class ParseResource(ParseBase, Pointer):
PROTECTED_ATTRIBUTES = ['objectId', 'createdAt', 'updatedAt'] PROTECTED_ATTRIBUTES = ['objectId', 'createdAt', 'updatedAt']
...@@ -302,4 +303,3 @@ class Object(ParseResource): ...@@ -302,4 +303,3 @@ class Object(ParseResource):
} }
self.__class__.PUT(self._absolute_url, **payload) self.__class__.PUT(self._absolute_url, **payload)
self.__dict__[key] += amount self.__dict__[key] += amount
...@@ -9,10 +9,11 @@ import os ...@@ -9,10 +9,11 @@ import os
import sys import sys
import subprocess import subprocess
import unittest import unittest
import urllib2
import datetime import datetime
import __init__ as parse_rest
from core import ResourceRequestNotFound
from connection import register
from datatypes import GeoPoint, Object from datatypes import GeoPoint, Object
from function import Function from function import Function
from user import User from user import User
...@@ -24,7 +25,7 @@ except ImportError: ...@@ -24,7 +25,7 @@ except ImportError:
sys.exit('You must create a settings_local.py file with APPLICATION_ID, ' \ sys.exit('You must create a settings_local.py file with APPLICATION_ID, ' \
'REST_API_KEY, MASTER_KEY variables set') 'REST_API_KEY, MASTER_KEY variables set')
parse_rest.ParseBase.register( register(
getattr(settings_local, 'APPLICATION_ID'), getattr(settings_local, 'APPLICATION_ID'),
getattr(settings_local, 'REST_API_KEY'), getattr(settings_local, 'REST_API_KEY'),
master_key=getattr(settings_local, 'MASTER_KEY') master_key=getattr(settings_local, 'MASTER_KEY')
...@@ -169,7 +170,6 @@ class TestTypes(unittest.TestCase): ...@@ -169,7 +170,6 @@ class TestTypes(unittest.TestCase):
'Can not serialize geopoint data') 'Can not serialize geopoint data')
def testCanConvertDate(self): def testCanConvertDate(self):
native_score = self.score._to_native()
native_date = self.score._to_native().get('date_of_birth') native_date = self.score._to_native().get('date_of_birth')
self.assert_(type(native_date) is dict, self.assert_(type(native_date) is dict,
'Could not serialize date into dict') 'Could not serialize date into dict')
...@@ -271,7 +271,6 @@ class TestQuery(unittest.TestCase): ...@@ -271,7 +271,6 @@ class TestQuery(unittest.TestCase):
def testCanCompareDateInequality(self): def testCanCompareDateInequality(self):
today = datetime.datetime.today() today = datetime.datetime.today()
tomorrow = today + datetime.timedelta(days=1) tomorrow = today + datetime.timedelta(days=1)
yesterday = today - datetime.timedelta(days=1)
self.assert_(GameScore.Query.lte(createdAt=tomorrow).count() == 5, self.assert_(GameScore.Query.lte(createdAt=tomorrow).count() == 5,
'Could not make inequality comparison with dates') 'Could not make inequality comparison with dates')
...@@ -352,7 +351,7 @@ class TestUser(unittest.TestCase): ...@@ -352,7 +351,7 @@ class TestUser(unittest.TestCase):
try: try:
u = User.login(self.USERNAME, self.PASSWORD) u = User.login(self.USERNAME, self.PASSWORD)
except parse_rest.ResourceRequestNotFound as e: except ResourceRequestNotFound:
# if the user doesn't exist, that's fine # if the user doesn't exist, that's fine
return return
u.delete() u.delete()
......
...@@ -11,11 +11,9 @@ ...@@ -11,11 +11,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
import datetime
import copy
from __init__ import API_ROOT from core import ResourceRequestLoginRequired
from connection import API_ROOT
from datatypes import ParseResource, ParseType from datatypes import ParseResource, ParseType
from query import QueryManager from query import QueryManager
...@@ -85,7 +83,7 @@ class User(ParseResource): ...@@ -85,7 +83,7 @@ class User(ParseResource):
try: try:
User.POST(url, email=email) User.POST(url, email=email)
return True return True
except Exception, why: except:
return False return False
def _to_native(self): def _to_native(self):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment