Skip to content

Commit 9cda4c0

Browse files
authored
[corehttp] Misc updates (#34394)
These updates are similar updates that were made to azure-core previously. - Changed ServiceNamedKey to be a class instead of a namedtuple to fix a verifytypes issue. - Typing/linting updates. - Async auth policy lock refactoring. - Refactored streaming tests to remove requirement on external endpoint. Signed-off-by: Paul Van Eck <[email protected]>
1 parent 143d2ff commit 9cda4c0

File tree

11 files changed

+315
-75
lines changed

11 files changed

+315
-75
lines changed

sdk/core/corehttp/corehttp/credentials.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# license information.
55
# -------------------------------------------------------------------------
66
from __future__ import annotations
7-
from collections import namedtuple
87
from types import TracebackType
98
from typing import Any, NamedTuple, Optional, AsyncContextManager, Type
109
from typing_extensions import Protocol, runtime_checkable
@@ -40,7 +39,12 @@ def get_token(self, *scopes: str, claims: Optional[str] = None, **kwargs: Any) -
4039
...
4140

4241

43-
ServiceNamedKey = namedtuple("ServiceNamedKey", ["name", "key"])
42+
class ServiceNamedKey(NamedTuple):
43+
"""Represents a name and key pair."""
44+
45+
name: str
46+
key: str
47+
4448

4549
__all__ = [
4650
"AccessToken",

sdk/core/corehttp/corehttp/runtime/_base.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
# IN THE SOFTWARE.
2424
#
2525
# --------------------------------------------------------------------------
26-
from typing import Any
26+
from typing import Any, Dict
2727
from urllib.parse import urlparse
2828

2929

30-
def _format_url_section(template, **kwargs):
30+
def _format_url_section(template, **kwargs: Dict[str, str]) -> str:
3131
"""String format the template with the kwargs, auto-skip sections of the template that are NOT in the kwargs.
3232
3333
By default in Python, "format" will raise a KeyError if a template element is not found. Here the section between
@@ -53,6 +53,7 @@ def _format_url_section(template, **kwargs):
5353
f"The value provided for the url part '{template}' was incorrect, and resulted in an invalid url"
5454
) from key
5555
last_template = template
56+
return last_template
5657

5758

5859
def _urljoin(base_url: str, stub_url: str) -> str:
@@ -71,7 +72,7 @@ def _urljoin(base_url: str, stub_url: str) -> str:
7172
stub_url_path = split_url.pop(0)
7273
stub_url_query = split_url.pop() if split_url else None
7374

74-
# Note that _replace is a public API named that way to avoid to avoid conflicts in namedtuple
75+
# Note that _replace is a public API named that way to avoid conflicts in namedtuple
7576
# https://docs.python.org/3/library/collections.html?highlight=namedtuple#collections.namedtuple
7677
parsed_base_url = parsed_base_url._replace(
7778
path=parsed_base_url.path.rstrip("/") + "/" + stub_url_path,

sdk/core/corehttp/corehttp/runtime/policies/_authentication_async.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# license information.
55
# -------------------------------------------------------------------------
66
from __future__ import annotations
7-
import asyncio
87
import time
98
from typing import TYPE_CHECKING, Any, Awaitable, Optional, cast, TypeVar
109

@@ -14,6 +13,7 @@
1413
from ._base_async import AsyncHTTPPolicy
1514
from ._authentication import _BearerTokenCredentialPolicyBase
1615
from ...rest import AsyncHttpResponse, HttpRequest
16+
from ...utils._utils import get_running_async_lock
1717

1818
if TYPE_CHECKING:
1919
from ...credentials import AsyncTokenCredential
@@ -36,10 +36,16 @@ def __init__(
3636
) -> None:
3737
super().__init__()
3838
self._credential = credential
39-
self._lock = asyncio.Lock()
39+
self._lock_instance = None
4040
self._scopes = scopes
4141
self._token: Optional["AccessToken"] = None
4242

43+
@property
44+
def _lock(self):
45+
if self._lock_instance is None:
46+
self._lock_instance = get_running_async_lock()
47+
return self._lock_instance
48+
4349
async def on_request(self, request: PipelineRequest[HTTPRequestType]) -> None:
4450
"""Adds a bearer token Authorization header to request and sends request to next policy.
4551

sdk/core/corehttp/corehttp/runtime/policies/_universal.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import xml.etree.ElementTree as ET
3636
import types
3737
import re
38-
from typing import IO, cast, Union, Optional, AnyStr, Dict, Any, Mapping, TYPE_CHECKING
38+
from typing import IO, cast, Union, Optional, AnyStr, Dict, Any, MutableMapping, TYPE_CHECKING
3939

4040
from ... import __version__ as core_version
4141
from ...exceptions import DecodeError
@@ -449,12 +449,12 @@ class ProxyPolicy(SansIOHTTPPolicy[HTTPRequestType, HTTPResponseType]):
449449
Dictionary mapping protocol or protocol and host to the URL of the proxy
450450
to be used on each Request.
451451
452-
:param dict proxies: Maps protocol or protocol and hostname to the URL
452+
:param MutableMapping proxies: Maps protocol or protocol and hostname to the URL
453453
of the proxy.
454454
"""
455455

456456
def __init__(
457-
self, proxies: Optional[Mapping[str, str]] = None, **kwargs: Any
457+
self, proxies: Optional[MutableMapping[str, str]] = None, **kwargs: Any
458458
): # pylint: disable=unused-argument,super-init-not-called
459459
self.proxies = proxies
460460

sdk/core/corehttp/corehttp/transport/requests/_bigger_block_size_http_adapters.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,21 @@
2525
# --------------------------------------------------------------------------
2626

2727
import sys
28+
from typing import MutableMapping, Optional
29+
2830
from requests.adapters import HTTPAdapter # pylint: disable=all
31+
from urllib3.connectionpool import ConnectionPool
2932

3033

3134
class BiggerBlockSizeHTTPAdapter(HTTPAdapter):
32-
def get_connection(self, url, proxies=None):
35+
def get_connection(self, url: str, proxies: Optional[MutableMapping[str, str]] = None) -> ConnectionPool:
3336
"""Returns a urllib3 connection for the given URL. This should not be
3437
called from user code, and is only exposed for use when subclassing the
3538
:class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
3639
3740
:param str url: The URL to connect to.
3841
:param dict proxies: (optional) A Requests-style dictionary of proxies used on this request.
39-
:rtype: urllib3.ConnectionPool
42+
:rtype: urllib3.connectionpool.ConnectionPool
4043
:returns: The urllib3 ConnectionPool for the given URL.
4144
"""
4245
conn = super(BiggerBlockSizeHTTPAdapter, self).get_connection(url, proxies)

sdk/core/corehttp/corehttp/utils/_utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import datetime
88
from typing import (
99
Any,
10+
AsyncContextManager,
1011
Iterable,
1112
Iterator,
1213
Mapping,
@@ -164,3 +165,21 @@ def get_file_items(files: "FilesType") -> Sequence[Tuple[str, "FileType"]]:
164165
# though realistically it is ordered python 3.7 and after
165166
return cast(Sequence[Tuple[str, "FileType"]], files.items())
166167
return files
168+
169+
170+
def get_running_async_lock() -> AsyncContextManager:
171+
"""Get a lock instance from the async library that the current context is running under.
172+
:return: An instance of the running async library's Lock class.
173+
:rtype: AsyncContextManager
174+
:raises: RuntimeError if the current context is not running under an async library.
175+
"""
176+
177+
try:
178+
import asyncio
179+
180+
# Check if we are running in an asyncio event loop.
181+
asyncio.get_running_loop()
182+
return asyncio.Lock()
183+
except RuntimeError as err:
184+
# Otherwise, assume we are running in a trio event loop, but this currently isn't supported.
185+
raise RuntimeError("An asyncio event loop is required.") from err

sdk/core/corehttp/tests/async_tests/test_authentication_async.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,14 @@ async def get_token(self, *scopes, **kwargs):
252252

253253
cred = TestTokenCredential()
254254
await cred.get_token("scope")
255+
256+
257+
@pytest.mark.asyncio
258+
async def test_async_token_credential_asyncio_lock():
259+
auth_policy = AsyncBearerTokenCredentialPolicy(Mock(), "scope")
260+
assert isinstance(auth_policy._lock, asyncio.Lock)
261+
262+
263+
def test_async_token_credential_sync():
264+
"""Verify that AsyncBearerTokenCredentialPolicy can be constructed in a synchronous context."""
265+
AsyncBearerTokenCredentialPolicy(Mock(), "scope")

0 commit comments

Comments
 (0)