-
Notifications
You must be signed in to change notification settings - Fork 3k
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} Add dict transformation for typespec generated SDKs #30339
base: dev
Are you sure you want to change the base?
Changes from all commits
29dcfb4
0ceab94
46875c6
d6d5be7
344f39e
375b34d
e661003
185abc2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ | |
from urllib.request import urlopen | ||
|
||
from knack.log import get_logger | ||
from knack.util import CLIError, to_snake_case | ||
from knack.util import CLIError, to_snake_case, to_camel_case | ||
|
||
logger = get_logger(__name__) | ||
|
||
|
@@ -624,6 +624,40 @@ def b64_to_hex(s): | |
return hex_data | ||
|
||
|
||
def todict(obj, post_processor=None): | ||
""" | ||
Convert an object to a dictionary. Use 'post_processor(original_obj, dictionary)' to update the | ||
dictionary in the process | ||
""" | ||
from datetime import date, time, datetime, timedelta | ||
from enum import Enum | ||
if isinstance(obj, dict): | ||
result = {k: todict(v, post_processor) for (k, v) in obj.items()} | ||
return post_processor(obj, result) if post_processor else result | ||
if isinstance(obj, list): | ||
return [todict(a, post_processor) for a in obj] | ||
if isinstance(obj, Enum): | ||
return obj.value | ||
if isinstance(obj, (date, time, datetime)): | ||
return obj.isoformat() | ||
if isinstance(obj, timedelta): | ||
return str(obj) | ||
# This is the only difference with knack.util.todict because for typespec generated SDKs | ||
# The base model stores data in obj.__dict__['_data'] instead of in obj.__dict__ | ||
# We need to call obj.as_dict() to extract data for this kind of model | ||
if hasattr(obj, 'as_dict') and not hasattr(obj, '_attribute_map'): | ||
result = {to_camel_case(k): todict(v, post_processor) for k, v in obj.as_dict().items()} | ||
return post_processor(obj, result) if post_processor else result | ||
Comment on lines
+648
to
+650
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A good question from @kairu-ms, what if the REST spec defines a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now there is no such a property: https://github.com/search?q=repo%3AAzure%2Fazure-rest-api-specs%20asDict&type=code. If there is one in the future, we could rename it. |
||
if hasattr(obj, '_asdict'): | ||
return todict(obj._asdict(), post_processor) | ||
if hasattr(obj, '__dict__'): | ||
result = {to_camel_case(k): todict(v, post_processor) | ||
for k, v in obj.__dict__.items() | ||
if not callable(v) and not k.startswith('_')} | ||
return post_processor(obj, result) if post_processor else result | ||
return obj | ||
|
||
|
||
def random_string(length=16, force_lower=False, digits_only=False): | ||
from string import ascii_letters, digits, ascii_lowercase | ||
from random import choice | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another approach to detect if
obj
is an SDK model is something similar tostr(type(obj).__base__)
returns"<class 'azure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_securitydomain._model_base.Model'>"
However, this is also not very reliable as the name
Model
may change at any time.Using
isinstance()
is impossible asModel
is defined in each SDK, such asazure.cli.command_modules.keyvault.vendored_sdks.azure_keyvault_securitydomain._model_base.Model
, instead of inazure.core
. There is no singleModel
that is the base class of all SDK objects.Also, using
isinstance()
requires importing theModel
class which impairs the performance.As an example,
remove_additional_prop_layer
previously importsModel
with#13843 changed it to use a
try... catch...
strategy:azure-cli/src/azure-cli-core/azure/cli/core/commands/__init__.py
Lines 899 to 908 in 375b34d
Thus, there is no need to import
Model
for non-Model
objects.