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