import warnings
import urllib
import urllib2
-import md5
+import hashlib
+import time
_use_simplejson = False
try:
def dataReceived(self, state, datum):
if state not in self.states:
- raise RTMError, "Invalid state <%s>" % state
+ raise RTMError("Invalid state <%s>" % state)
self.data[state] = datum
def get(self, state):
def _sign(self, params):
"Sign the parameters with MD5 hash"
pairs = ''.join(['%s%s' % (k, v) for (k, v) in sortedItems(params)])
- return md5.md5(self._secret+pairs).hexdigest()
+ return hashlib.md5(self._secret+pairs).hexdigest()
@staticmethod
def open_url(url, queryArgs=None):
warnings.warn("Performing download of %s" % url, stacklevel=5)
return urllib2.urlopen(url)
+ @staticmethod
+ def read_by_length(connection, timeout):
+ # It appears that urllib uses the non-blocking variant of file objects
+ # which means reads might not always be complete, so grabbing as much
+ # of the data as possible with a sleep in between to give it more time
+ # to grab data.
+ contentLengthField = "Content-Length"
+ assert contentLengthField in connection.info(), "Connection didn't provide content length info"
+ specifiedLength = int(connection.info()["Content-Length"])
+
+ actuallyRead = 0
+ chunks = []
+
+ chunk = connection.read()
+ actuallyRead += len(chunk)
+ chunks.append(chunk)
+ while 0 < timeout and actuallyRead < specifiedLength:
+ time.sleep(1)
+ timeout -= 1
+ chunk = connection.read()
+ actuallyRead += len(chunk)
+ chunks.append(chunk)
+
+ json = "".join(chunks)
+
+ if "Content-Length" in connection.info():
+ assert len(json) == int(connection.info()["Content-Length"]), "The packet header promised %s of data but only was able to read %s of data" % (
+ connection.info()["Content-Length"],
+ len(json),
+ )
+
+ return json
+
+ @staticmethod
+ def read_by_guess(connection, timeout):
+ # It appears that urllib uses the non-blocking variant of file objects
+ # which means reads might not always be complete, so grabbing as much
+ # of the data as possible with a sleep in between to give it more time
+ # to grab data.
+
+ chunks = []
+
+ chunk = connection.read()
+ chunks.append(chunk)
+ while chunk and 0 < timeout:
+ time.sleep(1)
+ timeout -= 1
+ chunk = connection.read()
+ chunks.append(chunk)
+
+ json = "".join(chunks)
+
+ if "Content-Length" in connection.info():
+ assert len(json) == int(connection.info()["Content-Length"]), "The packet header promised %s of data but only was able to read %s of data" % (
+ connection.info()["Content-Length"],
+ len(json),
+ )
+
+ return json
+
def get(self, **params):
"Get the XML response for the passed `params`."
params['api_key'] = self._apiKey
params['api_sig'] = self._sign(params)
connection = self.open_url(SERVICE_URL, params)
- json = connection.read()
+ json = self.read_by_guess(connection, 5)
+ # json = self.read_by_length(connection, 5)
+
data = DottedDict('ROOT', parse_json(json))
rsp = data.rsp
if rsp.stat == 'fail':
- raise RTMAPIError, 'API call failed - %s (%s)' % (
- rsp.err.msg, rsp.err.code)
+ raise RTMAPIError(
+ 'API call failed - %s (%s)' % (
+ rsp.err.msg,
+ rsp.err.code,
+ )
+ )
else:
return rsp
def __getattr__(self, attr):
if attr not in self._methods:
- raise AttributeError, 'No such attribute: %s' % attr
+ raise AttributeError('No such attribute: %s' % attr)
rargs, oargs = self._methods[attr]
if self._prefix == 'tasksNotes':
# Sanity checks
for requiredArg in rargs:
if requiredArg not in params:
- raise TypeError, 'Required parameter (%s) missing' % requiredArg
+ raise TypeError('Required parameter (%s) missing' % requiredArg)
for param in params:
if param not in rargs + oargs: