-
Notifications
You must be signed in to change notification settings - Fork 7
Add switchable HTTP transports #2877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
92459c6
e9041ec
c6c313b
5b3fd2c
fbff605
c307654
e2bf8ce
b977b52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,6 +54,7 @@ hmac | |
| html | ||
| http | ||
| https | ||
| httpx | ||
| iff | ||
| io | ||
| issuecomment | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| """HTTP transport implementations for VWS clients.""" | ||
|
|
||
| from typing import Protocol, runtime_checkable | ||
|
|
||
| import httpx | ||
| import requests | ||
| from beartype import BeartypeConf, beartype | ||
|
|
||
| from vws.response import Response | ||
|
|
||
|
|
||
| @runtime_checkable | ||
| class Transport(Protocol): | ||
| """Protocol for HTTP transports used by VWS clients. | ||
|
|
||
| A transport is a callable that makes an HTTP request and | ||
| returns a ``Response``. | ||
| """ | ||
|
|
||
| def __call__( | ||
| self, | ||
| *, | ||
| method: str, | ||
| url: str, | ||
| headers: dict[str, str], | ||
| data: bytes, | ||
| timeout: float | tuple[float, float], | ||
| ) -> Response: | ||
| """Make an HTTP request. | ||
|
|
||
| Args: | ||
| method: The HTTP method (e.g. "GET", "POST"). | ||
| url: The full URL to request. | ||
| headers: Headers to send with the request. | ||
| data: The request body as bytes. | ||
| timeout: The timeout for the request. A float | ||
| sets both the connect and read timeouts. A | ||
| (connect, read) tuple sets them individually. | ||
|
|
||
| Returns: | ||
| A Response populated from the HTTP response. | ||
| """ | ||
| ... # pylint: disable=unnecessary-ellipsis | ||
|
|
||
|
|
||
| @beartype(conf=BeartypeConf(is_pep484_tower=True)) | ||
| class RequestsTransport: | ||
| """HTTP transport using the ``requests`` library. | ||
|
|
||
| This is the default transport. | ||
| """ | ||
|
|
||
| def __call__( | ||
| self, | ||
| *, | ||
| method: str, | ||
| url: str, | ||
| headers: dict[str, str], | ||
| data: bytes, | ||
| timeout: float | tuple[float, float], | ||
| ) -> Response: | ||
| """Make an HTTP request using ``requests``. | ||
|
|
||
| Args: | ||
| method: The HTTP method. | ||
| url: The full URL. | ||
| headers: Request headers. | ||
| data: The request body. | ||
| timeout: The request timeout. | ||
|
|
||
| Returns: | ||
| A Response populated from the requests response. | ||
| """ | ||
| requests_response = requests.request( | ||
| method=method, | ||
| url=url, | ||
| headers=headers, | ||
| data=data, | ||
| timeout=timeout, | ||
| ) | ||
|
|
||
| return Response( | ||
| text=requests_response.text, | ||
| url=requests_response.url, | ||
| status_code=requests_response.status_code, | ||
| headers=dict(requests_response.headers), | ||
| request_body=requests_response.request.body, | ||
| tell_position=requests_response.raw.tell(), | ||
| content=bytes(requests_response.content), | ||
| ) | ||
|
|
||
|
|
||
| @beartype(conf=BeartypeConf(is_pep484_tower=True)) | ||
| class HTTPXTransport: | ||
| """HTTP transport using the ``httpx`` library. | ||
|
|
||
| Use this transport for environments where ``httpx`` is | ||
| preferred over ``requests``. | ||
| """ | ||
|
|
||
| def __call__( | ||
| self, | ||
| *, | ||
| method: str, | ||
| url: str, | ||
| headers: dict[str, str], | ||
| data: bytes, | ||
| timeout: float | tuple[float, float], | ||
| ) -> Response: | ||
| """Make an HTTP request using ``httpx``. | ||
|
|
||
| Args: | ||
| method: The HTTP method. | ||
| url: The full URL. | ||
| headers: Request headers. | ||
| data: The request body. | ||
| timeout: The request timeout. | ||
|
|
||
| Returns: | ||
| A Response populated from the httpx response. | ||
| """ | ||
| if isinstance(timeout, tuple): | ||
| connect_timeout, read_timeout = timeout | ||
| httpx_timeout = httpx.Timeout( | ||
| connect=connect_timeout, | ||
| read=read_timeout, | ||
| write=None, | ||
| pool=None, | ||
| ) | ||
| else: | ||
| httpx_timeout = httpx.Timeout( | ||
| connect=timeout, | ||
| read=timeout, | ||
| write=None, | ||
| pool=None, | ||
| ) | ||
|
|
||
| httpx_response = httpx.request( | ||
| method=method, | ||
| url=url, | ||
| headers=headers, | ||
| content=data, | ||
| timeout=httpx_timeout, | ||
| follow_redirects=True, | ||
| ) | ||
|
|
||
| content = bytes(httpx_response.content) | ||
| request_content = httpx_response.request.content | ||
|
|
||
| return Response( | ||
| text=httpx_response.text, | ||
| url=str(object=httpx_response.url), | ||
| status_code=httpx_response.status_code, | ||
| headers=dict(httpx_response.headers), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HTTPXTransport produces lowercase header keys unlike RequestsTransportLow Severity
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HTTP headers are case-insensitive per RFC 7230. Both |
||
| request_body=bytes(request_content) or None, | ||
| tell_position=len(content), | ||
| content=content, | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
| TooManyRequestsError, | ||
| UnknownTargetError, | ||
| ) | ||
| from vws.transports import RequestsTransport, Transport | ||
| from vws.vumark_accept import VuMarkAccept | ||
|
|
||
|
|
||
|
|
@@ -29,25 +30,31 @@ class VuMarkService: | |
|
|
||
| def __init__( | ||
| self, | ||
| *, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Breaking API change: VuMarkService now requires keyword-only argumentsHigh Severity The bare
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an intentional change.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. Fixed in e2bf8ce — the float path now explicitly sets |
||
| server_access_key: str, | ||
| server_secret_key: str, | ||
| base_vws_url: str = "https://vws.vuforia.com", | ||
| request_timeout_seconds: float | tuple[float, float] = 30.0, | ||
| transport: Transport | None = None, | ||
| ) -> None: | ||
| """ | ||
| Args: | ||
| server_access_key: A VWS server access key. | ||
| server_secret_key: A VWS server secret key. | ||
| base_vws_url: The base URL for the VWS API. | ||
| request_timeout_seconds: The timeout for each HTTP request, as | ||
| used by ``requests.request``. This can be a float to set | ||
| both the connect and read timeouts, or a (connect, read) | ||
| tuple. | ||
| request_timeout_seconds: The timeout for each | ||
| HTTP request. This can be a float to set both | ||
| the connect and read timeouts, or a | ||
| (connect, read) tuple. | ||
| transport: The HTTP transport to use for | ||
| requests. Defaults to | ||
| ``RequestsTransport()``. | ||
| """ | ||
| self._server_access_key = server_access_key | ||
| self._server_secret_key = server_secret_key | ||
| self._base_vws_url = base_vws_url | ||
| self._request_timeout_seconds = request_timeout_seconds | ||
| self._transport = transport or RequestsTransport() | ||
|
|
||
| def generate_vumark_instance( | ||
| self, | ||
|
|
@@ -109,6 +116,7 @@ def generate_vumark_instance( | |
| base_vws_url=self._base_vws_url, | ||
| request_timeout_seconds=self._request_timeout_seconds, | ||
| extra_headers={"Accept": accept}, | ||
| transport=self._transport, | ||
| ) | ||
|
|
||
| if ( | ||
|
|
||


Uh oh!
There was an error while loading. Please reload this page.