Repository: encode/httpx
Pull request #1070 (2020-07-20 10:18:10)

Drop private Origin model
Since we don't expose the `Origin` model, and only use it in one place, this PR now switches that single usage to a plain util function.


Patch:
diff --git a/docs/api.md b/docs/api.md
index 2ad1f9f..a34d366 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -120,26 +120,9 @@ what gets sent over the wire.*
 * `.full_path` - **str**
 * `.fragment` - **str**
 * `.is_ssl` - **bool**
-* `.origin` - **Origin**
 * `.is_absolute_url` - **bool**
 * `.is_relative_url` - **bool**
 * `def .copy_with([scheme], [authority], [path], [query], [fragment])` - **URL**
-* `def .resolve_with(url)` - **URL**
-
-## `Origin`
-
-*A normalized, IDNA supporting set of scheme/host/port info.*
-
-```python
->>> Origin('https://example.org') == Origin('HTTPS://EXAMPLE.ORG:443')
-True
-```
-
-* `def __init__(url)`
-* `.scheme` - **str**
-* `.is_ssl` - **bool**
-* `.host` - **str**
-* `.port` - **int**
 
 ## `Headers`
 
diff --git a/httpx/_client.py b/httpx/_client.py
index d4ec7aa..66b4805 100644
--- a/httpx/_client.py
+++ b/httpx/_client.py
@@ -26,7 +26,7 @@ from ._exceptions import (
     TooManyRedirects,
     map_exceptions,
 )
-from ._models import URL, Cookies, Headers, Origin, QueryParams, Request, Response
+from ._models import URL, Cookies, Headers, QueryParams, Request, Response
 from ._status_codes import codes
 from ._transports.asgi import ASGITransport
 from ._transports.wsgi import WSGITransport
@@ -47,6 +47,7 @@ from ._utils import (
     NetRCInfo,
     get_environment_proxies,
     get_logger,
+    same_origin,
     should_not_be_proxied,
 )
 
@@ -346,7 +347,7 @@ class BaseClient:
         """
         headers = Headers(request.headers)
 
-        if Origin(url) != Origin(request.url):
+        if not same_origin(url, request.url):
             # Strip Authorization headers when responses are redirected away from
             # the origin.
             headers.pop("Authorization", None)
diff --git a/httpx/_models.py b/httpx/_models.py
index dca3eff..b992d9d 100644
--- a/httpx/_models.py
+++ b/httpx/_models.py
@@ -234,37 +234,6 @@ class URL:
         return f"{class_name}({url_str!r})"
 
 
-class Origin:
-    """
-    The URL scheme and authority information, as a comparable, hashable object.
-    """
-
-    def __init__(self, url: URLTypes) -> None:
-        if not isinstance(url, URL):
-            url = URL(url)
-        self.scheme = url.scheme
-        self.is_ssl = url.is_ssl
-        self.host = url.host
-        self.port = url.port
-
-    def __eq__(self, other: typing.Any) -> bool:
-        return (
-            isinstance(other, self.__class__)
-            and self.scheme == other.scheme
-            and self.host == other.host
-            and self.port == other.port
-        )
-
-    def __hash__(self) -> int:
-        return hash((self.scheme, self.host, self.port))
-
-    def __repr__(self) -> str:
-        class_name = self.__class__.__name__
-        return (
-            f"{class_name}(scheme={self.scheme!r} host={self.host!r} port={self.port})"
-        )
-
-
 class QueryParams(typing.Mapping[str, str]):
     """
     URL query parameters, as a multi-dict.
diff --git a/httpx/_utils.py b/httpx/_utils.py
index 8c01eb1..b85ec75 100644
--- a/httpx/_utils.py
+++ b/httpx/_utils.py
@@ -260,8 +260,18 @@ def get_logger(name: str) -> Logger:
     return typing.cast(Logger, logger)
 
 
+def same_origin(url: "URL", other: "URL") -> bool:
+    """
+    Return 'True' if the given URLs share the same origin.
+    """
+    return (
+        url.scheme == other.scheme and url.host == other.host and url.port == other.port
+    )
+
+
 def should_not_be_proxied(url: "URL") -> bool:
-    """ Return True if url should not be proxied,
+    """
+    Return True if url should not be proxied,
     return False otherwise.
     """
     no_proxy = getproxies().get("no")


Test patch:
diff --git a/tests/models/test_url.py b/tests/models/test_url.py
index 7910a8e..de9da7d 100644
--- a/tests/models/test_url.py
+++ b/tests/models/test_url.py
@@ -1,7 +1,6 @@
 import pytest
 
 from httpx import URL, InvalidURL
-from httpx._models import Origin
 
 
 @pytest.mark.parametrize(
@@ -177,27 +176,6 @@ def test_url_set():
     assert all(url in urls for url in url_set)
 
 
-def test_origin_from_url_string():
-    origin = Origin("https://example.com")
-    assert origin.scheme == "https"
-    assert origin.is_ssl
-    assert origin.host == "example.com"
-    assert origin.port == 443
-
-
-def test_origin_repr():
-    origin = Origin("https://example.com:8080")
-    assert str(origin) == "Origin(scheme='https' host='example.com' port=8080)"
-
-
-def test_origin_equal():
-    origin1 = Origin("https://example.com")
-    origin2 = Origin("https://example.com")
-    assert origin1 is not origin2
-    assert origin1 == origin2
-    assert len({origin1, origin2}) == 1
-
-
 def test_url_copywith_for_authority():
     copy_with_kwargs = {
         "username": "username",
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 70fc1d6..fa30ee8 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -12,6 +12,7 @@ from httpx._utils import (
     guess_json_utf,
     obfuscate_sensitive_headers,
     parse_header_links,
+    same_origin,
     should_not_be_proxied,
 )
 from tests.utils import override_log_level
@@ -294,3 +295,15 @@ def test_should_not_be_proxied(url, no_proxy, expected):
     os.environ.update(no_proxy)
     parsed_url = httpx.URL(url)
     assert should_not_be_proxied(parsed_url) == expected
+
+
+def test_same_origin():
+    origin1 = httpx.URL("https://example.com")
+    origin2 = httpx.URL("HTTPS://EXAMPLE.COM:443")
+    assert same_origin(origin1, origin2)
+
+
+def test_not_same_origin():
+    origin1 = httpx.URL("https://example.com")
+    origin2 = httpx.URL("HTTP://EXAMPLE.COM")
+    assert not same_origin(origin1, origin2)