From f828ed535da0347801be9104c814735cfcbb7fbf Mon Sep 17 00:00:00 2001 From: Vladimir Vinogradov Date: Fri, 3 Jan 2014 23:30:49 +0400 Subject: [PATCH 1/3] login method and ability to call API under user session --- __init__.py | 388 ++++++++++++++++++++++++++++------------------------ 1 file changed, 207 insertions(+), 181 deletions(-) diff --git a/__init__.py b/__init__.py index e01657c..078379e 100644 --- a/__init__.py +++ b/__init__.py @@ -11,245 +11,271 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import urllib, urllib2 +import urllib +import urllib2 import base64 import json import datetime import collections -API_ROOT = 'https://api.parse.com/1/classes' + +API_ROOT = 'https://api.parse.com/1' +API_CLASSES_ROOT = API_ROOT + '/classes' APPLICATION_ID = '' MASTER_KEY = '' +# user objects cannot be modified under master key, even with active session +# so for this case we need to use REST API key +REST_API_KEY = '' +SESSION_TOKEN = '' + + +def login(username, password): + request = urllib2.Request(API_ROOT + '/login?username=' + username + "&" + "password=" + password) + + request.add_header('X-Parse-Application-Id', APPLICATION_ID) + request.add_header('X-Parse-Master-Key', MASTER_KEY) + + response = urllib2.urlopen(request) + response_body = response.read() + response_dict = json.loads(response_body) + + global SESSION_TOKEN + SESSION_TOKEN = response_dict[u"sessionToken"] + + return response_dict class ParseBinaryDataWrapper(str): - pass + pass class ParseBase(object): - def _executeCall(self, uri, http_verb, data=None): - url = API_ROOT + uri - - request = urllib2.Request(url, data) + def _executeCall(self, uri, http_verb, data=None): + url = API_CLASSES_ROOT + uri - request.add_header('Content-type', 'application/json') + request = urllib2.Request(url, data) - # we could use urllib2's authentication system, but it seems like overkill for this - auth_header = "Basic %s" % base64.b64encode('%s:%s' % (APPLICATION_ID, MASTER_KEY)) - request.add_header("Authorization", auth_header) + request.add_header('Content-type', 'application/json') + request.add_header('X-Parse-Application-Id', APPLICATION_ID) + if REST_API_KEY: + request.add_header('X-Parse-REST-API-Key', REST_API_KEY) + elif MASTER_KEY: + request.add_header('X-Parse-Master-Key', MASTER_KEY) + if SESSION_TOKEN: + request.add_header('X-Parse-Session-Token', SESSION_TOKEN) - request.get_method = lambda: http_verb + request.get_method = lambda: http_verb - # TODO: add error handling for server response - response = urllib2.urlopen(request) - response_body = response.read() - response_dict = json.loads(response_body) + # TODO: add error handling for server response + response = urllib2.urlopen(request) + response_body = response.read() + response_dict = json.loads(response_body) - return response_dict + return response_dict - def _ISO8601ToDatetime(self, date_string): - # TODO: verify correct handling of timezone - date_string = date_string[:-1] + 'UTC' - date = datetime.datetime.strptime(date_string, "%Y-%m-%dT%H:%M:%S.%f%Z") - return date + def _ISO8601ToDatetime(self, date_string): + # TODO: verify correct handling of timezone + date_string = date_string[:-1] + 'UTC' + date = datetime.datetime.strptime(date_string, "%Y-%m-%dT%H:%M:%S.%f%Z") + return date class ParseObject(ParseBase): - def __init__(self, class_name, attrs_dict=None): - self._class_name = class_name - self._object_id = None - self._updated_at = None - self._created_at = None + def __init__(self, class_name, attrs_dict=None): + self._class_name = class_name + self._object_id = None + self._updated_at = None + self._created_at = None + + if attrs_dict: + self._populateFromDict(attrs_dict) + + def objectId(self): + return self._object_id - if attrs_dict: - self._populateFromDict(attrs_dict) + def updatedAt(self): + return self._updated_at and self._ISO8601ToDatetime(self._updated_at) or None - def objectId(self): - return self._object_id + def createdAt(self): + return self._created_at and self._ISO8601ToDatetime(self._created_at) or None - def updatedAt(self): - return self._updated_at and self._ISO8601ToDatetime(self._updated_at) or None + def save(self): + if self._object_id: + self._update() + else: + self._create() - def createdAt(self): - return self._created_at and self._ISO8601ToDatetime(self._created_at) or None + def delete(self): + # URL: /1/classes// + # HTTP Verb: DELETE - def save(self): - if self._object_id: - self._update() - else: - self._create() + uri = '/%s/%s' % (self._class_name, self._object_id) - def delete(self): - # URL: /1/classes// - # HTTP Verb: DELETE + self._executeCall(uri, 'DELETE') - uri = '/%s/%s' % (self._class_name, self._object_id) + self = self.__init__(None) - self._executeCall(uri, 'DELETE') + def _populateFromDict(self, attrs_dict): + self._object_id = attrs_dict['objectId'] + self._created_at = attrs_dict['createdAt'] + self._updated_at = attrs_dict['updatedAt'] - self = self.__init__(None) + del attrs_dict['objectId'] + del attrs_dict['createdAt'] + del attrs_dict['updatedAt'] - def _populateFromDict(self, attrs_dict): - self._object_id = attrs_dict['objectId'] - self._created_at = attrs_dict['createdAt'] - self._updated_at = attrs_dict['updatedAt'] + attrs_dict = dict(map(self._convertFromParseType, attrs_dict.items())) - del attrs_dict['objectId'] - del attrs_dict['createdAt'] - del attrs_dict['updatedAt'] + self.__dict__.update(attrs_dict) - attrs_dict = dict(map(self._convertFromParseType, attrs_dict.items())) + def _convertToParseType(self, prop): + key, value = prop - self.__dict__.update(attrs_dict) + if type(value) == ParseObject: + value = {'__type': 'Pointer', + 'className': value._class_name, + 'objectId': value._object_id} + elif type(value) == datetime.datetime: + value = {'__type': 'Date', + 'iso': value.isoformat()[:-3] + 'Z'} # take off the last 3 digits and add a Z + elif type(value) == ParseBinaryDataWrapper: + value = {'__type': 'Bytes', + 'base64': base64.b64encode(value)} - def _convertToParseType(self, prop): - key, value = prop + return (key, value) - if type(value) == ParseObject: - value = {'__type': 'Pointer', - 'className': value._class_name, - 'objectId': value._object_id} - elif type(value) == datetime.datetime: - value = {'__type': 'Date', - 'iso': value.isoformat()[:-3] + 'Z'} # take off the last 3 digits and add a Z - elif type(value) == ParseBinaryDataWrapper: - value = {'__type': 'Bytes', - 'base64': base64.b64encode(value)} + def _convertFromParseType(self, prop): + key, value = prop - return (key, value) + if type(value) == dict and value.has_key('__type'): + if value['__type'] == 'Pointer': + value = ParseQuery(value['className']).get(value['objectId']) + elif value['__type'] == 'Date': + value = self._ISO8601ToDatetime(value['iso']) + elif value['__type'] == 'Bytes': + value = ParseBinaryDataWrapper(base64.b64decode(value['base64'])) + else: + raise Exception('Invalid __type.') - def _convertFromParseType(self, prop): - key, value = prop + return (key, value) - if type(value) == dict and value.has_key('__type'): - if value['__type'] == 'Pointer': - value = ParseQuery(value['className']).get(value['objectId']) - elif value['__type'] == 'Date': - value = self._ISO8601ToDatetime(value['iso']) - elif value['__type'] == 'Bytes': - value = ParseBinaryDataWrapper(base64.b64decode(value['base64'])) - else: - raise Exception('Invalid __type.') + def _getJSONProperties(self): - return (key, value) + properties_list = self.__dict__.items() - def _getJSONProperties(self): + # filter properties that start with an underscore and equal to 'sessionToken' + properties_list = filter(lambda prop: prop[0][0] != '_' and prop[0] != 'sessionToken', properties_list) - properties_list = self.__dict__.items() + #properties_list = [(key, value) for key, value in self.__dict__.items() if key[0] != '_'] - # filter properties that start with an underscore - properties_list = filter(lambda prop: prop[0][0] != '_', properties_list) + properties_list = map(self._convertToParseType, properties_list) - #properties_list = [(key, value) for key, value in self.__dict__.items() if key[0] != '_'] + properties_dict = dict(properties_list) + json_properties = json.dumps(properties_dict) - properties_list = map(self._convertToParseType, properties_list) - - properties_dict = dict(properties_list) - json_properties = json.dumps(properties_dict) + return json_properties - return json_properties + def _create(self): + # URL: /1/classes/ + # HTTP Verb: POST - def _create(self): - # URL: /1/classes/ - # HTTP Verb: POST + uri = '/%s' % self._class_name - uri = '/%s' % self._class_name + data = self._getJSONProperties() - data = self._getJSONProperties() + response_dict = self._executeCall(uri, 'POST', data) - response_dict = self._executeCall(uri, 'POST', data) - - self._created_at = self._updated_at = response_dict['createdAt'] - self._object_id = response_dict['objectId'] + self._created_at = self._updated_at = response_dict['createdAt'] + self._object_id = response_dict['objectId'] - def _update(self): - # URL: /1/classes// - # HTTP Verb: PUT + def _update(self): + # URL: /1/classes// + # HTTP Verb: PUT - uri = '/%s/%s' % (self._class_name, self._object_id) + uri = '/%s/%s' % (self._class_name, self._object_id) - data = self._getJSONProperties() + data = self._getJSONProperties() - response_dict = self._executeCall(uri, 'PUT', data) + response_dict = self._executeCall(uri, 'PUT', data) - self._updated_at = response_dict['updatedAt'] + self._updated_at = response_dict['updatedAt'] class ParseQuery(ParseBase): - def __init__(self, class_name): - self._class_name = class_name - self._where = collections.defaultdict(dict) - self._options = {} - self._object_id = '' - - def eq(self, name, value): - self._where[name] = value - return self - - # It's tempting to generate the comparison functions programatically, - # but probably not worth the decrease in readability of the code. - def lt(self, name, value): - self._where[name]['$lt'] = value - return self - - def lte(self, name, value): - self._where[name]['$lte'] = value - return self - - def gt(self, name, value): - self._where[name]['$gt'] = value - return self - - def gte(self, name, value): - self._where[name]['$gte'] = value - return self - - def ne(self, name, value): - self._where[name]['$ne'] = value - return self - - def order(self, order, decending=False): - # add a minus sign before the order value if decending == True - self._options['order'] = decending and ('-' + order) or order - return self - - def limit(self, limit): - self._options['limit'] = limit - return self - - def skip(self, skip): - self._options['skip'] = skip - return self - - def get(self, object_id): - self._object_id = object_id - return self._fetch(single_result=True) - - def fetch(self): - # hide the single_result param of the _fetch method from the library user - # since it's only useful internally - return self._fetch() - - def _fetch(self, single_result=False): - # URL: /1/classes// - # HTTP Verb: GET - - if self._object_id: - uri = '/%s/%s' % (self._class_name, self._object_id) - else: - options = dict(self._options) # make a local copy - if self._where: - # JSON encode WHERE values - where = json.dumps(self._where) - options.update({'where': where}) - - uri = '/%s?%s' % (self._class_name, urllib.urlencode(options)) - - response_dict = self._executeCall(uri, 'GET') - - if single_result: - return ParseObject(self._class_name, response_dict) - else: - return [ParseObject(self._class_name, result) for result in response_dict['results']] + def __init__(self, class_name): + self._class_name = class_name + self._where = collections.defaultdict(dict) + self._options = {} + self._object_id = '' + + def eq(self, name, value): + self._where[name] = value + return self + + # It's tempting to generate the comparison functions programatically, + # but probably not worth the decrease in readability of the code. + def lt(self, name, value): + self._where[name]['$lt'] = value + return self + + def lte(self, name, value): + self._where[name]['$lte'] = value + return self + + def gt(self, name, value): + self._where[name]['$gt'] = value + return self + + def gte(self, name, value): + self._where[name]['$gte'] = value + return self + + def ne(self, name, value): + self._where[name]['$ne'] = value + return self + + def order(self, order, decending=False): + # add a minus sign before the order value if decending == True + self._options['order'] = decending and ('-' + order) or order + return self + + def limit(self, limit): + self._options['limit'] = limit + return self + + def skip(self, skip): + self._options['skip'] = skip + return self + + def get(self, object_id): + self._object_id = object_id + return self._fetch(single_result=True) + + def fetch(self): + # hide the single_result param of the _fetch method from the library user + # since it's only useful internally + return self._fetch() + + def _fetch(self, single_result=False): + # URL: /1/classes// + # HTTP Verb: GET + + if self._object_id: + uri = '/%s/%s' % (self._class_name, self._object_id) + else: + options = dict(self._options) # make a local copy + if self._where: + # JSON encode WHERE values + where = json.dumps(self._where) + options.update({'where': where}) + + uri = '/%s?%s' % (self._class_name, urllib.urlencode(options)) + + response_dict = self._executeCall(uri, 'GET') + + if single_result: + return ParseObject(self._class_name, response_dict) + else: + return [ParseObject(self._class_name, result) for result in response_dict['results']] From 073aa123e8c22db75302962661b84e8a43533396 Mon Sep 17 00:00:00 2001 From: Vladimir Vinogradov Date: Fri, 3 Jan 2014 23:39:37 +0400 Subject: [PATCH 2/3] converted tabs back to spaces --- __init__.py | 378 ++++++++++++++++++++++++++-------------------------- 1 file changed, 189 insertions(+), 189 deletions(-) diff --git a/__init__.py b/__init__.py index 078379e..4ace687 100644 --- a/__init__.py +++ b/__init__.py @@ -31,251 +31,251 @@ def login(username, password): - request = urllib2.Request(API_ROOT + '/login?username=' + username + "&" + "password=" + password) + request = urllib2.Request(API_ROOT + '/login?username=' + username + "&" + "password=" + password) - request.add_header('X-Parse-Application-Id', APPLICATION_ID) - request.add_header('X-Parse-Master-Key', MASTER_KEY) + request.add_header('X-Parse-Application-Id', APPLICATION_ID) + request.add_header('X-Parse-Master-Key', MASTER_KEY) - response = urllib2.urlopen(request) - response_body = response.read() - response_dict = json.loads(response_body) + response = urllib2.urlopen(request) + response_body = response.read() + response_dict = json.loads(response_body) - global SESSION_TOKEN - SESSION_TOKEN = response_dict[u"sessionToken"] + global SESSION_TOKEN + SESSION_TOKEN = response_dict[u"sessionToken"] - return response_dict + return response_dict class ParseBinaryDataWrapper(str): - pass + pass class ParseBase(object): - def _executeCall(self, uri, http_verb, data=None): - url = API_CLASSES_ROOT + uri + def _executeCall(self, uri, http_verb, data=None): + url = API_CLASSES_ROOT + uri - request = urllib2.Request(url, data) + request = urllib2.Request(url, data) - request.add_header('Content-type', 'application/json') - request.add_header('X-Parse-Application-Id', APPLICATION_ID) - if REST_API_KEY: - request.add_header('X-Parse-REST-API-Key', REST_API_KEY) - elif MASTER_KEY: - request.add_header('X-Parse-Master-Key', MASTER_KEY) - if SESSION_TOKEN: - request.add_header('X-Parse-Session-Token', SESSION_TOKEN) + request.add_header('Content-type', 'application/json') + request.add_header('X-Parse-Application-Id', APPLICATION_ID) + if REST_API_KEY: + request.add_header('X-Parse-REST-API-Key', REST_API_KEY) + elif MASTER_KEY: + request.add_header('X-Parse-Master-Key', MASTER_KEY) + if SESSION_TOKEN: + request.add_header('X-Parse-Session-Token', SESSION_TOKEN) - request.get_method = lambda: http_verb + request.get_method = lambda: http_verb - # TODO: add error handling for server response - response = urllib2.urlopen(request) - response_body = response.read() - response_dict = json.loads(response_body) + # TODO: add error handling for server response + response = urllib2.urlopen(request) + response_body = response.read() + response_dict = json.loads(response_body) - return response_dict + return response_dict - def _ISO8601ToDatetime(self, date_string): - # TODO: verify correct handling of timezone - date_string = date_string[:-1] + 'UTC' - date = datetime.datetime.strptime(date_string, "%Y-%m-%dT%H:%M:%S.%f%Z") - return date + def _ISO8601ToDatetime(self, date_string): + # TODO: verify correct handling of timezone + date_string = date_string[:-1] + 'UTC' + date = datetime.datetime.strptime(date_string, "%Y-%m-%dT%H:%M:%S.%f%Z") + return date class ParseObject(ParseBase): - def __init__(self, class_name, attrs_dict=None): - self._class_name = class_name - self._object_id = None - self._updated_at = None - self._created_at = None + def __init__(self, class_name, attrs_dict=None): + self._class_name = class_name + self._object_id = None + self._updated_at = None + self._created_at = None - if attrs_dict: - self._populateFromDict(attrs_dict) + if attrs_dict: + self._populateFromDict(attrs_dict) - def objectId(self): - return self._object_id + def objectId(self): + return self._object_id - def updatedAt(self): - return self._updated_at and self._ISO8601ToDatetime(self._updated_at) or None + def updatedAt(self): + return self._updated_at and self._ISO8601ToDatetime(self._updated_at) or None - def createdAt(self): - return self._created_at and self._ISO8601ToDatetime(self._created_at) or None + def createdAt(self): + return self._created_at and self._ISO8601ToDatetime(self._created_at) or None - def save(self): - if self._object_id: - self._update() - else: - self._create() + def save(self): + if self._object_id: + self._update() + else: + self._create() - def delete(self): - # URL: /1/classes// - # HTTP Verb: DELETE + def delete(self): + # URL: /1/classes// + # HTTP Verb: DELETE - uri = '/%s/%s' % (self._class_name, self._object_id) + uri = '/%s/%s' % (self._class_name, self._object_id) - self._executeCall(uri, 'DELETE') + self._executeCall(uri, 'DELETE') - self = self.__init__(None) + self = self.__init__(None) - def _populateFromDict(self, attrs_dict): - self._object_id = attrs_dict['objectId'] - self._created_at = attrs_dict['createdAt'] - self._updated_at = attrs_dict['updatedAt'] + def _populateFromDict(self, attrs_dict): + self._object_id = attrs_dict['objectId'] + self._created_at = attrs_dict['createdAt'] + self._updated_at = attrs_dict['updatedAt'] - del attrs_dict['objectId'] - del attrs_dict['createdAt'] - del attrs_dict['updatedAt'] + del attrs_dict['objectId'] + del attrs_dict['createdAt'] + del attrs_dict['updatedAt'] - attrs_dict = dict(map(self._convertFromParseType, attrs_dict.items())) + attrs_dict = dict(map(self._convertFromParseType, attrs_dict.items())) - self.__dict__.update(attrs_dict) + self.__dict__.update(attrs_dict) - def _convertToParseType(self, prop): - key, value = prop + def _convertToParseType(self, prop): + key, value = prop - if type(value) == ParseObject: - value = {'__type': 'Pointer', - 'className': value._class_name, - 'objectId': value._object_id} - elif type(value) == datetime.datetime: - value = {'__type': 'Date', - 'iso': value.isoformat()[:-3] + 'Z'} # take off the last 3 digits and add a Z - elif type(value) == ParseBinaryDataWrapper: - value = {'__type': 'Bytes', - 'base64': base64.b64encode(value)} + if type(value) == ParseObject: + value = {'__type': 'Pointer', + 'className': value._class_name, + 'objectId': value._object_id} + elif type(value) == datetime.datetime: + value = {'__type': 'Date', + 'iso': value.isoformat()[:-3] + 'Z'} # take off the last 3 digits and add a Z + elif type(value) == ParseBinaryDataWrapper: + value = {'__type': 'Bytes', + 'base64': base64.b64encode(value)} - return (key, value) + return (key, value) - def _convertFromParseType(self, prop): - key, value = prop + def _convertFromParseType(self, prop): + key, value = prop - if type(value) == dict and value.has_key('__type'): - if value['__type'] == 'Pointer': - value = ParseQuery(value['className']).get(value['objectId']) - elif value['__type'] == 'Date': - value = self._ISO8601ToDatetime(value['iso']) - elif value['__type'] == 'Bytes': - value = ParseBinaryDataWrapper(base64.b64decode(value['base64'])) - else: - raise Exception('Invalid __type.') + if type(value) == dict and value.has_key('__type'): + if value['__type'] == 'Pointer': + value = ParseQuery(value['className']).get(value['objectId']) + elif value['__type'] == 'Date': + value = self._ISO8601ToDatetime(value['iso']) + elif value['__type'] == 'Bytes': + value = ParseBinaryDataWrapper(base64.b64decode(value['base64'])) + else: + raise Exception('Invalid __type.') - return (key, value) + return (key, value) - def _getJSONProperties(self): + def _getJSONProperties(self): - properties_list = self.__dict__.items() + properties_list = self.__dict__.items() - # filter properties that start with an underscore and equal to 'sessionToken' - properties_list = filter(lambda prop: prop[0][0] != '_' and prop[0] != 'sessionToken', properties_list) + # filter properties that start with an underscore and equal to 'sessionToken' + properties_list = filter(lambda prop: prop[0][0] != '_' and prop[0] != 'sessionToken', properties_list) - #properties_list = [(key, value) for key, value in self.__dict__.items() if key[0] != '_'] + #properties_list = [(key, value) for key, value in self.__dict__.items() if key[0] != '_'] - properties_list = map(self._convertToParseType, properties_list) + properties_list = map(self._convertToParseType, properties_list) - properties_dict = dict(properties_list) - json_properties = json.dumps(properties_dict) + properties_dict = dict(properties_list) + json_properties = json.dumps(properties_dict) - return json_properties + return json_properties - def _create(self): - # URL: /1/classes/ - # HTTP Verb: POST + def _create(self): + # URL: /1/classes/ + # HTTP Verb: POST - uri = '/%s' % self._class_name + uri = '/%s' % self._class_name - data = self._getJSONProperties() + data = self._getJSONProperties() - response_dict = self._executeCall(uri, 'POST', data) + response_dict = self._executeCall(uri, 'POST', data) - self._created_at = self._updated_at = response_dict['createdAt'] - self._object_id = response_dict['objectId'] + self._created_at = self._updated_at = response_dict['createdAt'] + self._object_id = response_dict['objectId'] - def _update(self): - # URL: /1/classes// - # HTTP Verb: PUT + def _update(self): + # URL: /1/classes// + # HTTP Verb: PUT - uri = '/%s/%s' % (self._class_name, self._object_id) + uri = '/%s/%s' % (self._class_name, self._object_id) - data = self._getJSONProperties() + data = self._getJSONProperties() - response_dict = self._executeCall(uri, 'PUT', data) + response_dict = self._executeCall(uri, 'PUT', data) - self._updated_at = response_dict['updatedAt'] + self._updated_at = response_dict['updatedAt'] class ParseQuery(ParseBase): - def __init__(self, class_name): - self._class_name = class_name - self._where = collections.defaultdict(dict) - self._options = {} - self._object_id = '' - - def eq(self, name, value): - self._where[name] = value - return self - - # It's tempting to generate the comparison functions programatically, - # but probably not worth the decrease in readability of the code. - def lt(self, name, value): - self._where[name]['$lt'] = value - return self - - def lte(self, name, value): - self._where[name]['$lte'] = value - return self - - def gt(self, name, value): - self._where[name]['$gt'] = value - return self - - def gte(self, name, value): - self._where[name]['$gte'] = value - return self - - def ne(self, name, value): - self._where[name]['$ne'] = value - return self - - def order(self, order, decending=False): - # add a minus sign before the order value if decending == True - self._options['order'] = decending and ('-' + order) or order - return self - - def limit(self, limit): - self._options['limit'] = limit - return self - - def skip(self, skip): - self._options['skip'] = skip - return self - - def get(self, object_id): - self._object_id = object_id - return self._fetch(single_result=True) - - def fetch(self): - # hide the single_result param of the _fetch method from the library user - # since it's only useful internally - return self._fetch() - - def _fetch(self, single_result=False): - # URL: /1/classes// - # HTTP Verb: GET - - if self._object_id: - uri = '/%s/%s' % (self._class_name, self._object_id) - else: - options = dict(self._options) # make a local copy - if self._where: - # JSON encode WHERE values - where = json.dumps(self._where) - options.update({'where': where}) - - uri = '/%s?%s' % (self._class_name, urllib.urlencode(options)) - - response_dict = self._executeCall(uri, 'GET') - - if single_result: - return ParseObject(self._class_name, response_dict) - else: - return [ParseObject(self._class_name, result) for result in response_dict['results']] + def __init__(self, class_name): + self._class_name = class_name + self._where = collections.defaultdict(dict) + self._options = {} + self._object_id = '' + + def eq(self, name, value): + self._where[name] = value + return self + + # It's tempting to generate the comparison functions programatically, + # but probably not worth the decrease in readability of the code. + def lt(self, name, value): + self._where[name]['$lt'] = value + return self + + def lte(self, name, value): + self._where[name]['$lte'] = value + return self + + def gt(self, name, value): + self._where[name]['$gt'] = value + return self + + def gte(self, name, value): + self._where[name]['$gte'] = value + return self + + def ne(self, name, value): + self._where[name]['$ne'] = value + return self + + def order(self, order, decending=False): + # add a minus sign before the order value if decending == True + self._options['order'] = decending and ('-' + order) or order + return self + + def limit(self, limit): + self._options['limit'] = limit + return self + + def skip(self, skip): + self._options['skip'] = skip + return self + + def get(self, object_id): + self._object_id = object_id + return self._fetch(single_result=True) + + def fetch(self): + # hide the single_result param of the _fetch method from the library user + # since it's only useful internally + return self._fetch() + + def _fetch(self, single_result=False): + # URL: /1/classes// + # HTTP Verb: GET + + if self._object_id: + uri = '/%s/%s' % (self._class_name, self._object_id) + else: + options = dict(self._options) # make a local copy + if self._where: + # JSON encode WHERE values + where = json.dumps(self._where) + options.update({'where': where}) + + uri = '/%s?%s' % (self._class_name, urllib.urlencode(options)) + + response_dict = self._executeCall(uri, 'GET') + + if single_result: + return ParseObject(self._class_name, response_dict) + else: + return [ParseObject(self._class_name, result) for result in response_dict['results']] From b2d2d121f4632d30bfdcfdc65e469938c558bfc6 Mon Sep 17 00:00:00 2001 From: Vladimir Vinogradov Date: Fri, 3 Jan 2014 23:43:46 +0400 Subject: [PATCH 3/3] if specified, use REST API key for login too --- __init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index 4ace687..fd44ee6 100644 --- a/__init__.py +++ b/__init__.py @@ -34,7 +34,10 @@ def login(username, password): request = urllib2.Request(API_ROOT + '/login?username=' + username + "&" + "password=" + password) request.add_header('X-Parse-Application-Id', APPLICATION_ID) - request.add_header('X-Parse-Master-Key', MASTER_KEY) + if REST_API_KEY: + request.add_header('X-Parse-REST-API-Key', REST_API_KEY) + elif MASTER_KEY: + request.add_header('X-Parse-Master-Key', MASTER_KEY) response = urllib2.urlopen(request) response_body = response.read()