diff --git a/scrapy/http/request/form.py b/scrapy/http/request/form.py index 55e5ea1fa..e7a654ab9 100644 --- a/scrapy/http/request/form.py +++ b/scrapy/http/request/form.py @@ -22,6 +22,8 @@ def _unicode_to_str(string, encoding): class FormRequest(Request): + __slots__ = () + def __init__(self, *args, **kwargs): formdata = kwargs.pop('formdata', None) Request.__init__(self, *args, **kwargs) diff --git a/scrapy/http/response/html.py b/scrapy/http/response/html.py index 013e0805b..66e9124b5 100644 --- a/scrapy/http/response/html.py +++ b/scrapy/http/response/html.py @@ -12,6 +12,8 @@ from scrapy.utils.python import memoizemethod class HtmlResponse(TextResponse): + __slots__ = () + _template = r'''%s\s*=\s*["']?\s*%s\s*["']?''' _httpequiv_re = _template % ('http-equiv', 'Content-Type') diff --git a/scrapy/http/response/xml.py b/scrapy/http/response/xml.py index d14aaa80f..760ad33b9 100644 --- a/scrapy/http/response/xml.py +++ b/scrapy/http/response/xml.py @@ -12,6 +12,8 @@ from scrapy.utils.python import memoizemethod class XmlResponse(TextResponse): + __slots__ = () + _template = r'''%s\s*=\s*["']?\s*%s\s*["']?''' _encoding_re = _template % ('encoding', r'(?P[\w-]+)') XMLDECL_RE = re.compile(r'<\?xml\s.*?%s' % _encoding_re, re.I) diff --git a/scrapy/link.py b/scrapy/link.py index 1844da1da..657fa541b 100644 --- a/scrapy/link.py +++ b/scrapy/link.py @@ -10,7 +10,7 @@ class Link(object): At the moment, it contains just the url and link text. """ - __slots__ = 'url', 'text' + __slots__ = ['url', 'text'] def __init__(self, url, text=''): self.url = url diff --git a/scrapy/tests/test_http_headers.py b/scrapy/tests/test_http_headers.py index 3d4136c09..871a987ca 100644 --- a/scrapy/tests/test_http_headers.py +++ b/scrapy/tests/test_http_headers.py @@ -1,4 +1,5 @@ import unittest +import weakref import copy from scrapy.http import Headers @@ -103,3 +104,8 @@ class HeadersTest(unittest.TestCase): self.assertEqual(h1.getlist('header1'), ['value1']) self.assertEqual(h1.getlist('header2'), ['value2', 'value3']) + def test_slots(self): + """Check that classes are using slots and are weak-referenceable""" + x = Headers({}) + assert not hasattr(x, '__dict__'), "%s does not use __slots__" % \ + x.__class__.__name__ diff --git a/scrapy/tests/test_http_request.py b/scrapy/tests/test_http_request.py index ac6ee18dc..ecf94100a 100644 --- a/scrapy/tests/test_http_request.py +++ b/scrapy/tests/test_http_request.py @@ -1,5 +1,6 @@ import unittest import cgi +import weakref from cStringIO import StringIO from urlparse import urlparse @@ -166,6 +167,14 @@ class RequestTest(unittest.TestCase): self.assertEqual(r4.meta, {}) assert r4.dont_filter is False + def test_weakref_slots(self): + """Check that classes are using slots and are weak-referenceable""" + for cls in [Request, FormRequest]: + x = cls('http://www.example.com') + weakref.ref(x) + assert not hasattr(x, '__dict__'), "%s does not use __slots__" % \ + x.__class__.__name__ + class FormRequestTest(unittest.TestCase): @@ -299,6 +308,5 @@ class XmlRpcRequestTest(unittest.TestCase): self.assertEqual(r1.body, r2.body) - if __name__ == "__main__": unittest.main() diff --git a/scrapy/tests/test_http_response.py b/scrapy/tests/test_http_response.py index d60d43328..ccf5ae6cc 100644 --- a/scrapy/tests/test_http_response.py +++ b/scrapy/tests/test_http_response.py @@ -1,4 +1,6 @@ import unittest +import weakref + from scrapy.http import Response, TextResponse, HtmlResponse, XmlResponse, Headers class ResponseTest(unittest.TestCase): @@ -201,6 +203,14 @@ class ResponseTest(unittest.TestCase): self._assert_response_values(r5, 'iso-8859-1', body) self._assert_response_values(r6, 'utf-8', body2) + def test_weakref_slots(self): + """Check that classes are using slots and are weak-referenceable""" + for cls in [Response, TextResponse, XmlResponse, HtmlResponse]: + x = cls('http://www.example.com') + weakref.ref(x) + assert not hasattr(x, '__dict__'), "%s does not use __slots__" % \ + x.__class__.__name__ + if __name__ == "__main__": unittest.main() diff --git a/scrapy/tests/test_xpath.py b/scrapy/tests/test_xpath.py index 08032d9b3..582932132 100644 --- a/scrapy/tests/test_xpath.py +++ b/scrapy/tests/test_xpath.py @@ -1,10 +1,12 @@ import re import unittest +import weakref import libxml2 from scrapy.http import TextResponse, HtmlResponse, XmlResponse -from scrapy.xpath.selector import XmlXPathSelector, HtmlXPathSelector +from scrapy.xpath.selector import XmlXPathSelector, HtmlXPathSelector, \ + XPathSelector from scrapy.xpath.document import Libxml2Document from scrapy.utils.test import libxml2debug @@ -239,6 +241,15 @@ class XPathSelectorTestCase(unittest.TestCase): u'\n ', u'\n pff\n']) + @libxml2debug + def test_weakref_slots(self): + """Check that classes are using slots and are weak-referenceable""" + for cls in [XPathSelector, HtmlXPathSelector, XmlXPathSelector]: + x = cls() + weakref.ref(x) + assert not hasattr(x, '__dict__'), "%s does not use __slots__" % \ + x.__class__.__name__ + class Libxml2DocumentTest(unittest.TestCase): @libxml2debug diff --git a/scrapy/utils/datatypes.py b/scrapy/utils/datatypes.py index 094be5e0c..044bcae27 100644 --- a/scrapy/utils/datatypes.py +++ b/scrapy/utils/datatypes.py @@ -160,6 +160,9 @@ class SiteNode(object): class CaselessDict(dict): + + __slots__ = () + def __init__(self, seq=None): super(CaselessDict, self).__init__() if seq: diff --git a/scrapy/xpath/selector.py b/scrapy/xpath/selector.py index 1e0483600..f7d579a12 100644 --- a/scrapy/xpath/selector.py +++ b/scrapy/xpath/selector.py @@ -140,9 +140,10 @@ class XPathSelectorList(list): class XmlXPathSelector(XPathSelector): """XPathSelector for XML content""" + __slots__ = () _get_libxml2_doc = staticmethod(xmlDoc_from_xml) - class HtmlXPathSelector(XPathSelector): """XPathSelector for HTML content""" + __slots__ = () _get_libxml2_doc = staticmethod(xmlDoc_from_html)