Skip to content
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

[AppConfig] Support monitor page changes by page etag #34346

Merged
merged 24 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .vscode/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,12 @@
"azconfig"
]
},
{
"filename": "sdk/appconfiguration/azure-appconfiguration/**",
"words": [
"kvset"
]
},
{
"filename": "sdk/personalizer/test-resources.json",
"words": [
Expand Down
8 changes: 3 additions & 5 deletions sdk/appconfiguration/azure-appconfiguration/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# Release History

## 1.5.1 (Unreleased)
## 1.6.0b1 (2024-03-14)

### Features Added

### Breaking Changes
- Exposed `send_request()` method in each client to send custom requests using the client's existing pipeline.
xiangyan99 marked this conversation as resolved.
Show resolved Hide resolved
- Supported to get page ETag while iterating `list_configuration_setting()` result by page.

### Bugs Fixed
- Fixed a bug in consuming "etag" value in sync operation `set_configuration_setting()`.

### Other Changes

## 1.5.0 (2023-11-09)

### Other Changes
Expand Down
2 changes: 1 addition & 1 deletion sdk/appconfiguration/azure-appconfiguration/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "python",
"TagPrefix": "python/appconfiguration/azure-appconfiguration",
"Tag": "python/appconfiguration/azure-appconfiguration_6ae662d134"
"Tag": "python/appconfiguration/azure-appconfiguration_8137b21bd0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# license information.
# -------------------------------------------------------------------------
import binascii
import functools
from datetime import datetime
from typing import Any, Dict, List, Mapping, Optional, Union, cast, overload
from typing_extensions import Literal
Expand All @@ -19,12 +20,18 @@
ResourceModifiedError,
ResourceNotModifiedError,
)
from azure.core.rest import HttpRequest, HttpResponse
from azure.core.utils import CaseInsensitiveDict
from ._azure_appconfiguration_error import ResourceReadOnlyError
from ._azure_appconfiguration_requests import AppConfigRequestsCredentialsPolicy
from ._generated import AzureAppConfiguration
from ._generated.models import SnapshotUpdateParameters, SnapshotStatus
from ._models import ConfigurationSetting, ConfigurationSettingsFilter, ConfigurationSnapshot
from ._models import (
ConfigurationSetting,
ConfigurationSettingsFilter,
ConfigurationSnapshot,
ConfigurationSettingPropertiesPaged,
)
from ._utils import (
prep_if_match,
prep_if_none_match,
Expand All @@ -34,6 +41,9 @@
)
from ._sync_token import SyncTokenPolicy

def _return_deserialized_and_headers(response, deserialized, response_headers):
return deserialized, response_headers


class AzureAppConfigurationClient:
"""Represents a client that calls restful API of Azure App Configuration service.
Expand Down Expand Up @@ -109,6 +119,23 @@ def from_connection_string(cls, connection_string: str, **kwargs: Any) -> "Azure
id_credential=id_credential,
**kwargs,
)

@distributed_trace
def send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs) -> HttpResponse:
"""Runs a network request using the client's existing pipeline.

The request URL can be relative to the vault URL. The service API version used for the request is the same as
the client's unless otherwise specified. This method does not raise if the response is an error; to raise an
exception, call `raise_for_status()` on the returned response object. For more information about how to send
custom requests with this method, see https://aka.ms/azsdk/dpcodegen/python/send_request.

:param request: The network request you want to make.
:type request: ~azure.core.rest.HttpRequest
:keyword bool stream: Whether the response payload will be streamed. Defaults to False.
:return: The response of your network call. Does not do error handling on your response.
:rtype: ~azure.core.rest.HttpResponse
"""
return self._impl._send_request(request, stream=stream, **kwargs)

@overload
def list_configuration_settings(
Expand Down Expand Up @@ -172,7 +199,9 @@ def list_configuration_settings(
"""

@distributed_trace
def list_configuration_settings(self, *args, **kwargs) -> ItemPaged[ConfigurationSetting]:
def list_configuration_settings(
self, *args, **kwargs
) -> ItemPaged[ConfigurationSetting]:
accept_datetime = kwargs.pop("accept_datetime", None)
if isinstance(accept_datetime, datetime):
accept_datetime = str(accept_datetime)
Expand All @@ -192,17 +221,20 @@ def list_configuration_settings(self, *args, **kwargs) -> ItemPaged[Configuratio
)
key_filter, kwargs = get_key_filter(*args, **kwargs)
label_filter, kwargs = get_label_filter(*args, **kwargs)
return self._impl.get_key_values( # type: ignore
command = functools.partial(self._impl.get_key_values_in_one_page, **kwargs)
return ItemPaged(
command,
key=key_filter,
label=label_filter,
accept_datetime=accept_datetime,
select=select,
cls=lambda objs: [ConfigurationSetting._from_generated(x) for x in objs],
**kwargs,
cls=_return_deserialized_and_headers,
page_iterator_class=ConfigurationSettingPropertiesPaged,
)

except binascii.Error as exc:
raise binascii.Error("Connection string secret has incorrect padding") from exc

@distributed_trace
def get_configuration_setting(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,154 @@

Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize
"""
from typing import List
import urllib.parse
from typing import Any, AsyncIterable, List, Optional, Union
from azure.core.exceptions import (
ClientAuthenticationError,
HttpResponseError,
ResourceExistsError,
ResourceNotFoundError,
ResourceNotModifiedError,
map_error,
)
from azure.core.rest import HttpRequest
from azure.core.tracing.decorator_async import distributed_trace_async
from azure.core.utils import case_insensitive_dict
from ._azure_app_configuration_operations import (
AzureAppConfigurationOperationsMixin as AzureAppConfigOpGenerated,
ClsType,
build_get_key_values_request,
)
from ... import models as _models
from ..._vendor import _convert_request

__all__: List[str] = [] # Add all objects you want publicly available to users at this package level

class AzureAppConfigurationOperationsMixin(AzureAppConfigOpGenerated):
@distributed_trace_async
async def get_key_values_in_one_page(
self,
key: Optional[str] = None,
label: Optional[str] = None,
after: Optional[str] = None,
accept_datetime: Optional[str] = None,
select: Optional[List[Union[str, _models.KeyValueFields]]] = None,
if_match: Optional[str] = None,
if_none_match: Optional[str] = None,
continuation_token: Optional[str] = None,
**kwargs: Any
) -> AsyncIterable["_models.KeyValue"]:
"""Gets a list of key-values in one page.

Gets a list of key-values in one page.

:param key: A filter used to match keys. Default value is None.
:type key: str
:param label: A filter used to match labels. Default value is None.
:type label: str
:param after: Instructs the server to return elements that appear after the element referred to
by the specified token. Default value is None.
:type after: str
:param accept_datetime: Requests the server to respond with the state of the resource at the
specified time. Default value is None.
:type accept_datetime: str
:param select: Used to select what fields are present in the returned resource(s). Default
value is None.
:type select: list[str or ~azure.appconfiguration.models.KeyValueFields]
:param if_match: Used to perform an operation only if the targeted resource's etag matches the
value provided. Default value is None.
:type if_match: str
:param if_none_match: Used to perform an operation only if the targeted resource's etag does
not match the value provided. Default value is None.
:type if_none_match: str
:param str continuation_token: An opaque continuation token.
:keyword callable cls: A custom type or function that will be passed the direct response
:return: An iterator like instance of either KeyValue or the result of cls(response)
:rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.appconfiguration.models.KeyValue]
:raises ~azure.core.exceptions.HttpResponseError:
"""
_headers = kwargs.pop("headers", {}) or {}
_params = case_insensitive_dict(kwargs.pop("params", {}) or {})

api_version: str = kwargs.pop("api_version", _params.pop("api-version", self._config.api_version))
cls: ClsType[_models.KeyValueListResult] = kwargs.pop("cls", None)

error_map = {
401: ClientAuthenticationError,
404: ResourceNotFoundError,
409: ResourceExistsError,
304: ResourceNotModifiedError,
}
error_map.update(kwargs.pop("error_map", {}) or {})

def prepare_request(next_link=None):
if not next_link:

_request = build_get_key_values_request(
key=key,
label=label,
after=after,
accept_datetime=accept_datetime,
select=select,
if_match=if_match,
if_none_match=if_none_match,
sync_token=self._config.sync_token,
api_version=api_version,
headers=_headers,
params=_params,
)
_request = _convert_request(_request)
path_format_arguments = {
"endpoint": self._serialize.url(
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
),
}
_request.url = self._client.format_url(_request.url, **path_format_arguments)

else:
# make call to next link with the client's api-version
_parsed_next_link = urllib.parse.urlparse(next_link)
_next_request_params = case_insensitive_dict(
{
key: [urllib.parse.quote(v) for v in value]
for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()
}
)
_next_request_params["api-version"] = self._config.api_version
_request = HttpRequest(
"GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params
)
_request = _convert_request(_request)
path_format_arguments = {
"endpoint": self._serialize.url(
"self._config.endpoint", self._config.endpoint, "str", skip_quote=True
),
}
_request.url = self._client.format_url(_request.url, **path_format_arguments)
_request.method = "GET"
return _request

_request = prepare_request(continuation_token)

_stream = False
pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access
_request, stream=_stream, **kwargs
)
response = pipeline_response.http_response

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize.failsafe_deserialize(_models.Error, pipeline_response)
raise HttpResponseError(response=response, model=error)

response_headers = response.headers
deserialized = self._deserialize("KeyValueListResult", pipeline_response)

if cls:
return cls(pipeline_response, deserialized, response_headers)

return deserialized

__all__: List[str] = ["AzureAppConfigurationOperationsMixin"] # Add all objects you want publicly available to users at this package level


def patch_sdk():
Expand Down
Loading
Loading