Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
ParsePy
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
ParsePy
Commits
c6106771
Commit
c6106771
authored
Jul 17, 2014
by
Roman Krejcik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Python3 support
parent
cd9ef16a
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
114 additions
and
123 deletions
+114
-123
parse_rest/connection.py
+7
-10
parse_rest/datatypes.py
+17
-14
parse_rest/installation.py
+3
-3
parse_rest/query.py
+9
-15
parse_rest/tests.py
+67
-74
parse_rest/user.py
+4
-4
setup.py
+7
-3
No files found.
parse_rest/connection.py
View file @
c6106771
...
@@ -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
):
...
...
parse_rest/datatypes.py
View file @
c6106771
...
@@ -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
...
...
parse_rest/installation.py
View file @
c6106771
...
@@ -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
):
...
...
parse_rest/query.py
View file @
c6106771
...
@@ -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__
(
cl
s
,
name
,
bases
,
dct
):
def
__new__
(
mc
s
,
name
,
bases
,
dct
):
cls
=
super
(
QuerysetMetaclass
,
cls
)
.
__new__
(
cl
s
,
name
,
bases
,
dct
)
cls
=
super
(
QuerysetMetaclass
,
mcs
)
.
__new__
(
mc
s
,
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
())
parse_rest/tests.py
View file @
c6106771
...
@@ -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
.
assert
Equal
(
self
.
score
.
score
,
1337
,
'Could not set score'
)
def
testCanInstantiateParseType
(
self
):
def
testCanInstantiateParseType
(
self
):
self
.
assert
_
(
self
.
sao_paulo
.
location
.
latitude
==
-
23.5
)
self
.
assert
Equal
(
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
.
assert
Equal
(
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
.
assert
IsInstance
(
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
.
assert
Equal
(
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
.
assert
False
(
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
.
assert
True
(
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
.
assert
Equal
(
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
.
assert
True
(
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
.
assert
Equal
(
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
.
assert
IsInstance
(
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
.
assert
IsInstance
(
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
.
assert
Equal
(
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
.
assert
IsInstance
(
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
.
assert
Equal
(
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
.
assert
True
(
GameScore
.
Query
.
filter
(
score
=
s
)
.
exists
(),
"exists giving false negative"
)
"exists giving false negative"
)
self
.
assert
_
(
not
GameScore
.
Query
.
filter
(
score
=
10
)
.
exists
(),
self
.
assert
False
(
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
.
assert
Equal
(
qobj
.
objectId
,
s
.
objectId
,
"Getting object with .filter() failed"
)
"Getting object with .filter() failed"
)
self
.
assert
_
(
qobj
.
score
==
s
.
score
,
self
.
assert
Equal
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
Equal
(
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
.
assert
Equal
(
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
.
assert
False
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
user
is
not
None
)
self
.
assert
_
(
user
.
username
==
self
.
username
)
self
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
True
(
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
.
assert
NotEqual
(
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
):
...
...
parse_rest/user.py
View file @
c6106771
...
@@ -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
):
...
...
setup.py
View file @
c6106771
...
@@ -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"
,
]
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment