diff --git a/src/urllib3/request.py b/src/urllib3/request.py index 398386a5b9..3b4cf99922 100644 --- a/src/urllib3/request.py +++ b/src/urllib3/request.py @@ -1,6 +1,9 @@ from __future__ import absolute_import +import sys + from .filepost import encode_multipart_formdata +from .packages import six from .packages.six.moves.urllib.parse import urlencode __all__ = ["RequestMethods"] @@ -168,3 +171,21 @@ def request_encode_body( extra_kw.update(urlopen_kw) return self.urlopen(method, url, **extra_kw) + + +if not six.PY2: + + class RequestModule(sys.modules[__name__].__class__): + def __call__(self, *args, **kwargs): + """ + If user tries to call this module directly urllib3 v2.x style raise an error to the user + suggesting they may need urllib3 v2 + """ + raise TypeError( + "'module' object is not callable\n" + "urllib3.request() method is not supported in this release, " + "upgrade to urllib3 v2 to use it\n" + "see https://urllib3.readthedocs.io/en/stable/v2-migration-guide.html" + ) + + sys.modules[__name__].__class__ = RequestModule diff --git a/test/test_request.py b/test/test_request.py new file mode 100644 index 0000000000..1db819dc28 --- /dev/null +++ b/test/test_request.py @@ -0,0 +1,26 @@ +import types + +import pytest + +import urllib3 +from urllib3.packages import six + + +@pytest.mark.skipif( + six.PY2, + reason="This behaviour isn't added when running urllib3 in Python 2", +) +class TestRequestImport(object): + def test_request_import_error(self): + """Ensure an appropriate error is raised to the user + if they try and run urllib3.request()""" + with pytest.raises(TypeError) as exc_info: + urllib3.request(1, a=2) + assert "urllib3 v2" in exc_info.value.args[0] + + def test_request_module_properties(self): + """Ensure properties of the overridden request module + are still present""" + assert isinstance(urllib3.request, types.ModuleType) + expected_attrs = {"RequestMethods", "encode_multipart_formdata", "urlencode"} + assert set(dir(urllib3.request)).issuperset(expected_attrs)