Repository: encode/httpx

Issue:
Breaking drop of URL.raw in patch release 0.23.1
The patch release `0.23.1` included a breaking change in #2241 

The justification seems to be that "we don't use it", but `url.raw` is a public property used by other libraries including `ddtrace` 0.x versions: https://github.com/DataDog/dd-trace-py/blob/v0.61.3/ddtrace/contrib/httpx/patch.py#L41 

Can this breaking change be reverted and maybe soft-deprecated? @tomchristie @michaeloliverx 


Discussion:
Looks like this has been raised in https://github.com/encode/httpx/issues/2457 but it seems like reverting here would be more ideal (and safer) than hoping other dependencies all refactor their usage?
@developerDemetri - Would it help you folks if we released a patch version which included `url.raw` returning a `NamedTuple`? That wouldn't be a full rollback or adding `httpx.RawURL` back to the API, but we could do that quickly and easily, and it would resolve the specific case you're pointing to.
> @developerDemetri - Would it help you folks if we released a patch version which included `url.raw` returning a `NamedTuple`? That wouldn't be a full rollback or adding `httpx.RawURL` back to the API, but we could do that quickly and easily, and it would resolve the specific case you're pointing to.

Yup, that should help for our use case and anyone else relying on `url.raw` 

Resolving patch:
diff --git a/httpx/_types.py b/httpx/_types.py
--- a/httpx/_types.py
+++ b/httpx/_types.py
@@ -16,6 +16,7 @@
     Iterator,
     List,
     Mapping,
+    NamedTuple,
     Optional,
     Sequence,
     Tuple,
@@ -31,6 +32,16 @@
 
 PrimitiveData = Optional[Union[str, int, float, bool]]
 
+RawURL = NamedTuple(
+    "RawURL",
+    [
+        ("raw_scheme", bytes),
+        ("raw_host", bytes),
+        ("port", Optional[int]),
+        ("raw_path", bytes),
+    ],
+)
+
 URLTypes = Union["URL", str]
 
 QueryParamTypes = Union[
diff --git a/httpx/_urls.py b/httpx/_urls.py
--- a/httpx/_urls.py
+++ b/httpx/_urls.py
@@ -6,7 +6,7 @@
 import rfc3986.exceptions
 
 from ._exceptions import InvalidURL
-from ._types import PrimitiveData, QueryParamTypes, URLTypes
+from ._types import PrimitiveData, QueryParamTypes, RawURL, URLTypes
 from ._utils import primitive_value_to_str
 
 
@@ -311,6 +311,21 @@ def fragment(self) -> str:
         """
         return unquote(self._uri_reference.fragment or "")
 
+    @property
+    def raw(self) -> RawURL:
+        """
+        Provides the (scheme, host, port, target) for the outgoing request.
+
+        In older versions of `httpx` this was used in the low-level transport API.
+        We no longer use `RawURL`, and this property will be deprecated in a future release.
+        """
+        return RawURL(
+            self.raw_scheme,
+            self.raw_host,
+            self.port,
+            self.raw_path,
+        )
+
     @property
     def is_absolute_url(self) -> bool:
         """


Test patch:
diff --git a/tests/models/test_url.py b/tests/models/test_url.py
--- a/tests/models/test_url.py
+++ b/tests/models/test_url.py
@@ -424,3 +424,13 @@ def test_ipv6_url_from_raw_url(host):
     assert url.host == "::ffff:192.168.0.1"
     assert url.netloc == b"[::ffff:192.168.0.1]"
     assert str(url) == "https://[::ffff:192.168.0.1]/"
+
+
+def test_url_raw_compatibility():
+    url = httpx.URL("https://www.example.com/path")
+    scheme, host, port, raw_path = url.raw
+
+    assert scheme == b"https"
+    assert host == b"www.example.com"
+    assert port is None
+    assert raw_path == b"/path"