Skip to content

Commit

Permalink
Run next pylint on ACR (Azure#30950)
Browse files Browse the repository at this point in the history
  • Loading branch information
YalinLi0312 authored Jul 5, 2023
1 parent ad9ccfc commit 1366b82
Show file tree
Hide file tree
Showing 14 changed files with 81 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
# Licensed under the MIT License.
# ------------------------------------
from typing import Optional, Union

from azure.core.credentials import TokenCredential, AccessToken

from ._exchange_client import ExchangeClientAuthenticationPolicy
from ._generated import ContainerRegistry
from ._generated.models import TokenGrantType
Expand All @@ -24,8 +26,7 @@ class AnonymousACRExchangeClient(object):
:param endpoint: Azure Container Registry endpoint
:type endpoint: str
:keyword api_version: API Version. The default value is "2021-07-01". Note that overriding this default value
may result in unsupported behavior.
:keyword api_version: API Version. The default value is "2021-07-01".
:paramtype api_version: str
"""

Expand All @@ -41,7 +42,7 @@ def __init__(self, endpoint: str, **kwargs) -> None: # pylint: disable=missing-c
**kwargs
)

def get_acr_access_token(self, challenge: str, **kwargs) -> Optional[str]:
def get_acr_access_token(self, challenge: str, **kwargs) -> Optional[str]: # pylint:disable=client-method-missing-tracing-decorator
parsed_challenge = _parse_challenge(challenge)
return self.exchange_refresh_token_for_access_token(
"",
Expand All @@ -51,7 +52,7 @@ def get_acr_access_token(self, challenge: str, **kwargs) -> Optional[str]:
**kwargs
)

def exchange_refresh_token_for_access_token(
def exchange_refresh_token_for_access_token( # pylint:disable=client-method-missing-tracing-decorator
self, refresh_token: str, service: str, scope: str, grant_type: Union[str, TokenGrantType], **kwargs
) -> Optional[str]:
access_token = self._client.authentication.exchange_acr_refresh_token_for_acr_access_token( # type: ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@ def on_request(self, request: PipelineRequest) -> None:
The base implementation authorizes the request with a bearer token.
:param ~azure.core.pipeline.PipelineRequest request: the request
:return: None
:rtype: None
"""
# Future caching implementation will be included here
pass # pylint: disable=unnecessary-pass

def send(self, request: PipelineRequest) -> PipelineResponse:
"""Authorizes a request with a bearer token, possibly handling an authentication challenge
:param ~azure.core.pipeline.PipelineRequest request: the request
:param ~azure.core.pipeline.PipelineRequest request: The pipeline request object.
:return: The pipeline response object.
:rtype: ~azure.core.pipeline.PipelineResponse
"""
_enforce_https(request)

Expand Down Expand Up @@ -70,8 +74,9 @@ def on_challenge(self, request: PipelineRequest, response: PipelineResponse, cha
:param ~azure.core.pipeline.PipelineResponse response: the resource provider's response
:param str challenge: response's WWW-Authenticate header, unparsed. It may contain multiple challenges.
:returns: a bool indicating whether the policy should send the request
:rtype: bool
"""
# pylint:disable=unused-argument, no-self-use
# pylint:disable=unused-argument

access_token = self._exchange_client.get_acr_access_token(challenge)
if access_token is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ class ContainerRegistryBaseClient(object):
:param credential: Token credential for authenticating requests with Azure, or None in anonymous access
:type credential: ~azure.core.credentials.TokenCredential or None
:keyword credential_scopes: URL for credential authentication if different from the default
:paramtype credential_scopes: List[str]
:keyword api_version: API Version. The default value is "2021-07-01". Note that overriding this default value
may result in unsupported behavior.
:paramtype credential_scopes: list[str]
:keyword api_version: API Version. The default value is "2021-07-01".
:paramtype api_version: str
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ def __init__(
:param str endpoint: An ACR endpoint.
:param credential: The credential with which to authenticate. This should be None in anonymous access.
:type credential: ~azure.core.credentials.TokenCredential or None
:keyword api_version: API Version. The default value is "2021-07-01". Note that overriding this default value
may result in unsupported behavior.
:keyword api_version: API Version. The default value is "2021-07-01".
:paramtype api_version: str
:keyword audience: URL to use for credential authentication with AAD. Its value could be
"https://management.azure.com", "https://management.chinacloudapi.cn" or
Expand Down Expand Up @@ -247,6 +246,7 @@ def get_repository_properties(self, repository: str, **kwargs) -> RepositoryProp
:param str repository: Name of the repository
:rtype: ~azure.containerregistry.RepositoryProperties
:return: The properties of a repository
:raises: ~azure.core.exceptions.ResourceNotFoundError
"""
return RepositoryProperties._from_generated( # pylint: disable=protected-access
Expand Down Expand Up @@ -401,6 +401,7 @@ def get_manifest_properties(self, repository: str, tag_or_digest: str, **kwargs)
:param str repository: Name of the repository
:param str tag_or_digest: Tag or digest of the manifest
:return: The properties of a registry artifact
:rtype: ~azure.containerregistry.ArtifactManifestProperties
:raises: ~azure.core.exceptions.ResourceNotFoundError
Expand Down Expand Up @@ -433,6 +434,7 @@ def get_tag_properties(self, repository: str, tag: str, **kwargs) -> ArtifactTag
:param str repository: Name of the repository
:param str tag: The tag to get tag properties for
:return: The properties for a tag
:rtype: ~azure.containerregistry.ArtifactTagProperties
:raises: ~azure.core.exceptions.ResourceNotFoundError
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ def _download_chunk(self) -> PipelineResponse:
def __next__(self) -> bytes:
try:
return self._yield_data()
except StopIteration:
except StopIteration as exc:
if self._downloaded >= self._blob_size:
computed_digest = "sha256:" + self._hasher.hexdigest()
if computed_digest != self._digest:
raise DigestValidationError(
"The content of retrieved blob digest does not match the requested digest."
)
) from exc
raise
self._response = self._download_chunk()
self._response_bytes = self._response.http_response.iter_bytes()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ class ACRExchangeClient(object):
:type endpoint: str
:param credential: Credential which provides tokens to authenticate requests
:type credential: ~azure.core.credentials.TokenCredential
:keyword api_version: API Version. The default value is "2021-07-01". Note that overriding this default value
may result in unsupported behavior.
:keyword api_version: API Version. The default value is "2021-07-01".
:paramtype api_version: str
:keyword credential_scopes: The scopes that access token can request.
:paramtype credential_scopes: List[str]
:paramtype credential_scopes: list[str]
"""

def __init__(self, endpoint: str, credential: TokenCredential, **kwargs) -> None:
Expand All @@ -56,20 +55,20 @@ def __init__(self, endpoint: str, credential: TokenCredential, **kwargs) -> None
self._refresh_token = None # type: Optional[str]
self._expiration_time = 0 # type: float

def get_acr_access_token(self, challenge: str, **kwargs) -> Optional[str]:
def get_acr_access_token(self, challenge: str, **kwargs) -> Optional[str]: # pylint:disable=client-method-missing-tracing-decorator
parsed_challenge = _parse_challenge(challenge)
refresh_token = self.get_refresh_token(parsed_challenge["service"], **kwargs)
return self.exchange_refresh_token_for_access_token(
refresh_token, service=parsed_challenge["service"], scope=parsed_challenge["scope"], **kwargs
)

def get_refresh_token(self, service: str, **kwargs) -> str:
def get_refresh_token(self, service: str, **kwargs) -> str: # pylint:disable=client-method-missing-tracing-decorator
if not self._refresh_token or self._expiration_time - time.time() > 300:
self._refresh_token = self.exchange_aad_token_for_refresh_token(service, **kwargs)
self._expiration_time = _parse_exp_time(self._refresh_token)
return self._refresh_token

def exchange_aad_token_for_refresh_token(self, service: str, **kwargs) -> str:
def exchange_aad_token_for_refresh_token(self, service: str, **kwargs) -> str: # pylint:disable=client-method-missing-tracing-decorator
refresh_token = self._client.authentication.exchange_aad_access_token_for_acr_refresh_token( # type: ignore
grant_type=PostContentSchemaGrantType.ACCESS_TOKEN,
service=service,
Expand All @@ -78,7 +77,7 @@ def exchange_aad_token_for_refresh_token(self, service: str, **kwargs) -> str:
)
return refresh_token.refresh_token if refresh_token.refresh_token is not None else ""

def exchange_refresh_token_for_access_token(
def exchange_refresh_token_for_access_token( # pylint:disable=client-method-missing-tracing-decorator
self, refresh_token: str, service: str, scope: str, **kwargs
) -> Optional[str]:
access_token = self._client.authentication.exchange_acr_refresh_token_for_acr_access_token( # type: ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ def _is_tag(tag_or_digest: str) -> bool:
return not (len(tag) == 2 and tag[0].startswith("sha"))

def _clean(matches: List[str]) -> None:
"""This method removes empty strings and commas from the regex matching of the Challenge header"""
"""This method removes empty strings and commas from the regex matching of the Challenge header.
:param list[str] matches: The regex list to clean.
:return: None
"""
while True:
try:
matches.remove("")
Expand All @@ -61,7 +65,12 @@ def _clean(matches: List[str]) -> None:
return

def _parse_challenge(header: str) -> Dict[str, str]:
"""Parse challenge header into service and scope"""
"""Parse challenge header into service and scope
:param str header: The challenge header to parse.
:return: A service and scope dict parsed from challenge header.
:rtype: dict[str, str]
"""
ret: Dict[str, str] = {}
if header.startswith(BEARER):
challenge_params = header[len(BEARER) + 1 :]
Expand All @@ -74,7 +83,7 @@ def _parse_challenge(header: str) -> Dict[str, str]:
return ret

def _parse_next_link(link_string: str) -> Optional[str]:
"""Parses the next link in the list operations response URL
"""Parse the next link in the list operations response URL
Per the Docker v2 HTTP API spec, the Link header is an RFC5988
compliant rel='next' with URL to next result set, if available.
Expand All @@ -84,13 +93,21 @@ def _parse_next_link(link_string: str) -> Optional[str]:
Link = "Link" ":" #link-value
link-value = "<" URI-Reference ">" * (";" link-param )
See: https://tools.ietf.org/html/rfc5988#section-5
:param str link_string: The Link header in HTTP response.
:return: The URI reference of next link.
:rtype: str or None
"""
if not link_string:
return None
return link_string[1 : link_string.find(">")]

def _enforce_https(request: PipelineRequest) -> None:
"""Raise ServiceRequestError if the request URL is non-HTTPS and the sender did not specify enforce_https=False"""
"""Raise ServiceRequestError if the request URL is non-HTTPS and the sender did not specify enforce_https=False
:param ~azure.core.pipeline.PipelineRequest request: The pipeline request object.
:return: None
"""

# move 'enforce_https' from options to context so it persists
# across retries but isn't passed to a transport implementation
Expand All @@ -114,8 +131,7 @@ def _strip_alg(digest):
return digest.split(":")[1]
return digest

def _parse_exp_time(raw_token):
# type: (str) -> float
def _parse_exp_time(raw_token: str) -> float:
raw_token_list = raw_token.split(".")
if len(raw_token_list) > 2:
value = raw_token_list[1]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class ArtifactOperatingSystem(str, Enum, metaclass=CaseInsensitiveEnumMeta):
WINDOWS = "windows"


class ArtifactManifestProperties(object): # pylint: disable=too-many-instance-attributes
class ArtifactManifestProperties: # pylint: disable=too-many-instance-attributes
"""Represents properties of a registry artifact.
:ivar bool can_delete: Delete Permissions for an artifact.
Expand Down Expand Up @@ -156,7 +156,7 @@ def fully_qualified_reference(self) -> str:
return f"{_host_only(self._registry)}/{self._repository_name}{':' if _is_tag(self._digest) else '@'}{_strip_alg(self._digest)}" # pylint: disable=line-too-long


class RepositoryProperties(object):
class RepositoryProperties:
"""Represents properties of a single repository.
:ivar bool can_delete: Delete Permissions for a repository.
Expand Down Expand Up @@ -234,7 +234,7 @@ def tag_count(self) -> int:
return self._tag_count


class ArtifactTagProperties(object):
class ArtifactTagProperties:
"""Represents properties of a single tag
:ivar bool can_delete: Delete Permissions for a tag.
Expand Down Expand Up @@ -304,7 +304,7 @@ def repository_name(self) -> str:
return self._repository_name


class GetManifestResult(object):
class GetManifestResult:
"""The get manifest result.
:ivar manifest: The manifest JSON.
Expand All @@ -321,6 +321,7 @@ def __init__(self, **kwargs):

class DigestValidationError(ValueError):
"""Thrown when a manifest digest validation fails.
:param str message: Message for caller describing the reason for the failure.
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
# Licensed under the MIT License.
# ------------------------------------
from typing import Optional, Union

from azure.core.credentials import AccessToken
from azure.core.credentials_async import AsyncTokenCredential

from ._async_exchange_client import ExchangeClientAuthenticationPolicy
from .._generated.aio import ContainerRegistry
from .._generated.models import TokenGrantType
Expand Down Expand Up @@ -34,8 +36,7 @@ class AnonymousACRExchangeClient(object):
:param endpoint: Azure Container Registry endpoint
:type endpoint: str
:keyword api_version: Api Version. Default value is "2021-07-01". Note that overriding this
default value may result in unsupported behavior.
:keyword api_version: Api Version. Default value is "2021-07-01".
:paramtype api_version: str
"""

Expand All @@ -51,7 +52,7 @@ def __init__(self, endpoint: str, **kwargs) -> None: # pylint: disable=missing-c
**kwargs
)

async def get_acr_access_token(self, challenge: str, **kwargs) -> Optional[str]:
async def get_acr_access_token(self, challenge: str, **kwargs) -> Optional[str]: # pylint:disable=client-method-missing-tracing-decorator-async
parsed_challenge = _parse_challenge(challenge)
return await self.exchange_refresh_token_for_access_token(
"",
Expand All @@ -61,7 +62,7 @@ async def get_acr_access_token(self, challenge: str, **kwargs) -> Optional[str]:
**kwargs
)

async def exchange_refresh_token_for_access_token(
async def exchange_refresh_token_for_access_token( # pylint:disable=client-method-missing-tracing-decorator-async
self, refresh_token: str, service: str, scope: str, grant_type: Union[str, TokenGrantType], **kwargs
) -> Optional[str]:
access_token = await self._client.authentication.exchange_acr_refresh_token_for_acr_access_token( # type: ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,19 @@ async def on_request(self, request: PipelineRequest) -> None:
"""Called before the policy sends a request.
The base implementation authorizes the request with a bearer token.
:param ~azure.core.pipeline.PipelineRequest request: the request
:param ~azure.core.pipeline.PipelineRequest request: The pipeline request object.
:return: None
:rtype: None
"""
# Future caching implementation will be included here
pass # pylint: disable=unnecessary-pass

async def send(self, request: PipelineRequest) -> PipelineResponse:
"""Authorizes a request with a bearer token, possibly handling an authentication challenge
:param ~azure.core.pipeline.PipelineRequest request: the request
:param ~azure.core.pipeline.PipelineRequest request: The pipeline request object.
:return: The pipeline response object.
:rtype: ~azure.core.pipeline.PipelineResponse
"""
_enforce_https(request)

Expand Down Expand Up @@ -70,8 +74,9 @@ async def on_challenge(self, request: PipelineRequest, response: PipelineRespons
:param ~azure.core.pipeline.PipelineResponse response: the resource provider's response
:param str challenge: response's WWW-Authenticate header, unparsed. It may contain multiple challenges.
:returns: a bool indicating whether the policy should send the request
:rtype: bool
"""
# pylint:disable=unused-argument,no-self-use
# pylint:disable=unused-argument

access_token = await self._exchange_client.get_acr_access_token(challenge)
if access_token is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ class ContainerRegistryBaseClient(object):
:param credential: Token credential for authenticating requests with Azure, or None in anonymous access
:type credential: ~azure.core.credentials_async.AsyncTokenCredential or None
:keyword credential_scopes: URL for credential authentication if different from the default
:paramtype credential_scopes: List[str]
:keyword api_version: Api Version. Default value is "2021-07-01". Note that overriding this
default value may result in unsupported behavior.
:paramtype credential_scopes: list[str]
:keyword api_version: Api Version. Default value is "2021-07-01".
:paramtype api_version: str
"""

Expand Down Expand Up @@ -60,7 +59,7 @@ async def close(self) -> None:
"""
await self._client.close()

def _is_tag(self, tag_or_digest: str) -> bool: # pylint: disable=no-self-use
def _is_tag(self, tag_or_digest: str) -> bool:
tag = tag_or_digest.split(":")
return not (len(tag) == 2 and tag[0].startswith("sha"))

Expand Down
Loading

0 comments on commit 1366b82

Please sign in to comment.