blob: d929a5e0e2a258548644fcd80037a6535451c3dc [file] [log] [blame]
Brett Cannon74bfd702003-04-25 09:39:47 +00001"""Regresssion tests for urllib"""
2
Jeremy Hylton1afc1692008-06-18 20:49:58 +00003import urllib.parse
4import urllib.request
guido@google.coma119df92011-03-29 11:41:02 -07005import urllib.error
Georg Brandl24420152008-05-26 16:32:26 +00006import http.client
Barry Warsaw820c1202008-06-12 04:06:45 +00007import email.message
Jeremy Hylton66dc8c52007-08-04 03:42:26 +00008import io
Brett Cannon74bfd702003-04-25 09:39:47 +00009import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +000010from test import support
Brett Cannon74bfd702003-04-25 09:39:47 +000011import os
Senthil Kumaran2d2ea1b2011-04-14 13:16:30 +080012import sys
Georg Brandl5a650a22005-08-26 08:51:34 +000013import tempfile
Jeremy Hylton6102e292000-08-31 15:48:10 +000014
Brett Cannon74bfd702003-04-25 09:39:47 +000015def hexescape(char):
16 """Escape char as RFC 2396 specifies"""
17 hex_repr = hex(ord(char))[2:].upper()
18 if len(hex_repr) == 1:
19 hex_repr = "0%s" % hex_repr
20 return "%" + hex_repr
Jeremy Hylton6102e292000-08-31 15:48:10 +000021
Jeremy Hylton1afc1692008-06-18 20:49:58 +000022# Shortcut for testing FancyURLopener
23_urlopener = None
24def urlopen(url, data=None, proxies=None):
25 """urlopen(url [, data]) -> open file-like object"""
26 global _urlopener
27 if proxies is not None:
28 opener = urllib.request.FancyURLopener(proxies=proxies)
29 elif not _urlopener:
30 opener = urllib.request.FancyURLopener()
31 _urlopener = opener
32 else:
33 opener = _urlopener
34 if data is None:
35 return opener.open(url)
36 else:
37 return opener.open(url, data)
38
Senthil Kumarance260142011-11-01 01:35:17 +080039
40class FakeHTTPMixin(object):
41 def fakehttp(self, fakedata):
42 class FakeSocket(io.BytesIO):
43 io_refs = 1
44
45 def sendall(self, str):
46 pass
47
48 def makefile(self, *args, **kwds):
49 self.io_refs += 1
50 return self
51
52 def read(self, amt=None):
53 if self.closed:
54 return b""
55 return io.BytesIO.read(self, amt)
56
57 def readline(self, length=None):
58 if self.closed:
59 return b""
60 return io.BytesIO.readline(self, length)
61
62 def close(self):
63 self.io_refs -= 1
64 if self.io_refs == 0:
65 io.BytesIO.close(self)
66
67 class FakeHTTPConnection(http.client.HTTPConnection):
68 def connect(self):
69 self.sock = FakeSocket(fakedata)
70 self._connection_class = http.client.HTTPConnection
71 http.client.HTTPConnection = FakeHTTPConnection
72
73 def unfakehttp(self):
74 http.client.HTTPConnection = self._connection_class
75
76
Brett Cannon74bfd702003-04-25 09:39:47 +000077class urlopen_FileTests(unittest.TestCase):
78 """Test urlopen() opening a temporary file.
Jeremy Hylton6102e292000-08-31 15:48:10 +000079
Brett Cannon74bfd702003-04-25 09:39:47 +000080 Try to test as much functionality as possible so as to cut down on reliance
Andrew M. Kuchlingf1a2f9e2004-06-29 13:07:53 +000081 on connecting to the Net for testing.
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000082
Brett Cannon74bfd702003-04-25 09:39:47 +000083 """
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000084
Brett Cannon74bfd702003-04-25 09:39:47 +000085 def setUp(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000086 # Create a temp file to use for testing
87 self.text = bytes("test_urllib: %s\n" % self.__class__.__name__,
88 "ascii")
89 f = open(support.TESTFN, 'wb')
Brett Cannon74bfd702003-04-25 09:39:47 +000090 try:
Jeremy Hylton1afc1692008-06-18 20:49:58 +000091 f.write(self.text)
Brett Cannon74bfd702003-04-25 09:39:47 +000092 finally:
Jeremy Hylton1afc1692008-06-18 20:49:58 +000093 f.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000094 self.pathname = support.TESTFN
Jeremy Hylton1afc1692008-06-18 20:49:58 +000095 self.returned_obj = urlopen("file:%s" % self.pathname)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +000096
Brett Cannon74bfd702003-04-25 09:39:47 +000097 def tearDown(self):
98 """Shut down the open object"""
99 self.returned_obj.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000100 os.remove(support.TESTFN)
Jeremy Hylton7ae51bf2000-09-14 16:59:07 +0000101
Brett Cannon74bfd702003-04-25 09:39:47 +0000102 def test_interface(self):
103 # Make sure object returned by urlopen() has the specified methods
104 for attr in ("read", "readline", "readlines", "fileno",
Christian Heimes9bd667a2008-01-20 15:14:11 +0000105 "close", "info", "geturl", "getcode", "__iter__"):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000106 self.assertTrue(hasattr(self.returned_obj, attr),
Brett Cannon74bfd702003-04-25 09:39:47 +0000107 "object returned by urlopen() lacks %s attribute" %
108 attr)
Skip Montanaroe78b92a2001-01-20 20:22:30 +0000109
Brett Cannon74bfd702003-04-25 09:39:47 +0000110 def test_read(self):
111 self.assertEqual(self.text, self.returned_obj.read())
Skip Montanaro080c9972001-01-28 21:12:22 +0000112
Brett Cannon74bfd702003-04-25 09:39:47 +0000113 def test_readline(self):
114 self.assertEqual(self.text, self.returned_obj.readline())
Guido van Rossuma0982942007-07-10 08:30:03 +0000115 self.assertEqual(b'', self.returned_obj.readline(),
Brett Cannon74bfd702003-04-25 09:39:47 +0000116 "calling readline() after exhausting the file did not"
117 " return an empty string")
Skip Montanaro080c9972001-01-28 21:12:22 +0000118
Brett Cannon74bfd702003-04-25 09:39:47 +0000119 def test_readlines(self):
120 lines_list = self.returned_obj.readlines()
121 self.assertEqual(len(lines_list), 1,
122 "readlines() returned the wrong number of lines")
123 self.assertEqual(lines_list[0], self.text,
124 "readlines() returned improper text")
Skip Montanaro080c9972001-01-28 21:12:22 +0000125
Brett Cannon74bfd702003-04-25 09:39:47 +0000126 def test_fileno(self):
127 file_num = self.returned_obj.fileno()
Ezio Melottie9615932010-01-24 19:26:24 +0000128 self.assertIsInstance(file_num, int, "fileno() did not return an int")
Brett Cannon74bfd702003-04-25 09:39:47 +0000129 self.assertEqual(os.read(file_num, len(self.text)), self.text,
130 "Reading on the file descriptor returned by fileno() "
131 "did not return the expected text")
Skip Montanaroe78b92a2001-01-20 20:22:30 +0000132
Brett Cannon74bfd702003-04-25 09:39:47 +0000133 def test_close(self):
Senthil Kumarand91ffca2011-03-19 17:25:27 +0800134 # Test close() by calling it here and then having it be called again
Brett Cannon74bfd702003-04-25 09:39:47 +0000135 # by the tearDown() method for the test
136 self.returned_obj.close()
Skip Montanaro080c9972001-01-28 21:12:22 +0000137
Brett Cannon74bfd702003-04-25 09:39:47 +0000138 def test_info(self):
Ezio Melottie9615932010-01-24 19:26:24 +0000139 self.assertIsInstance(self.returned_obj.info(), email.message.Message)
Skip Montanaroe78b92a2001-01-20 20:22:30 +0000140
Brett Cannon74bfd702003-04-25 09:39:47 +0000141 def test_geturl(self):
142 self.assertEqual(self.returned_obj.geturl(), self.pathname)
Skip Montanaro080c9972001-01-28 21:12:22 +0000143
Christian Heimes9bd667a2008-01-20 15:14:11 +0000144 def test_getcode(self):
Florent Xicluna419e3842010-08-08 16:16:07 +0000145 self.assertIsNone(self.returned_obj.getcode())
Christian Heimes9bd667a2008-01-20 15:14:11 +0000146
Brett Cannon74bfd702003-04-25 09:39:47 +0000147 def test_iter(self):
148 # Test iterator
149 # Don't need to count number of iterations since test would fail the
150 # instant it returned anything beyond the first line from the
Raymond Hettinger038018a2011-06-26 14:29:35 +0200151 # comparison.
152 # Use the iterator in the usual implicit way to test for ticket #4608.
153 for line in self.returned_obj:
Brett Cannon74bfd702003-04-25 09:39:47 +0000154 self.assertEqual(line, self.text)
Skip Montanaro080c9972001-01-28 21:12:22 +0000155
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000156class ProxyTests(unittest.TestCase):
157
158 def setUp(self):
Walter Dörwaldb525e182009-04-26 21:39:21 +0000159 # Records changes to env vars
160 self.env = support.EnvironmentVarGuard()
Benjamin Peterson46a99002010-01-09 18:45:30 +0000161 # Delete all proxy related env vars
Antoine Pitroub3a88b52010-10-14 18:31:39 +0000162 for k in list(os.environ):
Antoine Pitrou8c8f1ac2010-10-14 18:32:54 +0000163 if 'proxy' in k.lower():
Benjamin Peterson46a99002010-01-09 18:45:30 +0000164 self.env.unset(k)
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000165
166 def tearDown(self):
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000167 # Restore all proxy related env vars
Walter Dörwaldb525e182009-04-26 21:39:21 +0000168 self.env.__exit__()
169 del self.env
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000170
171 def test_getproxies_environment_keep_no_proxies(self):
Walter Dörwaldb525e182009-04-26 21:39:21 +0000172 self.env.set('NO_PROXY', 'localhost')
173 proxies = urllib.request.getproxies_environment()
174 # getproxies_environment use lowered case truncated (no '_proxy') keys
Florent Xicluna419e3842010-08-08 16:16:07 +0000175 self.assertEqual('localhost', proxies['no'])
Senthil Kumaran89976f12011-08-06 12:27:40 +0800176 # List of no_proxies with space.
177 self.env.set('NO_PROXY', 'localhost, anotherdomain.com, newdomain.com')
178 self.assertTrue(urllib.request.proxy_bypass_environment('anotherdomain.com'))
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000179
Senthil Kumarance260142011-11-01 01:35:17 +0800180class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin):
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000181 """Test urlopen() opening a fake http connection."""
182
Antoine Pitrou988dbd72010-12-17 17:35:56 +0000183 def check_read(self, ver):
184 self.fakehttp(b"HTTP/" + ver + b" 200 OK\r\n\r\nHello!")
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000185 try:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000186 fp = urlopen("http://python.org/")
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000187 self.assertEqual(fp.readline(), b"Hello!")
188 self.assertEqual(fp.readline(), b"")
Christian Heimes9bd667a2008-01-20 15:14:11 +0000189 self.assertEqual(fp.geturl(), 'http://python.org/')
190 self.assertEqual(fp.getcode(), 200)
Hye-Shik Chang39aef792004-06-05 13:30:56 +0000191 finally:
192 self.unfakehttp()
193
Senthil Kumaran26430412011-04-13 07:01:19 +0800194 def test_url_fragment(self):
195 # Issue #11703: geturl() omits fragments in the original URL.
196 url = 'http://docs.python.org/library/urllib.html#OK'
Senthil Kumaranb17abb12011-04-13 07:22:29 +0800197 self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!")
Senthil Kumaran26430412011-04-13 07:01:19 +0800198 try:
199 fp = urllib.request.urlopen(url)
200 self.assertEqual(fp.geturl(), url)
201 finally:
202 self.unfakehttp()
203
Senthil Kumarand91ffca2011-03-19 17:25:27 +0800204 def test_willclose(self):
205 self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello!")
Senthil Kumaranacbaa922011-03-20 05:30:16 +0800206 try:
207 resp = urlopen("http://www.python.org")
208 self.assertTrue(resp.fp.will_close)
209 finally:
210 self.unfakehttp()
Senthil Kumarand91ffca2011-03-19 17:25:27 +0800211
Antoine Pitrou988dbd72010-12-17 17:35:56 +0000212 def test_read_0_9(self):
213 # "0.9" response accepted (but not "simple responses" without
214 # a status line)
215 self.check_read(b"0.9")
216
217 def test_read_1_0(self):
218 self.check_read(b"1.0")
219
220 def test_read_1_1(self):
221 self.check_read(b"1.1")
222
Christian Heimes57dddfb2008-01-02 18:30:52 +0000223 def test_read_bogus(self):
224 # urlopen() should raise IOError for many error codes.
225 self.fakehttp(b'''HTTP/1.1 401 Authentication Required
226Date: Wed, 02 Jan 2008 03:03:54 GMT
227Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
228Connection: close
229Content-Type: text/html; charset=iso-8859-1
230''')
231 try:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000232 self.assertRaises(IOError, urlopen, "http://python.org/")
Christian Heimes57dddfb2008-01-02 18:30:52 +0000233 finally:
234 self.unfakehttp()
235
guido@google.coma119df92011-03-29 11:41:02 -0700236 def test_invalid_redirect(self):
237 # urlopen() should raise IOError for many error codes.
238 self.fakehttp(b'''HTTP/1.1 302 Found
239Date: Wed, 02 Jan 2008 03:03:54 GMT
240Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
241Location: file://guidocomputer.athome.com:/python/license
242Connection: close
243Content-Type: text/html; charset=iso-8859-1
244''')
245 try:
246 self.assertRaises(urllib.error.HTTPError, urlopen,
247 "http://python.org/")
248 finally:
249 self.unfakehttp()
250
Guido van Rossumd8faa362007-04-27 19:54:29 +0000251 def test_empty_socket(self):
Jeremy Hylton66dc8c52007-08-04 03:42:26 +0000252 # urlopen() raises IOError if the underlying socket does not send any
253 # data. (#1680230)
Christian Heimes57dddfb2008-01-02 18:30:52 +0000254 self.fakehttp(b'')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000255 try:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000256 self.assertRaises(IOError, urlopen, "http://something")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000257 finally:
258 self.unfakehttp()
259
Senthil Kumarande0eb242010-08-01 17:53:37 +0000260 def test_userpass_inurl(self):
Antoine Pitrou988dbd72010-12-17 17:35:56 +0000261 self.fakehttp(b"HTTP/1.0 200 OK\r\n\r\nHello!")
Senthil Kumarande0eb242010-08-01 17:53:37 +0000262 try:
263 fp = urlopen("http://user:pass@python.org/")
264 self.assertEqual(fp.readline(), b"Hello!")
265 self.assertEqual(fp.readline(), b"")
266 self.assertEqual(fp.geturl(), 'http://user:pass@python.org/')
267 self.assertEqual(fp.getcode(), 200)
268 finally:
269 self.unfakehttp()
270
Brett Cannon19691362003-04-29 05:08:06 +0000271class urlretrieve_FileTests(unittest.TestCase):
Brett Cannon74bfd702003-04-25 09:39:47 +0000272 """Test urllib.urlretrieve() on local files"""
Skip Montanaro080c9972001-01-28 21:12:22 +0000273
Brett Cannon19691362003-04-29 05:08:06 +0000274 def setUp(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000275 # Create a list of temporary files. Each item in the list is a file
276 # name (absolute path or relative to the current working directory).
277 # All files in this list will be deleted in the tearDown method. Note,
278 # this only helps to makes sure temporary files get deleted, but it
279 # does nothing about trying to close files that may still be open. It
280 # is the responsibility of the developer to properly close files even
281 # when exceptional conditions occur.
282 self.tempFiles = []
283
Brett Cannon19691362003-04-29 05:08:06 +0000284 # Create a temporary file.
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000285 self.registerFileForCleanUp(support.TESTFN)
Guido van Rossuma0982942007-07-10 08:30:03 +0000286 self.text = b'testing urllib.urlretrieve'
Georg Brandl5a650a22005-08-26 08:51:34 +0000287 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000288 FILE = open(support.TESTFN, 'wb')
Georg Brandl5a650a22005-08-26 08:51:34 +0000289 FILE.write(self.text)
290 FILE.close()
291 finally:
292 try: FILE.close()
293 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000294
295 def tearDown(self):
Georg Brandl5a650a22005-08-26 08:51:34 +0000296 # Delete the temporary files.
297 for each in self.tempFiles:
298 try: os.remove(each)
299 except: pass
300
301 def constructLocalFileUrl(self, filePath):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000302 filePath = os.path.abspath(filePath)
303 try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000304 filePath.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +0000305 except UnicodeEncodeError:
306 raise unittest.SkipTest("filePath is not encodable to utf8")
307 return "file://%s" % urllib.request.pathname2url(filePath)
Georg Brandl5a650a22005-08-26 08:51:34 +0000308
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000309 def createNewTempFile(self, data=b""):
Georg Brandl5a650a22005-08-26 08:51:34 +0000310 """Creates a new temporary file containing the specified data,
311 registers the file for deletion during the test fixture tear down, and
312 returns the absolute path of the file."""
313
314 newFd, newFilePath = tempfile.mkstemp()
315 try:
316 self.registerFileForCleanUp(newFilePath)
317 newFile = os.fdopen(newFd, "wb")
318 newFile.write(data)
319 newFile.close()
320 finally:
321 try: newFile.close()
322 except: pass
323 return newFilePath
324
325 def registerFileForCleanUp(self, fileName):
326 self.tempFiles.append(fileName)
Brett Cannon19691362003-04-29 05:08:06 +0000327
328 def test_basic(self):
329 # Make sure that a local file just gets its own location returned and
330 # a headers value is returned.
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000331 result = urllib.request.urlretrieve("file:%s" % support.TESTFN)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000332 self.assertEqual(result[0], support.TESTFN)
Ezio Melottie9615932010-01-24 19:26:24 +0000333 self.assertIsInstance(result[1], email.message.Message,
334 "did not get a email.message.Message instance "
335 "as second returned value")
Brett Cannon19691362003-04-29 05:08:06 +0000336
337 def test_copy(self):
338 # Test that setting the filename argument works.
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000339 second_temp = "%s.2" % support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000340 self.registerFileForCleanUp(second_temp)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000341 result = urllib.request.urlretrieve(self.constructLocalFileUrl(
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000342 support.TESTFN), second_temp)
Brett Cannon19691362003-04-29 05:08:06 +0000343 self.assertEqual(second_temp, result[0])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000344 self.assertTrue(os.path.exists(second_temp), "copy of the file was not "
Brett Cannon19691362003-04-29 05:08:06 +0000345 "made")
Alex Martelli01c77c62006-08-24 02:58:11 +0000346 FILE = open(second_temp, 'rb')
Brett Cannon19691362003-04-29 05:08:06 +0000347 try:
348 text = FILE.read()
Brett Cannon19691362003-04-29 05:08:06 +0000349 FILE.close()
Georg Brandl5a650a22005-08-26 08:51:34 +0000350 finally:
351 try: FILE.close()
352 except: pass
Brett Cannon19691362003-04-29 05:08:06 +0000353 self.assertEqual(self.text, text)
354
355 def test_reporthook(self):
356 # Make sure that the reporthook works.
357 def hooktester(count, block_size, total_size, count_holder=[0]):
Ezio Melottie9615932010-01-24 19:26:24 +0000358 self.assertIsInstance(count, int)
359 self.assertIsInstance(block_size, int)
360 self.assertIsInstance(total_size, int)
Brett Cannon19691362003-04-29 05:08:06 +0000361 self.assertEqual(count, count_holder[0])
362 count_holder[0] = count_holder[0] + 1
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000363 second_temp = "%s.2" % support.TESTFN
Georg Brandl5a650a22005-08-26 08:51:34 +0000364 self.registerFileForCleanUp(second_temp)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000365 urllib.request.urlretrieve(
366 self.constructLocalFileUrl(support.TESTFN),
Georg Brandl5a650a22005-08-26 08:51:34 +0000367 second_temp, hooktester)
368
369 def test_reporthook_0_bytes(self):
370 # Test on zero length file. Should call reporthook only 1 time.
371 report = []
372 def hooktester(count, block_size, total_size, _report=report):
373 _report.append((count, block_size, total_size))
374 srcFileName = self.createNewTempFile()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000375 urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName),
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000376 support.TESTFN, hooktester)
Georg Brandl5a650a22005-08-26 08:51:34 +0000377 self.assertEqual(len(report), 1)
378 self.assertEqual(report[0][2], 0)
379
380 def test_reporthook_5_bytes(self):
381 # Test on 5 byte file. Should call reporthook only 2 times (once when
382 # the "network connection" is established and once when the block is
383 # read). Since the block size is 8192 bytes, only one block read is
384 # required to read the entire file.
385 report = []
386 def hooktester(count, block_size, total_size, _report=report):
387 _report.append((count, block_size, total_size))
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000388 srcFileName = self.createNewTempFile(b"x" * 5)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000389 urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName),
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000390 support.TESTFN, hooktester)
Georg Brandl5a650a22005-08-26 08:51:34 +0000391 self.assertEqual(len(report), 2)
392 self.assertEqual(report[0][1], 8192)
393 self.assertEqual(report[0][2], 5)
394
395 def test_reporthook_8193_bytes(self):
396 # Test on 8193 byte file. Should call reporthook only 3 times (once
397 # when the "network connection" is established, once for the next 8192
398 # bytes, and once for the last byte).
399 report = []
400 def hooktester(count, block_size, total_size, _report=report):
401 _report.append((count, block_size, total_size))
Guido van Rossum70d0dda2007-08-29 01:53:26 +0000402 srcFileName = self.createNewTempFile(b"x" * 8193)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000403 urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName),
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000404 support.TESTFN, hooktester)
Georg Brandl5a650a22005-08-26 08:51:34 +0000405 self.assertEqual(len(report), 3)
406 self.assertEqual(report[0][1], 8192)
407 self.assertEqual(report[0][2], 8193)
Skip Montanaro080c9972001-01-28 21:12:22 +0000408
Senthil Kumarance260142011-11-01 01:35:17 +0800409
410class urlretrieve_HttpTests(unittest.TestCase, FakeHTTPMixin):
411 """Test urllib.urlretrieve() using fake http connections"""
412
413 def test_short_content_raises_ContentTooShortError(self):
414 self.fakehttp(b'''HTTP/1.1 200 OK
415Date: Wed, 02 Jan 2008 03:03:54 GMT
416Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
417Connection: close
418Content-Length: 100
419Content-Type: text/html; charset=iso-8859-1
420
421FF
422''')
423
424 def _reporthook(par1, par2, par3):
425 pass
426
427 with self.assertRaises(urllib.error.ContentTooShortError):
428 try:
429 urllib.request.urlretrieve('http://example.com/',
430 reporthook=_reporthook)
431 finally:
432 self.unfakehttp()
433
434 def test_short_content_raises_ContentTooShortError_without_reporthook(self):
435 self.fakehttp(b'''HTTP/1.1 200 OK
436Date: Wed, 02 Jan 2008 03:03:54 GMT
437Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7e
438Connection: close
439Content-Length: 100
440Content-Type: text/html; charset=iso-8859-1
441
442FF
443''')
444 with self.assertRaises(urllib.error.ContentTooShortError):
445 try:
446 urllib.request.urlretrieve('http://example.com/')
447 finally:
448 self.unfakehttp()
449
450
Brett Cannon74bfd702003-04-25 09:39:47 +0000451class QuotingTests(unittest.TestCase):
452 """Tests for urllib.quote() and urllib.quote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000453
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000454 According to RFC 2396 (Uniform Resource Identifiers), to escape a
455 character you write it as '%' + <2 character US-ASCII hex value>.
456 The Python code of ``'%' + hex(ord(<character>))[2:]`` escapes a
457 character properly. Case does not matter on the hex letters.
Brett Cannon74bfd702003-04-25 09:39:47 +0000458
459 The various character sets specified are:
Tim Petersc2659cf2003-05-12 20:19:37 +0000460
Brett Cannon74bfd702003-04-25 09:39:47 +0000461 Reserved characters : ";/?:@&=+$,"
462 Have special meaning in URIs and must be escaped if not being used for
463 their special meaning
464 Data characters : letters, digits, and "-_.!~*'()"
465 Unreserved and do not need to be escaped; can be, though, if desired
466 Control characters : 0x00 - 0x1F, 0x7F
467 Have no use in URIs so must be escaped
468 space : 0x20
469 Must be escaped
470 Delimiters : '<>#%"'
471 Must be escaped
472 Unwise : "{}|\^[]`"
473 Must be escaped
Tim Petersc2659cf2003-05-12 20:19:37 +0000474
Brett Cannon74bfd702003-04-25 09:39:47 +0000475 """
476
477 def test_never_quote(self):
478 # Make sure quote() does not quote letters, digits, and "_,.-"
479 do_not_quote = '' .join(["ABCDEFGHIJKLMNOPQRSTUVWXYZ",
480 "abcdefghijklmnopqrstuvwxyz",
481 "0123456789",
482 "_.-"])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000483 result = urllib.parse.quote(do_not_quote)
Brett Cannon74bfd702003-04-25 09:39:47 +0000484 self.assertEqual(do_not_quote, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000485 "using quote(): %r != %r" % (do_not_quote, result))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000486 result = urllib.parse.quote_plus(do_not_quote)
Brett Cannon74bfd702003-04-25 09:39:47 +0000487 self.assertEqual(do_not_quote, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000488 "using quote_plus(): %r != %r" % (do_not_quote, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000489
490 def test_default_safe(self):
491 # Test '/' is default value for 'safe' parameter
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000492 self.assertEqual(urllib.parse.quote.__defaults__[0], '/')
Brett Cannon74bfd702003-04-25 09:39:47 +0000493
494 def test_safe(self):
495 # Test setting 'safe' parameter does what it should do
496 quote_by_default = "<>"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000497 result = urllib.parse.quote(quote_by_default, safe=quote_by_default)
Brett Cannon74bfd702003-04-25 09:39:47 +0000498 self.assertEqual(quote_by_default, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000499 "using quote(): %r != %r" % (quote_by_default, result))
Jeremy Hylton1ef7c6b2009-03-26 16:57:30 +0000500 result = urllib.parse.quote_plus(quote_by_default,
501 safe=quote_by_default)
Brett Cannon74bfd702003-04-25 09:39:47 +0000502 self.assertEqual(quote_by_default, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000503 "using quote_plus(): %r != %r" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000504 (quote_by_default, result))
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000505 # Safe expressed as bytes rather than str
506 result = urllib.parse.quote(quote_by_default, safe=b"<>")
507 self.assertEqual(quote_by_default, result,
508 "using quote(): %r != %r" % (quote_by_default, result))
509 # "Safe" non-ASCII characters should have no effect
510 # (Since URIs are not allowed to have non-ASCII characters)
511 result = urllib.parse.quote("a\xfcb", encoding="latin-1", safe="\xfc")
512 expect = urllib.parse.quote("a\xfcb", encoding="latin-1", safe="")
513 self.assertEqual(expect, result,
514 "using quote(): %r != %r" %
515 (expect, result))
516 # Same as above, but using a bytes rather than str
517 result = urllib.parse.quote("a\xfcb", encoding="latin-1", safe=b"\xfc")
518 expect = urllib.parse.quote("a\xfcb", encoding="latin-1", safe="")
519 self.assertEqual(expect, result,
520 "using quote(): %r != %r" %
521 (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000522
523 def test_default_quoting(self):
524 # Make sure all characters that should be quoted are by default sans
525 # space (separate test for that).
526 should_quote = [chr(num) for num in range(32)] # For 0x00 - 0x1F
527 should_quote.append('<>#%"{}|\^[]`')
528 should_quote.append(chr(127)) # For 0x7F
529 should_quote = ''.join(should_quote)
530 for char in should_quote:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000531 result = urllib.parse.quote(char)
Brett Cannon74bfd702003-04-25 09:39:47 +0000532 self.assertEqual(hexescape(char), result,
Jeremy Hylton1ef7c6b2009-03-26 16:57:30 +0000533 "using quote(): "
534 "%s should be escaped to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000535 (char, hexescape(char), result))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000536 result = urllib.parse.quote_plus(char)
Brett Cannon74bfd702003-04-25 09:39:47 +0000537 self.assertEqual(hexescape(char), result,
538 "using quote_plus(): "
Tim Petersc2659cf2003-05-12 20:19:37 +0000539 "%s should be escapes to %s, not %s" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000540 (char, hexescape(char), result))
541 del should_quote
542 partial_quote = "ab[]cd"
543 expected = "ab%5B%5Dcd"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000544 result = urllib.parse.quote(partial_quote)
Brett Cannon74bfd702003-04-25 09:39:47 +0000545 self.assertEqual(expected, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000546 "using quote(): %r != %r" % (expected, result))
Senthil Kumaran305a68e2011-09-13 06:40:27 +0800547 result = urllib.parse.quote_plus(partial_quote)
Brett Cannon74bfd702003-04-25 09:39:47 +0000548 self.assertEqual(expected, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000549 "using quote_plus(): %r != %r" % (expected, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000550
551 def test_quoting_space(self):
552 # Make sure quote() and quote_plus() handle spaces as specified in
553 # their unique way
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000554 result = urllib.parse.quote(' ')
Brett Cannon74bfd702003-04-25 09:39:47 +0000555 self.assertEqual(result, hexescape(' '),
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000556 "using quote(): %r != %r" % (result, hexescape(' ')))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000557 result = urllib.parse.quote_plus(' ')
Brett Cannon74bfd702003-04-25 09:39:47 +0000558 self.assertEqual(result, '+',
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000559 "using quote_plus(): %r != +" % result)
Brett Cannon74bfd702003-04-25 09:39:47 +0000560 given = "a b cd e f"
561 expect = given.replace(' ', hexescape(' '))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000562 result = urllib.parse.quote(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000563 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000564 "using quote(): %r != %r" % (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000565 expect = given.replace(' ', '+')
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000566 result = urllib.parse.quote_plus(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000567 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000568 "using quote_plus(): %r != %r" % (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000569
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000570 def test_quoting_plus(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000571 self.assertEqual(urllib.parse.quote_plus('alpha+beta gamma'),
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000572 'alpha%2Bbeta+gamma')
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000573 self.assertEqual(urllib.parse.quote_plus('alpha+beta gamma', '+'),
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000574 'alpha+beta+gamma')
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000575 # Test with bytes
576 self.assertEqual(urllib.parse.quote_plus(b'alpha+beta gamma'),
577 'alpha%2Bbeta+gamma')
578 # Test with safe bytes
579 self.assertEqual(urllib.parse.quote_plus('alpha+beta gamma', b'+'),
580 'alpha+beta+gamma')
581
582 def test_quote_bytes(self):
583 # Bytes should quote directly to percent-encoded values
584 given = b"\xa2\xd8ab\xff"
585 expect = "%A2%D8ab%FF"
586 result = urllib.parse.quote(given)
587 self.assertEqual(expect, result,
588 "using quote(): %r != %r" % (expect, result))
589 # Encoding argument should raise type error on bytes input
590 self.assertRaises(TypeError, urllib.parse.quote, given,
591 encoding="latin-1")
592 # quote_from_bytes should work the same
593 result = urllib.parse.quote_from_bytes(given)
594 self.assertEqual(expect, result,
595 "using quote_from_bytes(): %r != %r"
596 % (expect, result))
597
598 def test_quote_with_unicode(self):
599 # Characters in Latin-1 range, encoded by default in UTF-8
600 given = "\xa2\xd8ab\xff"
601 expect = "%C2%A2%C3%98ab%C3%BF"
602 result = urllib.parse.quote(given)
603 self.assertEqual(expect, result,
604 "using quote(): %r != %r" % (expect, result))
605 # Characters in Latin-1 range, encoded by with None (default)
606 result = urllib.parse.quote(given, encoding=None, errors=None)
607 self.assertEqual(expect, result,
608 "using quote(): %r != %r" % (expect, result))
609 # Characters in Latin-1 range, encoded with Latin-1
610 given = "\xa2\xd8ab\xff"
611 expect = "%A2%D8ab%FF"
612 result = urllib.parse.quote(given, encoding="latin-1")
613 self.assertEqual(expect, result,
614 "using quote(): %r != %r" % (expect, result))
615 # Characters in BMP, encoded by default in UTF-8
616 given = "\u6f22\u5b57" # "Kanji"
617 expect = "%E6%BC%A2%E5%AD%97"
618 result = urllib.parse.quote(given)
619 self.assertEqual(expect, result,
620 "using quote(): %r != %r" % (expect, result))
621 # Characters in BMP, encoded with Latin-1
622 given = "\u6f22\u5b57"
623 self.assertRaises(UnicodeEncodeError, urllib.parse.quote, given,
624 encoding="latin-1")
625 # Characters in BMP, encoded with Latin-1, with replace error handling
626 given = "\u6f22\u5b57"
627 expect = "%3F%3F" # "??"
628 result = urllib.parse.quote(given, encoding="latin-1",
629 errors="replace")
630 self.assertEqual(expect, result,
631 "using quote(): %r != %r" % (expect, result))
632 # Characters in BMP, Latin-1, with xmlcharref error handling
633 given = "\u6f22\u5b57"
634 expect = "%26%2328450%3B%26%2323383%3B" # "&#28450;&#23383;"
635 result = urllib.parse.quote(given, encoding="latin-1",
636 errors="xmlcharrefreplace")
637 self.assertEqual(expect, result,
638 "using quote(): %r != %r" % (expect, result))
Raymond Hettinger2bdec7b2005-09-10 14:30:09 +0000639
Georg Brandlfaf41492009-05-26 18:31:11 +0000640 def test_quote_plus_with_unicode(self):
641 # Encoding (latin-1) test for quote_plus
642 given = "\xa2\xd8 \xff"
643 expect = "%A2%D8+%FF"
644 result = urllib.parse.quote_plus(given, encoding="latin-1")
645 self.assertEqual(expect, result,
646 "using quote_plus(): %r != %r" % (expect, result))
647 # Errors test for quote_plus
648 given = "ab\u6f22\u5b57 cd"
649 expect = "ab%3F%3F+cd"
650 result = urllib.parse.quote_plus(given, encoding="latin-1",
651 errors="replace")
652 self.assertEqual(expect, result,
653 "using quote_plus(): %r != %r" % (expect, result))
654
Senthil Kumarand496c4c2010-07-30 19:34:36 +0000655
Brett Cannon74bfd702003-04-25 09:39:47 +0000656class UnquotingTests(unittest.TestCase):
657 """Tests for unquote() and unquote_plus()
Tim Petersc2659cf2003-05-12 20:19:37 +0000658
Brett Cannon74bfd702003-04-25 09:39:47 +0000659 See the doc string for quoting_Tests for details on quoting and such.
660
661 """
662
663 def test_unquoting(self):
664 # Make sure unquoting of all ASCII values works
665 escape_list = []
666 for num in range(128):
667 given = hexescape(chr(num))
668 expect = chr(num)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000669 result = urllib.parse.unquote(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000670 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000671 "using unquote(): %r != %r" % (expect, result))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000672 result = urllib.parse.unquote_plus(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000673 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000674 "using unquote_plus(): %r != %r" %
Brett Cannon74bfd702003-04-25 09:39:47 +0000675 (expect, result))
676 escape_list.append(given)
677 escape_string = ''.join(escape_list)
678 del escape_list
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000679 result = urllib.parse.unquote(escape_string)
Brett Cannon74bfd702003-04-25 09:39:47 +0000680 self.assertEqual(result.count('%'), 1,
Brett Cannon74bfd702003-04-25 09:39:47 +0000681 "using unquote(): not all characters escaped: "
682 "%s" % result)
Georg Brandl604ef372010-07-31 08:20:02 +0000683 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote, None)
684 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote, ())
Florent Xicluna62829dc2010-08-14 20:51:58 +0000685 with support.check_warnings(('', BytesWarning), quiet=True):
686 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote, b'')
Brett Cannon74bfd702003-04-25 09:39:47 +0000687
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000688 def test_unquoting_badpercent(self):
689 # Test unquoting on bad percent-escapes
690 given = '%xab'
691 expect = given
692 result = urllib.parse.unquote(given)
693 self.assertEqual(expect, result, "using unquote(): %r != %r"
694 % (expect, result))
695 given = '%x'
696 expect = given
697 result = urllib.parse.unquote(given)
698 self.assertEqual(expect, result, "using unquote(): %r != %r"
699 % (expect, result))
700 given = '%'
701 expect = given
702 result = urllib.parse.unquote(given)
703 self.assertEqual(expect, result, "using unquote(): %r != %r"
704 % (expect, result))
705 # unquote_to_bytes
706 given = '%xab'
707 expect = bytes(given, 'ascii')
708 result = urllib.parse.unquote_to_bytes(given)
709 self.assertEqual(expect, result, "using unquote_to_bytes(): %r != %r"
710 % (expect, result))
711 given = '%x'
712 expect = bytes(given, 'ascii')
713 result = urllib.parse.unquote_to_bytes(given)
714 self.assertEqual(expect, result, "using unquote_to_bytes(): %r != %r"
715 % (expect, result))
716 given = '%'
717 expect = bytes(given, 'ascii')
718 result = urllib.parse.unquote_to_bytes(given)
719 self.assertEqual(expect, result, "using unquote_to_bytes(): %r != %r"
720 % (expect, result))
Georg Brandl604ef372010-07-31 08:20:02 +0000721 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote_to_bytes, None)
722 self.assertRaises((TypeError, AttributeError), urllib.parse.unquote_to_bytes, ())
Senthil Kumaran79e17f62010-07-19 18:17:19 +0000723
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000724 def test_unquoting_mixed_case(self):
725 # Test unquoting on mixed-case hex digits in the percent-escapes
726 given = '%Ab%eA'
727 expect = b'\xab\xea'
728 result = urllib.parse.unquote_to_bytes(given)
729 self.assertEqual(expect, result,
730 "using unquote_to_bytes(): %r != %r"
731 % (expect, result))
732
Brett Cannon74bfd702003-04-25 09:39:47 +0000733 def test_unquoting_parts(self):
734 # Make sure unquoting works when have non-quoted characters
735 # interspersed
736 given = 'ab%sd' % hexescape('c')
737 expect = "abcd"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000738 result = urllib.parse.unquote(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000739 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000740 "using quote(): %r != %r" % (expect, result))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000741 result = urllib.parse.unquote_plus(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000742 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000743 "using unquote_plus(): %r != %r" % (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +0000744
Brett Cannon74bfd702003-04-25 09:39:47 +0000745 def test_unquoting_plus(self):
746 # Test difference between unquote() and unquote_plus()
747 given = "are+there+spaces..."
748 expect = given
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000749 result = urllib.parse.unquote(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000750 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000751 "using unquote(): %r != %r" % (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000752 expect = given.replace('+', ' ')
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000753 result = urllib.parse.unquote_plus(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000754 self.assertEqual(expect, result,
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000755 "using unquote_plus(): %r != %r" % (expect, result))
756
757 def test_unquote_to_bytes(self):
758 given = 'br%C3%BCckner_sapporo_20050930.doc'
759 expect = b'br\xc3\xbcckner_sapporo_20050930.doc'
760 result = urllib.parse.unquote_to_bytes(given)
761 self.assertEqual(expect, result,
762 "using unquote_to_bytes(): %r != %r"
763 % (expect, result))
764 # Test on a string with unescaped non-ASCII characters
765 # (Technically an invalid URI; expect those characters to be UTF-8
766 # encoded).
767 result = urllib.parse.unquote_to_bytes("\u6f22%C3%BC")
768 expect = b'\xe6\xbc\xa2\xc3\xbc' # UTF-8 for "\u6f22\u00fc"
769 self.assertEqual(expect, result,
770 "using unquote_to_bytes(): %r != %r"
771 % (expect, result))
772 # Test with a bytes as input
773 given = b'%A2%D8ab%FF'
774 expect = b'\xa2\xd8ab\xff'
775 result = urllib.parse.unquote_to_bytes(given)
776 self.assertEqual(expect, result,
777 "using unquote_to_bytes(): %r != %r"
778 % (expect, result))
779 # Test with a bytes as input, with unescaped non-ASCII bytes
780 # (Technically an invalid URI; expect those bytes to be preserved)
781 given = b'%A2\xd8ab%FF'
782 expect = b'\xa2\xd8ab\xff'
783 result = urllib.parse.unquote_to_bytes(given)
784 self.assertEqual(expect, result,
785 "using unquote_to_bytes(): %r != %r"
786 % (expect, result))
Brett Cannon74bfd702003-04-25 09:39:47 +0000787
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000788 def test_unquote_with_unicode(self):
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000789 # Characters in the Latin-1 range, encoded with UTF-8
790 given = 'br%C3%BCckner_sapporo_20050930.doc'
791 expect = 'br\u00fcckner_sapporo_20050930.doc'
792 result = urllib.parse.unquote(given)
793 self.assertEqual(expect, result,
794 "using unquote(): %r != %r" % (expect, result))
795 # Characters in the Latin-1 range, encoded with None (default)
796 result = urllib.parse.unquote(given, encoding=None, errors=None)
797 self.assertEqual(expect, result,
798 "using unquote(): %r != %r" % (expect, result))
799
800 # Characters in the Latin-1 range, encoded with Latin-1
801 result = urllib.parse.unquote('br%FCckner_sapporo_20050930.doc',
802 encoding="latin-1")
803 expect = 'br\u00fcckner_sapporo_20050930.doc'
804 self.assertEqual(expect, result,
805 "using unquote(): %r != %r" % (expect, result))
806
807 # Characters in BMP, encoded with UTF-8
808 given = "%E6%BC%A2%E5%AD%97"
809 expect = "\u6f22\u5b57" # "Kanji"
810 result = urllib.parse.unquote(given)
811 self.assertEqual(expect, result,
812 "using unquote(): %r != %r" % (expect, result))
813
814 # Decode with UTF-8, invalid sequence
815 given = "%F3%B1"
816 expect = "\ufffd" # Replacement character
817 result = urllib.parse.unquote(given)
818 self.assertEqual(expect, result,
819 "using unquote(): %r != %r" % (expect, result))
820
821 # Decode with UTF-8, invalid sequence, replace errors
822 result = urllib.parse.unquote(given, errors="replace")
823 self.assertEqual(expect, result,
824 "using unquote(): %r != %r" % (expect, result))
825
826 # Decode with UTF-8, invalid sequence, ignoring errors
827 given = "%F3%B1"
828 expect = ""
829 result = urllib.parse.unquote(given, errors="ignore")
830 self.assertEqual(expect, result,
831 "using unquote(): %r != %r" % (expect, result))
832
833 # A mix of non-ASCII and percent-encoded characters, UTF-8
834 result = urllib.parse.unquote("\u6f22%C3%BC")
835 expect = '\u6f22\u00fc'
836 self.assertEqual(expect, result,
837 "using unquote(): %r != %r" % (expect, result))
838
839 # A mix of non-ASCII and percent-encoded characters, Latin-1
840 # (Note, the string contains non-Latin-1-representable characters)
841 result = urllib.parse.unquote("\u6f22%FC", encoding="latin-1")
842 expect = '\u6f22\u00fc'
843 self.assertEqual(expect, result,
844 "using unquote(): %r != %r" % (expect, result))
Raymond Hettinger4b0f20d2005-10-15 16:41:53 +0000845
Brett Cannon74bfd702003-04-25 09:39:47 +0000846class urlencode_Tests(unittest.TestCase):
847 """Tests for urlencode()"""
848
849 def help_inputtype(self, given, test_type):
850 """Helper method for testing different input types.
Tim Petersc2659cf2003-05-12 20:19:37 +0000851
Brett Cannon74bfd702003-04-25 09:39:47 +0000852 'given' must lead to only the pairs:
853 * 1st, 1
854 * 2nd, 2
855 * 3rd, 3
Tim Petersc2659cf2003-05-12 20:19:37 +0000856
Brett Cannon74bfd702003-04-25 09:39:47 +0000857 Test cannot assume anything about order. Docs make no guarantee and
858 have possible dictionary input.
Tim Petersc2659cf2003-05-12 20:19:37 +0000859
Brett Cannon74bfd702003-04-25 09:39:47 +0000860 """
861 expect_somewhere = ["1st=1", "2nd=2", "3rd=3"]
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000862 result = urllib.parse.urlencode(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000863 for expected in expect_somewhere:
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000864 self.assertIn(expected, result,
Brett Cannon74bfd702003-04-25 09:39:47 +0000865 "testing %s: %s not found in %s" %
866 (test_type, expected, result))
867 self.assertEqual(result.count('&'), 2,
868 "testing %s: expected 2 '&'s; got %s" %
869 (test_type, result.count('&')))
870 amp_location = result.index('&')
871 on_amp_left = result[amp_location - 1]
872 on_amp_right = result[amp_location + 1]
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000873 self.assertTrue(on_amp_left.isdigit() and on_amp_right.isdigit(),
Brett Cannon74bfd702003-04-25 09:39:47 +0000874 "testing %s: '&' not located in proper place in %s" %
875 (test_type, result))
876 self.assertEqual(len(result), (5 * 3) + 2, #5 chars per thing and amps
877 "testing %s: "
878 "unexpected number of characters: %s != %s" %
879 (test_type, len(result), (5 * 3) + 2))
880
881 def test_using_mapping(self):
882 # Test passing in a mapping object as an argument.
883 self.help_inputtype({"1st":'1', "2nd":'2', "3rd":'3'},
884 "using dict as input type")
885
886 def test_using_sequence(self):
887 # Test passing in a sequence of two-item sequences as an argument.
888 self.help_inputtype([('1st', '1'), ('2nd', '2'), ('3rd', '3')],
889 "using sequence of two-item tuples as input")
890
891 def test_quoting(self):
892 # Make sure keys and values are quoted using quote_plus()
893 given = {"&":"="}
894 expect = "%s=%s" % (hexescape('&'), hexescape('='))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000895 result = urllib.parse.urlencode(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000896 self.assertEqual(expect, result)
897 given = {"key name":"A bunch of pluses"}
898 expect = "key+name=A+bunch+of+pluses"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000899 result = urllib.parse.urlencode(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000900 self.assertEqual(expect, result)
901
902 def test_doseq(self):
903 # Test that passing True for 'doseq' parameter works correctly
904 given = {'sequence':['1', '2', '3']}
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000905 expect = "sequence=%s" % urllib.parse.quote_plus(str(['1', '2', '3']))
906 result = urllib.parse.urlencode(given)
Brett Cannon74bfd702003-04-25 09:39:47 +0000907 self.assertEqual(expect, result)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000908 result = urllib.parse.urlencode(given, True)
Brett Cannon74bfd702003-04-25 09:39:47 +0000909 for value in given["sequence"]:
910 expect = "sequence=%s" % value
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000911 self.assertIn(expect, result)
Brett Cannon74bfd702003-04-25 09:39:47 +0000912 self.assertEqual(result.count('&'), 2,
913 "Expected 2 '&'s, got %s" % result.count('&'))
914
Jeremy Hylton1ef7c6b2009-03-26 16:57:30 +0000915 def test_empty_sequence(self):
916 self.assertEqual("", urllib.parse.urlencode({}))
917 self.assertEqual("", urllib.parse.urlencode([]))
918
919 def test_nonstring_values(self):
920 self.assertEqual("a=1", urllib.parse.urlencode({"a": 1}))
921 self.assertEqual("a=None", urllib.parse.urlencode({"a": None}))
922
923 def test_nonstring_seq_values(self):
924 self.assertEqual("a=1&a=2", urllib.parse.urlencode({"a": [1, 2]}, True))
925 self.assertEqual("a=None&a=a",
926 urllib.parse.urlencode({"a": [None, "a"]}, True))
927 self.assertEqual("a=a&a=b",
928 urllib.parse.urlencode({"a": {"a": 1, "b": 1}}, True))
929
Senthil Kumarandf022da2010-07-03 17:48:22 +0000930 def test_urlencode_encoding(self):
931 # ASCII encoding. Expect %3F with errors="replace'
932 given = (('\u00a0', '\u00c1'),)
933 expect = '%3F=%3F'
934 result = urllib.parse.urlencode(given, encoding="ASCII", errors="replace")
935 self.assertEqual(expect, result)
936
937 # Default is UTF-8 encoding.
938 given = (('\u00a0', '\u00c1'),)
939 expect = '%C2%A0=%C3%81'
940 result = urllib.parse.urlencode(given)
941 self.assertEqual(expect, result)
942
943 # Latin-1 encoding.
944 given = (('\u00a0', '\u00c1'),)
945 expect = '%A0=%C1'
946 result = urllib.parse.urlencode(given, encoding="latin-1")
947 self.assertEqual(expect, result)
948
949 def test_urlencode_encoding_doseq(self):
950 # ASCII Encoding. Expect %3F with errors="replace'
951 given = (('\u00a0', '\u00c1'),)
952 expect = '%3F=%3F'
953 result = urllib.parse.urlencode(given, doseq=True,
954 encoding="ASCII", errors="replace")
955 self.assertEqual(expect, result)
956
957 # ASCII Encoding. On a sequence of values.
958 given = (("\u00a0", (1, "\u00c1")),)
959 expect = '%3F=1&%3F=%3F'
960 result = urllib.parse.urlencode(given, True,
961 encoding="ASCII", errors="replace")
962 self.assertEqual(expect, result)
963
964 # Utf-8
965 given = (("\u00a0", "\u00c1"),)
966 expect = '%C2%A0=%C3%81'
967 result = urllib.parse.urlencode(given, True)
968 self.assertEqual(expect, result)
969
970 given = (("\u00a0", (42, "\u00c1")),)
971 expect = '%C2%A0=42&%C2%A0=%C3%81'
972 result = urllib.parse.urlencode(given, True)
973 self.assertEqual(expect, result)
974
975 # latin-1
976 given = (("\u00a0", "\u00c1"),)
977 expect = '%A0=%C1'
978 result = urllib.parse.urlencode(given, True, encoding="latin-1")
979 self.assertEqual(expect, result)
980
981 given = (("\u00a0", (42, "\u00c1")),)
982 expect = '%A0=42&%A0=%C1'
983 result = urllib.parse.urlencode(given, True, encoding="latin-1")
984 self.assertEqual(expect, result)
985
986 def test_urlencode_bytes(self):
987 given = ((b'\xa0\x24', b'\xc1\x24'),)
988 expect = '%A0%24=%C1%24'
989 result = urllib.parse.urlencode(given)
990 self.assertEqual(expect, result)
991 result = urllib.parse.urlencode(given, True)
992 self.assertEqual(expect, result)
993
994 # Sequence of values
995 given = ((b'\xa0\x24', (42, b'\xc1\x24')),)
996 expect = '%A0%24=42&%A0%24=%C1%24'
997 result = urllib.parse.urlencode(given, True)
998 self.assertEqual(expect, result)
999
1000 def test_urlencode_encoding_safe_parameter(self):
1001
1002 # Send '$' (\x24) as safe character
1003 # Default utf-8 encoding
1004
1005 given = ((b'\xa0\x24', b'\xc1\x24'),)
1006 result = urllib.parse.urlencode(given, safe=":$")
1007 expect = '%A0$=%C1$'
1008 self.assertEqual(expect, result)
1009
1010 given = ((b'\xa0\x24', b'\xc1\x24'),)
1011 result = urllib.parse.urlencode(given, doseq=True, safe=":$")
1012 expect = '%A0$=%C1$'
1013 self.assertEqual(expect, result)
1014
1015 # Safe parameter in sequence
1016 given = ((b'\xa0\x24', (b'\xc1\x24', 0xd, 42)),)
1017 expect = '%A0$=%C1$&%A0$=13&%A0$=42'
1018 result = urllib.parse.urlencode(given, True, safe=":$")
1019 self.assertEqual(expect, result)
1020
1021 # Test all above in latin-1 encoding
1022
1023 given = ((b'\xa0\x24', b'\xc1\x24'),)
1024 result = urllib.parse.urlencode(given, safe=":$",
1025 encoding="latin-1")
1026 expect = '%A0$=%C1$'
1027 self.assertEqual(expect, result)
1028
1029 given = ((b'\xa0\x24', b'\xc1\x24'),)
1030 expect = '%A0$=%C1$'
1031 result = urllib.parse.urlencode(given, doseq=True, safe=":$",
1032 encoding="latin-1")
1033
1034 given = ((b'\xa0\x24', (b'\xc1\x24', 0xd, 42)),)
1035 expect = '%A0$=%C1$&%A0$=13&%A0$=42'
1036 result = urllib.parse.urlencode(given, True, safe=":$",
1037 encoding="latin-1")
1038 self.assertEqual(expect, result)
1039
Brett Cannon74bfd702003-04-25 09:39:47 +00001040class Pathname_Tests(unittest.TestCase):
1041 """Test pathname2url() and url2pathname()"""
1042
1043 def test_basic(self):
1044 # Make sure simple tests pass
1045 expected_path = os.path.join("parts", "of", "a", "path")
1046 expected_url = "parts/of/a/path"
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001047 result = urllib.request.pathname2url(expected_path)
Brett Cannon74bfd702003-04-25 09:39:47 +00001048 self.assertEqual(expected_url, result,
1049 "pathname2url() failed; %s != %s" %
1050 (result, expected_url))
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001051 result = urllib.request.url2pathname(expected_url)
Brett Cannon74bfd702003-04-25 09:39:47 +00001052 self.assertEqual(expected_path, result,
1053 "url2pathame() failed; %s != %s" %
1054 (result, expected_path))
1055
1056 def test_quoting(self):
1057 # Test automatic quoting and unquoting works for pathnam2url() and
1058 # url2pathname() respectively
1059 given = os.path.join("needs", "quot=ing", "here")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001060 expect = "needs/%s/here" % urllib.parse.quote("quot=ing")
1061 result = urllib.request.pathname2url(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001062 self.assertEqual(expect, result,
1063 "pathname2url() failed; %s != %s" %
1064 (expect, result))
1065 expect = given
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001066 result = urllib.request.url2pathname(result)
Brett Cannon74bfd702003-04-25 09:39:47 +00001067 self.assertEqual(expect, result,
1068 "url2pathname() failed; %s != %s" %
1069 (expect, result))
1070 given = os.path.join("make sure", "using_quote")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001071 expect = "%s/using_quote" % urllib.parse.quote("make sure")
1072 result = urllib.request.pathname2url(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001073 self.assertEqual(expect, result,
1074 "pathname2url() failed; %s != %s" %
1075 (expect, result))
1076 given = "make+sure/using_unquote"
1077 expect = os.path.join("make+sure", "using_unquote")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001078 result = urllib.request.url2pathname(given)
Brett Cannon74bfd702003-04-25 09:39:47 +00001079 self.assertEqual(expect, result,
1080 "url2pathname() failed; %s != %s" %
1081 (expect, result))
Tim Petersc2659cf2003-05-12 20:19:37 +00001082
Senthil Kumaran2d2ea1b2011-04-14 13:16:30 +08001083 @unittest.skipUnless(sys.platform == 'win32',
1084 'test specific to the urllib.url2path function.')
1085 def test_ntpath(self):
1086 given = ('/C:/', '///C:/', '/C|//')
1087 expect = 'C:\\'
1088 for url in given:
1089 result = urllib.request.url2pathname(url)
1090 self.assertEqual(expect, result,
1091 'urllib.request..url2pathname() failed; %s != %s' %
1092 (expect, result))
1093 given = '///C|/path'
1094 expect = 'C:\\path'
1095 result = urllib.request.url2pathname(given)
1096 self.assertEqual(expect, result,
1097 'urllib.request.url2pathname() failed; %s != %s' %
1098 (expect, result))
1099
Senthil Kumaraneaaec272009-03-30 21:54:41 +00001100class Utility_Tests(unittest.TestCase):
1101 """Testcase to test the various utility functions in the urllib."""
1102
1103 def test_splitpasswd(self):
1104 """Some of password examples are not sensible, but it is added to
1105 confirming to RFC2617 and addressing issue4675.
1106 """
1107 self.assertEqual(('user', 'ab'),urllib.parse.splitpasswd('user:ab'))
1108 self.assertEqual(('user', 'a\nb'),urllib.parse.splitpasswd('user:a\nb'))
1109 self.assertEqual(('user', 'a\tb'),urllib.parse.splitpasswd('user:a\tb'))
1110 self.assertEqual(('user', 'a\rb'),urllib.parse.splitpasswd('user:a\rb'))
1111 self.assertEqual(('user', 'a\fb'),urllib.parse.splitpasswd('user:a\fb'))
1112 self.assertEqual(('user', 'a\vb'),urllib.parse.splitpasswd('user:a\vb'))
1113 self.assertEqual(('user', 'a:b'),urllib.parse.splitpasswd('user:a:b'))
1114
Senthil Kumaran1b7da512011-10-06 00:32:02 +08001115 def test_thishost(self):
1116 """Test the urllib.request.thishost utility function returns a tuple"""
1117 self.assertIsInstance(urllib.request.thishost(), tuple)
1118
Senthil Kumaran690ce9b2009-05-05 18:41:13 +00001119
1120class URLopener_Tests(unittest.TestCase):
1121 """Testcase to test the open method of URLopener class."""
1122
1123 def test_quoted_open(self):
1124 class DummyURLopener(urllib.request.URLopener):
1125 def open_spam(self, url):
1126 return url
1127
1128 self.assertEqual(DummyURLopener().open(
1129 'spam://example/ /'),'//example/%20/')
1130
Senthil Kumaran734f0592010-02-20 22:19:04 +00001131 # test the safe characters are not quoted by urlopen
1132 self.assertEqual(DummyURLopener().open(
1133 "spam://c:|windows%/:=&?~#+!$,;'@()*[]|/path/"),
1134 "//c:|windows%/:=&?~#+!$,;'@()*[]|/path/")
1135
Guido van Rossume7ba4952007-06-06 23:52:48 +00001136# Just commented them out.
1137# Can't really tell why keep failing in windows and sparc.
Ezio Melotti13925002011-03-16 11:05:33 +02001138# Everywhere else they work ok, but on those machines, sometimes
Guido van Rossume7ba4952007-06-06 23:52:48 +00001139# fail in one of the tests, sometimes in other. I have a linux, and
1140# the tests go ok.
1141# If anybody has one of the problematic enviroments, please help!
1142# . Facundo
1143#
1144# def server(evt):
Georg Brandlf78e02b2008-06-10 17:40:04 +00001145# import socket, time
Guido van Rossume7ba4952007-06-06 23:52:48 +00001146# serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1147# serv.settimeout(3)
1148# serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1149# serv.bind(("", 9093))
1150# serv.listen(5)
1151# try:
1152# conn, addr = serv.accept()
1153# conn.send("1 Hola mundo\n")
1154# cantdata = 0
1155# while cantdata < 13:
1156# data = conn.recv(13-cantdata)
1157# cantdata += len(data)
1158# time.sleep(.3)
1159# conn.send("2 No more lines\n")
1160# conn.close()
1161# except socket.timeout:
1162# pass
1163# finally:
1164# serv.close()
1165# evt.set()
1166#
1167# class FTPWrapperTests(unittest.TestCase):
1168#
1169# def setUp(self):
Georg Brandlf78e02b2008-06-10 17:40:04 +00001170# import ftplib, time, threading
Guido van Rossume7ba4952007-06-06 23:52:48 +00001171# ftplib.FTP.port = 9093
1172# self.evt = threading.Event()
1173# threading.Thread(target=server, args=(self.evt,)).start()
1174# time.sleep(.1)
1175#
1176# def tearDown(self):
1177# self.evt.wait()
1178#
1179# def testBasic(self):
1180# # connects
1181# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
Georg Brandlf78e02b2008-06-10 17:40:04 +00001182# ftp.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001183#
1184# def testTimeoutNone(self):
Georg Brandlf78e02b2008-06-10 17:40:04 +00001185# # global default timeout is ignored
1186# import socket
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001187# self.assertTrue(socket.getdefaulttimeout() is None)
Guido van Rossume7ba4952007-06-06 23:52:48 +00001188# socket.setdefaulttimeout(30)
1189# try:
1190# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
1191# finally:
Georg Brandlf78e02b2008-06-10 17:40:04 +00001192# socket.setdefaulttimeout(None)
Guido van Rossume7ba4952007-06-06 23:52:48 +00001193# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
Georg Brandlf78e02b2008-06-10 17:40:04 +00001194# ftp.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001195#
Georg Brandlf78e02b2008-06-10 17:40:04 +00001196# def testTimeoutDefault(self):
1197# # global default timeout is used
1198# import socket
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001199# self.assertTrue(socket.getdefaulttimeout() is None)
Georg Brandlf78e02b2008-06-10 17:40:04 +00001200# socket.setdefaulttimeout(30)
1201# try:
1202# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [])
1203# finally:
1204# socket.setdefaulttimeout(None)
1205# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
1206# ftp.close()
1207#
1208# def testTimeoutValue(self):
1209# ftp = urllib.ftpwrapper("myuser", "mypass", "localhost", 9093, [],
1210# timeout=30)
1211# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
1212# ftp.close()
Guido van Rossume7ba4952007-06-06 23:52:48 +00001213
Senthil Kumarande49d642011-10-16 23:54:44 +08001214class RequestTests(unittest.TestCase):
1215 """Unit tests for urllib.request.Request."""
1216
1217 def test_default_values(self):
1218 Request = urllib.request.Request
1219 request = Request("http://www.python.org")
1220 self.assertEqual(request.get_method(), 'GET')
1221 request = Request("http://www.python.org", {})
1222 self.assertEqual(request.get_method(), 'POST')
1223
1224 def test_with_method_arg(self):
1225 Request = urllib.request.Request
1226 request = Request("http://www.python.org", method='HEAD')
1227 self.assertEqual(request.method, 'HEAD')
1228 self.assertEqual(request.get_method(), 'HEAD')
1229 request = Request("http://www.python.org", {}, method='HEAD')
1230 self.assertEqual(request.method, 'HEAD')
1231 self.assertEqual(request.get_method(), 'HEAD')
1232 request = Request("http://www.python.org", method='GET')
1233 self.assertEqual(request.get_method(), 'GET')
1234 request.method = 'HEAD'
1235 self.assertEqual(request.get_method(), 'HEAD')
Skip Montanaro080c9972001-01-28 21:12:22 +00001236
1237
Brett Cannon74bfd702003-04-25 09:39:47 +00001238def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001239 support.run_unittest(
Walter Dörwald21d3a322003-05-01 17:45:56 +00001240 urlopen_FileTests,
Hye-Shik Chang39aef792004-06-05 13:30:56 +00001241 urlopen_HttpTests,
Walter Dörwald21d3a322003-05-01 17:45:56 +00001242 urlretrieve_FileTests,
Senthil Kumarance260142011-11-01 01:35:17 +08001243 urlretrieve_HttpTests,
Benjamin Peterson9bc93512008-09-22 22:10:59 +00001244 ProxyTests,
Walter Dörwald21d3a322003-05-01 17:45:56 +00001245 QuotingTests,
1246 UnquotingTests,
1247 urlencode_Tests,
Guido van Rossume7ba4952007-06-06 23:52:48 +00001248 Pathname_Tests,
Senthil Kumaraneaaec272009-03-30 21:54:41 +00001249 Utility_Tests,
Senthil Kumaran690ce9b2009-05-05 18:41:13 +00001250 URLopener_Tests,
Guido van Rossume7ba4952007-06-06 23:52:48 +00001251 #FTPWrapperTests,
Senthil Kumarande49d642011-10-16 23:54:44 +08001252 RequestTests,
Walter Dörwald21d3a322003-05-01 17:45:56 +00001253 )
Brett Cannon74bfd702003-04-25 09:39:47 +00001254
1255
1256
1257if __name__ == '__main__':
1258 test_main()