From fb41208b55c28949c4d15d3eef70e465deacd97f Mon Sep 17 00:00:00 2001 From: Artem Goncharov <artem.goncharov@gmail.com> Date: Sat, 17 Aug 2024 15:52:13 +0200 Subject: [PATCH] Flip use of UNSET in the previous change we added support for UNSET to have empty schema. It is more logical to use UNSET when the schema is not defined and not when it is empty. Fix that. Change-Id: I6568ca826d119b42f74d3f2ee9a691ac1278bc26 --- codegenerator/openapi/base.py | 67 ++++++++++++++++++------------- codegenerator/openapi/cinder.py | 2 +- codegenerator/openapi/glance.py | 4 +- codegenerator/openapi/keystone.py | 2 +- codegenerator/openapi/nova.py | 5 ++- 5 files changed, 47 insertions(+), 33 deletions(-) diff --git a/codegenerator/openapi/base.py b/codegenerator/openapi/base.py index 6920ea4..8d37cf9 100644 --- a/codegenerator/openapi/base.py +++ b/codegenerator/openapi/base.py @@ -601,7 +601,7 @@ class OpenStackServerSourceBase: action_name = None query_params_versions = [] - body_schemas = [] + body_schemas: list[str | None] | Unset = UNSET expected_errors = ["404"] response_code = None # Version bound on an operation are set only when it is not an @@ -682,13 +682,16 @@ class OpenStackServerSourceBase: openapi_spec.components.schemas.setdefault( schema_name, TypeSchema(**body_schema) ) - body_schemas.append(f"#/components/schemas/{schema_name}") + if body_schemas is UNSET: + body_schemas = [] + if isinstance(body_schemas, list): + body_schemas.append(f"#/components/schemas/{schema_name}") rsp_spec = getattr(fdef, "return_type", None) if rsp_spec: ser_schema = _convert_wsme_to_jsonschema(rsp_spec) response_code = getattr(fdef, "status_code", None) - if not body_schemas and deser_schema: + if body_schemas is UNSET and deser_schema: # Glance may have request deserializer attached schema schema_name = ( "".join([x.title() for x in path_resource_names]) @@ -903,7 +906,10 @@ class OpenStackServerSourceBase: mode, action_name, ): - mime_type: str = "application/json" + # Body is not expected, exit (unless we are in the "action") + if body_schemas is None or (body_schemas == [] and mode != "action"): + return + mime_type: str | None = "application/json" schema_name = None schema_ref: str | Unset | None = None # We should not modify path_resource_names of the caller @@ -917,10 +923,10 @@ class OpenStackServerSourceBase: ) cont_schema = None - if len(body_schemas) == 1: + if body_schemas is not UNSET and len(body_schemas) == 1: # There is only one body known at the moment # None is a special case with explicitly no body supported - if body_schemas[0] is not UNSET: + if True: # body_schemas[0] is not UNSET: if cont_schema_name in openapi_spec.components.schemas: # if we have already oneOf - add there cont_schema = openapi_spec.components.schemas[ @@ -934,7 +940,7 @@ class OpenStackServerSourceBase: else: # otherwise just use schema as body schema_ref = body_schemas[0] - elif len(body_schemas) > 1: + elif body_schemas is not UNSET and len(body_schemas) > 1: # We may end up here multiple times if we have versioned operation. In this case merge to what we have already op_body = operation_spec.requestBody.setdefault("content", {}) old_schema = op_body.get(mime_type, {}).get("schema", {}) @@ -968,7 +974,7 @@ class OpenStackServerSourceBase: # not to create container. Now we need to change that by # merging with previous data cont_schema.oneOf.append({"$ref": old_ref}) - elif len(body_schemas) == 0 and mode == "action": + elif mode == "action": # There are actions without a real body description, but we know that action requires dummy body cont_schema = openapi_spec.components.schemas.setdefault( cont_schema_name, @@ -980,7 +986,7 @@ class OpenStackServerSourceBase: ), ) schema_ref = f"#/components/schemas/{cont_schema_name}" - elif len(body_schemas) == 0: + elif body_schemas is UNSET: # We know nothing about request schema_name = ( "".join([x.title() for x in path_resource_names]) @@ -996,6 +1002,7 @@ class OpenStackServerSourceBase: schema_name, description=f"Request of the {operation_spec.operationId} operation", action_name=action_name, + schema_def=UNSET, ) if mode == "action": @@ -1011,7 +1018,7 @@ class OpenStackServerSourceBase: os_ext["discriminator"] = "action" if cont_schema and action_name: cont_schema.openstack["action-name"] = action_name - elif schema_ref is not None and schema_ref is not UNSET: + elif schema_ref is not None: op_body = operation_spec.requestBody.setdefault("content", {}) js_content = op_body.setdefault(mime_type, {}) body_schema = js_content.setdefault("schema", {}) @@ -1134,19 +1141,20 @@ class OpenStackServerSourceBase: self, openapi_spec, name, - description=None, - schema_def=None, + description: str | None = None, + schema_def=UNSET, action_name=None, - ) -> tuple[str, str]: - if not schema_def: + ) -> tuple[str | None, str | None]: + if schema_def is UNSET: logging.warn( "No Schema definition for %s[%s] is known", name, action_name ) + # Create dummy schema since we got no data for it schema_def = { "type": "object", "description": LiteralScalarString(description), } - if schema_def is not UNSET: + if schema_def is not None: schema = openapi_spec.components.schemas.setdefault( name, TypeSchema( @@ -1154,12 +1162,14 @@ class OpenStackServerSourceBase: ), ) - if action_name: - if not schema.openstack: - schema.openstack = {} - schema.openstack.setdefault("action-name", action_name) + if action_name: + if not schema.openstack: + schema.openstack = {} + schema.openstack.setdefault("action-name", action_name) - return (f"#/components/schemas/{name}", "application/json") + return (f"#/components/schemas/{name}", "application/json") + else: + return (None, None) def _get_tags_for_url(self, url): """Return Tag (group) name based on the URL""" @@ -1200,7 +1210,7 @@ class OpenStackServerSourceBase: """Extract schemas from the decorated method.""" # Unwrap operation decorators to access all properties expected_errors: list[str] = [] - body_schemas: list[str | Unset] = [] + body_schemas: list[str | None] | Unset = UNSET query_params_versions: list[tuple] = [] response_body_schema: dict | Unset | None = UNSET @@ -1234,6 +1244,9 @@ class OpenStackServerSourceBase: "request_body_schema", getattr(f, "_request_body_schema", {}), ) + # body schemas are not UNSET anymore + if body_schemas is UNSET: + body_schemas = [] if obj is not None: if obj.get("type") in ["object", "array"]: # We only allow object and array bodies @@ -1272,9 +1285,12 @@ class OpenStackServerSourceBase: comp_schema.openstack["action-name"] = action_name ref_name = f"#/components/schemas/{typ_name}" - body_schemas.append(ref_name) + if isinstance(body_schemas, list): + body_schemas.append(ref_name) else: - body_schemas.append(UNSET) + # register no-body + if isinstance(body_schemas, list): + body_schemas.append(None) if "response_body_schema" in closure_locals or hasattr( f, "_response_body_schema" @@ -1284,10 +1300,7 @@ class OpenStackServerSourceBase: "response_body_schema", getattr(f, "_response_body_schema", {}), ) - if obj is not None: - response_body_schema = obj - else: - response_body_schema = UNSET + response_body_schema = obj if "query_params_schema" in closure_locals or hasattr( f, "_request_query_schema" ): diff --git a/codegenerator/openapi/cinder.py b/codegenerator/openapi/cinder.py index 367d875..5e31f00 100644 --- a/codegenerator/openapi/cinder.py +++ b/codegenerator/openapi/cinder.py @@ -203,7 +203,7 @@ class CinderV3Generator(OpenStackServerSourceBase): schema_def=None, action_name=None, ): - mime_type: str = "application/json" + mime_type: str | None = "application/json" # Invoke modularized schema _get_schema_ref for resource_mod in self.RESOURCE_MODULES: diff --git a/codegenerator/openapi/glance.py b/codegenerator/openapi/glance.py index 251ab9a..a456851 100644 --- a/codegenerator/openapi/glance.py +++ b/codegenerator/openapi/glance.py @@ -423,8 +423,8 @@ class GlanceGenerator(OpenStackServerSourceBase): from glance.api.v2 import tasks from glance import schema as glance_schema - ref: str - mime_type: str = "application/json" + ref: str | None + mime_type: str | None = "application/json" if name == "TasksListResponse": openapi_spec.components.schemas.setdefault( diff --git a/codegenerator/openapi/keystone.py b/codegenerator/openapi/keystone.py index 2378df3..3636fc7 100644 --- a/codegenerator/openapi/keystone.py +++ b/codegenerator/openapi/keystone.py @@ -511,7 +511,7 @@ class KeystoneGenerator(OpenStackServerSourceBase): # Invoke modularized schema _get_schema_ref for resource_mod in self.RESOURCE_MODULES: hook = getattr(resource_mod, "_get_schema_ref", None) - if hook and schema_def is not UNSET: + if hook: (ref, mime_type, matched) = hook( openapi_spec, name, description, schema_def, action_name ) diff --git a/codegenerator/openapi/nova.py b/codegenerator/openapi/nova.py index 9049675..a4884c1 100644 --- a/codegenerator/openapi/nova.py +++ b/codegenerator/openapi/nova.py @@ -158,8 +158,9 @@ class NovaGenerator(OpenStackServerSourceBase): ): from nova.api.openstack.compute.schemas import flavors - schema = None - mime_type: str = "application/json" + schema: None = None + ref: str | None + mime_type: str | None = "application/json" # NOTE(gtema): This must go away once scemas are merged directly to # Nova # /servers