Skip to content

Commit b9ae945

Browse files
App config provider fix my py next (#33905)
* Adding mypy ignores * MyPy fixes * format fix * Fixed PyLint * fixing refresh on * fixing mypy errors * updated for mypy changes * Fixing MyPy issue * Fixes pylint issue * Fixed check --------- Co-authored-by: Krista Pratico <[email protected]>
1 parent d6a956c commit b9ae945

14 files changed

+153
-117
lines changed

sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_azureappconfigurationprovider.py

Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,20 @@
1515
Any,
1616
Callable,
1717
Dict,
18-
Iterable,
1918
Mapping,
2019
Optional,
2120
overload,
2221
List,
2322
Tuple,
2423
TYPE_CHECKING,
2524
Union,
25+
Iterator,
26+
KeysView,
27+
ItemsView,
28+
ValuesView,
29+
TypeVar,
2630
)
27-
from azure.appconfiguration import ( # pylint:disable=no-name-in-module
31+
from azure.appconfiguration import ( # type:ignore # pylint:disable=no-name-in-module
2832
AzureAppConfigurationClient,
2933
FeatureFlagConfigurationSetting,
3034
SecretReferenceConfigurationSetting,
@@ -49,8 +53,8 @@
4953
if TYPE_CHECKING:
5054
from azure.core.credentials import TokenCredential
5155

52-
JSON = Union[str, Mapping[str, Any]] # pylint: disable=unsubscriptable-object
53-
56+
JSON = Mapping[str, Any] # pylint: disable=unsubscriptable-object
57+
_T = TypeVar("_T")
5458
logger = logging.getLogger(__name__)
5559

5660
min_uptime = 5
@@ -63,6 +67,9 @@ def load(
6367
*,
6468
selects: Optional[List[SettingSelector]] = None,
6569
trim_prefixes: Optional[List[str]] = None,
70+
keyvault_credential: Optional["TokenCredential"] = None,
71+
keyvault_client_configs: Optional[Mapping[str, JSON]] = None,
72+
secret_resolver: Optional[Callable[[str], str]] = None,
6673
key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions] = None,
6774
refresh_on: Optional[List[Tuple[str, str]]] = None,
6875
refresh_interval: int = 30,
@@ -109,6 +116,9 @@ def load(
109116
connection_string: str,
110117
selects: Optional[List[SettingSelector]] = None,
111118
trim_prefixes: Optional[List[str]] = None,
119+
keyvault_credential: Optional["TokenCredential"] = None,
120+
keyvault_client_configs: Optional[Mapping[str, JSON]] = None,
121+
secret_resolver: Optional[Callable[[str], str]] = None,
112122
key_vault_options: Optional[AzureAppConfigurationKeyVaultOptions] = None,
113123
refresh_on: Optional[List[Tuple[str, str]]] = None,
114124
refresh_interval: int = 30,
@@ -201,8 +211,8 @@ def load(*args, **kwargs) -> "AzureAppConfigurationProvider":
201211
for (key, label), etag in provider._refresh_on.items():
202212
if not etag:
203213
try:
204-
sentinel = provider._client.get_configuration_setting(key, label, headers=headers)
205-
provider._refresh_on[(key, label)] = sentinel.etag
214+
sentinel = provider._client.get_configuration_setting(key, label, headers=headers) # type:ignore
215+
provider._refresh_on[(key, label)] = sentinel.etag # type:ignore
206216
except HttpResponseError as e:
207217
if e.status_code == 404:
208218
# If the sentinel is not found a refresh should be triggered when it is created.
@@ -279,15 +289,17 @@ def _buildprovider(
279289
**kwargs
280290
)
281291
return provider
282-
provider._client = AzureAppConfigurationClient(
283-
endpoint,
284-
credential,
285-
user_agent=user_agent,
286-
retry_total=retry_total,
287-
retry_backoff_max=retry_backoff_max,
288-
**kwargs
289-
)
290-
return provider
292+
if endpoint is not None and credential is not None:
293+
provider._client = AzureAppConfigurationClient(
294+
endpoint,
295+
credential,
296+
user_agent=user_agent,
297+
retry_total=retry_total,
298+
retry_backoff_max=retry_backoff_max,
299+
**kwargs
300+
)
301+
return provider
302+
raise ValueError("Please pass either endpoint and credential, or a connection string.")
291303

292304

293305
def _resolve_keyvault_reference(
@@ -320,7 +332,9 @@ def _resolve_keyvault_reference(
320332
provider._secret_clients[vault_url] = referenced_client
321333

322334
if referenced_client:
323-
return referenced_client.get_secret(keyvault_identifier.name, version=keyvault_identifier.version).value
335+
secret_value = referenced_client.get_secret(keyvault_identifier.name, version=keyvault_identifier.version).value
336+
if secret_value is not None:
337+
return secret_value
324338

325339
if provider._secret_resolver:
326340
return provider._secret_resolver(config.secret_id)
@@ -352,7 +366,7 @@ def _is_json_content_type(content_type: str) -> bool:
352366

353367
def _build_sentinel(setting: Union[str, Tuple[str, str]]) -> Tuple[str, str]:
354368
try:
355-
key, label = setting
369+
key, label = setting # type:ignore
356370
except IndexError:
357371
key = setting
358372
label = EMPTY_LABEL
@@ -417,18 +431,17 @@ class AzureAppConfigurationProvider(Mapping[str, Union[str, JSON]]): # pylint:
417431

418432
def __init__(self, **kwargs) -> None:
419433
self._dict: Dict[str, str] = {}
420-
self._trim_prefixes: List[str] = []
421434
self._client: Optional[AzureAppConfigurationClient] = None
422435
self._secret_clients: Dict[str, SecretClient] = {}
423436
self._selects: List[SettingSelector] = kwargs.pop(
424437
"selects", [SettingSelector(key_filter="*", label_filter=EMPTY_LABEL)]
425438
)
426439

427440
trim_prefixes: List[str] = kwargs.pop("trim_prefixes", [])
428-
self._trim_prefixes = sorted(trim_prefixes, key=len, reverse=True)
441+
self._trim_prefixes: List[str] = sorted(trim_prefixes, key=len, reverse=True)
429442

430443
refresh_on: List[Tuple[str, str]] = kwargs.pop("refresh_on", None) or []
431-
self._refresh_on: Mapping[Tuple[str, str] : Optional[str]] = {_build_sentinel(s): None for s in refresh_on}
444+
self._refresh_on: Mapping[Tuple[str, str], Optional[str]] = {_build_sentinel(s): None for s in refresh_on}
432445
self._refresh_timer: _RefreshTimer = _RefreshTimer(**kwargs)
433446
self._on_refresh_success: Optional[Callable] = kwargs.pop("on_refresh_success", None)
434447
self._on_refresh_error: Optional[Callable[[Exception], None]] = kwargs.pop("on_refresh_error", None)
@@ -460,7 +473,7 @@ def refresh(self, **kwargs) -> None:
460473
headers = _get_headers("Watch", uses_key_vault=self._uses_key_vault, **kwargs)
461474
for (key, label), etag in updated_sentinel_keys.items():
462475
try:
463-
updated_sentinel = self._client.get_configuration_setting(
476+
updated_sentinel = self._client.get_configuration_setting( # type:ignore
464477
key=key,
465478
label=label,
466479
etag=etag,
@@ -554,14 +567,14 @@ def _process_key_value(self, config):
554567
return config.value
555568
return config.value
556569

557-
def __getitem__(self, key: str) -> str:
570+
def __getitem__(self, key: str) -> Any:
558571
# pylint:disable=docstring-missing-param,docstring-missing-return,docstring-missing-rtype
559572
"""
560573
Returns the value of the specified key.
561574
"""
562575
return self._dict[key]
563576

564-
def __iter__(self) -> Iterable[str]:
577+
def __iter__(self) -> Iterator[str]:
565578
return self._dict.__iter__()
566579

567580
def __len__(self) -> int:
@@ -574,40 +587,48 @@ def __contains__(self, __x: object) -> bool:
574587
"""
575588
return self._dict.__contains__(__x)
576589

577-
def keys(self) -> Iterable[str]:
590+
def keys(self) -> KeysView[str]:
578591
"""
579592
Returns a list of keys loaded from Azure App Configuration.
580593
581594
:return: A list of keys loaded from Azure App Configuration.
582-
:rtype: Iterable[str]
595+
:rtype: KeysView[str]
583596
"""
584597
with self._update_lock:
585-
return list(self._dict.keys())
598+
return copy.deepcopy(self._dict).keys()
586599

587-
def items(self) -> Iterable[Tuple[str, Union[str, JSON]]]:
600+
def items(self) -> ItemsView[str, Union[str, Mapping[str, Any]]]:
588601
"""
589602
Returns a set-like object of key-value pairs loaded from Azure App Configuration. Any values that are Key Vault
590603
references will be resolved.
591604
592605
:return: A set-like object of key-value pairs loaded from Azure App Configuration.
593-
:rtype: Iterable[Tuple[str, Union[str, JSON]]]
606+
:rtype: ItemsView[str, Union[str, Mapping[str, Any]]]
594607
"""
595608
with self._update_lock:
596-
return copy.deepcopy(self._dict.items())
609+
return copy.deepcopy(self._dict).items()
597610

598-
def values(self) -> Iterable[Union[str, JSON]]:
611+
def values(self) -> ValuesView[Union[str, Mapping[str, Any]]]:
599612
"""
600613
Returns a list of values loaded from Azure App Configuration. Any values that are Key Vault references will be
601614
resolved.
602615
603616
:return: A list of values loaded from Azure App Configuration. The values are either Strings or JSON objects,
604-
based on there content type.
605-
:rtype: Iterable[[str], [JSON]]
617+
based on there content type.
618+
:rtype: ValuesView[Union[str, Mapping[str, Any]]]
606619
"""
607620
with self._update_lock:
608-
return copy.deepcopy(list((self._dict.values())))
621+
return copy.deepcopy((self._dict)).values()
622+
623+
@overload
624+
def get(self, key: str, default: None = None) -> Union[str, JSON, None]:
625+
...
626+
627+
@overload
628+
def get(self, key: str, default: Union[str, JSON, _T]) -> Union[str, JSON, _T]: # pylint: disable=signature-differs
629+
...
609630

610-
def get(self, key: str, default: Optional[str] = None) -> Union[str, JSON]:
631+
def get(self, key: str, default: Optional[Union[str, JSON, _T]] = None) -> Union[str, JSON, _T, None]:
611632
"""
612633
Returns the value of the specified key. If the key does not exist, returns the default value.
613634
@@ -618,7 +639,7 @@ def get(self, key: str, default: Optional[str] = None) -> Union[str, JSON]:
618639
:rtype: Union[str, JSON]
619640
"""
620641
with self._update_lock:
621-
return copy.deepcopy(self._dict.get(key, default))
642+
return copy.deepcopy(self._dict).get(key, default)
622643

623644
def __eq__(self, other: Any) -> bool:
624645
if not isinstance(other, AzureAppConfigurationProvider):
@@ -640,15 +661,15 @@ def close(self) -> None:
640661
"""
641662
for client in self._secret_clients.values():
642663
client.close()
643-
self._client.close()
664+
self._client.close() # type: ignore
644665

645666
def __enter__(self) -> "AzureAppConfigurationProvider":
646-
self._client.__enter__()
667+
self._client.__enter__() # type: ignore
647668
for client in self._secret_clients.values():
648669
client.__enter__()
649670
return self
650671

651672
def __exit__(self, *args) -> None:
652-
self._client.__exit__(*args)
673+
self._client.__exit__(*args) # type: ignore
653674
for client in self._secret_clients.values():
654675
client.__exit__()

0 commit comments

Comments
 (0)