Merge dangra/lxml-formrequest

This commit is contained in:
Daniel Graña 2012-04-19 17:10:29 -03:00
commit 8b45a00f36
2 changed files with 359 additions and 278 deletions

View File

@ -32,10 +32,8 @@ class FormRequest(Request):
@classmethod
def from_response(cls, response, formname=None, formnumber=0, formdata=None,
clickdata=None, dont_click=False, **kwargs):
from scrapy.selector.lxmldocument import LxmlDocument
kwargs.setdefault('encoding', response.encoding)
root = LxmlDocument(response, lxml.html.HTMLParser)
form = _get_form(root, formname, formnumber, response)
form = _get_form(response, formname, formnumber)
formdata = _get_inputs(form, formdata, dont_click, clickdata, response)
url = form.action or form.base_url
return cls(url, method=form.method, formdata=formdata, **kwargs)
@ -47,11 +45,10 @@ def _urlencode(seq, enc):
for v in (vs if hasattr(vs, '__iter__') else [vs])]
return urllib.urlencode(values, doseq=1)
def _get_form(root, formname, formnumber, response):
"""
Uses all the passed arguments to get the required form
element
"""
def _get_form(response, formname, formnumber):
"""Find the form element """
from scrapy.selector.lxmldocument import LxmlDocument
root = LxmlDocument(response, lxml.html.HTMLParser)
if not root.forms:
raise ValueError("No <form> element found in %s" % response)
@ -77,15 +74,34 @@ def _get_inputs(form, formdata, dont_click, clickdata, response):
except (ValueError, TypeError):
raise ValueError('formdata should be a dict or iterable of tuples')
inputs = [(n, u'' if v is None else v) for n, v in form.fields.items() if n not in formdata]
inputs = form.xpath('descendant::textarea'
'|descendant::select'
'|descendant::input[@type!="submit" '
'and ((@type!="checkbox" and @type!="radio") or @checked)]')
values = [(k, u'' if v is None else v) \
for k, v in (_value(e) for e in inputs) \
if k and k not in formdata]
if not dont_click:
clickable = _get_clickable(clickdata, form)
if clickable and clickable[0] not in formdata and not clickable[0] is None:
inputs.append(clickable)
values.append(clickable)
inputs.extend(formdata.iteritems())
return inputs
values.extend(formdata.iteritems())
return values
def _value(ele):
n = ele.name
v = ele.value
# Match browser behaviour on simple select tag without options selected
# Or for select tags wihout options
if v is None and ele.tag == 'select' and not ele.multiple:
o = ele.value_options
if o:
return n, o[0]
else:
return None, None
return n, v
def _get_clickable(clickdata, form):
"""

View File

@ -206,323 +206,388 @@ class FormRequestTest(RequestTest):
self.assertEqual(r3.body, 'colours=red&colours=blue&colours=green&price=%C2%A3+100')
def test_from_response_post(self):
respbody = """
<form action="post.php" method="POST">
<input type="hidden" name="test" value="val1">
<input type="hidden" name="test" value="val2">
<input type="hidden" name="test2" value="xxx">
</form>
"""
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
r1 = self.request_class.from_response(response, formdata={'one': ['two', 'three'], 'six': 'seven'}, callback=lambda x: x)
self.assertEqual(r1.method, 'POST')
self.assertEqual(r1.headers['Content-type'], 'application/x-www-form-urlencoded')
fs = cgi.FieldStorage(StringIO(r1.body), r1.headers, environ={"REQUEST_METHOD": "POST"})
self.assertEqual(r1.url, "http://www.example.com/this/post.php")
self.assertEqual(set([f.value for f in fs["test"]]), set(["val1", "val2"]))
self.assertEqual(set([f.value for f in fs["one"]]), set(["two", "three"]))
self.assertEqual(fs['test2'].value, 'xxx')
self.assertEqual(fs['six'].value, 'seven')
response = _buildresponse(
"""<form action="post.php" method="POST">
<input type="hidden" name="test" value="val1">
<input type="hidden" name="test" value="val2">
<input type="hidden" name="test2" value="xxx">
</form>""",
url="http://www.example.com/this/list.html")
req = self.request_class.from_response(response,
formdata={'one': ['two', 'three'], 'six': 'seven'})
self.assertEqual(req.method, 'POST')
self.assertEqual(req.headers['Content-type'], 'application/x-www-form-urlencoded')
self.assertEqual(req.url, "http://www.example.com/this/post.php")
fs = _qs(req)
self.assertEqual(set(fs["test"]), set(["val1", "val2"]))
self.assertEqual(set(fs["one"]), set(["two", "three"]))
self.assertEqual(fs['test2'], ['xxx'])
self.assertEqual(fs['six'], ['seven'])
def test_from_response_extra_headers(self):
respbody = """
<form action="post.php" method="POST">
<input type="hidden" name="test" value="val1">
<input type="hidden" name="test" value="val2">
<input type="hidden" name="test2" value="xxx">
</form>
"""
headers = {"Accept-Encoding": "gzip,deflate"}
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
r1 = self.request_class.from_response(response, formdata={'one': ['two', 'three'], 'six': 'seven'}, headers=headers, callback=lambda x: x)
self.assertEqual(r1.method, 'POST')
self.assertEqual(r1.headers['Content-type'], 'application/x-www-form-urlencoded')
self.assertEqual(r1.headers['Accept-Encoding'], 'gzip,deflate')
response = _buildresponse(
"""<form action="post.php" method="POST">
<input type="hidden" name="test" value="val1">
<input type="hidden" name="test" value="val2">
<input type="hidden" name="test2" value="xxx">
</form>""")
req = self.request_class.from_response(response,
formdata={'one': ['two', 'three'], 'six': 'seven'},
headers={"Accept-Encoding": "gzip,deflate"})
self.assertEqual(req.method, 'POST')
self.assertEqual(req.headers['Content-type'], 'application/x-www-form-urlencoded')
self.assertEqual(req.headers['Accept-Encoding'], 'gzip,deflate')
def test_from_response_get(self):
respbody = """
<form action="get.php" method="GET">
<input type="hidden" name="test" value="val1">
<input type="hidden" name="test" value="val2">
<input type="hidden" name="test2" value="xxx">
</form>
"""
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
r1 = self.request_class.from_response(response, formdata={'one': ['two', 'three'], 'six': 'seven'})
response = _buildresponse(
"""<form action="get.php" method="GET">
<input type="hidden" name="test" value="val1">
<input type="hidden" name="test" value="val2">
<input type="hidden" name="test2" value="xxx">
</form>""",
url="http://www.example.com/this/list.html")
r1 = self.request_class.from_response(response,
formdata={'one': ['two', 'three'], 'six': 'seven'})
self.assertEqual(r1.method, 'GET')
self.assertEqual(urlparse(r1.url).hostname, "www.example.com")
self.assertEqual(urlparse(r1.url).path, "/this/get.php")
urlargs = cgi.parse_qs(urlparse(r1.url).query)
self.assertEqual(set(urlargs['test']), set(['val1', 'val2']))
self.assertEqual(set(urlargs['one']), set(['two', 'three']))
self.assertEqual(urlargs['test2'], ['xxx'])
self.assertEqual(urlargs['six'], ['seven'])
fs = _qs(r1)
self.assertEqual(set(fs['test']), set(['val1', 'val2']))
self.assertEqual(set(fs['one']), set(['two', 'three']))
self.assertEqual(fs['test2'], ['xxx'])
self.assertEqual(fs['six'], ['seven'])
def test_from_response_override_params(self):
respbody = """
<form action="get.php" method="POST">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
</form>
"""
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
r1 = self.request_class.from_response(response, formdata={'two': '2'})
fs = cgi.FieldStorage(StringIO(r1.body), r1.headers, environ={"REQUEST_METHOD": "POST"})
self.assertEqual(fs['one'].value, '1')
self.assertEqual(fs['two'].value, '2')
response = _buildresponse(
"""<form action="get.php" method="POST">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
</form>""")
req = self.request_class.from_response(response, formdata={'two': '2'})
fs = _qs(req)
self.assertEqual(fs['one'], ['1'])
self.assertEqual(fs['two'], ['2'])
def test_from_response_submit_first_clickable(self):
respbody = """
<form action="get.php" method="GET">
<input type="submit" name="clickable1" value="clicked1">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
<input type="submit" name="clickable2" value="clicked2">
</form>
"""
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
r1 = self.request_class.from_response(response, formdata={'two': '2'})
urlargs = cgi.parse_qs(urlparse(r1.url).query)
self.assertEqual(urlargs['clickable1'], ['clicked1'])
self.assertFalse('clickable2' in urlargs, urlargs)
self.assertEqual(urlargs['one'], ['1'])
self.assertEqual(urlargs['two'], ['2'])
response = _buildresponse(
"""<form action="get.php" method="GET">
<input type="submit" name="clickable1" value="clicked1">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
<input type="submit" name="clickable2" value="clicked2">
</form>""")
req = self.request_class.from_response(response, formdata={'two': '2'})
fs = _qs(req)
self.assertEqual(fs['clickable1'], ['clicked1'])
self.assertFalse('clickable2' in fs, fs)
self.assertEqual(fs['one'], ['1'])
self.assertEqual(fs['two'], ['2'])
def test_from_response_submit_not_first_clickable(self):
respbody = """
<form action="get.php" method="GET">
<input type="submit" name="clickable1" value="clicked1">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
<input type="submit" name="clickable2" value="clicked2">
</form>
"""
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
r1 = self.request_class.from_response(response, formdata={'two': '2'}, clickdata={'name': 'clickable2'})
urlargs = cgi.parse_qs(urlparse(r1.url).query)
self.assertEqual(urlargs['clickable2'], ['clicked2'])
self.assertFalse('clickable1' in urlargs, urlargs)
self.assertEqual(urlargs['one'], ['1'])
self.assertEqual(urlargs['two'], ['2'])
response = _buildresponse(
"""<form action="get.php" method="GET">
<input type="submit" name="clickable1" value="clicked1">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
<input type="submit" name="clickable2" value="clicked2">
</form>""")
req = self.request_class.from_response(response, formdata={'two': '2'}, \
clickdata={'name': 'clickable2'})
fs = _qs(req)
self.assertEqual(fs['clickable2'], ['clicked2'])
self.assertFalse('clickable1' in fs, fs)
self.assertEqual(fs['one'], ['1'])
self.assertEqual(fs['two'], ['2'])
def test_from_response_multiple_clickdata(self):
respbody = """
<form action="get.php" method="GET">
<input type="submit" name="clickable" value="clicked1">
<input type="submit" name="clickable" value="clicked2">
<input type="hidden" name="one" value="clicked1">
<input type="hidden" name="two" value="clicked2">
</form>
"""
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
r1 = self.request_class.from_response(response, \
response = _buildresponse(
"""<form action="get.php" method="GET">
<input type="submit" name="clickable" value="clicked1">
<input type="submit" name="clickable" value="clicked2">
<input type="hidden" name="one" value="clicked1">
<input type="hidden" name="two" value="clicked2">
</form>""")
req = self.request_class.from_response(response, \
clickdata={'name': 'clickable', 'value': 'clicked2'})
urlargs = cgi.parse_qs(urlparse(r1.url).query)
self.assertEqual(urlargs['clickable'], ['clicked2'])
self.assertEqual(urlargs['one'], ['clicked1'])
self.assertEqual(urlargs['two'], ['clicked2'])
fs = _qs(req)
self.assertEqual(fs['clickable'], ['clicked2'])
self.assertEqual(fs['one'], ['clicked1'])
self.assertEqual(fs['two'], ['clicked2'])
def test_from_response_unicode_clickdata(self):
body = u"""
<form action="get.php" method="GET">
<input type="submit" name="price in \u00a3" value="\u00a3 1000">
<input type="submit" name="price in \u20ac" value="\u20ac 2000">
<input type="hidden" name="poundsign" value="\u00a3">
<input type="hidden" name="eurosign" value="\u20ac">
</form>
"""
response = HtmlResponse("http://www.example.com", body=body, \
encoding='utf-8')
r1 = self.request_class.from_response(response, \
response = _buildresponse(
u"""<form action="get.php" method="GET">
<input type="submit" name="price in \u00a3" value="\u00a3 1000">
<input type="submit" name="price in \u20ac" value="\u20ac 2000">
<input type="hidden" name="poundsign" value="\u00a3">
<input type="hidden" name="eurosign" value="\u20ac">
</form>""")
req = self.request_class.from_response(response, \
clickdata={'name': u'price in \u00a3'})
urlargs = cgi.parse_qs(urlparse(r1.url).query)
self.assertTrue(urlargs[u'price in \u00a3'.encode('utf-8')])
def test_from_response_with_select(self):
body = u"""
<form name="form1">
<select name="inputname"><option selected="selected" value="inputvalue">text</option></select>
<input type="submit" name="clickable" value="clicked">
</form>
"""
res = HtmlResponse("http://example.com", body=body, encoding='utf-8')
req = self.request_class.from_response(res)
urlargs = cgi.parse_qs(urlparse(req.url).query)
self.assertEqual(urlargs['inputname'], ['inputvalue'])
fs = _qs(req)
self.assertTrue(fs[u'price in \u00a3'.encode('utf-8')])
def test_from_response_multiple_forms_clickdata(self):
body = u"""
<form name="form1">
<input type="submit" name="clickable" value="clicked1">
<input type="hidden" name="field1" value="value1">
</form>
<form name="form2">
<input type="submit" name="clickable" value="clicked2">
<input type="hidden" name="field2" value="value2">
</form>
"""
res = HtmlResponse("http://example.com", body=body, encoding='utf-8')
req = self.request_class.from_response(res, formname='form2', \
response = _buildresponse(
"""<form name="form1">
<input type="submit" name="clickable" value="clicked1">
<input type="hidden" name="field1" value="value1">
</form>
<form name="form2">
<input type="submit" name="clickable" value="clicked2">
<input type="hidden" name="field2" value="value2">
</form>
""")
req = self.request_class.from_response(response, formname='form2', \
clickdata={'name': 'clickable'})
urlargs = cgi.parse_qs(urlparse(req.url).query)
self.assertEqual(urlargs['clickable'], ['clicked2'])
self.assertEqual(urlargs['field2'], ['value2'])
self.assertFalse('field1' in urlargs, urlargs)
fs = _qs(req)
self.assertEqual(fs['clickable'], ['clicked2'])
self.assertEqual(fs['field2'], ['value2'])
self.assertFalse('field1' in fs, fs)
def test_from_response_override_clickable(self):
body = u'<form><input type="submit" name="clickme" value="one"></form>'
res = HtmlResponse("http://example.com", body=body, encoding='utf-8')
req = self.request_class.from_response(res, \
formdata={'clickme': 'two'}, \
clickdata={'name': 'clickme'})
urlargs = cgi.parse_qs(urlparse(req.url).query)
self.assertEqual(urlargs['clickme'], ['two'])
response = _buildresponse('''<form><input type="submit" name="clickme" value="one"> </form>''')
req = self.request_class.from_response(response, \
formdata={'clickme': 'two'}, clickdata={'name': 'clickme'})
fs = _qs(req)
self.assertEqual(fs['clickme'], ['two'])
def test_from_response_dont_click(self):
respbody = """
<form action="get.php" method="GET">
<input type="submit" name="clickable1" value="clicked1">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
<input type="submit" name="clickable2" value="clicked2">
</form>
"""
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
response = _buildresponse(
"""<form action="get.php" method="GET">
<input type="submit" name="clickable1" value="clicked1">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
<input type="submit" name="clickable2" value="clicked2">
</form>""")
r1 = self.request_class.from_response(response, dont_click=True)
urlargs = cgi.parse_qs(urlparse(r1.url).query)
self.assertFalse('clickable1' in urlargs, urlargs)
self.assertFalse('clickable2' in urlargs, urlargs)
fs = _qs(r1)
self.assertFalse('clickable1' in fs, fs)
self.assertFalse('clickable2' in fs, fs)
def test_from_response_ambiguous_clickdata(self):
respbody = """
<form action="get.php" method="GET">
<input type="submit" name="clickable1" value="clicked1">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
<input type="submit" name="clickable2" value="clicked2">
</form>
"""
response = HtmlResponse("http://www.example.com/this/list.html", body=respbody)
self.assertRaises(ValueError,
self.request_class.from_response,
response,
clickdata={'type': 'submit'})
response = _buildresponse(
"""
<form action="get.php" method="GET">
<input type="submit" name="clickable1" value="clicked1">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="3">
<input type="submit" name="clickable2" value="clicked2">
</form>""")
self.assertRaises(ValueError, self.request_class.from_response,
response, clickdata={'type': 'submit'})
def test_from_response_non_matching_clickdata(self):
body = """
<form>
<input type="submit" name="clickable" value="clicked">
</form>
"""
res = HtmlResponse("http://example.com", body=body)
self.assertRaises(ValueError,
self.request_class.from_response, res,
clickdata={'nonexistent': 'notme'})
response = _buildresponse(
"""<form>
<input type="submit" name="clickable" value="clicked">
</form>""")
self.assertRaises(ValueError, self.request_class.from_response,
response, clickdata={'nonexistent': 'notme'})
def test_from_response_errors_noform(self):
respbody = """<html></html>"""
response = HtmlResponse("http://www.example.com/lala.html", body=respbody)
response = _buildresponse("""<html></html>""")
self.assertRaises(ValueError, self.request_class.from_response, response)
def test_from_response_errors_formnumber(self):
respbody = """
<form action="get.php" method="GET">
<input type="hidden" name="test" value="val1">
<input type="hidden" name="test" value="val2">
<input type="hidden" name="test2" value="xxx">
</form>
"""
response = HtmlResponse("http://www.example.com/lala.html", body=respbody)
response = _buildresponse(
"""<form action="get.php" method="GET">
<input type="hidden" name="test" value="val1">
<input type="hidden" name="test" value="val2">
<input type="hidden" name="test2" value="xxx">
</form>""")
self.assertRaises(IndexError, self.request_class.from_response, response, formnumber=1)
def test_from_response_noformname(self):
respbody = """
<form action="post.php" method="POST">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="2">
</form>
"""
response = HtmlResponse("http://www.example.com/formname.html", body=respbody)
r1 = self.request_class.from_response(response, formdata={'two':'3'}, callback=lambda x: x)
response = _buildresponse(
"""<form action="post.php" method="POST">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="2">
</form>""")
r1 = self.request_class.from_response(response, formdata={'two':'3'})
self.assertEqual(r1.method, 'POST')
self.assertEqual(r1.headers['Content-type'], 'application/x-www-form-urlencoded')
fs = cgi.FieldStorage(StringIO(r1.body), r1.headers, environ={"REQUEST_METHOD": "POST"})
self.assertEqual(fs['one'].value, '1')
self.assertEqual(fs['two'].value, '3')
fs = _qs(r1)
self.assertEqual(fs, {'one': ['1'], 'two': ['3']})
def test_from_response_formname_exists(self):
respbody = """
<form action="post.php" method="POST">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="2">
</form>
<form name="form2" action="post.php" method="POST">
<input type="hidden" name="three" value="3">
<input type="hidden" name="four" value="4">
</form>
"""
response = HtmlResponse("http://www.example.com/formname.html", body=respbody)
r1 = self.request_class.from_response(response, formname="form2", callback=lambda x: x)
response = _buildresponse(
"""<form action="post.php" method="POST">
<input type="hidden" name="one" value="1">
<input type="hidden" name="two" value="2">
</form>
<form name="form2" action="post.php" method="POST">
<input type="hidden" name="three" value="3">
<input type="hidden" name="four" value="4">
</form>""")
r1 = self.request_class.from_response(response, formname="form2")
self.assertEqual(r1.method, 'POST')
fs = cgi.FieldStorage(StringIO(r1.body), r1.headers, environ={"REQUEST_METHOD": "POST"})
self.assertEqual(fs['three'].value, "3")
self.assertEqual(fs['four'].value, "4")
fs = _qs(r1)
self.assertEqual(fs, {'four': ['4'], 'three': ['3']})
def test_from_response_formname_notexist(self):
respbody = """
<form name="form1" action="post.php" method="POST">
<input type="hidden" name="one" value="1">
</form>
<form name="form2" action="post.php" method="POST">
<input type="hidden" name="two" value="2">
</form>
"""
response = HtmlResponse("http://www.example.com/formname.html", body=respbody)
r1 = self.request_class.from_response(response, formname="form3", callback=lambda x: x)
response = _buildresponse(
"""<form name="form1" action="post.php" method="POST">
<input type="hidden" name="one" value="1">
</form>
<form name="form2" action="post.php" method="POST">
<input type="hidden" name="two" value="2">
</form>""")
r1 = self.request_class.from_response(response, formname="form3")
self.assertEqual(r1.method, 'POST')
fs = cgi.FieldStorage(StringIO(r1.body), r1.headers, environ={"REQUEST_METHOD": "POST"})
self.assertEqual(fs['one'].value, "1")
fs = _qs(r1)
self.assertEqual(fs, {'one': ['1']})
def test_from_response_formname_errors_formnumber(self):
respbody = """
<form name="form1" action="post.php" method="POST">
<input type="hidden" name="one" value="1">
</form>
<form name="form2" action="post.php" method="POST">
<input type="hidden" name="two" value="2">
</form>
"""
response = HtmlResponse("http://www.example.com/formname.html", body=respbody)
self.assertRaises(IndexError, self.request_class.from_response, response, formname="form3", formnumber=2)
response = _buildresponse(
"""<form name="form1" action="post.php" method="POST">
<input type="hidden" name="one" value="1">
</form>
<form name="form2" action="post.php" method="POST">
<input type="hidden" name="two" value="2">
</form>""")
self.assertRaises(IndexError, self.request_class.from_response, \
response, formname="form3", formnumber=2)
def test_from_response_missed_value(self):
respbody = """
<form action="get.php" method="POST">
<input type="hidden" name="key1" value="val1">
<input type="hidden" name="key2">
<input type="radio" name="key3" checked>
<input type="checkbox" name="key4" checked>
<textarea name="key5">val5</textarea>
<textarea name="key6"/>
<select name="key7">
<option name="opt1" selected></option>
<option name="opt2">opt2</option>
</select>
<input type="submit" value="val8">
</form>
"""
res = HtmlResponse("http://example.com", body=respbody, encoding='utf-8')
def test_from_response_select(self):
res = _buildresponse(
'''<form>
<select name="i1">
<option value="i1v1">option 1</option>
<option value="i1v2" selected>option 2</option>
</select>
<select name="i2">
<option value="i2v1">option 1</option>
<option value="i2v2">option 2</option>
</select>
<select>
<option value="i3v1">option 1</option>
<option value="i3v2">option 2</option>
</select>
<select name="i4" multiple>
<option value="i4v1">option 1</option>
<option value="i4v2" selected>option 2</option>
<option value="i4v3" selected>option 3</option>
</select>
<select name="i5" multiple>
<option value="i5v1">option 1</option>
<option value="i5v2">option 2</option>
</select>
<select name="i6"></select>
<select name="i7"/>
</form>''')
req = self.request_class.from_response(res)
fs = cgi.parse_qs(req.body, True)
self.assertEqual(fs['key1'], ['val1'])
self.assertEqual(fs['key2'], [''])
self.assertEqual(fs['key3'], ['on'])
self.assertEqual(fs['key4'], ['on'])
self.assertEqual(fs['key5'], ['val5'])
self.assertEqual(fs['key6'], [''])
self.assertEqual(fs['key7'], [''])
self.assertEqual(set(fs), set(['key1', 'key2', 'key3', 'key4', 'key5', 'key6', 'key7']))
fs = _qs(req)
self.assertEqual(fs, {'i1': ['i1v2'], 'i2': ['i2v1'], 'i4': ['i4v2', 'i4v3']})
def test_from_response_radio(self):
res = _buildresponse(
'''<form>
<input type="radio" name="i1" value="i1v1">
<input type="radio" name="i1" value="iv2" checked>
<input type="radio" name="i2" checked>
<input type="radio" name="i2">
<input type="radio" name="i3" value="i3v1">
<input type="radio" name="i3">
</form>''')
req = self.request_class.from_response(res)
fs = _qs(req)
self.assertEqual(fs, {'i1': ['iv2'], 'i2': ['on']})
def test_from_response_checkbox(self):
res = _buildresponse(
'''<form>
<input type="checkbox" name="i1" value="i1v1">
<input type="checkbox" name="i1" value="iv2" checked>
<input type="checkbox" name="i2" checked>
<input type="checkbox" name="i2">
<input type="checkbox" name="i3" value="i3v1">
<input type="checkbox" name="i3">
</form>''')
req = self.request_class.from_response(res)
fs = _qs(req)
self.assertEqual(fs, {'i1': ['iv2'], 'i2': ['on']})
def test_from_response_input_text(self):
res = _buildresponse(
'''<form>
<input type="text" name="i1" value="i1v1">
<input type="text" name="i2">
<input type="text">
</form>''')
req = self.request_class.from_response(res)
fs = _qs(req)
self.assertEqual(fs, {'i1': ['i1v1'], 'i2': ['']})
def test_from_response_input_hidden(self):
res = _buildresponse(
'''<form>
<input type="hidden" name="i1" value="i1v1">
<input type="hidden" name="i2">
<input type="hidden">
</form>''')
req = self.request_class.from_response(res)
fs = _qs(req)
self.assertEqual(fs, {'i1': ['i1v1'], 'i2': ['']})
def test_from_response_input_hidden(self):
res = _buildresponse(
'''<form>
<input type="hidden" name="i1" value="i1v1">
<input type="hidden" name="i2">
<input type="hidden">
</form>''')
req = self.request_class.from_response(res)
fs = _qs(req)
self.assertEqual(fs, {'i1': ['i1v1'], 'i2': ['']})
def test_from_response_input_textarea(self):
res = _buildresponse(
'''<form>
<textarea name="i1">i1v</textarea>
<textarea name="i2"></textarea>
<textarea name="i3"/>
<textarea>i4v</textarea>
</form>''')
req = self.request_class.from_response(res)
fs = _qs(req)
self.assertEqual(fs, {'i1': ['i1v'], 'i2': [''], 'i3': ['']})
def test_from_response_descendants(self):
res = _buildresponse(
'''<form>
<div>
<fieldset>
<input type="text" name="i1">
<select name="i2">
<option value="v1" selected>
</select>
</fieldset>
<input type="radio" name="i3" value="i3v2" checked>
<input type="checkbox" name="i4" value="i4v2" checked>
<textarea name="i5"></textarea>
<input type="hidden" name="h1" value="h1v">
</div>
<input type="hidden" name="h2" value="h2v">
</form>''')
req = self.request_class.from_response(res)
fs = _qs(req)
self.assertEqual(set(fs), set(['h2', 'i2', 'i1', 'i3', 'h1', 'i5', 'i4']))
def _buildresponse(body, **kwargs):
kwargs.setdefault('body', body)
kwargs.setdefault('url', 'http://example.com')
kwargs.setdefault('encoding', 'utf-8')
return HtmlResponse(**kwargs)
def _qs(req):
if req.method == 'POST':
qs = req.body
else:
qs = req.url.partition('?')[2]
return cgi.parse_qs(qs, True)
class XmlRpcRequestTest(RequestTest):