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

fix wild cards handling #9066

Merged
merged 4 commits into from
Dec 13, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
from ._azure_appconfiguration_credential import AppConfigConnectionStringCredential
from ._utils import (
get_endpoint_from_connection_string,
escape_and_tostr,
prep_if_match,
prep_if_none_match,
)
Expand Down Expand Up @@ -146,17 +145,17 @@ def _create_appconfig_pipeline(self, credential, base_url=None, aad_mode=False,
@distributed_trace
def list_configuration_settings(
self, keys=None, labels=None, **kwargs
): # type: (Optional[list], Optional[list], dict) -> azure.core.paging.ItemPaged[ConfigurationSetting]
): # type: (Optional[str], Optional[str], dict) -> azure.core.paging.ItemPaged[ConfigurationSetting]

"""List the configuration settings stored in the configuration service, optionally filtered by
label and accept_datetime

:param keys: filter results based on their keys. '*' can be
used as wildcard in the beginning or end of the filter
:type keys: list[str]
:type keys: str
:param labels: filter results based on their label. '*' can be
used as wildcard in the beginning or end of the filter
:type labels: list[str]
:type labels: str
:keyword datetime accept_datetime: filter out ConfigurationSetting created after this datetime
:keyword list[str] fields: specify which fields to include in the results. Leave None to include all fields
:keyword dict headers: if "headers" exists, its value (a dict) will be added to the http request header
Expand All @@ -177,24 +176,22 @@ def list_configuration_settings(
pass # do something

filtered_listed = client.list_configuration_settings(
labels=["*Labe*"], keys=["*Ke*"], accept_datetime=accept_datetime
labels="*Labe*", keys="*Ke*", accept_datetime=accept_datetime
)
for item in filtered_listed:
pass # do something
"""
select = kwargs.pop("fields", None)
if select:
select = ['locked' if x == 'read_only' else x for x in select]
encoded_labels = escape_and_tostr(labels)
encoded_keys = escape_and_tostr(keys)
error_map = {
401: ClientAuthenticationError
}

try:
return self._impl.get_key_values(
label=encoded_labels,
key=encoded_keys,
label=labels,
key=keys,
select=select,
cls=lambda objs: [ConfigurationSetting._from_key_value(x) for x in objs],
error_map=error_map,
Expand Down Expand Up @@ -438,17 +435,17 @@ def delete_configuration_setting(
@distributed_trace
def list_revisions(
self, keys=None, labels=None, **kwargs
): # type: (Optional[list], Optional[list], dict) -> azure.core.paging.ItemPaged[ConfigurationSetting]
): # type: (Optional[str], Optional[str], dict) -> azure.core.paging.ItemPaged[ConfigurationSetting]

"""
Find the ConfigurationSetting revision history.

:param keys: filter results based on their keys. '*' can be
used as wildcard in the beginning or end of the filter
:type keys: list[str]
:type keys: str
:param labels: filter results based on their label. '*' can be
used as wildcard in the beginning or end of the filter
:type labels: list[str]
:type labels: str
:keyword datetime accept_datetime: filter out ConfigurationSetting created after this datetime
:keyword list[str] fields: specify which fields to include in the results. Leave None to include all fields
:keyword dict headers: if "headers" exists, its value (a dict) will be added to the http request header
Expand All @@ -469,24 +466,22 @@ def list_revisions(
pass # do something

filtered_revisions = client.list_revisions(
labels=["*Labe*"], keys=["*Ke*"], accept_datetime=accept_datetime
labels="*Labe*", keys="*Ke*", accept_datetime=accept_datetime
)
for item in filtered_revisions:
pass # do something
"""
select = kwargs.pop("fields", None)
if select:
select = ['locked' if x == 'read_only' else x for x in select]
encoded_labels = escape_and_tostr(labels)
encoded_keys = escape_and_tostr(keys)
error_map = {
401: ClientAuthenticationError
}

try:
return self._impl.get_revisions(
label=encoded_labels,
key=encoded_keys,
label=labels,
key=keys,
select=select,
cls=lambda objs: [ConfigurationSetting._from_key_value(x) for x in objs],
error_map=error_map,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,8 @@
# -------------------------------------------------------------------------

from datetime import datetime
import re
from azure.core import MatchConditions

def escape_reserved(value):
"""
Reserved characters are star(*), comma(,) and backslash(\\)
If a reserved character is part of the value, then it must be escaped using \\{Reserved Character}.
Non-reserved characters can also be escaped.
"""
if value is None:
return None
if value == "":
return "\0" # '\0' will be encoded to %00 in the url.
if isinstance(value, list):
return [escape_reserved(s) for s in value]
value = str(value) # value is unicode for Python 2.7
# precede all reserved characters with a backslash.
# But if a * is at the beginning or the end, don't add the backslash
return re.sub(r"((?!^)\*(?!$)|\\|,)", r"\\\1", value)

def escape_and_tostr(value):
if value is None:
return None
if value == [None]:
return None
value = escape_reserved(value)
return ','.join(value)

def quote_etag(etag):
if not etag or etag == "*":
return etag
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
from .._azure_appconfiguration_error import ResourceReadOnlyError
from .._utils import (
get_endpoint_from_connection_string,
escape_and_tostr,
prep_if_match,
prep_if_none_match,
)
Expand Down Expand Up @@ -156,17 +155,17 @@ def _create_appconfig_pipeline(self, credential, base_url=None, aad_mode=False,
@distributed_trace
def list_configuration_settings(
self, keys=None, labels=None, **kwargs
): # type: (list, list, dict) -> azure.core.paging.ItemPaged[ConfigurationSetting]
): # type: (Optional[str], Optional[str], dict) -> azure.core.paging.ItemPaged[ConfigurationSetting]

"""List the configuration settings stored in the configuration service, optionally filtered by
label and accept_datetime

:param keys: filter results based on their keys. '*' can be
used as wildcard in the beginning or end of the filter
:type keys: list[str]
:type keys: str
:param labels: filter results based on their label. '*' can be
used as wildcard in the beginning or end of the filter
:type labels: list[str]
:type labels: str
:keyword datetime accept_datetime: filter out ConfigurationSetting created after this datetime
:keyword list[str] fields: specify which fields to include in the results. Leave None to include all fields
:keyword dict headers: if "headers" exists, its value (a dict) will be added to the http request header
Expand All @@ -187,24 +186,22 @@ def list_configuration_settings(
pass # do something

filtered_listed = async_client.list_configuration_settings(
labels=["*Labe*"], keys=["*Ke*"], accept_datetime=accept_datetime
labels="*Labe*", keys="*Ke*", accept_datetime=accept_datetime
)
async for item in filtered_listed:
pass # do something
"""
select = kwargs.pop("fields", None)
if select:
select = ['locked' if x == 'read_only' else x for x in select]
encoded_labels = escape_and_tostr(labels)
encoded_keys = escape_and_tostr(keys)
error_map = {
401: ClientAuthenticationError
}

try:
return self._impl.get_key_values(
label=encoded_labels,
key=encoded_keys,
label=labels,
key=keys,
select=select,
cls=lambda objs: [ConfigurationSetting._from_key_value(x) for x in objs],
error_map=error_map,
Expand Down Expand Up @@ -454,17 +451,17 @@ async def delete_configuration_setting(
@distributed_trace
def list_revisions(
self, keys=None, labels=None, **kwargs
): # type: (Optional[list], Optional[list], dict) -> azure.core.paging.AsyncItemPaged[ConfigurationSetting]
): # type: (Optional[str], Optional[str], dict) -> azure.core.paging.AsyncItemPaged[ConfigurationSetting]

"""
Find the ConfigurationSetting revision history.

:param keys: filter results based on their keys. '*' can be
used as wildcard in the beginning or end of the filter
:type keys: list[str]
:type keys: str
:param labels: filter results based on their label. '*' can be
used as wildcard in the beginning or end of the filter
:type labels: list[str]
:type labels: str
:keyword datetime accept_datetime: filter out ConfigurationSetting created after this datetime
:keyword list[str] fields: specify which fields to include in the results. Leave None to include all fields
:keyword dict headers: if "headers" exists, its value (a dict) will be added to the http request header
Expand All @@ -486,24 +483,22 @@ def list_revisions(
pass # do something

filtered_revisions = async_client.list_revisions(
labels=["*Labe*"], keys=["*Ke*"], accept_datetime=accept_datetime
labels="*Labe*", keys="*Ke*", accept_datetime=accept_datetime
)
async for item in filtered_revisions:
pass # do something
"""
select = kwargs.pop("fields", None)
if select:
select = ['locked' if x == 'read_only' else x for x in select]
encoded_labels = escape_and_tostr(labels)
encoded_keys = escape_and_tostr(keys)
error_map = {
401: ClientAuthenticationError
}

try:
return self._impl.get_revisions(
label=encoded_labels,
key=encoded_keys,
label=labels,
key=keys,
select=select,
cls=lambda objs: [ConfigurationSetting._from_key_value(x) for x in objs],
error_map=error_map,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import datetime
import os
import logging
import re

class AppConfigurationClientTest(AzureMgmtTestCase):
def __init__(self, method_name):
Expand Down Expand Up @@ -73,7 +74,7 @@ def _add_for_test(self, kv):
exist = bool(
list(
self.app_config_client.list_configuration_settings(
keys=[kv.key], labels=[kv.label]
keys=kv.key, labels=kv.label
)
)
)
Expand Down Expand Up @@ -253,7 +254,7 @@ def test_delete_wrong_etag(self):
# method: list_configuration_settings
def test_list_configuration_settings_key_label(self):
items = self.app_config_client.list_configuration_settings(
labels=[LABEL], keys=[KEY]
labels=LABEL, keys=KEY
)
cnt = 0
for kv in items:
Expand All @@ -262,15 +263,15 @@ def test_list_configuration_settings_key_label(self):
assert cnt == 1

def test_list_configuration_settings_only_label(self):
items = self.app_config_client.list_configuration_settings(labels=[LABEL])
items = self.app_config_client.list_configuration_settings(labels=LABEL)
cnt = 0
for kv in items:
assert kv.label == LABEL
cnt += 1
assert cnt == 1

def test_list_configuration_settings_only_key(self):
items = self.app_config_client.list_configuration_settings(keys=[KEY])
items = self.app_config_client.list_configuration_settings(keys=KEY)
cnt = 0
for kv in items:
assert kv.key == KEY
Expand All @@ -279,7 +280,7 @@ def test_list_configuration_settings_only_key(self):

def test_list_configuration_settings_fields(self):
items = self.app_config_client.list_configuration_settings(
keys=["*"], labels=[LABEL], fields=["key", "content_type"]
keys="*", labels=LABEL, fields=["key", "content_type"]
)
cnt = 0
for kv in items:
Expand All @@ -297,8 +298,9 @@ def test_list_configuration_settings_reserved_chars(self):
resered_char_kv
)
self.to_delete.append(resered_char_kv)
escaped_label = re.sub(r"((?!^)\*(?!$)|\\|,)", r"\\\1", LABEL_RESERVED_CHARS)
items = self.app_config_client.list_configuration_settings(
labels=[LABEL_RESERVED_CHARS]
labels=escaped_label
)
cnt = 0
for kv in items:
Expand All @@ -308,7 +310,7 @@ def test_list_configuration_settings_reserved_chars(self):

def test_list_configuration_settings_contains(self):
items = self.app_config_client.list_configuration_settings(
labels=["*" + LABEL + "*"]
labels="*" + LABEL + "*"
)
cnt = 0
for kv in items:
Expand All @@ -320,7 +322,7 @@ def test_list_configuration_settings_correct_etag(self):
to_list_kv = self.test_config_setting
custom_headers = {"If-Match": to_list_kv.etag}
items = self.app_config_client.list_configuration_settings(
keys=[to_list_kv.key], labels=[to_list_kv.label], headers=custom_headers
keys=to_list_kv.key, labels=to_list_kv.label, headers=custom_headers
)
cnt = 0
for kv in items:
Expand All @@ -343,7 +345,7 @@ def test_list_configuration_settings_multi_pages(self):
]
except ResourceExistsError:
pass
items = self.app_config_client.list_configuration_settings(keys=["multi_*"])
items = self.app_config_client.list_configuration_settings(keys="multi_*")
assert len(list(items)) > PAGE_SIZE

# Remove the configuration settings
Expand All @@ -358,7 +360,7 @@ def test_list_configuration_settings_multi_pages(self):
pass

def test_list_configuration_settings_null_label(self):
items = self.app_config_client.list_configuration_settings(labels=[""])
items = self.app_config_client.list_configuration_settings(labels="\0")
assert len(list(items)) > 0

def test_list_configuration_settings_only_accepttime(self):
Expand All @@ -372,7 +374,7 @@ def test_list_configuration_settings_only_accepttime(self):
def test_list_revisions_key_label(self):
to_list1 = self.test_config_setting
items = self.app_config_client.list_revisions(
labels=[to_list1.label], keys=[to_list1.key]
labels=to_list1.label, keys=to_list1.key
)
cnt = 0
for kv in items:
Expand All @@ -381,15 +383,15 @@ def test_list_revisions_key_label(self):
assert cnt >= 2

def test_list_revisions_only_label(self):
items = self.app_config_client.list_revisions(labels=[LABEL])
items = self.app_config_client.list_revisions(labels=LABEL)
cnt = 0
for kv in items:
assert kv.label == LABEL
cnt += 1
assert cnt >= 1

def test_list_revisions_key_no_label(self):
items = self.app_config_client.list_revisions(keys=[KEY])
items = self.app_config_client.list_revisions(keys=KEY)
cnt = 0
for kv in items:
assert kv.key == KEY
Expand All @@ -398,7 +400,7 @@ def test_list_revisions_key_no_label(self):

def test_list_revisions_fields(self):
items = self.app_config_client.list_revisions(
keys=["*"], labels=[LABEL], fields=["key", "content_type"]
keys="*", labels=LABEL, fields=["key", "content_type"]
)
for kv in items:
assert (
Expand All @@ -413,7 +415,7 @@ def test_list_revisions_correct_etag(self):
to_list_kv = self.test_config_setting
custom_headers = {"If-Match": to_list_kv.etag}
items = self.app_config_client.list_revisions(
keys=[to_list_kv.key], labels=[to_list_kv.label], headers=custom_headers
keys=to_list_kv.key, labels=to_list_kv.label, headers=custom_headers
)
cnt = 0
for kv in items:
Expand Down
Loading