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

{core} Fixed generic update issue. #30703

Merged
merged 2 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 6 additions & 6 deletions src/azure-cli-core/azure/cli/core/commands/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.cli.core.commands.events import EVENT_INVOKER_PRE_LOAD_ARGUMENTS
from azure.cli.core.commands.validators import IterateValue
from azure.cli.core.util import shell_safe_json_parse, get_command_type_kwarg
from azure.cli.core.util import shell_safe_json_parse, get_command_type_kwarg, getprop
from azure.cli.core.profiles import ResourceType, get_sdk

from knack.arguments import CLICommandArgument, ignore_type
Expand Down Expand Up @@ -600,7 +600,7 @@ def remove_properties(instance, argument_values):
def throw_and_show_options(instance, part, path):
from msrest.serialization import Model
options = instance.__dict__ if hasattr(instance, '__dict__') else instance
if isinstance(instance, Model) and isinstance(getattr(instance, 'additional_properties', None), dict):
if isinstance(instance, Model) and isinstance(getprop(instance, 'additional_properties', None), dict):
options.update(options.pop('additional_properties'))
parent = '.'.join(path[:-1]).replace('.[', '[')
error_message = "Couldn't find '{}' in '{}'.".format(part, parent)
Expand Down Expand Up @@ -673,15 +673,15 @@ def _update_instance(instance, part, path): # pylint: disable=too-many-return-s
matches.append(x)
elif not isinstance(x, dict):
snake_key = make_snake_case(key)
if hasattr(x, snake_key) and getattr(x, snake_key, None) == value:
if hasattr(x, snake_key) and getprop(x, snake_key, None) == value:
matches.append(x)

if len(matches) == 1:
return matches[0]
if len(matches) > 1:
raise CLIError("non-unique key '{}' found multiple matches on {}. Key must be unique."
.format(key, path[-2]))
if key in getattr(instance, 'additional_properties', {}):
if key in getprop(instance, 'additional_properties', {}):
instance.enable_additional_properties_sending()
return instance.additional_properties[key]
raise CLIError("item with value '{}' doesn\'t exist for key '{}' on {}".format(value, key, path[-2]))
Expand All @@ -697,8 +697,8 @@ def _update_instance(instance, part, path): # pylint: disable=too-many-return-s
return instance[part]

if hasattr(instance, make_snake_case(part)):
return getattr(instance, make_snake_case(part), None)
if part in getattr(instance, 'additional_properties', {}):
return getprop(instance, make_snake_case(part), None)
if part in getprop(instance, 'additional_properties', {}):
instance.enable_additional_properties_sending()
return instance.additional_properties[part]
raise AttributeError()
Expand Down
18 changes: 18 additions & 0 deletions src/azure-cli-core/azure/cli/core/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,24 @@ def test_b64_to_hex_type(self):
self.assertIsInstance(b64_to_hex(self.base64), str)


class TestGetProperty(unittest.TestCase):

def test_getprop(self):
from azure.cli.core.util import getprop
with self.assertRaises(AttributeError):
getprop(self, '__class__')
with self.assertRaises(AttributeError):
getprop(self, '__init__')
with self.assertRaises(AttributeError):
getprop(self, 'assertRaises')
with self.assertRaises(AttributeError):
getprop(self, '_diffThreshold')
with self.assertRaises(AttributeError):
getprop(self, 'new_props')
self.assertEqual(getprop(self, 'maxDiff'), self.maxDiff)
self.assertEqual(getprop(self, 'new_props', "new_props"), "new_props")


class TestHandleException(unittest.TestCase):

@mock.patch('azure.cli.core.azclierror.logger.error', autospec=True)
Expand Down
14 changes: 14 additions & 0 deletions src/azure-cli-core/azure/cli/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -1428,3 +1428,17 @@ def run_az_cmd(args, out_file=None):
cli = get_default_cli()
cli.invoke(args, out_file=out_file)
return cli.result


def getprop(o, name, *default):
""" This function is used to get the property of the object.
It will raise an error if the property is a private property or a method.
"""
if name.startswith('_'):
# avoid to access the private properties or methods
raise AttributeError(name)
v = getattr(o, name, *default)
if callable(v):
# avoid to access the methods
raise AttributeError(name)
return v