Fixed issue with unicode keyword arguments bug in earlier Python versions (see http://bugs.python.org/issue2646). Closes #250

This commit is contained in:
Pablo Hoffman 2010-09-25 21:17:36 -03:00
parent b11e11037f
commit 1ef2cd400c
4 changed files with 50 additions and 1 deletions

View File

@ -3,6 +3,7 @@ from twisted.internet import defer
from scrapy.http import Request
from scrapy.utils.misc import arg_to_iter
from scrapy.utils.spider import create_spider_for_request
from scrapy.utils.python import stringify_dict
from scrapy import log
@ -23,6 +24,7 @@ class ExecutionQueue(object):
msg = self._queue.pop()
if msg:
name = msg.pop('name')
msg = stringify_dict(msg) # see #250
self.append_spider_name(name, **msg)
def get_next(self):

View File

@ -100,6 +100,17 @@ class ExecutionQueueTest(unittest.TestCase):
self.assert_(spider.name == 'test123')
self.assert_(spider.arg == '123')
def test_append_next(self):
# the reason for this test: http://dev.scrapy.org/ticket/250
class MockQueue(object):
def pop(self):
return {u'name': u'test123', u'test': u'hello'}
self.queue._queue = MockQueue()
self.queue._append_next()
spider = self.queue.spider_requests[0][0]
self.assert_(spider.name == 'test123')
self.assert_(spider.test == 'hello')
def _assert_request_urls(self, requests, urls):
assert all(isinstance(x, Request) for x in requests)
self.assertEqual([x.url for x in requests], urls)

View File

@ -4,7 +4,7 @@ from itertools import count
from scrapy.utils.python import str_to_unicode, unicode_to_str, \
memoizemethod_noargs, isbinarytext, equal_attributes, \
WeakKeyCache
WeakKeyCache, stringify_dict
class UtilsPythonTestCase(unittest.TestCase):
def test_str_to_unicode(self):
@ -122,7 +122,29 @@ class UtilsPythonTestCase(unittest.TestCase):
del k
self.assertFalse(len(wk._weakdict))
def test_stringify_dict(self):
d = {'a': 123, u'b': 'c', u'd': u'e', object(): u'e'}
d2 = stringify_dict(d, keys_only=False)
self.failUnlessEqual(d, d2)
self.failIf(d is d2) # shouldn't modify in place
self.failIf(any(isinstance(x, unicode) for x in d2.keys()))
self.failIf(any(isinstance(x, unicode) for x in d2.values()))
def test_stringify_dict_tuples(self):
tuples = [('a', 123), (u'b', 'c'), (u'd', u'e'), (object(), u'e')]
d = dict(tuples)
d2 = stringify_dict(tuples, keys_only=False)
self.failUnlessEqual(d, d2)
self.failIf(d is d2) # shouldn't modify in place
self.failIf(any(isinstance(x, unicode) for x in d2.keys()), d2.keys())
self.failIf(any(isinstance(x, unicode) for x in d2.values()))
def test_stringify_dict_keys_only(self):
d = {'a': 123, u'b': 'c', u'd': u'e', object(): u'e'}
d2 = stringify_dict(d)
self.failUnlessEqual(d, d2)
self.failIf(d is d2) # shouldn't modify in place
self.failIf(any(isinstance(x, unicode) for x in d2.keys()))
if __name__ == "__main__":
unittest.main()

View File

@ -191,3 +191,17 @@ class WeakKeyCache(object):
if key not in self._weakdict:
self._weakdict[key] = self.default_factory(key)
return self._weakdict[key]
def stringify_dict(dct_or_tuples, encoding='utf-8', keys_only=True):
"""Return a (new) dict with the unicode keys (and values if, keys_only is
False) of the given dict converted to strings. `dct_or_tuples` can be a
dict or a list of tuples, like any dict constructor supports.
"""
d = {}
for k, v in dict(dct_or_tuples).iteritems():
k = k.encode(encoding) if isinstance(k, unicode) else k
if not keys_only:
v = v.encode(encoding) if isinstance(v, unicode) else v
d[k] = v
return d