Commit c6106771 by Roman Krejcik

Python3 support

parent cd9ef16a
...@@ -11,18 +11,13 @@ ...@@ -11,18 +11,13 @@
# 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/>.
try: from six.moves.urllib.request import Request, urlopen
from urllib2 import Request, urlopen, HTTPError from six.moves.urllib.error import HTTPError
from urllib import urlencode from six.moves.urllib.parse import urlencode
except ImportError:
# is Python3
from urllib.request import Request, urlopen
from urllib.error import HTTPError
from urllib.parse import urlencode
import json import json
import core from parse_rest import core
API_ROOT = 'https://api.parse.com/1' API_ROOT = 'https://api.parse.com/1'
ACCESS_KEYS = {} ACCESS_KEYS = {}
...@@ -79,6 +74,8 @@ class ParseBase(object): ...@@ -79,6 +74,8 @@ class ParseBase(object):
if http_verb == 'GET' and data: if http_verb == 'GET' and data:
url += '?%s' % urlencode(kw) url += '?%s' % urlencode(kw)
data = None data = None
else:
data = data.encode('utf-8')
request = Request(url, data, headers) request = Request(url, data, headers)
request.add_header('Content-type', 'application/json') request.add_header('Content-type', 'application/json')
...@@ -101,7 +98,7 @@ class ParseBase(object): ...@@ -101,7 +98,7 @@ class ParseBase(object):
}.get(e.code, core.ParseError) }.get(e.code, core.ParseError)
raise exc(e.read()) raise exc(e.read())
return json.loads(response.read()) return json.loads(response.read().decode('utf-8'))
@classmethod @classmethod
def GET(cls, uri, **kw): def GET(cls, uri, **kw):
......
...@@ -10,12 +10,14 @@ ...@@ -10,12 +10,14 @@
# #
# 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/>.
from __future__ import unicode_literals
import base64 import base64
import datetime import datetime
import six
from connection import API_ROOT, ParseBase from parse_rest.connection import API_ROOT, ParseBase
from query import QueryManager from parse_rest.query import QueryManager
class ParseType(object): class ParseType(object):
...@@ -94,7 +96,7 @@ class Pointer(ParseType): ...@@ -94,7 +96,7 @@ class Pointer(ParseType):
# also circular refs through more object are now ignored, in fact lazy loaded references will be best solution # also circular refs through more object are now ignored, in fact lazy loaded references will be best solution
objectData = dict(objectData) objectData = dict(objectData)
# now lets see if we have any references to the parent class here # now lets see if we have any references to the parent class here
for key, value in objectData.iteritems(): for key, value in six.iteritems(objectData):
if isinstance(value, dict) and "className" in value and value["className"] == parent_class_name: if isinstance(value, dict) and "className" in value and value["className"] == parent_class_name:
# simply put the reference here as a string -- not sure what the drawbacks are for this but it works for me # simply put the reference here as a string -- not sure what the drawbacks are for this but it works for me
objectData[key] = value["objectId"] objectData[key] = value["objectId"]
...@@ -115,7 +117,6 @@ class Pointer(ParseType): ...@@ -115,7 +117,6 @@ class Pointer(ParseType):
return klass(**objectData) return klass(**objectData)
def __init__(self, obj): def __init__(self, obj):
self._object = obj self._object = obj
def _to_native(self): def _to_native(self):
...@@ -157,7 +158,7 @@ class Date(ParseType): ...@@ -157,7 +158,7 @@ class Date(ParseType):
"""Can be initialized either with a string or a datetime""" """Can be initialized either with a string or a datetime"""
if isinstance(date, datetime.datetime): if isinstance(date, datetime.datetime):
self._date = date self._date = date
elif isinstance(date, unicode): elif isinstance(date, six.string_types):
self._date = Date._from_str(date) self._date = Date._from_str(date)
def _to_native(self): def _to_native(self):
...@@ -247,7 +248,6 @@ class ParseResource(ParseBase, Pointer): ...@@ -247,7 +248,6 @@ class ParseResource(ParseBase, Pointer):
return dict([(k, v) for k, v in self.__dict__.items() if allowed(k)]) return dict([(k, v) for k, v in self.__dict__.items() if allowed(k)])
def __init__(self, **kw): def __init__(self, **kw):
for key, value in kw.items(): for key, value in kw.items():
setattr(self, key, ParseType.convert_from_parse(value, self.__class__.__name__)) setattr(self, key, ParseType.convert_from_parse(value, self.__class__.__name__))
...@@ -324,19 +324,21 @@ class ParseResource(ParseBase, Pointer): ...@@ -324,19 +324,21 @@ class ParseResource(ParseBase, Pointer):
updatedAt = property(_get_updated_datetime, _set_updated_datetime) updatedAt = property(_get_updated_datetime, _set_updated_datetime)
def __repr__(self): def __repr__(self):
return '<%s:%s>' % (unicode(self.__class__.__name__), self.objectId) return '<%s:%s>' % (self.__class__.__name__, self.objectId)
class ObjectMetaclass(type): class ObjectMetaclass(type):
def __new__(cls, name, bases, dct): def __new__(mcs, name, bases, dct):
cls = super(ObjectMetaclass, cls).__new__(cls, name, bases, dct) cls = super(ObjectMetaclass, mcs).__new__(mcs, name, bases, dct)
cls.set_endpoint_root() # attr check must be here because of specific six.with_metaclass implemetantion where metaclass is used also for
cls.Query = QueryManager(cls) # internal NewBase which hasn't set_endpoint_root method
if hasattr(cls, 'set_endpoint_root'):
cls.set_endpoint_root()
cls.Query = QueryManager(cls)
return cls return cls
class Object(ParseResource): class Object(six.with_metaclass(ObjectMetaclass, ParseResource)):
__metaclass__ = ObjectMetaclass
ENDPOINT_ROOT = '/'.join([API_ROOT, 'classes']) ENDPOINT_ROOT = '/'.join([API_ROOT, 'classes'])
@classmethod @classmethod
...@@ -357,7 +359,8 @@ class Object(ParseResource): ...@@ -357,7 +359,8 @@ class Object(ParseResource):
@property @property
def _absolute_url(self): def _absolute_url(self):
if not self.objectId: return None if not self.objectId:
return None
return '/'.join([self.__class__.ENDPOINT_ROOT, self.objectId]) return '/'.join([self.__class__.ENDPOINT_ROOT, self.objectId])
@property @property
......
...@@ -11,9 +11,9 @@ ...@@ -11,9 +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/>.
from connection import API_ROOT from parse_rest.connection import API_ROOT
from datatypes import ParseResource from parse_rest.datatypes import ParseResource
from query import QueryManager from parse_rest.query import QueryManager
class Installation(ParseResource): class Installation(ParseResource):
......
...@@ -14,11 +14,8 @@ ...@@ -14,11 +14,8 @@
import json import json
import collections import collections
import copy import copy
import six
try:
unicode = unicode
except NameError:
unicode = str
class QueryResourceDoesNotExist(Exception): class QueryResourceDoesNotExist(Exception):
'''Query returned no results''' '''Query returned no results'''
...@@ -42,8 +39,7 @@ class QueryManager(object): ...@@ -42,8 +39,7 @@ class QueryManager(object):
def _count(self, **kw): def _count(self, **kw):
kw.update({"count": 1, "limit": 0}) kw.update({"count": 1, "limit": 0})
return self.model_class.GET(self.model_class.ENDPOINT_ROOT, return self.model_class.GET(self.model_class.ENDPOINT_ROOT, **kw).get('count')
**kw).get('count')
def all(self): def all(self):
return Queryset(self) return Queryset(self)
...@@ -60,8 +56,8 @@ class QueryManager(object): ...@@ -60,8 +56,8 @@ class QueryManager(object):
class QuerysetMetaclass(type): class QuerysetMetaclass(type):
"""metaclass to add the dynamically generated comparison functions""" """metaclass to add the dynamically generated comparison functions"""
def __new__(cls, name, bases, dct): def __new__(mcs, name, bases, dct):
cls = super(QuerysetMetaclass, cls).__new__(cls, name, bases, dct) cls = super(QuerysetMetaclass, mcs).__new__(mcs, name, bases, dct)
for fname in ['limit', 'skip']: for fname in ['limit', 'skip']:
def func(self, value, fname=fname): def func(self, value, fname=fname):
...@@ -73,16 +69,15 @@ class QuerysetMetaclass(type): ...@@ -73,16 +69,15 @@ class QuerysetMetaclass(type):
return cls return cls
class Queryset(object): class Queryset(six.with_metaclass(QuerysetMetaclass, object)):
__metaclass__ = QuerysetMetaclass
OPERATORS = [ OPERATORS = [
'lt', 'lte', 'gt', 'gte', 'ne', 'in', 'nin', 'exists', 'select', 'dontSelect', 'all', 'relatedTo' 'lt', 'lte', 'gt', 'gte', 'ne', 'in', 'nin', 'exists', 'select', 'dontSelect', 'all', 'relatedTo'
] ]
@staticmethod @staticmethod
def convert_to_parse(value): def convert_to_parse(value):
from datatypes import ParseType from parse_rest.datatypes import ParseType
return ParseType.convert_to_parse(value, as_pointer=True) return ParseType.convert_to_parse(value, as_pointer=True)
@classmethod @classmethod
...@@ -143,8 +138,7 @@ class Queryset(object): ...@@ -143,8 +138,7 @@ class Queryset(object):
self._where[attr]['$' + operator] = parse_value self._where[attr]['$' + operator] = parse_value
except TypeError: except TypeError:
# self._where[attr] wasn't settable # self._where[attr] wasn't settable
raise ValueError("Cannot filter for a constraint " + raise ValueError("Cannot filter for a constraint after filtering for a specific value")
"after filtering for a specific value")
return self return self
def order_by(self, order, descending=False): def order_by(self, order, descending=False):
...@@ -171,4 +165,4 @@ class Queryset(object): ...@@ -171,4 +165,4 @@ class Queryset(object):
return results[0] return results[0]
def __repr__(self): def __repr__(self):
return unicode(self._fetch()) return repr(self._fetch())
...@@ -4,20 +4,21 @@ ...@@ -4,20 +4,21 @@
""" """
Contains unit tests for the Python Parse REST API wrapper Contains unit tests for the Python Parse REST API wrapper
""" """
from __future__ import print_function
import os import os
import sys import sys
import subprocess import subprocess
import unittest import unittest
import datetime import datetime
import six
from parse_rest.core import ResourceRequestNotFound
from core import ResourceRequestNotFound from parse_rest.connection import register, ParseBatcher
from connection import register, ParseBatcher from parse_rest.datatypes import GeoPoint, Object, Function
from datatypes import GeoPoint, Object, Function from parse_rest.user import User
from user import User from parse_rest import query
import query from parse_rest.installation import Push
from installation import Push
try: try:
import settings_local import settings_local
...@@ -25,17 +26,12 @@ except ImportError: ...@@ -25,17 +26,12 @@ 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')
try:
unicode = unicode
except NameError:
# is python3
unicode = str
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')
) )
GLOBAL_JSON_TEXT = """{ GLOBAL_JSON_TEXT = """{
"applications": { "applications": {
...@@ -95,48 +91,47 @@ class TestObject(unittest.TestCase): ...@@ -95,48 +91,47 @@ class TestObject(unittest.TestCase):
score.delete() score.delete()
def testCanInitialize(self): def testCanInitialize(self):
self.assert_(self.score.score == 1337, 'Could not set score') self.assertEqual(self.score.score, 1337, 'Could not set score')
def testCanInstantiateParseType(self): def testCanInstantiateParseType(self):
self.assert_(self.sao_paulo.location.latitude == -23.5) self.assertEqual(self.sao_paulo.location.latitude, -23.5)
def testCanSaveDates(self): def testCanSaveDates(self):
now = datetime.datetime.now() now = datetime.datetime.now()
self.score.last_played = now self.score.last_played = now
self.score.save() self.score.save()
self.assert_(self.score.last_played == now, 'Could not save date') self.assertEqual(self.score.last_played, now, 'Could not save date')
def testCanCreateNewObject(self): def testCanCreateNewObject(self):
self.score.save() self.score.save()
object_id = self.score.objectId object_id = self.score.objectId
self.assert_(object_id is not None, 'Can not create object') self.assertIsNotNone(object_id, 'Can not create object')
self.assert_(type(object_id) == unicode) self.assertIsInstance(object_id, six.string_types)
self.assert_(type(self.score.createdAt) == datetime.datetime) self.assertIsInstance(self.score.createdAt, datetime.datetime)
self.assert_(GameScore.Query.filter(objectId=object_id).exists(), self.assertTrue(GameScore.Query.filter(objectId=object_id).exists(), 'Can not create object')
'Can not create object')
def testCanUpdateExistingObject(self): def testCanUpdateExistingObject(self):
self.sao_paulo.save() self.sao_paulo.save()
self.sao_paulo.country = 'Brazil' self.sao_paulo.country = 'Brazil'
self.sao_paulo.save() self.sao_paulo.save()
self.assert_(type(self.sao_paulo.updatedAt) == datetime.datetime) self.assertIsInstance(self.sao_paulo.updatedAt, datetime.datetime)
city = City.Query.get(name='São Paulo') city = City.Query.get(name='São Paulo')
self.assert_(city.country == 'Brazil', 'Could not update object') self.assertEqual(city.country, 'Brazil', 'Could not update object')
def testCanDeleteExistingObject(self): def testCanDeleteExistingObject(self):
self.score.save() self.score.save()
object_id = self.score.objectId object_id = self.score.objectId
self.score.delete() self.score.delete()
self.assert_(not GameScore.Query.filter(objectId=object_id).exists(), self.assertFalse(GameScore.Query.filter(objectId=object_id).exists(),
'Failed to delete object %s on Parse ' % self.score) 'Failed to delete object %s on Parse ' % self.score)
def testCanIncrementField(self): def testCanIncrementField(self):
previous_score = self.score.score previous_score = self.score.score
self.score.save() self.score.save()
self.score.increment('score') self.score.increment('score')
self.assert_(GameScore.Query.filter(score=previous_score + 1).exists(), self.assertTrue(GameScore.Query.filter(score=previous_score + 1).exists(),
'Failed to increment score on backend') 'Failed to increment score on backend')
def testAssociatedObject(self): def testAssociatedObject(self):
...@@ -149,10 +144,8 @@ class TestObject(unittest.TestCase): ...@@ -149,10 +144,8 @@ class TestObject(unittest.TestCase):
# get the object, see if it has saved # get the object, see if it has saved
qs = GameScore.Query.get(objectId=self.score.objectId) qs = GameScore.Query.get(objectId=self.score.objectId)
self.assert_(isinstance(qs.item, Object), self.assertIsInstance(qs.item, Object, "Associated CollectedItem is not an object")
"Associated CollectedItem is not an object") self.assertEqual(qs.item.type, "Sword", "Associated CollectedItem does not have correct attributes")
self.assert_(qs.item.type == "Sword",
"Associated CollectedItem does not have correct attributes")
def testBatch(self): def testBatch(self):
"""test saving, updating and deleting objects in batches""" """test saving, updating and deleting objects in batches"""
...@@ -160,9 +153,9 @@ class TestObject(unittest.TestCase): ...@@ -160,9 +153,9 @@ class TestObject(unittest.TestCase):
for s in range(5)] for s in range(5)]
batcher = ParseBatcher() batcher = ParseBatcher()
batcher.batch_save(scores) batcher.batch_save(scores)
self.assert_(GameScore.Query.filter(player_name='Jane').count() == 5, self.assertEqual(GameScore.Query.filter(player_name='Jane').count(), 5,
"batch_save didn't create objects") "batch_save didn't create objects")
self.assert_(all(s.objectId is not None for s in scores), self.assertTrue(all(s.objectId is not None for s in scores),
"batch_save didn't record object IDs") "batch_save didn't record object IDs")
# test updating # test updating
...@@ -172,11 +165,11 @@ class TestObject(unittest.TestCase): ...@@ -172,11 +165,11 @@ class TestObject(unittest.TestCase):
updated_scores = GameScore.Query.filter(player_name='Jane') updated_scores = GameScore.Query.filter(player_name='Jane')
self.assertEqual(sorted([s.score for s in updated_scores]), self.assertEqual(sorted([s.score for s in updated_scores]),
range(10, 15), msg="batch_save didn't update objects") list(range(10, 15)), msg="batch_save didn't update objects")
# test deletion # test deletion
batcher.batch_delete(scores) batcher.batch_delete(scores)
self.assert_(GameScore.Query.filter(player_name='Jane').count() == 0, self.assertEqual(GameScore.Query.filter(player_name='Jane').count(), 0,
"batch_delete didn't delete objects") "batch_delete didn't delete objects")
...@@ -186,31 +179,31 @@ class TestTypes(unittest.TestCase): ...@@ -186,31 +179,31 @@ class TestTypes(unittest.TestCase):
self.score = GameScore( self.score = GameScore(
score=1337, player_name='John Doe', cheat_mode=False, score=1337, player_name='John Doe', cheat_mode=False,
date_of_birth=self.now date_of_birth=self.now
) )
self.sao_paulo = City( self.sao_paulo = City(
name='São Paulo', location=GeoPoint(-23.5, -46.6167) name='São Paulo', location=GeoPoint(-23.5, -46.6167)
) )
def testCanConvertToNative(self): def testCanConvertToNative(self):
native_data = self.sao_paulo._to_native() native_data = self.sao_paulo._to_native()
self.assert_(type(native_data) is dict, 'Can not convert object to dict') self.assertIsInstance(native_data, dict, 'Can not convert object to dict')
def testCanConvertNestedLocation(self): def testCanConvertNestedLocation(self):
native_sao_paulo = self.sao_paulo._to_native() native_sao_paulo = self.sao_paulo._to_native()
location_dict = native_sao_paulo.get('location') location_dict = native_sao_paulo.get('location')
self.assert_(type(location_dict) is dict, self.assertIsInstance(location_dict, dict,
'Expected dict after conversion. Got %s' % location_dict) 'Expected dict after conversion. Got %s' % location_dict)
self.assert_(location_dict.get('latitude') == -23.5, self.assertEqual(location_dict.get('latitude'), -23.5,
'Can not serialize geopoint data') 'Can not serialize geopoint data')
def testCanConvertDate(self): def testCanConvertDate(self):
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.assertIsInstance(native_date, dict,
'Could not serialize date into dict') 'Could not serialize date into dict')
iso_date = native_date.get('iso') iso_date = native_date.get('iso')
now = '{0}Z'.format(self.now.isoformat()[:-3]) now = '{0}Z'.format(self.now.isoformat()[:-3])
self.assert_(iso_date == now, 'Expected %s. Got %s' % (now, iso_date)) self.assertEqual(iso_date, now, 'Expected %s. Got %s' % (now, iso_date))
class TestQuery(unittest.TestCase): class TestQuery(unittest.TestCase):
...@@ -235,23 +228,23 @@ class TestQuery(unittest.TestCase): ...@@ -235,23 +228,23 @@ class TestQuery(unittest.TestCase):
def testExists(self): def testExists(self):
"""test the Queryset.exists() method""" """test the Queryset.exists() method"""
for s in range(1, 6): for s in range(1, 6):
self.assert_(GameScore.Query.filter(score=s).exists(), self.assertTrue(GameScore.Query.filter(score=s).exists(),
"exists giving false negative") "exists giving false negative")
self.assert_(not GameScore.Query.filter(score=10).exists(), self.assertFalse(GameScore.Query.filter(score=10).exists(),
"exists giving false positive") "exists giving false positive")
def testCanFilter(self): def testCanFilter(self):
'''test the Queryset.filter() method''' '''test the Queryset.filter() method'''
for s in self.scores: for s in self.scores:
qobj = GameScore.Query.filter(objectId=s.objectId).get() qobj = GameScore.Query.filter(objectId=s.objectId).get()
self.assert_(qobj.objectId == s.objectId, self.assertEqual(qobj.objectId, s.objectId,
"Getting object with .filter() failed") "Getting object with .filter() failed")
self.assert_(qobj.score == s.score, self.assertEqual(qobj.score, s.score,
"Getting object with .filter() failed") "Getting object with .filter() failed")
# test relational query with other Objects # test relational query with other Objects
num_scores = GameScore.Query.filter(game=self.game).count() num_scores = GameScore.Query.filter(game=self.game).count()
self.assert_(num_scores == len(self.scores), self.assertTrue(num_scores == len(self.scores),
"Relational query with .filter() failed") "Relational query with .filter() failed")
def testGetExceptions(self): def testGetExceptions(self):
...@@ -265,37 +258,37 @@ class TestQuery(unittest.TestCase): ...@@ -265,37 +258,37 @@ class TestQuery(unittest.TestCase):
last_week = datetime.datetime.now() - datetime.timedelta(days=7) last_week = datetime.datetime.now() - datetime.timedelta(days=7)
score = GameScore(name='test', last_played=last_week) score = GameScore(name='test', last_played=last_week)
score.save() score.save()
self.assert_(GameScore.Query.filter(last_played=last_week).exists(), self.assertTrue(GameScore.Query.filter(last_played=last_week).exists(),
'Could not run query with dates') 'Could not run query with dates')
def testComparisons(self): def testComparisons(self):
"""test comparison operators- gt, gte, lt, lte, ne""" """test comparison operators- gt, gte, lt, lte, ne"""
scores_gt_3 = list(GameScore.Query.filter(score__gt=3)) scores_gt_3 = list(GameScore.Query.filter(score__gt=3))
self.assertEqual(len(scores_gt_3), 2) self.assertEqual(len(scores_gt_3), 2)
self.assert_(all([s.score > 3 for s in scores_gt_3])) self.assertTrue(all([s.score > 3 for s in scores_gt_3]))
scores_gte_3 = list(GameScore.Query.filter(score__gte=3)) scores_gte_3 = list(GameScore.Query.filter(score__gte=3))
self.assertEqual(len(scores_gte_3), 3) self.assertEqual(len(scores_gte_3), 3)
self.assert_(all([s.score >= 3 for s in scores_gt_3])) self.assertTrue(all([s.score >= 3 for s in scores_gt_3]))
scores_lt_4 = list(GameScore.Query.filter(score__lt=4)) scores_lt_4 = list(GameScore.Query.filter(score__lt=4))
self.assertEqual(len(scores_lt_4), 3) self.assertEqual(len(scores_lt_4), 3)
self.assert_(all([s.score < 4 for s in scores_lt_4])) self.assertTrue(all([s.score < 4 for s in scores_lt_4]))
scores_lte_4 = list(GameScore.Query.filter(score__lte=4)) scores_lte_4 = list(GameScore.Query.filter(score__lte=4))
self.assertEqual(len(scores_lte_4), 4) self.assertEqual(len(scores_lte_4), 4)
self.assert_(all([s.score <= 4 for s in scores_lte_4])) self.assertTrue(all([s.score <= 4 for s in scores_lte_4]))
scores_ne_2 = list(GameScore.Query.filter(score__ne=2)) scores_ne_2 = list(GameScore.Query.filter(score__ne=2))
self.assertEqual(len(scores_ne_2), 4) self.assertEqual(len(scores_ne_2), 4)
self.assert_(all([s.score != 2 for s in scores_ne_2])) self.assertTrue(all([s.score != 2 for s in scores_ne_2]))
# test chaining # test chaining
lt_4_gt_2 = list(GameScore.Query.filter(score__lt=4).filter(score__gt=2)) lt_4_gt_2 = list(GameScore.Query.filter(score__lt=4).filter(score__gt=2))
self.assert_(len(lt_4_gt_2) == 1, 'chained lt+gt not working') self.assertEqual(len(lt_4_gt_2), 1, 'chained lt+gt not working')
self.assert_(lt_4_gt_2[0].score == 3, 'chained lt+gt not working') self.assertEqual(lt_4_gt_2[0].score, 3, 'chained lt+gt not working')
q = GameScore.Query.filter(score__gt=3, score__lt=3) q = GameScore.Query.filter(score__gt=3, score__lt=3)
self.assert_(not q.exists(), "chained lt+gt not working") self.assertFalse(q.exists(), "chained lt+gt not working")
def testOptions(self): def testOptions(self):
"""test three options- order, limit, and skip""" """test three options- order, limit, and skip"""
...@@ -308,15 +301,15 @@ class TestQuery(unittest.TestCase): ...@@ -308,15 +301,15 @@ class TestQuery(unittest.TestCase):
[5, 4, 3, 2, 1]) [5, 4, 3, 2, 1])
scores_limit_3 = list(GameScore.Query.all().limit(3)) scores_limit_3 = list(GameScore.Query.all().limit(3))
self.assert_(len(scores_limit_3) == 3, "Limit did not return 3 items") self.assertTrue(len(scores_limit_3) == 3, "Limit did not return 3 items")
scores_skip_3 = list(GameScore.Query.all().skip(3)) scores_skip_3 = list(GameScore.Query.all().skip(3))
self.assert_(len(scores_skip_3) == 2, "Skip did not return 2 items") self.assertTrue(len(scores_skip_3) == 2, "Skip did not return 2 items")
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)
self.assert_(GameScore.Query.filter(createdAt__lte=tomorrow).count() == 5, self.assertTrue(GameScore.Query.filter(createdAt__lte=tomorrow).count() == 5,
'Could not make inequality comparison with dates') 'Could not make inequality comparison with dates')
def tearDown(self): def tearDown(self):
...@@ -407,13 +400,13 @@ class TestUser(unittest.TestCase): ...@@ -407,13 +400,13 @@ class TestUser(unittest.TestCase):
def testCanSignUp(self): def testCanSignUp(self):
self._destroy_user() self._destroy_user()
user = User.signup(self.username, self.password) user = User.signup(self.username, self.password)
self.assert_(user is not None) self.assertTrue(user is not None)
self.assert_(user.username == self.username) self.assertTrue(user.username == self.username)
def testCanLogin(self): def testCanLogin(self):
self._get_user() # User should be created here. self._get_user() # User should be created here.
user = User.login(self.username, self.password) user = User.login(self.username, self.password)
self.assert_(user.is_authenticated(), 'Login failed') self.assertTrue(user.is_authenticated(), 'Login failed')
def testCanUpdate(self): def testCanUpdate(self):
user = self._get_logged_user() user = self._get_logged_user()
...@@ -423,7 +416,7 @@ class TestUser(unittest.TestCase): ...@@ -423,7 +416,7 @@ class TestUser(unittest.TestCase):
user.phone = phone_number user.phone = phone_number
user.save() user.save()
self.assert_(User.Query.filter(phone=phone_number).exists(), self.assertTrue(User.Query.filter(phone=phone_number).exists(),
'Failed to update user data. New info not on Parse') 'Failed to update user data. New info not on Parse')
def testCanBatchUpdate(self): def testCanBatchUpdate(self):
...@@ -436,10 +429,10 @@ class TestUser(unittest.TestCase): ...@@ -436,10 +429,10 @@ class TestUser(unittest.TestCase):
batcher = ParseBatcher() batcher = ParseBatcher()
batcher.batch_save([user]) batcher.batch_save([user])
self.assert_(User.Query.filter(phone=phone_number).exists(), self.assertTrue(User.Query.filter(phone=phone_number).exists(),
'Failed to batch update user data. New info not on Parse') 'Failed to batch update user data. New info not on Parse')
self.assert_(user.updatedAt != original_updatedAt, self.assertNotEqual(user.updatedAt, original_updatedAt,
'Failed to batch update user data: updatedAt not changed') 'Failed to batch update user data: updatedAt not changed')
class TestPush(unittest.TestCase): class TestPush(unittest.TestCase):
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from core import ResourceRequestLoginRequired from parse_rest.core import ResourceRequestLoginRequired
from connection import API_ROOT from parse_rest.connection import API_ROOT
from datatypes import ParseResource, ParseType from parse_rest.datatypes import ParseResource, ParseType
from query import QueryManager from parse_rest.query import QueryManager
def login_required(func): def login_required(func):
......
...@@ -27,6 +27,7 @@ setup( ...@@ -27,6 +27,7 @@ setup(
url='https://github.com/dgrtwo/ParsePy', url='https://github.com/dgrtwo/ParsePy',
packages=['parse_rest'], packages=['parse_rest'],
package_data={"parse_rest": [os.path.join("cloudcode", "*", "*")]}, package_data={"parse_rest": [os.path.join("cloudcode", "*", "*")]},
install_requires=['six'],
maintainer='David Robinson', maintainer='David Robinson',
maintainer_email='dgrtwo@princeton.edu', maintainer_email='dgrtwo@princeton.edu',
cmdclass={'test': TestCommand}, cmdclass={'test': TestCommand},
...@@ -36,6 +37,9 @@ setup( ...@@ -36,6 +37,9 @@ setup(
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
'Programming Language :: Python' "Programming Language :: Python :: 2.6",
] "Programming Language :: Python :: 2.7",
) "Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
]
)
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