diff --git a/docs/news.rst b/docs/news.rst index 04cfa6e8b..2ec7ea293 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -3,6 +3,12 @@ Release notes ============= +0.20 (not released yet) +----------------------- + +- Request/Response url/body attributes are now immutable (modifying them had + been deprecated for a long time) + 0.18.0 (released 2013-08-09) ---------------------------- diff --git a/scrapy/http/common.py b/scrapy/http/common.py index 34d5389bf..ba6ab277c 100644 --- a/scrapy/http/common.py +++ b/scrapy/http/common.py @@ -1,10 +1,6 @@ -import warnings -from scrapy.exceptions import ScrapyDeprecationWarning - -def deprecated_setter(setter, attrname): +def obsolete_setter(setter, attrname): def newsetter(self, value): c = self.__class__.__name__ - warnings.warn("Don't modify %s.%s attribute, use %s.replace() instead" % \ - (c, attrname, c), ScrapyDeprecationWarning, stacklevel=2) - return setter(self, value) + msg = "%s.%s is not modifiable, use %s.replace() instead" % (c, attrname, c) + raise AttributeError(msg) return newsetter diff --git a/scrapy/http/request/__init__.py b/scrapy/http/request/__init__.py index 1b14e2068..609a0d433 100644 --- a/scrapy/http/request/__init__.py +++ b/scrapy/http/request/__init__.py @@ -13,7 +13,7 @@ from scrapy.http.headers import Headers from scrapy.utils.trackref import object_ref from scrapy.utils.decorator import deprecated from scrapy.utils.url import escape_ajax -from scrapy.http.common import deprecated_setter +from scrapy.http.common import obsolete_setter class Request(object_ref): @@ -60,7 +60,7 @@ class Request(object_ref): if ':' not in self._url: raise ValueError('Missing scheme in request url: %s' % self._url) - url = property(_get_url, deprecated_setter(_set_url, 'url')) + url = property(_get_url, obsolete_setter(_set_url, 'url')) def _get_body(self): return self._body @@ -78,7 +78,7 @@ class Request(object_ref): else: raise TypeError("Request body must either str or unicode. Got: '%s'" % type(body).__name__) - body = property(_get_body, deprecated_setter(_set_body, 'body')) + body = property(_get_body, obsolete_setter(_set_body, 'body')) @property def encoding(self): diff --git a/scrapy/http/response/__init__.py b/scrapy/http/response/__init__.py index 46be1e362..7ff683eb6 100644 --- a/scrapy/http/response/__init__.py +++ b/scrapy/http/response/__init__.py @@ -9,7 +9,7 @@ import copy from scrapy.http.headers import Headers from scrapy.utils.trackref import object_ref -from scrapy.http.common import deprecated_setter +from scrapy.http.common import obsolete_setter class Response(object_ref): @@ -39,7 +39,7 @@ class Response(object_ref): raise TypeError('%s url must be str, got %s:' % (type(self).__name__, \ type(url).__name__)) - url = property(_get_url, deprecated_setter(_set_url, 'url')) + url = property(_get_url, obsolete_setter(_set_url, 'url')) def _get_body(self): return self._body @@ -56,7 +56,7 @@ class Response(object_ref): raise TypeError("Response body must either str or unicode. Got: '%s'" \ % type(body).__name__) - body = property(_get_body, deprecated_setter(_set_body, 'body')) + body = property(_get_body, obsolete_setter(_set_body, 'body')) def __str__(self): return "<%d %s>" % (self.status, self.url) diff --git a/scrapy/tests/test_http_request.py b/scrapy/tests/test_http_request.py index 9d2f235cc..d3378148d 100644 --- a/scrapy/tests/test_http_request.py +++ b/scrapy/tests/test_http_request.py @@ -175,6 +175,11 @@ class RequestTest(unittest.TestCase): r = self.request_class("http://www.example.com", method=u"POST") assert isinstance(r.method, str) + def test_immutable_attributes(self): + r = self.request_class("http://example.com") + self.assertRaises(AttributeError, setattr, r, 'url', 'http://example2.com') + self.assertRaises(AttributeError, setattr, r, 'body', 'xxx') + class FormRequestTest(RequestTest): diff --git a/scrapy/tests/test_http_response.py b/scrapy/tests/test_http_response.py index 26c66453a..0809340a1 100644 --- a/scrapy/tests/test_http_response.py +++ b/scrapy/tests/test_http_response.py @@ -107,6 +107,11 @@ class BaseResponseTest(unittest.TestCase): def _assert_response_encoding(self, response, encoding): self.assertEqual(response.encoding, resolve_encoding(encoding)) + def test_immutable_attributes(self): + r = self.response_class("http://example.com") + self.assertRaises(AttributeError, setattr, r, 'url', 'http://example2.com') + self.assertRaises(AttributeError, setattr, r, 'body', 'xxx') + class ResponseText(BaseResponseTest): def test_no_unicode_url(self):