Commit c6106771 by Roman Krejcik

Python3 support

parent cd9ef16a
......@@ -11,18 +11,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
try:
from urllib2 import Request, urlopen, HTTPError
from urllib import urlencode
except ImportError:
# is Python3
from urllib.request import Request, urlopen
from urllib.error import HTTPError
from urllib.parse import urlencode
from six.moves.urllib.request import Request, urlopen
from six.moves.urllib.error import HTTPError
from six.moves.urllib.parse import urlencode
import json
import core
from parse_rest import core
API_ROOT = 'https://api.parse.com/1'
ACCESS_KEYS = {}
......@@ -79,6 +74,8 @@ class ParseBase(object):
if http_verb == 'GET' and data:
url += '?%s' % urlencode(kw)
data = None
else:
data = data.encode('utf-8')
request = Request(url, data, headers)
request.add_header('Content-type', 'application/json')
......@@ -101,7 +98,7 @@ class ParseBase(object):
}.get(e.code, core.ParseError)
raise exc(e.read())
return json.loads(response.read())
return json.loads(response.read().decode('utf-8'))
@classmethod
def GET(cls, uri, **kw):
......
......@@ -10,12 +10,14 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import base64
import datetime
import six
from connection import API_ROOT, ParseBase
from query import QueryManager
from parse_rest.connection import API_ROOT, ParseBase
from parse_rest.query import QueryManager
class ParseType(object):
......@@ -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
objectData = dict(objectData)
# 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:
# 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"]
......@@ -115,7 +117,6 @@ class Pointer(ParseType):
return klass(**objectData)
def __init__(self, obj):
self._object = obj
def _to_native(self):
......@@ -157,7 +158,7 @@ class Date(ParseType):
"""Can be initialized either with a string or a datetime"""
if isinstance(date, datetime.datetime):
self._date = date
elif isinstance(date, unicode):
elif isinstance(date, six.string_types):
self._date = Date._from_str(date)
def _to_native(self):
......@@ -247,7 +248,6 @@ class ParseResource(ParseBase, Pointer):
return dict([(k, v) for k, v in self.__dict__.items() if allowed(k)])
def __init__(self, **kw):
for key, value in kw.items():
setattr(self, key, ParseType.convert_from_parse(value, self.__class__.__name__))
......@@ -324,19 +324,21 @@ class ParseResource(ParseBase, Pointer):
updatedAt = property(_get_updated_datetime, _set_updated_datetime)
def __repr__(self):
return '<%s:%s>' % (unicode(self.__class__.__name__), self.objectId)
return '<%s:%s>' % (self.__class__.__name__, self.objectId)
class ObjectMetaclass(type):
def __new__(cls, name, bases, dct):
cls = super(ObjectMetaclass, cls).__new__(cls, name, bases, dct)
def __new__(mcs, name, bases, dct):
cls = super(ObjectMetaclass, mcs).__new__(mcs, name, bases, dct)
# attr check must be here because of specific six.with_metaclass implemetantion where metaclass is used also for
# 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
class Object(ParseResource):
__metaclass__ = ObjectMetaclass
class Object(six.with_metaclass(ObjectMetaclass, ParseResource)):
ENDPOINT_ROOT = '/'.join([API_ROOT, 'classes'])
@classmethod
......@@ -357,7 +359,8 @@ class Object(ParseResource):
@property
def _absolute_url(self):
if not self.objectId: return None
if not self.objectId:
return None
return '/'.join([self.__class__.ENDPOINT_ROOT, self.objectId])
@property
......
......@@ -11,9 +11,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from connection import API_ROOT
from datatypes import ParseResource
from query import QueryManager
from parse_rest.connection import API_ROOT
from parse_rest.datatypes import ParseResource
from parse_rest.query import QueryManager
class Installation(ParseResource):
......
......@@ -14,11 +14,8 @@
import json
import collections
import copy
import six
try:
unicode = unicode
except NameError:
unicode = str
class QueryResourceDoesNotExist(Exception):
'''Query returned no results'''
......@@ -42,8 +39,7 @@ class QueryManager(object):
def _count(self, **kw):
kw.update({"count": 1, "limit": 0})
return self.model_class.GET(self.model_class.ENDPOINT_ROOT,
**kw).get('count')
return self.model_class.GET(self.model_class.ENDPOINT_ROOT, **kw).get('count')
def all(self):
return Queryset(self)
......@@ -60,8 +56,8 @@ class QueryManager(object):
class QuerysetMetaclass(type):
"""metaclass to add the dynamically generated comparison functions"""
def __new__(cls, name, bases, dct):
cls = super(QuerysetMetaclass, cls).__new__(cls, name, bases, dct)
def __new__(mcs, name, bases, dct):
cls = super(QuerysetMetaclass, mcs).__new__(mcs, name, bases, dct)
for fname in ['limit', 'skip']:
def func(self, value, fname=fname):
......@@ -73,8 +69,7 @@ class QuerysetMetaclass(type):
return cls
class Queryset(object):
__metaclass__ = QuerysetMetaclass
class Queryset(six.with_metaclass(QuerysetMetaclass, object)):
OPERATORS = [
'lt', 'lte', 'gt', 'gte', 'ne', 'in', 'nin', 'exists', 'select', 'dontSelect', 'all', 'relatedTo'
......@@ -82,7 +77,7 @@ class Queryset(object):
@staticmethod
def convert_to_parse(value):
from datatypes import ParseType
from parse_rest.datatypes import ParseType
return ParseType.convert_to_parse(value, as_pointer=True)
@classmethod
......@@ -143,8 +138,7 @@ class Queryset(object):
self._where[attr]['$' + operator] = parse_value
except TypeError:
# self._where[attr] wasn't settable
raise ValueError("Cannot filter for a constraint " +
"after filtering for a specific value")
raise ValueError("Cannot filter for a constraint after filtering for a specific value")
return self
def order_by(self, order, descending=False):
......@@ -171,4 +165,4 @@ class Queryset(object):
return results[0]
def __repr__(self):
return unicode(self._fetch())
return repr(self._fetch())
......@@ -12,10 +12,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from core import ResourceRequestLoginRequired
from connection import API_ROOT
from datatypes import ParseResource, ParseType
from query import QueryManager
from parse_rest.core import ResourceRequestLoginRequired
from parse_rest.connection import API_ROOT
from parse_rest.datatypes import ParseResource, ParseType
from parse_rest.query import QueryManager
def login_required(func):
......
......@@ -27,6 +27,7 @@ setup(
url='https://github.com/dgrtwo/ParsePy',
packages=['parse_rest'],
package_data={"parse_rest": [os.path.join("cloudcode", "*", "*")]},
install_requires=['six'],
maintainer='David Robinson',
maintainer_email='dgrtwo@princeton.edu',
cmdclass={'test': TestCommand},
......@@ -36,6 +37,9 @@ setup(
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'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