summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/urllib.request.rst35
-rw-r--r--Doc/whatsnew/3.3.rst10
-rw-r--r--Lib/test/test_urllib.py23
-rw-r--r--Lib/urllib/request.py9
-rw-r--r--Misc/NEWS4
5 files changed, 72 insertions, 9 deletions
diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst
index c08cbc6..ecb357e 100644
--- a/Doc/library/urllib.request.rst
+++ b/Doc/library/urllib.request.rst
@@ -132,7 +132,7 @@ The :mod:`urllib.request` module defines the following functions:
The following classes are provided:
-.. class:: Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False)
+.. class:: Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
This class is an abstraction of a URL request.
@@ -140,8 +140,8 @@ The following classes are provided:
*data* may be a string specifying additional data to send to the
server, or ``None`` if no such data is needed. Currently HTTP
- requests are the only ones that use *data*; the HTTP request will
- be a POST instead of a GET when the *data* parameter is provided.
+ requests are the only ones that use *data*, in order to choose between
+ ``'GET'`` and ``'POST'`` when *method* is not specified.
*data* should be a buffer in the standard
:mimetype:`application/x-www-form-urlencoded` format. The
:func:`urllib.parse.urlencode` function takes a mapping or sequence
@@ -157,8 +157,8 @@ The following classes are provided:
:mod:`urllib`'s default user agent string is
``"Python-urllib/2.6"`` (on Python 2.6).
- The final two arguments are only of interest for correct handling
- of third-party HTTP cookies:
+ The following two arguments, *origin_req_host* and *unverifiable*,
+ are only of interest for correct handling of third-party HTTP cookies:
*origin_req_host* should be the request-host of the origin
transaction, as defined by :rfc:`2965`. It defaults to
@@ -175,6 +175,13 @@ The following classes are provided:
document, and the user had no option to approve the automatic
fetching of the image, this should be true.
+ *method* should be a string that indicates the HTTP request method that
+ will be used (e.g. ``'HEAD'``). Its value is stored in the
+ :attr:`Request.method` attribute and is used by :meth:`Request.get_method()`.
+
+ .. versionchanged:: 3.3
+ :attr:`Request.method` argument is added to the Request class.
+
.. class:: OpenerDirector()
@@ -369,6 +376,15 @@ request.
boolean, indicates whether the request is unverifiable as defined
by RFC 2965.
+.. attribute:: Request.method
+
+ The HTTP request method to use. This value is used by
+ :meth:`Request.get_method` to override the computed HTTP request
+ method that would otherwise be returned. This attribute is
+ initialized with the value of the *method* argument passed to the constructor.
+
+ ..versionadded:: 3.3
+
.. method:: Request.add_data(data)
Set the :class:`Request` data to *data*. This is ignored by all handlers except
@@ -378,8 +394,13 @@ request.
.. method:: Request.get_method()
- Return a string indicating the HTTP request method. This is only meaningful for
- HTTP requests, and currently always returns ``'GET'`` or ``'POST'``.
+ Return a string indicating the HTTP request method. If
+ :attr:`Request.method` is not ``None``, return its value, otherwise return
+ ``'GET'`` if :attr:`Request.data` is ``None``, or ``'POST'`` if it's not.
+ This is only meaningful for HTTP requests.
+
+ .. versionchanged:: 3.3
+ get_method now looks at the value of :attr:`Request.method` first.
.. method:: Request.has_data()
diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst
index 6c57d72..945aa97 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -474,6 +474,16 @@ shutil
path also specifying the user/group names and not only their numeric
ids. (Contributed by Sandro Tosi in :issue:`12191`)
+urllib
+------
+
+The :class:`~urllib.request.Request` class, now accepts a *method* argument
+used by :meth:`~urllib.request.Request.get_method` to determine what HTTP method
+should be used. For example, this will send an ``'HEAD'`` request::
+
+ >>> urlopen(Request('http://www.python.org', method='HEAD'))
+
+(:issue:`1673007`)
Optimizations
=============
diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py
index 77637a6..4e34ae5 100644
--- a/Lib/test/test_urllib.py
+++ b/Lib/test/test_urllib.py
@@ -1157,6 +1157,28 @@ class URLopener_Tests(unittest.TestCase):
# self.assertEqual(ftp.ftp.sock.gettimeout(), 30)
# ftp.close()
+class RequestTests(unittest.TestCase):
+ """Unit tests for urllib.request.Request."""
+
+ def test_default_values(self):
+ Request = urllib.request.Request
+ request = Request("http://www.python.org")
+ self.assertEqual(request.get_method(), 'GET')
+ request = Request("http://www.python.org", {})
+ self.assertEqual(request.get_method(), 'POST')
+
+ def test_with_method_arg(self):
+ Request = urllib.request.Request
+ request = Request("http://www.python.org", method='HEAD')
+ self.assertEqual(request.method, 'HEAD')
+ self.assertEqual(request.get_method(), 'HEAD')
+ request = Request("http://www.python.org", {}, method='HEAD')
+ self.assertEqual(request.method, 'HEAD')
+ self.assertEqual(request.get_method(), 'HEAD')
+ request = Request("http://www.python.org", method='GET')
+ self.assertEqual(request.get_method(), 'GET')
+ request.method = 'HEAD'
+ self.assertEqual(request.get_method(), 'HEAD')
def test_main():
@@ -1172,6 +1194,7 @@ def test_main():
Utility_Tests,
URLopener_Tests,
#FTPWrapperTests,
+ RequestTests,
)
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
index a947608..65ce287 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -177,7 +177,8 @@ def request_host(request):
class Request:
def __init__(self, url, data=None, headers={},
- origin_req_host=None, unverifiable=False):
+ origin_req_host=None, unverifiable=False,
+ method=None):
# unwrap('<URL:type://host/path>') --> 'type://host/path'
self.full_url = unwrap(url)
self.full_url, self.fragment = splittag(self.full_url)
@@ -191,6 +192,7 @@ class Request:
origin_req_host = request_host(self)
self.origin_req_host = origin_req_host
self.unverifiable = unverifiable
+ self.method = method
self._parse()
def _parse(self):
@@ -202,7 +204,10 @@ class Request:
self.host = unquote(self.host)
def get_method(self):
- if self.data is not None:
+ """Return a string indicating the HTTP request method."""
+ if self.method is not None:
+ return self.method
+ elif self.data is not None:
return "POST"
else:
return "GET"
diff --git a/Misc/NEWS b/Misc/NEWS
index f02e878..f490a7a 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -304,6 +304,10 @@ Core and Builtins
Library
-------
+
+- issue #1673007: urllib2 to support HEAD request via new method argument.
+ Patch contributions by David Stanek, Patrick Westerhoff and Ezio Melotti.
+
- Issue #12386: packaging does not fail anymore when writing the RESOURCES
file.