From 2260bda4ed64c17a2f352508aa29b8b32a6253a2 Mon Sep 17 00:00:00 2001 From: Julie Zhu Date: Mon, 27 Oct 2025 11:49:08 +1100 Subject: [PATCH 1/3] ignore x-ms-client-flatten argument --- src/aaz_dev/command/api/editor.py | 5 ++++ .../swagger/controller/command_generator.py | 30 ++++++++++++------- .../swagger/model/schema/cmd_builder.py | 9 ++++-- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/aaz_dev/command/api/editor.py b/src/aaz_dev/command/api/editor.py index 4480f7a7..c0338813 100644 --- a/src/aaz_dev/command/api/editor.py +++ b/src/aaz_dev/command/api/editor.py @@ -619,6 +619,11 @@ def editor_workspace_tree_node_add_swagger_resources(name, node_names): except KeyError: raise exceptions.InvalidAPIUsage("Invalid request") + for resource in resources: + resource["options"] = { + "ignore_x_ms_client_flatten": True + } + manager.add_new_resources_by_swagger( mod_names=mod_names, version=version, diff --git a/src/aaz_dev/swagger/controller/command_generator.py b/src/aaz_dev/swagger/controller/command_generator.py index 4c418681..0a4fd2ed 100644 --- a/src/aaz_dev/swagger/controller/command_generator.py +++ b/src/aaz_dev/swagger/controller/command_generator.py @@ -448,14 +448,16 @@ def create_draft_command_group(self, resource, if path_item.get is not None and 'get' in methods: cmd_builder = CMDBuilder(path=resource.path, method='get', mutability=MutabilityEnum.Read, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) op = self.generate_operation(cmd_builder, path_item, instance_var) show_or_list_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(show_or_list_command) if path_item.delete is not None and 'delete' in methods: cmd_builder = CMDBuilder(path=resource.path, method='delete', mutability=MutabilityEnum.Create, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) op = self.generate_operation(cmd_builder, path_item, instance_var) delete_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) delete_command.confirmation = DEFAULT_CONFIRMATION_PROMPT # add confirmation for delete command by default @@ -463,21 +465,24 @@ def create_draft_command_group(self, resource, if path_item.put is not None and 'put' in methods: cmd_builder = CMDBuilder(path=resource.path, method='put', mutability=MutabilityEnum.Create, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) op = self.generate_operation(cmd_builder, path_item, instance_var) create_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(create_command) if path_item.post is not None and 'post' in methods: cmd_builder = CMDBuilder(path=resource.path, method='post', mutability=MutabilityEnum.Create, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) op = self.generate_operation(cmd_builder, path_item, instance_var) action_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(action_command) if path_item.head is not None and 'head' in methods: cmd_builder = CMDBuilder(path=resource.path, method='head', mutability=MutabilityEnum.Read, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) op = self.generate_operation(cmd_builder, path_item, instance_var) head_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(head_command) @@ -488,12 +493,14 @@ def create_draft_command_group(self, resource, update_by_generic_command = None if path_item.patch is not None and 'patch' in methods: cmd_builder = CMDBuilder(path=resource.path, method='patch', mutability=MutabilityEnum.Update, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) op = self.generate_operation(cmd_builder, path_item, instance_var) update_by_patch_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) if path_item.get is not None and path_item.put is not None and 'get' in methods and 'put' in methods: cmd_builder = CMDBuilder(path=resource.path, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) get_op = self.generate_operation( cmd_builder, path_item, instance_var, method='get', mutability=MutabilityEnum.Read) put_op = self.generate_operation( @@ -511,7 +518,8 @@ def create_draft_command_group(self, resource, if 'get' not in methods or 'put' not in methods: raise exceptions.InvalidAPIUsage(f"Invalid update_by resource: '{resource}': 'get' or 'put' not in methods: '{methods}'") cmd_builder = CMDBuilder(path=resource.path, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) get_op = self.generate_operation( cmd_builder, path_item, instance_var, method='get', mutability=MutabilityEnum.Read) put_op = self.generate_operation( @@ -529,7 +537,8 @@ def create_draft_command_group(self, resource, raise exceptions.InvalidAPIUsage(f"Invalid update_by resource: '{resource}': 'patch' not in methods: '{methods}'") if kwargs.get('is_identity', False) is True: - cmd_builder = CMDBuilder(path=resource.path, parameterized_host=parameterized_host) + cmd_builder = CMDBuilder(path=resource.path, parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) get_op = self.generate_operation(cmd_builder, path_item, instance_var, method='get', mutability=MutabilityEnum.Read) patch_op = self.generate_operation(cmd_builder, path_item, instance_var, method='patch', mutability=MutabilityEnum.Update) specific_update_command = self.generate_specific_update_command(path_item, resource, instance_var, cmd_builder, get_op, patch_op) @@ -541,7 +550,8 @@ def create_draft_command_group(self, resource, else: cmd_builder = CMDBuilder(path=resource.path, method='patch', mutability=MutabilityEnum.Update, - parameterized_host=parameterized_host) + parameterized_host=parameterized_host, + ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) op = self.generate_operation(cmd_builder, path_item, instance_var) patch_update_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(patch_update_command) diff --git a/src/aaz_dev/swagger/model/schema/cmd_builder.py b/src/aaz_dev/swagger/model/schema/cmd_builder.py index 9e8e6ce9..72a8b632 100644 --- a/src/aaz_dev/swagger/model/schema/cmd_builder.py +++ b/src/aaz_dev/swagger/model/schema/cmd_builder.py @@ -42,7 +42,7 @@ class CMDBuilder: - def __init__(self, path, method=None, mutability=None, in_base=False, frozen=False, parent_ids=None, cls_definitions=None, parameterized_host=None): + def __init__(self, path, method=None, mutability=None, in_base=False, frozen=False, parent_ids=None, cls_definitions=None, parameterized_host=None, ignore_x_ms_client_flatten=None): self.path = path self.method = method self.mutability = mutability @@ -53,6 +53,7 @@ def __init__(self, path, method=None, mutability=None, in_base=False, frozen=Fal self.parent_ids = parent_ids or [] self.cls_definitions = {} if cls_definitions is None else cls_definitions self.parameterized_host = parameterized_host + self.ignore_x_ms_client_flatten=ignore_x_ms_client_flatten def __call__(self, schema, **kwargs): sub_builder = CMDBuilder( @@ -63,7 +64,8 @@ def __call__(self, schema, **kwargs): frozen=kwargs.pop('frozen', self.frozen), parent_ids=[*self.parent_ids, self.id], cls_definitions=kwargs.pop('cls_definitions', self.cls_definitions), - parameterized_host=kwargs.pop('parameterized_host', self.parameterized_host) + parameterized_host=kwargs.pop('parameterized_host', self.parameterized_host), + ignore_x_ms_client_flatten=kwargs.pop('ignore_x_ms_client_flatten', self.ignore_x_ms_client_flatten) ) if getattr(schema, 'read_only', None): sub_builder.read_only = True @@ -84,6 +86,9 @@ def __call__(self, schema, **kwargs): key=sub_builder.id, value=sub_builder.parent_ids.index(sub_builder.id), ) + if hasattr(schema, 'x_ms_client_flatten') and schema.x_ms_client_flatten and self.ignore_x_ms_client_flatten: + schema.x_ms_client_flatten = None + return schema.to_cmd(sub_builder, **kwargs) def find_traces(self, traces): From e2108e75eb5cb240aa014b644cc68c56c01ba6c0 Mon Sep 17 00:00:00 2001 From: Julie Zhu Date: Tue, 25 Nov 2025 19:15:33 +1100 Subject: [PATCH 2/3] disable flatten for request body object in new command --- src/aaz_dev/command/api/_cmds.py | 4 +++ src/aaz_dev/command/api/editor.py | 5 --- .../model/configuration/_arg_builder.py | 2 ++ .../command/model/configuration/_schema.py | 2 ++ .../swagger/controller/command_generator.py | 31 +++++++------------ .../swagger/model/schema/cmd_builder.py | 10 +++--- src/aaz_dev/swagger/model/schema/parameter.py | 1 + 7 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/aaz_dev/command/api/_cmds.py b/src/aaz_dev/command/api/_cmds.py index 278c49c0..f54ec406 100644 --- a/src/aaz_dev/command/api/_cmds.py +++ b/src/aaz_dev/command/api/_cmds.py @@ -230,6 +230,10 @@ def to_aaz(module_name): aaz_manager=AAZSpecsManager(), source=SourceTypeEnum.OpenAPI, ) + for resource in resources: + resource["options"] = { + "non_flatten": True + } ws.add_new_resources_by_swagger(mod_names=module_name, version=version, resources=resources) # provide default short summary diff --git a/src/aaz_dev/command/api/editor.py b/src/aaz_dev/command/api/editor.py index c0338813..4480f7a7 100644 --- a/src/aaz_dev/command/api/editor.py +++ b/src/aaz_dev/command/api/editor.py @@ -619,11 +619,6 @@ def editor_workspace_tree_node_add_swagger_resources(name, node_names): except KeyError: raise exceptions.InvalidAPIUsage("Invalid request") - for resource in resources: - resource["options"] = { - "ignore_x_ms_client_flatten": True - } - manager.add_new_resources_by_swagger( mod_names=mod_names, version=version, diff --git a/src/aaz_dev/command/model/configuration/_arg_builder.py b/src/aaz_dev/command/model/configuration/_arg_builder.py index e20e592d..a1cd60ab 100644 --- a/src/aaz_dev/command/model/configuration/_arg_builder.py +++ b/src/aaz_dev/command/model/configuration/_arg_builder.py @@ -110,6 +110,8 @@ def _build_arg(self): def _need_flatten(self): if isinstance(self.schema, CMDObjectSchema): + if self.schema.non_flatten: + return False if self.get_cls(): # not support to flatten object which is a cls. return False diff --git a/src/aaz_dev/command/model/configuration/_schema.py b/src/aaz_dev/command/model/configuration/_schema.py index a7ceb010..a5c65465 100644 --- a/src/aaz_dev/command/model/configuration/_schema.py +++ b/src/aaz_dev/command/model/configuration/_schema.py @@ -890,6 +890,8 @@ class CMDObjectSchemaBase(CMDSchemaBase): discriminators = ListType(CMDObjectSchemaDiscriminatorField()) additional_props = CMDObjectSchemaAdditionalPropertiesField() + non_flatten = None + # define a schema cls which can be used by others, # cls definition will not include properties in CMDSchema only, such as following properties: # - name diff --git a/src/aaz_dev/swagger/controller/command_generator.py b/src/aaz_dev/swagger/controller/command_generator.py index 0a4fd2ed..48631f45 100644 --- a/src/aaz_dev/swagger/controller/command_generator.py +++ b/src/aaz_dev/swagger/controller/command_generator.py @@ -445,19 +445,18 @@ def create_draft_command_group(self, resource, command_group.commands = [] path_item = self.get_path_item(resource) parameterized_host = self.get_parameterized_host(resource) + non_flatten = kwargs.get("non_flatten", None) if path_item.get is not None and 'get' in methods: cmd_builder = CMDBuilder(path=resource.path, method='get', mutability=MutabilityEnum.Read, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host) op = self.generate_operation(cmd_builder, path_item, instance_var) show_or_list_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(show_or_list_command) if path_item.delete is not None and 'delete' in methods: cmd_builder = CMDBuilder(path=resource.path, method='delete', mutability=MutabilityEnum.Create, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host) op = self.generate_operation(cmd_builder, path_item, instance_var) delete_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) delete_command.confirmation = DEFAULT_CONFIRMATION_PROMPT # add confirmation for delete command by default @@ -465,24 +464,21 @@ def create_draft_command_group(self, resource, if path_item.put is not None and 'put' in methods: cmd_builder = CMDBuilder(path=resource.path, method='put', mutability=MutabilityEnum.Create, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host, non_flatten=non_flatten) op = self.generate_operation(cmd_builder, path_item, instance_var) create_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(create_command) if path_item.post is not None and 'post' in methods: cmd_builder = CMDBuilder(path=resource.path, method='post', mutability=MutabilityEnum.Create, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host, non_flatten=non_flatten) op = self.generate_operation(cmd_builder, path_item, instance_var) action_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(action_command) if path_item.head is not None and 'head' in methods: cmd_builder = CMDBuilder(path=resource.path, method='head', mutability=MutabilityEnum.Read, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host) op = self.generate_operation(cmd_builder, path_item, instance_var) head_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(head_command) @@ -493,14 +489,12 @@ def create_draft_command_group(self, resource, update_by_generic_command = None if path_item.patch is not None and 'patch' in methods: cmd_builder = CMDBuilder(path=resource.path, method='patch', mutability=MutabilityEnum.Update, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host, non_flatten=non_flatten) op = self.generate_operation(cmd_builder, path_item, instance_var) update_by_patch_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) if path_item.get is not None and path_item.put is not None and 'get' in methods and 'put' in methods: cmd_builder = CMDBuilder(path=resource.path, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host, non_flatten=non_flatten) get_op = self.generate_operation( cmd_builder, path_item, instance_var, method='get', mutability=MutabilityEnum.Read) put_op = self.generate_operation( @@ -518,8 +512,7 @@ def create_draft_command_group(self, resource, if 'get' not in methods or 'put' not in methods: raise exceptions.InvalidAPIUsage(f"Invalid update_by resource: '{resource}': 'get' or 'put' not in methods: '{methods}'") cmd_builder = CMDBuilder(path=resource.path, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host, non_flatten=non_flatten) get_op = self.generate_operation( cmd_builder, path_item, instance_var, method='get', mutability=MutabilityEnum.Read) put_op = self.generate_operation( @@ -537,8 +530,7 @@ def create_draft_command_group(self, resource, raise exceptions.InvalidAPIUsage(f"Invalid update_by resource: '{resource}': 'patch' not in methods: '{methods}'") if kwargs.get('is_identity', False) is True: - cmd_builder = CMDBuilder(path=resource.path, parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + cmd_builder = CMDBuilder(path=resource.path, parameterized_host=parameterized_host, non_flatten=non_flatten) get_op = self.generate_operation(cmd_builder, path_item, instance_var, method='get', mutability=MutabilityEnum.Read) patch_op = self.generate_operation(cmd_builder, path_item, instance_var, method='patch', mutability=MutabilityEnum.Update) specific_update_command = self.generate_specific_update_command(path_item, resource, instance_var, cmd_builder, get_op, patch_op) @@ -550,8 +542,7 @@ def create_draft_command_group(self, resource, else: cmd_builder = CMDBuilder(path=resource.path, method='patch', mutability=MutabilityEnum.Update, - parameterized_host=parameterized_host, - ignore_x_ms_client_flatten=kwargs.get("ignore_x_ms_client_flatten", None)) + parameterized_host=parameterized_host, non_flatten=non_flatten) op = self.generate_operation(cmd_builder, path_item, instance_var) patch_update_command = self.generate_command(path_item, resource, instance_var, cmd_builder, op) command_group.commands.append(patch_update_command) diff --git a/src/aaz_dev/swagger/model/schema/cmd_builder.py b/src/aaz_dev/swagger/model/schema/cmd_builder.py index 72a8b632..b017a208 100644 --- a/src/aaz_dev/swagger/model/schema/cmd_builder.py +++ b/src/aaz_dev/swagger/model/schema/cmd_builder.py @@ -42,7 +42,7 @@ class CMDBuilder: - def __init__(self, path, method=None, mutability=None, in_base=False, frozen=False, parent_ids=None, cls_definitions=None, parameterized_host=None, ignore_x_ms_client_flatten=None): + def __init__(self, path, method=None, mutability=None, in_base=False, frozen=False, parent_ids=None, cls_definitions=None, parameterized_host=None, non_flatten=None): self.path = path self.method = method self.mutability = mutability @@ -53,7 +53,7 @@ def __init__(self, path, method=None, mutability=None, in_base=False, frozen=Fal self.parent_ids = parent_ids or [] self.cls_definitions = {} if cls_definitions is None else cls_definitions self.parameterized_host = parameterized_host - self.ignore_x_ms_client_flatten=ignore_x_ms_client_flatten + self.non_flatten=non_flatten def __call__(self, schema, **kwargs): sub_builder = CMDBuilder( @@ -65,7 +65,7 @@ def __call__(self, schema, **kwargs): parent_ids=[*self.parent_ids, self.id], cls_definitions=kwargs.pop('cls_definitions', self.cls_definitions), parameterized_host=kwargs.pop('parameterized_host', self.parameterized_host), - ignore_x_ms_client_flatten=kwargs.pop('ignore_x_ms_client_flatten', self.ignore_x_ms_client_flatten) + non_flatten=kwargs.pop('non_flatten', self.non_flatten) ) if getattr(schema, 'read_only', None): sub_builder.read_only = True @@ -86,8 +86,6 @@ def __call__(self, schema, **kwargs): key=sub_builder.id, value=sub_builder.parent_ids.index(sub_builder.id), ) - if hasattr(schema, 'x_ms_client_flatten') and schema.x_ms_client_flatten and self.ignore_x_ms_client_flatten: - schema.x_ms_client_flatten = None return schema.to_cmd(sub_builder, **kwargs) @@ -237,6 +235,8 @@ def build_schema(self, schema): raise exceptions.InvalidSwaggerValueError( f"type is not supported", key=getattr(schema, "traces", None), value=[schema_type]) + if isinstance(model, CMDObjectSchemaBase): + model.non_flatten = self.non_flatten model.read_only = self.read_only model.frozen = self.frozen return model diff --git a/src/aaz_dev/swagger/model/schema/parameter.py b/src/aaz_dev/swagger/model/schema/parameter.py index 502e8fc6..5ed17cda 100644 --- a/src/aaz_dev/swagger/model/schema/parameter.py +++ b/src/aaz_dev/swagger/model/schema/parameter.py @@ -219,6 +219,7 @@ def to_cmd(self, builder, **kwargs): if isinstance(v, CMDObjectSchema): # flatten body parameter v.client_flatten = True + v.non_flatten = None else: raise exceptions.InvalidSwaggerValueError( msg="Invalid Request type", From 83cdb1bae0dbd6e667b048a39e9b4527f7284380 Mon Sep 17 00:00:00 2001 From: Julie Zhu Date: Wed, 26 Nov 2025 13:57:06 +1100 Subject: [PATCH 3/3] doc: update help msg --- src/aaz_dev/command/api/_cmds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aaz_dev/command/api/_cmds.py b/src/aaz_dev/command/api/_cmds.py index f54ec406..557e0cc0 100644 --- a/src/aaz_dev/command/api/_cmds.py +++ b/src/aaz_dev/command/api/_cmds.py @@ -160,7 +160,7 @@ def generate_command_models_from_swagger(swagger_tag, workspace_path=None): sys.exit(1) -@bp.cli.command("generate-all", short_help="Fully generate data model from OpenAPI specification, mainly for use in https://github.com/magodo/az-rs.") +@bp.cli.command("generate-all", short_help="Fully generate metadata from the specification, mainly for use in https://github.com/magodo/az-rs, and additionally to validate compatibility.") @click.option( "--swagger-path", '-s', type=click.Path(file_okay=False, dir_okay=True, readable=True, resolve_path=True),