Repository: urllib3/urllib3

Issue:
Start using towncrier for tracking changes
This will make sure that we don't miss anything. Asking if anyone on our team has configured towncrier in the past :)


Discussion:
I did :)

Are we OK with the five default categories or do we want to customize that? https://towncrier.readthedocs.io/en/actual-freaking-docs/quickstart.html#creating-news-fragments
Can we add a section for breaking changes?

Resolving patch:
diff --git a/docs/conf.py b/docs/conf.py
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -9,6 +9,18 @@
 root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
 sys.path.insert(0, root_path)
 
+# https://docs.readthedocs.io/en/stable/builds.html#build-environment
+if "READTHEDOCS" in os.environ:
+    import glob
+
+    if glob.glob("../changelog/*.*.rst"):
+        print("-- Found changes; running towncrier --", flush=True)
+        import subprocess
+
+        subprocess.run(
+            ["towncrier", "--yes", "--date", "not released yet"], cwd="..", check=True
+        )
+
 import urllib3
 
 # -- General configuration -----------------------------------------------------
diff --git a/src/urllib3/response.py b/src/urllib3/response.py
--- a/src/urllib3/response.py
+++ b/src/urllib3/response.py
@@ -199,6 +199,7 @@ def __init__(
         version: int,
         reason: Optional[str],
         decode_content: bool,
+        request_url: Optional[str],
     ) -> None:
         if isinstance(headers, HTTPHeaderDict):
             self.headers = headers
@@ -208,6 +209,7 @@ def __init__(
         self.version = version
         self.reason = reason
         self.decode_content = decode_content
+        self.request_url: Optional[str]
 
         self.chunked = False
         tr_enc = self.headers.get("transfer-encoding", "").lower()
@@ -412,6 +414,7 @@ def __init__(
             version=version,
             reason=reason,
             decode_content=decode_content,
+            request_url=request_url,
         )
 
         self.retries = retries
@@ -423,7 +426,10 @@ def __init__(
         self._original_response = original_response
         self._fp_bytes_read = 0
         self.msg = msg
-        self._request_url = request_url
+        if self.retries is not None and self.retries.history:
+            self._request_url = self.retries.history[-1].redirect_location
+        else:
+            self._request_url = request_url
 
         if body and isinstance(body, (str, bytes)):
             self._body = body
@@ -901,10 +907,11 @@ def url(self) -> Optional[str]:
         If the request that generated this response redirected, this method
         will return the final redirect location.
         """
-        if self.retries is not None and self.retries.history:
-            return self.retries.history[-1].redirect_location
-        else:
-            return self._request_url
+        return self._request_url
+
+    @url.setter
+    def url(self, url: str) -> None:
+        self._request_url = url
 
     def __iter__(self) -> Iterator[bytes]:
         buffer: List[bytes] = []


Test patch:
diff --git a/test/test_response.py b/test/test_response.py
--- a/test/test_response.py
+++ b/test/test_response.py
@@ -869,6 +869,14 @@ def test_geturl(self):
         resp = HTTPResponse(fp, request_url=request_url)
         assert resp.geturl() == request_url
 
+    def test_url(self):
+        fp = BytesIO(b"")
+        request_url = "https://example.com"
+        resp = HTTPResponse(fp, request_url=request_url)
+        assert resp.url == request_url
+        resp.url = "https://anotherurl.com"
+        assert resp.url == "https://anotherurl.com"
+
     def test_geturl_retries(self):
         fp = BytesIO(b"")
         resp = HTTPResponse(fp, request_url="http://example.com")