1
0
mirror of https://github.com/scrapy/scrapy.git synced 2025-02-24 20:23:44 +00:00

added Request.replace method, improved tests for replace/copy method in Request/Response classes

--HG--
extra : convert_revision : svn%3Ab85faa78-f9eb-468e-a121-7cced6da292c%40745
This commit is contained in:
Pablo Hoffman 2009-01-18 17:52:21 +00:00
parent 314bbabb30
commit 0c9f7257a2
4 changed files with 66 additions and 15 deletions

View File

@ -17,9 +17,8 @@ from scrapy.utils.defer import chain_deferred
class Request(object): class Request(object):
def __init__(self, url, callback=None, method='GET', def __init__(self, url, callback=None, method='GET', headers=None, body=None,
body=None, headers=None, cookies=None, meta=None, cookies=None, meta=None, url_encoding='utf-8', dont_filter=None):
url_encoding='utf-8', dont_filter=None):
self.encoding = url_encoding # this one has to be set first self.encoding = url_encoding # this one has to be set first
self.set_url(url) self.set_url(url)
@ -69,14 +68,14 @@ class Request(object):
'method': self.method, 'method': self.method,
'url': self.url, 'url': self.url,
'headers': self.headers, 'headers': self.headers,
'cookies': self.cookies,
'body': self.body, 'body': self.body,
'cookies': self.cookies,
'meta': self.meta, 'meta': self.meta,
} }
return "%s(%s)" % (self.__class__.__name__, repr(d)) return "%s(%s)" % (self.__class__.__name__, repr(d))
def copy(self): def copy(self):
"""Return a new request cloned from this one""" """Return a copy a of this Request"""
new = copy.copy(self) new = copy.copy(self)
new.cache = {} new.cache = {}
for att in self.__dict__: for att in self.__dict__:
@ -86,6 +85,17 @@ class Request(object):
new.deferred = defer.Deferred() new.deferred = defer.Deferred()
return new return new
def replace(self, url=None, method=None, headers=None, body=None, cookies=None, meta=None):
"""Create a new Request with the same attributes except for those
given new values.
"""
return self.__class__(url=url or self.url,
method=method or self.method,
headers=headers or copy.deepcopy(self.headers),
body=body or self.body,
cookies=cookies or self.cookies,
meta=meta or self.meta)
def httprepr(self): def httprepr(self):
""" Return raw HTTP request representation (as string). This is """ Return raw HTTP request representation (as string). This is
provided only for reference since it's not the actual stream of bytes provided only for reference since it's not the actual stream of bytes

View File

@ -51,24 +51,21 @@ class Response(object):
return "<%d %s>" % (self.status, self.url) return "<%d %s>" % (self.status, self.url)
def copy(self): def copy(self):
"""Create a new Response based on the current one""" """Return a copy of this Response"""
return self.replace() return self.replace()
def replace(self, url=None, status=None, headers=None, body=None): def replace(self, url=None, status=None, headers=None, body=None, meta=None):
"""Create a new Response with the same attributes except for those """Create a new Response with the same attributes except for those
given new values. given new values.
Example:
>>> newresp = oldresp.replace(body="New body")
""" """
new = self.__class__(url=url or self.url, new = self.__class__(url=url or self.url,
status=status or self.status, status=status or self.status,
headers=headers or copy.deepcopy(self.headers), headers=headers or copy.deepcopy(self.headers),
body=body) meta=meta or self.meta)
if body is None: if body is None:
new.body = copy.deepcopy(self.body) new.body = copy.deepcopy(self.body)
new.meta = self.meta.copy() else:
new.body = _ResponseBody(body, self.headers_encoding())
return new return new
def httprepr(self): def httprepr(self):
@ -184,3 +181,6 @@ class _ResponseBody(object):
def __len__(self): def __len__(self):
return len(self._content) return len(self._content)
def __eq__(self, other):
return self._content == other._content and self.declared_encoding == other.declared_encoding

View File

@ -105,7 +105,10 @@ class RequestTest(unittest.TestCase):
def test_copy(self): def test_copy(self):
"""Test Request copy""" """Test Request copy"""
r1 = Request("http://www.example.com") def somecallback():
pass
r1 = Request("http://www.example.com", callback=somecallback)
r1.meta['foo'] = 'bar' r1.meta['foo'] = 'bar'
r1.cache['lala'] = 'lolo' r1.cache['lala'] = 'lolo'
r2 = r1.copy() r2 = r1.copy()
@ -113,10 +116,18 @@ class RequestTest(unittest.TestCase):
assert r1.cache assert r1.cache
assert not r2.cache assert not r2.cache
assert r1.deferred is not r2.deferred
# make sure meta dict is shallow copied # make sure meta dict is shallow copied
assert r1.meta is not r2.meta, "meta must be a shallow copy, not identical" assert r1.meta is not r2.meta, "meta must be a shallow copy, not identical"
self.assertEqual(r1.meta, r2.meta) self.assertEqual(r1.meta, r2.meta)
# make sure headers attribute is shallow copied
assert r1.headers is not r2.headers, "headers must be a shallow copy, not identical"
self.assertEqual(r1.headers, r2.headers)
# Request.body can be identical since it's an immutable object (str)
def test_copy_inherited_classes(self): def test_copy_inherited_classes(self):
"""Test Request children copies preserve their class""" """Test Request children copies preserve their class"""
@ -128,6 +139,16 @@ class RequestTest(unittest.TestCase):
assert type(r2) is CustomRequest assert type(r2) is CustomRequest
def test_replace(self):
"""Test Request.replace() method"""
hdrs = Headers({"key": "value"})
r1 = Request("http://www.example.com")
r2 = r1.replace(method="POST", body="New body", headers=hdrs)
self.assertEqual(r1.url, r2.url)
self.assertEqual((r1.method, r2.method), ("GET", "POST"))
self.assertEqual((r1.body, r2.body), (None, "New body"))
self.assertEqual((r1.headers, r2.headers), ({}, hdrs))
def test_httprepr(self): def test_httprepr(self):
r1 = Request("http://www.example.com") r1 = Request("http://www.example.com")
self.assertEqual(r1.httprepr(), 'GET http://www.example.com HTTP/1.1\r\nHost: www.example.com\r\n\r\n') self.assertEqual(r1.httprepr(), 'GET http://www.example.com HTTP/1.1\r\nHost: www.example.com\r\n\r\n')

View File

@ -36,7 +36,7 @@ class ResponseTest(unittest.TestCase):
def test_copy(self): def test_copy(self):
"""Test Response copy""" """Test Response copy"""
r1 = Response("http://www.example.com") r1 = Response("http://www.example.com", body="Some body")
r1.meta['foo'] = 'bar' r1.meta['foo'] = 'bar'
r1.cache['lala'] = 'lolo' r1.cache['lala'] = 'lolo'
r2 = r1.copy() r2 = r1.copy()
@ -48,6 +48,14 @@ class ResponseTest(unittest.TestCase):
assert r1.meta is not r2.meta, "meta must be a shallow copy, not identical" assert r1.meta is not r2.meta, "meta must be a shallow copy, not identical"
self.assertEqual(r1.meta, r2.meta) self.assertEqual(r1.meta, r2.meta)
# make sure headers attribute is shallow copied
assert r1.headers is not r2.headers, "headers must be a shallow copy, not identical"
self.assertEqual(r1.headers, r2.headers)
# make sure body is shallow copied
assert r1.body is not r2.body, "body must be a shallow copy, not identical"
self.assertEqual(r1.body, r2.body)
def test_copy_inherited_classes(self): def test_copy_inherited_classes(self):
"""Test Response children copies preserve their class""" """Test Response children copies preserve their class"""
@ -59,6 +67,18 @@ class ResponseTest(unittest.TestCase):
assert type(r2) is CustomResponse assert type(r2) is CustomResponse
def test_replace(self):
"""Test Response.replace() method"""
hdrs = Headers({"key": "value"})
r1 = Response("http://www.example.com")
r2 = r1.replace(status=301, body="New body", headers=hdrs)
assert r1.body is None
assert isinstance(r2.body, _ResponseBody)
self.assertEqual(r1.url, r2.url)
self.assertEqual((r1.status, r2.status), (200, 301))
self.assertEqual((r1.body, r2.body.to_string()), (None, "New body"))
self.assertEqual((r1.headers, r2.headers), ({}, hdrs))
def test_httprepr(self): def test_httprepr(self):
r1 = Response("http://www.example.com") r1 = Response("http://www.example.com")
self.assertEqual(r1.httprepr(), 'HTTP/1.1 200 OK\r\n\r\n') self.assertEqual(r1.httprepr(), 'HTTP/1.1 200 OK\r\n\r\n')