|
6 | 6 | Operation, |
7 | 7 | PathItem, |
8 | 8 | Reference, |
| 9 | + RequestBody, |
9 | 10 | Response, |
10 | 11 | Schema, |
11 | 12 | ) |
@@ -94,46 +95,56 @@ def is_schema_type(obj: Any) -> bool: |
94 | 95 |
|
95 | 96 |
|
96 | 97 | def generate_body_param(operation: Operation) -> Union[str, None]: |
| 98 | + """Return JSON body expression; tolerant of missing or primitive schema types. |
| 99 | +
|
| 100 | + Behavior: |
| 101 | + - Reference body -> data.dict() |
| 102 | + - Array of model-like items -> [i.dict() for i in data] |
| 103 | + - Array of primitives / unknown -> data |
| 104 | + - Object / object-like (has properties/allOf/oneOf/anyOf/additionalProperties) -> data |
| 105 | + - Primitive / missing type -> data |
| 106 | + """ |
97 | 107 | if operation.requestBody is None: |
98 | 108 | return None |
99 | | - else: |
100 | | - if isinstance(operation.requestBody, Reference30) or isinstance( |
101 | | - operation.requestBody, Reference31 |
102 | | - ): |
103 | | - return "data.dict()" |
104 | | - |
105 | | - if operation.requestBody.content is None: |
106 | | - return None # pragma: no cover |
107 | | - |
108 | | - if operation.requestBody.content.get("application/json") is None: |
109 | | - return None # pragma: no cover |
110 | | - |
111 | | - media_type = operation.requestBody.content.get("application/json") |
112 | | - |
113 | | - if media_type is None: |
114 | | - return None # pragma: no cover |
115 | | - |
116 | | - if isinstance( |
117 | | - media_type.media_type_schema, (Reference, Reference30, Reference31) |
118 | | - ): |
119 | | - return "data.dict()" |
120 | | - elif hasattr(media_type.media_type_schema, "ref"): |
121 | | - # Handle Reference objects from different OpenAPI versions |
122 | | - return "data.dict()" |
123 | | - elif isinstance(media_type.media_type_schema, (Schema, Schema30, Schema31)): |
124 | | - schema = media_type.media_type_schema |
125 | | - if schema.type == "array": |
| 109 | + # Check for Reference across all versions |
| 110 | + if isinstance(operation.requestBody, (Reference, Reference30, Reference31)): |
| 111 | + return "data.dict()" |
| 112 | + # Defensive access to content attribute |
| 113 | + content = getattr(operation.requestBody, "content", None) |
| 114 | + if not isinstance(content, dict): |
| 115 | + return None |
| 116 | + mt = content.get("application/json") |
| 117 | + if mt is None: |
| 118 | + return None |
| 119 | + schema = getattr(mt, "media_type_schema", None) |
| 120 | + # Check for Reference across all versions |
| 121 | + if isinstance(schema, (Reference, Reference30, Reference31)): |
| 122 | + return "data.dict()" |
| 123 | + # Check for Schema across all versions |
| 124 | + if isinstance(schema, (Schema, Schema30, Schema31)): |
| 125 | + # Array handling |
| 126 | + if getattr(schema, "type", None) == "array": |
| 127 | + items = getattr(schema, "items", None) |
| 128 | + if isinstance(items, (Reference, Reference30, Reference31)): |
126 | 129 | return "[i.dict() for i in data]" |
127 | | - elif schema.type == "object": |
128 | | - return "data" |
129 | | - else: |
130 | | - raise Exception( |
131 | | - f"Unsupported schema type for request body: {schema.type}" |
132 | | - ) # pragma: no cover |
133 | | - else: |
134 | | - raise Exception( |
135 | | - f"Unsupported schema type for request body: {type(media_type.media_type_schema)}" |
136 | | - ) # pragma: no cover |
| 130 | + if isinstance(items, (Schema, Schema30, Schema31)): |
| 131 | + if getattr(items, "type", None) == "object" or any( |
| 132 | + getattr(items, attr, None) for attr in ["properties", "allOf", "oneOf", "anyOf"] |
| 133 | + ): |
| 134 | + return "[i.dict() for i in data]" |
| 135 | + return "data" |
| 136 | + # Object-like |
| 137 | + if ( |
| 138 | + getattr(schema, "type", None) == "object" |
| 139 | + or any( |
| 140 | + getattr(schema, attr, None) |
| 141 | + for attr in ["properties", "allOf", "oneOf", "anyOf", "additionalProperties"] |
| 142 | + ) |
| 143 | + ): |
| 144 | + return "data" |
| 145 | + # Primitive / unspecified |
| 146 | + return "data" |
| 147 | + return None |
137 | 148 |
|
138 | 149 |
|
139 | 150 | def generate_params(operation: Operation) -> str: |
@@ -225,17 +236,14 @@ def _generate_params_from_content(content: Any): |
225 | 236 | return params + default_params |
226 | 237 |
|
227 | 238 |
|
228 | | -def generate_operation_id( |
229 | | - operation: Operation, http_op: str, path_name: Optional[str] = None |
230 | | -) -> str: |
231 | | - if operation.operationId is not None: |
| 239 | +def generate_operation_id(operation: Operation, http_op: str, path_name: Optional[str] = None) -> str: |
| 240 | + if operation.operationId: |
232 | 241 | return common.normalize_symbol(operation.operationId) |
233 | | - elif path_name is not None: |
234 | | - return common.normalize_symbol(f"{http_op}_{path_name}") |
235 | | - else: |
236 | | - raise Exception( |
237 | | - f"OperationId is not defined for {http_op} of path_name {path_name} --> {operation.summary}" |
238 | | - ) # pragma: no cover |
| 242 | + if path_name: |
| 243 | + # Insert underscore before parameter placeholders so /lists/{listId} -> lists_{listId} |
| 244 | + cleaned = re.sub(r"\{([^}]+)\}", r"_\1", path_name) |
| 245 | + return common.normalize_symbol(f"{http_op}_{cleaned}") |
| 246 | + raise RuntimeError("Missing operationId and path_name for operation") |
239 | 247 |
|
240 | 248 |
|
241 | 249 | def _generate_params( |
|
0 commit comments